bridge: add support for adding vlans to a bridge
authorJohn Crispin <john@phrozen.org>
Sun, 12 Jul 2020 16:50:19 +0000 (18:50 +0200)
committerFelix Fietkau <nbd@nbd.name>
Sat, 18 Jul 2020 18:31:16 +0000 (20:31 +0200)
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>
device.h
system-dummy.c
system-linux.c
system.h

index 5f3fae29355bff33ebc82c7b37dfd1054531b7a3..4fb15a3f4b17c5b124ce5eee650a0145771197a4 100644 (file)
--- 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;
index a4bf05d0095ddc3b505fd450b58330b054bfbff0..aeba9db4e445606d491a4acad72a85173c8d7a0a 100644 (file)
@@ -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);
index 97b38e750c63ba697a3111fd50ee156c4bb96d5f..c5583e079c9b9a3eaabd704bcfe3a959e07bc9bb 100644 (file)
@@ -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;
index 258b1afb47e1b511dcebb5e46c2eca84a9c0827f..015987f285f2f81ce1ca753fcdee32c576ad6c57 100644 (file)
--- 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);