aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2009-02-25 02:18:28 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-25 02:18:28 -0500
commit1ce85fe402137824246bad03ff85f3913d565c17 (patch)
tree3a54c150e9616709a8f65270cd1f4aeecac4d48e
parent4fb0a54a55d34c28dc53c39567ce171166572699 (diff)
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>
-rw-r--r--include/linux/rtnetlink.h4
-rw-r--r--net/bridge/br_netlink.c3
-rw-r--r--net/core/fib_rules.c3
-rw-r--r--net/core/neighbour.c3
-rw-r--r--net/core/rtnetlink.c9
-rw-r--r--net/decnet/dn_dev.c3
-rw-r--r--net/decnet/dn_table.c3
-rw-r--r--net/ipv4/devinet.c3
-rw-r--r--net/ipv4/fib_semantics.c5
-rw-r--r--net/ipv6/addrconf.c9
-rw-r--r--net/ipv6/ndisc.c6
-rw-r--r--net/ipv6/route.c5
-rw-r--r--net/netlink/af_netlink.c14
-rw-r--r--net/phonet/pn_netlink.c5
14 files changed, 45 insertions, 30 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 1e5f6730ff31..35a07c830f79 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -622,8 +622,8 @@ static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
622 622
623extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo); 623extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
624extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid); 624extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
625extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, 625extern void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
626 struct nlmsghdr *nlh, gfp_t flags); 626 u32 group, struct nlmsghdr *nlh, gfp_t flags);
627extern void rtnl_set_sk_err(struct net *net, u32 group, int error); 627extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
628extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); 628extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
629extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, 629extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index ba7be195803c..fcffb3fb1177 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -98,7 +98,8 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
98 kfree_skb(skb); 98 kfree_skb(skb);
99 goto errout; 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;
102errout: 103errout:
103 if (err < 0) 104 if (err < 0)
104 rtnl_set_sk_err(net, RTNLGRP_LINK, err); 105 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 32b3a0152d7a..98691e1466b8 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -588,7 +588,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
588 goto errout; 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;
592errout: 593errout:
593 if (err < 0) 594 if (err < 0)
594 rtnl_set_sk_err(net, ops->nlgroup, err); 595 rtnl_set_sk_err(net, ops->nlgroup, err);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 278a142d1047..e1144cb94b99 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2534,7 +2534,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
2534 kfree_skb(skb); 2534 kfree_skb(skb);
2535 goto errout; 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;
2538errout: 2539errout:
2539 if (err < 0) 2540 if (err < 0)
2540 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); 2541 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 790dd205bb5d..d78030f88bd0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -455,8 +455,8 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
455 return nlmsg_unicast(rtnl, skb, pid); 455 return nlmsg_unicast(rtnl, skb, pid);
456} 456}
457 457
458int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, 458void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
459 struct nlmsghdr *nlh, gfp_t flags) 459 struct nlmsghdr *nlh, gfp_t flags)
460{ 460{
461 struct sock *rtnl = net->rtnl; 461 struct sock *rtnl = net->rtnl;
462 int report = 0; 462 int report = 0;
@@ -464,7 +464,7 @@ int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
464 if (nlh) 464 if (nlh)
465 report = nlmsg_report(nlh); 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
470void rtnl_set_sk_err(struct net *net, u32 group, int error) 470void rtnl_set_sk_err(struct net *net, u32 group, int error)
@@ -1246,7 +1246,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
1246 kfree_skb(skb); 1246 kfree_skb(skb);
1247 goto errout; 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;
1250errout: 1251errout:
1251 if (err < 0) 1252 if (err < 0)
1252 rtnl_set_sk_err(net, RTNLGRP_LINK, err); 1253 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index daf2b98b15fe..e457769bf7a7 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -769,7 +769,8 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
769 kfree_skb(skb); 769 kfree_skb(skb);
770 goto errout; 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;
773errout: 774errout:
774 if (err < 0) 775 if (err < 0)
775 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err); 776 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 69ad9280c693..67054b0d550f 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -375,7 +375,8 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
375 kfree_skb(skb); 375 kfree_skb(skb);
376 goto errout; 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;
379errout: 380errout:
380 if (err < 0) 381 if (err < 0)
381 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err); 382 rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index d519a6a66726..126bb911880f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1216,7 +1216,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
1216 kfree_skb(skb); 1216 kfree_skb(skb);
1217 goto errout; 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;
1220errout: 1221errout:
1221 if (err < 0) 1222 if (err < 0)
1222 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); 1223 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4817dea3bc73..f831df500907 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -322,8 +322,9 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
322 kfree_skb(skb); 322 kfree_skb(skb);
323 goto errout; 323 goto errout;
324 } 324 }
325 err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE, 325 rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
326 info->nlh, GFP_KERNEL); 326 info->nlh, GFP_KERNEL);
327 return;
327errout: 328errout:
328 if (err < 0) 329 if (err < 0)
329 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); 330 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 03e2a1ad71e9..f8f76d6e21cb 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3638,7 +3638,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
3638 kfree_skb(skb); 3638 kfree_skb(skb);
3639 goto errout; 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;
3642errout: 3643errout:
3643 if (err < 0) 3644 if (err < 0)
3644 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); 3645 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3849,7 +3850,8 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
3849 kfree_skb(skb); 3850 kfree_skb(skb);
3850 goto errout; 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;
3853errout: 3855errout:
3854 if (err < 0) 3856 if (err < 0)
3855 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); 3857 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3919,7 +3921,8 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
3919 kfree_skb(skb); 3921 kfree_skb(skb);
3920 goto errout; 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;
3923errout: 3926errout:
3924 if (err < 0) 3927 if (err < 0)
3925 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); 3928 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3cd83b85e9ef..9f061d1adbc2 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1095,11 +1095,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1095 &ipv6_hdr(ra)->saddr); 1095 &ipv6_hdr(ra)->saddr);
1096 nlmsg_end(skb, nlh); 1096 nlmsg_end(skb, nlh);
1097 1097
1098 err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, 1098 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
1099 GFP_ATOMIC);
1100 if (err < 0)
1101 goto errout;
1102
1103 return; 1099 return;
1104 1100
1105nla_put_failure: 1101nla_put_failure:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c3d486a3edad..1394ddb6e35c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2400,8 +2400,9 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
2400 kfree_skb(skb); 2400 kfree_skb(skb);
2401 goto errout; 2401 goto errout;
2402 } 2402 }
2403 err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE, 2403 rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
2404 info->nlh, gfp_any()); 2404 info->nlh, gfp_any());
2405 return;
2405errout: 2406errout:
2406 if (err < 0) 2407 if (err < 0)
2407 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); 2408 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index ed587be1e1c2..2760b62dc2c1 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1760,12 +1760,18 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
1760 exclude_pid = pid; 1760 exclude_pid = pid;
1761 } 1761 }
1762 1762
1763 /* errors reported via destination sk->sk_err */ 1763 /* errors reported via destination sk->sk_err, but propagate
1764 nlmsg_multicast(sk, skb, exclude_pid, group, flags); 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 if (report) {
1768 err = nlmsg_unicast(sk, skb, pid); 1769 int err2;
1770
1771 err2 = nlmsg_unicast(sk, skb, pid);
1772 if (!err || err == -ESRCH)
1773 err = err2;
1774 }
1769 1775
1770 return err; 1776 return err;
1771} 1777}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 1ceea1f92413..cec4e5951681 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -47,8 +47,9 @@ static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
47 kfree_skb(skb); 47 kfree_skb(skb);
48 goto errout; 48 goto errout;
49 } 49 }
50 err = rtnl_notify(skb, dev_net(dev), 0, 50 rtnl_notify(skb, dev_net(dev), 0,
51 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL); 51 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
52 return;
52errout: 53errout:
53 if (err < 0) 54 if (err < 0)
54 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err); 55 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);