diff options
author | David Ahern <dsahern@gmail.com> | 2017-08-17 22:59:36 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-08-18 13:01:04 (GMT) |
commit | 0164d57aee542507942b1f746d9ff3140d61658b (patch) | |
tree | a6d9f71c479c5509e414dff149af0428f8b86f5d /lib | |
parent | 000a792c7b2b3cffa731c8170eb9c969b569d8a9 (diff) | |
download | libnl-0164d57aee542507942b1f746d9ff3140d61658b.zip libnl-0164d57aee542507942b1f746d9ff3140d61658b.tar.gz libnl-0164d57aee542507942b1f746d9ff3140d61658b.tar.bz2 |
route: Add support for lwtunnel encapsulations
Add framework to support lwtunnel encapsulations per nexthop.
Encapsulations types are expected to fill in the nh_encap_ops for
building and parsing messages, compare encapsulations in routes,
dumping the encapsulations and freeing memory.
Signed-off-by: David Ahern <dsahern@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/route/nexthop.c | 34 | ||||
-rw-r--r-- | lib/route/nexthop_encap.c | 99 | ||||
-rw-r--r-- | lib/route/route_obj.c | 25 |
3 files changed, 158 insertions, 0 deletions
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c index c69b23e..b38a315 100644 --- a/lib/route/nexthop.c +++ b/lib/route/nexthop.c @@ -16,6 +16,7 @@ */ #include <netlink-private/netlink.h> +#include <netlink-private/route/nexthop-encap.h> #include <netlink/netlink.h> #include <netlink/utils.h> #include <netlink/route/rtnl.h> @@ -29,6 +30,7 @@ #define NH_ATTR_REALMS 0x000010 #define NH_ATTR_NEWDST 0x000020 #define NH_ATTR_VIA 0x000040 +#define NH_ATTR_ENCAP 0x000080 /** @endcond */ /** @@ -98,6 +100,12 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh) nl_addr_put(nh->rtnh_gateway); nl_addr_put(nh->rtnh_newdst); nl_addr_put(nh->rtnh_via); + if (nh->rtnh_encap) { + if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor) + nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv); + free(nh->rtnh_encap->priv); + free(nh->rtnh_encap); + } free(nh); } @@ -119,6 +127,8 @@ int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, b->rtnh_newdst)); diff |= NH_DIFF(VIA, nl_addr_cmp(a->rtnh_via, b->rtnh_via)); + diff |= NH_DIFF(ENCAP, nh_encap_compare(a->rtnh_encap, + b->rtnh_encap)); if (loose) diff |= NH_DIFF(FLAGS, @@ -138,6 +148,9 @@ static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp) link_cache = nl_cache_mngt_require_safe("route/link"); + if (nh->ce_mask & NH_ATTR_ENCAP) + nh_encap_dump(nh->rtnh_encap, dp); + if (nh->ce_mask & NH_ATTR_NEWDST) nl_dump(dp, "as to %s ", nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf))); @@ -177,6 +190,9 @@ static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) nl_dump(dp, "nexthop"); + if (nh->ce_mask & NH_ATTR_ENCAP) + nh_encap_dump(nh->rtnh_encap, dp); + if (nh->ce_mask & NH_ATTR_NEWDST) nl_dump(dp, " as to %s", nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf))); @@ -233,6 +249,24 @@ void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) } } +void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap) +{ + if (nh->rtnh_encap) { + if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor) + nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv); + free(nh->rtnh_encap->priv); + free(nh->rtnh_encap); + } + + if (rtnh_encap) { + nh->rtnh_encap = rtnh_encap; + nh->ce_mask |= NH_ATTR_ENCAP; + } else { + nh->rtnh_encap = NULL; + nh->ce_mask &= ~NH_ATTR_ENCAP; + } +} + /** * @name Attributes * @{ diff --git a/lib/route/nexthop_encap.c b/lib/route/nexthop_encap.c new file mode 100644 index 0000000..9d9307a --- /dev/null +++ b/lib/route/nexthop_encap.c @@ -0,0 +1,99 @@ + +#include <netlink-private/netlink.h> +#include <netlink-private/types.h> +#include <netlink-private/route/nexthop-encap.h> +#include <linux/lwtunnel.h> + +static struct lwtunnel_encap_type { + const char *name; + struct nh_encap_ops *ops; +} lwtunnel_encap_types[__LWTUNNEL_ENCAP_MAX] = { + [LWTUNNEL_ENCAP_NONE] = { .name = "none" }, + [LWTUNNEL_ENCAP_MPLS] = { .name = "mpls" }, + [LWTUNNEL_ENCAP_IP] = { .name = "ip" }, + [LWTUNNEL_ENCAP_IP6] = { .name = "ip6" }, + [LWTUNNEL_ENCAP_ILA] = { .name = "ila" }, + [LWTUNNEL_ENCAP_BPF] = { .name = "bpf" }, +}; + +static const char *nh_encap_type2str(unsigned int type) +{ + if (type > LWTUNNEL_ENCAP_MAX) + return "unknown"; + + return lwtunnel_encap_types[type].name ? : "unknown"; +} + +void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp) +{ + nl_dump(dp, " encap %s ", + nh_encap_type2str(rtnh_encap->ops->encap_type)); + + if (rtnh_encap->ops && rtnh_encap->ops->dump) + rtnh_encap->ops->dump(rtnh_encap->priv, dp); +} + +int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap) +{ + struct nlattr *encap; + int err; + + if (!rtnh_encap->ops || !rtnh_encap->ops->build_msg) { + NL_DBG(2, "Nexthop encap type not implemented\n"); + return -NLE_INVAL; + } + + NLA_PUT_U16(msg, RTA_ENCAP_TYPE, rtnh_encap->ops->encap_type); + + encap = nla_nest_start(msg, RTA_ENCAP); + if (!encap) + goto nla_put_failure; + + err = rtnh_encap->ops->build_msg(msg, rtnh_encap->priv); + if (err) + return err; + + nla_nest_end(msg, encap); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type, + struct rtnl_nexthop *rtnh) +{ + uint16_t e_type = nla_get_u16(encap_type); + + if (e_type == LWTUNNEL_ENCAP_NONE) { + NL_DBG(2, "RTA_ENCAP_TYPE should not be LWTUNNEL_ENCAP_NONE\n"); + return -NLE_INVAL; + } + if (e_type > LWTUNNEL_ENCAP_MAX) { + NL_DBG(2, "Unknown RTA_ENCAP_TYPE: %d\n", e_type); + return -NLE_INVAL; + } + + if (!lwtunnel_encap_types[e_type].ops) { + NL_DBG(2, "RTA_ENCAP_TYPE %s is not implemented\n", + lwtunnel_encap_types[e_type].name); + return -NLE_MSGTYPE_NOSUPPORT; + } + + return lwtunnel_encap_types[e_type].ops->parse_msg(encap, rtnh); +} + +int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b) +{ + if (!a && !b) + return 0; + + if ((a && !b) || (!a && b) || (a->ops != b->ops)) + return 1; + + if (!a->ops || !a->ops->compare) + return 0; + + return a->ops->compare(a->priv, b->priv); +} diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index 0f84248..8ae6b89 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -32,6 +32,7 @@ #include <netlink-private/netlink.h> #include <netlink-private/utils.h> +#include <netlink-private/route/nexthop-encap.h> #include <netlink/netlink.h> #include <netlink/cache.h> #include <netlink/utils.h> @@ -1014,6 +1015,8 @@ static struct nla_policy route_policy[RTA_MAX+1] = { [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .type = NLA_NESTED }, [RTA_TTL_PROPAGATE] = { .type = NLA_U8 }, + [RTA_ENCAP] = { .type = NLA_NESTED }, + [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, }; static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) @@ -1089,6 +1092,14 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) if (err) goto errout; } + + if (ntb[RTA_ENCAP] && ntb[RTA_ENCAP_TYPE]) { + err = nh_encap_parse_msg(ntb[RTA_ENCAP], + ntb[RTA_ENCAP_TYPE], + nh); + if (err) + goto errout; + } } rtnl_route_add_nexthop(route, nh); @@ -1275,6 +1286,13 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) nla_get_u8(tb[RTA_TTL_PROPAGATE])); } + if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) { + err = nh_encap_parse_msg(tb[RTA_ENCAP], + tb[RTA_ENCAP_TYPE], old_nh); + if (err) + goto errout; + } + if (old_nh) { rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff); if (route->rt_nr_nh == 0) { @@ -1402,6 +1420,9 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst); if (nh->rtnh_via && rtnl_route_put_via(msg, nh->rtnh_via) < 0) goto nla_put_failure; + if (nh->rtnh_encap && + nh_encap_build_msg(msg, nh->rtnh_encap) < 0) + goto nla_put_failure; } else if (rtnl_route_get_nnexthops(route) > 1) { struct nlattr *multipath; struct rtnl_nexthop *nh; @@ -1434,6 +1455,10 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) if (nh->rtnh_realms) NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + if (nh->rtnh_encap && + nh_encap_build_msg(msg, nh->rtnh_encap) < 0) + goto nla_put_failure; + rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - (void *) rtnh; } |