ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

邻居表的proxy_qlen长度和proxy_delay延时参数

2020-11-24 22:57:02  阅读:281  来源: 互联网

标签:arp qlen dev delay proxy skb tbl


proxy_qlen控制邻居代理缓存的报文数量,proxy_delay定义处理需要代理的arp报文的时间间隔。对于arp协议,内核默认的proxy_qlen为64,proxy_delay为80。

通过PROC文件proxy_qlen可查看和修改其值。

$ cat /proc/sys/net/ipv4/neigh/ens33/proxy_qlen 
64
$ cat /proc/sys/net/ipv4/neigh/ens33/proxy_delay 
80

在arp邻居表arp_tbl中将NEIGH_VAR_PROXY_QLEN索引所对应的表项初始化为64,将NEIGH_VAR_PROXY_DELAY索引所对应的表项初始化为HZ值的8/10,对于内核如果HZ为1000,其值为800;而对于用户层面,HZ为100,其值为80。

struct neigh_table arp_tbl = {
    .family     = AF_INET,
    .key_len    = 4,
    .protocol   = cpu_to_be16(ETH_P_IP),
    .hash       = arp_hash,
    .key_eq     = arp_key_eq,
    .constructor    = arp_constructor,
    .proxy_redo = parp_redo,
    .id     = "arp_cache",
    .parms      = {
        .tbl            = &arp_tbl,
        .reachable_time     = 30 * HZ,
        .data   = {
            [NEIGH_VAR_PROXY_QLEN] = 64,
			[NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,

内核中静态变量neigh_sysctl_table定义了proxy_qlen和proxy_delay的PROC文件信息。

static struct neigh_sysctl_table {
    struct ctl_table_header *sysctl_header;
    struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
} neigh_sysctl_template __read_mostly = {
    .neigh_vars = {
		...
		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),

netlink接口

除了以上的PROC文件外,还可使用ip ntable命令查看和修改设备的邻居表参数proxy_qlen和proxy_delay的值。

# $ ip ntable show dev ens33
inet arp_cache 
    dev ens33 
    refcnt 1 reachable 37268 base_reachable 30000 retrans 1000 
    gc_stale 60000 delay_probe 5000 queue 101 
    app_probes 0 ucast_probes 3 mcast_probes 3 
    anycast_delay 1000 proxy_delay 800 proxy_queue 64 locktime 1000 
	
inet6 ndisc_cache 
    dev ens33 
    refcnt 1 reachable 31516 base_reachable 30000 retrans 1000 
    gc_stale 60000 delay_probe 5000 queue 101 
    app_probes 0 ucast_probes 3 mcast_probes 3 
    anycast_delay 1000 proxy_delay 800 proxy_queue 64 locktime 0 

对于proxy_qlen,与PROC文件不同,这里使用的名称为proxy_queue,其值等于64。这里显示的proxy_delay值为毫秒值。如下将设备ens33的邻居表参数proxy_queue修改为128。将proxy_delay设置为1000,即1秒钟。

# ip ntable change name arp_cache dev ens33 proxy_queue 128
# ip ntable change name arp_cache dev ens33 proxy_delay 1000

内核函数neightbl_set负责以上ip ntable change命令的处理。函数nla_get_u32读取IP命令行设置的proxy_queue的值。对于arp协议,宏NEIGH_VAR_SET将修改全局变量arp_tbl的成员parms的data数组,具体为以NEIGH_VAR_PROXY_QLEN索引所对应的成员的值。

函数nla_get_msecs读取IP命令行设置的proxy_delay的值。对于arp协议,宏NEIGH_VAR_SET将修改全局变量arp_tbl的成员parms的data数组,具体为以NEIGH_VAR_PROXY_DELAY索引所对应的成员的值。

static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack)
{
    struct neigh_table *tbl;
    struct nlattr *tb[NDTA_MAX+1];
	
    if (tb[NDTA_PARMS]) {
	    struct neigh_parms *p;
	    p = lookup_neigh_parms(tbl, net, ifindex);
        ...
        for (i = 1; i <= NDTPA_MAX; i++) {
            if (tbp[i] == NULL) continue;
            switch (i) {
            ...
            case NDTPA_PROXY_QLEN:
                NEIGH_VAR_SET(p, PROXY_QLEN,
                          nla_get_u32(tbp[i]));
                break;
            case NDTPA_PROXY_DELAY:
                NEIGH_VAR_SET(p, PROXY_DELAY,
                          nla_get_msecs(tbp[i]));
                break;

显示命令ip ntable show由内核中的函数neightbl_fill_parms处理,,负责填充内核中proxy_queue和proxy_delay的参数值,对于proxy_queue的值,由nla_put_u32函数由邻居表参数中取出并进行填充。对于proxy_delay的值,由nla_put_msecs函数由邻居表参数中取出并转换为毫秒值进行填充。

static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
{
    ...
    if ((parms->dev &&
         ...
        nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
        nla_put_msecs(skb, NDTPA_PROXY_DELAY,
              NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||

proxy_qlen和proxy_delay处理

首先看一下arp代理相关的几个控制开关,默认值都是0,不开启。

$ cat /proc/sys/net/ipv4/conf/ens33/forwarding 
0
$ cat /proc/sys/net/ipv4/conf/ens33/proxy_arp
0
$ cat /proc/sys/net/ipv4/conf/ens33/proxy_arp_pvlan 
0
$ cat /proc/sys/net/ipv4/conf/ens33/medium_id 
0

在arp报文处理函数arp_process中,如果arp报文的目标IP不是本机IP地址,即addr_type不等于RTN_LOCAL,但是,满足以下几个条件:

1) 接收arp报文的网络接口(in_dev)开启了转发功能(以上的forwarding文件值不为0);
2) 目标IP地址为单播(addr_type == RTN_UNICAST);
3) 满足以下任一一个条件:
3a) 接口开启了代理转发功能(以上proxy_arp文件值不为0);
3b) 接口开启了Private-vlan转发功能(以上的proxy_arp_pvlan文件中不为0);
3c) 目标IP地址对应的路由出口设备与接收arp报文的接口设备不同,并且,找到了代理邻居表项。

static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    ...
    if (arp->ar_op == htons(ARPOP_REQUEST) &&
        ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
        rt = skb_rtable(skb);
        addr_type = rt->rt_type;
               
        if (addr_type == RTN_LOCAL) {
            ...
        } else if (IN_DEV_FORWARD(in_dev)) {
            if (addr_type == RTN_UNICAST  &&
                (arp_fwd_proxy(in_dev, dev, rt) ||
                 arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
                 (rt->dst.dev != dev &&
                  pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) {
                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                if (n) neigh_release(n);

如果此arp报文已经添加到代理邻居队列中(标志LOCALLY_ENQUEUED),或者报文的物理地址就是本机(PACKET_HOST),再或者proxy_delay设置为零的情况,立即回复arp,使用接收设备的硬件地址。否则,执行代理的入队列操作,参见函数pneigh_enqueue。

                if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
                    skb->pkt_type == PACKET_HOST ||
                    NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) {
                    arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
                             sip, dev, tip, sha,
                             dev->dev_addr, sha,
                             reply_dst);
                } else {
                    pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
                    goto out_free_dst;
                }
                goto out_consume_skb;

如下函数pneigh_enqueue,如果邻居处理队列长度超过proxy_qlen设定的值,释放当前报文,不再进行处理。否则,将报文添加到proxy_queue队列的尾部,并且,将队列处理定时器的下一次超时时长设置为不超过proxy_delay时长的一个随机值。

代理队列超时处理函数neigh_proxy_process可能会再次调用arp_process处理队列中的报文。

void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
            struct sk_buff *skb)
{
    unsigned long now = jiffies;

    unsigned long sched_next = now + (prandom_u32() %
                      NEIGH_VAR(p, PROXY_DELAY));

    if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
        kfree_skb(skb);
        return;
    }

    NEIGH_CB(skb)->sched_next = sched_next;
    NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;

    spin_lock(&tbl->proxy_queue.lock);
    if (del_timer(&tbl->proxy_timer)) {
        if (time_before(tbl->proxy_timer.expires, sched_next))
            sched_next = tbl->proxy_timer.expires;
    }
    skb_dst_drop(skb);
    dev_hold(skb->dev);
    __skb_queue_tail(&tbl->proxy_queue, skb);
    mod_timer(&tbl->proxy_timer, sched_next);
    spin_unlock(&tbl->proxy_queue.lock);
}

内核版本 5.0

标签:arp,qlen,dev,delay,proxy,skb,tbl
来源: https://blog.csdn.net/sinat_20184565/article/details/110099790

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有