* 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
#include <net/if_arp.h>
#include <arpa/inet.h>
+#include <netinet/ether.h>
#include <netinet/in.h>
#include <linux/rtnetlink.h>
system_set_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/gc_stale_time", dev->ifname, val);
}
+static void system_set_neigh4locktime(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/locktime", dev->ifname, val);
+}
+
static void system_set_dadtransmits(struct device *dev, const char *val)
{
system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/dad_transmits", dev->ifname, val);
dev->ifname, buf, buf_sz);
}
+static int system_get_neigh4locktime(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/locktime",
+ dev->ifname, buf, buf_sz);
+}
+
static int system_get_dadtransmits(struct device *dev, char *buf, const size_t buf_sz)
{
return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/dad_transmits",
s->flags |= DEV_OPT_NEIGHREACHABLETIME;
}
+ if (!system_get_neigh4locktime(dev, buf, sizeof(buf))) {
+ s->neigh4locktime = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_NEIGHLOCKTIME;
+ }
+
if (!system_get_neigh4gcstaletime(dev, buf, sizeof(buf))) {
s->neigh4gcstaletime = strtoul(buf, NULL, 0);
s->flags |= DEV_OPT_NEIGHGCSTALETIME;
snprintf(buf, sizeof(buf), "%d", s->neigh6reachabletime);
system_set_neigh6reachabletime(dev, buf);
}
+ if (s->flags & DEV_OPT_NEIGHLOCKTIME & apply_mask) {
+ snprintf(buf, sizeof(buf), "%d", s->neigh4locktime);
+ system_set_neigh4locktime(dev, buf);
+ }
if (s->flags & DEV_OPT_NEIGHGCSTALETIME & apply_mask) {
snprintf(buf, sizeof(buf), "%d", s->neigh4gcstaletime);
system_set_neigh4gcstaletime(dev, buf);
rtm.rtm_type == RTN_ANYCAST) {
rtm.rtm_scope = RT_SCOPE_LINK;
} else if (rtm.rtm_type == RTN_BLACKHOLE || rtm.rtm_type == RTN_UNREACHABLE ||
- rtm.rtm_type == RTN_PROHIBIT || rtm.rtm_type == RTN_FAILED_POLICY) {
+ rtm.rtm_type == RTN_PROHIBIT || rtm.rtm_type == RTN_FAILED_POLICY ||
+ rtm.rtm_type == RTN_THROW) {
rtm.rtm_scope = RT_SCOPE_UNIVERSE;
dev = NULL;
}
FILE *f;
char *e, buf[128];
unsigned int n, proto = 256;
-
- if ((n = strtoul(type, &e, 0)) >= 0 && !*e && e != type)
+ n = strtoul(type, &e, 0);
+ if (!*e && e != type)
proto = n;
else if (!strcmp(type, "unspec"))
proto = RTPROT_UNSPEC;
}
}
- if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
- uint8_t icsum, ocsum, iseqno, oseqno;
- if (sscanf(blobmsg_get_string(cur), "%u,%u,%hhu,%hhu,%hhu,%hhu",
- &ikey, &okey, &icsum, &ocsum, &iseqno, &oseqno) < 6) {
- ret = -EINVAL;
- goto failure;
- }
+ if ((cur = tb[TUNNEL_ATTR_DATA])) {
+ struct blob_attr *tb_data[__GRE_DATA_ATTR_MAX];
- if (ikey)
- iflags |= GRE_KEY;
+ blobmsg_parse(gre_data_attr_list.params, __GRE_DATA_ATTR_MAX, tb_data,
+ blobmsg_data(cur), blobmsg_len(cur));
- if (okey)
- oflags |= GRE_KEY;
+ if ((cur = tb_data[GRE_DATA_IKEY])) {
+ if ((ikey = blobmsg_get_u32(cur)))
+ iflags |= GRE_KEY;
+ }
+
+ if ((cur = tb_data[GRE_DATA_OKEY])) {
+ if ((okey = blobmsg_get_u32(cur)))
+ oflags |= GRE_KEY;
+ }
- if (icsum)
- iflags |= GRE_CSUM;
+ if ((cur = tb_data[GRE_DATA_ICSUM])) {
+ if (blobmsg_get_bool(cur))
+ iflags |= GRE_CSUM;
+ }
- if (ocsum)
- oflags |= GRE_CSUM;
+ if ((cur = tb_data[GRE_DATA_OCSUM])) {
+ if (blobmsg_get_bool(cur))
+ oflags |= GRE_CSUM;
+ }
- if (iseqno)
- iflags |= GRE_SEQ;
+ if ((cur = tb_data[GRE_DATA_ISEQNO])) {
+ if (blobmsg_get_bool(cur))
+ iflags |= GRE_SEQ;
+ }
- if (oseqno)
- oflags |= GRE_SEQ;
+ if ((cur = tb[GRE_DATA_OSEQNO])) {
+ if (blobmsg_get_bool(cur))
+ oflags |= GRE_SEQ;
+ }
}
if (v6) {
struct nl_msg *nlm;
struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
struct blob_attr *cur;
- uint32_t ikey = 0, okey = 0;
int ret = 0;
nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
if (link)
nla_put_u32(nlm, IFLA_VTI_LINK, link);
- if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
- if (sscanf(blobmsg_get_string(cur), "%u,%u",
- &ikey, &okey) < 2) {
- ret = -EINVAL;
- goto failure;
- }
- }
-
if (v6) {
struct in6_addr in6buf;
if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
}
- if (okey)
- nla_put_u32(nlm, IFLA_VTI_OKEY, htonl(okey));
+ if ((cur = tb[TUNNEL_ATTR_DATA])) {
+ struct blob_attr *tb_data[__VTI_DATA_ATTR_MAX];
+ uint32_t ikey = 0, okey = 0;
- if (ikey)
- nla_put_u32(nlm, IFLA_VTI_IKEY, htonl(ikey));
+ blobmsg_parse(vti_data_attr_list.params, __VTI_DATA_ATTR_MAX, tb_data,
+ blobmsg_data(cur), blobmsg_len(cur));
+
+ if ((cur = tb_data[VTI_DATA_IKEY])) {
+ if ((ikey = blobmsg_get_u32(cur)))
+ nla_put_u32(nlm, IFLA_VTI_IKEY, htonl(ikey));
+ }
+
+ if ((cur = tb_data[VTI_DATA_OKEY])) {
+ if ((okey = blobmsg_get_u32(cur)))
+ nla_put_u32(nlm, IFLA_VTI_OKEY, htonl(okey));
+ }
+ }
nla_nest_end(nlm, infodata);
nla_nest_end(nlm, linkinfo);
}
#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;
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);
} 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);