aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/rtnetlink.h2
-rw-r--r--net/mpls/af_mpls.c60
2 files changed, 62 insertions, 0 deletions
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index bad65550ae3e..06f75a407f74 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -631,6 +631,8 @@ enum rtnetlink_groups {
631#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF 631#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
632 RTNLGRP_MDB, 632 RTNLGRP_MDB,
633#define RTNLGRP_MDB RTNLGRP_MDB 633#define RTNLGRP_MDB RTNLGRP_MDB
634 RTNLGRP_MPLS_ROUTE,
635#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE
634 __RTNLGRP_MAX 636 __RTNLGRP_MAX
635}; 637};
636#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) 638#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
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;