学无先后,达者为师

网站首页 编程语言 正文

接口状态与策略路由表

作者:redwingz 更新时间: 2022-08-15 编程语言

添加如下的路由策略:

# ip rule add from 10.0.1.3 oif ens33 lookup 10
# 
# ip rule
0:      from all lookup local
32760:  from 10.0.1.3 lookup 10
32766:  from all lookup main
32767:  from all lookup default

在策略路由表10中,添加默认网关192.168.0.40。查看可见出接口为ens33。

# ip route add default via 192.168.0.40 table 10
# 
# 
# ip route show table 10
default via 192.168.0.40 dev ens33 

如下删除接口ens33接口上的IP地址,路由规则还在,但是路由表10中的ens33相关表项已经被清除,导致策略路由失效。

# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.4  netmask 255.255.255.0  broadcast 192.168.0.255

# 
# ip addr del 192.168.0.4/24 dev ens33
#
# ip rule
0:      from all lookup local
32760:  from 10.0.1.3 lookup 10
32766:  from all lookup main
32767:  from all lookup default
#
# ip route show table 10  
#

或者将出接口ens33设置为down状态,也将清除路由表10中的路由表项。这导致在接口UP/DOWN,或者修改接口地址时,要重新下发策略路由表中的表项。

# ip link set ens33 down

路由项删除

如下在地址删除处理中,向inetaddr_chain链发送NETDEV_DOWN消息。

static void __inet_del_ifa(struct in_device *in_dev,
               struct in_ifaddr __rcu **ifap,
               int destroy, struct nlmsghdr *nlh, u32 portid)
{

    rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
    blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);

路由子系统在inetaddr_chain上注册了处理函数fib_inetaddr_event,由函数fib_del_ifaddr处理IP地址删除事件。如果此接口上没有IP地址,由函数fib_disable_ip处理。

static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
{
    struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;

    switch (event) {
    case NETDEV_DOWN:
        fib_del_ifaddr(ifa, NULL);
        atomic_inc(&net->ipv4.dev_addr_genid);
        if (!ifa->ifa_dev->ifa_list) {
            /* Last address was deleted from this interface.
             * Disable IP.
             */
            fib_disable_ip(dev, event, true);
        }

如下fib_disable_ip函数,处理路由表项及缓存的删除。

static void fib_disable_ip(struct net_device *dev, unsigned long event,
               bool force)
{
    if (fib_sync_down_dev(dev, event, force))
        fib_flush(dev_net(dev));
    else
        rt_cache_flush(dev_net(dev));
    arp_ifdown(dev);

遍历接口设备相关联的路由表项,将下一跳设置为RTNH_F_DEAD。

int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force)
{    
    int scope = RT_SCOPE_NOWHERE;
    unsigned int hash = fib_devindex_hashfn(dev->ifindex);
    struct hlist_head *head = &fib_info_devhash[hash];

    hlist_for_each_entry(nh, head, nh_hash) {
        struct fib_info *fi = nh->nh_parent;

        if (nh->fib_nh_dev != dev || fi == prev_fi)
            continue;
        change_nexthops(fi) {
            if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD)
                dead++;
            else if (nexthop_nh->fib_nh_dev == dev &&
                 nexthop_nh->fib_nh_scope != scope) {
                switch (event) {
                case NETDEV_DOWN:
                case NETDEV_UNREGISTER:
                    nexthop_nh->fib_nh_flags |= RTNH_F_DEAD;

最后,fib_flush遍历命名空间中所有的路由表,已经每个表中的路由项,删除设置了RTNH_F_DEAD标志的表项。

void fib_flush(struct net *net)
{
    for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
        struct hlist_head *head = &net->ipv4.fib_table_hash[h];
        struct hlist_node *tmp;
        struct fib_table *tb;

        hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
            flushed += fib_table_flush(net, tb, false);
    }

    if (flushed)
        rt_cache_flush(net);

内核版本 5.10

原文链接:https://blog.csdn.net/sinat_20184565/article/details/126325194

栏目分类
最近更新