netlink: change nlmsg_notify() return value logic
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 25 Feb 2009 07:18:28 +0000 (23:18 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 25 Feb 2009 07:18:28 +0000 (23:18 -0800)
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>
14 files changed:
include/linux/rtnetlink.h
net/bridge/br_netlink.c
net/core/fib_rules.c
net/core/neighbour.c
net/core/rtnetlink.c
net/decnet/dn_dev.c
net/decnet/dn_table.c
net/ipv4/devinet.c
net/ipv4/fib_semantics.c
net/ipv6/addrconf.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/netlink/af_netlink.c
net/phonet/pn_netlink.c

index 1e5f6730ff31f412b65b731a5c7b375e4ddf0046..35a07c830f792cfa3b47fa3dbe5acff025dc44a2 100644 (file)
@@ -622,8 +622,8 @@ static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
 
 extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
 extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
-extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-                      struct nlmsghdr *nlh, gfp_t flags);
+extern void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
+                       u32 group, struct nlmsghdr *nlh, gfp_t flags);
 extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
 extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
 extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
index ba7be195803c596e9234ebc985eeff99ce08b5c8..fcffb3fb1177aa57352f4fdbcc0247944d1959ac 100644 (file)
@@ -98,7 +98,8 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
index 32b3a0152d7adba2079e5a1bc5f5ba9001037996..98691e1466b80699b664983e5403b4b1a3a19db2 100644 (file)
@@ -588,7 +588,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
                goto errout;
        }
 
-       err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
+       rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, ops->nlgroup, err);
index 278a142d1047bcdd93e118326e3b56a952d14d5e..e1144cb94b9954592ff7bb83581bec0077e44e98 100644 (file)
@@ -2534,7 +2534,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
index 790dd205bb5d9b9a9704734934b74db6029a44c0..d78030f88bd0f21733d4f06f517de5fc4fc39a67 100644 (file)
@@ -455,8 +455,8 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
        return nlmsg_unicast(rtnl, skb, pid);
 }
 
-int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-               struct nlmsghdr *nlh, gfp_t flags)
+void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
+                struct nlmsghdr *nlh, gfp_t flags)
 {
        struct sock *rtnl = net->rtnl;
        int report = 0;
@@ -464,7 +464,7 @@ int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
        if (nlh)
                report = nlmsg_report(nlh);
 
-       return nlmsg_notify(rtnl, skb, pid, group, report, flags);
+       nlmsg_notify(rtnl, skb, pid, group, report, flags);
 }
 
 void 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)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
index daf2b98b15fef79d3d9d1915ebe48a36b6007d1e..e457769bf7a7b81b0f4e7557a59688ff916995d4 100644 (file)
@@ -769,7 +769,8 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
+       rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
index 69ad9280c6936a99975bdf2f7d8361b8924783c7..67054b0d550f9a26b47b469c3a542d083ef5a00f 100644 (file)
@@ -375,7 +375,8 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
+       rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
index d519a6a6672634902f93459e0581e92a2af51f0b..126bb911880fa675861f4b1940655e18fcbe1774 100644 (file)
@@ -1216,7 +1216,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
+       rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
index 4817dea3bc737225ec99a605b3b5d5681ac6e082..f831df500907cb9644b601685b150c1a39aa8485 100644 (file)
@@ -322,8 +322,9 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
-                         info->nlh, GFP_KERNEL);
+       rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
+                   info->nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
index 03e2a1ad71e9605e95ed47f2688412cd9f86b8df..f8f76d6e21cbe3d212a6d6d830ce3a9cc46c1c03 100644 (file)
@@ -3638,7 +3638,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3849,7 +3850,8 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3919,7 +3921,8 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
index 3cd83b85e9efd39ddaa12d1541568cdb7d83f490..9f061d1adbc2b3770d987ff0fe239a2ef29417bc 100644 (file)
@@ -1095,11 +1095,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
                &ipv6_hdr(ra)->saddr);
        nlmsg_end(skb, nlh);
 
-       err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL,
-                         GFP_ATOMIC);
-       if (err < 0)
-               goto errout;
-
+       rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
        return;
 
 nla_put_failure:
index c3d486a3edad17f4a9125829462863850ced9a65..1394ddb6e35c5a570cc34f0be3d6d11b55651cc3 100644 (file)
@@ -2400,8 +2400,9 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
-                         info->nlh, gfp_any());
+       rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
+                   info->nlh, gfp_any());
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
index ed587be1e1c2b972770f37a167570b4d88b50861..2760b62dc2c12a16c85630e49d82cf78f75a977c 100644 (file)
@@ -1760,12 +1760,18 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
                        exclude_pid = pid;
                }
 
-               /* errors reported via destination sk->sk_err */
-               nlmsg_multicast(sk, skb, exclude_pid, group, flags);
+               /* errors reported via destination sk->sk_err, but propagate
+                * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
+               err = nlmsg_multicast(sk, skb, exclude_pid, group, flags);
        }
 
-       if (report)
-               err = nlmsg_unicast(sk, skb, pid);
+       if (report) {
+               int err2;
+
+               err2 = nlmsg_unicast(sk, skb, pid);
+               if (!err || err == -ESRCH)
+                       err = err2;
+       }
 
        return err;
 }
index 1ceea1f92413d2d4b03d545152f339e628ab9b33..cec4e59516817ecc0b64a8fdaa04c11de52aa0b2 100644 (file)
@@ -47,8 +47,9 @@ static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, dev_net(dev), 0,
-                         RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
+       rtnl_notify(skb, dev_net(dev), 0,
+                   RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);