linux清理缓存cache_udp缓冲区满了,数据是否会丢失

linux清理缓存cache_udp缓冲区满了,数据是否会丢失linux 自定义模块来缓存skb的意义

大家好,又见面了,我是你们的朋友全栈君。

linux中,管理网卡收发报文的结构是sk_buff,这个结构比freebsd中的m_buf复杂的多,这个也是为什么现在用户态协议栈大多采用bsd为基础来实现的一个原因。

struct sk_buff {
    /* These two members must be first. */
    struct sk_buff        *next;-------------有没有人想过为啥不用内核标准的list来,而是单独两个成员?如果你有好的想法,可以跟我讨论。
    struct sk_buff        *prev;
#ifdef __GENKSYMS__
    ktime_t        tstamp;
#else
    union {
        ktime_t        tstamp;
        struct skb_mstamp skb_mstamp;
    };
#endif
    struct sock        *sk;
    struct net_device    *dev;

    /*
     * This is the control buffer. It is free to use for every
     * layer. Please put your private variables there. If you
     * want to keep them across layers you have to do a skb_clone()
     * first. This is owned by whoever has the skb queued ATM.
     */
    char            cb[48] __aligned(8);------------------------------------这个可以看很多private的处理

    unsigned long        _skb_refdst;
#ifdef CONFIG_XFRM
    struct    sec_path    *sp;
#endif
    unsigned int        len,
                data_len;
    __u16            mac_len,
                hdr_len;
    union {
        __wsum        csum;
        struct {
            __u16    csum_start;
            __u16    csum_offset;
        };
    };
    __u32            priority;
    kmemcheck_bitfield_begin(flags1);
    __u8            RH_KABI_RENAME(local_df, ignore_df):1,
                cloned:1,
                ip_summed:2,
                nohdr:1,
                nfctinfo:3;
    __u8            pkt_type:3,
                fclone:2,
                ipvs_property:1,
                peeked:1,
                nf_trace:1;
    kmemcheck_bitfield_end(flags1);
    __be16            protocol;

    void            (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
    struct nf_conntrack    *nfct;
#endif
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
    struct nf_bridge_info    *nf_bridge;
#endif

    /* fields enclosed in headers_start/headers_end are copied
     * using a single memcpy() in __copy_skb_header()
     */
    /* private: */
    RH_KABI_EXTEND(__u32    headers_start[0])
    /* public: */

    int            skb_iif;

    RH_KABI_REPLACE(__u32    rxhash,
            __u32    hash)

    __be16            vlan_proto;
    __u16            vlan_tci;

#ifdef CONFIG_NET_SCHED
    __u16            tc_index;    /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
    __u16            tc_verd;    /* traffic control verdict */
#endif
#endif

    __u16            queue_mapping;
    kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE
    __u8            ndisc_nodetype:2;
#endif
    __u8            pfmemalloc:1;
    __u8            ooo_okay:1;
    __u8            RH_KABI_RENAME(l4_rxhash, l4_hash):1;
    __u8            wifi_acked_valid:1;
    __u8            wifi_acked:1;
    __u8            no_fcs:1;
    __u8            head_frag:1;
    /* Indicates the inner headers are valid in the skbuff. */
    __u8            encapsulation:1;
    RH_KABI_EXTEND(__u8            encap_hdr_csum:1)-----------------------这个使用在我之前一篇博客中有描述。
    RH_KABI_EXTEND(__u8            csum_valid:1)
    RH_KABI_EXTEND(__u8            csum_complete_sw:1)
    RH_KABI_EXTEND(__u8            xmit_more:1)
    RH_KABI_EXTEND(__u8            inner_protocol_type:1)
    RH_KABI_EXTEND(__u8            remcsum_offload:1)
    /* 0/2 bit hole (depending on ndisc_nodetype presence) */
    kmemcheck_bitfield_end(flags2);

#if defined CONFIG_NET_DMA_RH_KABI || defined CONFIG_NET_RX_BUSY_POLL || defined CONFIG_XPS
    union {
        unsigned int    napi_id;
        RH_KABI_EXTEND(unsigned int    sender_cpu)
        RH_KABI_DEPRECATE(dma_cookie_t,    dma_cookie)
    };
#endif
#ifdef CONFIG_NETWORK_SECMARK
    __u32            secmark;
#endif
    union {
        __u32        mark;
        __u32        dropcount;
        __u32        reserved_tailroom;
    };

#ifdef __GENKSYMS__
    __be16            inner_protocol;
#else
    union {
        __be16        inner_protocol;
        __u8        inner_ipproto;
    };
#endif

    __u16            inner_transport_header;
    __u16            inner_network_header;
    __u16            inner_mac_header;
    __u16            transport_header;
    __u16            network_header;
    __u16            mac_header;

    RH_KABI_EXTEND(kmemcheck_bitfield_begin(flags3))
    RH_KABI_EXTEND(__u8    csum_level:2)
    RH_KABI_EXTEND(__u8    rh_csum_pad:1)
    RH_KABI_EXTEND(__u8    csum_bad:1)
    RH_KABI_EXTEND(__u8    offload_fwd_mark:1)
    RH_KABI_EXTEND(__u8    sw_hash:1)
    RH_KABI_EXTEND(__u8     csum_not_inet:1)
    RH_KABI_EXTEND(__u8    dst_pending_confirm:1)
    /* 8 bit hole */
    RH_KABI_EXTEND(kmemcheck_bitfield_end(flags3))

    /* private: */
    RH_KABI_EXTEND(__u32    headers_end[0])
    /* public: */

    /* RHEL SPECIFIC
     *
     * The following padding has been inserted before ABI freeze to
     * allow extending the structure while preserve ABI. Feel free
     * to replace reserved slots with required structure field
     * additions of your backport, eventually moving the replaced slot
     * before headers_end, if it need to be copied by __copy_skb_header()
     */
    u32            rh_reserved1;
    u32            rh_reserved2;
    u32            rh_reserved3;
    u32            rh_reserved4;

    /* These elements must be at the end, see alloc_skb() for details.  */
    sk_buff_data_t        tail;
    sk_buff_data_t        end;
    unsigned char        *head,
                *data;
    unsigned int        truesize;
    atomic_t        users;
};

skb是管理结构,目前linux 3.10是使用slub的方式来管理skb的缓存,但这个管理有没有什么问题?

据说曾经有人测试过,在2G主频上的cpu从slab中分配一个skb需要耗时4us,这个我自己没有测试过,我想如果是获取的slab位于percpu上,应该不需要这么长时间。但是只要看过slab的管理的话,应该也明白这个消耗虽然比从buddly中分配要小很多,但是从绝对值来说也不会太少。对于大量需要消耗skb的网络服务器来说,申请skb和释放skb的消耗就显得比较重了。

解决方法:

1.做一个自己的skb的缓存池,这样申请的时候,不走slab,释放的时候,也只是减少引用计数,不需要还给slab。

2.显然应该实现为percpu的模式,避免查找skb的时候,锁的消耗。

3.percpu的缓存池消耗不一,所以要有一个cpu的node级别的二级缓存池,保证各个核在的增长和消耗达到阈值之后有一个平衡,如果没绑定的话,比如对于某个流来说,完全可能在Acpu上申请,在Bcpu上释放,不要问我为什么不绑定,因为假设你用docker的话,不太适合绑定,因为虚拟网卡一般配置单队列,而且开启xps的话,是根据当前cpuid而不是根据四元组来选择tx,可能选择到不同的tx来发送报文,而各个tx明显会有忙闲的区别,docker中程序的发包很可能导致tcp乱序严重。

4.在物理机上,有条件的话尽量做flow的绑定,也就是说,某个flow只在某个cpu上运行,保证局部性,这样的话,因为flow可以和一部分skb关联,这样填充二层和三层头的动作都可以节省了,如果你觉得节省这一点无所谓的话,大可以测试一下节省掉这些memcpy的消耗,从我们的测试效果看,很好。如果把skb看做一辆货车的话,对应的二层和三层的头就可以看做司机了,你说

我们运点货,犯得着老换货车,老换司机么?肯定有人会说,我每次发送的位置又不一样,所以得拷贝二层和三层的头,那假设你大多数发包的时候长度一样呢?

5.因为是自己管理skb的缓存,所以cb 成员就可以随便怎么处理了,很多控制信息都可以放在这里,方便。

6.对于单个流需要的流量比较多的情况,比如流媒体服务器,高清发送,预占的skb可以保证时延可控。

缺点:

1.预占部分内存,通过drop_cache也放不掉,如果是缓存自增长和收缩模式,也会有一些消耗。

 

转载于:https://www.cnblogs.com/10087622blog/p/9596518.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107330.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月20日 下午3:20
下一篇 2022年4月20日 下午3:20


相关推荐

