邻居表项的locktime时长

如果内核在locktime时间内接收到多个ARP报文,仅首个报文生效。对于arp协议,内核默认的locktime时长为1秒钟,可通过PROC文件或者ip命令进行修改。

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_LOCKTIME] = 1 * HZ,

通过PROC文件locktime可查看和修改此值,如下,默认为100,对应于1秒钟。

$ cat /proc/sys/net/ipv4/neigh/eth0/locktime 
100

内核中静态变量neigh_sysctl_table定义了locktime的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_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),

如下定义,locktime的处理有neigh_proc_dointvec_userhz_jiffies,其负责将内核使用的jiffies值转换为用户层面的HZ(值为100),即内核locktime初始化为1000,用户层面显示为100。

#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
    NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)

netlink接口

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

# ip ntable show dev eth0
inet arp_cache 
    dev eth0
    refcnt 12 reachable 28884 base_reachable 30000 retrans 1000 
    gc_stale 60000 delay_probe 5000 queue 31 
    app_probes 0 ucast_probes 3 mcast_probes 3 
    anycast_delay 1000 proxy_delay 800 proxy_queue 64 locktime 1000 

与PROC文件不同,这里显示的locktime单位为毫秒值。如下将设备eth0的邻居表参数locktime修改为2秒钟。

# ip ntable change name arp_cache dev eth0 base_reachable 2000

内核函数neigh_init初始化了以上ip ntable change命令的处理函数neightbl_set。

static int __init neigh_init(void)
{
    ...
    rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);

如下为neightbl_set的实现,函数nla_get_msecs读取IP命令行设置的locktime的毫秒值参数,转换为内核使用的jiffies值,设置到邻居表的参数中。对于arp协议,将设置到arp_tbl成员parms的子成员data数组中,索引位置为NEIGH_VAR_LOCKTIME。

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++) {
            switch (i) {
            ...
            case NDTPA_LOCKTIME:
                NEIGH_VAR_SET(p, LOCKTIME, nla_get_msecs(tbp[i]));

显示命令ip ntable show由内核中的函数neightbl_fill_parms填充值,对于locktime的值,由nla_put_msecs填充。

static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
{
    ...
    if ((parms->dev &&
         ...
        nla_put_msecs(skb, NDTPA_LOCKTIME,
              NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD)

如下函数nla_put_msecs,其需要将内核使用locktime的jiffies值转换为ip ntable show显示时的毫秒值,通过jiffies_to_msecs实现。

static inline int nla_put_msecs(struct sk_buff *skb, int attrtype,
                unsigned long njiffies, int padattr)
{
    u64 tmp = jiffies_to_msecs(njiffies);
  
    return nla_put_64bit(skb, attrtype, sizeof(u64), &tmp, padattr);
}

locktime处理

在arp报文处理函数arp_process中,对于连续(back-to-back)接收到的ARP回复,内核选择使用首个回复报文,因为,如果链路上存在多个活动的ARP代理,这样就选择了其中速度较快的一个,也可屏蔽一些无用的ARP回复。

内核判断连续报文的依据为locktime时长,在此段时间内接收到的ARP报文,进行更新时不设置覆盖标志位NEIGH_UPDATE_F_OVERRIDE(garp的情况除外)。

static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    ...
    /* Update our ARP tables */

    n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
    ...
    if (n) {
        int state = NUD_REACHABLE;
        int override;

        /* If several different ARP replies follows back-to-back,
           use the FIRST one. It is possible, if several proxy
           agents are active. Taking the first reply prevents
           arp trashing and chooses the fastest router.
         */
        override = time_after(jiffies,
                      n->updated +
                      NEIGH_VAR(n->parms, LOCKTIME)) || is_garp;

        /* Broadcast replies and request packets
           do not assert neighbour reachability.
         */
        if (arp->ar_op != htons(ARPOP_REPLY) || skb->pkt_type != PACKET_HOST)
            state = NUD_STALE;
        neigh_update(n, sha, state,
                 override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);

内核版本 5.0

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页