aboutsummaryrefslogtreecommitdiffstats
path: root/net/mpls
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2015-03-03 20:14:31 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-04 00:26:06 -0500
commit8de147dc8e2adea82b8a1a2a08fcc983330f6770 (patch)
tree2c0562994dc0ee616aabef727064120cf615f356 /net/mpls
parent03c0566542f4c7a45ce3193f27cbf5700b506c18 (diff)
mpls: Multicast route table change notifications
Unlike IPv4 this code notifies on all cases where mpls routes are added or removed and it never automatically removes routes. Avoiding both the userspace confusion that is caused by omitting route updates and the possibility of a flood of netlink traffic when an interface goes doew. For now reserved labels are handled automatically and userspace is not notified. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mpls')
-rw-r--r--net/mpls/af_mpls.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index b4d7cec398d2..75a994a50381 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -36,6 +36,10 @@ struct mpls_route { /* next hop label forwarding entry */
36static int zero = 0; 36static int zero = 0;
37static int label_limit = (1 << 20) - 1; 37static int label_limit = (1 << 20) - 1;
38 38
39static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
40 struct nlmsghdr *nlh, struct net *net, u32 portid,
41 unsigned int nlm_flags);
42
39static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) 43static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
40{ 44{
41 struct mpls_route *rt = NULL; 45 struct mpls_route *rt = NULL;
@@ -246,6 +250,20 @@ static void mpls_rt_free(struct mpls_route *rt)
246 kfree_rcu(rt, rt_rcu); 250 kfree_rcu(rt, rt_rcu);
247} 251}
248 252
253static void mpls_notify_route(struct net *net, unsigned index,
254 struct mpls_route *old, struct mpls_route *new,
255 const struct nl_info *info)
256{
257 struct nlmsghdr *nlh = info ? info->nlh : NULL;
258 unsigned portid = info ? info->portid : 0;
259 int event = new ? RTM_NEWROUTE : RTM_DELROUTE;
260 struct mpls_route *rt = new ? new : old;
261 unsigned nlm_flags = (old && new) ? NLM_F_REPLACE : 0;
262 /* Ignore reserved labels for now */
263 if (rt && (index >= 16))
264 rtmsg_lfib(event, index, rt, nlh, net, portid, nlm_flags);
265}
266
249static void mpls_route_update(struct net *net, unsigned index, 267static void mpls_route_update(struct net *net, unsigned index,
250 struct net_device *dev, struct mpls_route *new, 268 struct net_device *dev, struct mpls_route *new,
251 const struct nl_info *info) 269 const struct nl_info *info)
@@ -260,6 +278,8 @@ static void mpls_route_update(struct net *net, unsigned index,
260 old = rt; 278 old = rt;
261 } 279 }
262 280
281 mpls_notify_route(net, index, old, new, info);
282
263 /* If we removed a route free it now */ 283 /* If we removed a route free it now */
264 mpls_rt_free(old); 284 mpls_rt_free(old);
265} 285}
@@ -692,6 +712,46 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
692 return skb->len; 712 return skb->len;
693} 713}
694 714
715static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
716{
717 size_t payload =
718 NLMSG_ALIGN(sizeof(struct rtmsg))
719 + nla_total_size(2 + rt->rt_via_alen) /* RTA_VIA */
720 + nla_total_size(4); /* RTA_DST */
721 if (rt->rt_labels) /* RTA_NEWDST */
722 payload += nla_total_size(rt->rt_labels * 4);
723 if (rt->rt_dev) /* RTA_OIF */
724 payload += nla_total_size(4);
725 return payload;
726}
727
728static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
729 struct nlmsghdr *nlh, struct net *net, u32 portid,
730 unsigned int nlm_flags)
731{
732 struct sk_buff *skb;
733 u32 seq = nlh ? nlh->nlmsg_seq : 0;
734 int err = -ENOBUFS;
735
736 skb = nlmsg_new(lfib_nlmsg_size(rt), GFP_KERNEL);
737 if (skb == NULL)
738 goto errout;
739
740 err = mpls_dump_route(skb, portid, seq, event, label, rt, nlm_flags);
741 if (err < 0) {
742 /* -EMSGSIZE implies BUG in lfib_nlmsg_size */
743 WARN_ON(err == -EMSGSIZE);
744 kfree_skb(skb);
745 goto errout;
746 }
747 rtnl_notify(skb, net, portid, RTNLGRP_MPLS_ROUTE, nlh, GFP_KERNEL);
748
749 return;
750errout:
751 if (err < 0)
752 rtnl_set_sk_err(net, RTNLGRP_MPLS_ROUTE, err);
753}
754
695static int resize_platform_label_table(struct net *net, size_t limit) 755static int resize_platform_label_table(struct net *net, size_t limit)
696{ 756{
697 size_t size = sizeof(struct mpls_route *) * limit; 757 size_t size = sizeof(struct mpls_route *) * limit;