上次分析了策略规则的添加、查找,本节将分析策略规则的删除功能。对于策略规则来说,策略规则一般是通过应用层手动添加的,是不可能自动学习的,且策略规则一般来说都是一直有效的,因此对于策略规则来说,就不存在所谓的垃圾回收机制了,对于策略规则来说,只能通过手工删除操作,而不能像路由缓存、连接跟踪项一样,有异步的垃圾回收机制。
本节我们就分析下策略规则删除相关的接口函数,一般来说,应用层通过socket的ioctl机制或者netlink机制来调用该接口函数实现策略规则的删除。
1.fib_nl_delrule
应用层通过netlink向kernel传递删除规则的命令后,kernel就会通过调用函数fib_nl_delrule来实现策略规则的删除。
下面就分析一下这个函数:
功能:根据应用层传递的参数,删除符合要求的fib rule
1.根据应用层传递的协议类型,获取相应三层协议定义的fib_rules_ops
2.对应用层传递的参数进行解析
3.遍历协议对应的fib_rules_ops->rules_list,查找符合条件的fib rule,并将
该fib rule从fib_rules_ops->rules_list表中删除,并调用fib_rule_put减去对该fib rule
的引用计数并决定是否释放该fib rule占用的缓存
int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct fib_rule_hdr *frh = nlmsg_data(nlh);
struct fib_rules_ops *ops = NULL;
struct fib_rule *rule;
struct nlattr *tb[FRA_MAX+1];
int err = -EINVAL;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
goto errout;
ops = lookup_rules_ops(frh->family);
if (ops == NULL) {
err = EAFNOSUPPORT;
goto errout;
}
err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy);
if (err < 0)
goto errout;
err = validate_rulemsg(frh, tb, ops);
if (err < 0)
goto errout;
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;
goto errout;
}
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);
return 0;
}
err = -ENOENT;
errout:
rules_ops_put(ops);
return err;
}
对于删除操作来说,只需要遍历协议相关的fib rule的链表,找到符合条件的fib rule,然后将其从策略规则的链表中删除即可。至此也算分析完了策略规则这个模块,下一节分析路由缓存相关的知识。