diff --git a/board/netconf/rootfs/lib/infix/cli-pretty b/board/netconf/rootfs/lib/infix/cli-pretty
index eaeecdad6..d05075b5d 100755
--- a/board/netconf/rootfs/lib/infix/cli-pretty
+++ b/board/netconf/rootfs/lib/infix/cli-pretty
@@ -56,8 +56,6 @@ class Iface:
self.in_octets = ''
self.out_octets = ''
- self.parent = data.get('ietf-if-extensions:parent-interface', None)
-
if self.data.get('ietf-ip:ipv4'):
self.mtu = self.data.get('ietf-ip:ipv4').get('mtu', '')
self.ipv4_addr = self.data.get('ietf-ip:ipv4').get('address', '')
@@ -75,6 +73,11 @@ class Iface:
else:
self.bridge = ''
+ if self.data.get('infix-interfaces:vlan'):
+ self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
+ else:
+ self.lower_if = ''
+
def is_vlan(self):
return self.data['type'] == "infix-if-type:vlan"
@@ -136,7 +139,7 @@ class Iface:
self.pr_name(pipe="")
self.pr_proto_eth()
- if self.parent:
+ if self.lower_if:
self.pr_proto_ipv4(pipe='│')
self.pr_proto_ipv6(pipe='│')
else:
@@ -144,7 +147,7 @@ class Iface:
self.pr_proto_ipv6()
return
- parent = find_iface(_ifaces, self.parent)
+ parent = find_iface(_ifaces, self.lower_if)
if not parent:
print(f"Error, didn't find parent interface for vlan {self.name}")
sys.exit(1)
@@ -227,7 +230,7 @@ def pr_interface_list(json):
continue
# These interfaces are printed by there parent, such as bridge
- if iface.parent:
+ if iface.lower_if:
continue
if iface.bridge:
continue
diff --git a/src/confd/bin/bootstrap b/src/confd/bin/bootstrap
index 1d30829b7..f16c77a5f 100755
--- a/src/confd/bin/bootstrap
+++ b/src/confd/bin/bootstrap
@@ -147,11 +147,7 @@ sysrepoctl -s $SEARCH \
-i ietf-yang-push@2019-09-09.yang -g wheel -p 0660 \
-e on-change \
-i iana-if-type@2023-01-26.yang -g wheel -p 0660 \
- -i ietf-if-extensions@2023-01-26.yang -g wheel -p 0660 \
- -e sub-interfaces \
-i ieee802-dot1q-types@2022-10-29.yang -g wheel -p 0660 \
- -i ietf-if-vlan-encapsulation@2023-01-26.yang \
- -g wheel -p 0660 \
-i infix-ip@2023-09-14.yang -g wheel -p 0660 \
-i infix-if-type@2023-08-21.yang -g wheel -p 0660 \
-i infix-interfaces@2023-09-19.yang -g wheel -p 0660 \
diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c
index 4eba89c1c..c044d4a6a 100644
--- a/src/confd/src/ietf-interfaces.c
+++ b/src/confd/src/ietf-interfaces.c
@@ -168,43 +168,37 @@ static int ifchange_cand_infer_vlan(sr_session_ctx_t *session, const char *path)
goto out_free_ifname;
err = srx_nitems(session, &cnt,
- "%s/ietf-if-extensions:parent-interface", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/lower-layer-if", xpath);
if (!err && !cnt) {
inferred.data.string_val = ifname;
err = srx_set_item(session, &inferred, 0,
- "%s/ietf-if-extensions:parent-interface", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/lower-layer-if", xpath);
if (err)
goto out_free_ifname;
}
err = srx_nitems(session, &cnt,
- "%s"
- "/ietf-if-extensions:encapsulation"
- "/ietf-if-vlan-encapsulation:dot1q-vlan"
- "/outer-tag/tag-type", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/tag-type", xpath);
if (!err && !cnt) {
inferred.data.string_val = "ieee802-dot1q-types:c-vlan";
err = srx_set_item(session, &inferred, 0,
- "%s"
- "/ietf-if-extensions:encapsulation"
- "/ietf-if-vlan-encapsulation:dot1q-vlan"
- "/outer-tag/tag-type", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/tag-type", xpath);
if (err)
goto out_free_ifname;
}
err = srx_nitems(session, &cnt,
- "%s"
- "/ietf-if-extensions:encapsulation"
- "/ietf-if-vlan-encapsulation:dot1q-vlan"
- "/outer-tag/vlan-id", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/id", xpath);
if (!err && !cnt) {
inferred.data.string_val = vidstr;
err = srx_set_item(session, &inferred, 0,
- "%s"
- "/ietf-if-extensions:encapsulation"
- "/ietf-if-vlan-encapsulation:dot1q-vlan"
- "/outer-tag/vlan-id", xpath);
+ "%s/infix-if-vlan:vlan"
+ "/id", xpath);
if (err)
goto out_free_ifname;
}
@@ -891,38 +885,36 @@ static int netdag_gen_veth(struct dagger *net, struct lyd_node *dif,
static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
struct lyd_node *cif, FILE *ip)
{
- const char *parent = lydx_get_cattr(cif, "parent-interface");
const char *ifname = lydx_get_cattr(cif, "name");
struct lydx_diff typed, vidd;
- struct lyd_node *otag;
+ struct lyd_node *vlan;
+ const char *lower_if;
const char *proto;
int err;
- DEBUG("ifname %s parent %s", ifname, parent);
-
- err = dagger_add_dep(net, ifname, parent);
- if (err)
- return ERR_IFACE(cif, err, "Unable to add dep \"%s\"", parent);
-
- otag = lydx_get_descendant(lyd_child(dif ? : cif),
- "encapsulation",
- "dot1q-vlan",
- "outer-tag",
- NULL);
- if (!otag) {
+ vlan = lydx_get_descendant(lyd_child(dif ? : cif), "vlan", NULL);
+ if (!vlan) {
/*
- * Note: this is only an error if outer-tag is missing
+ * Note: this is only an error if vlan subcontext is missing
* from cif, otherwise it just means the interface had a
* a change that was not related to the VLAN config.
*/
if (!dif)
- ERROR("%s: missing mandatory outer-tag", ifname);
+ ERROR("%s: missing mandatory vlan", ifname);
return 0;
}
+
+ lower_if = lydx_get_cattr(vlan, "lower-layer-if");
+ DEBUG("ifname %s lower if %s\n", ifname, lower_if);
+
+ err = dagger_add_dep(net, ifname, lower_if);
+ if (err)
+ return ERR_IFACE(cif, err, "Unable to add dep \"%s\"", lower_if);
- fprintf(ip, "link add dev %s down link %s type vlan", ifname, parent);
- if (lydx_get_diff(lydx_get_child(otag, "tag-type"), &typed)) {
+ fprintf(ip, "link add dev %s down link %s type vlan", ifname, lower_if);
+
+ if (lydx_get_diff(lydx_get_child(vlan, "tag-type"), &typed)) {
proto = bridge_tagtype2str(typed.new);
if (!proto)
return ERR_IFACE(cif, -ENOSYS, "Unsupported tag type \"%s\"", typed.new);
@@ -930,7 +922,7 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
fprintf(ip, " proto %s", proto);
}
- if (lydx_get_diff(lydx_get_child(otag, "vlan-id"), &vidd))
+ if (lydx_get_diff(lydx_get_child(vlan, "id"), &vidd))
fprintf(ip, " id %s", vidd.new);
fputc('\n', ip);
@@ -996,24 +988,15 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
{
const char *iftype = lydx_get_cattr(cif, "type");
- if (!strcmp(iftype, "infix-if-type:bridge")) {
- if (is_phys_addr_deleted(dif))
- return true;
- } else if (!strcmp(iftype, "infix-if-type:vlan")) {
+ if (strcmp(iftype, "infix-if-type:ethernet")) {
if (is_phys_addr_deleted(dif))
return true;
+ }
- if (lydx_get_cattr(dif, "parent-interface") ||
- lydx_get_descendant(lyd_child(dif),
- "encapsulation",
- "dot1q-vlan",
- "outer-tag",
- NULL))
+ if (!strcmp(iftype, "infix-if-type:vlan")) {
+ if (lydx_get_descendant(lyd_child(dif), "vlan", NULL))
return true;
} else if (!strcmp(iftype, "infix-if-type:veth")) {
- if (is_phys_addr_deleted(dif))
- return true;
-
if (lydx_get_descendant(lyd_child(dif), "peer", NULL))
return true;
/*
diff --git a/src/confd/yang/ietf-if-extensions@2023-01-26.yang b/src/confd/yang/ietf-if-extensions@2023-01-26.yang
deleted file mode 100644
index fdcb0bcc0..000000000
--- a/src/confd/yang/ietf-if-extensions@2023-01-26.yang
+++ /dev/null
@@ -1,535 +0,0 @@
-module ietf-if-extensions {
- yang-version 1.1;
-
- namespace "urn:ietf:params:xml:ns:yang:ietf-if-extensions";
-
- prefix if-ext;
-
- import ietf-yang-types {
- prefix yang;
- reference "RFC 6991: Common YANG Data Types";
- }
-
- import ietf-interfaces {
- prefix if;
- reference
- "RFC 8343: A YANG Data Model For Interface Management";
- }
-
- import iana-if-type {
- prefix ianaift;
- reference "RFC 7224: IANA Interface Type YANG Module";
- }
-
- organization
- "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
-
- contact
- "WG Web:
- WG List:
-
- Editor: Robert Wilton
- ";
-
- description
- "This module contains common definitions for extending the IETF
- interface YANG model (RFC 8343) with common configurable layer 2
- properties.
-
- Copyright (c) 2023 IETF Trust and the persons identified as
- authors of the code. All rights reserved.
-
- Redistribution and use in source and binary forms, with or
- without modification, is permitted pursuant to, and subject to
- the license terms contained in, the Revised BSD License set
- forth in Section 4.c of the IETF Trust's Legal Provisions
- Relating to IETF Documents
- (https://trustee.ietf.org/license-info).
-
- This version of this YANG module is part of RFC XXXX
- (https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
- for full legal notices.
-
- The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
- NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
- 'MAY', and 'OPTIONAL' in this document are to be interpreted as
- described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
- they appear in all capitals, as shown here.";
-
- revision 2023-01-26 {
- description
- "Initial revision.";
-
- reference
- "RFC XXXX, Common Interface Extension YANG Data Models";
- }
-
- feature link-flap-suppression {
- description
- "This feature indicates that configurable interface link
- delay is supported, which is a feature is used to limit the
- propagation of very short interface link state flaps.";
- reference "RFC XXXX, Section 2.1 Link Flap Suppression";
- }
-
- feature dampening {
- description
- "This feature indicates that the device supports interface
- dampening, which is a feature that is used to limit the
- propagation of interface link state flaps over longer
- periods.";
- reference "RFC XXXX, Section 2.2 Dampening";
- }
-
- feature loopback {
- description
- "This feature indicates that configurable interface loopback is
- supported.";
- reference "RFC XXXX, Section 2.4 Loopback";
- }
-
- feature max-frame-size {
- description
- "This feature indicates that the device supports configuring or
- reporting the maximum frame size on interfaces.";
- reference "RFC XXXX, Section 2.5 Maximum Frame Size";
- }
-
- feature sub-interfaces {
- description
- "This feature indicates that the device supports the
- instantiation of sub-interfaces. Sub-interfaces are defined
- as logical child interfaces that allow features and forwarding
- decisions to be applied to a subset of the traffic processed
- on the specified parent interface.";
- reference "RFC XXXX, Section 2.6 Sub-interface";
- }
-
- /*
- * Define common identities to help allow interface types to be
- * assigned properties.
- */
- identity sub-interface {
- description
- "Base type for generic sub-interfaces.
-
- New or custom interface types can derive from this type to
- inherit generic sub-interface configuration.";
- reference "RFC XXXX, Section 2.6 Sub-interface";
- }
-
- identity ethSubInterface{
- base ianaift:l2vlan;
- base sub-interface;
-
- description
- "This identity represents the child sub-interface of any
- interface types that uses Ethernet framing (with or without
- 802.1Q tagging).";
- }
-
- identity loopback {
- description "Base identity for interface loopback options";
- reference "RFC XXXX, Section 2.4";
- }
- identity internal {
- base loopback;
- description
- "All egress traffic on the interface is internally looped back
- within the interface to be received on the ingress path.";
- reference "RFC XXXX, Section 2.4";
- }
- identity line {
- base loopback;
- description
- "All ingress traffic received on the interface is internally
- looped back within the interface to the egress path.";
- reference "RFC XXXX, Section 2.4";
- }
- identity connector {
- base loopback;
- description
- "The interface has a physical loopback connector attached that
- loops all egress traffic back into the interface's ingress
- path, with equivalent semantics to loopback internal.";
- reference "RFC XXXX, Section 2.4";
- }
-
- identity forwarding-mode {
- description "Base identity for forwarding-mode options.";
- reference "RFC XXXX, Section 2.7";
- }
- identity physical {
- base forwarding-mode;
- description
- "Physical layer forwarding. This includes DWDM or OTN based
- optical switching.";
- reference "RFC XXXX, Section 2.7";
- }
- identity data-link {
- base forwarding-mode;
- description
- "Layer 2 based forwarding, such as Ethernet/VLAN based
- switching, or L2VPN services.";
- reference "RFC XXXX, Section 2.7";
- }
- identity network {
- base forwarding-mode;
- description
- "Network layer based forwarding, such as IP, MPLS, or L3VPNs.";
- reference "RFC XXXX, Section 2.7";
- }
-
- /*
- * Augments the IETF interfaces model with leaves to configure
- * and monitor link-flap-suppression on an interface.
- */
- augment "/if:interfaces/if:interface" {
- description
- "Augments the IETF interface model with optional common
- interface level commands that are not formally covered by any
- specific standard.";
-
- /*
- * Defines standard YANG for the Link Flap Suppression feature.
- */
- container link-flap-suppression {
- if-feature "link-flap-suppression";
- description
- "Holds link flap related feature configuration.";
- leaf down {
- type uint32;
- units milliseconds;
- description
- "Delays the propagation of a 'loss of carrier signal' event
- that would cause the interface state to go down, i.e. the
- command allows short link flaps to be suppressed. The
- configured value indicates the minimum time interval (in
- milliseconds) that the link signal must be continuously
- down before the interface state is brought down. If not
- configured, the behavior on loss of link signal is
- vendor/interface specific, but with the general
- expectation that there should be little or no delay.";
- }
- leaf up {
- type uint32;
- units milliseconds;
- description
- "Defines the minimum time interval (in milliseconds) that
- the link signal must be continuously present and error
- free before the interface state is allowed to transition
- from down to up. If not configured, the behavior is
- vendor/interface specific, but with the general
- expectation that sufficient default delay should be used
- to ensure that the interface is stable when enabled before
- being reported as being up. Configured values that are
- too low for the hardware capabilties may be rejected.";
- }
- leaf carrier-transitions {
- type yang:counter64;
- units transitions;
- config false;
- description
- "Defines the number of times the underlying link state
- has changed to, or from, state up. This counter should be
- incremented even if the high layer interface state changes
- are being suppressed by a running link flap suppression
- timer.";
- }
- leaf timer-running {
- type enumeration {
- enum none {
- description
- "No link flap suppression timer is running.";
- }
- enum up {
- description
- "link-flap-suppression up timer is running. The
- underlying link state is up, but interface state is
- not reported as up.";
- }
- enum down {
- description
- "link-flap-suppression down timer is running.
- Interface state is reported as up, but the underlying
- link state is actually down.";
- }
- }
- config false;
- description
- "Reports whether a link flap suppression timer is actively
- running, in which case the interface state does not match
- the underlying link state.";
- }
-
- reference "RFC XXXX, Section 2.1 Link Flap Suppression";
- }
-
- /*
- * Augments the IETF interfaces model with a container to hold
- * generic interface dampening
- */
- container dampening {
- if-feature "dampening";
- presence
- "Enable interface link flap dampening with default settings
- (that are vendor/device specific).";
- description
- "Interface dampening limits the propagation of interface link
- state flaps over longer periods.";
- reference "RFC XXXX, Section 2.2 Dampening";
-
- leaf half-life {
- type uint32;
- units seconds;
- description
- "The time (in seconds) after which a penalty would be half
- its original value. Once the interface has been assigned
- a penalty, the penalty is decreased at a decay rate
- equivalent to the half-life. For some devices, the
- allowed values may be restricted to particular multiples
- of seconds. The default value is vendor/device
- specific.";
- reference "RFC XXXX, Section 2.3.2 Half-Life Period";
- }
-
- leaf reuse {
- type uint32;
- description
- "Penalty value below which a stable interface is
- unsuppressed (i.e. brought up) (no units). The default
- value is vendor/device specific. The penalty value for a
- link up->down state change is 1000 units.";
- reference "RFC XXXX, Section 2.2.3 Reuse Threshold";
- }
-
- leaf suppress {
- type uint32;
- description
- "Limit at which an interface is suppressed (i.e. held down)
- when its penalty exceeds that limit (no units). The value
- must be greater than the reuse threshold. The default
- value is vendor/device specific. The penalty value for a
- link up->down state change is 1000 units.";
- reference "RFC XXXX, Section 2.2.1 Suppress Threshold";
- }
-
- leaf max-suppress-time {
- type uint32;
- units seconds;
- description
- "Maximum time (in seconds) that an interface can be
- suppressed before being unsuppressed if no further link
- up->down state change penalties have been applied. This
- value effectively acts as a ceiling that the penalty value
- cannot exceed. The default value is vendor/device
- specific.";
- reference "RFC XXXX, Section 2.2.4 Maximum Suppress Time";
- }
-
- leaf penalty {
- type uint32;
- config false;
- description
- "The current penalty value for this interface. When the
- penalty value exceeds the 'suppress' leaf then the
- interface is suppressed (i.e. held down).";
- reference "RFC XXXX, Section 2.2 Dampening";
- }
-
- leaf suppressed {
- type boolean;
- config false;
- description
- "Represents whether the interface is suppressed (i.e. held
- down) because the 'penalty' leaf value exceeds the
- 'suppress' leaf.";
- reference "RFC XXXX, Section 2.2 Dampening";
- }
-
- leaf time-remaining {
- when '../suppressed = "true"' {
- description
- "Only suppressed interfaces have a time remaining.";
- }
- type uint32;
- units seconds;
- config false;
- description
- "For a suppressed interface, this leaf represents how long
- (in seconds) that the interface will remain suppressed
- before it is allowed to go back up again.";
- reference "RFC XXXX, Section 2.2 Dampening";
- }
- }
-
- /*
- * Various types of interfaces support a configurable layer 2
- * encapsulation, any that are supported by YANG should be
- * listed here.
- *
- * Different encapsulations can hook into the common encaps-type
- * choice statement.
- */
- container encapsulation {
- when
- "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:pos') or
- derived-from-or-self(../if:type,
- 'ianaift:atmSubInterface') or
- derived-from-or-self(../if:type, 'ianaift:l2vlan') or
- derived-from-or-self(../if:type, 'ethSubInterface')" {
-
- description
- "All interface types that can have a configurable L2
- encapsulation.";
- }
-
- description
- "Holds the OSI layer 2 encapsulation associated with an
- interface.";
- choice encaps-type {
- description
- "Extensible choice of layer 2 encapsulations";
- reference "RFC XXXX, Section 2.3 Encapsulation";
- }
- }
-
- /*
- * Various types of interfaces support loopback configuration,
- * any that are supported by YANG should be listed here.
- */
- leaf loopback {
- when "derived-from-or-self(../if:type,
- 'ianaift:ethernetCsmacd') or
- derived-from-or-self(../if:type, 'ianaift:sonet') or
- derived-from-or-self(../if:type, 'ianaift:atm') or
- derived-from-or-self(../if:type, 'ianaift:otnOtu')" {
- description
- "All interface types that support loopback configuration.";
- }
- if-feature "loopback";
- type identityref {
- base loopback;
- }
- description "Enables traffic loopback.";
- reference "RFC XXXX, Section 2.4 Loopback";
- }
-
- /*
- * Allows the maximum frame size to be configured or reported.
- */
- leaf max-frame-size {
- if-feature "max-frame-size";
- type uint32 {
- range "64 .. max";
- }
- description
- "The maximum size of layer 2 frames that may be transmitted
- or received on the interface (including any frame header,
- maximum frame payload size, and frame checksum sequence).
-
- If configured, the max-frame-size also limits the maximum
- frame size of any child sub-interfaces. The MTU available
- to higher layer protocols is restricted to the maximum frame
- payload size, and MAY be further restricted by explicit
- layer 3 or protocol specific MTU configuration.";
-
- reference "RFC XXXX, Section 2.5 Maximum Frame Size";
- }
-
- /*
- * Augments the IETF interfaces model with a leaf that indicates
- * which mode, or layer, is being used to forward the traffic.
- */
- leaf forwarding-mode {
- type identityref {
- base forwarding-mode;
- }
- config false;
-
- description
- "The forwarding mode that the interface is operating in.";
- reference "RFC XXXX, Section 2.7 Forwarding Mode";
- }
- }
-
- /*
- * Add generic support for sub-interfaces.
- *
- * This should be extended to cover all interface types that are
- * child interfaces of other interfaces.
- */
- augment "/if:interfaces/if:interface" {
- when "derived-from(if:type, 'sub-interface') or
- derived-from-or-self(if:type, 'ianaift:l2vlan') or
- derived-from-or-self(if:type, 'ianaift:atmSubInterface') or
- derived-from-or-self(if:type, 'ianaift:frameRelay')" {
- description
- "Any ianaift:types that explicitly represent sub-interfaces
- or any types that derive from the sub-interface identity.";
- }
- if-feature "sub-interfaces";
-
- description
- "Adds a parent interface field to interfaces that model
- sub-interfaces.";
- leaf parent-interface {
-
- type if:interface-ref;
-
- mandatory true;
- description
- "This is the reference to the parent interface of this
- sub-interface.";
- reference "RFC XXXX, Section 2.6 Sub-interface";
- }
- }
-
- /*
- * Add discard counter for unknown sub-interface encapsulation
- */
- augment "/if:interfaces/if:interface/if:statistics" {
- when "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:ifPwType')" {
- description
- "Applies to interfaces that can demultiplex ingress frames to
- sub-interfaces.";
- }
- if-feature "sub-interfaces";
-
- description
- "Augment the interface model statistics with a sub-interface
- demux discard counter.";
- leaf in-discard-unknown-encaps {
- type yang:counter64;
- units frames;
- description
- "A count of the number of frames that were well formed, but
- otherwise discarded because their encapsulation does not
- classify the frame to the interface or any child
- sub-interface. E.g., a frame might be discarded because the
- it has an unknown VLAN Id, or does not have a VLAN Id when
- one is expected.
-
- For consistency, frames counted against this counter are
- also counted against the IETF interfaces statistics. In
- particular, they are included in in-octets and in-discards,
- but are not included in in-unicast-pkts, in-multicast-pkts
- or in-broadcast-pkts, because they are not delivered to a
- higher layer.
-
- Discontinuities in the values of this counter can occur at
- re-initialization of the management system, and at other
- times as indicated by the value of the 'discontinuity-time'
- leaf defined in the ietf-interfaces YANG module
- (RFC 8343).";
- }
- }
-}
diff --git a/src/confd/yang/infix-if-vlan@2023-10-25.yang b/src/confd/yang/infix-if-vlan@2023-10-25.yang
new file mode 100644
index 000000000..b8993c4da
--- /dev/null
+++ b/src/confd/yang/infix-if-vlan@2023-10-25.yang
@@ -0,0 +1,49 @@
+submodule infix-if-vlan {
+ yang-version 1.1;
+ belongs-to infix-interfaces {
+ prefix infix-if;
+ }
+
+ import ietf-interfaces {
+ prefix if;
+ }
+
+ import infix-if-type {
+ prefix infixift;
+ }
+ import ieee802-dot1q-types {
+ prefix dot1q-types;
+ }
+ contact "kernelkit@googlegroups.com";
+ description
+ "This module implements VLAN (8021q) encapsulation";
+
+ revision 2023-10-25 {
+ description "Initial revision";
+ }
+
+ augment "/if:interfaces/if:interface" {
+ when "derived-from-or-self(if:type, 'infixift:vlan')" {
+ description "Only shown for if:type vlan";
+ }
+ description "Augment to add 802.1Q VLAN tag classifications";
+ container vlan {
+ description "Configure 802.1q/802.1ad VLANs";
+ leaf tag-type {
+ type dot1q-types:dot1q-tag-type;
+ default dot1q-types:c-vlan;
+ description "VLAN type";
+ }
+ leaf id {
+ type dot1q-types:vlanid;
+ mandatory true;
+ description "VLAN Id";
+ }
+ leaf lower-layer-if {
+ type if:interface-ref;
+ mandatory true;
+ description "Base interface for VLAN";
+ }
+ }
+ }
+}
diff --git a/src/confd/yang/infix-interfaces@2023-09-19.yang b/src/confd/yang/infix-interfaces@2023-09-19.yang
index 99c55ac48..1fe5496e9 100644
--- a/src/confd/yang/infix-interfaces@2023-09-19.yang
+++ b/src/confd/yang/infix-interfaces@2023-09-19.yang
@@ -13,6 +13,7 @@ module infix-interfaces {
include infix-if-base;
include infix-if-bridge;
include infix-if-veth;
+ include infix-if-vlan;
organization "KernelKit";
contact "kernelkit@googlegroups.com";
diff --git a/src/statd/iface-ip-link.c b/src/statd/iface-ip-link.c
index 05ebf501c..a719c9cda 100644
--- a/src/statd/iface-ip-link.c
+++ b/src/statd/iface-ip-link.c
@@ -254,9 +254,10 @@ static int ip_link_kind_is_dsa(json_t *j_iface)
static int ly_add_ip_link_parent(const struct ly_ctx *ctx, struct lyd_node **parent,
char *xpath, json_t *j_iface)
{
+ struct lyd_node *vlan_node;
+ char *vlan_xpath;
json_t *j_val;
int err;
-
j_val = json_object_get(j_iface, "link");
if (!j_val) {
/* Interface has no parent */
@@ -272,15 +273,29 @@ static int ly_add_ip_link_parent(const struct ly_ctx *ctx, struct lyd_node **par
ERROR("Expected a JSON string for 'link'");
return SR_ERR_SYS;
}
+ err = asprintf(&vlan_xpath, "%s/infix-interfaces:vlan", xpath);
+ if (err == -1) {
+ ERROR("Error, creating vlan xpath");
+ return SR_ERR_SYS;
+ }
+
+ err = lyd_new_path(*parent, ctx, vlan_xpath, NULL, 0, &vlan_node);
+ if (err) {
+ ERROR("Failed adding 'lower-layer-if' node (%s), libyang error %d: %s",
+ vlan_xpath, err, ly_errmsg(ctx));
+ free(vlan_xpath);
+ return SR_ERR_LY;
+ }
- err = lydx_new_path(ctx, parent, xpath,
- "ietf-if-extensions:parent-interface", "%s",
- json_string_value(j_val));
+ err = lydx_new_path(ctx, &vlan_node, vlan_xpath, "lower-layer-if",
+ "%s", json_string_value(j_val));
if (err) {
- ERROR("Error, adding 'link' to data tree, libyang error %d", err);
+ ERROR("Error, adding 'lower-layer-if' to data tree, libyang error %d", err);
+ free(vlan_xpath);
return SR_ERR_LY;
}
+ free(vlan_xpath);
return SR_ERR_OK;
}
diff --git a/test/case/ietf_interfaces/vlan_ping.py b/test/case/ietf_interfaces/vlan_ping.py
index f441c72b9..e20bdf41f 100755
--- a/test/case/ietf_interfaces/vlan_ping.py
+++ b/test/case/ietf_interfaces/vlan_ping.py
@@ -21,14 +21,9 @@
{
"name": f"{tport}.10",
"type": "infix-if-type:vlan",
- "parent-interface": tport,
- "encapsulation": {
- "dot1q-vlan": {
- "outer-tag": {
- "tag-type": "ieee802-dot1q-types:c-vlan",
- "vlan-id": 10,
- }
- }
+ "vlan": {
+ "id": 10,
+ "lower-layer-if": tport,
},
"ipv4": {
diff --git a/test/case/infix_interfaces/bridge_vlan.py b/test/case/infix_interfaces/bridge_vlan.py
index cfe607d73..f7505cd93 100755
--- a/test/case/infix_interfaces/bridge_vlan.py
+++ b/test/case/infix_interfaces/bridge_vlan.py
@@ -41,14 +41,9 @@
"name": "vlan10",
"type": "infix-if-type:vlan",
"enabled": True,
- "parent-interface": "br0",
- "encapsulation": {
- "dot1q-vlan": {
- "outer-tag": {
- "tag-type": "ieee802-dot1q-types:c-vlan",
- "vlan-id": 10,
- }
- }
+ "vlan": {
+ "lower-layer-if": "br0",
+ "id": 10,
},
"ipv4": {
"address": [