From 760d74f99c885364931d0124fc737f3b43e57b74 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 17 Aug 2017 15:59:37 -0700 Subject: [PATCH] route: Add support for MPLS encap Add support for MPLS lwtunnel encapsulation. Signed-off-by: David Ahern --- Makefile.am | 1 + include/netlink-private/route/nexthop-encap.h | 5 + include/netlink/route/nexthop.h | 6 + lib/route/nexthop_encap.c | 2 +- lib/route/nh_encap_mpls.c | 134 ++++++++++++++++++ libnl-route-3.sym | 1 + 6 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 lib/route/nh_encap_mpls.c diff --git a/Makefile.am b/Makefile.am index c24f16d..d97cec6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -386,6 +386,7 @@ lib_libnl_route_3_la_SOURCES = \ lib/route/netconf.c \ lib/route/nexthop.c \ lib/route/nexthop_encap.c \ + lib/route/nh_encap_mpls.c \ lib/route/pktloc.c \ lib/route/qdisc/blackhole.c \ lib/route/qdisc.c \ diff --git a/include/netlink-private/route/nexthop-encap.h b/include/netlink-private/route/nexthop-encap.h index ba96b0d..dde1bfb 100644 --- a/include/netlink-private/route/nexthop-encap.h +++ b/include/netlink-private/route/nexthop-encap.h @@ -27,4 +27,9 @@ int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap); void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp); int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b); + +/* + * MPLS encap + */ +extern struct nh_encap_ops mpls_encap_ops; #endif diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h index 654b84d..5b422dd 100644 --- a/include/netlink/route/nexthop.h +++ b/include/netlink/route/nexthop.h @@ -64,6 +64,12 @@ extern struct nl_addr * rtnl_route_nh_get_via(struct rtnl_nexthop *); extern char * rtnl_route_nh_flags2str(int, char *, size_t); extern int rtnl_route_nh_str2flags(const char *); +/* + * nexthop encapsulations + */ +extern int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh, + struct nl_addr *addr, + uint8_t ttl); #ifdef __cplusplus } #endif diff --git a/lib/route/nexthop_encap.c b/lib/route/nexthop_encap.c index 9d9307a..849d2e3 100644 --- a/lib/route/nexthop_encap.c +++ b/lib/route/nexthop_encap.c @@ -9,7 +9,7 @@ static struct lwtunnel_encap_type { struct nh_encap_ops *ops; } lwtunnel_encap_types[__LWTUNNEL_ENCAP_MAX] = { [LWTUNNEL_ENCAP_NONE] = { .name = "none" }, - [LWTUNNEL_ENCAP_MPLS] = { .name = "mpls" }, + [LWTUNNEL_ENCAP_MPLS] = { .name = "mpls", .ops = &mpls_encap_ops }, [LWTUNNEL_ENCAP_IP] = { .name = "ip" }, [LWTUNNEL_ENCAP_IP6] = { .name = "ip6" }, [LWTUNNEL_ENCAP_ILA] = { .name = "ila" }, diff --git a/lib/route/nh_encap_mpls.c b/lib/route/nh_encap_mpls.c new file mode 100644 index 0000000..5e96289 --- /dev/null +++ b/lib/route/nh_encap_mpls.c @@ -0,0 +1,134 @@ + +#include +#include +#include +#include +#include +#include + +struct mpls_iptunnel_encap { + struct nl_addr *dst; + uint8_t ttl; +}; + +static void mpls_encap_dump(void *priv, struct nl_dump_params *dp) +{ + struct mpls_iptunnel_encap *encap_info = priv; + char buf[256]; + + nl_dump(dp, "%s ", nl_addr2str(encap_info->dst, buf, sizeof(buf))); + + if (encap_info->ttl) + nl_dump(dp, "ttl %u ", encap_info->ttl); +} + +static int mpls_encap_build_msg(struct nl_msg *msg, void *priv) +{ + struct mpls_iptunnel_encap *encap_info = priv; + + NLA_PUT_ADDR(msg, MPLS_IPTUNNEL_DST, encap_info->dst); + if (encap_info->ttl) + NLA_PUT_U8(msg, MPLS_IPTUNNEL_TTL, encap_info->ttl); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static void mpls_encap_destructor(void *priv) +{ + struct mpls_iptunnel_encap *encap_info = priv; + + nl_addr_put(encap_info->dst); +} + +static struct nla_policy mpls_encap_policy[MPLS_IPTUNNEL_MAX + 1] = { + [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, + [MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 }, +}; + +static int mpls_encap_parse_msg(struct nlattr *nla, struct rtnl_nexthop *nh) +{ + struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1]; + struct nl_addr *labels; + uint8_t ttl = 0; + int err; + + + err = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, mpls_encap_policy); + if (err) + return err; + + if (!tb[MPLS_IPTUNNEL_DST]) + return -NLE_INVAL; + + labels = nl_addr_alloc_attr(tb[MPLS_IPTUNNEL_DST], AF_MPLS); + if (!labels) + return -NLE_NOMEM; + + if (tb[MPLS_IPTUNNEL_TTL]) + ttl = nla_get_u8(tb[MPLS_IPTUNNEL_TTL]); + + err = rtnl_route_nh_encap_mpls(nh, labels, ttl); + + nl_addr_put(labels); + + return err; +} + +static int mpls_encap_compare(void *_a, void *_b) +{ + struct mpls_iptunnel_encap *a = _a; + struct mpls_iptunnel_encap *b = _b; + int diff = 0; + + diff |= (a->ttl != b->ttl); + diff |= nl_addr_cmp(a->dst, b->dst); + + return diff; +} + +struct nh_encap_ops mpls_encap_ops = { + .encap_type = LWTUNNEL_ENCAP_MPLS, + .build_msg = mpls_encap_build_msg, + .parse_msg = mpls_encap_parse_msg, + .compare = mpls_encap_compare, + .dump = mpls_encap_dump, + .destructor = mpls_encap_destructor, +}; + +int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh, + struct nl_addr *addr, + uint8_t ttl) +{ + struct mpls_iptunnel_encap *mpls_encap; + struct rtnl_nh_encap *rtnh_encap; + + if (!addr) + return -NLE_INVAL; + + if (!nl_addr_valid(nl_addr_get_binary_addr(addr), + nl_addr_get_len(addr))) + return -NLE_INVAL; + + rtnh_encap = calloc(1, sizeof(*rtnh_encap)); + if (!rtnh_encap) + return -NLE_NOMEM; + + mpls_encap = calloc(1, sizeof(*mpls_encap)); + if (!mpls_encap) { + free(rtnh_encap); + return -NLE_NOMEM; + } + + mpls_encap->dst = nl_addr_get(addr); + mpls_encap->ttl = ttl; + + rtnh_encap->priv = mpls_encap; + rtnh_encap->ops = &mpls_encap_ops; + + nh_set_encap(nh, rtnh_encap); + + return 0; +} diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 4382775..e66682a 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1059,4 +1059,5 @@ global: rtnl_route_nh_get_via; rtnl_route_set_ttl_propagate; rtnl_route_get_ttl_propagate; + rtnl_route_nh_encap_mpls; } libnl_3_2_29; -- 2.40.0