Mpls handler allows creation/deletion of mpls routes without using rtnetlink. When an incoming mpls packet matches this route, the saved function handler is called.
Signed-off-by: Amine Kherbouche <amine.kherbou...@6wind.com> Signed-off-by: David Lamparter <equi...@diac24.net> --- include/net/mpls.h | 10 +++++++ net/mpls/af_mpls.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ net/mpls/internal.h | 3 +++ 3 files changed, 88 insertions(+) diff --git a/include/net/mpls.h b/include/net/mpls.h index 1dbc669..0ff51b6 100644 --- a/include/net/mpls.h +++ b/include/net/mpls.h @@ -33,4 +33,14 @@ static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb) { return (struct mpls_shim_hdr *)skb_network_header(skb); } + +typedef int (*mpls_handler)(void *arg, struct sk_buff *skb, + struct net_device *dev, u32 index, u8 bos); + +extern int mpls_handler_add(struct net *net, u32 index, u8 via_table, u8 via[], + mpls_handler handler, void *handler_arg, + struct netlink_ext_ack *extack); +extern int mpls_handler_del(struct net *net, u32 index, + struct netlink_ext_ack *extack); + #endif diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index c5b9ce4..82d2126 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -10,6 +10,7 @@ #include <linux/netconf.h> #include <linux/vmalloc.h> #include <linux/percpu.h> +#include <net/mpls.h> #include <net/ip.h> #include <net/dst.h> #include <net/sock.h> @@ -299,6 +300,7 @@ static bool mpls_egress(struct net *net, struct mpls_route *rt, success = true; break; } + case MPT_HANDLER: case MPT_UNSPEC: /* Should have decided which protocol it is by now */ break; @@ -356,6 +358,10 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, goto drop; } + if (rt->rt_payload_type == MPT_HANDLER) + return rt->rt_handler(rt->rt_harg, skb, dev, + dec.label, dec.bos); + nh = mpls_select_multipath(rt, skb); if (!nh) goto err; @@ -457,6 +463,8 @@ static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = { struct mpls_route_config { u32 rc_protocol; u32 rc_ifindex; + mpls_handler rc_handler; + void *rc_harg; u8 rc_via_table; u8 rc_via_alen; u8 rc_via[MAX_VIA_ALEN]; @@ -995,6 +1003,11 @@ static int mpls_route_add(struct mpls_route_config *cfg, rt->rt_payload_type = cfg->rc_payload_type; rt->rt_ttl_propagate = cfg->rc_ttl_propagate; + if (cfg->rc_handler) { + rt->rt_handler = cfg->rc_handler; + rt->rt_harg = cfg->rc_harg; + } + if (cfg->rc_mp) err = mpls_nh_build_multi(cfg, rt, max_labels, extack); else @@ -1271,6 +1284,68 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, return skb->len; } +int mpls_handler_add(struct net *net, u32 label, u8 via_table, u8 via[], + mpls_handler handler, void *handler_arg, + struct netlink_ext_ack *extack) +{ + struct net_device *dev = handler_arg; + struct mpls_route_config *cfg; + u8 alen = 0; + int err; + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + memset(cfg, 0, sizeof(*cfg)); + if (via_table == NEIGH_ARP_TABLE) + alen = sizeof(struct in_addr); + else if (via_table == NEIGH_ND_TABLE) + alen = sizeof(struct in6_addr); + + cfg->rc_ttl_propagate = MPLS_TTL_PROP_DEFAULT; + cfg->rc_protocol = RTPROT_KERNEL; + cfg->rc_nlflags |= NLM_F_CREATE; + cfg->rc_payload_type = MPT_HANDLER; + cfg->rc_via_table = via_table; + cfg->rc_label = label; + cfg->rc_via_alen = alen; + memcpy(&cfg->rc_via, via, alen); + cfg->rc_ifindex = dev->ifindex; + cfg->rc_nlinfo.nl_net = net; + cfg->rc_harg = handler_arg; + cfg->rc_handler = handler; + cfg->rc_output_labels = 0; + + err = mpls_route_add(cfg, extack); + kfree(cfg); + + return err; +} +EXPORT_SYMBOL(mpls_handler_add); + +int mpls_handler_del(struct net *net, u32 index, + struct netlink_ext_ack *extack) +{ + struct mpls_route_config *cfg; + int err = 0; + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + memset(cfg, 0, sizeof(*cfg)); + cfg->rc_protocol = RTPROT_KERNEL; + cfg->rc_label = index; + cfg->rc_nlinfo.nl_net = net; + + err = mpls_route_del(cfg, extack); + kfree(cfg); + + return err; +} +EXPORT_SYMBOL(mpls_handler_del); + #define MPLS_PERDEV_SYSCTL_OFFSET(field) \ (&((struct mpls_dev *)0)->field) diff --git a/net/mpls/internal.h b/net/mpls/internal.h index cf65aec..2cd73eb 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -78,6 +78,7 @@ enum mpls_payload_type { MPT_UNSPEC, /* IPv4 or IPv6 */ MPT_IPV4 = 4, MPT_IPV6 = 6, + MPT_HANDLER = 255, /* Other types not implemented: * - Pseudo-wire with or without control word (RFC4385) @@ -141,6 +142,8 @@ enum mpls_ttl_propagation { */ struct mpls_route { /* next hop label forwarding entry */ struct rcu_head rt_rcu; + mpls_handler rt_handler; + void *rt_harg; u8 rt_protocol; u8 rt_payload_type; u8 rt_max_alen; -- 2.1.4