diff options
author | Felix Fietkau <nbd@nbd.name> | 2021-06-04 09:05:31 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2021-06-04 09:05:33 +0200 |
commit | 50381d0a2998f6c0fc4823f0c2aa4206063d549e (patch) | |
tree | e22f15cc925923c12a741a41e4fa289270c3a547 | |
parent | 7f199050f395d5295a3f665bcd2eb8cc755d08aa (diff) | |
download | netifd-50381d0a2998f6c0fc4823f0c2aa4206063d549e.tar.gz |
bridge: allow adding/removing VLANs to configured member ports via hotplug
This is useful for a dynamic VLAN setup, where extra tags need to be created
on the trunking port on demand
Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r-- | bridge.c | 54 | ||||
-rw-r--r-- | device.h | 2 | ||||
-rw-r--r-- | extdev.c | 2 | ||||
-rw-r--r-- | interface.c | 7 | ||||
-rw-r--r-- | vlan.c | 21 | ||||
-rw-r--r-- | vlandev.c | 21 |
6 files changed, 80 insertions, 27 deletions
@@ -706,8 +706,21 @@ bridge_hotplug_get_vlan(struct bridge_state *bst, unsigned int vid) return vlan; } +static struct bridge_vlan_hotplug_port * +bridge_hotplug_get_vlan_port(struct bridge_vlan *vlan, const char *ifname) +{ + struct bridge_vlan_hotplug_port *port; + + list_for_each_entry(port, &vlan->hotplug_ports, list) + if (!strcmp(port->port.ifname, ifname)) + return port; + + return NULL; +} + static void -bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *vlans, const char *ifname) +bridge_hotplug_set_member_vlans(struct bridge_state *bst, struct blob_attr *vlans, + const char *ifname, struct bridge_member *bm, bool add) { struct bridge_vlan *vlan; struct blob_attr *cur; @@ -750,6 +763,27 @@ bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *v } } + port = bridge_hotplug_get_vlan_port(vlan, ifname); + if (!add) { + if (!port) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, false); + list_del(&port->list); + free(port); + continue; + } + + if (port) { + if (port->port.flags == flags) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, false); + port->port.flags = flags; + __bridge_set_member_vlan(bm, vlan, &port->port, true); + continue; + } + port = calloc_a(sizeof(*port), &name_buf, strlen(ifname) + 1); if (!port) continue; @@ -757,6 +791,11 @@ bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *v port->port.flags = flags; port->port.ifname = strcpy(name_buf, ifname); list_add_tail(&port->list, &vlan->hotplug_ports); + + if (!bm) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, true); } } @@ -764,15 +803,18 @@ static int bridge_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) { struct bridge_state *bst = container_of(dev, struct bridge_state, dev); + struct bridge_member *bm; - bridge_hotplug_create_member_vlans(bst, vlan, member->ifname); - bridge_create_member(bst, member->ifname, member, true); + bm = vlist_find(&bst->members, member->ifname, bm, node); + bridge_hotplug_set_member_vlans(bst, vlan, member->ifname, bm, true); + if (!bm) + bridge_create_member(bst, member->ifname, member, true); return 0; } static int -bridge_hotplug_del(struct device *dev, struct device *member) +bridge_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) { struct bridge_state *bst = container_of(dev, struct bridge_state, dev); struct bridge_member *bm; @@ -781,6 +823,10 @@ bridge_hotplug_del(struct device *dev, struct device *member) if (!bm) return UBUS_STATUS_NOT_FOUND; + bridge_hotplug_set_member_vlans(bst, vlan, member->ifname, bm, false); + if (!bm->dev.hotplug) + return 0; + vlist_delete(&bst->members, &bm->node); return 0; } @@ -253,7 +253,7 @@ struct device { struct device_hotplug_ops { int (*prepare)(struct device *dev, struct device **bridge_dev); int (*add)(struct device *main, struct device *member, struct blob_attr *vlan); - int (*del)(struct device *main, struct device *member); + int (*del)(struct device *main, struct device *member, struct blob_attr *vlan); }; enum bridge_vlan_flags { @@ -643,7 +643,7 @@ extdev_hotplug_add(struct device *ebr_dev, struct device *ebm_dev, struct blob_a } static int -extdev_hotplug_remove(struct device *dev, struct device *member) +extdev_hotplug_remove(struct device *dev, struct device *member, struct blob_attr *vlan) { struct extdev_bridge *ebr; struct extdev_bridge_member *ubm; diff --git a/interface.c b/interface.c index 1d1a5f8..2391e12 100644 --- a/interface.c +++ b/interface.c @@ -1034,12 +1034,13 @@ interface_set_main_dev(struct interface *iface, struct device *dev) } static int -interface_remove_link(struct interface *iface, struct device *dev) +interface_remove_link(struct interface *iface, struct device *dev, + struct blob_attr *vlan) { struct device *mdev = iface->main_dev.dev; if (mdev && mdev->hotplug_ops) - return mdev->hotplug_ops->del(mdev, dev); + return mdev->hotplug_ops->del(mdev, dev, vlan); if (dev == iface->ext_dev.dev) device_remove_user(&iface->ext_dev); @@ -1103,7 +1104,7 @@ interface_handle_link(struct interface *iface, const char *name, ret = interface_add_link(iface, dev, vlan, link_ext); } else { - ret = interface_remove_link(iface, dev); + ret = interface_remove_link(iface, dev, vlan); } out: @@ -39,7 +39,7 @@ static void free_vlan_if(struct device *iface) } static int -vlan_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) +__vlan_hotplug_op(struct device *dev, struct device *member, struct blob_attr *vlan, bool add) { struct vlan_device *vldev = container_of(dev, struct vlan_device, dev); void *a; @@ -53,19 +53,22 @@ vlan_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vl blobmsg_printf(&b, NULL, "%d", vldev->id); blobmsg_close_array(&b, a); - return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); + if (add) + return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); + else + return dev->hotplug_ops->del(dev, member, blobmsg_data(b.head)); } static int -vlan_hotplug_del(struct device *dev, struct device *member) +vlan_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) { - struct vlan_device *vldev = container_of(dev, struct vlan_device, dev); - - dev = vldev->dep.dev; - if (!dev || !dev->hotplug_ops) - return UBUS_STATUS_NOT_SUPPORTED; + return __vlan_hotplug_op(dev, member, vlan, true); +} - return dev->hotplug_ops->del(dev, member); +static int +vlan_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) +{ + return __vlan_hotplug_op(dev, member, vlan, false); } static int @@ -61,7 +61,7 @@ struct vlandev_device { }; static int -vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) +__vlandev_hotplug_op(struct device *dev, struct device *member, struct blob_attr *vlan, bool add) { struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev); void *a; @@ -75,19 +75,22 @@ vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr blobmsg_printf(&b, NULL, "%d", mvdev->config.vid); blobmsg_close_array(&b, a); - return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); + if (add) + return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); + else + return dev->hotplug_ops->del(dev, member, blobmsg_data(b.head)); } static int -vlandev_hotplug_del(struct device *dev, struct device *member) +vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) { - struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev); - - dev = mvdev->parent.dev; - if (!dev || !dev->hotplug_ops) - return UBUS_STATUS_NOT_SUPPORTED; + return __vlandev_hotplug_op(dev, member, vlan, true); +} - return dev->hotplug_ops->del(dev, member); +static int +vlandev_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) +{ + return __vlandev_hotplug_op(dev, member, vlan, false); } static int |