#include <net/if.h>
#include <net/if_arp.h>
+#include <limits.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include "netifd.h"
#include "device.h"
#include "system.h"
+#include "utils.h"
struct event_socket {
struct uloop_fd uloop;
system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val);
}
+static void system_bridge_set_vlan_filtering(struct device *dev, const char *val)
+{
+ system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/vlan_filtering", dev->ifname, val);
+}
+
static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
{
int fd = -1, ret = -1;
if (!system_get_dev_sysctl("/sys/class/net/%s/carrier", dev->ifname, buf, sizeof(buf)))
link_state = strtoul(buf, NULL, 0);
+ if (dev->type == &simple_device_type && !system_if_force_external(dev->ifname))
+ device_set_present(dev, true);
+
device_set_link(dev, link_state ? true : false);
out:
move:
dev = device_find(interface_old);
if (!dev)
- goto found;
+ return;
if (dev->type != &simple_device_type)
goto found;
device_set_present(dev, false);
+ return;
+
found:
dev = device_find(interface);
if (!dev)
return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
}
+int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int vflags)
+{
+ struct ifinfomsg ifi = { .ifi_family = PF_BRIDGE, };
+ struct bridge_vlan_info vinfo = { .vid = vid, };
+ unsigned short flags = 0;
+ struct nlattr *afspec;
+ struct nl_msg *nlm;
+ int ret = 0;
+
+ ifi.ifi_index = if_nametoindex(iface);
+ if (!ifi.ifi_index)
+ return -1;
+
+ nlm = nlmsg_alloc_simple(add ? RTM_SETLINK : RTM_DELLINK, NLM_F_REQUEST);
+ if (!nlm)
+ return -1;
+
+ nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
+
+ if (vflags & BRVLAN_F_SELF)
+ flags |= BRIDGE_FLAGS_SELF;
+
+ if (vflags & BRVLAN_F_PVID)
+ vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
+
+ if (vflags & BRVLAN_F_UNTAGGED)
+ vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+
+ afspec = nla_nest_start(nlm, IFLA_AF_SPEC);
+ if (!afspec) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ if (flags)
+ nla_put_u16(nlm, IFLA_BRIDGE_FLAGS, flags);
+
+ nla_put(nlm, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo);
+ nla_nest_end(nlm, afspec);
+
+ return system_rtnl_call(nlm);
+
+failure:
+ nlmsg_free(nlm);
+ return ret;
+}
+
int system_if_resolve(struct device *dev)
{
struct ifreq ifr;
system_bridge_set_forward_delay(bridge, buf);
system_bridge_conf_multicast(bridge, cfg, buf, sizeof(buf));
+ system_bridge_set_vlan_filtering(bridge, cfg->vlan_filtering ? "1" : "0");
snprintf(buf, sizeof(buf), "%d", cfg->priority);
system_bridge_set_priority(bridge, buf);
return -ENOMEM;
}
-int system_link_netns_move(const char *ifname, int netns_fd)
+int system_link_netns_move(struct device *dev, int netns_fd, const char *target_ifname)
{
struct nl_msg *msg;
struct ifinfomsg iim = {
.ifi_family = AF_UNSPEC,
- .ifi_index = 0,
};
+ if (!dev)
+ return -1;
+
+ iim.ifi_index = system_if_resolve(dev);
msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST);
if (!msg)
return -1;
nlmsg_append(msg, &iim, sizeof(iim), 0);
- nla_put_string(msg, IFLA_IFNAME, ifname);
+ if (target_ifname)
+ nla_put_string(msg, IFLA_IFNAME, target_ifname);
+
nla_put_u32(msg, IFLA_NET_NS_FD, netns_fd);
return system_rtnl_call(msg);
}
int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg)
{
struct nl_msg *msg;
- struct nlattr *linkinfo, *data;
+ struct nlattr *linkinfo, *data, *qos;
struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
+ struct vlan_qos_mapping *elem;
+ struct ifla_vlan_qos_mapping nl_qos_map;
int rv;
msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
netifd_log_message(L_WARNING, "%s Your kernel is older than linux 3.10.0, 802.1ad is not supported defaulting to 802.1q", vlandev->type->name);
#endif
+ if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
+ goto nla_put_failure;
+
+ vlist_simple_for_each_element(&cfg->ingress_qos_mapping_list, elem, node) {
+ nl_qos_map.from = elem->from;
+ nl_qos_map.to = elem->to;
+ nla_put(msg, IFLA_VLAN_QOS_MAPPING, sizeof(nl_qos_map), &nl_qos_map);
+ }
+ nla_nest_end(msg, qos);
+
+ if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
+ goto nla_put_failure;
+
+ vlist_simple_for_each_element(&cfg->egress_qos_mapping_list, elem, node) {
+ nl_qos_map.from = elem->from;
+ nl_qos_map.to = elem->to;
+ nla_put(msg, IFLA_VLAN_QOS_MAPPING, sizeof(nl_qos_map), &nl_qos_map);
+ }
+ nla_nest_end(msg, qos);
+
nla_nest_end(msg, data);
nla_nest_end(msg, linkinfo);
}
nla_put_u16(msg, IFLA_VXLAN_PORT, htons(port));
+ if ((cur = tb_data[VXLAN_DATA_ATTR_SRCPORTMIN])) {
+ struct ifla_vxlan_port_range srcports = {0,0};
+
+ uint32_t low = blobmsg_get_u32(cur);
+ if (low < 1 || low > 65535 - 1) {
+ ret = -EINVAL;
+ goto failure;
+ }
+
+ srcports.low = htons((uint16_t) low);
+ srcports.high = htons((uint16_t) (low+1));
+
+ if ((cur = tb_data[VXLAN_DATA_ATTR_SRCPORTMAX])) {
+ uint32_t high = blobmsg_get_u32(cur);
+ if (high < 1 || high > 65535) {
+ ret = -EINVAL;
+ goto failure;
+ }
+
+ if (high > low)
+ srcports.high = htons((uint16_t) high);
+ }
+
+ nla_put(msg, IFLA_VXLAN_PORT_RANGE, sizeof(srcports), &srcports);
+ }
+
if ((cur = tb_data[VXLAN_DATA_ATTR_RXCSUM])) {
bool rxcsum = blobmsg_get_bool(cur);
nla_put_u8(msg, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, !rxcsum);