上次分析了策略规则的添加、查找,本节将分析策略规则的删除功能。对于策略规则来说,策略规则一般是通过应用层手动添加的,是不可能自动学习的,且策略规则一般来说都是一直有效的,因此对于策略规则来说,就不存在所谓的垃圾回收机制了,对于策略规则来说,只能通过手工删除操作,而不能像路由缓存、连接跟踪项一样,有异步的垃圾回收机制。
本节我们就分析下策略规则删除相关的接口函数,一般来说,应用层通过socket的ioctl机制或者netlink机制来调用该接口函数实现策略规则的删除。
1.fib_nl_delrule
应用层通过netlink向kernel传递删除规则的命令后,kernel就会通过调用函数fib_nl_delrule来实现策略规则的删除。
下面就分析一下这个函数:
功能:根据应用层传递的参数,删除符合要求的fibrule
1.根据应用层传递的协议类型,获取相应三层协议定义的fib_rules_ops
2.对应用层传递的参数进行解析
3.遍历协议对应的fib_rules_ops->rules_list,查找符合条件的fibrule,并将
该fibrule从fib_rules_ops->rules_list表中删除,并调用fib_rule_put减去对该fibrule
的引用计数并决定是否释放该fibrule占用的缓存
intfib_nl_delrule(structsk_buff*skb,structnlmsghdr*nlh,void*arg)
{
structfib_rule_hdr*frh=nlmsg_data(nlh);
structfib_rules_ops*ops=NULL;
structfib_rule*rule;
structnlattr*tb[FRA_MAX+1];
interr=-EINVAL;
if(nlh->nlmsg_len<nlmsg_msg_size(sizeof(*frh)))
gotoerrout;
ops=lookup_rules_ops(frh->family);
if(ops==NULL){
err=EAFNOSUPPORT;
gotoerrout;
}
err=nlmsg_parse(nlh,sizeof(*frh),tb,FRA_MAX,ops->policy);
if(err<0)
gotoerrout;
err=validate_rulemsg(frh,tb,ops);
if(err<0)
gotoerrout;
list_for_each_entry(rule,ops->rules_list,list){
if(frh->action&&(frh->action!=rule->action))
continue;
if(frh->table&&(frh_get_table(frh,tb)!=rule->table))
continue;
if(tb[FRA_PRIORITY]&&
(rule->pref!=nla_get_u32(tb[FRA_PRIORITY])))
continue;
if(tb[FRA_IFNAME]&&
nla_strcmp(tb[FRA_IFNAME],rule->ifname))
continue;
if(tb[FRA_FWMARK]&&
(rule->mark!=nla_get_u32(tb[FRA_FWMARK])))
continue;
if(tb[FRA_FWMASK]&&
(rule->mark_mask!=nla_get_u32(tb[FRA_FWMASK])))
continue;
if(!ops->compare(rule,frh,tb))
continue;
if(rule->flags&FIB_RULE_PERMANENT){
err=-EPERM;
gotoerrout;
}
list_del_rcu(&rule->list);
synchronize_rcu();
notify_rule_change(RTM_DELRULE,rule,ops,nlh,
NETLINK_CB(skb).pid);
fib_rule_put(rule);
rules_ops_put(ops);
return0;
}
err=-ENOENT;
errout:
rules_ops_put(ops);
returnerr;
}
对于删除操作来说,只需要遍历协议相关的fibrule的链表,找到符合条件的fibrule,然后将其从策略规则的链表中删除即可。至此也算分析完了策略规则这个模块,下一节分析路由缓存相关的知识。
从哪里跌倒就会从哪里爬起来,让我们一起努力吧