#include <linux/ip6_tunnel.h>
#include <linux/ethtool.h>
#include <linux/fib_rules.h>
+#include <linux/veth.h>
#include <linux/version.h>
#ifndef RTN_FAILED_POLICY
#define IFA_FLAGS (IFA_MULTICAST + 1)
#endif
-
#include <string.h>
#include <fcntl.h>
#include <glob.h>
static bool
create_raw_event_socket(struct event_socket *ev, int protocol, int groups,
- uloop_fd_handler cb, int flags)
+ uloop_fd_handler cb, int flags)
{
ev->sock = create_socket(protocol, groups);
if (!ev->sock)
return -1;
if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1,
- handle_hotplug_event, 0))
+ handle_hotplug_event, 0))
return -1;
// Receive network link events form kernel
system_set_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms", dev->ifname, val);
}
+static void system_set_neigh4gcstaletime(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/gc_stale_time", dev->ifname, val);
+}
+
+static void system_set_neigh6gcstaletime(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/gc_stale_time", 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);
system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val);
}
+static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_fast_leave", dev->ifname, val);
+}
+
static void system_bridge_set_hairpin_mode(struct device *dev, const char *val)
{
system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, val);
dev->ifname, val);
}
+static void system_bridge_set_learning(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/sys/class/net/%s/brport/learning", dev->ifname, val);
+}
+
+static void system_bridge_set_unicast_flood(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/sys/class/net/%s/brport/unicast_flood", dev->ifname, val);
+}
+
+static void system_set_sendredirects(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val);
+}
+
static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
{
int fd = -1, ret = -1;
dev->ifname, buf, buf_sz);
}
+static int system_get_neigh4gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("/proc/sys/net/ipv4/neigh/%s/gc_stale_time",
+ dev->ifname, buf, buf_sz);
+}
+
+static int system_get_neigh6gcstaletime(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("/proc/sys/net/ipv6/neigh/%s/gc_stale_time",
+ 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",
dev->ifname, buf, buf_sz);
}
+static int system_get_sendredirects(struct device *dev, char *buf, const size_t buf_sz)
+{
+ return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects",
+ dev->ifname, buf, buf_sz);
+}
+
// Evaluate netlink messages
static int cb_rtnl_event(struct nl_msg *msg, void *arg)
{
if (!nla[IFLA_IFNAME])
goto out;
- struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
+ struct device *dev = device_find(nla_data(nla[IFLA_IFNAME]));
if (!dev)
goto out;
return;
found:
- dev = device_get(interface, false);
+ dev = device_find(interface);
if (!dev)
return;
system_bridge_set_multicast_router(dev, buf, false);
}
+ if (dev->settings.flags & DEV_OPT_MULTICAST_FAST_LEAVE &&
+ dev->settings.multicast_fast_leave)
+ system_bridge_set_multicast_fast_leave(dev, "1");
+
+ if (dev->settings.flags & DEV_OPT_LEARNING &&
+ !dev->settings.learning)
+ system_bridge_set_learning(dev, "0");
+
+ if (dev->settings.flags & DEV_OPT_UNICAST_FLOOD &&
+ !dev->settings.unicast_flood)
+ system_bridge_set_unicast_flood(dev, "0");
+
return ret;
}
return system_link_del(macvlan->ifname);
}
+int system_veth_add(struct device *veth, struct veth_config *cfg)
+{
+ struct nl_msg *msg;
+ struct ifinfomsg empty_iim = {};
+ struct nlattr *linkinfo, *data, *veth_info;
+ int rv;
+
+ msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+
+ if (!msg)
+ return -1;
+
+ nlmsg_append(msg, &empty_iim, sizeof(empty_iim), 0);
+
+ if (cfg->flags & VETH_OPT_MACADDR)
+ nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
+ nla_put_string(msg, IFLA_IFNAME, veth->ifname);
+
+ if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ nla_put_string(msg, IFLA_INFO_KIND, "veth");
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (!(veth_info = nla_nest_start(msg, VETH_INFO_PEER)))
+ goto nla_put_failure;
+
+ nlmsg_append(msg, &empty_iim, sizeof(empty_iim), 0);
+
+ if (cfg->flags & VETH_OPT_PEER_NAME)
+ nla_put_string(msg, IFLA_IFNAME, cfg->peer_name);
+ if (cfg->flags & VETH_OPT_PEER_MACADDR)
+ nla_put(msg, IFLA_ADDRESS, sizeof(cfg->peer_macaddr), cfg->peer_macaddr);
+
+ nla_nest_end(msg, veth_info);
+ nla_nest_end(msg, data);
+ nla_nest_end(msg, linkinfo);
+
+ rv = system_rtnl_call(msg);
+ if (rv) {
+ if (cfg->flags & VETH_OPT_PEER_NAME)
+ D(SYSTEM, "Error adding veth '%s' with peer '%s': %d\n", veth->ifname, cfg->peer_name, rv);
+ else
+ D(SYSTEM, "Error adding veth '%s': %d\n", veth->ifname, rv);
+ }
+
+ return rv;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOMEM;
+}
+
+int system_veth_del(struct device *veth)
+{
+ return system_link_del(veth->ifname);
+}
+
static int system_vlan(struct device *dev, int id)
{
struct vlan_ioctl_args ifr = {
nlmsg_append(msg, &iim, sizeof(iim), 0);
nla_put_string(msg, IFLA_IFNAME, vlandev->ifname);
nla_put_u32(msg, IFLA_LINK, dev->ifindex);
-
+
if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
goto nla_put_failure;
-
+
nla_put_string(msg, IFLA_INFO_KIND, "vlan");
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
s->flags |= DEV_OPT_NEIGHREACHABLETIME;
}
+ if (!system_get_neigh4gcstaletime(dev, buf, sizeof(buf))) {
+ s->neigh4gcstaletime = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_NEIGHGCSTALETIME;
+ }
+
+ if (!system_get_neigh6gcstaletime(dev, buf, sizeof(buf))) {
+ s->neigh6gcstaletime = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_NEIGHGCSTALETIME;
+ }
+
if (!system_get_dadtransmits(dev, buf, sizeof(buf))) {
s->dadtransmits = strtoul(buf, NULL, 0);
s->flags |= DEV_OPT_DADTRANSMITS;
}
+
+ if (!system_get_sendredirects(dev, buf, sizeof(buf))) {
+ s->sendredirects = strtoul(buf, NULL, 0);
+ s->flags |= DEV_OPT_SENDREDIRECTS;
+ }
}
static void
snprintf(buf, sizeof(buf), "%d", s->neigh6reachabletime);
system_set_neigh6reachabletime(dev, buf);
}
+ if (s->flags & DEV_OPT_NEIGHGCSTALETIME & apply_mask) {
+ snprintf(buf, sizeof(buf), "%d", s->neigh4gcstaletime);
+ system_set_neigh4gcstaletime(dev, buf);
+ snprintf(buf, sizeof(buf), "%d", s->neigh6gcstaletime);
+ system_set_neigh6gcstaletime(dev, buf);
+ }
if (s->flags & DEV_OPT_DADTRANSMITS & apply_mask) {
snprintf(buf, sizeof(buf), "%d", s->dadtransmits);
system_set_dadtransmits(dev, buf);
!s->multicast ? IFF_MULTICAST : 0) < 0)
s->flags &= ~DEV_OPT_MULTICAST;
}
+ if (s->flags & DEV_OPT_SENDREDIRECTS & apply_mask)
+ system_set_sendredirects(dev, s->sendredirects ? "1" : "0");
system_if_apply_rps_xps(dev, s);
}
.rtm_dst_len = route->mask,
.rtm_src_len = route->sourcemask,
.rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC,
- .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC,
+ .rtm_protocol = (route->flags & DEVROUTE_PROTO) ? route->proto : RTPROT_STATIC,
.rtm_scope = RT_SCOPE_NOWHERE,
.rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST,
.rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0,
return system_rtn_aton(type, id);
}
+bool system_resolve_rt_proto(const char *type, unsigned int *id)
+{
+ FILE *f;
+ char *e, buf[128];
+ unsigned int n, proto = 256;
+
+ if ((n = strtoul(type, &e, 0)) >= 0 && !*e && e != type)
+ proto = n;
+ else if (!strcmp(type, "unspec"))
+ proto = RTPROT_UNSPEC;
+ else if (!strcmp(type, "kernel"))
+ proto = RTPROT_KERNEL;
+ else if (!strcmp(type, "boot"))
+ proto = RTPROT_BOOT;
+ else if (!strcmp(type, "static"))
+ proto = RTPROT_STATIC;
+ else if ((f = fopen("/etc/iproute2/rt_protos", "r")) != NULL) {
+ while (fgets(buf, sizeof(buf) - 1, f) != NULL) {
+ if ((e = strtok(buf, " \t\n")) == NULL || *e == '#')
+ continue;
+
+ n = strtoul(e, NULL, 10);
+ e = strtok(NULL, " \t\n");
+
+ if (e && !strcmp(e, type)) {
+ proto = n;
+ break;
+ }
+ }
+ fclose(f);
+ }
+
+ if (proto > 255)
+ return false;
+
+ *id = proto;
+ return true;
+}
+
bool system_resolve_rt_table(const char *name, unsigned int *id)
{
FILE *f;
uint32_t ikey = 0, okey = 0, flags = 0, flowinfo = 0;
uint16_t iflags = 0, oflags = 0;
uint8_t tos = 0;
- int ret = 0, ttl = 64;
+ int ret = 0, ttl = 0;
nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
if (!nlm)
if ((cur = tb[TUNNEL_ATTR_TTL]))
ttl = blobmsg_get_u32(cur);
- nla_put_u8(nlm, IFLA_GRE_TTL, ttl);
-
if ((cur = tb[TUNNEL_ATTR_TOS])) {
char *str = blobmsg_get_string(cur);
if (strcmp(str, "inherit")) {
else
tos = 1;
}
- }
+ }
if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
uint8_t icsum, ocsum, iseqno, oseqno;
if (flags)
nla_put_u32(nlm, IFLA_GRE_FLAGS, flags);
+
+ if (!ttl)
+ ttl = 64;
} else {
struct in_addr inbuf;
bool set_df = true;
if ((cur = tb[TUNNEL_ATTR_DF]))
set_df = blobmsg_get_bool(cur);
- /* ttl !=0 and nopmtudisc are incompatible */
- if (ttl && !set_df) {
- ret = -EINVAL;
- goto failure;
- }
+ if (!set_df) {
+ /* ttl != 0 and nopmtudisc are incompatible */
+ if (ttl) {
+ ret = -EINVAL;
+ goto failure;
+ }
+ } else if (!ttl)
+ ttl = 64;
nla_put_u8(nlm, IFLA_GRE_PMTUDISC, set_df ? 1 : 0);
nla_put_u8(nlm, IFLA_GRE_TOS, tos);
}
+ if (ttl)
+ nla_put_u8(nlm, IFLA_GRE_TTL, ttl);
+
if (oflags)
nla_put_u16(nlm, IFLA_GRE_OFLAGS, oflags);
struct blob_attr *cur;
bool set_df = true;
struct ip_tunnel_parm p = {
- .link = link,
+ .link = link,
.iph = {
.version = 4,
.ihl = 5,
{
int ret = -1;
char buf[64];
+ int fd;
+
snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu",
dev->ifname);
- int fd = open(buf, O_RDWR);
+ fd = open(buf, O_RDWR);
+ if (fd < 0)
+ return ret;
if (!mtu) {
ssize_t len = read(fd, buf, sizeof(buf) - 1);