diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2017-02-28 10:57:05 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2017-03-07 11:47:46 +0100 |
commit | 91810ecc13239f3b18c8299de265b4f3531c0017 (patch) | |
tree | 1f274a6b35ae4db1e8fbe6749cdfbea9f38459a9 /system-linux.c | |
parent | f1076561f4cd4e391ca654d76498b0429413c61e (diff) |
system-linux: add VXLAN support
VXLAN shares many attributes with the tunnel devices, so it is implemented
as a new tunnel type. The 'remote' attribute can be used for an unicast
peer or a multicast group.
The IANA-assigned port 4789 is used by default, instead of the non-standard
port Linux defaults to.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
Acked-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'system-linux.c')
-rw-r--r-- | system-linux.c | 160 |
1 files changed, 159 insertions, 1 deletions
diff --git a/system-linux.c b/system-linux.c index f4d6c25..8888047 100644 --- a/system-linux.c +++ b/system-linux.c @@ -4,6 +4,7 @@ * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org> * Copyright (C) 2013 Steven Barth <steven@midlink.org> * Copyright (C) 2014 Gioacchino Mazzurco <gio@eigenlab.org> + * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -25,6 +26,7 @@ #include <net/if_arp.h> #include <arpa/inet.h> +#include <netinet/ether.h> #include <netinet/in.h> #include <linux/rtnetlink.h> @@ -2540,6 +2542,155 @@ failure: } #endif +#ifdef IFLA_VXLAN_MAX +static int system_add_vxlan(const char *name, const unsigned int link, struct blob_attr **tb, bool v6) +{ + struct blob_attr *tb_data[__VXLAN_DATA_ATTR_MAX]; + struct nl_msg *msg; + struct nlattr *linkinfo, *data; + struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, }; + struct blob_attr *cur; + int ret = 0; + + if ((cur = tb[TUNNEL_ATTR_DATA])) + blobmsg_parse(vxlan_data_attr_list.params, __VXLAN_DATA_ATTR_MAX, tb_data, + blobmsg_data(cur), blobmsg_len(cur)); + else + return -EINVAL; + + msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + + if (!msg) + return -1; + + nlmsg_append(msg, &iim, sizeof(iim), 0); + + nla_put_string(msg, IFLA_IFNAME, name); + + if ((cur = tb_data[VXLAN_DATA_ATTR_MACADDR])) { + struct ether_addr *ea = ether_aton(blobmsg_get_string(cur)); + if (!ea) { + ret = -EINVAL; + goto failure; + } + + nla_put(msg, IFLA_ADDRESS, ETH_ALEN, ea); + } + + if ((cur = tb[TUNNEL_ATTR_MTU])) { + uint32_t mtu = blobmsg_get_u32(cur); + nla_put_u32(msg, IFLA_MTU, mtu); + } + + if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO))) { + ret = -ENOMEM; + goto failure; + } + + nla_put_string(msg, IFLA_INFO_KIND, "vxlan"); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) { + ret = -ENOMEM; + goto failure; + } + + if (link) + nla_put_u32(msg, IFLA_VXLAN_LINK, link); + + if ((cur = tb_data[VXLAN_DATA_ATTR_ID])) { + uint32_t id = blobmsg_get_u32(cur); + if (id >= (1u << 24) - 1) { + ret = -EINVAL; + goto failure; + } + + nla_put_u32(msg, IFLA_VXLAN_ID, id); + } + + if (v6) { + struct in6_addr in6buf; + if ((cur = tb[TUNNEL_ATTR_LOCAL])) { + if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(msg, IFLA_VXLAN_LOCAL6, sizeof(in6buf), &in6buf); + } + + if ((cur = tb[TUNNEL_ATTR_REMOTE])) { + if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(msg, IFLA_VXLAN_GROUP6, sizeof(in6buf), &in6buf); + } + } else { + struct in_addr inbuf; + + if ((cur = tb[TUNNEL_ATTR_LOCAL])) { + if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(msg, IFLA_VXLAN_LOCAL, sizeof(inbuf), &inbuf); + } + + if ((cur = tb[TUNNEL_ATTR_REMOTE])) { + if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(msg, IFLA_VXLAN_GROUP, sizeof(inbuf), &inbuf); + } + } + + uint32_t port = 4789; + if ((cur = tb_data[VXLAN_DATA_ATTR_PORT])) { + port = blobmsg_get_u32(cur); + if (port < 1 || port > 65535) { + ret = -EINVAL; + goto failure; + } + } + nla_put_u16(msg, IFLA_VXLAN_PORT, htons(port)); + + if ((cur = tb[TUNNEL_ATTR_TOS])) { + char *str = blobmsg_get_string(cur); + unsigned tos = 1; + + if (strcmp(str, "inherit")) { + if (!system_tos_aton(str, &tos)) + return -EINVAL; + } + + nla_put_u8(msg, IFLA_VXLAN_TOS, tos); + } + + if ((cur = tb[TUNNEL_ATTR_TTL])) { + uint32_t ttl = blobmsg_get_u32(cur); + if (ttl < 1 || ttl > 255) { + ret = -EINVAL; + goto failure; + } + + nla_put_u8(msg, IFLA_VXLAN_TTL, ttl); + } + + nla_nest_end(msg, data); + nla_nest_end(msg, linkinfo); + + ret = system_rtnl_call(msg); + if (ret) + D(SYSTEM, "Error adding vxlan '%s': %d\n", name, ret); + + return ret; + +failure: + nlmsg_free(msg); + return ret; +} +#endif + static int system_add_proto_tunnel(const char *name, const uint8_t proto, const unsigned int link, struct blob_attr **tb) { struct blob_attr *cur; @@ -2609,7 +2760,8 @@ static int __system_del_ip_tunnel(const char *name, struct blob_attr **tb) if (!strcmp(str, "greip") || !strcmp(str, "gretapip") || !strcmp(str, "greip6") || !strcmp(str, "gretapip6") || - !strcmp(str, "vtiip") || !strcmp(str, "vtiip6")) + !strcmp(str, "vtiip") || !strcmp(str, "vtiip6") || + !strcmp(str, "vxlan") || !strcmp(str, "vxlan6")) return system_link_del(name); else return tunnel_ioctl(name, SIOCDELTUNNEL, NULL); @@ -2833,6 +2985,12 @@ failure: } else if (!strcmp(str, "vtiip6")) { return system_add_vti_tunnel(name, "vti6", link, tb, true); #endif +#ifdef IFLA_VXLAN_MAX + } else if(!strcmp(str, "vxlan")) { + return system_add_vxlan(name, link, tb, false); + } else if(!strcmp(str, "vxlan6")) { + return system_add_vxlan(name, link, tb, true); +#endif #endif } else if (!strcmp(str, "ipip")) { return system_add_proto_tunnel(name, IPPROTO_IPIP, link, tb); |