diff options
author | David Ahern <dsahern@gmail.com> | 2019-05-22 15:04:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-22 20:48:43 -0400 |
commit | 19a3b7eea42402accf52bcb9ddb51bfdb4d7a13b (patch) | |
tree | a7829e17b8cc38db2e463e4ab6eacc3318a6ff39 | |
parent | cdaa16a4f70cfa6c55641588c3a3eb9b53abd56b (diff) |
ipv6: export function to send route updates
Add fib6_rt_update to send RTM_NEWROUTE with NLM_F_REPLACE set. This
helper will be used by the nexthop code to notify userspace of routes
that are impacted when a nexthop config is updated via replace.
This notification is needed for legacy apps that do not understand
the new nexthop object. Apps that are nexthop aware can use the
RTA_NH_ID attribute in the route notification to just ignore it.
In the future this should be wrapped in a sysctl to allow OS'es that
are fully updated to avoid the notificaton storm.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip6_fib.h | 6 | ||||
-rw-r--r-- | include/net/ipv6_stubs.h | 3 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 32 |
5 files changed, 46 insertions, 4 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index d038d02cbc3c..0d0d06b1cd26 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -452,6 +452,12 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, | |||
452 | struct netlink_ext_ack *extack); | 452 | struct netlink_ext_ack *extack); |
453 | void fib6_nh_release(struct fib6_nh *fib6_nh); | 453 | void fib6_nh_release(struct fib6_nh *fib6_nh); |
454 | 454 | ||
455 | int call_fib6_entry_notifiers(struct net *net, | ||
456 | enum fib_event_type event_type, | ||
457 | struct fib6_info *rt, | ||
458 | struct netlink_ext_ack *extack); | ||
459 | void fib6_rt_update(struct net *net, struct fib6_info *rt, | ||
460 | struct nl_info *info); | ||
455 | void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, | 461 | void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, |
456 | unsigned int flags); | 462 | unsigned int flags); |
457 | 463 | ||
diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h index 97f42e16b3b3..5c93e942c50b 100644 --- a/include/net/ipv6_stubs.h +++ b/include/net/ipv6_stubs.h | |||
@@ -47,6 +47,9 @@ struct ipv6_stub { | |||
47 | void (*fib6_nh_release)(struct fib6_nh *fib6_nh); | 47 | void (*fib6_nh_release)(struct fib6_nh *fib6_nh); |
48 | void (*fib6_update_sernum)(struct net *net, struct fib6_info *rt); | 48 | void (*fib6_update_sernum)(struct net *net, struct fib6_info *rt); |
49 | int (*ip6_del_rt)(struct net *net, struct fib6_info *rt); | 49 | int (*ip6_del_rt)(struct net *net, struct fib6_info *rt); |
50 | void (*fib6_rt_update)(struct net *net, struct fib6_info *rt, | ||
51 | struct nl_info *info); | ||
52 | |||
50 | void (*udpv6_encap_enable)(void); | 53 | void (*udpv6_encap_enable)(void); |
51 | void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr, | 54 | void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr, |
52 | const struct in6_addr *solicited_addr, | 55 | const struct in6_addr *solicited_addr, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 55138f0d2b9d..cc6f8d0c625a 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -927,6 +927,7 @@ static const struct ipv6_stub ipv6_stub_impl = { | |||
927 | .fib6_nh_init = fib6_nh_init, | 927 | .fib6_nh_init = fib6_nh_init, |
928 | .fib6_nh_release = fib6_nh_release, | 928 | .fib6_nh_release = fib6_nh_release, |
929 | .fib6_update_sernum = fib6_update_sernum_stub, | 929 | .fib6_update_sernum = fib6_update_sernum_stub, |
930 | .fib6_rt_update = fib6_rt_update, | ||
930 | .ip6_del_rt = ip6_del_rt, | 931 | .ip6_del_rt = ip6_del_rt, |
931 | .udpv6_encap_enable = udpv6_encap_enable, | 932 | .udpv6_encap_enable = udpv6_encap_enable, |
932 | .ndisc_send_na = ndisc_send_na, | 933 | .ndisc_send_na = ndisc_send_na, |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index df726fb8f70f..7958cf91895a 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -393,10 +393,10 @@ static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net, | |||
393 | return call_fib6_notifier(nb, net, event_type, &info.info); | 393 | return call_fib6_notifier(nb, net, event_type, &info.info); |
394 | } | 394 | } |
395 | 395 | ||
396 | static int call_fib6_entry_notifiers(struct net *net, | 396 | int call_fib6_entry_notifiers(struct net *net, |
397 | enum fib_event_type event_type, | 397 | enum fib_event_type event_type, |
398 | struct fib6_info *rt, | 398 | struct fib6_info *rt, |
399 | struct netlink_ext_ack *extack) | 399 | struct netlink_ext_ack *extack) |
400 | { | 400 | { |
401 | struct fib6_entry_notifier_info info = { | 401 | struct fib6_entry_notifier_info info = { |
402 | .info.extack = extack, | 402 | .info.extack = extack, |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7a014ca877ed..c52a7f49d096 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -5123,6 +5123,38 @@ errout: | |||
5123 | rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); | 5123 | rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); |
5124 | } | 5124 | } |
5125 | 5125 | ||
5126 | void fib6_rt_update(struct net *net, struct fib6_info *rt, | ||
5127 | struct nl_info *info) | ||
5128 | { | ||
5129 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; | ||
5130 | struct sk_buff *skb; | ||
5131 | int err = -ENOBUFS; | ||
5132 | |||
5133 | /* call_fib6_entry_notifiers will be removed when in-kernel notifier | ||
5134 | * is implemented and supported for nexthop objects | ||
5135 | */ | ||
5136 | call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, rt, NULL); | ||
5137 | |||
5138 | skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); | ||
5139 | if (!skb) | ||
5140 | goto errout; | ||
5141 | |||
5142 | err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0, | ||
5143 | RTM_NEWROUTE, info->portid, seq, NLM_F_REPLACE); | ||
5144 | if (err < 0) { | ||
5145 | /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ | ||
5146 | WARN_ON(err == -EMSGSIZE); | ||
5147 | kfree_skb(skb); | ||
5148 | goto errout; | ||
5149 | } | ||
5150 | rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, | ||
5151 | info->nlh, gfp_any()); | ||
5152 | return; | ||
5153 | errout: | ||
5154 | if (err < 0) | ||
5155 | rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); | ||
5156 | } | ||
5157 | |||
5126 | static int ip6_route_dev_notify(struct notifier_block *this, | 5158 | static int ip6_route_dev_notify(struct notifier_block *this, |
5127 | unsigned long event, void *ptr) | 5159 | unsigned long event, void *ptr) |
5128 | { | 5160 | { |