Linux内核中PF_KEY协议族的实现(3)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。<br>msn: <a href="mailto:yfydz_no1@hotmail.com" target="_blank">yfydz_no1@hotmail.com</a><br>来源:<a href="http://yfydz.cublog.cn/" target="_blank">http://yfydz.cublog.cn</a><div> </div>
<div>5.10 添加/更新SPD(安全策略)</div>
<div>// 添加安全策略到安全策略数据库SPDB<br>static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br> int err = 0;<br> struct sadb_lifetime *lifetime;<br> struct sadb_address *sa;<br> struct sadb_x_policy *pol;<br> struct xfrm_policy *xp;<br> struct km_event c;<br> struct sadb_x_sec_ctx *sec_ctx;</div>
<div>// 错误检查, 源目的地址类型要一致, 策略信息非空<br> if (!present_and_same_family(ext_hdrs,<br> ext_hdrs) ||<br> !ext_hdrs)<br> return -EINVAL;<br>// 策略指针<br> pol = ext_hdrs;<br>// 策略类型只能是DISCARD, NONE和IPSEC三者之一<br> if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC)<br> return -EINVAL;<br>// 必须明确该SP作用于哪个方向的的数据: IN, OUT和FORWARD, 最后那个不是RFC标准的<br> if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)<br> return -EINVAL;</div>
<div>// 分配xfrm策略<br> xp = xfrm_policy_alloc(GFP_KERNEL);<br> if (xp == NULL)<br> return -ENOBUFS;<br>// 策略的动作: 阻塞还是放行<br> xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?<br> XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);<br>// 策略的优先级<br> xp->priority = pol->sadb_x_policy_priority;</div>
<div>// 获取策略源地址及地址类型(v4 or v6)<br> sa = ext_hdrs, <br> xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr);<br> if (!xp->family) {<br> err = -EINVAL;<br> goto out;<br> }<br>// 填充策略选择子结构参数, 选择子中包括用来辨别策略的相关参数, 用来查找匹配策略<br>// 协议族<br> xp->selector.family = xp->family;<br>// 地址长度<br> xp->selector.prefixlen_s = sa->sadb_address_prefixlen;<br>// 协议<br> xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);<br>// 策略中可以有上层协议的源端口参数, 不过不是必须的<br> xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;<br> if (xp->selector.sport)<br> xp->selector.sport_mask = htons(0xffff);</div>
<div>// 获取策略目的地址及地址类型(v4 or v6)<br>// 和源地址处理类似<br> sa = ext_hdrs, <br> pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr);<br> xp->selector.prefixlen_d = sa->sadb_address_prefixlen;</div>
<div> /* Amusing, we set this twice. KAME apps appear to set same value<br> * in both addresses.<br> */<br> xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);</div>
<div> xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port;<br> if (xp->selector.dport)<br> xp->selector.dport_mask = htons(0xffff);</div>
<div>// 用户定义的安全上下文<br> sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs;<br> if (sec_ctx != NULL) {<br> struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);</div>
<div> if (!uctx) {<br> err = -ENOBUFS;<br> goto out;<br> }</div>
<div> err = security_xfrm_policy_alloc(xp, uctx);<br> kfree(uctx);</div>
<div> if (err)<br> goto out;<br> }</div>
<div>// lft: xfrm_lifetime_config, 生存时间配置参数<br>// 关于字节数和包数的软硬限制初始化<br> xp->lft.soft_byte_limit = XFRM_INF;<br> xp->lft.hard_byte_limit = XFRM_INF;<br> xp->lft.soft_packet_limit = XFRM_INF;<br> xp->lft.hard_packet_limit = XFRM_INF;<br>// 如果在消息中定义了限制, 设置之<br> if ((lifetime = ext_hdrs) != NULL) {<br> xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);<br> xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);<br> xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;<br> xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;<br> }<br> if ((lifetime = ext_hdrs) != NULL) {<br> xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);<br> xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);<br> xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;<br> xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;<br> }<br> xp->xfrm_nr = 0;<br>// 如果是IPSEC策略, 解析相关请求<br> if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&<br> (err = parse_ipsecrequests(xp, pol)) < 0)<br> goto out;</div>
<div>// 将策略xp插入内核SPDB<br> err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,<br>// 一般是添加, 也可以是更新<br> hdr->sadb_msg_type != SADB_X_SPDUPDATE);</div>
<div> if (err)<br> goto out;</div>
<div> if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)<br> c.event = XFRM_MSG_UPDPOLICY;<br> else <br> c.event = XFRM_MSG_NEWPOLICY;</div>
<div> c.seq = hdr->sadb_msg_seq;<br> c.pid = hdr->sadb_msg_pid;<br>// 策略通知回调处理<br> km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);<br> xfrm_pol_put(xp);<br> return 0;</div>
<div>out:<br> security_xfrm_policy_free(xp);<br> kfree(xp);<br> return err;<br>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 插入策略<br>int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)<br>{<br> struct xfrm_policy *pol;<br> struct xfrm_policy *delpol;<br> struct hlist_head *chain;<br> struct hlist_node *entry, *newpos, *last;<br> struct dst_entry *gc_list;</div>
<div> write_lock_bh(&xfrm_policy_lock);<br>// 找到具体的hash链表, SPDB也是用HASH表实现的<br> chain = policy_hash_bysel(&policy->selector, policy->family, dir);<br> delpol = NULL;<br> newpos = NULL;<br> last = NULL;<br>// 遍历链表, 该链表是以策略的优先级值进行排序的链表, 因此需要根据新策略的优先级大小<br>// 将新策略插到合适的位置<br> hlist_for_each_entry(pol, entry, chain, bydst) {<br>// delpol要为空<br> if (!delpol &&<br>// 策略类型比较<br> pol->type == policy->type &&<br>// 选择子比较<br> !selector_cmp(&pol->selector, &policy->selector) &&<br>// 安全上下文比较<br> xfrm_sec_ctx_match(pol->security, policy->security)) {<br>// 找到了<br> if (excl) {<br>// 如果是添加操作, 要插入的策略在数据库中已经存在, 发生错误<br> write_unlock_bh(&xfrm_policy_lock);<br> return -EEXIST;<br> }<br>// 保存好要删除的策略位置<br> delpol = pol;<br>// 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适的插入位置<br>// 因为这个链表是以优先级值进行排序的, 不能乱<br>// 现在delpol已经非空了, 前面的策略查找条件已经不可能满足了<br> if (policy->priority > pol->priority)<br> continue;<br> } else if (policy->priority >= pol->priority) {<br>// 如果新的优先级不低于当前的优先级, 保存当前节点, 继续查找合适插入位置<br> last = &pol->bydst;<br> continue;<br> }<br>// 这里是根据新策略的优先级确定的插入位置<br> if (!newpos)<br> newpos = &pol->bydst;<br>// 如果已经找到要删除的策略, 中断<br> if (delpol)<br> break;<br> last = &pol->bydst;<br> }<br> if (!newpos)<br> newpos = last;<br>// 插入策略到按目的地址HASH的链表<br> if (newpos)<br> hlist_add_after(newpos, &policy->bydst);<br> else<br> hlist_add_head(&policy->bydst, chain);<br> xfrm_pol_hold(policy);<br> xfrm_policy_count++;<br> atomic_inc(&flow_cache_genid);<br>// 如果有相同的老策略, 要从目的地址HASH和索引号HASH这两个表中删除<br> if (delpol) {<br> hlist_del(&delpol->bydst);<br> hlist_del(&delpol->byidx);<br> xfrm_policy_count--;<br> }<br>// 获取策略索引号, 插入索引HASH链表<br> policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);<br> hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index));<br>// 策略插入实际时间<br> policy->curlft.add_time = (unsigned long)xtime.tv_sec;<br> policy->curlft.use_time = 0;<br> if (!mod_timer(&policy->timer, jiffies + HZ))<br> xfrm_pol_hold(policy);<br> write_unlock_bh(&xfrm_policy_lock);</div>
<div>// 释放老策略<br> if (delpol)<br> xfrm_policy_kill(delpol);<br> else if (xfrm_bydst_should_resize(dir, NULL))<br> schedule_work(&xfrm_hash_work);</div>
<div>// 下面释放所有策略当前的路由cache<br> read_lock_bh(&xfrm_policy_lock);<br> gc_list = NULL;<br> entry = &policy->bydst;<br>// 遍历链表, 搜集垃圾路由cache建立链表<br> hlist_for_each_entry_continue(policy, entry, bydst) {<br> struct dst_entry *dst;</div>
<div> write_lock(&policy->lock);<br> dst = policy->bundles;<br> if (dst) {<br> struct dst_entry *tail = dst;<br> while (tail->next)<br> tail = tail->next;<br> tail->next = gc_list;<br> gc_list = dst;</div>
<div> policy->bundles = NULL;<br> }<br> write_unlock(&policy->lock);<br> }<br> read_unlock_bh(&xfrm_policy_lock);<br>// 释放垃圾路由cahce<br> while (gc_list) {<br> struct dst_entry *dst = gc_list;</div>
<div> gc_list = dst->next;<br> dst_free(dst);<br> }</div>
<div> return 0;<br>}<br>EXPORT_SYMBOL(xfrm_policy_insert);</div>
<div><br>5.11 删除SPD</div>
<div><br>static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br> int err;<br> struct sadb_address *sa;<br> struct sadb_x_policy *pol;<br> struct xfrm_policy *xp, tmp;<br> struct xfrm_selector sel;<br> struct km_event c;<br> struct sadb_x_sec_ctx *sec_ctx;</div>
<div>// 错误检查, 源目的地址类型要一致, 策略信息非空<br> if (!present_and_same_family(ext_hdrs,<br> ext_hdrs) ||<br> !ext_hdrs)<br> return -EINVAL;<br>// 消息中定义的策略<br> pol = ext_hdrs;<br>// 策略类型合法性检查<br> if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)<br> return -EINVAL;</div>
<div> memset(&sel, 0, sizeof(sel));<br>// 解析消息中的源地址参数填充到选择子结构中<br> sa = ext_hdrs, <br> sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);<br> sel.prefixlen_s = sa->sadb_address_prefixlen;<br> sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);<br> sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;<br> if (sel.sport)<br> sel.sport_mask = htons(0xffff);</div>
<div>// 解析消息中的目的地址参数填充到选择子结构中<br> sa = ext_hdrs, <br> pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);<br> sel.prefixlen_d = sa->sadb_address_prefixlen;<br> sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);<br> sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;<br> if (sel.dport)<br> sel.dport_mask = htons(0xffff);</div>
<div> sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs;<br> memset(&tmp, 0, sizeof(struct xfrm_policy));<br>// 扩展的用户安全上下文信息处理<br> if (sec_ctx != NULL) {<br> struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);</div>
<div> if (!uctx)<br> return -ENOMEM;</div>
<div> err = security_xfrm_policy_alloc(&tmp, uctx);<br> kfree(uctx);</div>
<div> if (err)<br> return err;<br> }<br>// 根据策略类型, 处理的数据方向, 选择子参数等信息查找策略<br>// 同时最后一个参数为1表示找到后将策略从系统的SPDB链表中断开后删除<br> xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1,<br> &sel, tmp.security, 1);<br> security_xfrm_policy_free(&tmp);<br>// 没有该策略, 出错<br> if (xp == NULL)<br> return -ENOENT;</div>
<div> err = 0;</div>
<div> if ((err = security_xfrm_policy_delete(xp)))<br> goto out;<br> c.seq = hdr->sadb_msg_seq;<br> c.pid = hdr->sadb_msg_pid;<br> c.event = XFRM_MSG_DELPOLICY;<br>// 反方向的策略通知回调处理<br> km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);</div>
<div>out:<br>// 释放策略<br> xfrm_pol_put(xp);<br> return err;<br>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 根据选择子和上下文查找策略<br>struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,<br> struct xfrm_selector *sel,<br> struct xfrm_sec_ctx *ctx, int delete)<br>{<br> struct xfrm_policy *pol, *ret;<br> struct hlist_head *chain;<br> struct hlist_node *entry;</div>
<div> write_lock_bh(&xfrm_policy_lock);<br>// 定位HASH表<br> chain = policy_hash_bysel(sel, sel->family, dir);<br> ret = NULL;<br>// 遍历链表<br> hlist_for_each_entry(pol, entry, chain, bydst) {<br>// 根据类型, 选择子和上下文进行匹配<br> if (pol->type == type &&<br> !selector_cmp(sel, &pol->selector) &&<br> xfrm_sec_ctx_match(ctx, pol->security)) {<br> xfrm_pol_hold(pol);<br> if (delete) {<br>// 要的删除话将策略节点从目的地址HASH链表和索引HASH链表中断开<br> hlist_del(&pol->bydst);<br> hlist_del(&pol->byidx);<br> xfrm_policy_count--;<br> }<br> ret = pol;<br> break;<br> }<br> }<br> write_unlock_bh(&xfrm_policy_lock);</div>
<div> if (ret && delete) {<br> atomic_inc(&flow_cache_genid);<br>// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除<br> xfrm_policy_kill(ret);<br> }<br> return ret;<br>}<br>EXPORT_SYMBOL(xfrm_policy_bysel_ctx);</div>
<div><br>5.12 获取SPD</div>
<div><br>static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br> unsigned int dir;<br> int err;<br> struct sadb_x_policy *pol;<br> struct xfrm_policy *xp;<br> struct km_event c;</div>
<div>// 消息中的策略头<br> if ((pol = ext_hdrs) == NULL)<br> return -EINVAL;</div>
<div>// 根据策略id判断数据方向<br> dir = xfrm_policy_id2dir(pol->sadb_x_policy_id);<br> if (dir >= XFRM_POLICY_MAX)<br> return -EINVAL;</div>
<div>// 根据方向/ID等参数来查找策略, 如果最后一个参数为真的同时删除策略<br> xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id,<br> hdr->sadb_msg_type == SADB_X_SPDDELETE2);<br> if (xp == NULL)<br> return -ENOENT;</div>
<div> err = 0;</div>
<div> c.seq = hdr->sadb_msg_seq;<br> c.pid = hdr->sadb_msg_pid;<br> if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {<br>// 如果要删除策略, 进行通知回调<br> c.data.byid = 1;<br> c.event = XFRM_MSG_DELPOLICY;<br> km_policy_notify(xp, dir, &c);<br> } else {<br>// 将结果填充一个skb返回给用户空间<br> err = key_pol_get_resp(sk, xp, hdr, dir);<br> }</div>
<div> xfrm_pol_put(xp);<br> return err;<br>}</div>
<div> </div>
<div>5.13 输出整个SPD</div>
<div>static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br> struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };<br>// 遍历策略链表输出策略, dump_sa是输出单一SP的函数<br> return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data);<br>}</div>
<div>// 输出单一SP<br>static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)<br>{<br> struct pfkey_dump_data *data = ptr;<br> struct sk_buff *out_skb;<br> struct sadb_msg *out_hdr;</div>
<div>// 将安全策略填充到skb前的准备操作<br> out_skb = pfkey_xfrm_policy2msg_prep(xp);<br> if (IS_ERR(out_skb))<br> return PTR_ERR(out_skb);</div>
<div>// 将安全策略填充到skb<br> pfkey_xfrm_policy2msg(out_skb, xp, dir);</div>
<div>// 填充基本SA消息头<br> out_hdr = (struct sadb_msg *) out_skb->data;<br> out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;<br> out_hdr->sadb_msg_type = SADB_X_SPDDUMP;<br> out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;<br> out_hdr->sadb_msg_errno = 0;<br>// SA消息的序号<br> out_hdr->sadb_msg_seq = count;<br> out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;<br>// 发送到指定的sock<br> pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);<br> return 0;<br>}</div>
<div><br>/* net/xfrm/xfrm_policy.c */<br>// 遍历安全策略<br>int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),<br> void *data)<br>{<br> struct xfrm_policy *pol;<br> struct hlist_node *entry;<br> int dir, count, error;</div>
<div> read_lock_bh(&xfrm_policy_lock);<br> count = 0;<br>// 先统计符合类型的策略的数量, 方向是双向的<br> for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {<br> struct hlist_head *table = xfrm_policy_bydst.table;<br> int i;<br>// inexact HASH表<br> hlist_for_each_entry(pol, entry,<br> &xfrm_policy_inexact, bydst) {<br> if (pol->type == type)<br> count++;<br> }<br>// bydst HASH表<br> for (i = xfrm_policy_bydst.hmask; i >= 0; i--) {<br> hlist_for_each_entry(pol, entry, table + i, bydst) {<br> if (pol->type == type)<br> count++;<br> }<br> }<br> }</div>
<div> if (count == 0) {<br> error = -ENOENT;<br> goto out;<br> }<br>// 重新遍历HASH表, 当前的count值作为SA的序号, 因此用户空间收到的序号是递减的<br> for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {<br> struct hlist_head *table = xfrm_policy_bydst.table;<br> int i;</div>
<div> hlist_for_each_entry(pol, entry,<br> &xfrm_policy_inexact, bydst) {<br> if (pol->type != type)<br> continue;<br> error = func(pol, dir % XFRM_POLICY_MAX, --count, data);<br> if (error)<br> goto out;<br> }<br> for (i = xfrm_policy_bydst.hmask; i >= 0; i--) {<br> hlist_for_each_entry(pol, entry, table + i, bydst) {<br> if (pol->type != type)<br> continue;<br> error = func(pol, dir % XFRM_POLICY_MAX, --count, data);<br> if (error)<br> goto out;<br> }<br> }<br> }<br> error = 0;<br>out:<br> read_unlock_bh(&xfrm_policy_lock);<br> return error;<br>}<br>EXPORT_SYMBOL(xfrm_policy_walk);</div>
<div><br>5.14 删除全部SPD<br> = pfkey_spdflush,</div>
<div>// 删除全部SP<br>static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br> struct km_event c;<br>// 删除全部MAIN类型的SP<br> xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN);<br> c.data.type = XFRM_POLICY_TYPE_MAIN;<br> c.event = XFRM_MSG_FLUSHPOLICY;<br> c.pid = hdr->sadb_msg_pid;<br> c.seq = hdr->sadb_msg_seq;<br>// 通知回调处理<br> km_policy_notify(NULL, 0, &c);</div>
<div> return 0;<br>}</div>
<div>// 删除SP回调<br>static int key_notify_policy_flush(struct km_event *c)<br>{<br> struct sk_buff *skb_out;<br> struct sadb_msg *hdr;</div>
<div>// 分配skb<br> skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);<br> if (!skb_out)<br> return -ENOBUFS;<br> hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));<br>// SA消息类型为删除所有SP<br> hdr->sadb_msg_type = SADB_X_SPDFLUSH;<br> hdr->sadb_msg_seq = c->seq;<br> hdr->sadb_msg_pid = c->pid;<br> hdr->sadb_msg_version = PF_KEY_V2;<br> hdr->sadb_msg_errno = (uint8_t) 0;<br> hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));<br>// 广播给所有打开PF_KEY类型套接口的用户进程<br> pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);<br> return 0;</div>
<div>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 删除全部安全策略<br>void xfrm_policy_flush(u8 type)<br>{<br> int dir;</div>
<div> write_lock_bh(&xfrm_policy_lock);<br> for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {<br> struct xfrm_policy *pol;<br> struct hlist_node *entry;<br> int i, killed;</div>
<div> killed = 0;<br> again1:<br>// 遍历inexact HASH链表<br> hlist_for_each_entry(pol, entry,<br> &xfrm_policy_inexact, bydst) {<br>// 判断类型<br> if (pol->type != type)<br> continue;<br>// 将策略从bydst链表中断开<br> hlist_del(&pol->bydst);<br>// 将策略从byidt链表中断开<br> hlist_del(&pol->byidx);<br> write_unlock_bh(&xfrm_policy_lock);<br>// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除<br> xfrm_policy_kill(pol);<br> killed++;</div>
<div> write_lock_bh(&xfrm_policy_lock);<br> goto again1;<br> }<br>// 遍历bydst HASH链表<br> for (i = xfrm_policy_bydst.hmask; i >= 0; i--) {<br> again2:<br> hlist_for_each_entry(pol, entry,<br> xfrm_policy_bydst.table + i,<br> bydst) {<br> if (pol->type != type)<br> continue;<br>// 将节点从链表中断开<br> hlist_del(&pol->bydst);<br> hlist_del(&pol->byidx);<br> write_unlock_bh(&xfrm_policy_lock);<br>// 释放节点<br> xfrm_policy_kill(pol);<br> killed++;</div>
<div> write_lock_bh(&xfrm_policy_lock);<br> goto again2;<br> }<br> }</div>
<div> xfrm_policy_count -= killed;<br> }<br> atomic_inc(&flow_cache_genid);<br> write_unlock_bh(&xfrm_policy_lock);<br>}<br>EXPORT_SYMBOL(xfrm_policy_flush);</div>
<div><br>...... 待续 ......</div>
页:
[1]