Updates for strict checking and kernel side filtering
Subsystems (3)
cover Updates for strict checking and kernel side filtering
From: David Ahern <[email protected]>
Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.
David Ahern (12):
libnetlink: dump extack string in done message
libnetlink: Use NLMSG_LENGTH to set nlmsg_len
libnetlink: linkdump_req: Only AF_UNSPEC family expects an
ext_filter_mask
ip route: Remove rtnl_rtcache_request
ip route: Add protocol, table id and device to dump request
mroute: fix up family handling
mroute: Add table id attribute for kernel side filtering ip address: Split ip_linkaddr_list into link and addr functions ip address: Set device index in dump request
ip bridge: Set NETLINK_DUMP_STRICT_CHK on socket
ip route: Rename do_ipv6 to dump_family
neighbor: Add support for protocol attribute
bridge/bridge.c | 4 ++ include/libnetlink.h | 11 +-- ip/ip.c | 2 + ip/ip_common.h | 3 +- ip/ipaddress.c | 92 ++++++++++++++++++------ ip/ipmroute.c | 31 ++++++--- ip/ipneigh.c | 39 ++++++++++- ip/iproute.c | 89 ++++++++++++------------ ip/ipvrf.c | 2 +- lib/libnetlink.c | 192 ++++++++++++++++++++++++++++++++++++++------------- 10 files changed, 330 insertions(+), 135 deletions(-)
Signature · 1 line
2.11.0
PATCH 1/12 libnetlink: dump extack string in done message
From: David Ahern <[email protected]>
Print any extack message that has been appended to a NLMSG_DONE message. To avoid duplication, move the existing print code to a new helper.
--- lib/libnetlink.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-)
lib/libnetlink.c +39 -5
@@ -67,6 +67,14 @@ static int err_attr_cb(const struct nlattr *attr, void *data)return MNL_CB_OK ; } +static void print_ext_ack_msg (bool is_err,const char *msg) +{ +fprintf (stderr,"%s: %s" , is_err ?"Error" :"Warning" , msg); +if (msg[strlen (msg) -1 ] !='.' ) +fprintf (stderr,"." ); +fprintf (stderr,"\n" ); +} +/* dump netlink extended ack error message */ int nl_dump_ext_ack (const struct nlmsghdr *nlh,nl_ext_ack_fn_t errfn) {
@@ -108,12 +116,29 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)if (msg && *msg !='\0' ) {bool is_err = !!err->error; -fprintf (stderr,"%s: %s" , - is_err ?"Error" :"Warning" , msg); -if (msg[strlen (msg) -1 ] !='.' ) -fprintf (stderr,"." ); -fprintf (stderr,"\n" ); +print_ext_ack_msg (is_err, msg); +return is_err ?1 :0 ; + } +return 0 ; +} + +static int nl_dump_ext_ack_done (const struct nlmsghdr *nlh,int error) +{ +struct nlattr *tb[NLMSGERR_ATTR_MAX +1 ] = {}; +unsigned int hlen =sizeof (int ); +const char *msg =NULL ; + +if (mnl_attr_parse (nlh, hlen, err_attr_cb, tb) !=MNL_CB_OK ) +return 0 ; + +if (tb[NLMSGERR_ATTR_MSG ]) + msg =mnl_attr_get_str (tb[NLMSGERR_ATTR_MSG ]); + +if (msg && *msg !='\0' ) { +bool is_err = !!error; + +print_ext_ack_msg (is_err, msg);return is_err ?1 :0 ; }
@@ -127,6 +152,11 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn) {return 0 ; } + +static int nl_dump_ext_ack_done (const struct nlmsghdr *nlh,int error) +{ +return 0 ; +}#endif void rtnl_close (struct rtnl_handle *rth)
@@ -512,6 +542,10 @@ static int rtnl_dump_done(struct nlmsghdr *h) }if (len <0 ) { +/* check for any messages returned from kernel */ +if (nl_dump_ext_ack_done (h, len)) +return len; + errno = -len;switch (errno) {case ENOENT :
Signature · 1 line
2.11.0
PATCH 2/12 libnetlink: Use NLMSG_LENGTH to set nlmsg_len
In reply to David AhernFrom: David Ahern <[email protected]>
Change nlmsg_len from sizeof(req) to use NLMSG_LENGTH on the header. 2 of the inner headers are not 4-byte aligned, so add a 0-length buf after the header with the __aligned(NLMSG_ALIGNTO) to ensure the size of the request is large enough. Use NLMSG_ALIGN in NLMSG_LENGTH to set nlmsg_len.
--- lib/libnetlink.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
lib/libnetlink.c +14 -10
@@ -28,6 +28,8 @@#include "libnetlink.h" +#define __aligned (x) __attribute__((aligned(x))) +#ifndef SOL_NETLINK #define SOL_NETLINK 270#endif
@@ -238,7 +240,7 @@ int rtnl_addrdump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct ifaddrmsg ifm; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), .nlh.nlmsg_type = RTM_GETADDR, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -254,7 +256,7 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct ifaddrlblmsg ifal; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)), .nlh.nlmsg_type = RTM_GETADDRLABEL, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -270,7 +272,7 @@ int rtnl_routedump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct rtmsg rtm; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), .nlh.nlmsg_type = RTM_GETROUTE, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -286,7 +288,7 @@ int rtnl_ruledump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct fib_rule_hdr frh; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), .nlh.nlmsg_type = RTM_GETRULE, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -302,7 +304,7 @@ int rtnl_neighdump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct ndmsg ndm; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), .nlh.nlmsg_type = RTM_GETNEIGH, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -318,7 +320,7 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct ndtmsg ndtmsg; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)), .nlh.nlmsg_type = RTM_GETNEIGHTBL, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -334,7 +336,7 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)struct nlmsghdr nlh;struct br_port_msg bpm; } req = { - .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)), .nlh.nlmsg_type = RTM_GETMDB, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -349,8 +351,9 @@ int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)struct {struct nlmsghdr nlh;struct netconfmsg ncm; +char buf[0 ]__aligned(NLMSG_ALIGNTO) ; } req = { - .nlh.nlmsg_len =sizeof (req), + .nlh.nlmsg_len =NLMSG_LENGTH (NLMSG_ALIGN (sizeof (struct netconfmsg ))), .nlh.nlmsg_type =RTM_GETNETCONF , .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -365,8 +368,9 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)struct {struct nlmsghdr nlh;struct rtgenmsg rtm; +char buf[0 ]__aligned(NLMSG_ALIGNTO) ; } req = { - .nlh.nlmsg_len =sizeof (req), + .nlh.nlmsg_len =NLMSG_LENGTH (NLMSG_ALIGN (sizeof (struct rtgenmsg ))), .nlh.nlmsg_type =RTM_GETNSID , .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , .nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -388,7 +392,7 @@ int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,struct nlmsghdr nlh;struct ifinfomsg ifm;/* attribute has to be NLMSG aligned */ - struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); +struct rtattr ext_req__aligned(NLMSG_ALIGNTO) ;__u32 ext_filter_mask; } req = { .nlh.nlmsg_len = sizeof(req),
Signature · 1 line
2.11.0
PATCH 3/12 libnetlink: linkdump_req: Only AF_UNSPEC family expects an ext_filter_mask
In reply to David AhernFrom: David Ahern <[email protected]>
Only AF_UNSPEC handled by rtnl_dump_ifinfo expects an ext_filter_mask on a dump request. Update the linkdump request functions to only set and send ext_filter_mask for AF_UNSPEC.
--- lib/libnetlink.c | 93 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 33 deletions(-)
lib/libnetlink.c +60 -33
@@ -380,58 +380,85 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)return send (rth->fd, &req,sizeof (req),0 ); } -int rtnl_linkdump_req (struct rtnl_handle *rth,int family) -{ -return rtnl_linkdump_req_filter (rth, family,RTEXT_FILTER_VF ); -} - -int rtnl_linkdump_req_filter (struct rtnl_handle *rth,int family, -__u32 filt_mask) +static int __rtnl_linkdump_req (struct rtnl_handle *rth,int family) {struct {struct nlmsghdr nlh;struct ifinfomsg ifm; -/* attribute has to be NLMSG aligned */ -struct rtattr ext_req__aligned(NLMSG_ALIGNTO) ; -__u32 ext_filter_mask; } req = { - .nlh.nlmsg_len =sizeof (req), + .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifinfomsg )), .nlh.nlmsg_type =RTM_GETLINK , .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , .nlh.nlmsg_seq = rth->dump = ++rth->seq, .ifm.ifi_family = family, - .ext_req.rta_type =IFLA_EXT_MASK , - .ext_req.rta_len =RTA_LENGTH (sizeof (__u32)), - .ext_filter_mask = filt_mask, };return send (rth->fd, &req,sizeof (req),0 ); } +int rtnl_linkdump_req (struct rtnl_handle *rth,int family) +{ +if (family ==AF_UNSPEC ) +return rtnl_linkdump_req_filter (rth, family,RTEXT_FILTER_VF ); + +return __rtnl_linkdump_req (rth, family); +} + +int rtnl_linkdump_req_filter (struct rtnl_handle *rth,int family, +__u32 filt_mask) +{ +if (family ==AF_UNSPEC ) { +struct { +struct nlmsghdr nlh; +struct ifinfomsg ifm; +/* attribute has to be NLMSG aligned */ +struct rtattr ext_req__aligned(NLMSG_ALIGNTO) ; +__u32 ext_filter_mask; + } req = { + .nlh.nlmsg_len =sizeof (req), + .nlh.nlmsg_type =RTM_GETLINK , + .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .ifm.ifi_family = family, + .ext_req.rta_type =IFLA_EXT_MASK , + .ext_req.rta_len =RTA_LENGTH (sizeof (__u32)), + .ext_filter_mask = filt_mask, + }; + +return send (rth->fd, &req,sizeof (req),0 ); + } + +return __rtnl_linkdump_req (rth, family); +} +int rtnl_linkdump_req_filter_fn (struct rtnl_handle *rth,int family,req_filter_fn_t filter_fn) { -struct { -struct nlmsghdr nlh; -struct ifinfomsg ifm; -char buf[1024 ]; - } req = { - .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifinfomsg )), - .nlh.nlmsg_type =RTM_GETLINK , - .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , - .nlh.nlmsg_seq = rth->dump = ++rth->seq, - .ifm.ifi_family = family, - }; -int err; - -if (!filter_fn) -return -EINVAL ; +if (family ==AF_UNSPEC ) { +struct { +struct nlmsghdr nlh; +struct ifinfomsg ifm; +char buf[1024 ]; + } req = { + .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifinfomsg )), + .nlh.nlmsg_type =RTM_GETLINK , + .nlh.nlmsg_flags =NLM_F_DUMP |NLM_F_REQUEST , + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .ifm.ifi_family = family, + }; +int err; + +if (!filter_fn) +return -EINVAL ; + + err =filter_fn (&req.nlh,sizeof (req)); +if (err) +return err; - err =filter_fn (&req.nlh,sizeof (req)); -if (err) -return err; +return send (rth->fd, &req, req.nlh.nlmsg_len,0 ); + } -return send (rth->fd, &req, req.nlh.nlmsg_len,0 ); +return __rtnl_linkdump_req (rth, family); }int rtnl_statsdump_req_filter (struct rtnl_handle *rth,int fam,__u32 filt_mask)
Signature · 1 line
2.11.0
PATCH 5/12 ip route: Add protocol, table id and device to dump request
In reply to David AhernFrom: David Ahern <[email protected]>
Add protocol, table id and device to dump request if set in filter. If kernel side filtering is supported it is used to reduce the amount of data sent to userspace.
Older kernels do not parse attributes on a route dump request, so these are silently ignored and ip will do the filtering in userspace.
--- ip/iproute.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
ip/iproute.c +14 -0
@@ -1669,10 +1669,24 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)static int iproute_dump_filter (struct nlmsghdr *nlh,int reqlen) {struct rtmsg *rtm =NLMSG_DATA (nlh); +int err; + rtm->rtm_protocol = filter.protocol;if (filter.cloned) rtm->rtm_flags |=RTM_F_CLONED ; +if (filter.tb) { + err =addattr32 (nlh, reqlen,RTA_TABLE , filter.tb); +if (err) +return err; + } + +if (filter.oif) { + err =addattr32 (nlh, reqlen,RTA_OIF , filter.oif); +if (err) +return err; + } +return 0 ; }
Signature · 1 line
2.11.0
PATCH 6/12 mroute: fix up family handling
In reply to David AhernFrom: David Ahern <[email protected]>
Only ipv4 and ipv6 have multicast routing. Set family accordingly and just return for other cases.
--- ip/ipmroute.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
ip/ipmroute.c +9 -7
@@ -223,18 +223,20 @@ void ipmroute_reset_filter(int ifindex)static int mroute_list (int argc,char **argv) {char *id =NULL ; -int family; +int family = preferred_family;ipmroute_reset_filter (0 ); -if (preferred_family ==AF_UNSPEC ) - family =AF_INET ; -else - family =AF_INET6 ; -if (family ==AF_INET ) { +if (family ==AF_INET || family ==AF_UNSPEC ) { + family =RTNL_FAMILY_IPMR ; filter.af =RTNL_FAMILY_IPMR ; filter.tb =RT_TABLE_DEFAULT ;/* for backward compatibility */ - }else + }else if (family ==AF_INET6 ) { + family =RTNL_FAMILY_IP6MR ; filter.af =RTNL_FAMILY_IP6MR ; + }else { +/* family does not have multicast routing */ +return 0 ; + } filter.msrc.family = filter.mdst.family = family;
Signature · 1 line
2.11.0
PATCH 7/12 mroute: Add table id attribute for kernel side filtering
In reply to David AhernFrom: David Ahern <[email protected]>
Similar to 'ip route' add the table id to the dump request for kernel side filtering if it is supported.
--- ip/ipmroute.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
ip/ipmroute.c +14 -1
@@ -220,6 +220,19 @@ void ipmroute_reset_filter(int ifindex) filter.iif = ifindex; } +static int iproute_dump_filter (struct nlmsghdr *nlh,int reqlen) +{ +int err; + +if (filter.tb) { + err =addattr32 (nlh, reqlen,RTA_TABLE , filter.tb); +if (err) +return err; + } + +return 0 ; +} +static int mroute_list (int argc,char **argv) {char *id =NULL ;
@@ -285,7 +298,7 @@ static int mroute_list(int argc, char **argv) filter.iif = idx; } -if (rtnl_routedump_req (&rth, filter.af,NULL ) <0 ) { +if (rtnl_routedump_req (&rth, filter.af, iproute_dump_filter) <0 ) {perror ("Cannot send dump request" );return 1 ; }
Signature · 1 line
2.11.0
PATCH 4/12 ip route: Remove rtnl_rtcache_request
In reply to David AhernFrom: David Ahern <[email protected]>
Add a filter option to rtnl_routedump_req and use it to set rtm_flags removing the need for rtnl_rtcache_request for dump requests.
--- include/libnetlink.h | 7 ++++--- ip/ipmroute.c | 2 +- ip/iproute.c | 43 ++++++++++++++----------------------------- lib/libnetlink.c | 12 +++++++++++- 4 files changed, 30 insertions(+), 34 deletions(-)
include/libnetlink.h +4 -3
@@ -47,11 +47,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,void rtnl_close (struct rtnl_handle *rth); +typedef int (*req_filter_fn_t )(struct nlmsghdr *nlh,int reqlen); +int rtnl_addrdump_req (struct rtnl_handle *rth,int family) __attribute__((warn_unused_result));int rtnl_addrlbldump_req (struct rtnl_handle *rth,int family) __attribute__((warn_unused_result)); -int rtnl_routedump_req (struct rtnl_handle *rth,int family) +int rtnl_routedump_req (struct rtnl_handle *rth,int family, +req_filter_fn_t filter_fn) __attribute__((warn_unused_result));int rtnl_ruledump_req (struct rtnl_handle *rth,int family) __attribute__((warn_unused_result));
@@ -71,8 +74,6 @@ int rtnl_linkdump_req(struct rtnl_handle *rth, int fam)int rtnl_linkdump_req_filter (struct rtnl_handle *rth,int fam,__u32 filt_mask) __attribute__((warn_unused_result)); -typedef int (*req_filter_fn_t )(struct nlmsghdr *nlh,int reqlen); -int rtnl_linkdump_req_filter_fn (struct rtnl_handle *rth,int fam,req_filter_fn_t fn) __attribute__((warn_unused_result));
ip/ipmroute.c +1 -1
@@ -283,7 +283,7 @@ static int mroute_list(int argc, char **argv) filter.iif = idx; } -if (rtnl_routedump_req (&rth, filter.af) <0 ) { +if (rtnl_routedump_req (&rth, filter.af,NULL ) <0 ) {perror ("Cannot send dump request" );return 1 ; }
ip/iproute.c +14 -29
67 lines not on this page · raw message
lib/libnetlink.c +11 -1
@@ -266,11 +266,13 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)return send (rth->fd, &req,sizeof (req),0 ); } -int rtnl_routedump_req (struct rtnl_handle *rth,int family) +int rtnl_routedump_req (struct rtnl_handle *rth,int family, +req_filter_fn_t filter_fn) {struct {struct nlmsghdr nlh;struct rtmsg rtm; +char buf[128 ]; } req = { .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct rtmsg )), .nlh.nlmsg_type =RTM_GETROUTE ,
@@ -279,6 +281,14 @@ int rtnl_routedump_req(struct rtnl_handle *rth, int family) .rtm.rtm_family = family, }; +if (filter_fn) { +int err; + + err =filter_fn (&req.nlh,sizeof (req)); +if (err) +return err; + } +return send (rth->fd, &req,sizeof (req),0 ); }
Signature · 1 line
2.11.0
PATCH 8/12 ip address: Split ip_linkaddr_list into link and addr functions
In reply to David AhernFrom: David Ahern <[email protected]>
Split ip_linkaddr_list into one function that generates a list of devices and a second that generates the list of addresses.
--- ip/ip_common.h | 3 +-- ip/ipaddress.c | 39 ++++++++++++++++++++------------------- ip/ipvrf.c | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-)
ip/ip_common.h +1 -2
@@ -84,8 +84,7 @@ int do_seg6(int argc, char **argv);int iplink_get (char *name,__u32 filt_mask);int iplink_ifla_xstats (int argc,char **argv); -int ip_linkaddr_list (int family,req_filter_fn_t filter_fn, -struct nlmsg_chain *linfo,struct nlmsg_chain *ainfo); +int ip_link_list (req_filter_fn_t filter_fn,struct nlmsg_chain *linfo);void free_nlmsg_chain (struct nlmsg_chain *info);static inline int rtm_get_table (struct rtmsg *r,struct rtattr **tb)
ip/ipaddress.c +20 -19
@@ -1766,8 +1766,7 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)* caller can walk lists as desired and must call free_nlmsg_chain for * both when done */ -int ip_linkaddr_list (int family,req_filter_fn_t filter_fn, -struct nlmsg_chain *linfo,struct nlmsg_chain *ainfo) +int ip_link_list (req_filter_fn_t filter_fn,struct nlmsg_chain *linfo) {if (rtnl_linkdump_req_filter_fn (&rth, preferred_family, filter_fn) <0 ) {
@@ -1780,16 +1779,19 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,return 1 ; } -if (ainfo) { -if (rtnl_addrdump_req (&rth, family) <0 ) { -perror ("Cannot send dump request" ); -return 1 ; - } +return 0 ; +} -if (rtnl_dump_filter (&rth, store_nlmsg, ainfo) <0 ) { -fprintf (stderr,"Dump terminated\n" ); -return 1 ; - } +static int ip_addr_list (struct nlmsg_chain *ainfo) +{ +if (rtnl_addrdump_req (&rth, filter.family) <0 ) { +perror ("Cannot send dump request" ); +return 1 ; + } + +if (rtnl_dump_filter (&rth, store_nlmsg, ainfo) <0 ) { +fprintf (stderr,"Dump terminated\n" ); +return 1 ; }return 0 ;
@@ -1798,7 +1800,7 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,static int ipaddr_list_flush_or_save (int argc,char **argv,int action) {struct nlmsg_chain linfo = {NULL ,NULL }; -struct nlmsg_chain _ainfo = {NULL ,NULL }, *ainfo =NULL ; +struct nlmsg_chain _ainfo = {NULL ,NULL }, *ainfo = &_ainfo;struct nlmsg_list *l;char *filter_dev =NULL ;int no_link =0 ;
@@ -1940,19 +1942,18 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) goto out; } -if (filter.family !=AF_PACKET ) { - ainfo = &_ainfo; +if (ip_link_list (iplink_filter_req, &linfo) !=0 ) + goto out; +if (filter.family !=AF_PACKET ) {if (filter.oneline) no_link =1 ; - } -if (ip_linkaddr_list (filter.family, iplink_filter_req, - &linfo, ainfo) !=0 ) - goto out; +if (ip_addr_list (ainfo) !=0 ) + goto out; -if (filter.family !=AF_PACKET )ipaddr_filter (&linfo, ainfo); + }for (l = linfo.head; l; l = l->next) {struct nlmsghdr *n = &l->h;
ip/ipvrf.c +1 -1
@@ -589,7 +589,7 @@ static int ipvrf_show(int argc, char **argv)return 0 ; } -if (ip_linkaddr_list (0 , ipvrf_filter_req, &linfo,NULL ) ==0 ) { +if (ip_link_list (ipvrf_filter_req, &linfo) ==0 ) {struct nlmsg_list *l;unsigned nvrf =0 ;int n;
Signature · 1 line
2.11.0
PATCH 10/12 ip bridge: Set NETLINK_DUMP_STRICT_CHK on socket
In reply to David AhernFrom: David Ahern <[email protected]>
iproute2 has been updated for the new strict policy in the kernel. Add a helper to call setsockopt to enable the feature. Add a call to ip.c and bridge.c
The setsockopt fails on older kernels and the error can be safely ignored
- any new fields or attributes are ignored by the older kernel.
--- bridge/bridge.c | 4 ++++ include/libnetlink.h | 1 + ip/ip.c | 2 ++ lib/libnetlink.c | 9 +++++++++ 4 files changed, 16 insertions(+)
bridge/bridge.c +4 -0
@@ -97,6 +97,8 @@ static int batch(const char *name)return EXIT_FAILURE ; } +rtnl_set_strict_dump (&rth); + cmdlineno =0 ;while (getcmdline (&line, &len, stdin) !=-1 ) {char *largv[100 ];
@@ -205,6 +207,8 @@ main(int argc, char **argv)if (rtnl_open (&rth,0 ) <0 )exit (1 ); +rtnl_set_strict_dump (&rth); +if (argc >1 )return do_cmd (argv[1 ], argc-1 , argv+1 );
include/libnetlink.h +1 -0
@@ -46,6 +46,7 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions, __attribute__((warn_unused_result));void rtnl_close (struct rtnl_handle *rth); +void rtnl_set_strict_dump (struct rtnl_handle *rth);typedef int (*req_filter_fn_t )(struct nlmsghdr *nlh,int reqlen);
ip/ip.c +2 -0
@@ -308,6 +308,8 @@ int main(int argc, char **argv)if (rtnl_open (&rth,0 ) <0 )exit (1 ); +rtnl_set_strict_dump (&rth); +if (strlen (basename) >2 )return do_cmd (basename+2 , argc, argv);
lib/libnetlink.c +9 -0
@@ -161,6 +161,15 @@ static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error) }#endif +/* Older kernels may not support strict dump and filtering */ +void rtnl_set_strict_dump (struct rtnl_handle *rth) +{ +int one =1 ; + +setsockopt (rth->fd,SOL_NETLINK ,NETLINK_DUMP_STRICT_CHK , + &one,sizeof (one)); +} +void rtnl_close (struct rtnl_handle *rth) {if (rth->fd >=0 ) {
Signature · 1 line
2.11.0
PATCH 11/12 ip route: Rename do_ipv6 to dump_family
In reply to David AhernFrom: David Ahern <[email protected]>
do_ipv6 is really the preferred dump family. Rename it to make that apparent.
--- ip/iproute.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
ip/iproute.c +18 -18
@@ -1604,7 +1604,7 @@ static int save_route_prep(void)return 0 ; } -static int iproute_flush (int do_ipv6,rtnl_filter_t filter_fn) +static int iproute_flush (int family,rtnl_filter_t filter_fn) {time_t start =time (0 );char flushb[4096 -512 ];
@@ -1612,12 +1612,12 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)int ret;if (filter.cloned) { -if (do_ipv6 !=AF_INET6 ) { +if (family !=AF_INET6 ) {iproute_flush_cache ();if (show_stats)printf ("*** IPv4 routing cache is flushed.\n" ); } -if (do_ipv6 ==AF_INET ) +if (family ==AF_INET )return 0 ; }
@@ -1626,7 +1626,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn) filter.flushe =sizeof (flushb);for (;;) { -if (rtnl_routedump_req (&rth, do_ipv6,NULL ) <0 ) { +if (rtnl_routedump_req (&rth, family,NULL ) <0 ) {perror ("Cannot send dump request" );return -2 ; }
@@ -1638,7 +1638,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)if (filter.flushed ==0 ) {if (show_stats) {if (round ==0 && - (!filter.cloned || do_ipv6 ==AF_INET6 )) + (!filter.cloned || family ==AF_INET6 ))printf ("Nothing to flush.\n" );else printf("*** Flush is complete after %d round%s ***\n",
@@ -1692,7 +1692,7 @@ static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)static int iproute_list_flush_or_save (int argc,char **argv,int action) { -int do_ipv6 = preferred_family; +int dump_family = preferred_family;char *id =NULL ;char *od =NULL ;unsigned int mark =0 ;
@@ -1811,13 +1811,13 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)NEXT_ARG (); family =read_family (*argv);if (family ==AF_UNSPEC ) - family = do_ipv6; + family = dump_family;else NEXT_ARG ();get_prefix (&filter.rvia, *argv, family); }else if (strcmp (*argv,"src" ) ==0 ) {NEXT_ARG (); -get_prefix (&filter.rprefsrc, *argv, do_ipv6); +get_prefix (&filter.rprefsrc, *argv, dump_family); }else if (matches (*argv,"realms" ) ==0 ) {__u32 realm;
@@ -1837,15 +1837,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)NEXT_ARG ();if (matches (*argv,"root" ) ==0 ) {NEXT_ARG (); -get_prefix (&filter.rsrc, *argv, do_ipv6); +get_prefix (&filter.rsrc, *argv, dump_family); }else if (matches (*argv,"match" ) ==0 ) {NEXT_ARG (); -get_prefix (&filter.msrc, *argv, do_ipv6); +get_prefix (&filter.msrc, *argv, dump_family); }else {if (matches (*argv,"exact" ) ==0 ) {NEXT_ARG (); } -get_prefix (&filter.msrc, *argv, do_ipv6); +get_prefix (&filter.msrc, *argv, dump_family); filter.rsrc = filter.msrc; } }else {
@@ -1854,23 +1854,23 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) }if (matches (*argv,"root" ) ==0 ) {NEXT_ARG (); -get_prefix (&filter.rdst, *argv, do_ipv6); +get_prefix (&filter.rdst, *argv, dump_family); }else if (matches (*argv,"match" ) ==0 ) {NEXT_ARG (); -get_prefix (&filter.mdst, *argv, do_ipv6); +get_prefix (&filter.mdst, *argv, dump_family); }else {if (matches (*argv,"exact" ) ==0 ) {NEXT_ARG (); } -get_prefix (&filter.mdst, *argv, do_ipv6); +get_prefix (&filter.mdst, *argv, dump_family); filter.rdst = filter.mdst; } } argc--; argv++; } -if (do_ipv6 ==AF_UNSPEC && filter.tb) - do_ipv6 =AF_INET ; +if (dump_family ==AF_UNSPEC && filter.tb) + dump_family =AF_INET ;if (id || od) {int idx;
@@ -1893,9 +1893,9 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) filter.mark = mark;if (action ==IPROUTE_FLUSH ) -return iproute_flush (do_ipv6, filter_fn); +return iproute_flush (dump_family, filter_fn); -if (rtnl_routedump_req (&rth, do_ipv6, iproute_dump_filter) <0 ) { +if (rtnl_routedump_req (&rth, dump_family, iproute_dump_filter) <0 ) {perror ("Cannot send dump request" );return -2 ; }
Signature · 1 line
2.11.0
PATCH 9/12 ip address: Set device index in dump request
In reply to David AhernFrom: David Ahern <[email protected]>
Add a filter function to rtnl_addrdump_req to set device index in the address dump request if the user is filtering addresses by device. In addition, add a new ipaddr_link_get to do a single RTM_GETLINK request instead of a device dump yet still store the data in the linfo list.
--- include/libnetlink.h | 3 ++- ip/ipaddress.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------- lib/libnetlink.c | 12 ++++++++++- 3 files changed, 65 insertions(+), 9 deletions(-)
include/libnetlink.h +2 -1
@@ -49,7 +49,8 @@ void rtnl_close(struct rtnl_handle *rth);typedef int (*req_filter_fn_t )(struct nlmsghdr *nlh,int reqlen); -int rtnl_addrdump_req (struct rtnl_handle *rth,int family) +int rtnl_addrdump_req (struct rtnl_handle *rth,int family, +req_filter_fn_t filter_fn) __attribute__((warn_unused_result));int rtnl_addrlbldump_req (struct rtnl_handle *rth,int family) __attribute__((warn_unused_result));
ip/ipaddress.c +52 -7
101 lines not on this page · raw message
lib/libnetlink.c +11 -1
@@ -234,11 +234,13 @@ int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)return rtnl_open_byproto (rth, subscriptions,NETLINK_ROUTE ); } -int rtnl_addrdump_req (struct rtnl_handle *rth,int family) +int rtnl_addrdump_req (struct rtnl_handle *rth,int family, +req_filter_fn_t filter_fn) {struct {struct nlmsghdr nlh;struct ifaddrmsg ifm; +char buf[128 ]; } req = { .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifaddrmsg )), .nlh.nlmsg_type =RTM_GETADDR ,
@@ -247,6 +249,14 @@ int rtnl_addrdump_req(struct rtnl_handle *rth, int family) .ifm.ifa_family = family, }; +if (filter_fn) { +int err; + + err =filter_fn (&req.nlh,sizeof (req)); +if (err) +return err; + } +return send (rth->fd, &req,sizeof (req),0 ); }
Signature · 1 line
2.11.0
PATCH 12/12 neighbor: Add support for protocol attribute
In reply to David AhernFrom: David Ahern <[email protected]>
Add support to set protocol on neigh entries and to print the protocol on dumps.
--- ip/ipneigh.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
ip/ipneigh.c +36 -3
@@ -40,6 +40,7 @@ static structint flushp;int flushe;int master; +int protocol; } filter;static void usage (void ) __attribute__((noreturn));
@@ -48,7 +49,7 @@ static void usage(void) {fprintf (stderr,"Usage: ip neigh { add | del | change | replace }\n" " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n" ); -fprintf (stderr," [ router ] [ extern_learn ]\n\n" ); +fprintf (stderr," [ router ] [ extern_learn ] [ protocol PROTO ]\n\n" );fprintf (stderr," ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n" );fprintf (stderr," [ vrf NAME ]\n\n" ); fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
@@ -148,6 +149,14 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)NEXT_ARG (); dev = *argv; dev_ok =1 ; + }else if (matches (*argv,"protocol" ) ==0 ) { +__u32 proto; + +NEXT_ARG (); +if (rtnl_rtprot_a2n (&proto, *argv)) +invarg ("\"protocol\" value is invalid\n" , *argv); +if (addattr8 (&req.n,sizeof (req),NDA_PROTOCOL , proto)) +return -1 ; }else {if (strcmp (*argv,"to" ) ==0 ) {NEXT_ARG ();
@@ -244,6 +253,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)int len = n->nlmsg_len;struct rtattr *tb[NDA_MAX +1 ];static int logit =1 ; +__u8 protocol =0 ;if (n->nlmsg_type !=RTM_NEWNEIGH && n->nlmsg_type !=RTM_DELNEIGH && n->nlmsg_type !=RTM_GETNEIGH ) {
@@ -285,6 +295,12 @@ int print_neigh(struct nlmsghdr *n, void *arg)if (inet_addr_match_rta (&filter.pfx, tb[NDA_DST ]))return 0 ; +if (tb[NDA_PROTOCOL ]) + protocol =rta_getattr_u8 (tb[NDA_PROTOCOL ]); + +if (filter.protocol && filter.protocol != protocol) +return 0 ; +if (filter.unused_only && tb[NDA_CACHEINFO ]) {struct nda_cacheinfo *ci =RTA_DATA (tb[NDA_CACHEINFO ]);
@@ -371,6 +387,13 @@ int print_neigh(struct nlmsghdr *n, void *arg)if (r->ndm_state)print_neigh_state (r->ndm_state); +if (protocol) { +SPRINT_BUF (b1); + +print_string (PRINT_ANY ,"protocol" ," proto %s " , +rtnl_rtprot_n2a (protocol, b1,sizeof (b1))); + } +print_string (PRINT_FP ,NULL ,"\n" ,"" );close_json_object ();fflush (stdout);
@@ -458,9 +481,19 @@ static int do_show_or_flush(int argc, char **argv, int flush)if (state ==0 ) state =0x100 ; filter.state |= state; - }else if (strcmp (*argv,"proxy" ) ==0 ) + }else if (strcmp (*argv,"proxy" ) ==0 ) { req.ndm.ndm_flags =NTF_PROXY ; -else { + }else if (matches (*argv,"protocol" ) ==0 ) { +__u32 prot; + +NEXT_ARG (); +if (rtnl_rtprot_a2n (&prot, *argv)) { +if (strcmp (*argv,"all" )) +invarg ("invalid \"protocol\"\n" , *argv); + prot =0 ; + } + filter.protocol = prot; + }else {if (strcmp (*argv,"to" ) ==0 ) {NEXT_ARG (); }
Signature · 1 line
2.11.0
Quoted 4 lines · David Ahern
From: David Ahern <[email protected]>
Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.
David,
Since this was applied to iproute2-next I get:
bash-4.4# bridge/bridge fdb show
[ 5365.137224] netlink: 4 bytes leftover after parsing attributes in process `bridge'.
Error: bytes leftover after parsing attributes.
Dump terminated
And a lot of tests are failing. Given you enabled strict checking, I assume we should be using 'struct ndmsg' in FDB dump? Following patch fixes it for me. I can submit formally if you don't already have a patch.
bridge/fdb.c +6 -6
@@ -260,16 +260,16 @@ static int fdb_show(int argc, char **argv) {struct {struct nlmsghdr n; -struct ifinfomsg ifm; +struct ndmsg ndm;char buf[256 ]; } req = { - .n.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifinfomsg )), - .ifm.ifi_family =PF_BRIDGE , + .n.nlmsg_len =NLMSG_LENGTH (sizeof (struct ndmsg )), + .ndm.ndm_family =PF_BRIDGE , };char *filter_dev =NULL ;char *br =NULL ; -int msg_size =sizeof (struct ifinfomsg ); +int msg_size =sizeof (struct ndmsg );while (argc >0 ) {if ((strcmp (*argv,"brport" ) ==0 ) ||strcmp (*argv,"dev" ) ==0 ) {
@@ -313,10 +313,10 @@ static int fdb_show(int argc, char **argv) filter_index =ll_name_to_index (filter_dev);if (!filter_index)return nodev (filter_dev); - req.ifm.ifi_index = filter_index; + req.ndm.ndm_ifindex = filter_index; } -if (rtnl_dump_request (&rth,RTM_GETNEIGH , &req.ifm, msg_size) <0 ) { +if (rtnl_dump_request (&rth,RTM_GETNEIGH , &req.ndm, msg_size) <0 ) {perror ("Cannot send dump request" );exit (1 ); }
Quoted 15 lines · Ido Schimmel
Quoted 6 lines · David Ahern
From: David Ahern <[email protected]>
Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.
David,
Since this was applied to iproute2-next I get:
bash-4.4# bridge/bridge fdb show
Quoted 8 lines
[ 5365.137224] netlink: 4 bytes leftover after parsing attributes in process `bridge'.Error: bytes leftover after parsing attributes.
Dump terminatedAnd a lot of tests are failing. Given you enabled strict checking, I assume we should be using 'struct ndmsg' in FDB dump? Following patch fixes it for me. I can submit formally if you don't already have a patch.
Please submit formally. Thanks for the fix
Quoted 39 lines
bridge/fdb.c +6
-6@@ -260,16 +260,16 @@ static int fdb_show(int argc, char **argv) {struct {struct nlmsghdr n; -struct ifinfomsg ifm; +struct ndmsg ndm;char buf[256 ]; } req = { - .n.nlmsg_len =NLMSG_LENGTH (sizeof (struct ifinfomsg )), - .ifm.ifi_family =PF_BRIDGE , + .n.nlmsg_len =NLMSG_LENGTH (sizeof (struct ndmsg )), + .ndm.ndm_family =PF_BRIDGE , };char *filter_dev =NULL ;char *br =NULL ; -int msg_size =sizeof (struct ifinfomsg ); +int msg_size =sizeof (struct ndmsg );while (argc >0 ) {if ((strcmp (*argv,"brport" ) ==0 ) ||strcmp (*argv,"dev" ) ==0 ) {@@ -313,10 +313,10 @@ static int fdb_show(int argc, char **argv) filter_index =ll_name_to_index (filter_dev);if (!filter_index)return nodev (filter_dev); - req.ifm.ifi_index = filter_index; + req.ndm.ndm_ifindex = filter_index; } -if (rtnl_dump_request (&rth,RTM_GETNEIGH , &req.ifm, msg_size) <0 ) { +if (rtnl_dump_request (&rth,RTM_GETNEIGH , &req.ndm, msg_size) <0 ) {perror ("Cannot send dump request" );exit (1 ); }