Commit 1ce85fe402137824246bad03ff85f3913d565c17

Authored by Pablo Neira Ayuso
Committed by David S. Miller
1 parent 4fb0a54a55

netlink: change nlmsg_notify() return value logic

This patch changes the return value of nlmsg_notify() as follows:

If NETLINK_BROADCAST_ERROR is set by any of the listeners and
an error in the delivery happened, return the broadcast error;
else if there are no listeners apart from the socket that
requested a change with the echo flag, return the result of the
unicast notification. Thus, with this patch, the unicast
notification is handled in the same way of a broadcast listener
that has set the NETLINK_BROADCAST_ERROR socket flag.

This patch is useful in case that the caller of nlmsg_notify()
wants to know the result of the delivery of a netlink notification
(including the broadcast delivery) and take any action in case
that the delivery failed. For example, ctnetlink can drop packets
if the event delivery failed to provide reliable logging and
state-synchronization at the cost of dropping packets.

This patch also modifies the rtnetlink code to ignore the return
value of rtnl_notify() in all callers. The function rtnl_notify()
(before this patch) returned the error of the unicast notification
which makes rtnl_set_sk_err() reports errors to all listeners. This
is not of any help since the origin of the change (the socket that
requested the echoing) notices the ENOBUFS error if the notification
fails and should resync itself.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 14 changed files with 45 additions and 30 deletions Side-by-side Diff

include/linux/rtnetlink.h
... ... @@ -622,8 +622,8 @@
622 622  
623 623 extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
624 624 extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
625   -extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
626   - struct nlmsghdr *nlh, gfp_t flags);
  625 +extern void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
  626 + u32 group, struct nlmsghdr *nlh, gfp_t flags);
627 627 extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
628 628 extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
629 629 extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
net/bridge/br_netlink.c
... ... @@ -98,7 +98,8 @@
98 98 kfree_skb(skb);
99 99 goto errout;
100 100 }
101   - err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
  101 + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
  102 + return;
102 103 errout:
103 104 if (err < 0)
104 105 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
net/core/fib_rules.c
... ... @@ -588,7 +588,8 @@
588 588 goto errout;
589 589 }
590 590  
591   - err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
  591 + rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
  592 + return;
592 593 errout:
593 594 if (err < 0)
594 595 rtnl_set_sk_err(net, ops->nlgroup, err);
net/core/neighbour.c
... ... @@ -2534,7 +2534,8 @@
2534 2534 kfree_skb(skb);
2535 2535 goto errout;
2536 2536 }
2537   - err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
  2537 + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
  2538 + return;
2538 2539 errout:
2539 2540 if (err < 0)
2540 2541 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
net/core/rtnetlink.c
... ... @@ -455,8 +455,8 @@
455 455 return nlmsg_unicast(rtnl, skb, pid);
456 456 }
457 457  
458   -int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
459   - struct nlmsghdr *nlh, gfp_t flags)
  458 +void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
  459 + struct nlmsghdr *nlh, gfp_t flags)
460 460 {
461 461 struct sock *rtnl = net->rtnl;
462 462 int report = 0;
... ... @@ -464,7 +464,7 @@
464 464 if (nlh)
465 465 report = nlmsg_report(nlh);
466 466  
467   - return nlmsg_notify(rtnl, skb, pid, group, report, flags);
  467 + nlmsg_notify(rtnl, skb, pid, group, report, flags);
468 468 }
469 469  
470 470 void rtnl_set_sk_err(struct net *net, u32 group, int error)
... ... @@ -1246,7 +1246,8 @@
1246 1246 kfree_skb(skb);
1247 1247 goto errout;
1248 1248 }
1249   - err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
  1249 + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
  1250 + return;
1250 1251 errout:
1251 1252 if (err < 0)
1252 1253 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
... ... @@ -769,7 +769,8 @@
769 769 kfree_skb(skb);
770 770 goto errout;
771 771 }
772   - err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
  772 + rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
  773 + return;
