ipv6: export function to send route updates
authorDavid Ahern <dsahern@gmail.com>
Wed, 22 May 2019 19:04:41 +0000 (12:04 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 May 2019 00:48:43 +0000 (17:48 -0700)
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>
include/net/ip6_fib.h
include/net/ipv6_stubs.h
net/ipv6/af_inet6.c
net/ipv6/ip6_fib.c
net/ipv6/route.c

index d038d02..0d0d06b 100644 (file)
@@ -452,6 +452,12 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
                 struct netlink_ext_ack *extack);
 void fib6_nh_release(struct fib6_nh *fib6_nh);
 
+int call_fib6_entry_notifiers(struct net *net,
+                             enum fib_event_type event_type,
+                             struct fib6_info *rt,
+                             struct netlink_ext_ack *extack);
+void fib6_rt_update(struct net *net, struct fib6_info *rt,
+                   struct nl_info *info);
 void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
                     unsigned int flags);
 
index 97f42e1..5c93e94 100644 (file)
@@ -47,6 +47,9 @@ struct ipv6_stub {
        void (*fib6_nh_release)(struct fib6_nh *fib6_nh);
        void (*fib6_update_sernum)(struct net *net, struct fib6_info *rt);
        int (*ip6_del_rt)(struct net *net, struct fib6_info *rt);
+       void (*fib6_rt_update)(struct net *net, struct fib6_info *rt,
+                              struct nl_info *info);
+
        void (*udpv6_encap_enable)(void);
        void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr,
                              const struct in6_addr *solicited_addr,
index 55138f0..cc6f8d0 100644 (file)
@@ -927,6 +927,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
        .fib6_nh_init      = fib6_nh_init,
        .fib6_nh_release   = fib6_nh_release,
        .fib6_update_sernum = fib6_update_sernum_stub,
+       .fib6_rt_update    = fib6_rt_update,
        .ip6_del_rt        = ip6_del_rt,
        .udpv6_encap_enable = udpv6_encap_enable,
        .ndisc_send_na = ndisc_send_na,
index df726fb..7958cf9 100644 (file)
@@ -393,10 +393,10 @@ static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net,
        return call_fib6_notifier(nb, net, event_type, &info.info);
 }
 
-static int call_fib6_entry_notifiers(struct net *net,
-                                    enum fib_event_type event_type,
-                                    struct fib6_info *rt,
-                                    struct netlink_ext_ack *extack)
+int call_fib6_entry_notifiers(struct net *net,
+                             enum fib_event_type event_type,
+                             struct fib6_info *rt,
+                             struct netlink_ext_ack *extack)
 {
        struct fib6_entry_notifier_info info = {
                .info.extack = extack,
index 7a014ca..c52a7f4 100644 (file)
@@ -5123,6 +5123,38 @@ errout:
                rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
 }
 
+void fib6_rt_update(struct net *net, struct fib6_info *rt,
+                   struct nl_info *info)
+{
+       u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
+       struct sk_buff *skb;
+       int err = -ENOBUFS;
+
+       /* call_fib6_entry_notifiers will be removed when in-kernel notifier
+        * is implemented and supported for nexthop objects
+        */
+       call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, rt, NULL);
+
+       skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
+       if (!skb)
+               goto errout;
+
+       err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
+                           RTM_NEWROUTE, info->portid, seq, NLM_F_REPLACE);
+       if (err < 0) {
+               /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
+               WARN_ON(err == -EMSGSIZE);
+               kfree_skb(skb);
+               goto errout;
+       }
+       rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
+                   info->nlh, gfp_any());
+       return;
+errout:
+       if (err < 0)
+               rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
+}
+
 static int ip6_route_dev_notify(struct notifier_block *this,
                                unsigned long event, void *ptr)
 {