confd: handle small changes to bridge port properties

This patch adds support for small incremental changes to bridge ports.
Changes where the libyang diff does not include a bridge reference so
that it will have to be synthesized from the current configuration.

For example, forgetting to set a port's PVID in a VLAN filtering bridge
setup, changing a bridge port's multicast flooding properties, or any
other per-bridge-port setting after the fact.

Fixes #349.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-03-22 13:15:35 +01:00
committed by Tobias Waldekranz
parent ce2e15e4d2
commit 3ebbd0bf4f
+88 -5
View File
@@ -745,6 +745,57 @@ static int netdag_gen_ethtool(struct dagger *net, struct lyd_node *cif, struct l
return 0;
}
static void brport_pvid_adjust(FILE *br, struct lyd_node *vlan, int vid, const char *brport,
struct lydx_diff *pvidiff, int tagged)
{
const char *type = tagged ? "tagged" : "untagged";
struct lyd_node *port;
LYX_LIST_FOR_EACH(lyd_child(vlan), port, type) {
if (strcmp(brport, lyd_get_value(port)))
continue;
if (pvidiff->old && atoi(pvidiff->old) == vid)
fprintf(br, "vlan add vid %d dev %s %s\n", vid, brport, type);
if (pvidiff->new && atoi(pvidiff->new) == vid)
fprintf(br, "vlan add vid %d dev %s pvid %s\n", vid, brport, type);
}
}
/*
* Called when only pvid is changed for a bridge-port. Then we use the
* cif data to iterate over all known VLANS for the given port.
*/
static int bridge_port_vlans(struct dagger *net, struct lyd_node *cif, const char *brname,
const char *brport, struct lydx_diff *pvidiff)
{
struct lyd_node *bridge = lydx_find_by_name(lyd_parent(cif), "interface", brname);
struct lyd_node *vlan, *vlans;
int err = 0;
FILE *br;
vlans = lydx_get_descendant(lyd_child(bridge), "bridge", "vlans", NULL);
if (!vlans)
goto done;
br = dagger_fopen_next(net, "init", brname, 60, "init.bridge");
if (!br) {
err = -EIO;
goto done;
}
LYX_LIST_FOR_EACH(lyd_child(vlans), vlan, "vlan") {
int vid = atoi(lydx_get_cattr(vlan, "vid"));
brport_pvid_adjust(br, vlan, vid, brport, pvidiff, 0);
brport_pvid_adjust(br, vlan, vid, brport, pvidiff, 1);
}
fclose(br);
done:
return err;
}
static int bridge_diff_vlan_port(struct dagger *net, FILE *br, const char *brname, int vid,
const char *brport, int tagged, enum lydx_op op)
{
@@ -877,20 +928,52 @@ static void bridge_port_settings(FILE *next, const char *ifname, struct lyd_node
static int bridge_gen_ports(struct dagger *net, struct lyd_node *dif, struct lyd_node *cif, FILE *ip)
{
const char *ifname = lydx_get_cattr(cif, "name");
struct lyd_node *node, *bridge;
struct lydx_diff brdiff;
const char *ifname;
int err = 0;
if (!is_bridge_port(cif))
return 0;
node = lydx_get_descendant(lyd_child(dif), "bridge-port", NULL);
bridge = lydx_get_child(node, "bridge");
if (!node || !bridge)
return 0; /* bridge port but no diff, skip */
if (!node)
goto fail;
ifname = lydx_get_cattr(cif, "name");
/*
* If bridge is not in dif, then we only have bridge-port
* settings and can use cif instead for any new settings
* since we always set *all* port settings anyway.
*/
bridge = lydx_get_child(node, "bridge");
if (!bridge) {
struct lyd_node *pvid = lydx_get_child(node, "pvid");
struct lydx_diff pvidiff;
const char *brname;
FILE *next;
node = lydx_get_descendant(lyd_child(cif), "bridge-port", NULL);
brname = lydx_get_cattr(node, "bridge");
if (!node || !brname)
goto fail;
next = dagger_fopen_next(net, "init", ifname, 56, "init.ip");
if (!next) {
err = -EIO;
goto fail;
}
bridge_port_settings(next, ifname, cif);
fclose(next);
/* Change in bridge port's PVID => change in VLAN port memberships */
if (lydx_get_diff(pvid, &pvidiff))
bridge_port_vlans(net, cif, brname, ifname, &pvidiff);
err = dagger_add_dep(net, brname, ifname);
if (err)
return ERR_IFACE(cif, err, "Unable to add dep \"%s\" to %s", ifname, brdiff);
goto fail;
}
if (lydx_get_diff(bridge, &brdiff) && brdiff.old) {
FILE *prev;