Skip to content

Commit 3b1137f

Browse files
David Aherndavem330
David Ahern
authored andcommitted
net: ipv6: Change notifications for multipath add to RTA_MULTIPATH
Change ip6_route_multipath_add to send one notifciation with the full route encoded with RTA_MULTIPATH instead of a series of individual routes. This is done by adding a skip_notify flag to the nl_info struct. The flag is used to skip sending of the notification in the fib code that actually inserts the route. Once the full route has been added, a notification is generated with all nexthops. ip6_route_multipath_add handles 3 use cases: new routes, route replace, and route append. The multipath notification generated needs to be consistent with the order of the nexthops and it should be consistent with the order in a FIB dump which means the route with the first nexthop needs to be used as the route reference. For the first 2 cases (new and replace), a reference to the route used to send the notification is obtained by saving the first route added. For the append case, the last route added is used to loop back to its first sibling route which is the first nexthop in the multipath route. Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent beb1afa commit 3b1137f

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

include/net/netlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ struct nl_info {
229229
struct nlmsghdr *nlh;
230230
struct net *nl_net;
231231
u32 portid;
232+
bool skip_notify;
232233
};
233234

234235
int netlink_rcv_skb(struct sk_buff *skb,

net/ipv6/ip6_fib.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
881881
*ins = rt;
882882
rt->rt6i_node = fn;
883883
atomic_inc(&rt->rt6i_ref);
884-
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
884+
if (!info->skip_notify)
885+
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
885886
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
886887

887888
if (!(fn->fn_flags & RTN_RTINFO)) {
@@ -907,7 +908,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
907908
rt->rt6i_node = fn;
908909
rt->dst.rt6_next = iter->dst.rt6_next;
909910
atomic_inc(&rt->rt6i_ref);
910-
inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
911+
if (!info->skip_notify)
912+
inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
911913
if (!(fn->fn_flags & RTN_RTINFO)) {
912914
info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
913915
fn->fn_flags |= RTN_RTINFO;

net/ipv6/route.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3023,13 +3023,37 @@ static int ip6_route_info_append(struct list_head *rt6_nh_list,
30233023
return 0;
30243024
}
30253025

3026+
static void ip6_route_mpath_notify(struct rt6_info *rt,
3027+
struct rt6_info *rt_last,
3028+
struct nl_info *info,
3029+
__u16 nlflags)
3030+
{
3031+
/* if this is an APPEND route, then rt points to the first route
3032+
* inserted and rt_last points to last route inserted. Userspace
3033+
* wants a consistent dump of the route which starts at the first
3034+
* nexthop. Since sibling routes are always added at the end of
3035+
* the list, find the first sibling of the last route appended
3036+
*/
3037+
if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3038+
rt = list_first_entry(&rt_last->rt6i_siblings,
3039+
struct rt6_info,
3040+
rt6i_siblings);
3041+
}
3042+
3043+
if (rt)
3044+
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3045+
}
3046+
30263047
static int ip6_route_multipath_add(struct fib6_config *cfg)
30273048
{
3049+
struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3050+
struct nl_info *info = &cfg->fc_nlinfo;
30283051
struct fib6_config r_cfg;
30293052
struct rtnexthop *rtnh;
30303053
struct rt6_info *rt;
30313054
struct rt6_nh *err_nh;
30323055
struct rt6_nh *nh, *nh_safe;
3056+
__u16 nlflags;
30333057
int remaining;
30343058
int attrlen;
30353059
int err = 1;
@@ -3038,6 +3062,10 @@ static int ip6_route_multipath_add(struct fib6_config *cfg)
30383062
(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
30393063
LIST_HEAD(rt6_nh_list);
30403064

3065+
nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3066+
if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3067+
nlflags |= NLM_F_APPEND;
3068+
30413069
remaining = cfg->fc_mp_len;
30423070
rtnh = (struct rtnexthop *)cfg->fc_mp;
30433071

@@ -3080,9 +3108,20 @@ static int ip6_route_multipath_add(struct fib6_config *cfg)
30803108
rtnh = rtnh_next(rtnh, &remaining);
30813109
}
30823110

3111+
/* for add and replace send one notification with all nexthops.
3112+
* Skip the notification in fib6_add_rt2node and send one with
3113+
* the full route when done
3114+
*/
3115+
info->skip_notify = 1;
3116+
30833117
err_nh = NULL;
30843118
list_for_each_entry(nh, &rt6_nh_list, next) {
3085-
err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc);
3119+
rt_last = nh->rt6_info;
3120+
err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc);
3121+
/* save reference to first route for notification */
3122+
if (!rt_notif && !err)
3123+
rt_notif = nh->rt6_info;
3124+
30863125
/* nh->rt6_info is used or freed at this point, reset to NULL*/
30873126
nh->rt6_info = NULL;
30883127
if (err) {
@@ -3104,9 +3143,18 @@ static int ip6_route_multipath_add(struct fib6_config *cfg)
31043143
nhn++;
31053144
}
31063145

3146+
/* success ... tell user about new route */
3147+
ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
31073148
goto cleanup;
31083149

31093150
add_errout:
3151+
/* send notification for routes that were added so that
3152+
* the delete notifications sent by ip6_route_del are
3153+
* coherent
3154+
*/
3155+
if (rt_notif)
3156+
ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3157+
31103158
/* Delete routes that were already added */
31113159
list_for_each_entry(nh, &rt6_nh_list, next) {
31123160
if (err_nh == nh)

0 commit comments

Comments
 (0)