  • linux添加用户及用户权限管理命令_docker用户权限

    linux添加用户及用户权限管理命令_docker用户权限Linux添加用户及用户权限管理1.新建用户(组)①用户新建用户需要通过指令useradd来实现。useradd的一些基本用法如下:useraddusername 新建一个用户useradd-uuidusername 指定用户的uiduseradd-ggidusername 指定用户的gid(一定要存在)useradd-Ggiduseradd指定用户的附加组(…

    2025年8月2日
    4
  • 多线程(一):创建线程和线程的常用方法

    多线程(一):创建线程和线程的常用方法一:为什么要学多线程应付面试:多线程几乎是面试中必问的题,所以掌握一定的基础知识是必须的。了解并发编程:实际工作中很少写多线程的代码,这部分代码一般都被人封装起来了,在业务中使用多线程的机会也不是很多(看具体项目),但是作为一个高级程序员如果不会多线程是说不过去的。二:进程与线程进程进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统…

    2022年4月28日
    48
  • jedis与redis连接详解

    jedis与redis连接详解jedis 初始操作详解

    2026年3月16日
    2
  • 理解HTTP和TCP

    理解HTTP和TCP TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性。Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。所谓的无状态,是指浏览器每次向服…

    2025年11月20日
    6
  • 老金的公众号自动写作助手(写作通用):用GLM-4.7跑热点扫描+文章生成,还超省钱!

    老金的公众号自动写作助手(写作通用):用GLM-4.7跑热点扫描+文章生成,还超省钱!

    2026年3月12日
    2
  • mycat 插入数据,主键自增的时候 报错java.lang.RuntimeException: can‘t fetch sequnce in db,sequnce :AP_SHOW_BEHAVIO

    mycat 插入数据,主键自增的时候 报错java.lang.RuntimeException: can‘t fetch sequnce in db,sequnce :AP_SHOW_BEHAVIO问题描述 在使用 mycat 的主键生成的时候 报无法在 db 中获取序列原因分析 可能是 mycat 设置自增表中的函数不起作用解决方案 查看是否有没有的话 就要引用这个三个函数 创建全局序列所需函数 DELIMITER CREATEFUNCTI seq currval seq nameVARCHAR 50 RETURNSVARCH 64 DETERMINISTI 64 SETretval

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号