diff options
author | David Ahern <dsahern@gmail.com> | 2017-08-17 22:59:31 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-08-18 13:01:04 (GMT) |
commit | 3cf287ca17ab4e095b9d400c21f4f21e00e4ae8d (patch) | |
tree | 52bdc6065cddcd897d4a658a29d19fa3659155ba /lib/addr.c | |
parent | 665fccadcafd219b2b8e2bf7ce09d4cb8eb66d69 (diff) | |
download | libnl-3cf287ca17ab4e095b9d400c21f4f21e00e4ae8d.zip libnl-3cf287ca17ab4e095b9d400c21f4f21e00e4ae8d.tar.gz libnl-3cf287ca17ab4e095b9d400c21f4f21e00e4ae8d.tar.bz2 |
addr: Add support for AF_MPLS
MPLS 'addresses' are 4-byte labels with a prefix length of 20.
Signed-off-by: David Ahern <dsahern@gmail.com>
Diffstat (limited to 'lib/addr.c')
-rw-r--r-- | lib/addr.c | 56 |
1 files changed, 45 insertions, 11 deletions
@@ -31,6 +31,7 @@ #include <netlink/netlink.h> #include <netlink/utils.h> #include <netlink/addr.h> +#include <netlink-private/route/mpls.h> #include <linux/socket.h> /* 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 @@ prefix: 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) |