: Clean up netlink NLM_F_ECHO and rtnl event notifications
Subsystems (6)
PATCH 1/1 : Clean up netlink NLM_F_ECHO and rtnl event notifications
Aims at cleaning up rtnetlink event notifications and implements real NLM_F_ECHO support.
Please disregard my last IPv4 routing related patchset, I'll resubmit it based on this patchset.
PATCH 1/4 : Handle NLM_F_ECHO in netlink_rcv_skb()
The current behaviour around NLM_F_ECHO is inconsistent and spread all around in various subsystems and doesn't represent what it was meant for.
This patch handles NLM_F_ECHO in netlink_rcv_skb() to handle it in a central point. Most subsystems currently interpret NLM_F_ECHO as to just unicast events to the originator of the change while the real meaning of the flag is to echo the request.
net/netlink/af_netlink.c +25 -0
@@ -1430,6 +1430,28 @@ int netlink_dump_start(struct sock *ssk,return 0 ; } +static void netlink_echo (struct sk_buff *in_skb,struct nlmsghdr *orig) +{ +struct sk_buff *skb; +struct nlmsghdr *nlh; +int payload =nlmsg_len (orig); + + skb =nlmsg_new (nlmsg_total_size (payload),GFP_KERNEL ); +if (skb ==NULL ) +return ; + +/* +* Return original header with pid set to 0 (from kernel) and +* NLM_F_REQUEST flag removed to indicate this is not a request +* for an echo but the reply. +*/ + nlh =__nlmsg_put (skb,0 , orig->nlmsg_seq, orig->nlmsg_type, + payload, orig->nlmsg_flags & ~NLM_F_REQUEST ); +memcpy (nlmsg_data (nlh),nlmsg_data (orig), payload); + +nlmsg_unicast (in_skb->sk, skb,NETLINK_CB (in_skb).pid); +} +void netlink_ack (struct sk_buff *in_skb,struct nlmsghdr *nlh,int err) {struct sk_buff *skb;
@@ -1476,6 +1498,9 @@ static int netlink_rcv_skb(struct sk_bufif (nlh->nlmsg_len <NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)return 0 ; +if (nlh->nlmsg_flags &NLM_F_ECHO ) +netlink_echo (skb, nlh); +if (cb (skb, nlh, &err) <0 ) {/* Not an error, but we have to interrupt processing * here. Note: that in this case we do not pull
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 5 lines
This patch handles
NLM_F_ECHOinnetlink_rcv_skb()to handle it in a central point. Most subsystems currently interpretNLM_F_ECHOas to just unicast events to the originator of the change while the real meaning of the flag is to echo the request.
Do not you think it is useless to echo something back to originator, who just sent it?
Actually, the sense of NLM_F_ECHO was to tell user what happened due to his request. The answer is not original request, which can contain some incomplete fields etc., but full information about object deleted/added/changed. Moreover, the feedback can contain several messages (though accurately it is done only in net/sched/), f.e. when the request triggered deletion of one object and addition of another.
Obviously, it cannot be done in a central place.
Normally, it is not needed, "ip route add" does not tell user, what actually was done, so that it suppresses echo. But for multistage operation it is absolutely necessary: the answer contains f.e. auto-allocated handles, which should be given in subsequent requests.
Alexey
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
* Alexey Kuznetsov <[email protected]> 2006-08-10 19:51
Quoted 16 lines
Quoted 5 lines
This patch handles
NLM_F_ECHOinnetlink_rcv_skb()to handle it in a central point. Most subsystems currently interpretNLM_F_ECHOas to just unicast events to the originator of the change while the real meaning of the flag is to echo the request.Do not you think it is useless to echo something back to originator, who just sent it?
Actually, the sense of
NLM_F_ECHOwas to tell user what happened due to his request. The answer is not original request, which can contain some incomplete fields etc., but full information about object deleted/added/changed. Moreover, the feedback can contain several messages (though accurately it is done only innet/sched/), f.e. when the request triggered deletion of one object and addition of another.
Quoted 6 lines
Obviously, it cannot be done in a central place.
Normally, it is not needed, "ip route add" does not tell user, what actually was done, so that it suppresses echo. But for multistage operation it is absolutely necessary: the answer contains f.e. auto-allocated handles, which should be given in subsequent requests.
What's wrong with listening to the notification for that purpose?
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 1 line
What's wrong with listening to the notification for that purpose?
Nothing! NLM_F_ECHO _is_ listening for notifications without subscription to multicast groups and need to figure out what messages are yours. But beyond this NLM_F_ECHO is totally subset of this.
Which still makes much more sense then echoing of a know thing, does not it?
Alexey
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello
* Alexey Kuznetsov <[email protected]> 2006-08-11 00:32
Quoted 4 lines
Nothing!
NLM_F_ECHO_is_ listening for notifications without subscription to multicast groups and need to figure out what messages are yours. But beyond thisNLM_F_ECHOis totally subset of this.
Which still makes much more sense then echoing of a know thing, does not it?
I get your point and I see the value. Unfortunately, probably due to lack of documentation, this feature isn't used by any applications I know of. We even put in the hacks to make identification of own caused notifications easier by storing the netlink pid of the originator in the notification message.
I will put this back in (document it! :) and hide it behind nlmsg_notify() so we do it for all notifications for consistency.
I use echoing of the original request for debuging purposes, it allows to verify what is actually being parsed at the netlink family specific parsing function. Using libnl a flag enables NLM_F_ECHO in all messages and it gets simple to verify what exactly is being seen in the kernel side parser by looking at the messages log. I agree, there is no functional value besides the possibility to implement a netlink ping with NLMSG_NOOP.
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 3 lines
I get your point and I see the value. Unfortunately, probably due to lack of documentation, this feature isn't used by any applications I know of.
Well, tc was supposed to use it, but this did not happen and it remained deficient.
Quoted 3 lines
We even put in the hacks to make identification of own caused notifications easier by storing the netlink pid of the originator in the notification message.
Actually, it was supposed to be done everywhere, but originator info did not propagate deep enough in many cases, especially in IPv6. So, this is not a hack, it is a good work. :-)
BTW I have just remembered why it was especially important, this should be documented as well.
Each socket, which subscribes to multicasts becomes sensitive to rcvbuf overflows. F.e. when you do control operations on a socket, which is subscribed to multicasts, the response can be lost in stream of events and -ENOBUFS generated instead. If it is a daemon, it can resync the state, but if it is a simple utility, it cannot recover.
Probably, unicasts sent due to NLM_F_ECHO should somehow override rcvbuf limits.
This reminded me about a capital problem, found by openvz people. Frankly speaking, I still have no idea how to repair this, probably you will find a solution.
Look: while a dump, skb allocation can fail (because of many reasons, the most obvious is that rcvbuf space was eaten by multicasts). But error is not reported! Oops. The worst thing is that even if an error is reported, iproute would ignore it.
Alexey
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
* Alexey Kuznetsov <[email protected]> 2006-08-11 19:35
Quoted 2 lines
Well, tc was supposed to use it, but this did not happen and it remained deficient.
Makes sense, especially for auto generated handles. I've been listening to the notifications on a separate socket for this purpose. It would make sense however to extend a wait_for_ack() function and report back and eventual echoed objects to have a blocking operation as well.
Quoted 3 lines
Actually, it was supposed to be done everywhere, but originator info did not propagate deep enough in many cases, especially in IPv6. So, this is not a hack, it is a good work. :-)
It does make sense, the way it has been implemented if at all is creepy. Even worse, IPv6 is using current->pid, some other code has been using the pid from NETLINK_CREDS() :-)
Quoted 5 lines
Each socket, which subscribes to multicasts becomes sensitive to rcvbuf overflows. F.e. when you do control operations on a socket, which is subscribed to multicasts, the response can be lost in stream of events and
-ENOBUFSgenerated instead. If it is a daemon, it can resync the state, but if it is a simple utility, it cannot recover.
Yes, for that reason it is recommended to use a separate socket when receiving multicasts. Also because some of the multicast code is buggy and provides the pid of the requestor's socket to netlink_broadcast() leading to excluding that socket.
Quoted 11 lines
Probably, unicasts sent due to
NLM_F_ECHOshould somehow override rcvbuf limits.This reminded me about a capital problem, found by openvz people. Frankly speaking, I still have no idea how to repair this, probably you will find a solution.
Look: while a dump, skb allocation can fail (because of many reasons, the most obvious is that rcvbuf space was eaten by multicasts). But error is not reported! Oops. The worst thing is that even if an error is reported, iproute would ignore it.
I'm not sure I understand this correctly, if rcvbuf space was eaten by multicasts subsequent recvmsg() will follow invoking netlink_dump() again and the dump continues.
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 2 lines
Makes sense, especially for auto generated handles. I've been listening to the notifications on a separate socket for this purpose.
That's... complicated. But cool. :-)
Quoted 3 lines
It does make sense, the way it has been implemented if at all is creepy. Even worse, IPv6 is using
current->pid, some other code has been using the pid fromNETLINK_CREDS():-)
Yeah, some time ago I sent a path replacing those with 0, but apparently I forgot to grep IPv6. And did not even search for NETLINK_CREDS().
Quoted 3 lines
when receiving multicasts. Also because some of the multicast code is buggy and provides the pid of the requestor's socket to
netlink_broadcast()leading to excluding that socket.
Actually, it was the idea. If requestor asked NLM_F_ECHO and subscribed to muticasts, it suppresses double notifications. If it did not ask NLM_F_ECHO, he is not interested in results, he knows what's going on without this.
F.e. it was used by my implementation in gated: it did not set either NLM_F_ECHO or even NLM_F_ACK. And when making massive batch updates, it received nothing back: only errors and updates made by someone else.
Quoted 3 lines
I'm not sure I understand this correctly, if rcvbuf space was eaten by multicasts subsequent
recvmsg()will follow invokingnetlink_dump()again and the dump continues.
Indeed. I forgot how it works. :-)
I understood what is happening there. sock_rmalloc() fails not due to rcvbuf, but because of global resource limiting. Grr... it does not look solvable. Luckily, in normal kernel this can happen only if 0-order GFP_KERNEL allocation fails. Not impossible with oom_killer, but it definitely moves the status of the problem to marginal.
Alexey
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
* Alexey Kuznetsov <[email protected]> 2006-08-12 15:03
Quoted 8 lines
Actually, it was the idea. If requestor asked
NLM_F_ECHOand subscribed to muticasts, it suppresses double notifications. If it did not askNLM_F_ECHO, he is not interested in results, he knows what's going on without this.F.e. it was used by my implementation in gated: it did not set either
NLM_F_ECHOor evenNLM_F_ACK. And when making massive batch updates, it received nothing back: only errors and updates made by someone else.
So we do something like this:
/**
* nlmsg_notify - send a notification netlink message
* @sk: netlink socket to use
* @skb: notification message
* @pid: destination netlink pid for reports or 0
* @group: destination multicast group or 0
* @report: 1 to report back, 0 to disable
* @flags: allocation flags
*/
int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
unsigned int group, int report, gfp_t flags)
{
int err = 0;
if (group) {
int exclude_pid = 0;
if (report) {
atomic_inc(&skb->users);
exclude_pid = pid;
}
/* errors reported via destination sk->sk_err */
nlmsg_multicast(sk, skb, exclude_pid, group, flags);
}
if (report)
err = nlmsg_unicast(sk, skb, pid);
return err;
}Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 1 line
So we do something like this:
Yes, exactly.
Actually, there was a function with similar functionality: rtnetlink_send(). net/sched/* used it, older net/ipv4/ still did this directly.
Alexey
Re: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
In reply to Alexey KuznetsovQuoted 3 lines · Alexey Kuznetsov
Probably, unicasts sent due to
NLM_F_ECHOshould somehow override rcvbuf limits.
Actually I think the only safe solution is to allocate a separate socket for multicast messages. In other words, if you want reliable unicast reception on a socket, don't bind it to a multicast group.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtRe: [PATCH 1/4] [NETLINK]: Handle NLM_F_ECHO in netlink_rcv_skb()
Hello!
Quoted 3 lines
Actually I think the only safe solution is to allocate a separate socket for multicast messages. In other words, if you want reliable unicast reception on a socket, don't bind it to a multicast group.
Yes, it was the point of my advocacy of NLM_F_ECHO. :-)
Alexey
PATCH 2/4 : Use rtnl_multicast()/rtnl_unicast()
In reply to Thomas GrafIntroduces rtnl_multicast() to broadcast events and rtnl_unicast() to send unicast messages via the rtnl socket.
This obsoletes rtnetlink_send() which wrongly provided the netlink pid of the requesting applications to netlink_broadcast() which lead to events not being sent to that application even though it was subscribed.
This patch ensures consistency in all rtnetlink event notification mechansims, i.e. the pid of the requesting application is kept in nlmsg_pid to help applications such as quagga to identify whether the event was caused by themselves and properly feeds all calls to netlink_broadcast() with a pid of 0 to not exclude any sockets.
Removes the obsoleted NLM_F_ECHO code.
Some notifications are done in atomic contex, therefore nlmsg_multicast() had to be extended to take allocation flags.
include/linux/rtnetlink.h +2 -1
@@ -583,7 +583,8 @@ struct rtnetlink_link };extern struct rtnetlink_link * rtnetlink_links[NPROTO ]; -extern int rtnetlink_send (struct sk_buff *skb,u32 pid,u32 group,int echo); +extern int rtnl_multicast (struct sk_buff *skb,unsigned int group,gfp_t flags); +extern int rtnl_unicast (struct sk_buff *skb,u32 pid);extern int rtnetlink_put_metrics (struct sk_buff *skb,u32 *metrics);extern void __rta_fill (struct sk_buff *skb,int attrtype,int attrlen,const void *data);
net/core/rtnetlink.c +9 -14
@@ -153,17 +153,14 @@ size_t rtattr_strlcpy(char *dest, constreturn ret; } -int rtnetlink_send (struct sk_buff *skb,u32 pid,unsigned group,int echo) +int rtnl_multicast (struct sk_buff *skb,unsigned int group,gfp_t flags) { -int err =0 ; +return nlmsg_multicast (rtnl, skb,0 , group, flags); +} -NETLINK_CB (skb).dst_group = group; -if (echo) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid, group,GFP_KERNEL ); -if (echo) - err =netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); -return err; +int rtnl_unicast (struct sk_buff *skb,u32 pid) +{ +return nlmsg_unicast (rtnl, skb, pid); }int rtnetlink_put_metrics (struct sk_buff *skb,u32 *metrics)
@@ -560,9 +557,7 @@ static int rtnl_getlink(struct sk_buff * goto errout; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (skb).pid); errout:kfree (iw_buf);dev_put (dev);
@@ -609,8 +604,8 @@ void rtmsg_ifinfo(int type, struct net_dkfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_KERNEL ); + +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_KERNEL ); }/* Protected by RTNL sempahore. */
net/decnet/dn_table.c +2 -6
@@ -343,12 +343,8 @@ static void dn_rtmsg_fib(int event, strukfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group = RTNLGRP_DECnet_ROUTE; -if (nlh->nlmsg_flags &NLM_F_ECHO ) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid, RTNLGRP_DECnet_ROUTE,GFP_KERNEL ); -if (nlh->nlmsg_flags &NLM_F_ECHO ) -netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); + +rtnl_multicast (skb, RTNLGRP_DECnet_ROUTE,GFP_KERNEL ); } static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
net/ipv4/fib_semantics.c +2 -6
@@ -291,12 +291,8 @@ void rtmsg_fib(int event, u32 key, struckfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV4_ROUTE ; -if (n->nlmsg_flags&NLM_F_ECHO ) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid,RTNLGRP_IPV4_ROUTE ,GFP_KERNEL ); -if (n->nlmsg_flags&NLM_F_ECHO ) -netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); + +rtnl_multicast (skb,RTNLGRP_IPV4_ROUTE ,GFP_KERNEL ); }/* Return the first fib alias matching TOS with
net/sched/act_api.c +6 -20
@@ -459,7 +459,6 @@ static int act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) { struct sk_buff *skb; -int err =0 ; skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL );if (!skb)
@@ -468,10 +467,8 @@ act_get_notify(u32 pid, struct nlmsghdrkfree_skb (skb);return -EINVAL ; } - err =netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; -return err; + +return rtnl_unicast (skb, pid); } static struct tc_action *
@@ -592,11 +589,8 @@ static int tca_action_flush(struct rtatt nlh->nlmsg_flags |=NLM_F_ROOT ;module_put (a->ops->owner);kfree (a); - err =rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); -if (err >0 ) -return 0 ; -return err; +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); rtattr_failure: nlmsg_failure:
@@ -655,11 +649,8 @@ tca_action_gd(struct rtattr *rta, struct/* now do the delete */ tcf_action_destroy (head,0 ); - ret =rtnetlink_send (skb, pid,RTNLGRP_TC , - n->nlmsg_flags&NLM_F_ECHO ); -if (ret >0 ) -return 0 ; -return ret; + +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); } err:cleanup_a (head);
@@ -674,7 +665,6 @@ static int tcf_add_notify(struct tc_actistruct sk_buff *skb;struct rtattr *x;unsigned char *b; -int err =0 ; skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL );if (!skb)
@@ -697,12 +687,8 @@ static int tcf_add_notify(struct tc_acti x->rta_len = skb->tail - (u8 *)x; nlh->nlmsg_len = skb->tail - b; -NETLINK_CB (skb).dst_group =RTNLGRP_TC ; - err =rtnetlink_send (skb, pid,RTNLGRP_TC , flags&NLM_F_ECHO ); -if (err >0 ) - err =0 ; -return err; +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); rtattr_failure: nlmsg_failure:
net/sched/cls_api.c +1 -1
@@ -366,7 +366,7 @@ static int tfilter_notify(struct sk_buffreturn -EINVAL ; } -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); }struct tcf_dump_args
net/sched/sch_api.c +2 -2
@@ -815,7 +815,7 @@ static int qdisc_notify(struct sk_buff * }if (skb->len) -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); err_out:kfree_skb (skb);
@@ -1039,7 +1039,7 @@ static int tclass_notify(struct sk_buffreturn -EINVAL ; } -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); }struct qdisc_dump_args
include/net/genetlink.h +3 -2
@@ -133,11 +133,12 @@ static inline int genlmsg_cancel(struct* @skb: netlink message as socket buffer * @pid: own netlink pid to avoid sending to yourself * @group: multicast group id +* @flags: allocation flags */ static inline int genlmsg_multicast (struct sk_buff *skb,u32 pid, -unsigned int group) +unsigned int group,gfp_t flags) { -return nlmsg_multicast (genl_sock, skb, pid, group); +return nlmsg_multicast (genl_sock, skb, pid, group, flags); }/**
include/net/netlink.h +3 -2
@@ -545,15 +545,16 @@ static inline void nlmsg_free(struct sk_* @skb: netlink message as socket buffer * @pid: own netlink pid to avoid sending to yourself * @group: multicast group id +* @flags: allocation flags */ static inline int nlmsg_multicast (struct sock *sk,struct sk_buff *skb, -u32 pid,unsigned int group) +u32 pid,unsigned int group,gfp_t flags) {int err;NETLINK_CB (skb).dst_group = group; - err =netlink_broadcast (sk, skb, pid, group,GFP_KERNEL ); + err =netlink_broadcast (sk, skb, pid, group, flags);if (err >0 ) err =0 ;
net/netlabel/netlabel_user.c +1 -1
@@ -154,5 +154,5 @@ int netlbl_netlink_snd(struct sk_buff *s*/ int netlbl_netlink_snd_multicast (struct sk_buff *skb,u32 pid,u32 group) { -return genlmsg_multicast (skb, pid, group); +return genlmsg_multicast (skb, pid, group,GFP_KERNEL ); }
net/netlink/genetlink.c +1 -1
@@ -510,7 +510,7 @@ static int genl_ctrl_event(int event, voif (IS_ERR (msg))return PTR_ERR (msg); -genlmsg_multicast (msg,0 ,GENL_ID_CTRL ); +genlmsg_multicast (msg,0 ,GENL_ID_CTRL ,GFP_KERNEL );break ; }
net/bridge/br_netlink.c +1 -2
@@ -88,8 +88,7 @@ void br_ifinfo_notify(int event, structif (err) goto err_kfree; -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_ATOMIC ); +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC );return ; err_kfree:
net/core/fib_rules.c +1 -1
@@ -354,7 +354,7 @@ static void notify_rule_change(int eventkfree_skb (skb);netlink_set_err (rtnl,0 , ops->nlgroup,EINVAL ); }else -netlink_broadcast (rtnl, skb,0 , ops->nlgroup,GFP_KERNEL ); +rtnl_multicast (skb, ops->nlgroup,GFP_KERNEL ); }static void attach_rules (struct list_head *rules,struct net_device *dev)
net/core/neighbour.c +4 -8
@@ -2416,10 +2416,8 @@ void neigh_app_ns(struct neighbour *n)if (neigh_fill_info (skb, n,0 ,0 ,RTM_GETNEIGH ,NLM_F_REQUEST ) <=0 )kfree_skb (skb); -else { -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); - } +else +rtnl_multicast (skb,RTNLGRP_NEIGH ,GFP_ATOMIC ); }static void neigh_app_notify (struct neighbour *n)
@@ -2432,10 +2430,8 @@ static void neigh_app_notify(struct neigif (neigh_fill_info (skb, n,0 ,0 ,RTM_NEWNEIGH ,0 ) <=0 )kfree_skb (skb); -else { -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); - } +else + rtnl_multicast(skb, RTNLGRP_NEIGH, GFP_ATOMIC); }#endif /* CONFIG_ARPD */
net/core/wireless.c +2 -2
@@ -1903,8 +1903,8 @@ static inline void rtmsg_iwinfo(struct nkfree_skb (skb); return; } -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC ); }#endif /* WE_EVENT_RTNETLINK */
net/decnet/dn_dev.c +2 -2
@@ -757,8 +757,8 @@ static void rtmsg_ifa(int event, structnetlink_set_err (rtnl,0 , RTNLGRP_DECnet_IFADDR,EINVAL );return ; } -NETLINK_CB (skb).dst_group = RTNLGRP_DECnet_IFADDR; -netlink_broadcast (rtnl, skb,0 , RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); + +rtnl_multicast (skb, RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); }static int dn_dev_dump_ifaddr (struct sk_buff *skb,struct netlink_callback *cb)
net/decnet/dn_route.c +1 -3
@@ -1609,9 +1609,7 @@ int dn_cache_getroute(struct sk_buff *in goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); - -return err; +return rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out_free:kfree_skb (skb);
net/ipv4/devinet.c +1 -1
@@ -1200,7 +1200,7 @@ static void rtmsg_ifa(int event, structkfree_skb (skb);netlink_set_err (rtnl,0 ,RTNLGRP_IPV4_IFADDR ,EINVAL ); }else -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV4_IFADDR ,GFP_KERNEL ); +rtnl_multicast (skb,RTNLGRP_IPV4_IFADDR ,GFP_KERNEL ); }static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES ] = {
net/ipv4/ipmr.c +2 -2
@@ -312,7 +312,7 @@ static void ipmr_destroy_unres(struct mf e =NLMSG_DATA (nlh); e->error = -ETIMEDOUT ;memset (&e->msg,0 ,sizeof (e->msg)); -netlink_unicast (rtnl, skb,NETLINK_CB (skb).dst_pid,MSG_DONTWAIT ); +rtnl_unicast (skb,NETLINK_CB (skb).dst_pid); }else kfree_skb (skb); }
@@ -525,7 +525,7 @@ static void ipmr_cache_resolve(struct mf e->error = -EMSGSIZE ;memset (&e->msg,0 ,sizeof (e->msg)); } - err =netlink_unicast (rtnl, skb,NETLINK_CB (skb).dst_pid,MSG_DONTWAIT ); + err =rtnl_unicast (skb,NETLINK_CB (skb).dst_pid); }else ip_mr_forward (skb, c,0 ); }
net/ipv4/route.c +1 -3
@@ -2808,9 +2808,7 @@ int inet_rtm_getroute(struct sk_buff *in goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:return err; out_free:
net/ipv6/addrconf.c +7 -9
@@ -3268,9 +3268,7 @@ static int inet6_rtm_getaddr(struct sk_b goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:in6_ifa_put (ifa);return err;
@@ -3294,8 +3292,8 @@ static void inet6_ifa_notify(int event,netlink_set_err (rtnl,0 ,RTNLGRP_IPV6_IFADDR ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_IFADDR ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_IFADDR ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_IFADDR ,GFP_ATOMIC ); } static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
@@ -3448,8 +3446,8 @@ void inet6_ifinfo_notify(int event, strunetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_IFINFO ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_IFINFO ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_IFINFO ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_IFINFO ,GFP_ATOMIC ); }/* Maximum length of prefix_cacheinfo attributes */
@@ -3513,8 +3511,8 @@ static void inet6_prefix_notify(int evennetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_PREFIX ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_PREFIX ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_PREFIX ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_PREFIX ,GFP_ATOMIC ); }static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES ] = {
net/ipv6/route.c +3 -5
@@ -2161,9 +2161,7 @@ int inet6_rtm_getroute(struct sk_buff *i goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:return err; out_free:
@@ -2194,8 +2192,8 @@ void inet6_rt_notify(int event, struct rnetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_ROUTE ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_ROUTE ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_ROUTE ,gfp_any ()); + +rtnl_multicast (skb,RTNLGRP_IPV6_ROUTE ,gfp_any ()); }/*
PATCH RESEND 2/4 : Use rtnl_multicast()/rtnl_unicast()
... forgot to export the new symbols.
Introduces rtnl_multicast() to broadcast events and rtnl_unicast() to send unicast messages via the rtnl socket.
This obsoletes rtnetlink_send() which wrongly provided the netlink pid of the requesting applications to netlink_broadcast() which lead to events not being sent to that application even though it was subscribed.
This patch ensures consistency in all rtnetlink event notification mechansims, i.e. the pid of the requesting application is kept in nlmsg_pid to help applications such as quagga to identify whether the event was caused by themselves and properly feeds all calls to netlink_broadcast() with a pid of 0 to not exclude any sockets.
Removes the obsoleted NLM_F_ECHO code.
Some notifications are done in atomic contex, therefore nlmsg_multicast() had to be extended to take allocation flags.
include/linux/rtnetlink.h +2 -1
@@ -583,7 +583,8 @@ struct rtnetlink_link };extern struct rtnetlink_link * rtnetlink_links[NPROTO ]; -extern int rtnetlink_send (struct sk_buff *skb,u32 pid,u32 group,int echo); +extern int rtnl_multicast (struct sk_buff *skb,unsigned int group,gfp_t flags); +extern int rtnl_unicast (struct sk_buff *skb,u32 pid);extern int rtnetlink_put_metrics (struct sk_buff *skb,u32 *metrics);extern void __rta_fill (struct sk_buff *skb,int attrtype,int attrlen,const void *data);
net/core/rtnetlink.c +11 -14
@@ -153,17 +153,14 @@ size_t rtattr_strlcpy(char *dest, constreturn ret; } -int rtnetlink_send (struct sk_buff *skb,u32 pid,unsigned group,int echo) +int rtnl_multicast (struct sk_buff *skb,unsigned int group,gfp_t flags) { -int err =0 ; +return nlmsg_multicast (rtnl, skb,0 , group, flags); +} -NETLINK_CB (skb).dst_group = group; -if (echo) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid, group,GFP_KERNEL ); -if (echo) - err =netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); -return err; +int rtnl_unicast (struct sk_buff *skb,u32 pid) +{ +return nlmsg_unicast (rtnl, skb, pid); }int rtnetlink_put_metrics (struct sk_buff *skb,u32 *metrics)
@@ -560,9 +557,7 @@ static int rtnl_getlink(struct sk_buff * goto errout; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (skb).pid); errout:kfree (iw_buf);dev_put (dev);
@@ -609,8 +604,8 @@ void rtmsg_ifinfo(int type, struct net_dkfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_KERNEL ); + +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_KERNEL ); }/* Protected by RTNL sempahore. */
@@ -811,3 +806,5 @@ EXPORT_SYMBOL(rtnl);EXPORT_SYMBOL (rtnl_lock);EXPORT_SYMBOL (rtnl_trylock);EXPORT_SYMBOL (rtnl_unlock); +EXPORT_SYMBOL (rtnl_multicast); +EXPORT_SYMBOL (rtnl_unicast);
net/decnet/dn_table.c +2 -6
@@ -343,12 +343,8 @@ static void dn_rtmsg_fib(int event, strukfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group = RTNLGRP_DECnet_ROUTE; -if (nlh->nlmsg_flags &NLM_F_ECHO ) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid, RTNLGRP_DECnet_ROUTE,GFP_KERNEL ); -if (nlh->nlmsg_flags &NLM_F_ECHO ) -netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); + +rtnl_multicast (skb, RTNLGRP_DECnet_ROUTE,GFP_KERNEL ); } static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
net/ipv4/fib_semantics.c +2 -6
@@ -291,12 +291,8 @@ void rtmsg_fib(int event, u32 key, struckfree_skb (skb);return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV4_ROUTE ; -if (n->nlmsg_flags&NLM_F_ECHO ) -atomic_inc (&skb->users); -netlink_broadcast (rtnl, skb, pid,RTNLGRP_IPV4_ROUTE ,GFP_KERNEL ); -if (n->nlmsg_flags&NLM_F_ECHO ) -netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); + +rtnl_multicast (skb,RTNLGRP_IPV4_ROUTE ,GFP_KERNEL ); }/* Return the first fib alias matching TOS with
net/sched/act_api.c +6 -20
@@ -459,7 +459,6 @@ static int act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) { struct sk_buff *skb; -int err =0 ; skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL );if (!skb)
@@ -468,10 +467,8 @@ act_get_notify(u32 pid, struct nlmsghdrkfree_skb (skb);return -EINVAL ; } - err =netlink_unicast (rtnl, skb, pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; -return err; + +return rtnl_unicast (skb, pid); } static struct tc_action *
@@ -592,11 +589,8 @@ static int tca_action_flush(struct rtatt nlh->nlmsg_flags |=NLM_F_ROOT ;module_put (a->ops->owner);kfree (a); - err =rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); -if (err >0 ) -return 0 ; -return err; +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); rtattr_failure: nlmsg_failure:
@@ -655,11 +649,8 @@ tca_action_gd(struct rtattr *rta, struct/* now do the delete */ tcf_action_destroy (head,0 ); - ret =rtnetlink_send (skb, pid,RTNLGRP_TC , - n->nlmsg_flags&NLM_F_ECHO ); -if (ret >0 ) -return 0 ; -return ret; + +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); } err:cleanup_a (head);
@@ -674,7 +665,6 @@ static int tcf_add_notify(struct tc_actistruct sk_buff *skb;struct rtattr *x;unsigned char *b; -int err =0 ; skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL );if (!skb)
@@ -697,12 +687,8 @@ static int tcf_add_notify(struct tc_acti x->rta_len = skb->tail - (u8 *)x; nlh->nlmsg_len = skb->tail - b; -NETLINK_CB (skb).dst_group =RTNLGRP_TC ; - err =rtnetlink_send (skb, pid,RTNLGRP_TC , flags&NLM_F_ECHO ); -if (err >0 ) - err =0 ; -return err; +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); rtattr_failure: nlmsg_failure:
net/sched/cls_api.c +1 -1
@@ -366,7 +366,7 @@ static int tfilter_notify(struct sk_buffreturn -EINVAL ; } -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); }struct tcf_dump_args
net/sched/sch_api.c +2 -2
@@ -815,7 +815,7 @@ static int qdisc_notify(struct sk_buff * }if (skb->len) -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); err_out:kfree_skb (skb);
@@ -1039,7 +1039,7 @@ static int tclass_notify(struct sk_buffreturn -EINVAL ; } -return rtnetlink_send (skb, pid,RTNLGRP_TC , n->nlmsg_flags&NLM_F_ECHO ); +return rtnl_multicast (skb,RTNLGRP_TC ,GFP_KERNEL ); }struct qdisc_dump_args
include/net/genetlink.h +3 -2
@@ -133,11 +133,12 @@ static inline int genlmsg_cancel(struct* @skb: netlink message as socket buffer * @pid: own netlink pid to avoid sending to yourself * @group: multicast group id +* @flags: allocation flags */ static inline int genlmsg_multicast (struct sk_buff *skb,u32 pid, -unsigned int group) +unsigned int group,gfp_t flags) { -return nlmsg_multicast (genl_sock, skb, pid, group); +return nlmsg_multicast (genl_sock, skb, pid, group, flags); }/**
include/net/netlink.h +3 -2
@@ -545,15 +545,16 @@ static inline void nlmsg_free(struct sk_* @skb: netlink message as socket buffer * @pid: own netlink pid to avoid sending to yourself * @group: multicast group id +* @flags: allocation flags */ static inline int nlmsg_multicast (struct sock *sk,struct sk_buff *skb, -u32 pid,unsigned int group) +u32 pid,unsigned int group,gfp_t flags) {int err;NETLINK_CB (skb).dst_group = group; - err =netlink_broadcast (sk, skb, pid, group,GFP_KERNEL ); + err =netlink_broadcast (sk, skb, pid, group, flags);if (err >0 ) err =0 ;
net/netlabel/netlabel_user.c +1 -1
@@ -154,5 +154,5 @@ int netlbl_netlink_snd(struct sk_buff *s*/ int netlbl_netlink_snd_multicast (struct sk_buff *skb,u32 pid,u32 group) { -return genlmsg_multicast (skb, pid, group); +return genlmsg_multicast (skb, pid, group,GFP_KERNEL ); }
net/netlink/genetlink.c +1 -1
@@ -510,7 +510,7 @@ static int genl_ctrl_event(int event, voif (IS_ERR (msg))return PTR_ERR (msg); -genlmsg_multicast (msg,0 ,GENL_ID_CTRL ); +genlmsg_multicast (msg,0 ,GENL_ID_CTRL ,GFP_KERNEL );break ; }
net/bridge/br_netlink.c +1 -2
@@ -88,8 +88,7 @@ void br_ifinfo_notify(int event, structif (err) goto err_kfree; -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_ATOMIC ); +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC );return ; err_kfree:
net/core/fib_rules.c +1 -1
@@ -354,7 +354,7 @@ static void notify_rule_change(int eventkfree_skb (skb);netlink_set_err (rtnl,0 , ops->nlgroup,EINVAL ); }else -netlink_broadcast (rtnl, skb,0 , ops->nlgroup,GFP_KERNEL ); +rtnl_multicast (skb, ops->nlgroup,GFP_KERNEL ); }static void attach_rules (struct list_head *rules,struct net_device *dev)
net/core/neighbour.c +4 -8
@@ -2416,10 +2416,8 @@ void neigh_app_ns(struct neighbour *n)if (neigh_fill_info (skb, n,0 ,0 ,RTM_GETNEIGH ,NLM_F_REQUEST ) <=0 )kfree_skb (skb); -else { -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); - } +else +rtnl_multicast (skb,RTNLGRP_NEIGH ,GFP_ATOMIC ); }static void neigh_app_notify (struct neighbour *n)
@@ -2432,10 +2430,8 @@ static void neigh_app_notify(struct neigif (neigh_fill_info (skb, n,0 ,0 ,RTM_NEWNEIGH ,0 ) <=0 )kfree_skb (skb); -else { -NETLINK_CB (skb).dst_group =RTNLGRP_NEIGH ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_NEIGH ,GFP_ATOMIC ); - } +else + rtnl_multicast(skb, RTNLGRP_NEIGH, GFP_ATOMIC); }#endif /* CONFIG_ARPD */
net/core/wireless.c +2 -2
@@ -1903,8 +1903,8 @@ static inline void rtmsg_iwinfo(struct nkfree_skb (skb); return; } -NETLINK_CB (skb).dst_group =RTNLGRP_LINK ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_LINK ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC ); }#endif /* WE_EVENT_RTNETLINK */
net/decnet/dn_dev.c +2 -2
@@ -757,8 +757,8 @@ static void rtmsg_ifa(int event, structnetlink_set_err (rtnl,0 , RTNLGRP_DECnet_IFADDR,EINVAL );return ; } -NETLINK_CB (skb).dst_group = RTNLGRP_DECnet_IFADDR; -netlink_broadcast (rtnl, skb,0 , RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); + +rtnl_multicast (skb, RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); }static int dn_dev_dump_ifaddr (struct sk_buff *skb,struct netlink_callback *cb)
net/decnet/dn_route.c +1 -3
@@ -1609,9 +1609,7 @@ int dn_cache_getroute(struct sk_buff *in goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); - -return err; +return rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out_free:kfree_skb (skb);
net/ipv4/devinet.c +1 -1
@@ -1200,7 +1200,7 @@ static void rtmsg_ifa(int event, structkfree_skb (skb);netlink_set_err (rtnl,0 ,RTNLGRP_IPV4_IFADDR ,EINVAL ); }else -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV4_IFADDR ,GFP_KERNEL ); +rtnl_multicast (skb,RTNLGRP_IPV4_IFADDR ,GFP_KERNEL ); }static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES ] = {
net/ipv4/ipmr.c +2 -2
@@ -312,7 +312,7 @@ static void ipmr_destroy_unres(struct mf e =NLMSG_DATA (nlh); e->error = -ETIMEDOUT ;memset (&e->msg,0 ,sizeof (e->msg)); -netlink_unicast (rtnl, skb,NETLINK_CB (skb).dst_pid,MSG_DONTWAIT ); +rtnl_unicast (skb,NETLINK_CB (skb).dst_pid); }else kfree_skb (skb); }
@@ -525,7 +525,7 @@ static void ipmr_cache_resolve(struct mf e->error = -EMSGSIZE ;memset (&e->msg,0 ,sizeof (e->msg)); } - err =netlink_unicast (rtnl, skb,NETLINK_CB (skb).dst_pid,MSG_DONTWAIT ); + err =rtnl_unicast (skb,NETLINK_CB (skb).dst_pid); }else ip_mr_forward (skb, c,0 ); }
net/ipv4/route.c +1 -3
@@ -2808,9 +2808,7 @@ int inet_rtm_getroute(struct sk_buff *in goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:return err; out_free:
net/ipv6/addrconf.c +7 -9
@@ -3268,9 +3268,7 @@ static int inet6_rtm_getaddr(struct sk_b goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:in6_ifa_put (ifa);return err;
@@ -3294,8 +3292,8 @@ static void inet6_ifa_notify(int event,netlink_set_err (rtnl,0 ,RTNLGRP_IPV6_IFADDR ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_IFADDR ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_IFADDR ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_IFADDR ,GFP_ATOMIC ); } static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
@@ -3448,8 +3446,8 @@ void inet6_ifinfo_notify(int event, strunetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_IFINFO ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_IFINFO ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_IFINFO ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_IFINFO ,GFP_ATOMIC ); }/* Maximum length of prefix_cacheinfo attributes */
@@ -3513,8 +3511,8 @@ static void inet6_prefix_notify(int evennetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_PREFIX ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_PREFIX ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_PREFIX ,GFP_ATOMIC ); + +rtnl_multicast (skb,RTNLGRP_IPV6_PREFIX ,GFP_ATOMIC ); }static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES ] = {
net/ipv6/route.c +3 -5
@@ -2161,9 +2161,7 @@ int inet6_rtm_getroute(struct sk_buff *i goto out_free; } - err =netlink_unicast (rtnl, skb,NETLINK_CB (in_skb).pid,MSG_DONTWAIT ); -if (err >0 ) - err =0 ; + err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); out:return err; out_free:
@@ -2194,8 +2192,8 @@ void inet6_rt_notify(int event, struct rnetlink_set_err (rtnl,0 ,RTNLGRP_IPV6_ROUTE ,EINVAL );return ; } -NETLINK_CB (skb).dst_group =RTNLGRP_IPV6_ROUTE ; -netlink_broadcast (rtnl, skb,0 ,RTNLGRP_IPV6_ROUTE ,gfp_any ()); + +rtnl_multicast (skb,RTNLGRP_IPV6_ROUTE ,gfp_any ()); }/*
PATCH 3/4 : Dont set socket error for failed event notifications
In reply to Thomas GrafSetting a socket error on all sockets subscribed to a group if an event notificiation of said group fails due to memory pressure only confuses applications and is of no use.
This patch removes it all together.
net/bridge/br_netlink.c +5 -13
@@ -76,25 +76,17 @@ rtattr_failure:void br_ifinfo_notify (int event,struct net_bridge_port *port) {struct sk_buff *skb; -int err = -ENOMEM ;pr_debug ("bridge notify event=%d\n" , event); skb =alloc_skb (NLMSG_SPACE (sizeof (struct ifinfomsg ) +128 ),GFP_ATOMIC );if (!skb) - goto err_out; +return ; - err =br_fill_ifinfo (skb, port, current->pid,0 , event,0 ); -if (err) - goto err_kfree; - -rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC ); -return ; - -err_kfree: -kfree_skb (skb); -err_out: -netlink_set_err (rtnl,0 ,RTNLGRP_LINK , err); +if (br_fill_ifinfo (skb, port, current->pid,0 , event,0 ) <=0 ) +kfree_skb (skb); +else +rtnl_multicast (skb,RTNLGRP_LINK ,GFP_ATOMIC ); }/*
net/core/fib_rules.c +4 -4
@@ -349,11 +349,11 @@ static void notify_rule_change(int eventstruct sk_buff *skb =alloc_skb (size,GFP_KERNEL );if (skb ==NULL ) -netlink_set_err (rtnl,0 , ops->nlgroup,ENOBUFS ); -else if (fib_nl_fill_rule (skb, rule,0 ,0 , event,0 , ops) <0 ) { +return ; + +if (fib_nl_fill_rule (skb, rule,0 ,0 , event,0 , ops) <=0 )kfree_skb (skb); -netlink_set_err (rtnl,0 , ops->nlgroup,EINVAL ); - }else +else rtnl_multicast (skb, ops->nlgroup,GFP_KERNEL ); }
net/decnet/dn_dev.c +5 -9
@@ -748,17 +748,13 @@ static void rtmsg_ifa(int event, structint size =NLMSG_SPACE (sizeof (struct ifaddrmsg )+128 ); skb =alloc_skb (size,GFP_KERNEL ); -if (!skb) { -netlink_set_err (rtnl,0 , RTNLGRP_DECnet_IFADDR,ENOBUFS ); -return ; - } -if (dn_dev_fill_ifaddr (skb, ifa,0 ,0 , event,0 ) <0 ) { -kfree_skb (skb); -netlink_set_err (rtnl,0 , RTNLGRP_DECnet_IFADDR,EINVAL ); +if (skb ==NULL )return ; - } -rtnl_multicast (skb, RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); +if (dn_dev_fill_ifaddr (skb, ifa,0 ,0 , event,0 ) <=0 ) +kfree_skb (skb); +else +rtnl_multicast (skb, RTNLGRP_DECnet_IFADDR,GFP_KERNEL ); }static int dn_dev_dump_ifaddr (struct sk_buff *skb,struct netlink_callback *cb)
net/ipv4/devinet.c +4 -4
@@ -1195,11 +1195,11 @@ static void rtmsg_ifa(int event, struct skb =nlmsg_new (NLMSG_GOODSIZE ,GFP_KERNEL );if (skb ==NULL ) -netlink_set_err (rtnl,0 ,RTNLGRP_IPV4_IFADDR ,ENOBUFS ); -else if (inet_fill_ifaddr (skb, ifa,0 ,0 , event,0 ) <0 ) { +return ; + +if (inet_fill_ifaddr (skb, ifa,0 ,0 , event,0 ) <=0 )kfree_skb (skb); -netlink_set_err (rtnl,0 ,RTNLGRP_IPV4_IFADDR ,EINVAL ); - }else +else rtnl_multicast (skb,RTNLGRP_IPV4_IFADDR ,GFP_KERNEL ); }
net/ipv6/addrconf.c +15 -27
66 lines not on this page · raw message
net/ipv6/route.c +5 -9
@@ -2183,17 +2183,13 @@ void inet6_rt_notify(int event, struct r seq = nlh->nlmsg_seq; skb =alloc_skb (size,gfp_any ()); -if (!skb) { -netlink_set_err (rtnl,0 ,RTNLGRP_IPV6_ROUTE ,ENOBUFS ); +if (skb ==NULL )return ; - } -if (rt6_fill_node (skb, rt,NULL ,NULL ,0 , event, pid, seq,0 ,0 ) <0 ) { -kfree_skb (skb); -netlink_set_err (rtnl,0 ,RTNLGRP_IPV6_ROUTE ,EINVAL ); -return ; - } -rtnl_multicast (skb,RTNLGRP_IPV6_ROUTE ,gfp_any ()); +if (rt6_fill_node (skb, rt,NULL ,NULL ,0 , event, pid, seq,0 ,0 ) <=0 ) +kfree_skb (skb); +else +rtnl_multicast (skb,RTNLGRP_IPV6_ROUTE ,gfp_any ()); }/*
include/linux/netlink.h +0 -1
@@ -156,7 +156,6 @@ extern int netlink_has_listeners(structextern int netlink_unicast (struct sock *ssk,struct sk_buff *skb,__u32 pid,int nonblock);extern int netlink_broadcast (struct sock *ssk,struct sk_buff *skb,__u32 pid,__u32 group,gfp_t allocation); -extern void netlink_set_err (struct sock *ssk,__u32 pid,__u32 group,int code);extern int netlink_register_notifier (struct notifier_block *nb);extern int netlink_unregister_notifier (struct notifier_block *nb);
net/netlink/af_netlink.c +0 -45
57 lines not on this page · raw message
Re: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
Quoted 5 lines · Thomas Graf
Setting a socket error on all sockets subscribed to a group if an event notificiation of said group fails due to memory pressure only confuses applications and is of no use.
This patch removes it all together.
I disagree with this patch, how else are applications supposed to know when they missed an update and are not in sync anymore? I actually have a half-finished patch to add this in some spots where its missing (and uses better error codes).
Re: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
* Patrick McHardy <[email protected]> 2006-08-10 20:09
Quoted 11 lines
Quoted 5 lines · Thomas Graf
Setting a socket error on all sockets subscribed to a group if an event notificiation of said group fails due to memory pressure only confuses applications and is of no use.
This patch removes it all together.
I disagree with this patch, how else are applications supposed to know when they missed an update and are not in sync anymore? I actually have a half-finished patch to add this in some spots where its missing (and uses better error codes).
The application has no idea what went wrong nor does it know for which group so it will have to resync all group subscrptions and as it only happens due to memory pressure that will fail anyway.
Re: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
Quoted 8 lines · Thomas Graf
* Patrick McHardy <[email protected]> 2006-08-10 20:09
Quoted 4 lines
I disagree with this patch, how else are applications supposed to know when they missed an update and are not in sync anymore? I actually have a half-finished patch to add this in some spots where its missing (and uses better error codes).
Quoted 4 lines
The application has no idea what went wrong nor does it know for which group so it will have to resync all group subscrptions and as it only happens due to memory pressure that will fail anyway.
The error code (-ENOMEM) gives it a pretty good idea what went wrong. Its true that it doesn't know which group was affected (that could be fixed), but at least it knows that something went wrong and it needs to resync. If that fails due to memory shortage as well it can schedule a delayed resync or something, but without getting notified it has no chance of doing anything useful. This makes notification essentially useless. If I can't rely on either getting either a notification or an error, I can't rely on them at all.
Please put this back in.
Re: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
* Patrick McHardy <[email protected]> 2006-08-10 21:08
Quoted 11 lines
The error code (
-ENOMEM) gives it a pretty good idea what went wrong. Its true that it doesn't know which group was affected (that could be fixed), but at least it knows that something went wrong and it needs to resync. If that fails due to memory shortage as well it can schedule a delayed resync or something, but without getting notified it has no chance of doing anything useful. This makes notification essentially useless. If I can't rely on either getting either a notification or an error, I can't rely on them at all.Please put this back in.
Alright, I think it's pretty much theoretical but it doesn't really matter to me.
Dave, please revert the whole patchset.
David Miller
maintainerRe: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
From: Thomas Graf <[email protected]>
Date: Thu, 10 Aug 2006 21:23:23 +0200
Quoted 1 line
Dave, please revert the whole patchset.
Done and I've rebased the net-2.6.19 tree as well at:
kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.19.git
Thomas, there was a conflict which I did expect since I added all the 2.6.18 bug fixes into the tree. The conflict is for your netlink conversion of the iflink stuff.
I had to fix the -stable tree IFLA_ADDRESS handling because dev->set_mac_address expects a sockaddr not a raw MAC address.
I think I resolved the conflict while applying the patch properly, but if you could take a look I'd appreciate it.
Thanks.
Re: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
* David Miller <[email protected]> 2006-08-10 23:02
Quoted 10 lines
Thomas, there was a conflict which I did expect since I added all the 2.6.18 bug fixes into the tree. The conflict is for your netlink conversion of the iflink stuff.
I had to fix the -stable tree
IFLA_ADDRESShandling becausedev->set_mac_addressexpects a sockaddr not a raw MAC address.I think I resolved the conflict while applying the patch properly, but if you could take a look I'd appreciate it.
Looks good. You could have used nla_memcpy() instead of memcpy() but there is no functional difference in this case.
David Miller
maintainerRe: [PATCH 3/4] [NETLINK]: Dont set socket error for failed event notifications
From: Thomas Graf <[email protected]>
Date: Fri, 11 Aug 2006 12:38:22 +0200
Quoted 2 lines
Looks good. You could have used
nla_memcpy()instead ofmemcpy()but there is no functional difference in this case.
Right, because the code already verifies that the attribute length is at least dev->addr_len, and that is the size of the memcpy we do.
Thanks for checking things out.
PATCH 4/4 : Unexport global rtnl sock
In reply to Thomas GrafAll references to the rtnl sock are now done via wrapper functions, unexport it.
include/linux/rtnetlink.h +0 -2
@@ -574,8 +574,6 @@ extern int rtattr_parse(struct rtattr *t#define rtattr_parse_nested (tb, max, rta) \ rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta))) -extern struct sock *rtnl; -struct rtnetlink_link {int (*doit)(struct sk_buff *,struct nlmsghdr *,void *attr);
net/core/rtnetlink.c +1 -3
@@ -58,6 +58,7 @@#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ static DEFINE_MUTEX (rtnl_mutex); +static struct sock *rtnl;void rtnl_lock (void ) {
@@ -95,8 +96,6 @@ int rtattr_parse(struct rtattr *tb[], inreturn 0 ; } -struct sock *rtnl; -struct rtnetlink_link * rtnetlink_links[NPROTO ]; static const int rtm_min[RTM_NR_FAMILIES] =
@@ -802,7 +801,6 @@ EXPORT_SYMBOL(rtattr_strlcpy);EXPORT_SYMBOL (rtattr_parse);EXPORT_SYMBOL (rtnetlink_links);EXPORT_SYMBOL (rtnetlink_put_metrics); -EXPORT_SYMBOL (rtnl);EXPORT_SYMBOL (rtnl_lock);EXPORT_SYMBOL (rtnl_trylock);EXPORT_SYMBOL (rtnl_unlock);
David Miller
maintainerFrom: Thomas Graf <[email protected]>
Date: Wed, 09 Aug 2006 22:48:21 +0200
Quoted 5 lines
Aims at cleaning up rtnetlink event notifications and implements real
NLM_F_ECHOsupport.Please disregard my last IPv4 routing related patchset, I'll resubmit it based on this patchset.
All applied, nice work Thomas.
Especially nice to see the RTNL semaphore export go away :-)
Thanks.