773 774 errout:
774 775 if (err < 0)
775 776 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
net/decnet/dn_table.c
... ... @@ -375,7 +375,8 @@
375 375 kfree_skb(skb);
376 376 goto errout;
377 377 }
378   - err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
  378 + rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
  379 + return;
379 380 errout:
380 381 if (err < 0)
381 382 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
... ... @@ -1216,7 +1216,8 @@
1216 1216 kfree_skb(skb);
1217 1217 goto errout;
1218 1218 }
1219   - err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
  1219 + rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
  1220 + return;
1220 1221 errout:
1221 1222 if (err < 0)
1222 1223 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
net/ipv4/fib_semantics.c
... ... @@ -322,8 +322,9 @@
322 322 kfree_skb(skb);
323 323 goto errout;
324 324 }
325   - err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
326   - info->nlh, GFP_KERNEL);
  325 + rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
  326 + info->nlh, GFP_KERNEL);
  327 + return;
327 328 errout:
328 329 if (err < 0)
329 330 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
... ... @@ -3638,7 +3638,8 @@
3638 3638 kfree_skb(skb);
3639 3639 goto errout;
3640 3640 }
3641   - err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
  3641 + rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
  3642 + return;
3642 3643 errout:
3643 3644 if (err < 0)
3644 3645 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
... ... @@ -3849,7 +3850,8 @@
3849 3850 kfree_skb(skb);
3850 3851 goto errout;
3851 3852 }
3852   - err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
  3853 + rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
  3854 + return;
3853 3855 errout:
3854 3856 if (err < 0)
3855 3857 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
... ... @@ -3919,7 +3921,8 @@
3919 3921 kfree_skb(skb);
3920 3922 goto errout;
3921 3923 }
3922   - err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
  3924 + rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
  3925 + return;
3923 3926 errout:
3924 3927 if (err < 0)
3925 3928 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
... ... @@ -1095,11 +1095,7 @@
1095 1095 &ipv6_hdr(ra)->saddr);
1096 1096 nlmsg_end(skb, nlh);
1097 1097  
1098   - err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL,
1099   - GFP_ATOMIC);
1100   - if (err < 0)
1101   - goto errout;
1102   -
  1098 + rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
1103 1099 return;
1104 1100  
1105 1101 nla_put_failure:
... ... @@ -2400,8 +2400,9 @@
2400 2400 kfree_skb(skb);
2401 2401 goto errout;
2402 2402 }
2403   - err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
2404   - info->nlh, gfp_any());
  2403 + rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
  2404 + info->nlh, gfp_any());
  2405 + return;
2405 2406 errout:
2406 2407 if (err < 0)
2407 2408 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
net/netlink/af_netlink.c
... ... @@ -1760,12 +1760,18 @@
1760 1760 exclude_pid = pid;
1761 1761 }
1762 1762  
1763   - /* errors reported via destination sk->sk_err */
1764   - nlmsg_multicast(sk, skb, exclude_pid, group, flags);
  1763 + /* errors reported via destination sk->sk_err, but propagate
  1764 + * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
  1765 + err = nlmsg_multicast(sk, skb, exclude_pid, group, flags);
1765 1766 }
1766 1767  
1767   - if (report)
1768   - err = nlmsg_unicast(sk, skb, pid);
  1768 + if (report) {
  1769 + int err2;
  1770 +
  1771 + err2 = nlmsg_unicast(sk, skb, pid);
  1772 + if (!err || err == -ESRCH)
  1773 + err = err2;
  1774 + }
1769 1775  
1770 1776 return err;
1771 1777 }
net/phonet/pn_netlink.c
... ... @@ -47,8 +47,9 @@
47 47 kfree_skb(skb);
48 48 goto errout;
49 49 }
50   - err = rtnl_notify(skb, dev_net(dev), 0,
51   - RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
  50 + rtnl_notify(skb, dev_net(dev), 0,
  51 + RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
  52 + return;
52 53 errout:
53 54 if (err < 0)
54 55 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);