Convert neighbour code to new netlink api
Subsystems (2)
PATCH 1/1 Convert neighbour code to new netlink api
Pretty much straight forward, some minor fixes that go along with it.
PATCH 1/7 : Convert neighbour deletion to new netlink api
Fixes:
Return ENOENT if the neighbour is not found (was EINVAL) Return EAFNOSUPPORT if no table matches the specified address family.
net/core/neighbour.c +34 -19
@@ -30,6 +30,7 @@#include <net/dst.h> #include <net/sock.h> #include <net/netevent.h> +#include <net/netlink.h> #include <linux/rtnetlink.h> #include <linux/random.h> #include <linux/string.h>
@@ -1437,48 +1438,62 @@ int neigh_table_clear(struct neigh_tableint neigh_delete (struct sk_buff *skb,struct nlmsghdr *nlh,void *arg) { -struct ndmsg *ndm =NLMSG_DATA (nlh); -struct rtattr **nda = arg; +struct ndmsg *ndm; +struct nlattr *dst_attr;struct neigh_table *tbl;struct net_device *dev =NULL ; -int err = -ENODEV ; +int err = -EINVAL ; -if (ndm->ndm_ifindex && - (dev =dev_get_by_index (ndm->ndm_ifindex)) ==NULL ) +if (nlmsg_len (nlh) <sizeof (*ndm)) + goto out; + + dst_attr =nlmsg_find_attr (nlh,sizeof (*ndm),NDA_DST ); +if (dst_attr ==NULL ) goto out; + ndm =nlmsg_data (nlh); +if (ndm->ndm_ifindex) { + dev =dev_get_by_index (ndm->ndm_ifindex); +if (dev ==NULL ) { + err = -ENODEV ; + goto out; + } + } +read_lock (&neigh_tbl_lock);for (tbl = neigh_tables; tbl; tbl = tbl->next) { -struct rtattr *dst_attr = nda[NDA_DST -1 ]; -struct neighbour *n; +struct neighbour *neigh;if (tbl->family != ndm->ndm_family)continue ;read_unlock (&neigh_tbl_lock); - err = -EINVAL ; -if (!dst_attr ||RTA_PAYLOAD (dst_attr) < tbl->key_len) +if (nla_len (dst_attr) < tbl->key_len) goto out_dev_put;if (ndm->ndm_flags &NTF_PROXY ) { - err =pneigh_delete (tbl,RTA_DATA (dst_attr), dev); + err =pneigh_delete (tbl,nla_data (dst_attr), dev); goto out_dev_put; } -if (!dev) - goto out; +if (dev ==NULL ) + goto out_dev_put; - n =neigh_lookup (tbl,RTA_DATA (dst_attr), dev); -if (n) { - err =neigh_update (n,NULL ,NUD_FAILED , -NEIGH_UPDATE_F_OVERRIDE | -NEIGH_UPDATE_F_ADMIN ); -neigh_release (n); + neigh =neigh_lookup (tbl,nla_data (dst_attr), dev); +if (neigh ==NULL ) { + err = -ENOENT ; + goto out_dev_put; } + + err =neigh_update (neigh,NULL ,NUD_FAILED , +NEIGH_UPDATE_F_OVERRIDE | +NEIGH_UPDATE_F_ADMIN ); +neigh_release (neigh); goto out_dev_put; }read_unlock (&neigh_tbl_lock); - err = -EADDRNOTAVAIL ; + err = -EAFNOSUPPORT ; + out_dev_put:if (dev)dev_put (dev);
PATCH 2/7 : Convert neighbour addition to new netlink api
In reply to Thomas GrafFixes:
Return EAFNOSUPPORT if no table matches the specified address family.
net/core/neighbour.c +51 -39
@@ -1503,76 +1503,88 @@ out:int neigh_add (struct sk_buff *skb,struct nlmsghdr *nlh,void *arg) { -struct ndmsg *ndm =NLMSG_DATA (nlh); -struct rtattr **nda = arg; +struct ndmsg *ndm; +struct nlattr *tb[NDA_MAX +1 ];struct neigh_table *tbl;struct net_device *dev =NULL ; -int err = -ENODEV ; +int err; + + err =nlmsg_parse (nlh,sizeof (*ndm), tb,NDA_MAX ,NULL ); +if (err <0 ) + goto out; -if (ndm->ndm_ifindex && - (dev =dev_get_by_index (ndm->ndm_ifindex)) ==NULL ) + err = -EINVAL ; +if (tb[NDA_DST ] ==NULL ) goto out; + ndm =nlmsg_data (nlh); +if (ndm->ndm_ifindex) { + dev =dev_get_by_index (ndm->ndm_ifindex); +if (dev ==NULL ) { + err = -ENODEV ; + goto out; + } + +if (tb[NDA_LLADDR ] &&nla_len (tb[NDA_LLADDR ]) < dev->addr_len) + goto out_dev_put; + } +read_lock (&neigh_tbl_lock);for (tbl = neigh_tables; tbl; tbl = tbl->next) { -struct rtattr *lladdr_attr = nda[NDA_LLADDR -1 ]; -struct rtattr *dst_attr = nda[NDA_DST -1 ]; -int override =1 ; -struct neighbour *n; +int flags =NEIGH_UPDATE_F_ADMIN |NEIGH_UPDATE_F_OVERRIDE ; +struct neighbour *neigh; +void *dst, *lladdr;if (tbl->family != ndm->ndm_family)continue ;read_unlock (&neigh_tbl_lock); - err = -EINVAL ; -if (!dst_attr ||RTA_PAYLOAD (dst_attr) < tbl->key_len) +if (nla_len (tb[NDA_DST ]) < tbl->key_len) goto out_dev_put; + dst =nla_data (tb[NDA_DST ]); + lladdr = tb[NDA_LLADDR ] ?nla_data (tb[NDA_LLADDR ]) :NULL ;if (ndm->ndm_flags &NTF_PROXY ) { - err = -ENOBUFS ; -if (pneigh_lookup (tbl,RTA_DATA (dst_attr), dev,1 )) - err =0 ; + err =0 ; +if (pneigh_lookup (tbl, dst, dev,1 ) ==NULL ) + err = -ENOBUFS ; goto out_dev_put; } - err = -EINVAL ; -if (!dev) - goto out; -if (lladdr_attr &&RTA_PAYLOAD (lladdr_attr) < dev->addr_len) +if (dev ==NULL ) goto out_dev_put; + + neigh =neigh_lookup (tbl, dst, dev); +if (neigh ==NULL ) { +if (!(nlh->nlmsg_flags &NLM_F_CREATE )) { + err = -ENOENT ; + goto out_dev_put; + } - n =neigh_lookup (tbl,RTA_DATA (dst_attr), dev); -if (n) { -if (nlh->nlmsg_flags &NLM_F_EXCL ) { - err = -EEXIST ; -neigh_release (n); + neigh =__neigh_lookup_errno (tbl, dst, dev); +if (IS_ERR (neigh)) { + err =PTR_ERR (neigh); goto out_dev_put; } - - override = nlh->nlmsg_flags &NLM_F_REPLACE ; - }else if (!(nlh->nlmsg_flags &NLM_F_CREATE )) { - err = -ENOENT ; - goto out_dev_put; }else { - n =__neigh_lookup_errno (tbl,RTA_DATA (dst_attr), dev); -if (IS_ERR (n)) { - err =PTR_ERR (n); +if (nlh->nlmsg_flags &NLM_F_EXCL ) { + err = -EEXIST ; +neigh_release (neigh); goto out_dev_put; } - } - err =neigh_update (n, - lladdr_attr ?RTA_DATA (lladdr_attr) :NULL , - ndm->ndm_state, - (override ?NEIGH_UPDATE_F_OVERRIDE :0 ) | -NEIGH_UPDATE_F_ADMIN ); +if (!(nlh->nlmsg_flags &NLM_F_REPLACE )) + flags &= ~NEIGH_UPDATE_F_OVERRIDE ; + } -neigh_release (n); + err =neigh_update (neigh, lladdr, ndm->ndm_state, flags); +neigh_release (neigh); goto out_dev_put; }read_unlock (&neigh_tbl_lock); - err = -EADDRNOTAVAIL ; + err = -EAFNOSUPPORT ; + out_dev_put:if (dev)dev_put (dev);
PATCH 3/7 : Convert neighbour dumping to new netlink api
In reply to Thomas Grafnet/core/neighbour.c +51 -55
@@ -1898,48 +1898,49 @@ out:return skb->len; } -static int neigh_fill_info (struct sk_buff *skb,struct neighbour *n, -u32 pid,u32 seq,int event,unsigned int flags) +static int neigh_fill_info (struct sk_buff *skb,struct neighbour *neigh, +u32 pid,u32 seq,int type,unsigned int flags) {unsigned long now = jiffies; -unsigned char *b = skb->tail;struct nda_cacheinfo ci; -int locked =0 ; -u32 probes; -struct nlmsghdr *nlh =NLMSG_NEW (skb, pid, seq, event, -sizeof (struct ndmsg ), flags); -struct ndmsg *ndm =NLMSG_DATA (nlh); +struct nlmsghdr *nlh; +struct ndmsg *ndm; + + nlh =nlmsg_put (skb, pid, seq, type,sizeof (*ndm), flags); +if (nlh ==NULL ) +return -ENOBUFS ; - ndm->ndm_family = n->ops->family; + ndm =nlmsg_data (nlh); + ndm->ndm_family = neigh->ops->family; ndm->ndm_pad1 =0 ; ndm->ndm_pad2 =0 ; - ndm->ndm_flags = n->flags; - ndm->ndm_type = n->type; - ndm->ndm_ifindex = n->dev->ifindex; -RTA_PUT (skb,NDA_DST , n->tbl->key_len, n->primary_key); -read_lock_bh (&n->lock); - locked =1 ; - ndm->ndm_state = n->nud_state; -if (n->nud_state &NUD_VALID ) -RTA_PUT (skb,NDA_LLADDR , n->dev->addr_len, n->ha); - ci.ndm_used = now - n->used; - ci.ndm_confirmed = now - n->confirmed; - ci.ndm_updated = now - n->updated; - ci.ndm_refcnt =atomic_read (&n->refcnt) -1 ; - probes =atomic_read (&n->probes); -read_unlock_bh (&n->lock); - locked =0 ; -RTA_PUT (skb,NDA_CACHEINFO ,sizeof (ci), &ci); -RTA_PUT (skb,NDA_PROBES ,sizeof (probes), &probes); - nlh->nlmsg_len = skb->tail - b; -return skb->len; + ndm->ndm_flags = neigh->flags; + ndm->ndm_type = neigh->type; + ndm->ndm_ifindex = neigh->dev->ifindex; + +NLA_PUT (skb,NDA_DST , neigh->tbl->key_len, neigh->primary_key); + +read_lock_bh (&neigh->lock); + ndm->ndm_state = neigh->nud_state; +if ((neigh->nud_state &NUD_VALID ) && +nla_put (skb,NDA_LLADDR , neigh->dev->addr_len, neigh->ha) <0 ) { +read_unlock_bh (&neigh->lock); + goto nla_put_failure; + } -nlmsg_failure: -rtattr_failure: -if (locked) -read_unlock_bh (&n->lock); -skb_trim (skb, b - skb->data); -return -1 ; + ci.ndm_used = now - neigh->used; + ci.ndm_confirmed = now - neigh->confirmed; + ci.ndm_updated = now - neigh->updated; + ci.ndm_refcnt =atomic_read (&neigh->refcnt) -1 ; +read_unlock_bh (&neigh->lock); + +NLA_PUT_U32 (skb,NDA_PROBES ,atomic_read (&neigh->probes)); +NLA_PUT (skb,NDA_CACHEINFO ,sizeof (ci), &ci); + +return nlmsg_end (skb, nlh); + +nla_put_failure: +return nlmsg_cancel (skb, nlh); }
@@ -1983,7 +1984,7 @@ int neigh_dump_info(struct sk_buff *skb,int t, family, s_t;read_lock (&neigh_tbl_lock); - family = ((struct rtgenmsg *)NLMSG_DATA (cb->nlh))->rtgen_family; + family = ((struct rtgenmsg *)nlmsg_data (cb->nlh))->rtgen_family; s_t = cb->args[0 ];for (tbl = neigh_tables, t =0 ; tbl; tbl = tbl->next, t++) {
@@ -2364,39 +2365,34 @@ static struct file_operations neigh_stat#ifdef CONFIG_ARPD void neigh_app_ns (struct neighbour *n) { -struct nlmsghdr *nlh; -int size =NLMSG_SPACE (sizeof (struct ndmsg ) +256 ); -struct sk_buff *skb =alloc_skb (size,GFP_ATOMIC ); +struct sk_buff *skb; -if (!skb) + skb =nlmsg_new (NLMSG_GOODSIZE ,GFP_ATOMIC ); +if (skb ==NULL )return ; -if (neigh_fill_info (skb, n,0 ,0 ,RTM_GETNEIGH ,0 ) <0 ) { +if (neigh_fill_info (skb, n,0 ,0 ,RTM_GETNEIGH ,NLM_F_REQUEST ) <=0 )kfree_skb (skb); -return ; +else { +NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; +netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); } - nlh = (struct nlmsghdr *)skb->data; - nlh->nlmsg_flags =NLM_F_REQUEST ; -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); }static void neigh_app_notify (struct neighbour *n) { -struct nlmsghdr *nlh; -int size =NLMSG_SPACE (sizeof (struct ndmsg ) +256 ); -struct sk_buff *skb =alloc_skb (size,GFP_ATOMIC ); +struct sk_buff *skb; -if (!skb) + skb =nlmsg_new (NLMSG_GOODSIZE ,GFP_ATOMIC ); +if (skb ==NULL )return ; -if (neigh_fill_info (skb, n,0 ,0 ,RTM_NEWNEIGH ,0 ) <0 ) { +if (neigh_fill_info (skb, n,0 ,0 ,RTM_NEWNEIGH ,0 ) <=0 )kfree_skb (skb); -return ; +else { +NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; +netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); } - nlh = (struct nlmsghdr *)skb->data; -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); }#endif /* CONFIG_ARPD */
PATCH 4/7 : Move netlink neighbour bits to linux/neighbour.h
In reply to Thomas GrafMoves netlink neighbour bits to linux/neighbour.h. Also moves bits to be exported to userspace from net/neighbour.h to linux/neighbour.h and removes __KERNEL__ guards, userspace is not supposed to be using it.
rtnetlink_rcv_msg() is not longer required to parse attributes for the neighbour layer, remove dependency on obsolete and buggy rta_buf.
include/linux/neighbour.h new file +65 -0
@@ -0,0 +1,65 @@ +#ifndef __LINUX_NEIGHBOUR_H +#define __LINUX_NEIGHBOUR_H + +#include <linux/netlink.h> + +struct ndmsg +{ +__u8 ndm_family; +__u8 ndm_pad1; +__u16 ndm_pad2; +__s32 ndm_ifindex; +__u16 ndm_state; +__u8 ndm_flags; +__u8 ndm_type; +}; + +enum +{ +NDA_UNSPEC , +NDA_DST , +NDA_LLADDR , +NDA_CACHEINFO , +NDA_PROBES , + __NDA_MAX +}; + +#define NDA_MAX (__NDA_MAX - 1) + +/* +* Neighbor Cache Entry Flags +*/ + +#define NTF_PROXY 0x08/* == ATF_PUBL */ +#define NTF_ROUTER 0x80 + +/* +* Neighbor Cache Entry States. +*/ + +#define NUD_INCOMPLETE 0x01 +#define NUD_REACHABLE 0x02 +#define NUD_STALE 0x04 +#define NUD_DELAY 0x08 +#define NUD_PROBE 0x10 +#define NUD_FAILED 0x20 + +/* Dummy states */ +#define NUD_NOARP 0x40 +#define NUD_PERMANENT 0x80 +#define NUD_NONE 0x00 + +/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change +and make no address resolution or NUD. +NUD_PERMANENT is also cannot be deleted by garbage collectors. +*/ + +struct nda_cacheinfo +{ +__u32 ndm_confirmed; +__u32 ndm_used; +__u32 ndm_updated; +__u32 ndm_refcnt; +}; + +#endif
include/linux/rtnetlink.h +0 -63
69 lines not on this page · raw message
include/net/neighbour.h +2 -37
@@ -1,6 +1,8 @@#ifndef _NET_NEIGHBOUR_H#define _NET_NEIGHBOUR_H +#include <linux/neighbour.h> +/* * Generic neighbour manipulation *
@@ -14,40 +16,6 @@* - Add neighbour cache statistics like rtstat */ -/* The following flags & states are exported to user space, -so that they should be moved to include/linux/ directory. -*/ - -/* -* Neighbor Cache Entry Flags -*/ - -#define NTF_PROXY 0x08/* == ATF_PUBL */ -#define NTF_ROUTER 0x80 - -/* -* Neighbor Cache Entry States. -*/ - -#define NUD_INCOMPLETE 0x01 -#define NUD_REACHABLE 0x02 -#define NUD_STALE 0x04 -#define NUD_DELAY 0x08 -#define NUD_PROBE 0x10 -#define NUD_FAILED 0x20 - -/* Dummy states */ -#define NUD_NOARP 0x40 -#define NUD_PERMANENT 0x80 -#define NUD_NONE 0x00 - -/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change -and make no address resolution or NUD. -NUD_PERMANENT is also cannot be deleted by garbage collectors. -*/ - -#ifdef __KERNEL__ -#include <asm/atomic.h> #include <linux/netdevice.h> #include <linux/skbuff.h>
@@ -374,6 +342,3 @@ struct neighbour_cb {#define NEIGH_CB (skb) ((struct neighbour_cb *)(skb)->cb)#endif -#endif - -
net/core/rtnetlink.c +0 -2
@@ -104,7 +104,6 @@ static const int rtm_min[RTM_NR_FAMILIES [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), - [RTM_FAM(RTM_NEWNEIGH)] = NLMSG_LENGTH(sizeof(struct ndmsg)), [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
@@ -121,7 +120,6 @@ static const int rta_max[RTM_NR_FAMILIES [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, - [RTM_FAM(RTM_NEWNEIGH)] = NDA_MAX, [RTM_FAM(RTM_NEWRULE)] = FRA_MAX, [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX,
PATCH 5/7 : Convert neighbour table modification to new netlink api
In reply to Thomas Grafnet/core/neighbour.c +104 -68
@@ -1751,28 +1751,61 @@ static inline struct neigh_parms *lookupreturn NULL ; } +static struct nla_policy nl_neightbl_policy[NDTA_MAX +1 ]__read_mostly = { + [NDTA_NAME ] = { .type =NLA_STRING }, + [NDTA_THRESH1 ] = { .type =NLA_U32 }, + [NDTA_THRESH2 ] = { .type =NLA_U32 }, + [NDTA_THRESH3 ] = { .type =NLA_U32 }, + [NDTA_GC_INTERVAL ] = { .type =NLA_U64 }, + [NDTA_PARMS ] = { .type =NLA_NESTED }, +}; + +static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX +1 ]__read_mostly = { + [NDTPA_IFINDEX ] = { .type =NLA_U32 }, + [NDTPA_QUEUE_LEN ] = { .type =NLA_U32 }, + [NDTPA_PROXY_QLEN ] = { .type =NLA_U32 }, + [NDTPA_APP_PROBES ] = { .type =NLA_U32 }, + [NDTPA_UCAST_PROBES ] = { .type =NLA_U32 }, + [NDTPA_MCAST_PROBES ] = { .type =NLA_U32 }, + [NDTPA_BASE_REACHABLE_TIME ] = { .type =NLA_U64 }, + [NDTPA_GC_STALETIME ] = { .type =NLA_U64 }, + [NDTPA_DELAY_PROBE_TIME ] = { .type =NLA_U64 }, + [NDTPA_RETRANS_TIME ] = { .type =NLA_U64 }, + [NDTPA_ANYCAST_DELAY ] = { .type =NLA_U64 }, + [NDTPA_PROXY_DELAY ] = { .type =NLA_U64 }, + [NDTPA_LOCKTIME ] = { .type =NLA_U64 }, +}; +int neightbl_set (struct sk_buff *skb,struct nlmsghdr *nlh,void *arg) {struct neigh_table *tbl; -struct ndtmsg *ndtmsg =NLMSG_DATA (nlh); -struct rtattr **tb = arg; -int err = -EINVAL ; +struct ndtmsg *ndtmsg; +struct nlattr *tb[NDTA_MAX +1 ]; +int err; + + err =nlmsg_parse (nlh,sizeof (*ndtmsg), tb,NDTA_MAX , + nl_neightbl_policy); +if (err <0 ) + goto errout; -if (!tb[NDTA_NAME -1 ] || !RTA_PAYLOAD (tb[NDTA_NAME -1 ])) -return -EINVAL ; +if (tb[NDTA_NAME ] ==NULL ) { + err = -EINVAL ; + goto errout; + } + ndtmsg =nlmsg_data (nlh);read_lock (&neigh_tbl_lock);for (tbl = neigh_tables; tbl; tbl = tbl->next) {if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)continue ; -if (!rtattr_strcmp (tb[NDTA_NAME -1 ], tbl->id)) +if (nla_strcmp (tb[NDTA_NAME ], tbl->id) ==0 )break ; }if (tbl ==NULL ) { err = -ENOENT ; - goto errout; + goto errout_locked; }/*
@@ -1781,86 +1814,89 @@ int neightbl_set(struct sk_buff *skb, st*/ write_lock_bh (&tbl->lock); -if (tb[NDTA_THRESH1 -1 ]) - tbl->gc_thresh1 =RTA_GET_U32 (tb[NDTA_THRESH1 -1 ]); - -if (tb[NDTA_THRESH2 -1 ]) - tbl->gc_thresh2 =RTA_GET_U32 (tb[NDTA_THRESH2 -1 ]); - -if (tb[NDTA_THRESH3 -1 ]) - tbl->gc_thresh3 =RTA_GET_U32 (tb[NDTA_THRESH3 -1 ]); - -if (tb[NDTA_GC_INTERVAL -1 ]) - tbl->gc_interval =RTA_GET_MSECS (tb[NDTA_GC_INTERVAL -1 ]); - -if (tb[NDTA_PARMS -1 ]) { -struct rtattr *tbp[NDTPA_MAX ]; +if (tb[NDTA_PARMS ]) { +struct nlattr *tbp[NDTPA_MAX +1 ];struct neigh_parms *p; -u32 ifindex =0 ; +int i, ifindex =0 ; -if (rtattr_parse_nested (tbp,NDTPA_MAX , tb[NDTA_PARMS -1 ]) <0 ) - goto rtattr_failure; + err =nla_parse_nested (tbp,NDTPA_MAX , tb[NDTA_PARMS ], + nl_ntbl_parm_policy); +if (err <0 ) + goto errout_tbl_lock; -if (tbp[NDTPA_IFINDEX -1 ]) - ifindex =RTA_GET_U32 (tbp[NDTPA_IFINDEX -1 ]); +if (tbp[NDTPA_IFINDEX ]) + ifindex =nla_get_u32 (tbp[NDTPA_IFINDEX ]); p =lookup_neigh_params (tbl, ifindex);if (p ==NULL ) { err = -ENOENT ; - goto rtattr_failure; + goto errout_tbl_lock; } - -if (tbp[NDTPA_QUEUE_LEN -1 ]) - p->queue_len =RTA_GET_U32 (tbp[NDTPA_QUEUE_LEN -1 ]); - -if (tbp[NDTPA_PROXY_QLEN -1 ]) - p->proxy_qlen =RTA_GET_U32 (tbp[NDTPA_PROXY_QLEN -1 ]); - -if (tbp[NDTPA_APP_PROBES -1 ]) - p->app_probes =RTA_GET_U32 (tbp[NDTPA_APP_PROBES -1 ]); -if (tbp[NDTPA_UCAST_PROBES -1 ]) - p->ucast_probes = -RTA_GET_U32 (tbp[NDTPA_UCAST_PROBES -1 ]); - -if (tbp[NDTPA_MCAST_PROBES -1 ]) - p->mcast_probes = -RTA_GET_U32 (tbp[NDTPA_MCAST_PROBES -1 ]); - -if (tbp[NDTPA_BASE_REACHABLE_TIME -1 ]) - p->base_reachable_time = -RTA_GET_MSECS (tbp[NDTPA_BASE_REACHABLE_TIME -1 ]); - -if (tbp[NDTPA_GC_STALETIME -1 ]) - p->gc_staletime = -RTA_GET_MSECS (tbp[NDTPA_GC_STALETIME -1 ]); +for (i =1 ; i <=NDTPA_MAX ; i++) { +if (tbp[i] ==NULL ) +continue ; -if (tbp[NDTPA_DELAY_PROBE_TIME -1 ]) - p->delay_probe_time = -RTA_GET_MSECS (tbp[NDTPA_DELAY_PROBE_TIME -1 ]); +switch (i) { +case NDTPA_QUEUE_LEN : + p->queue_len =nla_get_u32 (tbp[i]); +break ; +case NDTPA_PROXY_QLEN : + p->proxy_qlen =nla_get_u32 (tbp[i]); +break ; +case NDTPA_APP_PROBES : + p->app_probes =nla_get_u32 (tbp[i]); +break ; +case NDTPA_UCAST_PROBES : + p->ucast_probes =nla_get_u32 (tbp[i]); +break ; +case NDTPA_MCAST_PROBES : + p->mcast_probes =nla_get_u32 (tbp[i]); +break ; +case NDTPA_BASE_REACHABLE_TIME : + p->base_reachable_time =nla_get_msecs (tbp[i]); +break ; +case NDTPA_GC_STALETIME : + p->gc_staletime =nla_get_msecs (tbp[i]); +break ; +case NDTPA_DELAY_PROBE_TIME : + p->delay_probe_time =nla_get_msecs (tbp[i]); +break ; +case NDTPA_RETRANS_TIME : + p->retrans_time =nla_get_msecs (tbp[i]); +break ; +case NDTPA_ANYCAST_DELAY : + p->anycast_delay =nla_get_msecs (tbp[i]); +break ; +case NDTPA_PROXY_DELAY : + p->proxy_delay =nla_get_msecs (tbp[i]); +break ; +case NDTPA_LOCKTIME : + p->locktime =nla_get_msecs (tbp[i]); +break ; + } + } + } -if (tbp[NDTPA_RETRANS_TIME -1 ]) - p->retrans_time = -RTA_GET_MSECS (tbp[NDTPA_RETRANS_TIME -1 ]); +if (tb[NDTA_THRESH1 ]) + tbl->gc_thresh1 =nla_get_u32 (tb[NDTA_THRESH1 ]); -if (tbp[NDTPA_ANYCAST_DELAY -1 ]) - p->anycast_delay = -RTA_GET_MSECS (tbp[NDTPA_ANYCAST_DELAY -1 ]); +if (tb[NDTA_THRESH2 ]) + tbl->gc_thresh2 =nla_get_u32 (tb[NDTA_THRESH2 ]); -if (tbp[NDTPA_PROXY_DELAY -1 ]) - p->proxy_delay = -RTA_GET_MSECS (tbp[NDTPA_PROXY_DELAY -1 ]); +if (tb[NDTA_THRESH3 ]) + tbl->gc_thresh3 =nla_get_u32 (tb[NDTA_THRESH3 ]); -if (tbp[NDTPA_LOCKTIME -1 ]) - p->locktime =RTA_GET_MSECS (tbp[NDTPA_LOCKTIME -1 ]); - } +if (tb[NDTA_GC_INTERVAL ]) + tbl->gc_interval =nla_get_msecs (tb[NDTA_GC_INTERVAL ]); err =0 ; -rtattr_failure: +errout_tbl_lock:write_unlock_bh (&tbl->lock); -errout: +errout_locked:read_unlock (&neigh_tbl_lock); +errout:return err; }
PATCH 6/7 : Convert neighbour table dumping to new netlink api
In reply to Thomas GrafAlso fixes skipping of already dumped neighbours.
net/core/neighbour.c +73 -66
@@ -1594,56 +1594,59 @@ out:static int neightbl_fill_parms (struct sk_buff *skb,struct neigh_parms *parms) { -struct rtattr *nest =NULL ; - - nest =RTA_NEST (skb,NDTA_PARMS ); +struct nlattr *nest; + + nest =nla_nest_start (skb,NDTA_PARMS ); +if (nest ==NULL ) +return -ENOBUFS ;if (parms->dev) -RTA_PUT_U32 (skb,NDTPA_IFINDEX , parms->dev->ifindex); +NLA_PUT_U32 (skb,NDTPA_IFINDEX , parms->dev->ifindex); -RTA_PUT_U32 (skb,NDTPA_REFCNT ,atomic_read (&parms->refcnt)); -RTA_PUT_U32 (skb,NDTPA_QUEUE_LEN , parms->queue_len); -RTA_PUT_U32 (skb,NDTPA_PROXY_QLEN , parms->proxy_qlen); -RTA_PUT_U32 (skb,NDTPA_APP_PROBES , parms->app_probes); -RTA_PUT_U32 (skb,NDTPA_UCAST_PROBES , parms->ucast_probes); -RTA_PUT_U32 (skb,NDTPA_MCAST_PROBES , parms->mcast_probes); -RTA_PUT_MSECS (skb,NDTPA_REACHABLE_TIME , parms->reachable_time); -RTA_PUT_MSECS (skb,NDTPA_BASE_REACHABLE_TIME , +NLA_PUT_U32 (skb,NDTPA_REFCNT ,atomic_read (&parms->refcnt)); +NLA_PUT_U32 (skb,NDTPA_QUEUE_LEN , parms->queue_len); +NLA_PUT_U32 (skb,NDTPA_PROXY_QLEN , parms->proxy_qlen); +NLA_PUT_U32 (skb,NDTPA_APP_PROBES , parms->app_probes); +NLA_PUT_U32 (skb,NDTPA_UCAST_PROBES , parms->ucast_probes); +NLA_PUT_U32 (skb,NDTPA_MCAST_PROBES , parms->mcast_probes); +NLA_PUT_MSECS (skb,NDTPA_REACHABLE_TIME , parms->reachable_time); +NLA_PUT_MSECS (skb,NDTPA_BASE_REACHABLE_TIME , parms->base_reachable_time); -RTA_PUT_MSECS (skb,NDTPA_GC_STALETIME , parms->gc_staletime); -RTA_PUT_MSECS (skb,NDTPA_DELAY_PROBE_TIME , parms->delay_probe_time); -RTA_PUT_MSECS (skb,NDTPA_RETRANS_TIME , parms->retrans_time); -RTA_PUT_MSECS (skb,NDTPA_ANYCAST_DELAY , parms->anycast_delay); -RTA_PUT_MSECS (skb,NDTPA_PROXY_DELAY , parms->proxy_delay); -RTA_PUT_MSECS (skb,NDTPA_LOCKTIME , parms->locktime); +NLA_PUT_MSECS (skb,NDTPA_GC_STALETIME , parms->gc_staletime); +NLA_PUT_MSECS (skb,NDTPA_DELAY_PROBE_TIME , parms->delay_probe_time); +NLA_PUT_MSECS (skb,NDTPA_RETRANS_TIME , parms->retrans_time); +NLA_PUT_MSECS (skb,NDTPA_ANYCAST_DELAY , parms->anycast_delay); +NLA_PUT_MSECS (skb,NDTPA_PROXY_DELAY , parms->proxy_delay); +NLA_PUT_MSECS (skb,NDTPA_LOCKTIME , parms->locktime); -return RTA_NEST_END (skb, nest); +return nla_nest_end (skb, nest); -rtattr_failure: -return RTA_NEST_CANCEL (skb, nest); +nla_put_failure: +return nla_nest_cancel (skb, nest); } -static int neightbl_fill_info (struct neigh_table *tbl,struct sk_buff *skb, -struct netlink_callback *cb) +static int neightbl_fill_info (struct sk_buff *skb,struct neigh_table *tbl, +u32 pid,u32 seq,int type,int flags) {struct nlmsghdr *nlh;struct ndtmsg *ndtmsg; - nlh =NLMSG_NEW_ANSWER (skb, cb,RTM_NEWNEIGHTBL ,sizeof (struct ndtmsg ), -NLM_F_MULTI ); + nlh =nlmsg_put (skb, pid, seq, type,sizeof (*ndtmsg), flags); +if (nlh ==NULL ) +return -ENOBUFS ; - ndtmsg =NLMSG_DATA (nlh); + ndtmsg =nlmsg_data (nlh);read_lock_bh (&tbl->lock); ndtmsg->ndtm_family = tbl->family; ndtmsg->ndtm_pad1 =0 ; ndtmsg->ndtm_pad2 =0 ; -RTA_PUT_STRING (skb,NDTA_NAME , tbl->id); -RTA_PUT_MSECS (skb,NDTA_GC_INTERVAL , tbl->gc_interval); -RTA_PUT_U32 (skb,NDTA_THRESH1 , tbl->gc_thresh1); -RTA_PUT_U32 (skb,NDTA_THRESH2 , tbl->gc_thresh2); -RTA_PUT_U32 (skb,NDTA_THRESH3 , tbl->gc_thresh3); +NLA_PUT_STRING (skb,NDTA_NAME , tbl->id); +NLA_PUT_MSECS (skb,NDTA_GC_INTERVAL , tbl->gc_interval); +NLA_PUT_U32 (skb,NDTA_THRESH1 , tbl->gc_thresh1); +NLA_PUT_U32 (skb,NDTA_THRESH2 , tbl->gc_thresh2); +NLA_PUT_U32 (skb,NDTA_THRESH3 , tbl->gc_thresh3); {unsigned long now = jiffies;
@@ -1662,7 +1665,7 @@ static int neightbl_fill_info(struct nei .ndtc_proxy_qlen = tbl->proxy_queue.qlen, }; -RTA_PUT (skb,NDTA_CONFIG ,sizeof (ndc), &ndc); +NLA_PUT (skb,NDTA_CONFIG ,sizeof (ndc), &ndc); } {
@@ -1687,55 +1690,50 @@ static int neightbl_fill_info(struct nei ndst.ndts_forced_gc_runs += st->forced_gc_runs; } -RTA_PUT (skb,NDTA_STATS ,sizeof (ndst), &ndst); +NLA_PUT (skb,NDTA_STATS ,sizeof (ndst), &ndst); }BUG_ON (tbl->parms.dev);if (neightbl_fill_parms (skb, &tbl->parms) <0 ) - goto rtattr_failure; + goto nla_put_failure;read_unlock_bh (&tbl->lock); -return NLMSG_END (skb, nlh); +return nlmsg_end (skb, nlh); -rtattr_failure: +nla_put_failure:read_unlock_bh (&tbl->lock); -return NLMSG_CANCEL (skb, nlh); - -nlmsg_failure: -return -1 ; +return nlmsg_cancel (skb, nlh); } -static int neightbl_fill_param_info (struct neigh_table *tbl, +static int neightbl_fill_param_info (struct sk_buff *skb, +struct neigh_table *tbl,struct neigh_parms *parms, -struct sk_buff *skb, -struct netlink_callback *cb) +u32 pid,u32 seq,int type, +unsigned int flags) {struct ndtmsg *ndtmsg;struct nlmsghdr *nlh; - nlh =NLMSG_NEW_ANSWER (skb, cb,RTM_NEWNEIGHTBL ,sizeof (struct ndtmsg ), -NLM_F_MULTI ); + nlh =nlmsg_put (skb, pid, seq, type,sizeof (*ndtmsg), flags); +if (nlh ==NULL ) +return -ENOBUFS ; - ndtmsg =NLMSG_DATA (nlh); + ndtmsg =nlmsg_data (nlh);read_lock_bh (&tbl->lock); ndtmsg->ndtm_family = tbl->family; ndtmsg->ndtm_pad1 =0 ; ndtmsg->ndtm_pad2 =0 ; -RTA_PUT_STRING (skb,NDTA_NAME , tbl->id); -if (neightbl_fill_parms (skb, parms) <0 ) - goto rtattr_failure; +if (nla_put_string (skb,NDTA_NAME , tbl->id) <0 || +neightbl_fill_parms (skb, parms) <0 ) + goto errout;read_unlock_bh (&tbl->lock); -return NLMSG_END (skb, nlh); - -rtattr_failure: +return nlmsg_end (skb, nlh); +errout:read_unlock_bh (&tbl->lock); -return NLMSG_CANCEL (skb, nlh); - -nlmsg_failure: -return -1 ; +return nlmsg_cancel (skb, nlh); } static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
@@ -1902,34 +1900,43 @@ errout:int neightbl_dump_info (struct sk_buff *skb,struct netlink_callback *cb) { -int idx, family; -int s_idx = cb->args[0 ]; +int family, tidx, nidx =0 ; +int tbl_skip = cb->args[0 ]; +int neigh_skip = cb->args[1 ];struct neigh_table *tbl; - family = ((struct rtgenmsg *)NLMSG_DATA (cb->nlh))->rtgen_family; + family = ((struct rtgenmsg *)nlmsg_data (cb->nlh))->rtgen_family;read_lock (&neigh_tbl_lock); -for (tbl = neigh_tables, idx =0 ; tbl; tbl = tbl->next) { +for (tbl = neigh_tables, tidx =0 ; tbl; tbl = tbl->next, tidx++) {struct neigh_parms *p; -if (idx < s_idx || (family && tbl->family != family)) +if (tidx < tbl_skip || (family && tbl->family != family))continue ; -if (neightbl_fill_info (tbl, skb, cb) <=0 ) +if (neightbl_fill_info (skb, tbl,NETLINK_CB (cb->skb).pid, + cb->nlh->nlmsg_seq,RTM_NEWNEIGHTBL , +NLM_F_MULTI ) <=0 )break ; -for (++idx, p = tbl->parms.next; p; p = p->next, idx++) { -if (idx < s_idx) +for (nidx =0 , p = tbl->parms.next; p; p = p->next, nidx++) { +if (nidx < neigh_skip)continue ; -if (neightbl_fill_param_info (tbl, p, skb, cb) <=0 ) +if (neightbl_fill_param_info (skb, tbl, p, +NETLINK_CB (cb->skb).pid, + cb->nlh->nlmsg_seq, +RTM_NEWNEIGHTBL , +NLM_F_MULTI ) <=0 ) goto out; } + neigh_skip =0 ; } out:read_unlock (&neigh_tbl_lock); - cb->args[0 ] = idx; + cb->args[0 ] = tidx; + cb->args[1 ] = nidx;return skb->len; }
PATCH 7/7 : Move netlink neighbour table bits to linux/neighbour.h
In reply to Thomas Grafrtnetlink_rcv_msg() is not longer required to parse attributes for the neighbour tables layer, remove dependency on obsolete and buggy rta_buf.
include/linux/neighbour.h +94 -0
@@ -62,4 +62,98 @@ struct nda_cacheinfo__u32 ndm_refcnt; }; +/***************************************************************** +* Neighbour tables specific messages. +* +* To retrieve the neighbour tables send RTM_GETNEIGHTBL with the +* NLM_F_DUMP flag set. Every neighbour table configuration is +* spread over multiple messages to avoid running into message +* size limits on systems with many interfaces. The first message +* in the sequence transports all not device specific data such as +* statistics, configuration, and the default parameter set. +* This message is followed by 0..n messages carrying device +* specific parameter sets. +* Although the ordering should be sufficient, NDTA_NAME can be +* used to identify sequences. The initial message can be identified +* by checking for NDTA_CONFIG. The device specific messages do +* not contain this TLV but have NDTPA_IFINDEX set to the +* corresponding interface index. +* +* To change neighbour table attributes, send RTM_SETNEIGHTBL +* with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], +* NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked +* otherwise. Device specific parameter sets can be changed by +* setting NDTPA_IFINDEX to the interface index of the corresponding +* device. +****/ + +struct ndt_stats +{ +__u64 ndts_allocs; +__u64 ndts_destroys; +__u64 ndts_hash_grows; +__u64 ndts_res_failed; +__u64 ndts_lookups; +__u64 ndts_hits; +__u64 ndts_rcv_probes_mcast; +__u64 ndts_rcv_probes_ucast; +__u64 ndts_periodic_gc_runs; +__u64 ndts_forced_gc_runs; +}; + +enum { +NDTPA_UNSPEC , +NDTPA_IFINDEX ,/* u32, unchangeable */ +NDTPA_REFCNT ,/* u32, read-only */ +NDTPA_REACHABLE_TIME ,/* u64, read-only, msecs */ +NDTPA_BASE_REACHABLE_TIME ,/* u64, msecs */ +NDTPA_RETRANS_TIME ,/* u64, msecs */ +NDTPA_GC_STALETIME ,/* u64, msecs */ +NDTPA_DELAY_PROBE_TIME ,/* u64, msecs */ +NDTPA_QUEUE_LEN ,/* u32 */ +NDTPA_APP_PROBES ,/* u32 */ +NDTPA_UCAST_PROBES ,/* u32 */ +NDTPA_MCAST_PROBES ,/* u32 */ +NDTPA_ANYCAST_DELAY ,/* u64, msecs */ +NDTPA_PROXY_DELAY ,/* u64, msecs */ +NDTPA_PROXY_QLEN ,/* u32 */ +NDTPA_LOCKTIME ,/* u64, msecs */ + __NDTPA_MAX +}; +#define NDTPA_MAX (__NDTPA_MAX - 1) + +struct ndtmsg +{ +__u8 ndtm_family; +__u8 ndtm_pad1; +__u16 ndtm_pad2; +}; + +struct ndt_config +{ +__u16 ndtc_key_len; +__u16 ndtc_entry_size; +__u32 ndtc_entries; +__u32 ndtc_last_flush;/* delta to now in msecs */ +__u32 ndtc_last_rand;/* delta to now in msecs */ +__u32 ndtc_hash_rnd; +__u32 ndtc_hash_mask; +__u32 ndtc_hash_chain_gc; +__u32 ndtc_proxy_qlen; +}; + +enum { +NDTA_UNSPEC , +NDTA_NAME ,/* char *, unchangeable */ +NDTA_THRESH1 ,/* u32 */ +NDTA_THRESH2 ,/* u32 */ +NDTA_THRESH3 ,/* u32 */ +NDTA_CONFIG ,/* struct ndt_config, read-only */ +NDTA_PARMS ,/* nested TLV NDTPA_* */ +NDTA_STATS ,/* struct ndt_stats, read-only */ +NDTA_GC_INTERVAL ,/* u64, msecs */ + __NDTA_MAX +}; +#define NDTA_MAX (__NDTA_MAX - 1) +#endif
include/linux/rtnetlink.h +0 -101
107 lines not on this page · raw message
net/core/rtnetlink.c +0 -2
@@ -112,7 +112,6 @@ static const int rtm_min[RTM_NR_FAMILIES [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), - [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)), }; static const int rta_max[RTM_NR_FAMILIES] =
@@ -125,7 +124,6 @@ static const int rta_max[RTM_NR_FAMILIES [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, - [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX, };void __rta_fill (struct sk_buff *skb,int attrtype,int attrlen,const void *data)
David Miller
maintainerFrom: Thomas Graf <[email protected]>
Date: Mon, 07 Aug 2006 19:09:44 +0200
Quoted 2 lines
Pretty much straight forward, some minor fixes that go along with it.
Looks good, all applied.
Thanks Thomas.