diff options
| -rw-r--r-- | include/uapi/linux/rtnetlink.h | 2 | ||||
| -rw-r--r-- | net/mpls/af_mpls.c | 60 |
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 */ | |||
| 36 | static int zero = 0; | 36 | static int zero = 0; |
| 37 | static int label_limit = (1 << 20) - 1; | 37 | static int label_limit = (1 << 20) - 1; |
| 38 | 38 | ||
| 39 | static 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 | |||
| 39 | static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) | 43 | static 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 | ||
| 253 | static 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 | |||
| 249 | static void mpls_route_update(struct net *net, unsigned index, | 267 | static 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 | ||
| 715 | static 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 | |||
| 728 | static 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; | ||
| 750 | errout: | ||
| 751 | if (err < 0) | ||
| 752 | rtnl_set_sk_err(net, RTNLGRP_MPLS_ROUTE, err); | ||
| 753 | } | ||
| 754 | |||
| 695 | static int resize_platform_label_table(struct net *net, size_t limit) | 755 | static 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; |
