From 86304e26569770f4b1b12f605828debe1969b8cb Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sun, 11 Jun 2023 19:04:22 +0200 Subject: [PATCH] confd: rudimentary support for Linux bridges Very limited, only TPMR-style bridge, no VLAN filtering support yet. Signed-off-by: Joachim Wiberg --- src/confd/src/confd/ietf-interfaces.c | 29 +++++ .../yang/infix-if-bridge@2023-05-31.yang | 114 ++++++++++++++++++ .../yang/infix-interfaces@2023-06-05.yang | 1 + 3 files changed, 144 insertions(+) create mode 100644 src/confd/yang/infix-if-bridge@2023-05-31.yang diff --git a/src/confd/src/confd/ietf-interfaces.c b/src/confd/src/confd/ietf-interfaces.c index 72dd9af6..555ff42e 100644 --- a/src/confd/src/confd/ietf-interfaces.c +++ b/src/confd/src/confd/ietf-interfaces.c @@ -677,6 +677,8 @@ 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; if (!strcmp(iftype, "iana-if-type:l2vlan")) return netdag_gen_vlan(net, dif, cif, ip); if (!strcmp(iftype, "infix-if-type:veth")) @@ -686,10 +688,33 @@ static int netdag_gen_afspec_set(struct dagger *net, struct lyd_node *dif, return -ENOSYS; } +static int netdag_bridge_links(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; + int err = 0; + + node = lydx_get_descendant(lyd_child(cif), "bridge-port", NULL); + if (node) { + const char *brname = lydx_get_cattr(node, "bridge"); + + fprintf(ip, " master %s", brname); + + err = dagger_add_dep(net, ifname, brname); + if (err) + return ERR_IFACE(cif, err, "Unable to add dep \"%s\" to %s", brname, ifname); + } + + return err; +} + static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif) { const char *iftype = lydx_get_cattr(cif, "type"); + if (!strcmp(iftype, "iana-if-type:bridge")) + return 0; if (!strcmp(iftype, "iana-if-type:l2vlan")) return lydx_get_cattr(dif, "parent-interface") || lydx_get_descendant(lyd_child(dif), @@ -789,6 +814,10 @@ static sr_error_t netdag_gen_iface(struct dagger *net, if (err) goto err_close_ip; + err = netdag_bridge_links(net, dif, cif, ip); + if (err) + goto err_close_ip; + fputc('\n', ip); /* Set type specific attributes */ diff --git a/src/confd/yang/infix-if-bridge@2023-05-31.yang b/src/confd/yang/infix-if-bridge@2023-05-31.yang new file mode 100644 index 00000000..756394be --- /dev/null +++ b/src/confd/yang/infix-if-bridge@2023-05-31.yang @@ -0,0 +1,114 @@ +submodule infix-if-bridge { + yang-version 1.1; + belongs-to infix-interfaces { + prefix infix-if; + } + + import iana-if-type { + prefix ianaift; + } + import ietf-interfaces { + prefix if; + } + import ieee802-dot1q-types { + prefix dot1q-types; + } + + organization "KernelKit"; + contact "kernelkit@googlegroups.com"; + description "Linux bridge extension for ietf-interfaces."; + + revision 2023-05-31 { + description "Initial revision."; + reference "internal"; + } + + /* + * Features + */ + + feature vlan-filtering { + description "Indicates if this bridge supports VLAN filtering."; + } + + /* + * Data Nodes + */ + + augment "/if:interfaces/if:interface" { + when "derived-from-or-self(if:type,'ianaift:bridge')" { + description "Only shown for if:type bridge"; + } + + description "Augment generic interfaces with a basic 802.1Q bridge."; + + container bridge { + description "IEEE 802.1Q style bridge."; + + container vlans { + if-feature "vlan-filtering"; + description "A VLAN filtering bridge has at least one VLAN."; + + list vlan { + key "vid"; + description "List of VLANs associated with the Bridge."; + + leaf vid { + type dot1q-types:vlanid; + description "The VLAN identifier to which this entry applies."; + } + + leaf-list untagged-ports { + type if:interface-ref; + description "The set of ports in the untagged set for VLAN."; + } + + leaf-list tagged-ports { + type if:interface-ref; + description "The set of ports in the tagged set for VLAN."; + } + } + } + } + } + + augment "/if:interfaces/if:interface/infix-if:port" { + when "derived-from-or-self(if:type,'ianaift:bridge') or "+ + "derived-from-or-self(if:type,'ianaift:ethernetCsmacd') or "+ + "derived-from-or-self(if:type,'ianaift:ieee8023adLag') or "+ + "derived-from-or-self(if:type,'ianaift:ilan')" { + description "Applies when a Bridge interface exists."; + } + + description "Augments the interface model with the Bridge Port"; + + case bridge-port { + description "Extension of the IETF Interfaces model (RFC7223)."; + + container bridge-port { + leaf bridge { + type if:interface-ref; + must "deref(.)/../bridge" { + error-message "Must refer to a bridge interface."; + } + mandatory true; + description "Bridge interface to which this interface is attached."; + } + + leaf pvid { + if-feature "vlan-filtering"; + type dot1q-types:vlanid; + default "1"; + description "The primary VID assigned to this bridge port."; + } + + leaf default-priority { + if-feature "vlan-filtering"; + type dot1q-types:priority-type; + default "0"; + description "The default priority assigned to this bridge port."; + } + } + } + } +} diff --git a/src/confd/yang/infix-interfaces@2023-06-05.yang b/src/confd/yang/infix-interfaces@2023-06-05.yang index a6e878f3..32601174 100644 --- a/src/confd/yang/infix-interfaces@2023-06-05.yang +++ b/src/confd/yang/infix-interfaces@2023-06-05.yang @@ -3,6 +3,7 @@ module infix-interfaces { namespace "urn:infix:interfaces:ns:yang:1.0"; prefix infix-if; + include infix-if-bridge; include infix-if-veth; import ietf-interfaces {