summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Crispin <john@phrozen.org>2020-07-12 18:50:19 +0200
committerFelix Fietkau <nbd@nbd.name>2020-07-18 20:31:16 +0200
commit82bcb641602579f339e9addafe5f1869134a0cd1 (patch)
tree6efe05a53645152e7d796d0ea2d132ce4b3ca2bb
parentccd9ddc10219ae90784411c7774a0d56dbced59b (diff)
downloadnetifd-82bcb641602579f339e9addafe5f1869134a0cd1.tar.gz
bridge: add support for adding vlans to a bridge
Add a rtnl helper for adding vlans to a bridge interface. Signed-off-by: John Crispin <john@phrozen.org> Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--device.h6
-rw-r--r--system-dummy.c11
-rw-r--r--system-linux.c47
-rw-r--r--system.h1
4 files changed, 65 insertions, 0 deletions
diff --git a/device.h b/device.h
index 5f3fae2..4fb15a3 100644
--- a/device.h
+++ b/device.h
@@ -228,6 +228,12 @@ struct device_hotplug_ops {
int (*del)(struct device *main, struct device *member);
};
+enum bridge_vlan_flags {
+ BRVLAN_F_SELF = (1 << 0),
+ BRVLAN_F_PVID = (1 << 1),
+ BRVLAN_F_UNTAGGED = (1 << 2),
+};
+
extern const struct uci_blob_param_list device_attr_list;
extern struct device_type simple_device_type;
extern struct device_type tunnel_device_type;
diff --git a/system-dummy.c b/system-dummy.c
index a4bf05d..aeba9db 100644
--- a/system-dummy.c
+++ b/system-dummy.c
@@ -55,6 +55,17 @@ int system_bridge_delif(struct device *bridge, struct device *dev)
return 0;
}
+int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int vflags)
+{
+ D(SYSTEM, "brctl vlan %s %s %s vid=%d pvid=%d untag=%d\n",
+ add ? "add" : "remove",
+ (vflags & BRVLAN_F_SELF) ? "self" : "master",
+ iface, vid,
+ !!(vflags & BRVLAN_F_PVID),
+ !!(vflags & BRVLAN_F_UNTAGGED));
+ return 0;
+}
+
int system_link_netns_move(struct device *dev, int netns_fd, const char *target_ifname)
{
D(SYSTEM, "ip link set %s name %s netns %d\n", dev->ifname, target_ifname, netns_fd);
diff --git a/system-linux.c b/system-linux.c
index 97b38e7..c5583e0 100644
--- a/system-linux.c
+++ b/system-linux.c
@@ -854,6 +854,53 @@ int system_bridge_delif(struct device *bridge, struct device *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;
diff --git a/system.h b/system.h
index 258b1af..015987f 100644
--- a/system.h
+++ b/system.h
@@ -196,6 +196,7 @@ int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg);
int system_bridge_delbr(struct device *bridge);
int system_bridge_addif(struct device *bridge, struct device *dev);
int system_bridge_delif(struct device *bridge, struct device *dev);
+int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int vflags);
int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg);
int system_macvlan_del(struct device *macvlan);