diff --git a/src/confd/src/confd/ietf-interfaces.c b/src/confd/src/confd/ietf-interfaces.c index 15a625cc..9a6dac9c 100644 --- a/src/confd/src/confd/ietf-interfaces.c +++ b/src/confd/src/confd/ietf-interfaces.c @@ -652,6 +652,47 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif, return 0; } +static int netdag_get_bridge_fwd_mask(struct lyd_node *cif) +{ + struct lyd_node *node, *proto; + int fwd_mask = 0; + + node = lydx_get_descendant(lyd_child(cif), "bridge", NULL); + if (!node) + goto fail; + + LYX_LIST_FOR_EACH(lyd_child(node), proto, "ieee-group-forward") { + struct lyd_node_term *leaf = (struct lyd_node_term *)proto; + struct lysc_node_leaf *sleaf = (struct lysc_node_leaf *)leaf->schema; + + if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_UNION)) { + struct lyd_value *actual = &leaf->value.subvalue->value; + int val; + + if (actual->realtype->basetype == LY_TYPE_UINT8) + val = actual->uint8; + else + val = actual->enum_item->value; + + fwd_mask |= 1 << val; + } + } + +fail: + return fwd_mask; +} + +static int netdag_set_bridge(struct dagger *net, struct lyd_node *dif, + struct lyd_node *cif, FILE *ip) +{ + const char *ifname = lydx_get_cattr(cif, "name"); + + fprintf(ip, "link set dev %s type bridge group_fwd_mask %d\n", + ifname, netdag_get_bridge_fwd_mask(cif)); + + return 0; +} + static int netdag_gen_afspec_add(struct dagger *net, struct lyd_node *dif, struct lyd_node *cif, FILE *ip) { @@ -662,7 +703,8 @@ static int netdag_gen_afspec_add(struct dagger *net, struct lyd_node *dif, DEBUG_IFACE(dif, ""); if (!strcmp(iftype, "iana-if-type:bridge")) { - fprintf(ip, "link add dev %s type bridge\n", ifname); + fprintf(ip, "link add dev %s type bridge group_fwd_mask %d\n", + ifname, netdag_get_bridge_fwd_mask(cif)); } else if (!strcmp(iftype, "infix-if-type:veth")) { err = netdag_gen_veth(net, NULL, cif, ip); } else if (!strcmp(iftype, "iana-if-type:l2vlan")) { @@ -687,7 +729,7 @@ static int netdag_gen_afspec_set(struct dagger *net, struct lyd_node *dif, DEBUG_IFACE(dif, ""); if (!strcmp(iftype, "iana-if-type:bridge")) - return 0; + return netdag_set_bridge(net, dif, cif, ip); if (!strcmp(iftype, "iana-if-type:l2vlan")) return netdag_gen_vlan(net, dif, cif, ip); if (!strcmp(iftype, "infix-if-type:veth")) diff --git a/src/confd/yang/infix-if-bridge@2023-05-31.yang b/src/confd/yang/infix-if-bridge@2023-05-31.yang index 756394be..d028e7c4 100644 --- a/src/confd/yang/infix-if-bridge@2023-05-31.yang +++ b/src/confd/yang/infix-if-bridge@2023-05-31.yang @@ -31,6 +31,38 @@ submodule infix-if-bridge { description "Indicates if this bridge supports VLAN filtering."; } + /* + * Typedefs + */ + typedef ieee-reserved-groups { + type union { + type uint8 { + range "0..15"; + } + type enumeration { + enum stp { + value 0; + description "Spanning Tree (STP/RSPT/MSTP)."; + } + enum lacp { + value 2; + description "802.3 Slow Protocols, e.g., LACP."; + } + enum dot1x { + value 3; + description "802.1X Port-Based Network Access Control."; + } + enum lldp { + value 14; + description "802.1AB Link Layer Discovery Protocol (LLDP)."; + } + } + } + description + "This is a user-friendly enumeration of the different reserved IEEE + reserved link-local multicast groups, in 01:80:C2:00:00:0X."; + } + /* * Data Nodes */ @@ -45,6 +77,12 @@ submodule infix-if-bridge { container bridge { description "IEEE 802.1Q style bridge."; + leaf-list ieee-group-forward { + type ieee-reserved-groups; + description + "List of IEEE link-local protocols to forward, e.g., STP, LLDP"; + } + container vlans { if-feature "vlan-filtering"; description "A VLAN filtering bridge has at least one VLAN.";