diff options
author | John Crispin <john@phrozen.org> | 2020-07-12 18:50:19 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2020-07-18 20:31:16 +0200 |
commit | 82bcb641602579f339e9addafe5f1869134a0cd1 (patch) | |
tree | 6efe05a53645152e7d796d0ea2d132ce4b3ca2bb | |
parent | ccd9ddc10219ae90784411c7774a0d56dbced59b (diff) |
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.h | 6 | ||||
-rw-r--r-- | system-dummy.c | 11 | ||||
-rw-r--r-- | system-linux.c | 47 | ||||
-rw-r--r-- | system.h | 1 |
4 files changed, 65 insertions, 0 deletions
@@ -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; @@ -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); |