From hcs at inbox.ru Sun Jun 4 22:11:21 2017 From: hcs at inbox.ru (SlavAg) Date: Mon, 5 Jun 2017 12:11:21 +0700 Subject: nl_cache_refill leak suppose In-Reply-To: References: Message-ID: <4f5216f8-b063-5e7e-4114-1351f04d3012@inbox.ru> Hello everybody, Have some problem with nl_cache_refill (and rtnl_link_alloc_cache too). When Im calling it periodically memory using by top enlarge. To avoid overhead i dont close nl socket and dont disconnect it. Keep it ready between calls. Before I am working with caches like this https://www.infradead.org/~tgr/libnl/doc/route.html and have same memory leaking. If I use rtnl_link_get_kernel instead - there is no problem with memory. version libnl 3.2.25 arch arm. int intf_get_stat (int intfindex,intf_stat *stat){ uint32_t ifindex; struct rtnl_link *link; int err; ifindex = intfindex+2; // strict since eth0 = index 2 if(statsock==NULL){ // statsock = nl_cli_alloc_socket(); if (!(statsock = nl_socket_alloc())){ printf( "Unable to allocate netlink socket"); return -1; } else { // nl_cli_connect(statsock, NETLINK_ROUTE); if ((err = nl_connect(statsock, NETLINK_ROUTE)) < 0){ printf( "Unable to connect netlink socket: %s", nl_geterror(err)); return -2; } } } if(stat_link_cache==NULL){ if ((err = rtnl_link_alloc_cache(statsock, AF_UNSPEC, &stat_link_cache)) < 0) { printf("Unable to allocate link cache: %s",nl_geterror(err)); return -3; } else { } } else { if((err = nl_cache_refill ( statsock, stat_link_cache)) < 0){ printf("Unable to refill link cache: %s",nl_geterror(err)); return -4; } } /* * if ((err = rtnl_link_alloc_cache(statsock, AF_UNSPEC, &link_cache)) < 0) { printf("Unable to allocate link cache: %s",nl_geterror(err)); return -1; } else { */ /* if((err = rtnl_link_get_kernel(statsock, ifindex, NULL, &link)) < 0){ printf( "Unable to get kernel link: %s", nl_geterror(err)); return -1; } */ link = rtnl_link_get(stat_link_cache, ifindex); printf("link index %d\n",ifindex); stat->link_rx_packets = rtnl_link_get_stat(link, RTNL_LINK_RX_PACKETS); printf("link_rx_packets %d\n",stat->link_rx_packets); stat->link_tx_packets = rtnl_link_get_stat(link, RTNL_LINK_TX_PACKETS); printf("link_tx_packets %d\n",stat->link_tx_packets); stat->link_rx_bytes = rtnl_link_get_stat(link, RTNL_LINK_RX_BYTES); printf("link_rx_bytes %d\n",stat->link_rx_bytes); stat->link_tx_bytes = rtnl_link_get_stat(link, RTNL_LINK_TX_BYTES); printf("link_tx_bytes %d\n",stat->link_tx_bytes); stat->link_rx_errors = rtnl_link_get_stat(link, RTNL_LINK_RX_ERRORS); stat->link_tx_errors = rtnl_link_get_stat(link, RTNL_LINK_TX_ERRORS); stat->link_rx_dropped = rtnl_link_get_stat(link, RTNL_LINK_RX_DROPPED); stat->link_tx_dropped = rtnl_link_get_stat(link, RTNL_LINK_TX_DROPPED); stat->link_rx_compressed = rtnl_link_get_stat(link, RTNL_LINK_RX_COMPRESSED); stat->link_tx_compressed = rtnl_link_get_stat(link, RTNL_LINK_TX_COMPRESSED); stat->link_rx_fifo_err = rtnl_link_get_stat(link, RTNL_LINK_RX_FIFO_ERR); stat->link_tx_fifo_err = rtnl_link_get_stat(link, RTNL_LINK_TX_FIFO_ERR); stat->link_rx_len_err = rtnl_link_get_stat(link, RTNL_LINK_RX_LEN_ERR); stat->link_rx_over_err = rtnl_link_get_stat(link, RTNL_LINK_RX_OVER_ERR); stat->link_rx_crc_err = rtnl_link_get_stat(link, RTNL_LINK_RX_CRC_ERR); stat->link_rx_frame_err = rtnl_link_get_stat(link, RTNL_LINK_RX_FRAME_ERR); stat->link_rx_missed_err = rtnl_link_get_stat(link, RTNL_LINK_RX_MISSED_ERR); stat->link_tx_abort_err = rtnl_link_get_stat(link, RTNL_LINK_TX_ABORT_ERR); stat->link_tx_carrier_err = rtnl_link_get_stat(link, RTNL_LINK_TX_CARRIER_ERR); stat->link_tx_hbeat_err = rtnl_link_get_stat(link, RTNL_LINK_TX_HBEAT_ERR); stat->link_tx_win_err = rtnl_link_get_stat(link, RTNL_LINK_TX_WIN_ERR); stat->link_collisions = rtnl_link_get_stat(link, RTNL_LINK_COLLISIONS); stat->link_multicast = rtnl_link_get_stat(link, RTNL_LINK_MULTICAST); rtnl_link_put(link); // printf(" c_refcnt %d\n",link_cache->c_refcnt); /* nl_cache_free(link_cache); } */ // nl_socket_free(sock); return 0; } With regards, Agafonov. From dsahern at gmail.com Fri Jun 30 09:48:51 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:51 -0600 Subject: [PATCH libnl 04/11] addr: Add support for AF_MPLS In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-5-dsahern@gmail.com> MPLS 'addresses' are 4-byte labels with a prefix length of 20. Signed-off-by: David Ahern --- lib/addr.c | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/lib/addr.c b/lib/addr.c index fe4b2deaa21a..390a798c8d8d 100644 --- a/lib/addr.c +++ b/lib/addr.c @@ -31,6 +31,7 @@ #include #include #include +#include #include /* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote @@ -223,7 +224,13 @@ struct nl_addr *nl_addr_build(int family, const void *buf, size_t size) addr->a_family = family; addr->a_len = size; - addr->a_prefixlen = size*8; + switch(family) { + case AF_MPLS: + addr->a_prefixlen = 20; /* MPLS address is a 20-bit label */ + break; + default: + addr->a_prefixlen = size*8; + } if (size) memcpy(addr->a_addr, buf, size); @@ -290,8 +297,8 @@ struct nl_addr *nl_addr_alloc_attr(const struct nlattr *nla, int family) */ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) { - int err, copy = 0, len = 0, family = AF_UNSPEC; - char *str, *prefix, buf[32]; + int err, copy = 0, len = 0, family = AF_UNSPEC, plen = 0; + char *str, *prefix = NULL, buf[256]; struct nl_addr *addr = NULL; /* gcc ain't that smart */ str = strdup(addrstr); @@ -300,9 +307,11 @@ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) goto errout; } - prefix = strchr(str, '/'); - if (prefix) - *prefix = '\0'; + if (hint != AF_MPLS) { + prefix = strchr(str, '/'); + if (prefix) + *prefix = '\0'; + } if (!strcasecmp(str, "none")) { family = hint; @@ -399,6 +408,17 @@ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) } } + if (hint == AF_MPLS) { + len = mpls_pton(AF_MPLS, str, buf, sizeof(buf)); + if (len <= 0) { + err = -NLE_INVAL; + goto errout; + } + family = AF_MPLS; + plen = 20; + goto prefix; + } + if (hint == AF_UNSPEC && strchr(str, ':')) { size_t i = 0; char *s = str, *p; @@ -445,9 +465,11 @@ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) goto errout; } nl_addr_set_prefixlen(addr, pl); - } else - nl_addr_set_prefixlen(addr, len * 8); - + } else { + if (!plen) + plen = len * 8; + nl_addr_set_prefixlen(addr, plen); + } *result = addr; err = 0; errout: @@ -639,7 +661,7 @@ int nl_addr_iszero(const struct nl_addr *addr) int nl_addr_valid(const char *addr, int family) { int ret; - char buf[32]; + char buf[256]; /* MPLS has N-labels at 4-bytes / label */ switch (family) { case AF_INET: @@ -649,6 +671,12 @@ int nl_addr_valid(const char *addr, int family) return 0; break; + case AF_MPLS: + ret = mpls_pton(family, addr, buf, sizeof(buf)); + if (ret <= 0) + return 0; + break; + case AF_DECnet: ret = dnet_pton(addr, buf); if (ret <= 0) @@ -982,6 +1010,10 @@ char *nl_addr2str(const struct nl_addr *addr, char *buf, size_t size) inet_ntop(AF_INET6, addr->a_addr, buf, size); break; + case AF_MPLS: + mpls_ntop(AF_MPLS, addr->a_addr, buf, size); + break; + case AF_DECnet: dnet_ntop(addr->a_addr, addr->a_len, buf, size); break; @@ -999,7 +1031,8 @@ char *nl_addr2str(const struct nl_addr *addr, char *buf, size_t size) } prefix: - if (addr->a_prefixlen != (8 * addr->a_len)) { + if (addr->a_family != AF_MPLS && + addr->a_prefixlen != (8 * addr->a_len)) { snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen); strncat(buf, tmp, size - strlen(buf) - 1); } @@ -1078,6 +1111,7 @@ static const struct trans_tbl afs[] = { #ifdef AF_VSOCK __ADD(AF_VSOCK,vsock), #endif + __ADD(AF_MPLS,mpls), }; char *nl_af2str(int family, char *buf, size_t size) -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:47 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:47 -0600 Subject: [PATCH libnl 00/11] Add support for MPLS routes and encapsulations Message-ID: <20170630164858.55528-1-dsahern@gmail.com> This patch set adds support for the MPLS address family (LSP and egress) and MPLS encapsulations (ingress to LSP). Patches 1, 2 and 8 update or import header files from the kernel tree. Patch 3 imports mpls_ntop and mpls_pton from iproute2. These are known working implementations so no since re-inventing those wheels. Patch 4 adds support to addr.c for MPLS labels as an nl_addr. Patch 5 adds support for routes in the MPLS address family. MPLS uses 2 new address attributes - RTA_NEWDST and RTA_VIA - per nexthop. RTA_NEWDST is the label stack to be applied on a forward and RTA_VIA is the nexthop for the packet (e.g., an IPv4 or IPv6 address). Patch 6 adds support for TTL propagation attribute per route. This attribute sets whether the TTL is propagated on tunnel egress. Patch 7 adds support for MPLS labels to the commands under src. The 'as' keyword is added as a nexthop option where the value is one or more labels (NEWDST to attribute). The via keyword is updated to use RTA_VIA if the route is added or deleted to the MPLS family. Patch 9 adds support for lwtunnel encapsulation as a generic framework with Patch 10 adding MPLS encapsulation support. Patch 11 adds support for MPLS encap to the commands under src David Ahern (11): Update rtnetlink.h from kernel tree Import mpls header from kernel tree addr: Add implementations for mpls_ntop and mpls_pton addr: Add support for AF_MPLS route: Add support for MPLS address family route: Add support for ttl propagation in MPLS routes Add support for label stack in nl-route commands Import lwtunnel encap files from kernel route: Add support for lwtunnel encapsulations route: Add support for MPLS encap Add support for mpls encap to libnl commands Makefile.am | 5 +- include/linux-private/linux/lwtunnel.h | 69 ++++++++++ include/linux-private/linux/mpls.h | 76 +++++++++++ include/linux-private/linux/mpls_iptunnel.h | 30 +++++ include/linux-private/linux/rtnetlink.h | 18 ++- include/netlink-private/route/nexthop-encap.h | 35 +++++ include/netlink-private/types.h | 11 ++ include/netlink/route/mpls.h | 15 +++ include/netlink/route/nexthop.h | 12 ++ include/netlink/route/route.h | 2 + lib/addr.c | 56 ++++++-- lib/mpls.c | 108 +++++++++++++++ lib/route/nexthop.c | 130 ++++++++++++++++++ lib/route/nexthop_encap.c | 99 ++++++++++++++ lib/route/nh_encap_mpls.c | 134 +++++++++++++++++++ lib/route/route.c | 1 + lib/route/route_obj.c | 181 ++++++++++++++++++++++++-- libnl-route-3.sym | 6 + src/lib/route.c | 26 +++- 19 files changed, 985 insertions(+), 29 deletions(-) create mode 100644 include/linux-private/linux/lwtunnel.h create mode 100644 include/linux-private/linux/mpls.h create mode 100644 include/linux-private/linux/mpls_iptunnel.h create mode 100644 include/netlink-private/route/nexthop-encap.h create mode 100644 include/netlink/route/mpls.h create mode 100644 lib/mpls.c create mode 100644 lib/route/nexthop_encap.c create mode 100644 lib/route/nh_encap_mpls.c -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:48 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:48 -0600 Subject: [PATCH libnl 01/11] Update rtnetlink.h from kernel tree In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-2-dsahern@gmail.com> Update to rtnetlink.h to top of net-next tree as of commit b217566a525ff24334d17635a865f44b68c2c583 Signed-off-by: David Ahern --- include/linux-private/linux/rtnetlink.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/linux-private/linux/rtnetlink.h b/include/linux-private/linux/rtnetlink.h index a92c7c41cdf5..1c363cd602ec 100644 --- a/include/linux-private/linux/rtnetlink.h +++ b/include/linux-private/linux/rtnetlink.h @@ -141,6 +141,11 @@ enum { RTM_GETNSID = 90, #define RTM_GETNSID RTM_GETNSID + RTM_NEWSTATS = 92, +#define RTM_NEWSTATS RTM_NEWSTATS + RTM_GETSTATS = 94, +#define RTM_GETSTATS RTM_GETSTATS + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -272,6 +277,8 @@ enum rt_scope_t { #define RTM_F_CLONED 0x200 /* This route is cloned */ #define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ #define RTM_F_PREFIX 0x800 /* Prefix addresses */ +#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */ +#define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */ /* Reserved table identifiers */ @@ -312,6 +319,10 @@ enum rtattr_type_t { RTA_PREF, RTA_ENCAP_TYPE, RTA_ENCAP, + RTA_EXPIRES, + RTA_PAD, + RTA_UID, + RTA_TTL_PROPAGATE, __RTA_MAX }; @@ -343,8 +354,9 @@ struct rtnexthop { #define RTNH_F_ONLINK 4 /* Gateway is forced on link */ #define RTNH_F_OFFLOAD 8 /* offloaded route */ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ +#define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */ -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN) +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) /* Macros to handle hexthops */ @@ -536,6 +548,9 @@ enum { TCA_FCNT, TCA_STATS2, TCA_STAB, + TCA_PAD, + TCA_DUMP_INVISIBLE, + TCA_CHAIN, __TCA_MAX }; @@ -668,6 +683,7 @@ struct tcamsg { #define RTEXT_FILTER_VF (1 << 0) #define RTEXT_FILTER_BRVLAN (1 << 1) #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) +#define RTEXT_FILTER_SKIP_STATS (1 << 3) /* End of information exported to user level */ -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:49 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:49 -0600 Subject: [PATCH libnl 02/11] Import mpls header from kernel tree In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-3-dsahern@gmail.com> Add include/uapi/linux/mpls.h from net-next tree as of commit b217566a525ff24334d17635a865f44b68c2c583 Signed-off-by: David Ahern --- include/linux-private/linux/mpls.h | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 include/linux-private/linux/mpls.h diff --git a/include/linux-private/linux/mpls.h b/include/linux-private/linux/mpls.h new file mode 100644 index 000000000000..bea57fb7fb94 --- /dev/null +++ b/include/linux-private/linux/mpls.h @@ -0,0 +1,76 @@ +#ifndef __LINUX_MPLS_H +#define __LINUX_MPLS_H + +#include +#include + +/* Reference: RFC 5462, RFC 3032 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Label | TC |S| TTL | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Label: Label Value, 20 bits + * TC: Traffic Class field, 3 bits + * S: Bottom of Stack, 1 bit + * TTL: Time to Live, 8 bits + */ + +struct mpls_label { + __be32 entry; +}; + +#define MPLS_LS_LABEL_MASK 0xFFFFF000 +#define MPLS_LS_LABEL_SHIFT 12 +#define MPLS_LS_TC_MASK 0x00000E00 +#define MPLS_LS_TC_SHIFT 9 +#define MPLS_LS_S_MASK 0x00000100 +#define MPLS_LS_S_SHIFT 8 +#define MPLS_LS_TTL_MASK 0x000000FF +#define MPLS_LS_TTL_SHIFT 0 + +/* Reserved labels */ +#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */ +#define MPLS_LABEL_RTALERT 1 /* RFC3032 */ +#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */ +#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */ +#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */ +#define MPLS_LABEL_GAL 13 /* RFC5586 */ +#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */ +#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ + +#define MPLS_LABEL_FIRST_UNRESERVED 16 /* RFC3032 */ + +/* These are embedded into IFLA_STATS_AF_SPEC: + * [IFLA_STATS_AF_SPEC] + * -> [AF_MPLS] + * -> [MPLS_STATS_xxx] + * + * Attributes: + * [MPLS_STATS_LINK] = { + * struct mpls_link_stats + * } + */ +enum { + MPLS_STATS_UNSPEC, /* also used as 64bit pad attribute */ + MPLS_STATS_LINK, + __MPLS_STATS_MAX, +}; + +#define MPLS_STATS_MAX (__MPLS_STATS_MAX - 1) + +struct mpls_link_stats { + __u64 rx_packets; /* total packets received */ + __u64 tx_packets; /* total packets transmitted */ + __u64 rx_bytes; /* total bytes received */ + __u64 tx_bytes; /* total bytes transmitted */ + __u64 rx_errors; /* bad packets received */ + __u64 tx_errors; /* packet transmit problems */ + __u64 rx_dropped; /* packet dropped on receive */ + __u64 tx_dropped; /* packet dropped on transmit */ + __u64 rx_noroute; /* no route for packet dest */ +}; + +#endif /* __LINUX_MPLS_H */ -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:50 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:50 -0600 Subject: [PATCH libnl 03/11] addr: Add implementations for mpls_ntop and mpls_pton In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-4-dsahern@gmail.com> Implementations of mpls_ntop and mpls_pton taken from iproute2. Signed-off-by: David Ahern --- Makefile.am | 3 +- include/netlink/route/mpls.h | 15 ++++++ lib/mpls.c | 108 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 include/netlink/route/mpls.h create mode 100644 lib/mpls.c diff --git a/Makefile.am b/Makefile.am index 2b817f4a185b..3fd6ba83ad6c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -323,7 +323,8 @@ lib_libnl_3_la_SOURCES = \ lib/utils.c \ lib/version.c \ lib/hash.c \ - lib/hashtable.c + lib/hashtable.c \ + lib/mpls.c EXTRA_lib_libnl_3_la_DEPENDENCIES = \ libnl-3.sym lib_libnl_3_la_CPPFLAGS = \ diff --git a/include/netlink/route/mpls.h b/include/netlink/route/mpls.h new file mode 100644 index 000000000000..502fd34ad4fb --- /dev/null +++ b/include/netlink/route/mpls.h @@ -0,0 +1,15 @@ +#ifndef MPLS_H_ +#define MPLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen); +extern int mpls_pton(int af, const char *src, void *addr, size_t alen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mpls.c b/lib/mpls.c new file mode 100644 index 000000000000..62e92845a30f --- /dev/null +++ b/lib/mpls.c @@ -0,0 +1,108 @@ +/* + * Adapted from mpls_ntop and mpls_pton copied from iproute2, + * lib/mpls_ntop.c and lib/mpls_pton.c + */ +#include +#include +#include +#include +#include +#include +#include + +static const char *mpls_ntop1(const struct mpls_label *addr, + char *buf, size_t buflen) +{ + size_t destlen = buflen; + char *dest = buf; + int count = 0; + + while (1) { + uint32_t entry = ntohl(addr[count++].entry); + uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; + int len = snprintf(dest, destlen, "%u", label); + + if (len >= destlen) + break; + + /* Is this the end? */ + if (entry & MPLS_LS_S_MASK) + return buf; + + dest += len; + destlen -= len; + if (destlen) { + *dest = '/'; + dest++; + destlen--; + } + } + errno = E2BIG; + + return NULL; +} + +const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen) +{ + switch(af) { + case AF_MPLS: + errno = 0; + return mpls_ntop1((struct mpls_label *)addr, buf, buflen); + } + + errno = EINVAL; + return NULL; +} + +static int mpls_pton1(const char *name, struct mpls_label *addr, + unsigned int maxlabels) +{ + char *endp; + unsigned count; + + for (count = 0; count < maxlabels; count++) { + unsigned long label; + + label = strtoul(name, &endp, 0); + /* Fail when the label value is out or range */ + if (label >= (1 << 20)) + return 0; + + if (endp == name) /* no digits */ + return 0; + + addr->entry = htonl(label << MPLS_LS_LABEL_SHIFT); + if (*endp == '\0') { + addr->entry |= htonl(1 << MPLS_LS_S_SHIFT); + return (count + 1) * sizeof(struct mpls_label); + } + + /* Bad character in the address */ + if (*endp != '/') + return 0; + + name = endp + 1; + addr += 1; + } + + /* The address was too long */ + return 0; +} + +int mpls_pton(int af, const char *src, void *addr, size_t alen) +{ + unsigned int maxlabels = alen / sizeof(struct mpls_label); + int err; + + switch(af) { + case AF_MPLS: + errno = 0; + err = mpls_pton1(src, (struct mpls_label *)addr, maxlabels); + break; + default: + errno = EAFNOSUPPORT; + err = -1; + } + + return err; +} -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:52 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:52 -0600 Subject: [PATCH libnl 05/11] route: Add support for MPLS address family In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-6-dsahern@gmail.com> Add support for route in MPLS family. New attributes: - RTA_NEWDST - label stack for a nexthop - RTA_VIA - nexthop address (e.g., IPv4 or IPv6) Other changes required: - scope has to be universe for MPLS routes so fixup rtnl_route_guess_scope - priority attribute should not be required for routes. For MPLS it can not be set. Change ROUTE_ATTR_PRIO to only be set if priority is set. - table attribute should not be set unless something other than the default table. For MPLS this attribute can not be set. '/' is the separator in label stacks for consistency with iproute2. Signed-off-by: David Ahern --- include/netlink-private/types.h | 2 + include/netlink/route/nexthop.h | 6 ++ lib/route/nexthop.c | 97 +++++++++++++++++++++++++++++ lib/route/route.c | 1 + lib/route/route_obj.c | 132 +++++++++++++++++++++++++++++++++++----- libnl-route-3.sym | 4 ++ 6 files changed, 228 insertions(+), 14 deletions(-) diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index b6c5cea06303..ad4b12521328 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -311,6 +311,8 @@ struct rtnl_nexthop uint32_t ce_mask; /* HACK to support attr macros */ struct nl_list_head rtnh_list; uint32_t rtnh_realms; + struct nl_addr * rtnh_newdst; + struct nl_addr * rtnh_via; }; struct rtnl_route diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h index 2aa44dce6fb0..654b84df9f27 100644 --- a/include/netlink/route/nexthop.h +++ b/include/netlink/route/nexthop.h @@ -55,6 +55,12 @@ extern void rtnl_route_nh_set_realms(struct rtnl_nexthop *, uint32_t); extern uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *); +extern int rtnl_route_nh_set_newdst(struct rtnl_nexthop *, + struct nl_addr *); +extern struct nl_addr * rtnl_route_nh_get_newdst(struct rtnl_nexthop *); +extern int rtnl_route_nh_set_via(struct rtnl_nexthop *, + struct nl_addr *); +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 *); diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c index a7cda90ba208..c69b23e1f0de 100644 --- a/lib/route/nexthop.c +++ b/lib/route/nexthop.c @@ -27,6 +27,8 @@ #define NH_ATTR_IFINDEX 0x000004 #define NH_ATTR_GATEWAY 0x000008 #define NH_ATTR_REALMS 0x000010 +#define NH_ATTR_NEWDST 0x000020 +#define NH_ATTR_VIA 0x000040 /** @endcond */ /** @@ -69,12 +71,33 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src) } } + if (src->rtnh_newdst) { + nh->rtnh_newdst = nl_addr_clone(src->rtnh_newdst); + if (!nh->rtnh_newdst) { + nl_addr_put(nh->rtnh_gateway); + free(nh); + return NULL; + } + } + + if (src->rtnh_via) { + nh->rtnh_via = nl_addr_clone(src->rtnh_via); + if (!nh->rtnh_via) { + nl_addr_put(nh->rtnh_gateway); + nl_addr_put(nh->rtnh_newdst); + free(nh); + return NULL; + } + } + return nh; } 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); free(nh); } @@ -92,6 +115,10 @@ int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, b->rtnh_gateway)); + diff |= NH_DIFF(NEWDST, nl_addr_cmp(a->rtnh_newdst, + b->rtnh_newdst)); + diff |= NH_DIFF(VIA, nl_addr_cmp(a->rtnh_via, + b->rtnh_via)); if (loose) diff |= NH_DIFF(FLAGS, @@ -111,8 +138,16 @@ 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_NEWDST) + nl_dump(dp, "as to %s ", + nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf))); + nl_dump(dp, "via"); + if (nh->ce_mask & NH_ATTR_VIA) + nl_dump(dp, " %s", + nl_addr2str(nh->rtnh_via, buf, sizeof(buf))); + if (nh->ce_mask & NH_ATTR_GATEWAY) nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); @@ -142,6 +177,14 @@ static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) nl_dump(dp, "nexthop"); + if (nh->ce_mask & NH_ATTR_NEWDST) + nl_dump(dp, " as to %s", + nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf))); + + if (nh->ce_mask & NH_ATTR_VIA) + nl_dump(dp, " via %s", + nl_addr2str(nh->rtnh_via, buf, sizeof(buf))); + if (nh->ce_mask & NH_ATTR_GATEWAY) nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); @@ -269,6 +312,60 @@ uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) return nh->rtnh_realms; } +int rtnl_route_nh_set_newdst(struct rtnl_nexthop *nh, struct nl_addr *addr) +{ + struct nl_addr *old = nh->rtnh_newdst; + + if (!nl_addr_valid(nl_addr_get_binary_addr(addr), + nl_addr_get_len(addr))) + return -NLE_INVAL; + + if (addr) { + nh->rtnh_newdst = nl_addr_get(addr); + nh->ce_mask |= NH_ATTR_NEWDST; + } else { + nh->ce_mask &= ~NH_ATTR_NEWDST; + nh->rtnh_newdst = NULL; + } + + if (old) + nl_addr_put(old); + + return 0; +} + +struct nl_addr *rtnl_route_nh_get_newdst(struct rtnl_nexthop *nh) +{ + return nh->rtnh_newdst; +} + +int rtnl_route_nh_set_via(struct rtnl_nexthop *nh, struct nl_addr *addr) +{ + struct nl_addr *old = nh->rtnh_via; + + if (!nl_addr_valid(nl_addr_get_binary_addr(addr), + nl_addr_get_len(addr))) + return -NLE_INVAL; + + if (addr) { + nh->rtnh_via = nl_addr_get(addr); + nh->ce_mask |= NH_ATTR_VIA; + } else { + nh->ce_mask &= ~NH_ATTR_VIA; + nh->rtnh_via= NULL; + } + + if (old) + nl_addr_put(old); + + return 0; +} + +struct nl_addr *rtnl_route_nh_get_via(struct rtnl_nexthop *nh) +{ + return nh->rtnh_via; +} + /** @} */ /** diff --git a/lib/route/route.c b/lib/route/route.c index 29851873c09b..6688749ae227 100644 --- a/lib/route/route.c +++ b/lib/route/route.c @@ -173,6 +173,7 @@ int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags) static struct nl_af_group route_groups[] = { { AF_INET, RTNLGRP_IPV4_ROUTE }, { AF_INET6, RTNLGRP_IPV6_ROUTE }, + { AF_MPLS, RTNLGRP_MPLS_ROUTE }, { AF_DECnet, RTNLGRP_DECnet_ROUTE }, { END_OF_GROUP_LIST }, }; diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index b8e9f77c1868..834b7743d632 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -646,8 +646,11 @@ uint8_t rtnl_route_get_protocol(struct rtnl_route *route) void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio) { - route->rt_prio = prio; - route->ce_mask |= ROUTE_ATTR_PRIO; + /* MPLS address family does not allow RTA_PRIORITY to be set */ + if (route->rt_family != AF_MPLS) { + route->rt_prio = prio; + route->ce_mask |= ROUTE_ATTR_PRIO; + } } uint32_t rtnl_route_get_priority(struct rtnl_route *route) @@ -657,13 +660,17 @@ uint32_t rtnl_route_get_priority(struct rtnl_route *route) int rtnl_route_set_family(struct rtnl_route *route, uint8_t family) { - if (family != AF_INET && family != AF_INET6 && family != AF_DECnet) - return -NLE_AF_NOSUPPORT; - - route->rt_family = family; - route->ce_mask |= ROUTE_ATTR_FAMILY; + switch(family) { + case AF_INET: + case AF_INET6: + case AF_DECnet: + case AF_MPLS: + route->rt_family = family; + route->ce_mask |= ROUTE_ATTR_FAMILY; + return 0; + } - return 0; + return -NLE_AF_NOSUPPORT; } uint8_t rtnl_route_get_family(struct rtnl_route *route) @@ -918,6 +925,9 @@ int rtnl_route_guess_scope(struct rtnl_route *route) if (route->rt_type == RTN_LOCAL) return RT_SCOPE_HOST; + if (route->rt_family == AF_MPLS) + return RT_SCOPE_UNIVERSE; + if (!nl_list_empty(&route->rt_nexthops)) { struct rtnl_nexthop *nh; @@ -936,6 +946,31 @@ int rtnl_route_guess_scope(struct rtnl_route *route) /** @} */ +static struct nl_addr *rtnl_route_parse_via(struct nlattr *nla) +{ + int alen = nla_len(nla) - offsetof(struct rtvia, rtvia_addr); + struct rtvia *via = nla_data(nla); + + return nl_addr_build(via->rtvia_family, via->rtvia_addr, alen); +} + +static int rtnl_route_put_via(struct nl_msg *msg, struct nl_addr *addr) +{ + unsigned int alen = nl_addr_get_len(addr); + struct nlattr *nla; + struct rtvia *via; + + nla = nla_reserve(msg, RTA_VIA, alen + sizeof(*via)); + if (!nla) + return -EMSGSIZE; + + via = nla_data(nla); + via->rtvia_family = nl_addr_get_family(addr); + memcpy(via->rtvia_addr, nl_addr_get_binary_addr(addr), alen); + + return 0; +} + static struct nla_policy route_policy[RTA_MAX+1] = { [RTA_IIF] = { .type = NLA_U32 }, [RTA_OIF] = { .type = NLA_U32 }, @@ -992,6 +1027,33 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) realms = nla_get_u32(ntb[RTA_FLOW]); rtnl_route_nh_set_realms(nh, realms); } + + if (ntb[RTA_NEWDST]) { + struct nl_addr *addr; + + addr = nl_addr_alloc_attr(ntb[RTA_NEWDST], + route->rt_family); + if (!addr) + goto errout; + + err = rtnl_route_nh_set_newdst(nh, addr); + nl_addr_put(addr); + if (err) + goto errout; + } + + if (ntb[RTA_VIA]) { + struct nl_addr *addr; + + addr = rtnl_route_parse_via(ntb[RTA_VIA]); + if (!addr) + goto errout; + + err = rtnl_route_nh_set_via(nh, addr); + nl_addr_put(addr); + if (err) + goto errout; + } } rtnl_route_add_nexthop(route, nh); @@ -1041,7 +1103,7 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE | ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL | - ROUTE_ATTR_FLAGS | ROUTE_ATTR_PRIO; + ROUTE_ATTR_FLAGS; if (tb[RTA_DST]) { if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family))) @@ -1140,6 +1202,33 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW])); } + if (tb[RTA_NEWDST]) { + struct nl_addr *addr; + + addr = nl_addr_alloc_attr(tb[RTA_NEWDST], route->rt_family); + if (!addr) + goto errout_nomem; + + err = rtnl_route_nh_set_newdst(old_nh, addr); + nl_addr_put(addr); + if (err) + goto errout; + } + + if (tb[RTA_VIA]) { + int alen = nla_len(tb[RTA_VIA]) - offsetof(struct rtvia, rtvia_addr); + struct rtvia *via = nla_data(tb[RTA_VIA]); + + addr = nl_addr_build(via->rtvia_family, via->rtvia_addr, alen); + if (!addr) + goto errout_nomem; + + err = rtnl_route_nh_set_via(old_nh, addr); + nl_addr_put(addr); + if (err) + goto errout; + } + if (old_nh) { rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff); if (route->rt_nr_nh == 0) { @@ -1214,12 +1303,17 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) goto nla_put_failure; /* Additional table attribute replacing the 8bit in the header, was - * required to allow more than 256 tables. */ - NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); + * required to allow more than 256 tables. MPLS does not allow the + * table attribute to be set + */ + if (route->rt_family != AF_MPLS) + NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); if (nl_addr_get_len(route->rt_dst)) NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); - NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); + + if (route->ce_mask & ROUTE_ATTR_PRIO) + NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); if (route->ce_mask & ROUTE_ATTR_SRC) NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); @@ -1255,6 +1349,10 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex); if (nh->rtnh_realms) NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + if (nh->rtnh_newdst) + 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; } else if (rtnl_route_get_nnexthops(route) > 1) { struct nlattr *multipath; struct rtnl_nexthop *nh; @@ -1277,6 +1375,13 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway); + if (nh->rtnh_newdst) + 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_realms) NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); @@ -1310,8 +1415,7 @@ struct nl_object_ops route_obj_ops = { .oo_update = route_update, .oo_attrs2str = route_attrs2str, .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | - ROUTE_ATTR_TABLE | ROUTE_ATTR_DST | - ROUTE_ATTR_PRIO), + ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), }; /** @endcond */ diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 2ba920b463cf..bb2d6583b8bc 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1053,4 +1053,8 @@ libnl_3_4 { rtnl_rule_get_l3mdev; rtnl_rule_set_l3mdev; rtnl_u32_get_action; + rtnl_route_nh_set_newdst; + rtnl_route_nh_get_newdst; + rtnl_route_nh_set_via; + rtnl_route_nh_get_via; } libnl_3_2_29; -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:56 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:56 -0600 Subject: [PATCH libnl 09/11] route: Add support for lwtunnel encapsulations In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-10-dsahern@gmail.com> 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 --- Makefile.am | 1 + include/netlink-private/route/nexthop-encap.h | 30 ++++++++ include/netlink-private/types.h | 8 +++ lib/route/nexthop.c | 33 +++++++++ lib/route/nexthop_encap.c | 99 +++++++++++++++++++++++++++ lib/route/route_obj.c | 25 +++++++ 6 files changed, 196 insertions(+) create mode 100644 include/netlink-private/route/nexthop-encap.h create mode 100644 lib/route/nexthop_encap.c diff --git a/Makefile.am b/Makefile.am index 3fd6ba83ad6c..26e0f479afba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -384,6 +384,7 @@ lib_libnl_route_3_la_SOURCES = \ lib/route/neightbl.c \ lib/route/netconf.c \ lib/route/nexthop.c \ + lib/route/nexthop_encap.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 new file mode 100644 index 000000000000..ba96b0d634a9 --- /dev/null +++ b/include/netlink-private/route/nexthop-encap.h @@ -0,0 +1,30 @@ +#ifndef NETLINK_NEXTHOP_ENCAP_H_ +#define NETLINK_NEXTHOP_ENCAP_H_ + +struct nh_encap_ops { + uint16_t encap_type; + + int (*build_msg)(struct nl_msg *msg, void *priv); + int (*parse_msg)(struct nlattr *nla, struct rtnl_nexthop *rtnh); + + int (*compare)(void *a, void *b); + + void (*dump)(void *priv, struct nl_dump_params *dp); + void (*destructor)(void *priv); +}; + +struct rtnl_nh_encap; + +/* + * generic nexthop encap + */ +void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap); + +int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type, + struct rtnl_nexthop *rtnh); +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); +#endif diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index 5d165b68b0ae..35c96899f742 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -300,6 +301,12 @@ struct rtnl_addr struct rtnl_link *a_link; }; +struct rtnl_nh_encap +{ + struct nh_encap_ops *ops; + void *priv; /* private data for encap type */ +}; + struct rtnl_nexthop { uint8_t rtnh_flags; @@ -313,6 +320,7 @@ struct rtnl_nexthop uint32_t rtnh_realms; struct nl_addr * rtnh_newdst; struct nl_addr * rtnh_via; + struct rtnl_nh_encap * rtnh_encap; }; struct rtnl_route diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c index c69b23e1f0de..279b2d8304fb 100644 --- a/lib/route/nexthop.c +++ b/lib/route/nexthop.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -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,23 @@ 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); + } + + 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 000000000000..9d9307a069d8 --- /dev/null +++ b/lib/route/nexthop_encap.c @@ -0,0 +1,99 @@ + +#include +#include +#include +#include + +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 67e2b6ad92f5..330a0ea6648f 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -995,6 +996,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) @@ -1070,6 +1073,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); @@ -1250,6 +1261,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) { @@ -1377,6 +1395,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; @@ -1409,6 +1430,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; } -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:54 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:54 -0600 Subject: [PATCH libnl 07/11] Add support for label stack in nl-route commands In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-8-dsahern@gmail.com> Add support for MPLS labels in nexthop specification. Specifically, the 'as' keyword specifies the MPLS label stack and if the route address family is MPLS then the nexthop via is added as a route via instead of a gateway (subtle differences introduced for MPLS). Signed-off-by: David Ahern --- src/lib/route.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/lib/route.c b/src/lib/route.c index cd3e89783b33..2eac0a05c97e 100644 --- a/src/lib/route.c +++ b/src/lib/route.c @@ -141,11 +141,13 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts, NH_DEV, NH_VIA, NH_WEIGHT, + NH_AS, }; static char *const tokens[] = { "dev", "via", "weight", + "as", NULL, }; struct rtnl_nexthop *nh; @@ -175,8 +177,20 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts, break; case NH_VIA: - addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route)); - rtnl_route_nh_set_gateway(nh, addr); + if (rtnl_route_get_family(route) == AF_MPLS) { + addr = nl_cli_addr_parse(arg, 0); + rtnl_route_nh_set_via(nh, addr); + } else { + addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route)); + rtnl_route_nh_set_gateway(nh, addr); + } + nl_addr_put(addr); + break; + + case NH_AS: + addr = nl_cli_addr_parse(arg, + rtnl_route_get_family(route)); + rtnl_route_nh_set_newdst(nh, addr); nl_addr_put(addr); break; -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:53 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:53 -0600 Subject: [PATCH libnl 06/11] route: Add support for ttl propagation in MPLS routes In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-7-dsahern@gmail.com> Add support for RTA_TTL_PROPAGATE attribute on a per-route basis. Used to enable/disable TTL propagation at LSP egress. Signed-off-by: David Ahern --- include/netlink-private/types.h | 1 + include/netlink/route/route.h | 2 ++ lib/route/route_obj.c | 24 ++++++++++++++++++++++++ libnl-route-3.sym | 1 + 4 files changed, 28 insertions(+) diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index ad4b12521328..5d165b68b0ae 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -327,6 +327,7 @@ struct rtnl_route uint8_t rt_scope; uint8_t rt_type; uint8_t rt_nmetrics; + uint8_t rt_ttl_propagate; uint32_t rt_flags; struct nl_addr * rt_dst; struct nl_addr * rt_src; diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h index 477250dd8258..d74fb4c2638a 100644 --- a/include/netlink/route/route.h +++ b/include/netlink/route/route.h @@ -94,6 +94,8 @@ extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *); extern void rtnl_route_set_iif(struct rtnl_route *, int); extern int rtnl_route_get_iif(struct rtnl_route *); extern int rtnl_route_get_src_len(struct rtnl_route *); +extern void rtnl_route_set_ttl_propagate(struct rtnl_route *route, + uint8_t ttl_prop); extern void rtnl_route_add_nexthop(struct rtnl_route *, struct rtnl_nexthop *); diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index 834b7743d632..67e2b6ad92f5 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -62,6 +62,7 @@ #define ROUTE_ATTR_MULTIPATH 0x008000 #define ROUTE_ATTR_REALMS 0x010000 #define ROUTE_ATTR_CACHEINFO 0x020000 +#define ROUTE_ATTR_TTL_PROPAGATE 0x100000 /** @endcond */ static void route_constructor(struct nl_object *c) @@ -245,6 +246,11 @@ static void route_dump_details(struct nl_object *a, struct nl_dump_params *p) if (r->ce_mask & ROUTE_ATTR_SRC) nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_TTL_PROPAGATE) { + nl_dump(p, " ttl-propagate %s", + r->rt_ttl_propagate ? "enabled" : "disabled"); + } + nl_dump(p, "\n"); if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { @@ -368,6 +374,8 @@ static uint64_t route_compare(struct nl_object *_a, struct nl_object *_b, diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif); diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src, b->rt_pref_src)); + diff |= ROUTE_DIFF(TTL_PROPAGATE, + a->rt_ttl_propagate != b->rt_ttl_propagate); if (flags & LOOSE_COMPARISON) { nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { @@ -565,6 +573,7 @@ static const struct trans_tbl route_attrs[] = { __ADD(ROUTE_ATTR_MULTIPATH, multipath), __ADD(ROUTE_ATTR_REALMS, realms), __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo), + __ADD(ROUTE_ATTR_TTL_PROPAGATE, ttl_propagate), }; static char *route_attrs2str(int attrs, char *buf, size_t len) @@ -900,6 +909,12 @@ struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n) return NULL; } +void rtnl_route_set_ttl_propagate(struct rtnl_route *route, uint8_t ttl_prop) +{ + route->rt_ttl_propagate = ttl_prop; + route->ce_mask |= ROUTE_ATTR_TTL_PROPAGATE; +} + /** @} */ /** @@ -979,6 +994,7 @@ static struct nla_policy route_policy[RTA_MAX+1] = { [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .type = NLA_NESTED }, + [RTA_TTL_PROPAGATE] = { .type = NLA_U8 }, }; static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) @@ -1229,6 +1245,11 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) goto errout; } + if (tb[RTA_TTL_PROPAGATE]) { + rtnl_route_set_ttl_propagate(route, + nla_get_u8(tb[RTA_TTL_PROPAGATE])); + } + if (old_nh) { rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff); if (route->rt_nr_nh == 0) { @@ -1324,6 +1345,9 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) if (route->ce_mask & ROUTE_ATTR_IIF) NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); + if (route->ce_mask & ROUTE_ATTR_TTL_PROPAGATE) + NLA_PUT_U8(msg, RTA_TTL_PROPAGATE, route->rt_ttl_propagate); + if (route->rt_nmetrics > 0) { uint32_t val; diff --git a/libnl-route-3.sym b/libnl-route-3.sym index bb2d6583b8bc..a8f67ad8471f 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1057,4 +1057,5 @@ libnl_3_4 { rtnl_route_nh_get_newdst; rtnl_route_nh_set_via; rtnl_route_nh_get_via; + rtnl_route_set_ttl_propagate; } libnl_3_2_29; -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:55 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:55 -0600 Subject: [PATCH libnl 08/11] Import lwtunnel encap files from kernel In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-9-dsahern@gmail.com> Import lwtunnel and mpls_iptunnel.h from net-next tree as of commit b217566a525ff24334d17635a865f44b68c2c583 Signed-off-by: David Ahern --- include/linux-private/linux/lwtunnel.h | 69 +++++++++++++++++++++++++++++ include/linux-private/linux/mpls_iptunnel.h | 30 +++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 include/linux-private/linux/lwtunnel.h create mode 100644 include/linux-private/linux/mpls_iptunnel.h diff --git a/include/linux-private/linux/lwtunnel.h b/include/linux-private/linux/lwtunnel.h new file mode 100644 index 000000000000..b616061a5450 --- /dev/null +++ b/include/linux-private/linux/lwtunnel.h @@ -0,0 +1,69 @@ +#ifndef __LINUX_LWTUNNEL_H_ +#define __LINUX_LWTUNNEL_H_ + +#include + +enum lwtunnel_encap_types { + LWTUNNEL_ENCAP_NONE, + LWTUNNEL_ENCAP_MPLS, + LWTUNNEL_ENCAP_IP, + LWTUNNEL_ENCAP_ILA, + LWTUNNEL_ENCAP_IP6, + LWTUNNEL_ENCAP_SEG6, + LWTUNNEL_ENCAP_BPF, + __LWTUNNEL_ENCAP_MAX, +}; + +#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1) + +enum lwtunnel_ip_t { + LWTUNNEL_IP_UNSPEC, + LWTUNNEL_IP_ID, + LWTUNNEL_IP_DST, + LWTUNNEL_IP_SRC, + LWTUNNEL_IP_TTL, + LWTUNNEL_IP_TOS, + LWTUNNEL_IP_FLAGS, + LWTUNNEL_IP_PAD, + __LWTUNNEL_IP_MAX, +}; + +#define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1) + +enum lwtunnel_ip6_t { + LWTUNNEL_IP6_UNSPEC, + LWTUNNEL_IP6_ID, + LWTUNNEL_IP6_DST, + LWTUNNEL_IP6_SRC, + LWTUNNEL_IP6_HOPLIMIT, + LWTUNNEL_IP6_TC, + LWTUNNEL_IP6_FLAGS, + LWTUNNEL_IP6_PAD, + __LWTUNNEL_IP6_MAX, +}; + +#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1) + +enum { + LWT_BPF_PROG_UNSPEC, + LWT_BPF_PROG_FD, + LWT_BPF_PROG_NAME, + __LWT_BPF_PROG_MAX, +}; + +#define LWT_BPF_PROG_MAX (__LWT_BPF_PROG_MAX - 1) + +enum { + LWT_BPF_UNSPEC, + LWT_BPF_IN, + LWT_BPF_OUT, + LWT_BPF_XMIT, + LWT_BPF_XMIT_HEADROOM, + __LWT_BPF_MAX, +}; + +#define LWT_BPF_MAX (__LWT_BPF_MAX - 1) + +#define LWT_BPF_MAX_HEADROOM 256 + +#endif /* __LINUX_LWTUNNEL_H_ */ diff --git a/include/linux-private/linux/mpls_iptunnel.h b/include/linux-private/linux/mpls_iptunnel.h new file mode 100644 index 000000000000..46f3001d450e --- /dev/null +++ b/include/linux-private/linux/mpls_iptunnel.h @@ -0,0 +1,30 @@ +/* + * mpls tunnel api + * + * Authors: + * Roopa Prabhu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __LINUX_MPLS_IPTUNNEL_H +#define __LINUX_MPLS_IPTUNNEL_H + +/* MPLS tunnel attributes + * [RTA_ENCAP] = { + * [MPLS_IPTUNNEL_DST] + * [MPLS_IPTUNNEL_TTL] + * } + */ +enum { + MPLS_IPTUNNEL_UNSPEC, + MPLS_IPTUNNEL_DST, + MPLS_IPTUNNEL_TTL, + __MPLS_IPTUNNEL_MAX, +}; +#define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) + +#endif /* __LINUX_MPLS_IPTUNNEL_H */ -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:57 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:57 -0600 Subject: [PATCH libnl 10/11] route: Add support for MPLS encap In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-11-dsahern@gmail.com> 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 26e0f479afba..7b138295be98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -385,6 +385,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 ba96b0d634a9..dde1bfbec05d 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 654b84df9f27..5b422ddfa593 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 9d9307a069d8..849d2e3edf73 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 000000000000..5e96289e3f60 --- /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 a8f67ad8471f..ab19ae3db731 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1058,4 +1058,5 @@ libnl_3_4 { rtnl_route_nh_set_via; rtnl_route_nh_get_via; rtnl_route_set_ttl_propagate; + rtnl_route_nh_encap_mpls; } libnl_3_2_29; -- 2.11.0 (Apple Git-81) From dsahern at gmail.com Fri Jun 30 09:48:58 2017 From: dsahern at gmail.com (David Ahern) Date: Fri, 30 Jun 2017 10:48:58 -0600 Subject: [PATCH libnl 11/11] Add support for mpls encap to libnl commands In-Reply-To: <20170630164858.55528-1-dsahern@gmail.com> References: <20170630164858.55528-1-dsahern@gmail.com> Message-ID: <20170630164858.55528-12-dsahern@gmail.com> Add support for MPLS lwtunnel encapsulation in nexthop specification. Specifically, the mpls keyword is used to specify the label stack to be applied to the route. Signed-off-by: David Ahern --- src/lib/route.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/route.c b/src/lib/route.c index 2eac0a05c97e..244848b80f85 100644 --- a/src/lib/route.c +++ b/src/lib/route.c @@ -142,12 +142,14 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts, NH_VIA, NH_WEIGHT, NH_AS, + NH_MPLS, }; static char *const tokens[] = { "dev", "via", "weight", "as", + "mpls", NULL, }; struct rtnl_nexthop *nh; @@ -194,6 +196,12 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts, nl_addr_put(addr); break; + case NH_MPLS: + addr = nl_cli_addr_parse(arg, AF_MPLS); + rtnl_route_nh_encap_mpls(nh, addr, 0); + nl_addr_put(addr); + break; + case NH_WEIGHT: lval = strtoul(arg, &endptr, 0); if (endptr == arg) -- 2.11.0 (Apple Git-81)