• switchdev(二)


    void br_set_state(struct net_bridge_port *p, unsigned int state)
    {
        struct switchdev_attr attr = {
            .orig_dev = p->dev,
            .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE,
            .flags = SWITCHDEV_F_DEFER,
            .u.stp_state = state,
        };
        int err;
    
        p->state = state;
        err = switchdev_port_attr_set(p->dev, &attr);
        if (err && err != -EOPNOTSUPP)
            br_warn(p->br, "error setting offload STP state on port %u(%s)
    ",
                    (unsigned int) p->port_no, p->dev->name);
        else
            br_info(p->br, "port %u(%s) entered %s state
    ",
                    (unsigned int) p->port_no, p->dev->name,
                    br_port_state_names[p->state]);
    }
    /* Caller must hold RTNL. */
    int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
    {
        struct trie *t = (struct trie *)tb->tb_data;
        struct fib_alias *fa, *new_fa;
        struct key_vector *l, *tp;
        struct fib_info *fi;
        u8 plen = cfg->fc_dst_len;
        u8 slen = KEYLENGTH - plen;
        u8 tos = cfg->fc_tos;
        u32 key;
        int err;
    
        if (plen > KEYLENGTH)
            return -EINVAL;
    
        key = ntohl(cfg->fc_dst);
    
        pr_debug("Insert table=%u %08x/%d
    ", tb->tb_id, key, plen);
    
        if ((plen < KEYLENGTH) && (key << plen))
            return -EINVAL;
    
        fi = fib_create_info(cfg);
        if (IS_ERR(fi)) {
            err = PTR_ERR(fi);
            goto err;
        }
    
        l = fib_find_node(t, &tp, key);
        fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority) : NULL;
    
        /* Now fa, if non-NULL, points to the first fib alias
         * with the same keys [prefix,tos,priority], if such key already
         * exists or to the node before which we will insert new one.
         *
         * If fa is NULL, we will need to allocate a new one and
         * insert to the tail of the section matching the suffix length
         * of the new alias.
         */
    
        if (fa && fa->fa_tos == tos &&
            fa->fa_info->fib_priority == fi->fib_priority) {
            struct fib_alias *fa_first, *fa_match;
    
            err = -EEXIST;
            if (cfg->fc_nlflags & NLM_F_EXCL)
                goto out;
    
            /* We have 2 goals:
             * 1. Find exact match for type, scope, fib_info to avoid
             * duplicate routes
             * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
             */
            fa_match = NULL;
            fa_first = fa;
            hlist_for_each_entry_from(fa, fa_list) {
                if ((fa->fa_slen != slen) || (fa->fa_tos != tos))
                    break;
                if (fa->fa_info->fib_priority != fi->fib_priority)
                    break;
                if (fa->fa_type == cfg->fc_type &&
                    fa->fa_info == fi) {
                    fa_match = fa;
                    break;
                }
            }
    
            if (cfg->fc_nlflags & NLM_F_REPLACE) {
                struct fib_info *fi_drop;
                u8 state;
    
                fa = fa_first;
                if (fa_match) {
                    if (fa == fa_match)
                        err = 0;
                    goto out;
                }
                err = -ENOBUFS;
                new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
                if (new_fa == NULL)
                    goto out;
    
                fi_drop = fa->fa_info;
                new_fa->fa_tos = fa->fa_tos;
                new_fa->fa_info = fi;
                new_fa->fa_type = cfg->fc_type;
                state = fa->fa_state;
                new_fa->fa_state = state & ~FA_S_ACCESSED;
                new_fa->fa_slen = fa->fa_slen;
    
                err = netdev_switch_fib_ipv4_add(key, plen, fi,
                                 new_fa->fa_tos,
                                 cfg->fc_type,
                                 cfg->fc_nlflags,
                                 tb->tb_id);
                if (err) {
                    netdev_switch_fib_ipv4_abort(fi);
                    kmem_cache_free(fn_alias_kmem, new_fa);
                    goto out;
                }
    
                hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list);
    
                alias_free_mem_rcu(fa);
    
                fib_release_info(fi_drop);
                if (state & FA_S_ACCESSED)
                    rt_cache_flush(cfg->fc_nlinfo.nl_net);
                rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
                    tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
    
                goto succeeded;
            }
            /* Error if we find a perfect match which
             * uses the same scope, type, and nexthop
             * information.
             */
            if (fa_match)
                goto out;
    
            if (!(cfg->fc_nlflags & NLM_F_APPEND))
                fa = fa_first;
        }
        err = -ENOENT;
        if (!(cfg->fc_nlflags & NLM_F_CREATE))
            goto out;
    
        err = -ENOBUFS;
        new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
        if (new_fa == NULL)
            goto out;
    
        new_fa->fa_info = fi;
        new_fa->fa_tos = tos;
        new_fa->fa_type = cfg->fc_type;
        new_fa->fa_state = 0;
        new_fa->fa_slen = slen;
    
        /* (Optionally) offload fib entry to switch hardware. */
        err = netdev_switch_fib_ipv4_add(key, plen, fi, tos,
                         cfg->fc_type,
                         cfg->fc_nlflags,
                         tb->tb_id);
        if (err) {
            netdev_switch_fib_ipv4_abort(fi);
            goto out_free_new_fa;
        }
    
        /* Insert new entry to the list. */
        err = fib_insert_alias(t, tp, l, new_fa, fa, key);
        if (err)
            goto out_sw_fib_del;
    
        if (!plen)
            tb->tb_num_default++;
    
        rt_cache_flush(cfg->fc_nlinfo.nl_net);
        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
              &cfg->fc_nlinfo, 0);
    succeeded:
        return 0;
    
    out_sw_fib_del:
        netdev_switch_fib_ipv4_del(key, plen, fi, tos, cfg->fc_type, tb->tb_id);
    out_free_new_fa:
        kmem_cache_free(fn_alias_kmem, new_fa);
    out:
        fib_release_info(fi);
    err:
        return err;
    }
    /**
     *    netdev_switch_fib_ipv4_add - Add IPv4 route entry to switch
     *
     *    @dst: route's IPv4 destination address
     *    @dst_len: destination address length (prefix length)
     *    @fi: route FIB info structure
     *    @tos: route TOS
     *    @type: route type
     *    @nlflags: netlink flags passed in (NLM_F_*)
     *    @tb_id: route table ID
     *
     *    Add IPv4 route entry to switch device.
     */
    int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
                       u8 tos, u8 type, u32 nlflags, u32 tb_id)
    {
        struct net_device *dev;
        const struct swdev_ops *ops;
        int err = 0;
    
        /* Don't offload route if using custom ip rules or if
         * IPv4 FIB offloading has been disabled completely.
         */
    
    #ifdef CONFIG_IP_MULTIPLE_TABLES
        if (fi->fib_net->ipv4.fib_has_custom_rules)
            return 0;
    #endif
    
        if (fi->fib_net->ipv4.fib_offload_disabled)
            return 0;
    
        dev = netdev_switch_get_dev_by_nhs(fi);
        if (!dev)
            return 0;
        ops = dev->swdev_ops;
    
        if (ops->swdev_fib_ipv4_add) {
            err = ops->swdev_fib_ipv4_add(dev, htonl(dst), dst_len,
                              fi, tos, type, nlflags,
                              tb_id);
            if (!err)
                fi->fib_flags |= RTNH_F_OFFLOAD;
        }
    
        return err;
    }
    EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_add);
  • 相关阅读:
    说说我当初是如何学Linux的
    案例八:shell自动化管理账本脚本
    案例七:shell实现开机自动播放挂载本地yum仓库程序
    案例六:shell脚本监控httpd服务80端口状态
    案例五:shell脚本实现定时监控http服务的运行状态
    案例四:Shell脚本生成随机密码
    案例三:shell统计ip访问情况并分析访问日志
    案例二:shell脚本获取当前日期和时间及磁盘使情况
    案例一:shell脚本指定日期减去一天
    Linux:保证数据安全落盘
  • 原文地址:https://www.cnblogs.com/dream397/p/12835522.html
Copyright © 2020-2023  润新知