net: Add support for dumping addresses for a specific device
Subsystems (3)
David Ahern
maintainercover net: Add support for dumping addresses for a specific device
From: David Ahern <[email protected]>
Use the recently added kernel side filter infrastructure to add support for dumping addresses only for a specific device.
Patch 1 creates an IPv4 version similar to IPv6's in6_dump_addrs function.
Patch 2 simplifies in6_dump_addrs by moving index tracking of IP addresses from inet6_dump_addr to in6_dump_addrs.
Patches 3 and 4 use the device-based address dump helpers to limit a dump to just the addresses on a specific device.
David Ahern (4):
net/ipv4: Move loop over addresses in dumps into in_dev_dump_addr net/ipv6: Remove ip_idx arg to in6_dump_addrs net/ipv4: Add support for dumping addresses for a specific device net/ipv6: Add support for dumping addresses for a specific device
net/ipv4/devinet.c | 77 +++++++++++++++++++++++++++++++++++++++-------------- net/ipv6/addrconf.c | 43 +++++++++++++++++++----------- 2 files changed, 85 insertions(+), 35 deletions(-)
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH 1/4 net/ipv4: Move loop over addresses on a device into in_dev_dump_addr
From: David Ahern <[email protected]>
Similar to IPv6 move the logic that walks over the ipv4 address list for a device into a helper.
--- net/ipv4/devinet.c | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-)
net/ipv4/devinet.c +34 -15
@@ -1713,6 +1713,32 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,return 0 ; } +static int in_dev_dump_addr (struct in_device *in_dev,struct sk_buff *skb, +struct netlink_callback *cb,int s_ip_idx, +struct inet_fill_args *fillargs) +{ +struct in_ifaddr *ifa; +int ip_idx =0 ; +int err; + +for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) { +if (ip_idx < s_ip_idx) +continue ; + + err =inet_fill_ifaddr (skb, ifa, fillargs); +if (err <0 ) + goto done; + +nl_dump_check_consistent (cb,nlmsg_hdr (skb)); + } + err =0 ; + +done: + cb->args[2 ] = ip_idx; + +return err; +} +static int inet_dump_ifaddr (struct sk_buff *skb,struct netlink_callback *cb) {const struct nlmsghdr *nlh = cb->nlh;
@@ -1727,19 +1753,17 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)struct net *tgt_net = net;int h, s_h;int idx, s_idx; -int ip_idx, s_ip_idx; +int s_ip_idx;struct net_device *dev;struct in_device *in_dev; -struct in_ifaddr *ifa;struct hlist_head *head; +int err; s_h = cb->args[0 ]; s_idx = idx = cb->args[1 ]; - s_ip_idx = ip_idx = cb->args[2 ]; + s_ip_idx = cb->args[2 ];if (cb->strict_check) { -int err; - err =inet_valid_dump_ifaddr_req (nlh, &fillargs, &tgt_net, skb->sk, cb->extack);if (err <0 )
@@ -1761,15 +1785,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)if (!in_dev) goto cont; -for (ifa = in_dev->ifa_list, ip_idx =0 ; ifa; - ifa = ifa->ifa_next, ip_idx++) { -if (ip_idx < s_ip_idx) -continue ; -if (inet_fill_ifaddr (skb, ifa, &fillargs) <0 ) { -rcu_read_unlock (); - goto done; - } -nl_dump_check_consistent (cb,nlmsg_hdr (skb)); + err =in_dev_dump_addr (in_dev, skb, cb, s_ip_idx, + &fillargs); +if (err <0 ) { +rcu_read_unlock (); + goto done; } cont: idx++;
@@ -1780,7 +1800,6 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) done: cb->args[0 ] = h; cb->args[1 ] = idx; - cb->args[2 ] = ip_idx;if (fillargs.netnsid >=0 )put_net (tgt_net);
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH 2/4 net/ipv6: Remove ip_idx arg to in6_dump_addrs
In reply to David AhernFrom: David Ahern <[email protected]>
ip_idx is always 0 going into in6_dump_addrs; it is passed as a pointer to save the last good index into cb. Since cb is already argument to in6_dump_addrs, just save the value there.
--- net/ipv6/addrconf.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
net/ipv6/addrconf.c +6 -10
@@ -4955,14 +4955,13 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,/* called with rcu_read_lock() */ static int in6_dump_addrs (struct inet6_dev *idev,struct sk_buff *skb, -struct netlink_callback *cb, -int s_ip_idx,int *p_ip_idx, +struct netlink_callback *cb,int s_ip_idx,struct inet6_fill_args *fillargs) {struct ifmcaddr6 *ifmca;struct ifacaddr6 *ifaca; +int ip_idx =0 ;int err =1 ; -int ip_idx = *p_ip_idx;read_lock_bh (&idev->lock);switch (fillargs->type) {
@@ -5012,7 +5011,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,break ; }read_unlock_bh (&idev->lock); - *p_ip_idx = ip_idx; + cb->args[2 ] = ip_idx;return err; }
@@ -5081,16 +5080,15 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, };struct net *net =sock_net (skb->sk);struct net *tgt_net = net; +int idx, s_idx, s_ip_idx;int h, s_h; -int idx, ip_idx; -int s_idx, s_ip_idx;struct net_device *dev;struct inet6_dev *idev;struct hlist_head *head; s_h = cb->args[0 ]; s_idx = idx = cb->args[1 ]; - s_ip_idx = ip_idx = cb->args[2 ]; + s_ip_idx = cb->args[2 ];if (cb->strict_check) {int err;
@@ -5111,12 +5109,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, goto cont;if (h > s_h || idx > s_idx) s_ip_idx =0 ; - ip_idx =0 ; idev =__in6_dev_get (dev);if (!idev) goto cont; -if (in6_dump_addrs (idev, skb, cb, s_ip_idx, &ip_idx, +if (in6_dump_addrs (idev, skb, cb, s_ip_idx, &fillargs) <0 ) goto done; cont:
@@ -5127,7 +5124,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,rcu_read_unlock (); cb->args[0 ] = h; cb->args[1 ] = idx; - cb->args[2 ] = ip_idx;if (fillargs.netnsid >=0 )put_net (tgt_net);
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH 3/4 net/ipv4: Add support for dumping addresses for a specific device
In reply to David AhernFrom: David Ahern <[email protected]>
If an RTM_GETADDR dump request has ifa_index set in the ifaddrmsg header, then return only the addresses for that device.
--- net/ipv4/devinet.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
net/ipv4/devinet.c +23 -5
@@ -109,6 +109,7 @@ struct inet_fill_args {int event;unsigned int flags;int netnsid; +int ifindex; };#define IN4_ADDR_HSIZE_SHIFT 8
@@ -1663,8 +1664,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,static int inet_valid_dump_ifaddr_req (const struct nlmsghdr *nlh,struct inet_fill_args *fillargs,struct net **tgt_net,struct sock *sk, -struct netlink_ext_ack *extack) +struct netlink_callback *cb) { +struct netlink_ext_ack *extack = cb->extack;struct nlattr *tb[IFA_MAX +1 ];struct ifaddrmsg *ifm;int err, i;
@@ -1679,9 +1681,11 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,NL_SET_ERR_MSG (extack,"ipv4: Invalid values in header for address dump request" );return -EINVAL ; } -if (ifm->ifa_index) { -NL_SET_ERR_MSG (extack,"ipv4: Filter by device index not supported for address dump" ); -return -EINVAL ; + + fillargs->ifindex = ifm->ifa_index; +if (fillargs->ifindex) { + cb->answer_flags |=NLM_F_DUMP_FILTERED ; + fillargs->flags |=NLM_F_DUMP_FILTERED ; } err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
@@ -1765,9 +1769,22 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)if (cb->strict_check) { err =inet_valid_dump_ifaddr_req (nlh, &fillargs, &tgt_net, - skb->sk, cb->extack); + skb->sk, cb);if (err <0 )return err; + +if (fillargs.ifindex) { + dev =__dev_get_by_index (tgt_net, fillargs.ifindex); +if (!dev) +return -ENODEV ; + + in_dev =__in_dev_get_rtnl (dev); +if (in_dev) { + err =in_dev_dump_addr (in_dev, skb, cb, s_ip_idx, + &fillargs); + } + goto put_tgt_net; + } }for (h = s_h; h <NETDEV_HASHENTRIES ; h++, s_idx =0 ) {
@@ -1800,6 +1817,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) done: cb->args[0 ] = h; cb->args[1 ] = idx; +put_tgt_net:if (fillargs.netnsid >=0 )put_net (tgt_net);
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH 4/4 net/ipv6: Add support for dumping addresses for a specific device
In reply to David AhernFrom: David Ahern <[email protected]>
If an RTM_GETADDR dump request has ifa_index set in the ifaddrmsg header, then return only the addresses for that device.
Since inet6_dump_addr is reused for multicast and anycast addresses, this adds support for device specfic dumps of RTM_GETMULTICAST and RTM_GETANYCAST as well.
--- net/ipv6/addrconf.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
net/ipv6/addrconf.c +22 -5
@@ -4821,6 +4821,7 @@ struct inet6_fill_args {int event;unsigned int flags;int netnsid; +int ifindex;enum addr_type_t type; };
@@ -5018,8 +5019,9 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,static int inet6_valid_dump_ifaddr_req (const struct nlmsghdr *nlh,struct inet6_fill_args *fillargs,struct net **tgt_net,struct sock *sk, -struct netlink_ext_ack *extack) +struct netlink_callback *cb) { +struct netlink_ext_ack *extack = cb->extack;struct nlattr *tb[IFA_MAX +1 ];struct ifaddrmsg *ifm;int err, i;
@@ -5034,9 +5036,11 @@ static int inet6_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,NL_SET_ERR_MSG_MOD (extack,"Invalid values in header for address dump request" );return -EINVAL ; } -if (ifm->ifa_index) { -NL_SET_ERR_MSG_MOD (extack,"Filter by device index not supported for address dump" ); -return -EINVAL ; + + fillargs->ifindex = ifm->ifa_index; +if (fillargs->ifindex) { + cb->answer_flags |=NLM_F_DUMP_FILTERED ; + fillargs->flags |=NLM_F_DUMP_FILTERED ; } err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
@@ -5094,9 +5098,21 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,int err; err =inet6_valid_dump_ifaddr_req (nlh, &fillargs, &tgt_net, - skb->sk, cb->extack); + skb->sk, cb);if (err <0 )return err; + +if (fillargs.ifindex) { + dev =__dev_get_by_index (tgt_net, fillargs.ifindex); +if (!dev) +return -ENODEV ; + idev =__in6_dev_get (dev); +if (idev) { + err =in6_dump_addrs (idev, skb, cb, s_ip_idx, + &fillargs); + } + goto put_tgt_net; + } }rcu_read_lock ();
@@ -5124,6 +5140,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,rcu_read_unlock (); cb->args[0 ] = h; cb->args[1 ] = idx; +put_tgt_net:if (fillargs.netnsid >=0 )put_net (tgt_net);
Signature · 1 line
2.11.0
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Fri, 19 Oct 2018 12:45:26 -0700
Quoted 5 lines
From: David Ahern <[email protected]>
Use the recently added kernel side filter infrastructure to add support for dumping addresses only for a specific device.
Quoted 7 lines
Patch 1 creates an IPv4 version similar to IPv6's
in6_dump_addrsfunction.Patch 2 simplifies
in6_dump_addrsby moving index tracking of IP addresses frominet6_dump_addrtoin6_dump_addrs.Patches 3 and 4 use the device-based address dump helpers to limit a dump to just the addresses on a specific device.
Create good infrastructure, and it will get used.
Series applied, thanks David.