Merge pull request #1495 from kernelkit/speed-duplex

This commit is contained in:
Joachim Wiberg
2026-05-27 23:40:29 +02:00
committed by GitHub
59 changed files with 5730 additions and 1941 deletions
+35 -4
View File
@@ -11,21 +11,53 @@ All notable changes to the project are documented in this file.
- Upgrade Linux kernel to 6.18.33 (LTS)
- Upgrade Buildroot to 2025.02.14 (LTS)
- Upgrade FRR to 10.5.4
- Add support for [Acer Connect Vero W6m][AcerConnectVero], a COTS home router,
based upon the same hardware as [Banana Pi BPI-R3][BPI-R3], but
- Add support for [Acer Connect Vero W6m][AcerConnectVero], a low-cost COTS
home router, based on the same hardware as [Banana Pi BPI-R3][BPI-R3], but
with a Wi-Fi 6E (6 GHz band) chip.
- Add configurable channel-width in Wi-Fi configuration.
- Upgrade `ieee802-ethernet-interface` YANG model to revision 2025-09-10 (IEEE
Std 802.3.2-2025), adding the standard `phy-type` and `pmd-type` operational
leaves. Speed is now exposed via `ietf-interfaces:speed` (bps, RFC 8343);
the now obsolete `eth:speed` is no longer returned
- Rework `show interface` summary output as layered protocol rows. When a
port has link, a physical-medium row (e.g. `1000baseT`, `10GbaseLR`) appears
above the `ethernet` row. VLAN, GRE, VXLAN and WiFi interfaces likewise get
one row per protocol layer, with type-specific data on each (`vid:`,
`remote:`, `vni:`, `station ssid:`, etc.), issue #530
- New `auto-negotiation/advertised-pmd-types` leaf-list replaces the
retired `enable=false + speed + duplex` idiom for pinned link modes
(IEEE Std 802.3.2-2025 obsoleted `eth:speed`), issue #805. Existing
startup configurations are migrated automatically on upgrade; see
[ethernet.md](ethernet.md#restricting-advertised-link-modes) for the
new model, the duplex × PMD mapping, and the `enable=false` escape
hatch for non-autoneg peers
- New `ethernet/mdi-x` boolean leaf to force the copper MDI/MDI-X pinout
(true = MDI-X, false = MDI, absent = Auto-MDIX). Needed on some PHYs
where Auto-MDIX stops working once auto-negotiation is disabled; see
[ethernet.md](ethernet.md#restricting-advertised-link-modes)
- New operational `supported-pmd-types` leaf-list on each Ethernet interface,
exposing the set of PMD types currently supported. Useful for SFP/SFP+
diagnosis: an LR-only optic narrows the list to a single entry, confirming
the transceiver without `ethtool -m`
- New CLI command `show operational`, and XPath filtering for this and any of
the other datastores, using `[path /path/to/subtree]`
### Fixes
- Fix #1493: container with a physical interface not properly removed
when switching to a configuration without containers
- Fix #1506: add documentation on how to configure VLAN interfaces,
including stacked (Q-in-Q) VLAN interfaces, in a dedicated `vlan.md`
- Fix long-standing typo `auto-negotation` in `yanger`, which caused
the operational `auto-negotiation/enable` leaf to always read as
`unknown` regardless of the actual port setting
- Handle unclean daemon exits better, e.g., `dbus-daemon` crashing and
leaving a stale pidfile behind, causing it to refuse to be restarted
- Fix occasional blank or garbled `[ OK ]` lines at startup
- Disallow multicast MAC addresses in custom MAC address configuration
- Fix broken Wi-Fi 6 GHz band configuration.
[BPI-R3]: https://docs.banana-pi.org/en/BPI-R3/BananaPi_BPI-R3
[AcerConnectVero]: ../board/aarch64/acer-connect-vero-w6m/
[v26.04.0][] - 2026-04-30
@@ -73,7 +105,6 @@ All notable changes to the project are documented in this file.
- Fix [BPI-R3][] PCIe devices failing to initialize on boot due to a missing
clock definition in the device tree
[BPI-R3]: https://wiki.banana-pi.org/Banana_Pi_BPI-R3
[BPI-R4]: https://docs.banana-pi.org/en/BPI-R4/BananaPi_BPI-R4
[ESPRESSObin]: https://espressobin.net/
[SAMA7G54]: https://www.microchip.com/en-us/development-tool/ev21h18a
@@ -177,7 +208,7 @@ All notable changes to the project are documented in this file.
- Fix CLI `copy` command problem to copy to scp/sftp destinations
[BPI-R3-MINI]: https://wiki.banana-pi.org/Banana_Pi_BPI-R3_Mini
[BPI-R3-MINI]: https://docs.banana-pi.org/en/BPI-R3_Mini/BananaPi_BPI-R3_Mini
[SAMA7G54-EK]: https://www.microchip.com/en-us/development-tool/ev21h18a
[v26.01.0][] - 2026-02-03
+2 -2
View File
@@ -73,8 +73,8 @@ admin@example:/config/interface/br0/> <b>set bridge vlans vlan 20 tagged br0</b>
</code></pre>
To route or to manage via a VLAN, a VLAN interface needs to be created
on top of the bridge, see section [VLAN Interfaces](ethernet.md#vlan-interfaces)
for more on this topic.
on top of the bridge, see section [VLAN Interfaces](vlan.md) for more
on this topic.
> [!NOTE]
> In some use-cases only a single management VLAN on the bridge is used.
+1 -1
View File
@@ -164,7 +164,7 @@ interfaces {
}
}
admin@host-12-34-56:/config/interface/eth0/> leave
admin@host-12-34-56:/> show interfaces
admin@host-12-34-56:/> show interface
INTERFACE PROTOCOL STATE DATA
lo loopback UNKNOWN 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
+4 -4
View File
@@ -109,11 +109,11 @@ When configuring, e.g., `dns-server`, or `router` options with the value
`auto`, the system uses the IP address from the interface matching the
subnet. For example:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv4 192.168.1.1/24 (static)
eth1 ethernet UP 02:00:00:00:00:01
eth1 ethernet UP 02:00:00:00:00:01
ipv4 192.168.2.1/24 (static)
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> <b>edit option dns-server</b>
+184 -120
View File
@@ -1,52 +1,8 @@
# Ethernet Interfaces
This document covers VLAN interfaces, physical Ethernet interfaces,
and virtual Ethernet (VETH) pairs.
## VLAN Interfaces
Creating a VLAN can be done in many ways. This section assumes VLAN
interfaces created atop another Linux interface. E.g., the VLAN
interfaces created on top of the Ethernet interface or bridge in the
picture below.
![VLAN interface on top of Ethernet or Bridge interfaces](img/interface-vlan-variants.svg)
A VLAN interface is basically a filtering abstraction. When you run
`tcpdump` on a VLAN interface you will only see the frames matching the
VLAN ID of the interface, compared to *all* the VLAN IDs if you run
`tcpdump` on the lower-layer interface.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0.20</b>
admin@example:/config/interface/eth0.20/> <b>show</b>
type vlan;
vlan {
tag-type c-vlan;
id 20;
lower-layer-if eth0;
}
admin@example:/config/interface/eth0.20/> <b>leave</b>
</code></pre>
The example below assumes bridge br0 is already created, see [VLAN
Filtering Bridge](bridging.md#vlan-filtering-bridge).
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface vlan10</b>
admin@example:/config/interface/vlan10/> <b>set vlan id 10</b>
admin@example:/config/interface/vlan10/> <b>set vlan lower-layer-if br0</b>
admin@example:/config/interface/vlan10/> <b>leave</b>
</code></pre>
As conventions, a VLAN interface for VID 20 on top of an Ethernet
interface *eth0* is named *eth0.20*, and a VLAN interface for VID 10 on
top of a bridge interface *br0* is named *vlan10*.
> [!NOTE]
> If you name your VLAN interface `foo0.N` or `vlanN`, where `N` is a
> number, the CLI infers the interface type automatically.
This document covers physical Ethernet interfaces and virtual Ethernet
(VETH) pairs. For VLAN interfaces stacked on top of an Ethernet port
or bridge, see [VLAN Interfaces](vlan.md).
## Physical Ethernet Interfaces
@@ -56,111 +12,219 @@ top of a bridge interface *br0* is named *vlan10*.
Physical Ethernet interfaces provide low-level settings for speed/duplex as
well as packet status and [statistics](#ethernet-statistics).
By default, Ethernet interfaces defaults to auto-negotiating
speed/duplex modes, advertising all speed and duplex modes available.
In the example below, the switch would by default auto-negotiate speed
1 Gbit/s on port eth1 and 100 Mbit/s on port eth4, as those are the
highest speeds supported by H1 and H2 respectively.
By default, Ethernet interfaces defaults to auto-negotiating speed/duplex
modes, advertising all speed and duplex modes available. In the example
below, the switch would by default auto-negotiate speed 1 Gbps on port eth1
and 100 Mbps on port eth4, as those are the highest speeds supported by H1 and
H2 respectively.
![4-port Gbit/s switch connected to Gbit and Fast Ethernet Hosts](img/ethernet-autoneg.svg)
The speed and duplex status for the links can be listed as shown
below, assuming the link operational status is 'up'.
A quick at-a-glance view of the physical link is available in the summary
listing. When a port is up, a physical-layer row appears above the ethernet
row, naming the IEEE PMD type (e.g. `1000baseT`, `10GbaseLR`) in the PROTOCOL
column and the negotiated duplex in DATA. When the link is down the row is
omitted and the interface name falls onto the ethernet row.
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth1 1000baseT UP duplex: full
ethernet 00:53:00:06:11:01
eth2 1000baseT UP duplex: full
ethernet 00:53:00:06:11:02
eth3 ethernet DOWN 00:53:00:06:11:03
eth4 100baseTX UP duplex: full
ethernet 00:53:00:06:11:04
...
</code></pre>
The detail view spells everything out, including auto-negotiation
state and the speed in Mbit/s.
<pre class="cli"><code>admin@example:/> <b>show interface eth1</b>
name : eth1
index : 2
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:01
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
name : eth1
index : 2
mtu : 1500
operational status : up
link mode : 1000baseT
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:01
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
...
admin@example:/> <b>show interface eth4</b>
name : eth4
index : 5
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 100
physical address : 00:53:00:06:11:04
ipv4 addresses :
ipv6 addresses :
in-octets : 75439
out-octets : 550704
name : eth4
index : 5
mtu : 1500
operational status : up
link mode : 100baseTX
auto-negotiation : on
duplex : full
speed : 100
physical address : 00:53:00:06:11:04
ipv4 addresses :
ipv6 addresses :
in-octets : 75439
out-octets : 550704
...
admin@example:/>
</code></pre>
### Configuring fixed speed and duplex
### Restricting advertised link modes
Auto-negotiation of speed/duplex mode is desired in almost all
use-cases, but it is possible to disable auto-negotiation and specify
a fixed speed and duplex mode.
Auto-negotiation is the right default for almost all links, but sometimes a
port has to come up at a fixed speed, usually when talking to old hardware
that won't auto-negotiate or does it badly. IEEE Std 802.3.2-2025 dropped
the old "turn off auto-negotiation, then set a fixed speed and duplex"
approach. Instead you restrict the set of PMD types the port may advertise:
list a single PMD and the link pins to that mode against any peer that
supports it.
> [!IMPORTANT]
> When setting a fixed speed and duplex mode, ensure both sides of the
> link have matching configuration. If speed does not match, the link
> will not come up. If duplex mode does not match, the result is
> reported collisions and/or bad throughput.
> [!NOTE]
> Earlier Infix releases needed `enable false` plus explicit `speed` and
> `duplex` leaves. IEEE Std 802.3.2-2025 retired the `eth:speed` leaf, so
> the speed now comes from the `advertised-pmd-types` entry instead.
> Existing `startup-config.cfg` files are migrated automatically on upgrade.
The example below configures port eth3 to fixed speed 100 Mbit/s
half-duplex mode.
Each entry in `auto-negotiation/advertised-pmd-types` is an IEEE PMD-type
identity (`ieee802-ethernet-phy-type:pmd-type-*`). The separate `duplex`
leaf controls half vs full duplex.
The example below pins port `eth3` to 100 Mbit/s half-duplex.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth3 ethernet</b>
admin@example:/config/interface/eth3/ethernet/> <b>set speed 0.1</b>
admin@example:/config/interface/eth3/ethernet/> <b>set auto-negotiation advertised-pmd-types pmd-type-100BASE-TX</b>
admin@example:/config/interface/eth3/ethernet/> <b>set duplex half</b>
admin@example:/config/interface/eth3/ethernet/> <b>set auto-negotiation enable false</b>
admin@example:/config/interface/eth3/ethernet/> <b>show</b>
auto-negotiation {
enable false;
advertised-pmd-types [ ieee802-ethernet-phy-type:pmd-type-100BASE-TX ];
}
duplex half;
speed 0.1;
admin@example:/config/interface/eth3/ethernet/> <b>leave</b>
admin@example:/>
</code></pre>
Speed metric is in Gbit/s. Auto-negotiation needs to be disabled in
order for fixed speed/duplex to apply. Only speeds `0.1`(100 Mbit/s)
and `0.01` (10 Mbit/s) can be specified. 1 Gbit/s and higher speeds
require auto-negotiation to be enabled.
List several PMDs to advertise all of them; auto-negotiation then settles
on the highest mode both ends support.
> [!IMPORTANT]
> When pinning a link mode, make sure both ends share at least one common
> (PMD, duplex) combination, otherwise the link will not come up.
#### Duplex and advertised modes
A PMD type like `10BASE-T` or `100BASE-TX` says nothing about duplex on its
own, but the kernel tracks half and full duplex as separate link modes.
Infix advertises both variants of every PMD you list, then narrows to one
duplex when the `duplex` leaf is set:
| `advertised-pmd-types` | `duplex` | Resulting advertised modes |
|----------------------------|----------|------------------------------------------|
| `[10BASE-T]` | _unset_ | `10baseT/Half` + `10baseT/Full` |
| `[10BASE-T]` | `full` | `10baseT/Full` |
| `[10BASE-T]` | `half` | `10baseT/Half` |
| `[10BASE-T, 100BASE-TX]` | _unset_ | all four half/full combinations |
| `[10BASE-T, 100BASE-TX]` | `full` | `10baseT/Full` + `100baseT/Full` |
| _unset_ | _unset_ | every mode the PHY supports (default) |
So `duplex` filters the PMDs you listed. PMDs with no half-duplex variant
(everything above 1 Gbps) only ever advertise full.
#### Disabling auto-negotiation
The method above keeps auto-negotiation on and only limits what it
advertises, so the peer still negotiates as usual. That doesn't help with
gear that won't negotiate at all, like some old switches or a back-to-back
copper link. For those, set `auto-negotiation/enable false` together with a
single `advertised-pmd-types` entry to force a fixed speed and duplex with
negotiation off:
<pre class="cli"><code>admin@example:/config/interface/eth3/ethernet/> <b>set auto-negotiation enable false</b>
admin@example:/config/interface/eth3/ethernet/> <b>set auto-negotiation advertised-pmd-types pmd-type-100BASE-TX</b>
admin@example:/config/interface/eth3/ethernet/> <b>set duplex full</b>
</code></pre>
With `enable false` you must list exactly one PMD: it sets the speed, and
the `duplex` leaf sets half or full. Leave `duplex` out and Infix uses
whatever the PMD supports, normally full.
Auto-MDIX usually rides along with auto-negotiation, so turning negotiation
off can leave both ends picking the same MDI/MDI-X pinout. The link then
comes up electrically but carries no traffic. When that happens, force
opposite pinouts with the `mdi-x` leaf — set one end true (MDI-X) and the
other false (MDI):
<pre class="cli"><code>admin@example:/config/interface/eth3/ethernet/> <b>set mdi-x false</b>
</code></pre>
Leaving `mdi-x` unset keeps Auto-MDIX in charge, which is correct whenever
auto-negotiation is on.
> [!NOTE]
> Whether `enable false` reaches the external PHY depends on the driver.
> Direct-attach NICs handle it directly. Switch user ports go through the
> switch driver, and some accept the request at the MAC but leave the PHY
> auto-negotiating: the kernel reports the configured speed while the wire
> runs at whatever was negotiated, and traffic stalls. If that happens,
> read the PHY's BMCR register (e.g. with `mdio` from `mdiotools`) to see
> what the PHY is actually doing.
The detail view exposes a `supported` block (operational state,
backed by the `supported-pmd-types` leaf-list) listing the PMD types
the kernel currently believes the interface can operate at. For
SFP/SFP+ cages this set reflects the inserted module: plug in a 10G
LR optic and `supported` will narrow to `10GbaseLR` only. Combined
with the operational `link mode` row above it, this makes it trivial
to confirm what an unknown transceiver actually is — no `ethtool -m`
round-trip needed.
<pre class="cli"><code>admin@example:/> <b>show interface eth13</b>
name : eth13
type : ethernet
operational status : up
link mode : 10GbaseLR
auto-negotiation : off
supported : 10GbaseLR
duplex : full
speed : 10000
...
</code></pre>
### Ethernet statistics
Ethernet packet statistics[^1] can be listed as shown below.
<pre class="cli"><code>admin@example:/> <b>show interface eth1</b>
name : eth1
index : 2
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:0a
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
eth-in-frames : 434
eth-in-multicast-frames : 296
eth-in-broadcast-frames : 138
eth-in-error-fcs-frames : 0
eth-in-error-oversize-frames : 0
eth-out-frames : 310
eth-out-multicast-frames : 310
eth-out-broadcast-frames : 0
eth-out-good-octets : 76821
eth-in-good-octets : 60598
name : eth1
index : 2
mtu : 1500
operational status : up
link mode : 1000baseT
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:0a
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
───────────────────
<b>Ethernet Statistics</b>
in-frames : 434
in-multicast-frames : 296
in-broadcast-frames : 138
in-error-fcs-frames : 0
in-error-oversize-frames : 0
out-frames : 310
out-multicast-frames : 310
out-broadcast-frames : 0
out-good-octets : 76821
in-good-octets : 60598
admin@example:/>
</code></pre>
+13 -7
View File
@@ -61,13 +61,19 @@ admin@example:/config/interface/eth0/> <b>leave</b>
The operational status can be inspected to see both administrative and
actual link state:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
INTERFACE PROTOCOL STATE DATA
eth0 ethernet <b>DISABLED</b> 02:00:00:00:00:00
eth1 ethernet UP 02:00:00:00:00:01
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet <b>DISABLED</b> 02:00:00:00:00:00
eth1 1000baseT UP duplex: full
ethernet 02:00:00:00:00:01
...
</code></pre>
The rows are layered bottom-up by protocol: a physical-medium row (only
emitted when the link is up) on top, then the ethernet row carrying the
bare MAC, then any ipv4/ipv6 sub-rows. See [Ethernet](ethernet.md) for the
full set of summary fields.
## Description
@@ -84,9 +90,9 @@ The description is visible in the operational datastore and in `show`
commands:
<pre class="cli"><code>admin@example:/> <b>show interface eth0</b>
name : eth0
description : Uplink to core switch
index : 2
name : eth0
description : Uplink to core switch
index : 2
...
</code></pre>
+39 -39
View File
@@ -117,11 +117,11 @@ will be ignored. For details on how to enable the NTP client, see the
![Switch example (eth0 and lo)](img/ip-address-example-switch.svg)
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -153,13 +153,13 @@ admin@example:/config/interface/eth0/ipv4/> <b>diff</b>
+ }
+}
admin@example:/config/interface/eth0/ipv4/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv4 169.254.1.3/16 (random)
ipv4 10.0.1.1/24 (static)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -188,12 +188,12 @@ admin@example:/config/interface/eth0/ipv4/autoconf/> <b>leave</b>
admin@example:/config/> <b>edit interface eth0 ipv4</b>
admin@example:/config/interface/eth0/ipv4/> <b>set dhcp</b>
admin@example:/config/interface/eth0/ipv4/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv4 10.1.2.100/24 (dhcp)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -235,11 +235,11 @@ admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set dhcp</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8::42/128 (dhcp)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -291,10 +291,10 @@ on the interface.
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set enabled false</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -308,12 +308,12 @@ admin@example:/>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set address 2001:db8::1 prefix-length 64</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8::1/64 (static)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -330,12 +330,12 @@ advertised by the router (here 2001:db8:0:1::0/64) and the interface
identifier. The resulting address is of type *link-layer*, as it is
formed based on the interface identifier ([ietf-ip.yang][2]).
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:0:ff:fe00:0/64 (link-layer)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -348,11 +348,11 @@ below.
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set autoconf create-global-addresses false</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -366,12 +366,12 @@ admin@example:/>
By default, the auto-configured link-local and global IPv6 addresses
are formed from a link-identifier based on the MAC address.
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:0:ff:fe00:0/64 (link-layer)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -385,12 +385,12 @@ possible to specify use of a random identifier ([ietf-ip.yang][2] and
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set autoconf create-temporary-addresses true</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:b705:8374:638e:74a8/64 (random)
ipv6 fe80::ad3d:b274:885a:9ffb/64 (random)
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
+66 -66
View File
@@ -87,34 +87,34 @@ Like other interfaces, link aggregates are also available in the general
interfaces overview in the CLI admin-exec context. Here is the above
static mode aggregate:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
.
.
.
lag0 lag UP static: balance-xor, hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE
└ eth8 lag ACTIVE
lag0 lag UP static: balance-xor, hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE
└ eth8 lag ACTIVE
</code></pre>
Same aggregate, but in LACP mode:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
.
.
.
lag0 lag UP lacp: active, rate: fast (1s), hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
└ eth8 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
lag0 lag UP lacp: active, rate: fast (1s), hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
└ eth8 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
</code></pre>
@@ -124,45 +124,45 @@ In addition to basic status shown in the interface overview, detailed
LAG status can be inspected:
<pre class="cli"><code>admin@example:/> <b>show interface lag0</b>
name : lag0
index : 25
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : static
lag type : balance-xor
lag hash : layer2
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 0
out-octets : 2142
name : lag0
index : 25
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : static
lag type : balance-xor
lag hash : layer2
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 0
out-octets : 2142
</code></pre>
Same aggregate, but in LACP mode:
<pre class="cli"><code>admin@example:/> <b>show interface lag0</b>
name : lag0
index : 24
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : lacp
lag hash : layer2
lacp mode : active
lacp rate : fast (1s)
lacp aggregate id : 1
name : lag0
index : 24
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : lacp
lag hash : layer2
lacp mode : active
lacp rate : fast (1s)
lacp aggregate id : 1
lacp system priority: 65535
lacp actor key : 9
lacp partner key : 9
lacp partner mac : 00:a0:85:00:03:00
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 100892
out-octets : 111776
lacp actor key : 9
lacp partner key : 9
lacp partner mac : 00:a0:85:00:03:00
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 100892
out-octets : 111776
</code></pre>
Member ports provide additional status information:
@@ -184,21 +184,21 @@ Member ports provide additional status information:
Example member port status:
<pre class="cli"><code>admin@example:/> <b>show interface eth7</b>
name : eth7
index : 8
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag member : lag0
lag member state : active
lacp aggregate id : 1
lacp actor state : active, short_timeout, aggregating, in_sync, collecting, distributing
lacp partner state : active, short_timeout, aggregating, in_sync, collecting, distributing
link failure count : 0
ipv4 addresses :
ipv6 addresses :
in-octets : 473244
out-octets : 499037
name : eth7
index : 8
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag member : lag0
lag member state : active
lacp aggregate id : 1
lacp actor state : active, short_timeout, aggregating, in_sync, collecting, distributing
lacp partner state : active, short_timeout, aggregating, in_sync, collecting, distributing
link failure count : 0
ipv4 addresses :
ipv6 addresses :
in-octets : 473244
out-octets : 499037
</code></pre>
+5 -5
View File
@@ -109,13 +109,13 @@ CLI can be entered from shell in the same way as for SSH.
See the 'help' command for an introduction to the system
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
e1 ethernet LOWER-DOWN 00:53:00:06:03:01
e2 ethernet LOWER-DOWN 00:53:00:06:03:02
e1 ethernet LOWER-DOWN 00:53:00:06:03:01
e2 ethernet LOWER-DOWN 00:53:00:06:03:02
...
admin@example:/>
</code></pre>
+1 -1
View File
@@ -47,7 +47,7 @@ other traffic would be bridged as usual.
|----------|----------------------------|--------------------------------------------------------------|
| [bridge](bridging.md) | infix-if-bridge | SW implementation of an IEEE 802.1Q bridge |
| [ip](ip.md) | ietf-ip, infix-ip | IP address to the subordinate interface |
| [vlan](ethernet.md#vlan-interfaces) | infix-if-vlan | Capture all traffic belonging to a specific 802.1Q VID |
| [vlan](vlan.md) | infix-if-vlan | Capture all traffic belonging to a specific 802.1Q VID |
| [lag](lag.md) | infix-if-lag | Link aggregation, static and IEEE 802.3ad (LACP) |
| lo | ietf-interfaces | Software loopback interface |
| [eth](ethernet.md#physical-ethernet-interfaces) | ieee802-ethernet-interface | Physical Ethernet device/port |
+61 -61
View File
@@ -39,20 +39,20 @@ Starting out, we assume a configuration where all ports are network
interfaces (possibly with IPv6 enabled).
```
admin@example:/> show interfaces
lo ethernet UP 00:00:00:00:00:00
admin@example:/> show interface
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
e1 ethernet LOWER-DOWN 00:53:00:06:11:01
e2 ethernet LOWER-DOWN 00:53:00:06:11:02
e3 ethernet LOWER-DOWN 00:53:00:06:11:03
e4 ethernet LOWER-DOWN 00:53:00:06:11:04
e5 ethernet LOWER-DOWN 00:53:00:06:11:05
e6 ethernet LOWER-DOWN 00:53:00:06:11:06
e7 ethernet LOWER-DOWN 00:53:00:06:11:07
e8 ethernet LOWER-DOWN 00:53:00:06:11:08
e9 ethernet LOWER-DOWN 00:53:00:06:11:09
e10 ethernet UP 00:53:00:06:11:0a
e1 ethernet LOWER-DOWN 00:53:00:06:11:01
e2 ethernet LOWER-DOWN 00:53:00:06:11:02
e3 ethernet LOWER-DOWN 00:53:00:06:11:03
e4 ethernet LOWER-DOWN 00:53:00:06:11:04
e5 ethernet LOWER-DOWN 00:53:00:06:11:05
e6 ethernet LOWER-DOWN 00:53:00:06:11:06
e7 ethernet LOWER-DOWN 00:53:00:06:11:07
e8 ethernet LOWER-DOWN 00:53:00:06:11:08
e9 ethernet LOWER-DOWN 00:53:00:06:11:09
e10 ethernet UP 00:53:00:06:11:0a
ipv6 fe80::0053:00ff:fe06:110a/64 (link-layer)
admin@example:/>
```
@@ -80,7 +80,7 @@ admin@example:/config/> set interface e10 bridge-port bridge br0
admin@example:/config/>
```
The interface status can be viewed using `show interfaces` after leaving
The interface status can be viewed using `show interface` after leaving
configuration context. When configuring via SSH, first assign an IP
address to `br0` *before leaving* configuration context, e.g.
@@ -95,10 +95,10 @@ setup, including [setting IP address](#set-ip-address).
```
admin@example:/config/> leave
admin@example:/>
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
br0 bridge
│ ethernet UP 00:53:00:06:11:01
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge LOWER-DOWN
├ e2 bridge LOWER-DOWN
├ e3 bridge LOWER-DOWN
@@ -109,7 +109,7 @@ br0 bridge
├ e8 bridge LOWER-DOWN
├ e9 bridge LOWER-DOWN
└ e10 bridge FORWARDING
lo ethernet UP 00:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -154,21 +154,21 @@ admin@example:/>
Interface status would now should something like the following
```
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
br0 bridge
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge LOWER-DOWN vlan:10u pvid:10
├ e2 bridge LOWER-DOWN vlan:10u pvid:10
├ e3 bridge LOWER-DOWN vlan:20u pvid:20
├ e4 bridge LOWER-DOWN vlan:20u pvid:20
├ e5 bridge LOWER-DOWN vlan:30u pvid:30
├ e6 bridge LOWER-DOWN vlan:30u pvid:30
├ e7 bridge LOWER-DOWN vlan:40u pvid:40
├ e8 bridge LOWER-DOWN vlan:40u pvid:40
├ e9 bridge LOWER-DOWN vlan:50u pvid:50
└ e10 bridge FORWARDING vlan:50u pvid:50
lo ethernet UP 00:00:00:00:00:00
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge LOWER-DOWN vlan:10u pvid: 10
├ e2 bridge LOWER-DOWN vlan:10u pvid: 10
├ e3 bridge LOWER-DOWN vlan:20u pvid: 20
├ e4 bridge LOWER-DOWN vlan:20u pvid: 20
├ e5 bridge LOWER-DOWN vlan:30u pvid: 30
├ e6 bridge LOWER-DOWN vlan:30u pvid: 30
├ e7 bridge LOWER-DOWN vlan:40u pvid: 40
├ e8 bridge LOWER-DOWN vlan:40u pvid: 40
├ e9 bridge LOWER-DOWN vlan:50u pvid: 50
└ e10 bridge FORWARDING vlan:50u pvid: 50
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -181,21 +181,21 @@ patched according to [above](#vlan-snake). We should see link up and
*FORWARDING* on all ports in the bridge.
```
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
br0 bridge
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge FORWARDING vlan:10u pvid:10
├ e2 bridge FORWARDING vlan:10u pvid:10
├ e3 bridge FORWARDING vlan:20u pvid:20
├ e4 bridge FORWARDING vlan:20u pvid:20
├ e5 bridge FORWARDING vlan:30u pvid:30
├ e6 bridge FORWARDING vlan:30u pvid:30
├ e7 bridge FORWARDING vlan:40u pvid:40
├ e8 bridge FORWARDING vlan:40u pvid:40
├ e9 bridge FORWARDING vlan:50u pvid:50
└ e10 bridge FORWARDING vlan:50u pvid:50
lo ethernet UP 00:00:00:00:00:00
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge FORWARDING vlan:10u pvid: 10
├ e2 bridge FORWARDING vlan:10u pvid: 10
├ e3 bridge FORWARDING vlan:20u pvid: 20
├ e4 bridge FORWARDING vlan:20u pvid: 20
├ e5 bridge FORWARDING vlan:30u pvid: 30
├ e6 bridge FORWARDING vlan:30u pvid: 30
├ e7 bridge FORWARDING vlan:40u pvid: 40
├ e8 bridge FORWARDING vlan:40u pvid: 40
├ e9 bridge FORWARDING vlan:50u pvid: 50
└ e10 bridge FORWARDING vlan:50u pvid: 50
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
@@ -284,26 +284,26 @@ admin@example:/>
Interface *vlan10* with an auto-configured IPv6 address should appear.
```
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
br0 bridge vlan:10t
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge FORWARDING vlan:10u pvid:10
├ e2 bridge FORWARDING vlan:10u pvid:10
├ e3 bridge FORWARDING vlan:20u pvid:20
├ e4 bridge FORWARDING vlan:20u pvid:20
├ e5 bridge FORWARDING vlan:30u pvid:30
├ e6 bridge FORWARDING vlan:30u pvid:30
├ e7 bridge FORWARDING vlan:40u pvid:40
├ e8 bridge FORWARDING vlan:40u pvid:40
├ e9 bridge FORWARDING vlan:50u pvid:50
└ e10 bridge FORWARDING vlan:50u pvid:50
lo ethernet UP 00:00:00:00:00:00
│ ethernet UP 00:53:00:06:11:01
├ e1 bridge FORWARDING vlan:10u pvid: 10
├ e2 bridge FORWARDING vlan:10u pvid: 10
├ e3 bridge FORWARDING vlan:20u pvid: 20
├ e4 bridge FORWARDING vlan:20u pvid: 20
├ e5 bridge FORWARDING vlan:30u pvid: 30
├ e6 bridge FORWARDING vlan:30u pvid: 30
├ e7 bridge FORWARDING vlan:40u pvid: 40
├ e8 bridge FORWARDING vlan:40u pvid: 40
├ e9 bridge FORWARDING vlan:50u pvid: 50
└ e10 bridge FORWARDING vlan:50u pvid: 50
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
vlan10 ethernet UP 00:53:00:06:11:01
vlan10 ethernet UP 00:53:00:06:11:01
│ ipv6 fe80::0053:00ff:fe06:1101/64 (link-layer)
└ br0 ethernet UP 00:53:00:06:11:01
└ br0 ethernet UP 00:53:00:06:11:01
admin@example:/>
```
+89
View File
@@ -0,0 +1,89 @@
# VLAN Interfaces
A VLAN interface is an interface stacked on top of another Linux interface
that filters traffic for a single 802.1Q VID. `tcpdump` on a VLAN interface
shows only frames matching that VID, compared to *all* VIDs when listening
on the lower-layer interface.
![VLAN interface on top of Ethernet or Bridge interfaces](img/interface-vlan-variants.svg)
This page covers VLAN interfaces stacked on Ethernet, on a VLAN-filtering
bridge, and on other VLAN interfaces. For VLAN handling *inside* a bridge
(port VIDs, tagged/untagged membership, pvid), see [VLAN Filtering
Bridge](bridging.md#vlan-filtering-bridge).
## On Top of an Ethernet Interface
A VLAN interface for VID 20 on top of an Ethernet interface `eth0` is by
convention named `eth0.20`.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0.20</b>
admin@example:/config/interface/eth0.20/> <b>show</b>
type vlan;
vlan {
tag-type c-vlan;
id 20;
lower-layer-if eth0;
}
admin@example:/config/interface/eth0.20/> <b>leave</b>
</code></pre>
The `tag-type` defaults to `c-vlan` (802.1Q customer VLAN, EtherType 0x8100).
Set to `s-vlan` (802.1ad service VLAN, EtherType 0x88A8) to terminate an outer
S-Tag.
> [!TIP]
> If you name your VLAN interface `foo0.N` or `vlanN`, where `N` is a
> number, the CLI infers the interface type automatically. Otherwise
> the type must be set explicitly.
## On Top of a Bridge
When the lower-layer interface is a VLAN-filtering bridge, the VLAN interface
gives the CPU an IP-addressable endpoint inside the bridged broadcast domain
for that VID. This pattern is named `vlanN` by convention.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface vlan10</b>
admin@example:/config/interface/vlan10/> <b>set vlan id 10</b>
admin@example:/config/interface/vlan10/> <b>set vlan lower-layer-if br0</b>
admin@example:/config/interface/vlan10/> <b>leave</b>
</code></pre>
The bridge `br0` must have VLAN 10 configured with the bridge itself as a
tagged member. See [VLAN Filtering Bridge](bridging.md#vlan-filtering-bridge)
for the bridge-side configuration.
## Stacked (Q-in-Q)
VLAN interfaces can be stacked. A VLAN interface whose lower-layer is itself
a VLAN interface terminates the inner tag, leaving the outer tag for the
parent to handle.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0.10</b>
admin@example:/config/interface/eth0.10/> <b>set vlan tag-type s-vlan</b>
admin@example:/config/interface/eth0.10/> <b>leave</b>
admin@example:/config/> <b>edit interface eth0.10.20</b>
admin@example:/config/interface/eth0.10.20/> <b>show</b>
type vlan;
vlan {
tag-type c-vlan;
id 20;
lower-layer-if eth0.10;
}
admin@example:/config/interface/eth0.10.20/> <b>leave</b>
</code></pre>
The summary view shows each VLAN row pointing at its immediate parent:
<pre class="cli"><code>admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0.10 vlan UP vid: 10
│ ipv4 10.0.10.1/24 (static)
└ eth0
eth0.10.20 vlan UP vid: 20
│ ipv4 10.0.10.20/28 (static)
└ eth0.10
</code></pre>
+7 -7
View File
@@ -345,17 +345,17 @@ tunnel endpoints use IPv4 or IPv6.
Check WireGuard interface status and peer connections:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<pre class="cli"><code>admin@example:/> <b>show interface</b>
wg0 wireguard UP 2 peers (1 up)
ipv4 10.0.0.1/24 (static)
ipv6 fd00::1/64 (static)
admin@example:/> <b>show interfaces wg0</b>
name : wg0
type : wireguard
index : 12
operational status : up
peers : 2
admin@example:/> <b>show interface wg0</b>
name : wg0
type : wireguard
index : 12
operational status : up
peers : 2
Peer 1:
status : UP
+23 -23
View File
@@ -223,22 +223,22 @@ access-point).
Use `show interface` to see discovered networks and their signal strength:
<pre class="cli"><code>admin@example:/> <b>show interface wifi0</b>
name : wifi0
type : wifi
index : 3
mtu : 1500
operational status : up
ip forwarding : enabled
physical address : f0:09:0d:36:5f:86
ipv4 addresses : 192.168.1.100/24 (dhcp)
ipv6 addresses :
in-octets : 148388
out-octets : 24555
mode : station
ssid : MyNetwork
signal : -45 dBm (good)
rx bitrate : 72.2 Mbps
tx bitrate : 86.6 Mbps
name : wifi0
type : wifi
index : 3
mtu : 1500
operational status : up
ip forwarding : enabled
physical address : f0:09:0d:36:5f:86
ipv4 addresses : 192.168.1.100/24 (dhcp)
ipv6 addresses :
in-octets : 148388
out-octets : 24555
mode : station
ssid : MyNetwork
signal : -45 dBm (good)
rx bitrate : 72.2 Mbps
tx bitrate : 86.6 Mbps
──────────────────────────────────────────────────────────────────────
<span class="title">Available Networks</span>
<span class="header">SSID BSSID SECURITY SIGNAL CHANNEL</span>
@@ -304,13 +304,13 @@ admin@example:/config/interface/wifi0/> <b>leave</b>
The connection attempt will start immediately. You can verify the connection status:
<pre class="cli"><code>admin@example:/> <b>show interface wifi0</b>
name : wifi0
type : wifi
operational status : up
physical address : f0:09:0d:36:5f:86
mode : station
ssid : MyHomeNetwork
signal : -52 dBm (good)
name : wifi0
type : wifi
operational status : up
physical address : f0:09:0d:36:5f:86
mode : station
ssid : MyHomeNetwork
signal : -52 dBm (good)
</code></pre>
**Station configuration parameters:**
+1
View File
@@ -33,6 +33,7 @@ nav:
- Bridging: bridging.md
- Link Aggregation: lag.md
- Ethernet Interfaces: ethernet.md
- VLAN Interfaces: vlan.md
- IP Addressing: ip.md
- Routing: routing.md
- Firewall Configuration: firewall.md
+5 -1
View File
@@ -283,6 +283,7 @@ static void rmtmp(const char *path)
static void sysrepo_print_error(sr_session_ctx_t *sess)
{
const sr_error_info_t *erri = NULL;
const char *msg;
int err;
if (!sess)
@@ -292,7 +293,10 @@ static void sysrepo_print_error(sr_session_ctx_t *sess)
if (err || !erri || !erri->err_count)
return;
warnx("%s (%d)", erri->err->message, erri->err->err_code);
msg = erri->err->message;
if (!msg)
msg = sr_strerror(erri->err->err_code);
warnx("%s (%d)", msg, erri->err->err_code);
}
/* Connect to sysrepo and create NACM-aware session on running datastore */
+23 -17
View File
@@ -17,17 +17,18 @@ def get_json(xpath: str, datastore: str = "operational", quiet: bool = False) ->
print("Invalid XPATH. It must be a valid string starting with '/'.")
return {}
try:
result = subprocess.run(["copy", datastore, "-x", shlex.quote(xpath)],
capture_output=True, text=True, check=True)
if not result.stdout.strip():
return {}
json_data = json.loads(result.stdout)
return json_data
except subprocess.CalledProcessError as e:
if not quiet:
print(f"Error running copy: {e}")
result = subprocess.run(["copy", datastore, "-x", shlex.quote(xpath)],
capture_output=True, text=True)
if result.returncode != 0:
# copy already wrote a 'failed retrieving …' message (and a
# sysrepo error line) to stderr; relay it verbatim.
if not quiet and result.stderr:
print(result.stderr.rstrip())
return {}
if not result.stdout.strip():
return {}
try:
return json.loads(result.stdout)
except json.JSONDecodeError as e:
if not quiet:
print(f"Error parsing JSON output: {e}")
@@ -40,15 +41,20 @@ def cli_pretty(json_data: dict, command: str, *args: str):
return
safe_args = [shlex.quote(arg) for arg in args]
json_input = json.dumps(json_data)
result = subprocess.run([
"/usr/libexec/statd/cli-pretty", command, *safe_args
], input=json_input, capture_output=True, text=True)
try:
json_input = json.dumps(json_data) # Keep as string, not bytes
result = subprocess.run([
"/usr/libexec/statd/cli-pretty", command, *safe_args
], input=json_input, capture_output=True, text=True, check=True)
# cli-pretty prints a user-facing message on stdout before any
# sys.exit(1) (e.g. 'Interface "w" not found'). Relay it regardless
# of the exit status, and only surface the generic exec error when
# nothing useful was produced.
if result.stdout:
print(result.stdout, end="")
except subprocess.CalledProcessError as e:
print(f"Error running cli-pretty: {e}")
elif result.returncode != 0:
msg = result.stderr.strip() or f"exit status {result.returncode}"
print(f"Error running cli-pretty: {msg}")
def dhcp(args: List[str]) -> None:
+2 -1
View File
@@ -1,6 +1,6 @@
AC_PREREQ(2.61)
# confd version is same as system YANG model version, step on breaking changes
AC_INIT([confd], [1.8], [https://github.com/kernelkit/infix/issues])
AC_INIT([confd], [1.9], [https://github.com/kernelkit/infix/issues])
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
AM_SILENT_RULES(yes)
@@ -22,6 +22,7 @@ AC_CONFIG_FILES([
share/migrate/1.6/Makefile
share/migrate/1.7/Makefile
share/migrate/1.8/Makefile
share/migrate/1.9/Makefile
yang/Makefile
yang/confd/Makefile
yang/test-mode/Makefile
+66
View File
@@ -0,0 +1,66 @@
#!/bin/sh
# Migrate fixed-speed ethernet configs to auto-negotiation/advertised-pmd-types.
#
# IEEE Std 802.3.2-2025 obsoleted the ieee802-ethernet-interface speed leaf,
# leaving no standards-blessed config-true location to pin a port to a fixed
# speed. Infix expresses the same intent via a new infix-augmented
# 'advertised-pmd-types' leaf-list inside the auto-negotiation container: when
# the list names exactly one PMD type, the link comes up at that mode against
# any cooperating peer — the standards-correct interpretation of "fixed speed".
#
# Rewrites
# ethernet { auto-negotiation { enable false; } speed S; duplex D; }
# into
# ethernet { auto-negotiation { enable false;
# advertised-pmd-types [PMD]; } duplex D; }
# where PMD is derived from (S, D) using a static lookup table. D and
# enable=false are preserved verbatim — confd's apply path treats
# enable=false plus a single advertised-pmd-types entry as "force
# autoneg off and pin to this speed/duplex", matching the legacy
# semantics for link partners that don't run auto-negotiation.
#
# Interfaces that don't disable auto-negotiation, or that lack a speed leaf,
# are left untouched.
file=$1
temp=${file}.tmp
#
# The (speed Gb/s, copper-T-implicit-duplex) → PMD table below is a subset
# of the canonical map in src/statd/python/yanger/ietf_interfaces/ethernet.py
# (_LINK_MODES, key by (port, speed, duplex)). Migrate only covers the
# copper-T cases that the old legacy syntax supported in the first place;
# fiber/DAC pinning was never expressible via the deprecated speed leaf.
#
jq '
def speed_to_pmd:
if . == "0.01" then "ieee802-ethernet-phy-type:pmd-type-10BASE-T"
elif . == "0.1" then "ieee802-ethernet-phy-type:pmd-type-100BASE-TX"
elif . == "1.0" then "ieee802-ethernet-phy-type:pmd-type-1000BASE-T"
elif . == "2.5" then "ieee802-ethernet-phy-type:pmd-type-2.5GBASE-T"
elif . == "5.0" then "ieee802-ethernet-phy-type:pmd-type-5GBASE-T"
elif . == "10.0" then "ieee802-ethernet-phy-type:pmd-type-10GBASE-T"
else null
end;
(.["ietf-interfaces:interfaces"].interface // [])
|= [ .[] |
. as $iface
| if ($iface["ieee802-ethernet-interface:ethernet"]?
["auto-negotiation"]?.enable == false)
and ($iface["ieee802-ethernet-interface:ethernet"]?.speed != null)
then
($iface["ieee802-ethernet-interface:ethernet"].speed | speed_to_pmd) as $pmd
| if $pmd == null then
$iface # leave unmappable speeds alone; admin must fix
else
$iface
| .["ieee802-ethernet-interface:ethernet"]
["auto-negotiation"]
+= {"infix-ethernet-interface:advertised-pmd-types": [$pmd]}
| del(.["ieee802-ethernet-interface:ethernet"].speed)
end
else
$iface
end ]
' "$file" > "$temp" && mv "$temp" "$file"
+2
View File
@@ -0,0 +1,2 @@
migratedir = $(pkgdatadir)/migrate/1.9
dist_migrate_DATA = 10-ethernet-advertise.sh
+1 -1
View File
@@ -1,2 +1,2 @@
SUBDIRS = 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8
SUBDIRS = 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9
migratedir = $(pkgdatadir)/migrate
+216 -42
View File
@@ -2,9 +2,12 @@
#include <fnmatch.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <jansson.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <srx/common.h>
#include <srx/lyx.h>
@@ -12,18 +15,96 @@
#include "interfaces.h"
/*
* Map IEEE pmd-type identity suffixes (everything after
* "ieee802-ethernet-phy-type:pmd-type-") to the Linux
* ETHTOOL_LINK_MODE_*_BIT_* indices that ethtool's --advertise mask
* uses. Half/full are separate bits in the kernel API but a single
* PMD identity in IEEE; the half_bit field is -1 for PMDs that have
* no half-duplex variant (everything past 1G).
*
* Where the kernel collapses several IEEE variants into one
* "family" bit (e.g. 1000baseX covers LX/SX/ZX/CX) the same bit
* appears in multiple rows by design — selecting any of them yields
* the same on-wire behaviour because ethtool can't distinguish them
* either.
*/
struct pmd_link_mode {
const char *pmd;
int speed_mbps;
int half_bit;
int full_bit;
};
#define NO_BIT (-1)
static const struct pmd_link_mode pmd_link_modes[] = {
{"10BASE-T", 10, ETHTOOL_LINK_MODE_10baseT_Half_BIT,
ETHTOOL_LINK_MODE_10baseT_Full_BIT},
{"100BASE-TX", 100, ETHTOOL_LINK_MODE_100baseT_Half_BIT,
ETHTOOL_LINK_MODE_100baseT_Full_BIT},
{"100BASE-FX", 100, NO_BIT, ETHTOOL_LINK_MODE_100baseFX_Full_BIT},
{"1000BASE-T", 1000, ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
/* 1000baseX_Full covers the LX/SX/ZX/CX family in the kernel —
* the API can't distinguish them; selecting any yields the same
* on-wire behaviour. */
{"1000BASE-LX", 1000, NO_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT},
{"1000BASE-SX", 1000, NO_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT},
{"1000BASE-ZX", 1000, NO_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT},
{"1000BASE-CX", 1000, NO_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT},
{"2.5GBASE-T", 2500, NO_BIT, ETHTOOL_LINK_MODE_2500baseT_Full_BIT},
{"2.5GBASE-X", 2500, NO_BIT, ETHTOOL_LINK_MODE_2500baseX_Full_BIT},
{"5GBASE-T", 5000, NO_BIT, ETHTOOL_LINK_MODE_5000baseT_Full_BIT},
{"10GBASE-T", 10000, NO_BIT, ETHTOOL_LINK_MODE_10000baseT_Full_BIT},
{"10GBASE-SR", 10000, NO_BIT, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT},
{"10GBASE-LR", 10000, NO_BIT, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT},
{"10GBASE-LRM", 10000, NO_BIT, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT},
{"10GBASE-ER", 10000, NO_BIT, ETHTOOL_LINK_MODE_10000baseER_Full_BIT},
/* SFP+ DAC has no standardised IEEE pmd-type identity for 10G;
* users can't restrict advertise to DAC-only at this rate. */
{"25GBASE-CR", 25000, NO_BIT, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT},
{"25GBASE-SR", 25000, NO_BIT, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT},
/* Kernel collapses LR/SR onto the same 25G bit. */
{"25GBASE-LR", 25000, NO_BIT, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT},
{"40GBASE-CR4", 40000, NO_BIT, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT},
{"40GBASE-SR4", 40000, NO_BIT, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT},
{"40GBASE-LR4", 40000, NO_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
{"100GBASE-CR4", 100000, NO_BIT, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT},
{"100GBASE-SR4", 100000, NO_BIT, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT},
{"100GBASE-LR4", 100000, NO_BIT, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT},
{NULL, 0, NO_BIT, NO_BIT}
};
static const struct pmd_link_mode *pmd_lookup(const char *identity)
{
const char *suffix;
const struct pmd_link_mode *m;
if (!identity)
return NULL;
suffix = strchr(identity, ':');
suffix = suffix ? suffix + 1 : identity;
if (strncmp(suffix, "pmd-type-", 9) == 0)
suffix += 9;
for (m = pmd_link_modes; m->pmd; m++) {
if (strcmp(m->pmd, suffix) == 0)
return m;
}
return NULL;
}
static bool iface_uses_autoneg(struct lyd_node *cif)
{
struct lyd_node *aneg = lydx_get_descendant(lyd_child(cif), "ethernet",
"auto-negotiation", NULL);
/* Because `ieee802-ethernet-interface` declares
* `auto-negotiation` as a presence container, the `enabled`
* leaf, although `true` by default, is not set if the whole
* container is absent. Since auto-negotiation is the expected
* default behavior for most Ethernet links, we choose to
* enable it in these situations.
*/
/* `auto-negotiation` is a presence container; when absent the port
* auto-negotiates (the modern default). When present, `enable`
* defaults to true and is materialised in the config tree, so
* lydx_get_bool() reads it correctly. */
return !aneg || lydx_get_bool(aneg, "enable");
}
@@ -60,13 +141,42 @@ static int netdag_gen_ethtool_flow_control(struct dagger *net, struct lyd_node *
return 0;
}
/* Walk the advertised-pmd-types leaf-list + duplex constraint, OR matching
* bits into *mask. *unmapped is filled with the first identity suffix we
* didn't recognise so the caller can produce a useful sysrepo error.
*/
static void pmd_list_to_mask(struct lyd_node *aneg, const char *duplex,
uint64_t *mask, const char **unmapped)
{
struct lyd_node *node;
*mask = 0;
LYX_LIST_FOR_EACH(lyd_child(aneg), node, "advertised-pmd-types") {
const char *id = lyd_get_value(node);
const struct pmd_link_mode *m = pmd_lookup(id);
if (!m) {
if (*unmapped == NULL)
*unmapped = id;
continue;
}
if ((!duplex || strcmp(duplex, "half") == 0) && m->half_bit != NO_BIT)
*mask |= (1ULL << m->half_bit);
if ((!duplex || strcmp(duplex, "full") == 0) && m->full_bit != NO_BIT)
*mask |= (1ULL << m->full_bit);
}
}
static int netdag_gen_ethtool_autoneg(struct dagger *net, struct lyd_node *cif)
{
struct lyd_node *eth = lydx_get_child(cif, "ethernet");
struct lyd_node *aneg = lydx_get_child(eth, "auto-negotiation");
const char *ifname = lydx_get_cattr(cif, "name");
enum netdag_init phase = NETDAG_INIT_PHYS;
const char *speed, *duplex;
int mbps, err = 0;
const char *duplex, *mdix, *unmapped = NULL;
const char *mdix_arg = "";
uint64_t mask = 0;
int err = 0;
FILE *fp;
if (iface_has_quirk(ifname, "broken-autoneg"))
@@ -79,45 +189,109 @@ static int netdag_gen_ethtool_autoneg(struct dagger *net, struct lyd_node *cif)
if (!fp)
return -EIO;
fprintf(fp, "[[ -n $(ethtool --json %s | jq '.[] | select(.\"supports-auto-negotiation\" == false)') ]] && exit 0\n", ifname);
if (iface_uses_autoneg(cif)) {
fprintf(fp, "[[ -n $(ethtool --json %s | jq '.[] | select(.\"supports-auto-negotiation\" == false)') ]] && exit 0\n", ifname);
fprintf(fp, "ethtool --change %s autoneg on", ifname);
} else {
speed = lydx_get_cattr(eth, "speed");
if (!speed) {
sr_session_set_error_message(net->session, "%s: "
"\"speed\" must be specified "
"when auto-negotiation is disabled", ifname);
duplex = lydx_get_cattr(eth, "duplex");
/* MDI/MDI-X pinout. The `mdi-x` boolean has no default, so an absent
* leaf (read as NULL here, hence lydx_get_cattr not lydx_get_bool) means
* Auto-MDIX — emit nothing, leaving the PHY alone and not poking drivers
* that reject the `mdix` arg. ethtool's `mdix on` is MDI-X (crossover),
* `off` is MDI. */
mdix = lydx_get_cattr(eth, "mdi-x");
if (mdix && !strcmp(mdix, "true"))
mdix_arg = " mdix on";
else if (mdix && !strcmp(mdix, "false"))
mdix_arg = " mdix off";
/* enable=false: force a fixed speed/duplex with autoneg off, for link
* partners that don't run autoneg (legacy fixed-speed switches, some
* back-to-back direct copper links). Standards-correct fixed-mode is
* advertised-pmd-types with autoneg on; this branch is the escape
* hatch for peers that won't even speak autoneg. Requires exactly one
* advertised-pmd-types entry — that PMD picks the speed; duplex comes
* from the explicit leaf or defaults to the only variant available.
*/
if (aneg && !lydx_get_bool(aneg, "enable")) {
const struct pmd_link_mode *forced = NULL;
const char *fixed_duplex;
struct lyd_node *node;
int n = 0;
LYX_LIST_FOR_EACH(lyd_child(aneg), node, "advertised-pmd-types") {
const char *id = lyd_get_value(node);
const struct pmd_link_mode *m = pmd_lookup(id);
if (!m) {
if (!unmapped)
unmapped = id;
} else if (!forced) {
forced = m;
}
n++;
}
if (unmapped) {
sr_session_set_error_message(net->session,
"%s: advertised-pmd-types entry \"%s\" is not a known PMD type",
ifname, unmapped);
err = -EINVAL;
goto out;
}
if (n != 1) {
sr_session_set_error_message(net->session,
"%s: auto-negotiation/enable=false requires exactly one "
"advertised-pmd-types entry (have %d)", ifname, n);
err = -EINVAL;
goto out;
}
mbps = (int)(atof(speed) * 1000.);
if (!((mbps == 10) || (mbps == 100))) {
sr_session_set_error_message(net->session, "%s: "
"\"speed\" must be either 0.01 or 0.1 "
"when auto-negotiation is disabled", ifname);
err = -EINVAL;
goto out;
}
if (duplex)
fixed_duplex = duplex;
else if (forced->full_bit != NO_BIT)
fixed_duplex = "full";
else
fixed_duplex = "half";
duplex = lydx_get_cattr(eth, "duplex");
if (!duplex || (strcmp(duplex, "full") && strcmp(duplex, "half"))) {
sr_session_set_error_message(net->session, "%s: "
"\"duplex\" must be either "
"\"full\" or \"half\" "
"when auto-negotiation is disabled", ifname);
err = -EINVAL;
goto out;
}
fprintf(fp,"ethtool --change %s autoneg off speed %d duplex %s\n", ifname, mbps, duplex);
fprintf(fp, "ethtool --change %s autoneg off speed %d duplex %s%s\n",
ifname, forced->speed_mbps, fixed_duplex, mdix_arg);
goto out;
}
if (aneg)
pmd_list_to_mask(aneg, duplex, &mask, &unmapped);
if (unmapped) {
sr_session_set_error_message(net->session,
"%s: advertised-pmd-types entry \"%s\" is not a known PMD type",
ifname, unmapped);
err = -EINVAL;
goto out;
}
if (mask) {
/* Restrict autoneg to the advertised set (single entry == fixed). */
fprintf(fp, "ethtool --change %s autoneg on advertise 0x%" PRIx64 "%s\n",
ifname, mask, mdix_arg);
} else {
/* No advertise restriction configured → advertise everything the
* PHY supports. Plain `autoneg on` is a no-op when autoneg is
* already enabled and does NOT restore a previously narrowed
* advertise mask, so query supported and re-enable each mode.
* ethtool's symbolic advertise syntax is bare NAME on|off pairs
* (despite what `--help` suggests, there is no `mode` keyword). */
fprintf(fp,
"args=$(ethtool --json %s | jq -r '.[0][\"supported-link-modes\"][]? | \"\\(.) on\"' | tr '\\n' ' ')\n"
"if [ -n \"$args\" ]; then\n"
"\tethtool --change %s autoneg on advertise $args%s\n"
"else\n"
"\tethtool --change %s autoneg on%s\n"
"fi\n",
ifname, ifname, mdix_arg, ifname, mdix_arg);
}
out:
fclose(fp);
return err;
}
int netdag_gen_ethtool(struct dagger *net, struct lyd_node *cif, struct lyd_node *dif)
@@ -129,16 +303,16 @@ int netdag_gen_ethtool(struct dagger *net, struct lyd_node *cif, struct lyd_node
return 0;
if (dagger_is_bootstrap(net) ||
lydx_get_descendant(lyd_child(eth), "auto-negotiation", "enable", NULL)) {
lydx_get_descendant(lyd_child(eth), "auto-negotiation", NULL)) {
err = netdag_gen_ethtool_flow_control(net, cif);
if (err)
return err;
}
if (dagger_is_bootstrap(net) ||
lydx_get_descendant(lyd_child(eth), "auto-negotiation", "enable", NULL) ||
lydx_get_child(eth, "speed") ||
lydx_get_child(eth, "duplex")) {
lydx_get_descendant(lyd_child(eth), "auto-negotiation", NULL) ||
lydx_get_child(eth, "duplex") ||
lydx_get_child(eth, "mdi-x")) {
err = netdag_gen_ethtool_autoneg(net, cif);
if (err)
return err;
+4 -3
View File
@@ -44,10 +44,11 @@ MODULES=(
"infix-meta@2025-12-10.yang"
"infix-system@2026-03-09.yang"
"infix-services@2026-03-20.yang"
"ieee802-ethernet-interface@2019-06-21.yang"
"infix-ethernet-interface@2024-02-27.yang"
"ieee802-ethernet-interface@2025-09-10.yang"
"ieee802-ethernet-phy-type@2025-09-10.yang"
"infix-ethernet-interface@2026-05-21.yang"
"infix-factory-default@2023-06-28.yang"
"infix-interfaces@2026-05-13.yang -e vlan-filtering"
"infix-interfaces@2026-05-18.yang -e vlan-filtering"
"ietf-crypto-types -e cleartext-symmetric-keys"
"infix-crypto-types@2026-02-14.yang"
"ietf-keystore -e symmetric-keys"
@@ -1,928 +0,0 @@
module ieee802-ethernet-interface {
yang-version 1.1;
namespace
"urn:ieee:std:802.3:yang:ieee802-ethernet-interface";
prefix ieee802-eth-if;
import ietf-yang-types {
prefix yang;
reference "IETF RFC 6991";
}
import ietf-interfaces {
prefix if;
reference "IETF RFC 8343";
}
import iana-if-type {
prefix ianaift;
reference "http://www.iana.org/assignments/yang-parameters/
iana-if-type@2018-07-03.yang";
}
organization
"IEEE Std 802.3 Ethernet Working Group
Web URL: http://www.ieee802.org/3/";
contact
"Web URL: http://www.ieee802.org/3/";
description
"This module contains YANG definitions for configuring IEEE Std
802.3 Ethernet Interfaces.
In this YANG module, 'Ethernet interface' can be interpreted
as referring to 'IEEE Std 802.3 compliant Ethernet
interfaces'.";
revision 2019-06-21{
description "Initial revision.";
reference "IEEE Std 802.3-2018, unless dated explicitly";
}
typedef eth-if-speed-type {
type decimal64 {
fraction-digits 3;
}
units "Gb/s";
description
"Used to represent the configured, negotiated, or actual speed
of an Ethernet interface in Gigabits per second (Gb/s),
accurate to 3 decimal places (i.e., accurate to 1 Mb/s).";
}
typedef duplex-type {
type enumeration {
enum full {
description
"Full duplex.";
}
enum half {
description
"Half duplex.";
}
enum unknown {
description
"Link is currently disconnected or initializing.";
}
}
default full;
description
"Used to represent the configured, negotiated, or actual
duplex mode of an Ethernet interface.";
reference "IEEE Std 802.3, 30.3.1.1.32, aDuplexStatus";
}
typedef pause-fc-direction-type {
type enumeration {
enum "disabled" {
description
"Flow-control disabled in both ingress and egress
directions, i.e., PAUSE frames are not transmitted and
PAUSE frames received in the ingress direction are
discarded without processing.";
}
enum "ingress-only" {
description
"PAUSE frame based flow control is enabled in the ingress
direction only, i.e., PAUSE frames may be transmitted to
reduce the ingress traffic flow, but PAUSE frames received
in the ingress direction are discarded without reducing
the egress traffic rate.";
}
enum "egress-only" {
description
"PAUSE frame based flow control is enabled in the egress
direction only, i.e., PAUSE frames are not transmitted,
but PAUSE frames received in the ingress direction are
processed to reduce the egress traffic rate.";
}
enum "bi-directional" {
description
"PAUSE frame based flow control is enabled in both ingress
and egress directions, i.e., PAUSE frames may be
transmitted to reduce the ingress traffic flow, and
PAUSE frames received on ingress are processed to reduce
the egress traffic rate.";
}
enum "undefined" {
description
"Link is currently disconnected or initializing.";
}
}
description
"Used to represent the configured, negotiated, or actual
PAUSE frame-based flow control setting.";
reference
"IEEE Std 802.3.1, dot3PauseAdminMode and dot3PauseOperMode";
}
feature ethernet-pfc {
description
"This device supports Ethernet priority flow-control.";
}
feature ethernet-pause {
description
"This device supports Ethernet PAUSE.";
}
augment "/if:interfaces/if:interface" {
when "derived-from-or-self(if:type, 'ianaift:ethernetCsmacd')" {
description
"Applies to all P2P Ethernet interfaces.";
}
description
"Augment interface model with Ethernet interface
specific configuration nodes.";
container ethernet {
description
"Contains all Ethernet interface related configuration.";
container auto-negotiation {
presence
"The presence of this container indicates that
auto-negotiation is supported on this Ethernet
interface.";
description
"Contains auto-negotiation transmission parameters
This container contains a data node that allows the
advertised duplex value in the negotiation to be
restricted.
If not specified then the default behavior for the duplex
data node is to negotiate all available values for the
particular type of Ethernet PHY associated with the
interface.
If auto-negotiation is enabled, and PAUSE frame based flow
control has not been explicitly configured, then the
default PAUSE frame based flow control capabilities that
are negotiated allow for bi-directional or egress-only
PAUSE frame based flow control.
If auto-negotiation is enabled, and PAUSE frame based flow
control has been explicitly configured, then the
configuration settings restrict the values that may be
negotiated. However, it should be noted that the protocol
does not allow only egress PAUSE frame based flow control
to be negotiated without also allowing bi-directional
PAUSE frame based flow control.";
reference
"IEEE Std 802.3, Clause 28 and Annexes 28A-D";
leaf enable {
type boolean;
default true;
description
"Controls whether auto-negotiation is enabled or
disabled.
For interface types that support auto-negotiation then
it defaults to being enabled.
For interface types that do not support auto-negotiation,
the related configuration data is ignored.";
}
leaf negotiation-status {
when "../enable = 'true'";
type enumeration {
enum in-progress {
description
"The auto-negotiation protocol is running and
negotiation is currently in-progress.";
}
enum complete {
description
"The auto-negotiation protocol has completed
successfully.";
}
enum failed {
description
"The auto-negotiation protocol has failed.";
}
enum unknown {
description
"The auto-negotiation status is not currently known,
this could be because it is still negotiating or the
protocol cannot run (e.g., if no medium is present).";
}
enum no-negotiation {
description
"No auto-negotiation is executed.
The auto-negotation function is either not supported
on this interface or has not been enabled.";
}
}
config false;
description
"The status of the auto-negotiation protocol.";
reference
"IEEE 802.3, 30.6.1.1.4, aAutoNegAutoConfig";
}
}
leaf duplex {
type duplex-type;
description
"Operational duplex mode of the Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.1.1.32 aDuplexStatus";
}
leaf speed {
type eth-if-speed-type;
units "Gb/s";
description
"Operational speed (data rate) of the Ethernet interface.
The default value is implementation-dependent.";
}
container flow-control {
description
"Holds the different types of Ethernet PAUSE frame based
flow control that can be enabled.";
container pause {
if-feature "ethernet-pause";
description
"IEEE Std 802.3 PAUSE frame based PAUSE frame based flow
control.";
reference
"IEEE Std 802.3, Annex 31B";
leaf direction {
type pause-fc-direction-type;
description
"Indicates which direction PAUSE frame based flow
control is enabled in, or whether it is disabled.
The default flow-control settings are vendor specific.
If auto-negotiation is enabled, then PAUSE based
flow-control is negotiated by default.
The default value is implementation-dependent.";
}
container statistics {
config false;
description
"Contains the number of PAUSE frames received or
transmitted.";
leaf in-frames-pause {
type yang:counter64;
units frames;
description
"A count of PAUSE MAC Control frames transmitted on
this Ethernet interface.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
reference
"IEEE Std 802.3, 30.3.4.3 aPAUSEMACCtrlFramesReceived";
}
leaf out-frames-pause {
type yang:counter64;
units frames;
description
"A count of PAUSE MAC Control frames transmitted on
this Ethernet interface.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
reference
"IEEE Std 802.3, 30.3.4.2
aPAUSEMACCtrlFramesTransmitted";
}
}
}
container pfc {
if-feature "ethernet-pfc";
description
"IEEE Std 802.3 Priority-based flow control.";
reference
"IEEE Std 802.3, Annex 31D";
leaf enable {
type boolean;
description
"True indicates that IEEE Std 802.3 priority-based
flow control is enabled, false indicates that
IEEE Std 802.3 priority-based flow control is disabled.
For interfaces that have auto-negotiation,
the priority-based flow control is enabled by default.";
}
container statistics {
config false;
description
"This container collects all statistics for
Ethernet interfaces.";
leaf in-frames-pfc {
type yang:counter64;
units frames;
description
"A count of PFC MAC Control frames received on this
Ethernet interface.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
reference
"IEEE Std 802.3.1, dot3HCInPFCFrames";
}
leaf out-frames-pfc {
type yang:counter64;
units frames;
description
"A count of PFC MAC Control frames transmitted on
this interface.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
reference
"IEEE Std 802.3.1, dot3HCInPFCFrames";
}
}
}
leaf force-flow-control {
type boolean;
default false;
description
"Explicitly forces the local PAUSE frame based flow control
settings regardless of what has been negotiated.
Since the auto-negotiation of flow-control settings
does not allow all sane combinations to be negotiated
(e.g., consider a device that is only capable of sending
PAUSE frames connected to a peer device that is only
capable of receiving and acting on PAUSE frames) and
failing to agree on the flow-control settings does not
cause the auto-negotiation to fail completely, then it is
sometimes useful to be able to explicitly enable
particular PAUSE frame based flow control settings on
the local device regardless of what is being advertised
or negotiated.";
reference
"IEEE Std 802.3, Table 28B-3";
}
}
leaf max-frame-length {
type uint16;
units octets;
config false;
description
"This indicates the MAC frame length (including FCS bytes)
at which frames are dropped for being too long.";
reference
"IEEE Std 802.3, 30.3.1.1.37 aMaxFrameLength";
}
leaf mac-control-extension-control {
type boolean;
config false;
description
"A value that identifies the current EXTENSION MAC Control
function, as specified in IEEE Std 802.3, Annex 31C.";
reference
"IEEE Std 802.3, 30.3.8.3 aEXTENSIONMACCtrlStatus
IEEE Std 802.3.1, dot3ExtensionMacCtrlStatus ";
}
leaf frame-limit-slow-protocol {
type uint64;
units f/s;
default 10;
config false;
description
"The maximum number of Slow Protocol frames of a given
subtype that can be transmitted in a one second interval.
The default value is 10.";
reference
"IEEE Std 802.3, 30.3.1.1.38 aSlowProtocolFrameLimit";
}
container capabilities {
config false;
description
"Container all Ethernet interface specific capabilities.";
leaf auto-negotiation {
type boolean;
description
"Indicates whether auto-negotiation may be configured on
this interface.";
}
}
container statistics {
config false;
description
"Contains statistics specific to Ethernet interfaces.
Discontinuities in the values of counters in the
container 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 (IETF RFC 8343).";
container frame {
description
"Contains frame statistics specific to Ethernet
interfaces.
All octet frame lengths include the 4 byte FCS.
Error counters are only reported once ... The count
represented by an instance of this object is incremented
when the frameCheckError status is returned by the MAC
service to the LLC (or other MAC user). Received frames
for which multiple error conditions pertain are,
according to the conventions of IEEE Std 802.3 Layer
Management, counted exclusively according to the error
status presented to the LLC.
A frame that is counted by an instance of this object is
also counted by the corresponding instance of 'in-errors'
leaf defined in the ietf-interfaces YANG module
(IETF RFC 8343).
Discontinuities in the values of counters in the
container 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 (IETF RFC 8343).";
leaf in-total-frames {
type yang:counter64;
units frames;
description
"The total number of frames (including bad frames)
received on the Ethernet interface.
This counter is calculated by summing the following
IEEE Std 802.3, Clause 30 counters:
aFramesReceivedOK +
aFrameCheckSequenceErrors +
aAlignmentErrors +
aFrameTooLongErrors +
aFramesLostDueToIntMACRcvError
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, Clause 30 counters, as specified
in the description above.";
}
leaf in-total-octets {
type yang:counter64;
units octets;
description
"The total number of octets of data (including those in
bad frames) received on the Ethernet interface.
Includes the 4-octet FCS.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IETF RFC 2819, etherStatsOctets";
}
leaf in-frames {
type yang:counter64;
units frames;
description
"A count of frames (including unicast, multicast and
broadcast) that have been successfully received on the
Ethernet interface.
This count does not include frames received with
frame-too-long, FCS, length or alignment errors, or
frames lost due to internal MAC sublayer error.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.5 aFramesReceivedOK";
}
leaf in-multicast-frames {
type yang:counter64;
units frames;
description
"A count of multicast frames that have been
successfully received on the Ethernet interface.
This counter represents a subset of the frames counted
by in-frames.
This count does not include frames received with
frame-too-long, FCS, length or alignment errors, or
frames lost due to internal MAC sublayer error.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.21 aMulticastFramesReceivedOK";
}
leaf in-broadcast-frames {
type yang:counter64;
units frames;
description
"A count of broadcast frames that have been
successfully received on the Ethernet interface.
This counter represents a subset of the frames counted
by in-frames.
This count does not include frames received with
frame-too-long, FCS, length or alignment errors, or
frames lost due to internal MAC sublayer error.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.22 aBroadcastFramesReceivedOK";
}
leaf in-error-fcs-frames {
type yang:counter64;
units frames;
description
"A count of receive frames that are of valid length,
but do not pass the FCS check, regardless of whether
or not the frames are an integral number of octets in
length.
This count effectively comprises
aFrameCheckSequenceErrors and aAlignmentErrors added
together.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.6 aFrameCheckSequenceErrors;
IEEE Std 802.3, 30.3.1.1.7 aAlignmentErrors";
}
leaf in-error-undersize-frames {
type yang:counter64;
units frames;
description
"A count of frames received on a particular Ethernet
interface that are less than 64 bytes in length, and
are discarded.
This counter is incremented regardless of whether the
frame passes the FCS check.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IETF RFC 2819, etherStatsUndersizePkts and
etherStatsFragments";
}
leaf in-error-oversize-frames {
type yang:counter64;
units frames;
description
"A count of frames received on a particular Ethernet
interface that exceed the maximum permitted frame
size, that is specified in max-frame-length, and are
discarded.
This counter is incremented regardless of whether the
frame passes the FCS check.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference "IEEE Std 802.3, 30.3.1.1.25 aFrameTooLongErrors";
}
leaf in-error-mac-internal-frames {
type yang:counter64;
units frames;
description
"A count of frames for which reception on a particular
Ethernet interface fails due to an internal MAC
sublayer receive error.
A frame is only counted by an instance of this object
if it is not counted by the corresponding instance of
either the in-error-fcs-frames, in-error-undersize-frames,
or in-error-oversize-frames. The precise meaning of the
count represented by an instance of this object is
implementation-specific.
In particular, an instance of this object may
represent a count of receive errors on a particular
Ethernet interface that are not otherwise counted.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.15
aFramesLostDueToIntMACRcvError";
}
leaf out-frames {
type yang:counter64;
units frames;
description
"A count of frames (including unicast, multicast and
broadcast) that have been successfully transmitted on
the Ethernet interface.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.2 aFramesTransmittedOK";
}
leaf out-multicast-frames {
type yang:counter64;
units frames;
description
"A count of multicast frames that have been
successfully transmitted on the Ethernet interface.
This counter represents a subset of the frames counted
by out-frames.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.18 aMulticastFramesXmittedOK";
}
leaf out-broadcast-frames {
type yang:counter64;
units frames;
description
"A count of broadcast frames that have been
successfully transmitted on the Ethernet interface.
This counter represents a subset of the frames counted
by out-frames.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.19 aBroadcastFramesXmittedOK";
}
leaf out-error-mac-internal-frames {
type yang:counter64;
units frames;
description
"A count of frames for which transmission on a
particular Ethernet interface fails due to an internal
MAC sublayer transmit error.
The precise meaning of the count represented by an
instance of this object is implementation-specific. In
particular, an instance of this object may represent a
count of transmission errors on a particular Ethernet
interface that are not otherwise counted.
Also see the 'description' statement associated with
the parent 'statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.1.1.12
aFramesLostDueToIntMACXmitError";
}
}
container phy {
description
"Ethernet statistics related to the PHY layer.
Discontinuities in the values of counters in the
container 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 (IETF RFC 8343).";
leaf in-error-symbol {
type yang:counter64;
units errors;
description
"A count of the number of symbol errors that have
occurred.
For the precise definition of when the symbol error
counter is incremented, please see the 'description'
text associated with aSymbolErrorDuringCarrier,
specified in IEEE Std 802.3, 30.3.2.1.5.
Also see the 'description' statement associated with
the parent 'phy-statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.2.1.5 aSymbolErrorDuringCarrier";
}
container lpi {
description
"Physical Ethernet statistics for the energy efficiency
related low power idle indications.";
leaf in-lpi-transitions {
type yang:counter64;
units transitions;
description
"A count of occurrences of the transition from
DEASSERT to ASSERT of the LPI_INDICATE
parameter. The indication reflects the state of the
PHY according to the requirements of the RS (see
IEEE Std 802.3, 22.7, 35.4, and 46.4).
Also see the 'description' statement associated with
the parent 'phy-statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.2.1.11 aReceiveLPITransitions";
}
leaf in-lpi-time {
type decimal64 {
fraction-digits 6;
}
units seconds;
description
"A count reflecting the total amount of time (in
seconds) that the LPI_REQUEST parameter has the
value ASSERT. The request is indicated to the PHY
according to the requirements of the RS (see IEEE Std
802.3, 22.7, 35.4, and 46.4).
Also see the 'description' statement associated with
the parent 'phy-statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.2.1.9 aReceiveLPIMicroseconds";
}
leaf out-lpi-transitions {
type yang:counter64;
units transitions;
description
"A count of occurrences of the transition from state
LPI_DEASSERTED to state LPI_ASSERTED in the LPI
transmit state diagram of the RS. The state
transition corresponds to the assertion of the
LPI_REQUEST parameter. The request is indicated to
the PHY according to the requirements of the RS (see
IEEE Std 802.3, 22.7, 35.4, 46.4.)
Also see the 'description' statement associated with
the parent 'phy-statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.2.1.10 aTransmitLPITransitions";
}
leaf out-lpi-time {
type decimal64 {
fraction-digits 6;
}
units seconds;
description
"A count reflecting the total amount of time (in
seconds) that the LPI_INDICATION parameter has the
value ASSERT. The request is indicated to the PHY
according to the requirements of the RS (see IEEE
802.3, 22.7, 35.4, and 46.4).
Also see the 'description' statement associated with
the parent 'phy-statistics' container for additional
common semantics related to this counter.";
reference
"IEEE Std 802.3, 30.3.2.1.8 aTransmitLPIMicroseconds";
}
}
}
container mac-control {
description
"A group of statistics specific to MAC Control operation
of selected Ethernet interfaces.
Discontinuities in the values of counters in the
container 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 (IETF RFC 8343).";
reference
"IEEE Std 802.3.1, dot3ExtensionTable";
leaf in-frames-mac-control-unknown {
type yang:counter64;
units frames;
description
"A count of MAC Control frames with an unsupported
opcode received on this Ethernet interface.
Frames counted against this counter are also counted
against in-discards defined in the ietf-interfaces
YANG module (IETF RFC 8343).
Also see the 'description' statement associated with
the parent 'mac-control-statistics' container for
additional semantics.";
reference
"IEEE Std 802.3, 30.3.3.5 aUnsupportedOpcodesReceived";
}
leaf in-frames-mac-control-extension {
type yang:counter64;
units frames;
description
"The count of Extension MAC Control frames received on
this Ethernet interface.
Also see the 'description' statement associated with
the parent 'mac-control-statistics' container for
additional semantics.";
reference
"IEEE Std 802.3, 30.3.8.2
aEXTENSIONMACCtrlFramesReceived";
}
leaf out-frames-mac-control-extension {
type yang:counter64;
units frames;
description
"The count of Extension MAC Control frames transmitted
on this Ethernet interface.
Also see the 'description' statement associated with
the parent 'mac-control-statistics' container for
additional semantics.";
reference
"IEEE Std 802.3, 30.3.8.1
aEXTENSIONMACCtrlFramesTransmitted";
}
}
}
}
}
}
@@ -0,0 +1,860 @@
module ieee802-ethernet-interface {
yang-version 1.1;
namespace "urn:ieee:std:802.3:yang:ieee802-ethernet-interface";
prefix ieee802-eth-if;
import ietf-yang-types {
prefix yang;
reference
"IETF RFC 6991";
}
import iana-if-type {
prefix ianaift;
reference
"http://www.iana.org/assignments/yang-parameters/
iana-if-type@2023-01-26.yang";
}
import ietf-interfaces {
prefix if;
reference
"IETF RFC 8343";
}
import ieee802-ethernet-phy-type {
prefix ieee802-phy;
reference
"IEEE Std 802.3-2022";
}
organization
"IEEE Std 802.3 Ethernet Working Group
Web URL: http://www.ieee802.org/3/";
contact
"Web URL: http://www.ieee802.org/3/";
description
"This module contains YANG definitions for configuring IEEE Std
802.3 Ethernet Interfaces.
In this YANG module, 'Ethernet interface' can be interpreted
as referring to 'IEEE Std 802.3 compliant Ethernet
interfaces'.";
revision 2025-09-10 {
description
"Updates under IEEE Std 802.3.2-2025";
reference
"IEEE Std 802.3-2022 and IEEE Std 802.3.1-2024, unless dated
explicitly";
}
feature ethernet-pfc {
description
"This device supports Ethernet priority flow control.";
}
feature ethernet-pause {
description
"This device supports Ethernet PAUSE.";
}
typedef eth-if-speed-type {
type decimal64 {
fraction-digits 3;
}
units "Gb/s";
status obsolete;
description
"Used to represent the configured, negotiated, or actual
speed of an Ethernet interface in Gigabits per second
(Gb/s), accurate to 3 decimal places (i.e., accurate to
1 Mb/s).";
}
typedef duplex-type {
type enumeration {
enum full {
description
"Full duplex.";
}
enum half {
description
"Half duplex.";
}
enum unknown {
description
"Link is currently disconnected or initializing.";
}
}
default "full";
description
"Used to represent the configured, negotiated, or actual
duplex mode of an Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.1.1.32, aDuplexStatus";
}
typedef pause-fc-direction-type {
type enumeration {
enum disabled {
description
"Flow control disabled in both ingress and egress
directions.";
}
enum ingress-only {
description
"PAUSE frame-based flow control is enabled in the ingress
direction only.";
}
enum egress-only {
description
"PAUSE frame-based flow control is enabled in the egress
direction only.";
}
enum bi-directional {
description
"PAUSE frame-based flow control is enabled in both
ingress and egress directions.";
}
enum undefined {
description
"Link is currently disconnected or initializing.";
}
}
description
"Used to represent the configured, negotiated, or actual
PAUSE frame-based flow control setting.";
reference
"IEEE Std 802.3.1, dot3PauseAdminMode and dot3PauseOperMode";
}
augment "/if:interfaces/if:interface" {
when "derived-from-or-self(if:type, 'ianaift:ethernetCsmacd')" {
description
"Applies to all Ethernet interfaces.";
}
description
"Augment interface model with Ethernet interface
specific configuration nodes.";
container ethernet {
description
"Contains all Ethernet interface related configuration.";
container auto-negotiation {
presence "The presence of this container indicates that
auto-negotiation is supported on this Ethernet
interface.";
description
"Contains auto-negotiation transmission parameters.
This container contains a data node that allows the
advertised duplex value in the negotiation to be
restricted.
If not specified then the default behavior for the
duplex data node is to negotiate all available values for
the particular type of Ethernet PHY associated with the
interface.";
reference
"IEEE Std 802.3, Clause 28 and Annexes 28A-D";
leaf enable {
type boolean;
default "true";
description
"Controls whether auto-negotiation is enabled or
disabled.
For interface types that support auto-negotiation then
it defaults to being enabled.
For interface types that do not support
auto-negotiation, the related configuration data is
ignored.";
}
leaf negotiation-status {
when "../enable = 'true'";
type enumeration {
enum in-progress {
description
"The auto-negotiation protocol is running and
negotiation is currently in-progress.";
}
enum complete {
description
"The auto-negotiation protocol has completed
successfully.";
}
enum failed {
description
"The auto-negotiation protocol has failed.";
}
enum unknown {
description
"The auto-negotiation status is not currently known,
this could be because it is still negotiating or the
protocol cannot run
(e.g., if no medium is present).";
}
enum no-negotiation {
description
"No auto-negotiation is executed.
The auto-negotiation function is either not
supported on this interface or has not been
enabled.";
}
}
config false;
description
"The status of the auto-negotiation protocol.";
reference
"IEEE 802.3, 30.6.1.1.4, aAutoNegAutoConfig";
}
}
leaf phy-type {
type identityref {
base ieee802-phy:phy-type;
}
config false;
description
"A value that uniquely identifies the IEEE 802.3 PHY type
of the interface.";
reference
"IEEE Std 802.3, 30.3.2.1.2 aPhyType";
}
leaf pmd-type {
type identityref {
base ieee802-phy:pmd-type;
}
config false;
description
"A value that uniquely identifies the IEEE 802.3 PMD type
of the interface.";
reference
"IEEE Std 802.3, 30.5.1.1.2 aMAUType";
}
leaf duplex {
type duplex-type;
description
"Operational duplex mode of the Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.1.1.32 aDuplexStatus";
}
leaf speed {
type eth-if-speed-type;
units "Gb/s";
status obsolete;
description
"Operational speed (data rate) of the Ethernet interface.
The default value is implementation dependent.
Superseded by speed in /if:interfaces/if:interface";
}
/* deprecated flow-control container */
container flow-control {
status deprecated;
description
"Holds the different types of Ethernet PAUSE frame-based
flow control that can be enabled.
Superseded by new container - pause.";
container pause {
if-feature "ethernet-pause";
description
"IEEE Std 802.3 PAUSE frame-based flow control.";
reference
"IEEE Std 802.3, Annex 31B";
leaf direction {
type pause-fc-direction-type;
description
"Indicates which direction PAUSE frame-based flow
control is enabled in, or whether it is disabled.
The default flow-control settings are vendor
specific. If auto-negotiation is enabled, then PAUSE
based flow control is negotiated by default.
The default value is implementation dependent.";
}
container statistics {
config false;
description
"Contains the number of PAUSE frames received or
transmitted.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
leaf in-frames-pause {
type yang:counter64;
units "frames";
description
"A count of PAUSE MAC Control frames transmitted on
this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.4.3
aPAUSEMACCtrlFramesReceived";
}
leaf out-frames-pause {
type yang:counter64;
units "frames";
description
"A count of PAUSE MAC Control frames transmitted on
this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.4.2
aPAUSEMACCtrlFramesTransmitted";
}
}
}
container pfc {
if-feature "ethernet-pfc";
description
"IEEE Std 802.3 Priority-based flow control.";
reference
"IEEE Std 802.3, Annex 31D";
leaf enable {
type boolean;
description
"True indicates that IEEE Std 802.3 priority-based
flow control is enabled, false indicates that
IEEE Std 802.3 priority-based flow control is
disabled. For interfaces that have auto-negotiation,
the priority-based flow control is enabled by
default.";
}
container statistics {
config false;
status deprecated;
description
"This container collects all statistics for
Ethernet interfaces.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
leaf in-frames-pfc {
type yang:counter64;
units "frames";
description
"Deprecated in-frames-pfc as not defined in base
standard. A count of PFC MAC Control frames
received on this Ethernet interface.";
reference
"IEEE Std 802.3.1, dot3HCInPFCFrames";
}
leaf out-frames-pfc {
type yang:counter64;
units "frames";
description
"Deprecated out-frames-pfc as not defined in base
standard. A count of PFC MAC Control frames
transmitted on this interface.";
reference
"IEEE Std 802.3.1, dot3HCInPFCFrames";
}
}
}
leaf force-flow-control {
type boolean;
default "false";
description
"Explicitly forces the local PAUSE frame-based flow
control settings regardless of what has been
negotiated.
Since the auto-negotiation of flow control settings
does not allow all sane combinations to be negotiated
(e.g., consider a device that is only capable of
sending PAUSE frames connected to a peer device that
is only capable of receiving and acting on PAUSE
frames) and failing to agree on the flow control
settings does not cause the auto-negotiation to fail
completely, then it is sometimes useful to be able to
explicitly enable particular PAUSE frame-based flow
control settings on the local device regardless of
what is being advertised or negotiated.";
reference
"IEEE Std 802.3, Table 28B-3";
}
}
leaf max-frame-length {
type uint16;
units "octets";
config false;
description
"This indicates the MAC frame length (including FCS bytes)
at which frames are dropped for being too long.";
reference
"IEEE Std 802.3, 30.3.1.1.37 aMaxFrameLength";
}
leaf mac-control-extension-control {
type boolean;
config false;
description
"A value that identifies the current EXTENSION
MAC Control function, as specified in
IEEE Std 802.3, Annex 31C.";
reference
"IEEE Std 802.3, 30.3.8.3 aEXTENSIONMACCtrlStatus
IEEE Std 802.3.1, dot3ExtensionMacCtrlStatus ";
}
leaf frame-limit-slow-protocol {
type uint64;
units "f/s";
default "10";
config false;
description
"The maximum number of Slow Protocol frames of a given
subtype that can be transmitted in a one second
interval.
The default value is 10.";
reference
"IEEE Std 802.3, 30.3.1.1.38 aSlowProtocolFrameLimit";
}
container capabilities {
config false;
description
"Contains all Ethernet interface specific capabilities.";
leaf auto-negotiation {
type boolean;
description
"Indicates whether auto-negotiation may be configured on
this interface.";
}
}
container ethernet-pause {
if-feature "ethernet-pause";
description
"IEEE Std 802.3 PAUSE flow control.
Discontinuities in the values of counters in
this container 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
(IETF RFC 8343).";
reference
"IEEE Std 802.3, 30.3.4 PAUSE entity managed object class
and Clause 31, Annex 31B)";
container control-and-status {
description
"PAUSE function control and status objects.";
leaf pause-admin-control {
type pause-fc-direction-type;
default "disabled";
description
"What PAUSE functionality will run on this interface
when Auto-Negotiation is not implemented
or disabled.";
reference
"IEEE Std 802.3.1, dot3PauseAdminMode";
}
leaf pause-oper-status {
type pause-fc-direction-type;
config false;
description
"What PAUSE functionality is running on this
interface, as a result of Auto-Negotiation or
setting pause-admin-control.";
reference
"IEEE Std 802.3.1, dot3PauseOperMode";
}
leaf link-delay-allowance {
type uint32;
description
"The value in bit-times of the allowance made by the
MAC Control PAUSE entity for round-trip propagation
delay.
The default value is implementation dependent.";
}
leaf pfc-enable-status {
type boolean;
config false;
description
"Is IEEE 802.1 Priority-based Flow Control (PFC)
enabled on the interface. If PFC is enabled, then
802.3 PAUSE flow control is disabled.";
reference
"IEEE Std 802.3, 30.3.3.6 aPFCEnableStatus";
}
}
container statistics {
config false;
description
"PAUSE frame counters.";
leaf in-frames-pause {
type yang:counter64;
units "frames";
description
"A count of MAC Control PAUSE frames transmitted on
this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.4.3
aPAUSEMACCtrlFramesReceived";
}
leaf out-frames-pause {
type yang:counter64;
units "frames";
description
"A count of MAC Control PAUSE frames transmitted on
this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.4.2
aPAUSEMACCtrlFramesTransmitted";
}
}
}
container statistics {
config false;
description
"Contains statistics specific to Ethernet interfaces.
Discontinuities in the values of counters in the
container 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 (IETF RFC 8343).";
container frame {
description
"Contains frame statistics specific to Ethernet
interfaces.
All octet frame lengths include the 4-byte FCS.
Error counters are only reported once. The count
represented by an instance of this object is
incremented when the frameCheckError status is
returned by the MAC service to the MAC Client.
Received frames for which multiple error conditions
pertain are, according to the conventions of
IEEE Std 802.3 Layer Management, counted exclusively
according to the error status presented to the MAC
Client.
A frame that is counted by an instance of this object
is also counted by the corresponding instance of
'in-errors' leaf defined in the ietf-interfaces YANG
module (IETF RFC 8343).";
leaf in-total-frames {
type yang:counter64;
units "frames";
description
"The total number of frames (including bad frames)
received on the Ethernet interface.
This counter is calculated by summing the following
IEEE Std 802.3, Clause 30 counters:
aFramesReceivedOK +
aFrameCheckSequenceErrors +
aAlignmentErrors +
aFrameTooLongErrors +
aFramesLostDueToIntMACRcvError";
reference
"IEEE Std 802.3, Clause 30 counters, as specified
in the description above.";
}
leaf in-total-octets {
type yang:counter64;
units "octets";
description
"The total number of octets of data (including those
in bad frames) received on the Ethernet interface.
Includes the 4-octet FCS.";
reference
"IETF RFC 2819, etherStatsOctets";
}
leaf in-frames {
type yang:counter64;
units "frames";
description
"A count of frames (including unicast, multicast, and
broadcast) that have been successfully received on
the Ethernet interface.
This count does not include frames received with
frame-too-long, FCS, length, or alignment errors, or
frames lost due to internal MAC sublayer error.";
reference
"IEEE Std 802.3, 30.3.1.1.5 aFramesReceivedOK";
}
leaf in-multicast-frames {
type yang:counter64;
units "frames";
description
"A count of multicast frames that have been
successfully received on the Ethernet interface.
This counter represents a subset of the frames
counted by in-frames.
This count does not include frames received with
frame-too-long, FCS, length, or alignment errors, or
frames lost due to internal MAC sublayer error.";
reference
"IEEE Std 802.3, 30.3.1.1.21
aMulticastFramesReceivedOK";
}
leaf in-broadcast-frames {
type yang:counter64;
units "frames";
description
"A count of broadcast frames that have been
successfully received on the Ethernet interface.
This counter represents a subset of the frames
counted by in-frames.
This count does not include frames received with
frame-too-long, FCS, length, or alignment errors, or
frames lost due to internal MAC sublayer error.";
reference
"IEEE Std 802.3, 30.3.1.1.22
aBroadcastFramesReceivedOK";
}
leaf in-error-fcs-frames {
type yang:counter64;
units "frames";
description
"A count of receive frames that are of valid length,
but do not pass the FCS check, regardless of whether
or not the frames are an integral number of octets
in length.
This counter is calculated by summing the following
counters:
aFrameCheckSequenceErrors +
aAlignmentErrors";
reference
"IEEE Std 802.3, 30.3.1.1.6 aFrameCheckSequenceErrors;
IEEE Std 802.3, 30.3.1.1.7 aAlignmentErrors";
}
leaf in-error-undersize-frames {
type yang:counter64;
units "frames";
status deprecated;
description
"Deprecated in-error-undersize-frames as not defined
in base standard. A count of frames received on a
particular Ethernet interface that are less than
64 bytes in length, and are discarded.
This counter is incremented regardless of whether
the frame passes the FCS check.";
reference
"IETF RFC 2819, etherStatsUndersizePkts and
etherStatsFragments";
}
leaf in-error-oversize-frames {
type yang:counter64;
units "frames";
description
"A count of frames received on a particular Ethernet
interface that exceed the maximum permitted frame
size, that is specified in max-frame-length, and are
discarded.
This counter is incremented regardless of whether
the frame passes the FCS check.";
reference
"IEEE Std 802.3, 30.3.1.1.25
aFrameTooLongErrors";
}
leaf in-error-mac-internal-frames {
type yang:counter64;
units "frames";
description
"A count of frames for which reception on a
particular Ethernet interface fails due to an
internal MAC sublayer receive error.
A frame is only counted by an instance of this
object if it is not counted by the corresponding
instance of either the in-error-fcs-frames,
in-error-undersize-frames, or
in-error-oversize-frames. The precise meaning of
the count represented by an instance of this object
is implementation-specific.
In particular, an instance of this object may
represent a count of receive errors on a particular
Ethernet interface that are not otherwise counted.";
reference
"IEEE Std 802.3, 30.3.1.1.15
aFramesLostDueToIntMACRcvError";
}
leaf out-frames {
type yang:counter64;
units "frames";
description
"A count of frames (including unicast, multicast, and
broadcast) that have been successfully transmitted
on the Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.1.1.2 aFramesTransmittedOK";
}
leaf out-multicast-frames {
type yang:counter64;
units "frames";
description
"A count of multicast frames that have been
successfully transmitted on the Ethernet interface.
This counter represents a subset of the frames
counted by out-frames.";
reference
"IEEE Std 802.3, 30.3.1.1.18
aMulticastFramesXmittedOK";
}
leaf out-broadcast-frames {
type yang:counter64;
units "frames";
description
"A count of broadcast frames that have been
successfully transmitted on the Ethernet interface.
This counter represents a subset of the frames
counted by out-frames.";
reference
"IEEE Std 802.3, 30.3.1.1.19
aBroadcastFramesXmittedOK";
}
leaf out-error-mac-internal-frames {
type yang:counter64;
units "frames";
description
"A count of frames for which transmission on a
particular Ethernet interface fails due to an
internal MAC sublayer transmit error.
The precise meaning of the count represented by an
instance of this object is implementation-specific.
In particular, an instance of this object may
represent a count of transmission errors on a
particular Ethernet interface that are not otherwise
counted.";
reference
"IEEE Std 802.3, 30.3.1.1.12
aFramesLostDueToIntMACXmitError";
}
}
container phy {
description
"Ethernet statistics related to the PHY layer.";
leaf in-error-symbol {
type yang:counter64;
units "errors";
description
"A count of the number of symbol errors that have
occurred.
For the precise definition of when the symbol error
counter is incremented, please see the 'description'
text associated with aSymbolErrorDuringCarrier,
specified in IEEE Std 802.3, 30.3.2.1.5.";
reference
"IEEE Std 802.3, 30.3.2.1.5
aSymbolErrorDuringCarrier";
}
container lpi {
description
"Physical Ethernet statistics for the energy
efficiency related low power idle indications.";
leaf in-lpi-transitions {
type yang:counter64;
units "transitions";
description
"The number of times the link partner transitioned to
Low Power Idle.
This counter has a maximum per second increment rate
of:
50 thousand for 100 Mb/s;
90 thousand for 1000 Mb/s
230 thousand for 10 Gb/s.";
reference
"IEEE Std 802.3, 30.3.2.1.11
aReceiveLPITransitions";
}
leaf in-lpi-time {
type decimal64 {
fraction-digits 6;
}
units "seconds";
description
"The amount of time the link partner has
been in Low Power Idle.";
reference
"IEEE Std 802.3, 30.3.2.1.9
aReceiveLPIMicroseconds";
}
leaf out-lpi-transitions {
type yang:counter64;
units "transitions";
description
"The number of times this port transitioned to
Low Power Idle.
This counter has a maximum per second increment rate
of:
50 thousand for 100 Mb/s;
90 thousand for 1000 Mb/s
230 thousand for 10 Gb/s.";
reference
"IEEE Std 802.3, 30.3.2.1.10
aTransmitLPITransitions";
}
leaf out-lpi-time {
type decimal64 {
fraction-digits 6;
}
units "seconds";
description
"The amount of time in this port has
been in Low Power Idle.";
reference
"IEEE Std 802.3, 30.3.2.1.8
aTransmitLPIMicroseconds";
}
}
}
container mac-control {
description
"A group of statistics specific to MAC Control
operation of selected Ethernet interfaces.";
reference
"IEEE Std 802.3.1, dot3ExtensionTable";
leaf in-frames-mac-control-unknown {
type yang:counter64;
units "frames";
description
"A count of MAC Control frames with an unsupported
opcode received on this Ethernet interface.
Frames counted against this counter are also counted
against in-discards defined in the ietf-interfaces
YANG module (IETF RFC 8343).";
reference
"IEEE Std 802.3, 30.3.3.5
aUnsupportedOpcodesReceived";
}
leaf in-frames-mac-control-extension {
type yang:counter64;
units "frames";
description
"The count of Extension MAC Control frames received
on this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.8.2
aEXTENSIONMACCtrlFramesReceived";
}
leaf out-frames-mac-control-extension {
type yang:counter64;
units "frames";
description
"The count of Extension MAC Control frames
transmitted on this Ethernet interface.";
reference
"IEEE Std 802.3, 30.3.8.1
aEXTENSIONMACCtrlFramesTransmitted";
}
}
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -5,10 +5,18 @@ module infix-ethernet-interface {
import ieee802-ethernet-interface {
prefix eth;
revision-date 2025-09-10;
}
import ieee802-ethernet-phy-type {
prefix ieee802-phy;
revision-date 2025-09-10;
}
import ietf-interfaces {
prefix if;
}
import iana-if-type {
prefix ianaift;
}
import ietf-yang-types {
prefix yang;
reference "IETF RFC 6991";
@@ -18,6 +26,34 @@ module infix-ethernet-interface {
contact "kernelkit@googlegroups.com";
description "Extensions and deviations to ieee802-ethernet-interface.yang";
revision 2026-05-21 {
description "Augment auto-negotiation with an 'advertise' leaf-list
of PMD-type identities, modelling the standards-correct
way to express what older configurations called 'fixed
speed': restrict the set of modes auto-negotiation may
advertise. IEEE Std 802.3.2-2025 obsoleted the eth:speed
leaf without providing a config-true replacement; this
augment fills that gap using existing IEEE PMD identities.
Old configurations using auto-negotiation/enable=false
plus speed+duplex are migrated by confd/share/migrate/1.9.
Also add an 'mdi-x' boolean leaf under ethernet for forcing
the copper MDI/MDI-X pinout, needed on some PHYs when
auto-negotiation is disabled and Auto-MDIX stops working.
Absent = Auto-MDIX, true = MDI-X, false = MDI; gated by a
when-expression on auto-negotiation/enable = false.";
reference "internal";
}
revision 2026-05-18 {
description "Updated to ieee802-ethernet-interface@2025-09-10 base
(IEEE Std 802.3.2-2025). No path or semantic changes
to Infix-exposed config; new operational leaves
phy-type and pmd-type from the upstream model are
used directly without deviation.";
reference "internal";
}
revision 2024-02-27 {
description "Add augment for in-good-octets and out-good-octets";
reference "internal";
@@ -36,6 +72,62 @@ module infix-ethernet-interface {
/*
* Data Nodes
*/
augment "/if:interfaces/if:interface/eth:ethernet/eth:auto-negotiation" {
when "derived-from-or-self(../../if:type, 'ianaift:ethernetCsmacd')";
description "Configuration knobs that constrain auto-negotiation.";
leaf-list advertised-pmd-types {
type identityref {
base ieee802-phy:pmd-type;
}
description "Restrict auto-negotiation to advertise only these PMD types.
When empty, the PHY advertises every mode it supports.";
}
}
/*
* mdi-x has deliberately NO default: the absent state is what carries
* the Auto-MDIX meaning, so adding a default would remove it. The C
* apply path must therefore read it with lydx_get_cattr() (absent vs
* true vs false), not lydx_get_bool() which collapses absent and false.
*
* The when-expression confines it to auto-negotiation/enable = false:
* Auto-MDIX is negotiated together with the link when autoneg is on, so
* forcing a pinout only makes sense once negotiation is disabled.
*/
augment "/if:interfaces/if:interface/eth:ethernet" {
when "derived-from-or-self(../if:type, 'ianaift:ethernetCsmacd')";
description "Copper PHY configuration knobs.";
leaf mdi-x {
when "../eth:auto-negotiation/eth:enable = 'false'";
type boolean;
description "Force the copper MDI/MDI-X crossover pinout. Only
available with auto-negotiation disabled, since Auto-MDIX
otherwise rides along with negotiation:
true force MDI-X (crossover)
false force MDI (straight)
The two ends of the link must use opposite values.
Leave unset for Auto-MDIX, the right choice for any link
that negotiates.";
}
}
augment "/if:interfaces/if:interface/eth:ethernet" {
when "derived-from-or-self(../if:type, 'ianaift:ethernetCsmacd')";
description "Operational facets for diagnosis.";
leaf-list supported-pmd-types {
type identityref {
base ieee802-phy:pmd-type;
}
config false;
description "PMD types this interface currently supports.
On SFP/SFP+ cages the set reflects the inserted module.";
}
}
augment "/if:interfaces/if:interface/eth:ethernet/eth:statistics/eth:frame" {
leaf out-good-octets {
type yang:counter64;
@@ -41,6 +41,15 @@ module infix-interfaces {
contact "kernelkit@googlegroups.com";
description "Linux bridge and lag extensions for ietf-interfaces.";
revision 2026-05-18 {
description "Track ieee802-ethernet-interface@2025-09-10 upgrade
(IEEE Std 802.3.2-2025): operational data now exposes
phy-type/pmd-type leaves and the interface speed via
ietf-interfaces:speed (bits/s) rather than the obsolete
eth:speed.";
reference "internal";
}
revision 2026-05-13 {
description "Add limitations on custom mac addresses on interfaces, now needs to be a correct unicast mac-address";
reference "internal";
+27 -3
View File
@@ -737,15 +737,39 @@ echo "Public: $pub"
</COMMAND>
<COMMAND name="factory-config" help="Show factory-config">
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy factory | jq -C . |pager</ACTION>
<SWITCH name="optional" min="0">
<COMMAND name="path" help="Filter by XPath, e.g. /ietf-interfaces:interfaces">
<PARAM name="xpath" ptype="/STRING" help="XPath into the datastore"/>
</COMMAND>
</SWITCH>
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy factory ${KLISH_PARAM_xpath:+-x $KLISH_PARAM_xpath} | jq -C . |pager</ACTION>
</COMMAND>
<COMMAND name="running-config" help="Show running-config">
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy running | jq -C . |pager</ACTION>
<SWITCH name="optional" min="0">
<COMMAND name="path" help="Filter by XPath, e.g. /ietf-interfaces:interfaces">
<PARAM name="xpath" ptype="/STRING" help="XPath into the datastore"/>
</COMMAND>
</SWITCH>
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy running ${KLISH_PARAM_xpath:+-x $KLISH_PARAM_xpath} | jq -C . |pager</ACTION>
</COMMAND>
<COMMAND name="startup-config" help="Show startup-config">
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy startup | jq -C . |pager</ACTION>
<SWITCH name="optional" min="0">
<COMMAND name="path" help="Filter by XPath, e.g. /ietf-interfaces:interfaces">
<PARAM name="xpath" ptype="/STRING" help="XPath into the datastore"/>
</COMMAND>
</SWITCH>
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy startup ${KLISH_PARAM_xpath:+-x $KLISH_PARAM_xpath} | jq -C . |pager</ACTION>
</COMMAND>
<COMMAND name="operational" help="Show operational data (running config + system state)">
<SWITCH name="optional" min="0">
<COMMAND name="path" help="Filter by XPath, e.g. /ietf-interfaces:interfaces">
<PARAM name="xpath" ptype="/STRING" help="XPath into the datastore"/>
</COMMAND>
</SWITCH>
<ACTION sym="script" in="tty" out="tty" interrupt="true">copy operational ${KLISH_PARAM_xpath:+-x $KLISH_PARAM_xpath} | jq -C . |pager</ACTION>
</COMMAND>
<COMMAND name="firewall" help="Show firewall status and configuration">
+9 -8
View File
@@ -106,14 +106,15 @@ interfaces {
}
}
admin@infix-12-34-56:/config/interface/eth0/&gt; leave
admin@infix-12-34-56:/&gt; show interfaces
INTERFACE PROTOCOL STATE DATA
eth0 ethernet UP 52:54:00:12:34:56
ipv4 192.168.2.200/24 (static)
ipv6 fe80::5054:ff:fe12:3456/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@infix-12-34-56:/&gt; show interface
INTERFACE PROTOCOL STATE DATA
eth0 1000baseT UP duplex: full
ethernet 52:54:00:12:34:56
ipv4 192.168.2.200/24 (static)
ipv6 fe80::5054:ff:fe12:3456/64 (link-layer)
lo loopback UP
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@infix-12-34-56:/&gt; copy running-config startup-config</code></pre>
<a href="doc/cli/introduction.md">Click here</a> for more details.
</details>
+215 -168
View File
@@ -101,7 +101,7 @@ def compress_interface_list(interfaces):
class Pad:
flags = 2
iface = 16
proto = 11
proto = 14
state = 12
data = 41
@@ -1042,7 +1042,15 @@ class Iface:
self.autoneg = get_json_data('unknown', self.data, 'ieee802-ethernet-interface:ethernet',
'auto-negotiation', 'enable')
self.duplex = get_json_data('', self.data,'ieee802-ethernet-interface:ethernet','duplex')
self.speed = get_json_data('', self.data, 'ieee802-ethernet-interface:ethernet', 'speed')
self.speed = get_json_data('', self.data, 'speed')
self.pmd_type = get_json_data('', self.data, 'ieee802-ethernet-interface:ethernet', 'pmd-type')
self.phy_type = get_json_data('', self.data, 'ieee802-ethernet-interface:ethernet', 'phy-type')
self.advertised = get_json_data([], self.data, 'ieee802-ethernet-interface:ethernet',
'auto-negotiation',
'infix-ethernet-interface:advertised-pmd-types')
self.supported = get_json_data([], self.data,
'ieee802-ethernet-interface:ethernet',
'infix-ethernet-interface:supported-pmd-types')
self.phys_address = data.get('phys-address', '')
self.br_mdb = get_json_data({}, self.data, 'infix-interfaces:bridge', 'multicast-filters')
@@ -1107,9 +1115,12 @@ class Iface:
self.wireguard = self.data.get('infix-interfaces:wireguard')
if self.data.get('infix-interfaces:vlan'):
self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
vlan_data = self.data.get('infix-interfaces:vlan')
self.lower_if = vlan_data.get('lower-layer-if', None)
self.vid = vlan_data.get('id', None)
else:
self.lower_if = ''
self.vid = None
def is_wifi(self):
return self.type == "infix-if-type:wifi"
@@ -1173,66 +1184,130 @@ class Iface:
row += f"{'':<{Pad.state}}{addr['ip']}/{addr['prefix-length']} {origin}"
print(row)
def _pr_proto_common(self, name, phys_address, pipe=''):
@staticmethod
def _pr_label_list(label, values):
"""Print label-prefixed values, one per row.
First row carries the label and a colon; later rows are blank-
prefixed continuations. When 'values' is empty, prints just the
label and a trailing colon — matching how 'ipv4 addresses' has
always been rendered when the interface has no IPs.
"""
if not values:
print(f"{label:<{19}}:")
return
first = True
for value in values:
key = label if first else ''
colon = ':' if first else ' '
print(f"{key:<{19}}{colon} {value}")
first = False
@staticmethod
def _pmd_label(identity):
"""Render an IEEE pmd-type / phy-type identityref as a display string.
Strips the module/leaf prefix and rewrites the IEEE 'BASE-' literal
to the lowercase 'base' the rest of the codebase uses (matching
ethtool's link-mode string format). Returns empty for empty input.
"""
if not identity:
return ""
return identity.removeprefix(
"ieee802-ethernet-phy-type:pmd-type-"
).removeprefix(
"ieee802-ethernet-phy-type:phy-type-"
).replace("BASE-", "base")
def _phy_label(self):
"""Display label for the active link.
Prefers pmd-type (specific medium, e.g. '10GbaseLR') over phy-type
(family-level, e.g. '10GbaseR') when both are populated. Empty
when neither is reported — non-ethernet interfaces don't have these
leaves, and yanger skips them for ethernet ports with no link or
unmapped (port, speed, duplex) tuple.
"""
return self._pmd_label(self.pmd_type or self.phy_type)
def _pr_proto_common(self, name, pipe='', data='', show_state=True):
# pipe="" means this row follows pr_name() on the same line, so col 1-2
# are already on screen. A non-empty pipe (" ", "│", "└ ") prints col
# 1-2 with that marker. show_state=False blanks the STATE column for
# sub-rows whose state was already reflected in the row above.
row = ""
if len(pipe) > 0:
row = f"{'':<{Pad.flags}}"
row += f"{pipe:<{Pad.iface}}"
row += f"{name:<{Pad.proto}}"
dec = Decore.green if self.oper() == "up" else Decore.red
row += dec(f"{self.oper().upper():<{Pad.state}}")
if phys_address:
row += f"{self.phys_address:<{Pad.data}}"
if show_state:
dec = Decore.green if self.oper() == "up" else Decore.red
row += dec(f"{self.oper().upper():<{Pad.state}}")
else:
row += f"{'':<{Pad.state}}"
if data:
row += f"{data:<{Pad.data}}"
return row
def _pr_phy_row(self, pipe=''):
"""Emit the physical-medium row when applicable. Return True if printed.
Skipped when pmd-type is unknown or the link is not up — keeping the
common 'boring port' cases quiet and falling back to the ethernet row.
"""
label = self._phy_label()
if not label or self.oper() != "up":
return False
data = f"duplex: {self.duplex}" if self.duplex else ""
print(self._pr_proto_common(label, pipe, data))
return True
def pr_proto_eth(self, pipe=''):
row = self._pr_proto_common("ethernet", True, pipe);
print(row)
print(self._pr_proto_common("ethernet", pipe, self.phys_address or ""))
def pr_proto_eth_subrow(self, pipe=' '):
"""Ethernet row beneath another protocol row: bare MAC, no STATE column."""
print(self._pr_proto_common("ethernet", pipe, self.phys_address or "",
show_state=False))
def pr_proto_veth(self, pipe=''):
row = self._pr_proto_common("veth", True, pipe);
parts = []
if self.phys_address:
parts.append(self.phys_address)
if self.lower_if:
row = f"{'':<{Pad.iface}}"
row += f"{'veth':<{Pad.proto}}"
row += f"{'':<{Pad.state}}"
row += f"peer:{self.lower_if}"
print(row)
def pr_proto_gretap(self, pipe=''):
row = self._pr_proto_common("gretap", True, pipe);
print(row)
parts.append(f"peer: {self.lower_if}")
print(self._pr_proto_common("veth", pipe, " ".join(parts)))
def pr_proto_gre(self, pipe=''):
row = self._pr_proto_common("gre", False, pipe);
print(row)
data = ""
if self.gre and (remote := self.gre.get('remote')):
data = f"remote: {remote}"
print(self._pr_proto_common("gre", pipe, data))
def pr_proto_vxlan(self, pipe=''):
row = self._pr_proto_common("vxlan", True, pipe);
print(row)
parts = []
if self.vxlan:
if (vni := self.vxlan.get('vni')) is not None:
parts.append(f"vni: {vni}")
if remote := self.vxlan.get('remote'):
parts.append(f"remote: {remote}")
print(self._pr_proto_common("vxlan", pipe, " ".join(parts)))
def pr_proto_wireguard(self, pipe=''):
row = self._pr_proto_common("wireguard", False, pipe)
data = ""
if self.wireguard:
peer_status = self.wireguard.get('peer-status', {})
peers = peer_status.get('peer', [])
total_peers = len(peers)
up_peers = sum(1 for p in peers if p.get('connection-status') == 'up')
if total_peers > 0:
row += f"{total_peers} peer"
if total_peers != 1:
row += "s"
row += f" ({up_peers} up)"
print(row)
plural = "s" if total_peers != 1 else ""
data = f"{total_peers} peer{plural} ({up_peers} up)"
print(self._pr_proto_common("wireguard", pipe, data))
def pr_proto_loopack(self, pipe=''):
row = self._pr_proto_common("loopback", False, pipe);
print(row)
print(self._pr_proto_common("loopback", pipe))
def pr_wifi_ssids(self):
width = 70
@@ -1309,42 +1384,19 @@ class Iface:
def pr_proto_wifi(self, pipe=''):
row = self._pr_proto_common("ethernet", True, pipe);
print(row)
ssid = None
signal = None
mode = None
if self.wifi:
# Detect mode: AP has "stations", Station has "signal-strength" or "scan-results"
ap=self.wifi.get("access-point", {})
if ap:
ssid = ap.get("ssid", "------")
mode = "AP"
stations_data = ap.get("stations", {})
stations = stations_data.get("station", [])
station_count = len(stations)
data_str = f"{mode}, ssid: {ssid}, stations: {station_count}"
else:
station=self.wifi.get("station", {})
ssid = station.get("ssid", "------")
signal = station.get("signal-strength")
mode = "Station"
if signal is not None:
signal_str = signal_to_status(signal)
data_str = f"{mode}, ssid: {ssid}, signal: {signal_str}"
else:
data_str = f"{mode}, ssid: {ssid}"
if self.wifi and (ap := self.wifi.get("access-point", {})):
ssid = ap.get("ssid", "------")
stations = ap.get("stations", {}).get("station", [])
data_str = f"access-point ssid: {ssid} stations: {len(stations)}"
elif self.wifi and (station := self.wifi.get("station", {})):
ssid = station.get("ssid", "------")
data_str = f"station ssid: {ssid}"
if (signal := station.get("signal-strength")) is not None:
data_str += f" signal: {signal_to_status(signal)}"
else:
data_str = "ssid: ------"
row = f"{'':<{Pad.flags}}"
row += f"{pipe:<{Pad.iface}}"
row = f"{'':<{Pad.flags}}"
row += f"{pipe:<{Pad.iface}}"
row += f"{'wifi':<{Pad.proto}}"
row += f"{'':<{Pad.state}}{data_str}"
print(row)
print(self._pr_proto_common("wifi", pipe, data_str))
def pr_proto_br(self, br_vlans):
data_str = ""
@@ -1357,23 +1409,18 @@ class Iface:
else:
row += Decore.red(f"{self.oper().upper():<{Pad.state}}")
vlans = []
for vlan in br_vlans:
if 'tagged' in vlan:
for tagged in vlan['tagged']:
if tagged == self.name:
if data_str:
data_str += f",{vlan['vid']}t"
else:
data_str += f"vlan:{vlan['vid']}t"
if 'untagged' in vlan:
for untagged in vlan['untagged']:
if untagged == self.name:
if data_str:
data_str += f",{vlan['vid']}u"
else:
data_str += f"vlan:{vlan['vid']}u"
if 'tagged' in vlan and self.name in vlan['tagged']:
vlans.append(f"{vlan['vid']}t")
if 'untagged' in vlan and self.name in vlan['untagged']:
vlans.append(f"{vlan['vid']}u")
tokens = []
if vlans:
tokens.append(f"vlan: {','.join(vlans)}")
if self.pvid:
data_str += f" pvid:{self.pvid}"
tokens.append(f"pvid: {self.pvid}")
data_str = " ".join(tokens)
if data_str:
row += f"{data_str:<{Pad.data}}"
@@ -1390,11 +1437,11 @@ class Iface:
lowers.append(_iface)
if lowers:
self.pr_proto_eth(pipe='')
self.pr_proto_eth_subrow(pipe='')
self.pr_proto_ipv4(pipe='')
self.pr_proto_ipv6(pipe='')
else:
self.pr_proto_eth(pipe=' ')
self.pr_proto_eth_subrow()
self.pr_proto_ipv4()
self.pr_proto_ipv6()
@@ -1449,11 +1496,11 @@ class Iface:
lowers.append(_iface)
if lowers:
self.pr_proto_eth(pipe='')
self.pr_proto_eth_subrow(pipe='')
self.pr_proto_ipv4(pipe='')
self.pr_proto_ipv6(pipe='')
else:
self.pr_proto_eth(pipe=' ')
self.pr_proto_eth_subrow()
self.pr_proto_ipv4()
self.pr_proto_ipv6()
@@ -1476,13 +1523,15 @@ class Iface:
def pr_gretap(self):
self.pr_name(pipe="")
self.pr_proto_gretap()
self.pr_proto_gre()
self.pr_proto_eth_subrow()
self.pr_proto_ipv4()
self.pr_proto_ipv6()
def pr_vxlan(self):
self.pr_name(pipe="")
self.pr_proto_vxlan()
self.pr_proto_eth_subrow()
self.pr_proto_ipv4()
self.pr_proto_ipv6()
@@ -1495,12 +1544,14 @@ class Iface:
def pr_wifi(self):
self.pr_name(pipe="")
self.pr_proto_wifi()
self.pr_proto_eth_subrow()
self.pr_proto_ipv4()
self.pr_proto_ipv6()
def pr_vlan(self, _ifaces):
self.pr_name(pipe="")
self.pr_proto_eth()
data = f"vid: {self.vid}" if self.vid is not None else ""
print(self._pr_proto_common("vlan", "", data))
if self.lower_if:
self.pr_proto_ipv4(pipe='')
@@ -1515,7 +1566,7 @@ class Iface:
print(f"Error, didn't find parent interface for vlan {self.name}")
sys.exit(1)
parent.pr_name(pipe='')
parent.pr_proto_eth()
print()
def pr_container(self):
# Add ⇅ flag for interfaces with IP forwarding enabled
@@ -1532,92 +1583,85 @@ class Iface:
def pr_iface(self):
if self.is_in_container():
print(Decore.gray_bg(f"{'owned by container':<{20}}: {', ' . join(self.containers)}"))
print(Decore.gray_bg(f"{'owned by container':<{19}}: {', ' . join(self.containers)}"))
print(f"{'name':<{20}}: {self.name}")
print(f"{'type':<{20}}: {self.type.split(':')[1]}")
print(f"{'index':<{20}}: {self.index}")
print(f"{'name':<{19}}: {self.name}")
print(f"{'type':<{19}}: {self.type.split(':')[1]}")
print(f"{'index':<{19}}: {self.index}")
if self.mtu:
print(f"{'mtu':<{20}}: {self.mtu}")
print(f"{'mtu':<{19}}: {self.mtu}")
if self.oper():
print(f"{'operational status':<{20}}: {self.oper(detail=True)}")
print(f"{'operational status':<{19}}: {self.oper(detail=True)}")
forwarding = "enabled" if self.name in Iface._routing_ifaces else "disabled"
print(f"{'ip forwarding':<{20}}: {forwarding}")
print(f"{'ip forwarding':<{19}}: {forwarding}")
if self.lower_if:
print(f"{'lower-layer-if':<{20}}: {self.lower_if}")
print(f"{'lower-layer-if':<{19}}: {self.lower_if}")
if label := self._phy_label():
print(f"{'link mode':<{19}}: {label}")
if self.speed:
mbps = int(self.speed) // 1_000_000
print(f"{'speed':<{19}}: {mbps}")
if self.duplex:
print(f"{'duplex':<{19}}: {self.duplex}")
if self.autoneg != 'unknown':
val = "on" if self.autoneg else "off"
print(f"{'auto-negotiation':<{20}}: {val}")
print(f"{'auto-negotiation':<{19}}: {val}")
if self.duplex:
print(f"{'duplex':<{20}}: {self.duplex}")
if self.advertised:
self._pr_label_list('advertised',
[self._pmd_label(pmd) for pmd in self.advertised])
if self.speed:
mbs = float(self.speed) * 1000
print(f"{'speed':<{20}}: {int(mbs)}")
if self.supported:
self._pr_label_list('supported',
[self._pmd_label(pmd) for pmd in self.supported])
if self.phys_address:
print(f"{'physical address':<{20}}: {self.phys_address}")
print(f"{'physical address':<{19}}: {self.phys_address}")
if self.lag_mode:
print(f"{'lag mode':<{20}}: {self.lag_mode}")
print(f"{'lag mode':<{19}}: {self.lag_mode}")
if self.lag_mode == "lacp":
print(f"{'lag hash':<{20}}: {self.lag_hash}")
print(f"{'lacp mode':<{20}}: {self.lacp_mode}")
print(f"{'lacp rate':<{20}}: {self.lacp_rate}")
print(f"{'lacp aggregate id':<{20}}: {self.lacp_id}")
print(f"{'lacp system priority':<{20}}: {self.lacp_sys_prio}")
print(f"{'lacp actor key':<{20}}: {self.lacp_actor_key}")
print(f"{'lacp partner key':<{20}}: {self.lacp_partner_key}")
print(f"{'lacp partner mac':<{20}}: {self.lacp_partner_mac}")
print(f"{'lag hash':<{19}}: {self.lag_hash}")
print(f"{'lacp mode':<{19}}: {self.lacp_mode}")
print(f"{'lacp rate':<{19}}: {self.lacp_rate}")
print(f"{'lacp aggregate id':<{19}}: {self.lacp_id}")
print(f"{'lacp sys priority':<{19}}: {self.lacp_sys_prio}")
print(f"{'lacp actor key':<{19}}: {self.lacp_actor_key}")
print(f"{'lacp partner key':<{19}}: {self.lacp_partner_key}")
print(f"{'lacp partner mac':<{19}}: {self.lacp_partner_mac}")
else:
print(f"{'lag type':<{20}}: {self.lag_type}")
print(f"{'lag hash':<{20}}: {self.lag_hash}")
print(f"{'link debounce up':<{20}}: {self.link_updelay} msec")
print(f"{'link debounce down':<{20}}: {self.link_downdelay} msec")
print(f"{'lag type':<{19}}: {self.lag_type}")
print(f"{'lag hash':<{19}}: {self.lag_hash}")
print(f"{'link debounce up':<{19}}: {self.link_updelay} msec")
print(f"{'link debounce down':<{19}}: {self.link_downdelay} msec")
if self.lag:
print(f"{'lag member':<{20}}: {self.lag}")
print(f"{'lag member state':<{20}}: {self.lag_state}")
print(f"{'lag member':<{19}}: {self.lag}")
print(f"{'lag member state':<{19}}: {self.lag_state}")
if self.lacp_state:
print(f"{'lacp aggregate id':<{20}}: {self.lacp_id}")
print(f"{'lacp actor state':<{20}}: {', '.join(self.lacp_state)}")
print(f"{'lacp partner state':<{20}}: {', '.join(self.lacp_pstate)}")
print(f"{'link failure count':<{20}}: {self.link_failures}")
print(f"{'lacp aggregate id':<{19}}: {self.lacp_id}")
print(f"{'lacp actor state':<{19}}: {', '.join(self.lacp_state)}")
print(f"{'lacp partner state':<{19}}: {', '.join(self.lacp_pstate)}")
print(f"{'link failure count':<{19}}: {self.link_failures}")
if self.ipv4_addr:
first = True
for addr in self.ipv4_addr:
def _addr_lines(addrs):
for addr in addrs:
origin = f"({addr['origin']})" if addr.get('origin') else ""
key = 'ipv4 addresses' if first else ''
colon = ':' if first else ' '
row = f"{key:<{20}}{colon} "
row += f"{addr['ip']}/{addr['prefix-length']} {origin}"
print(row)
first = False
else:
print(f"{'ipv4 addresses':<{20}}:")
yield f"{addr['ip']}/{addr['prefix-length']} {origin}"
if self.ipv6_addr:
first = True
for addr in self.ipv6_addr:
origin = f"({addr['origin']})" if addr.get('origin') else ""
key = 'ipv6 addresses' if first else ''
colon = ':' if first else ' '
row = f"{key:<{20}}{colon} "
row += f"{addr['ip']}/{addr['prefix-length']} {origin}"
print(row)
first = False
else:
print(f"{'ipv6 addresses':<{20}}:")
self._pr_label_list('ipv4 addresses', list(_addr_lines(self.ipv4_addr)))
self._pr_label_list('ipv6 addresses', list(_addr_lines(self.ipv6_addr)))
if self.in_octets and self.out_octets:
print(f"{'in-octets':<{20}}: {self.in_octets}")
print(f"{'out-octets':<{20}}: {self.out_octets}")
print(f"{'in-octets':<{19}}: {self.in_octets}")
print(f"{'out-octets':<{19}}: {self.out_octets}")
if self.wifi:
# Detect mode: AP has "stations", Station has "signal-strength" or "scan-results"
@@ -1627,43 +1671,43 @@ class Iface:
ssid = ap.get('ssid', "----")
stations_data = ap.get("stations", {})
stations = stations_data.get("station", [])
print(f"{'mode':<{20}}: {mode}")
print(f"{'ssid':<{20}}: {ssid}")
print(f"{'connected stations':<{20}}: {len(stations)}")
print(f"{'mode':<{19}}: {mode}")
print(f"{'ssid':<{19}}: {ssid}")
print(f"{'connected stations':<{19}}: {len(stations)}")
self.pr_wifi_stations()
else:
mode = "station"
station = self.wifi.get('station', {})
signal = station.get('signal-strength')
ssid = station.get('ssid', "----")
print(f"{'mode':<{20}}: {mode}")
print(f"{'ssid':<{20}}: {ssid}")
print(f"{'mode':<{19}}: {mode}")
print(f"{'ssid':<{19}}: {ssid}")
if signal is not None:
signal_status = signal_to_status(signal)
print(f"{'signal':<{20}}: {signal} dBm ({signal_status})")
print(f"{'signal':<{19}}: {signal} dBm ({signal_status})")
rx_speed = station.get('rx-speed')
tx_speed = station.get('tx-speed')
if rx_speed is not None:
print(f"{'rx bitrate':<{20}}: {rx_speed / 10:.1f} Mbps")
print(f"{'rx bitrate':<{19}}: {rx_speed / 10:.1f} Mbps")
if tx_speed is not None:
print(f"{'tx bitrate':<{20}}: {tx_speed / 10:.1f} Mbps")
print(f"{'tx bitrate':<{19}}: {tx_speed / 10:.1f} Mbps")
if "scan-results" in station:
self.pr_wifi_ssids()
if self.gre:
print(f"{'local address':<{20}}: {self.gre['local']}")
print(f"{'remote address':<{20}}: {self.gre['remote']}")
print(f"{'local address':<{19}}: {self.gre['local']}")
print(f"{'remote address':<{19}}: {self.gre['remote']}")
if self.vxlan:
print(f"{'local address':<{20}}: {self.vxlan['local']}")
print(f"{'remote address':<{20}}: {self.vxlan['remote']}")
print(f"{'VxLAN id':<{20}}: {self.vxlan['vni']}")
print(f"{'local address':<{19}}: {self.vxlan['local']}")
print(f"{'remote address':<{19}}: {self.vxlan['remote']}")
print(f"{'VxLAN id':<{19}}: {self.vxlan['vni']}")
if self.wireguard:
peer_status = self.wireguard.get('peer-status', {})
peers = peer_status.get('peer', [])
if peers:
print(f"{'peers':<{20}}: {len(peers)}")
print(f"{'peers':<{19}}: {len(peers)}")
for idx, peer in enumerate(peers, 1):
print(f"\n Peer {idx}:")
@@ -1700,10 +1744,10 @@ class Iface:
frame = get_json_data([], self.data,'ieee802-ethernet-interface:ethernet',
'statistics', 'frame')
if frame:
print("")
Decore.title("Ethernet Statistics")
for key, val in frame.items():
key = remove_yang_prefix(key)
print(f"eth-{key:<{25}}: {val}")
print(f"{key:<{25}}: {val}")
def pr_mdb(self, bridge):
for group in self.br_mdb.get("multicast-filter", {}):
@@ -1804,7 +1848,10 @@ def brport_sort(iface):
def print_interface(iface):
iface.pr_name()
iface.pr_proto_eth()
if iface._pr_phy_row():
iface.pr_proto_eth_subrow()
else:
iface.pr_proto_eth()
iface.pr_proto_ipv4()
iface.pr_proto_ipv6()
@@ -68,31 +68,172 @@ def statistics(ifname):
return statistics
# ethtool reports SPEED_UNKNOWN as UINT32_MAX when no link / no medium.
_ETHTOOL_SPEED_UNKNOWN = (1 << 32) - 1
# Map (ethtool port string, speed in Mb/s, duplex) -> (phy-type, pmd-type)
# identity suffixes per IEEE Std 802.3.2-2025 (ieee802-ethernet-phy-type).
#
# phy-type names the PHY family / line coding (e.g. 1000BASE-X is the 8B/10B
# family covering LX/SX/ZX/CX); pmd-type names the specific physical medium
# (1000BASE-LX vs 1000BASE-SX). For media where ethtool's (port, speed,
# duplex) tuple uniquely identifies the variant — copper, DAC, copper-T —
# both leaves are populated with the right identities (often the same name).
# For generic fiber where the same tuple can be SR/LR/ER/etc., we only
# populate phy-type (family) and leave pmd-type as None — emitting a guess
# would be misleading. Refining the PMD on fiber needs the SFP EEPROM
# (ethtool -m), deferred.
_LINK_MODES = {
# (port, speed Mb/s, duplex): (phy-type, pmd-type or None)
("Twisted Pair", 10, "full"): ("10BASE-T", "10BASE-T"),
("Twisted Pair", 10, "half"): ("10BASE-T", "10BASE-T"),
("Twisted Pair", 100, "full"): ("100BASE-X", "100BASE-TX"),
("Twisted Pair", 100, "half"): ("100BASE-X", "100BASE-TX"),
("Twisted Pair", 1000, "full"): ("1000BASE-T", "1000BASE-T"),
("Twisted Pair", 1000, "half"): ("1000BASE-T", "1000BASE-T"),
("Twisted Pair", 2500, "full"): ("2.5GBASE-T", "2.5GBASE-T"),
("Twisted Pair", 5000, "full"): ("5GBASE-T", "5GBASE-T"),
("Twisted Pair", 10000, "full"): ("10GBASE-T", "10GBASE-T"),
("Twisted Pair", 25000, "full"): ("25GBASE-T", "25GBASE-T"),
("Twisted Pair", 40000, "full"): ("40GBASE-T", "40GBASE-T"),
("MII", 10, "full"): ("10BASE-T", "10BASE-T"),
("MII", 10, "half"): ("10BASE-T", "10BASE-T"),
("MII", 100, "full"): ("100BASE-X", "100BASE-TX"),
("MII", 100, "half"): ("100BASE-X", "100BASE-TX"),
("FIBRE", 100, "full"): ("100BASE-X", None),
("FIBRE", 1000, "full"): ("1000BASE-X", None),
("FIBRE", 10000, "full"): ("10GBASE-R", None),
("FIBRE", 25000, "full"): ("25GBASE-R", None),
("FIBRE", 40000, "full"): ("40GBASE-R", None),
("FIBRE", 100000, "full"): ("100GBASE-R", None),
# SFP+ DAC has no IEEE-standardised pmd-type (10GBASE-CR is industry
# shorthand, not a YANG identity); the phy-type-10GBASE-R family is as
# specific as we honestly get.
("Direct Attach Copper", 10000, "full"): ("10GBASE-R", None),
("Direct Attach Copper", 25000, "full"): ("25GBASE-R", "25GBASE-CR"),
("Direct Attach Copper", 40000, "full"): ("40GBASE-R", "40GBASE-CR4"),
("Direct Attach Copper", 100000, "full"): ("100GBASE-R", "100GBASE-CR4"),
}
# Map ethtool link-mode string (e.g. '10000baseLR') to IEEE pmd-type identity
# suffix. The kernel reports a separate entry per (mode, duplex) — we strip
# the trailing '/Full' or '/Half' before lookup, then dedupe in the caller.
# Where the kernel collapses several IEEE variants into one family bit
# (e.g. 1000baseX covers LX/SX/ZX/CX) we pick the most common long-reach
# variant as our representative — same convention as _LINK_MODES.
_ETHTOOL_TO_PMD = {
"10baseT": "10BASE-T",
"10baseT1L": "10BASE-T1L",
"100baseT": "100BASE-TX", # kernel uses 100baseT for 100BASE-TX
"100baseT1": "100BASE-T1",
"100baseFX": "100BASE-FX",
"1000baseT": "1000BASE-T",
"1000baseT1": "1000BASE-T1",
"1000baseX": "1000BASE-LX", # 8B/10B family — could be SX/LX/ZX
"1000baseKX": "1000BASE-KX",
"2500baseT": "2.5GBASE-T",
"2500baseX": "2.5GBASE-X",
"5000baseT": "5GBASE-T",
"10000baseT": "10GBASE-T",
"10000baseSR": "10GBASE-SR",
"10000baseLR": "10GBASE-LR",
"10000baseLRM": "10GBASE-LRM",
"10000baseER": "10GBASE-ER",
"10000baseKR": "10GBASE-KR",
"10000baseKX4": "10GBASE-KX4",
"25000baseCR": "25GBASE-CR",
"25000baseSR": "25GBASE-SR",
"25000baseKR": "25GBASE-KR",
"40000baseCR4": "40GBASE-CR4",
"40000baseSR4": "40GBASE-SR4",
"40000baseLR4": "40GBASE-LR4",
"40000baseKR4": "40GBASE-KR4",
"100000baseCR4": "100GBASE-CR4",
"100000baseSR4": "100GBASE-SR4",
"100000baseLR4_ER4": "100GBASE-LR4",
"100000baseKR4": "100GBASE-KR4",
}
def _ethtool_modes_to_pmd_identities(modes):
"""Translate ethtool 'supported/advertised-link-modes' to PMD identities.
'modes' is the list of strings ethtool emits, e.g. ['1000baseT/Full',
'10000baseLR/Full']. Returns a deduped, order-preserving list of
fully-qualified ieee802-ethernet-phy-type:pmd-type-* identities, skipping
entries we don't have a mapping for (kernel-only "filler" bits like
Autoneg, TP, FIBRE, Pause, Asym_Pause that share the link-modes bitset
namespace but aren't link modes).
"""
seen = set()
out = []
for entry in modes or []:
# Drop '/Full' or '/Half' suffix
base = entry.split("/", 1)[0]
pmd = _ETHTOOL_TO_PMD.get(base)
if pmd is None or pmd in seen:
continue
seen.add(pmd)
out.append(f"ieee802-ethernet-phy-type:pmd-type-{pmd}")
return out
def link(ifname):
"""Parse speed/duplex/autoneg from ethtool output"""
"""Read link properties from ethtool.
Returns (eth_container_dict, interface_speed_bps_or_None); the
interface speed is lifted onto ietf-interfaces:speed by the caller.
"""
if data := HOST.run_json(["ethtool", "--json", ifname], {}):
data = data[0]
else:
return None
return {}, None
eth = {}
eth["auto-negotation"] = { "enable": data.get("auto-negotation", False) }
eth = {"auto-negotiation": {"enable": data.get("auto-negotiation", False)}}
if data.get("speed"):
gbps = round((int(data["speed"]) / 1000), 3)
eth["speed"] = str(gbps)
if data.get("duplex"):
eth["duplex"] = data["duplex"].lower()
return eth
duplex = (data.get("duplex") or "").lower()
if duplex in ("full", "half"):
eth["duplex"] = duplex
# Expose what the kernel currently considers supported as a config-false
# leaf-list — varies on SFP cages with the inserted module, so it's a
# useful diagnosis facet on its own.
supported = _ethtool_modes_to_pmd_identities(data.get("supported-link-modes"))
if supported:
eth["infix-ethernet-interface:supported-pmd-types"] = supported
# Suppress when advertised == supported — that's the default
# "advertise everything" state with no diagnostic value.
advertised = _ethtool_modes_to_pmd_identities(data.get("advertised-link-modes"))
if advertised and set(advertised) != set(supported):
eth["auto-negotiation"]["infix-ethernet-interface:advertised-pmd-types"] = advertised
speed_bps = None
speed_mbps = data.get("speed")
if isinstance(speed_mbps, int) and 0 < speed_mbps < _ETHTOOL_SPEED_UNKNOWN:
speed_bps = speed_mbps * 1_000_000
port = data.get("port") or ""
if mapping := _LINK_MODES.get((port, speed_mbps, duplex)):
phy, pmd = mapping
eth["phy-type"] = f"ieee802-ethernet-phy-type:phy-type-{phy}"
if pmd is not None:
eth["pmd-type"] = f"ieee802-ethernet-phy-type:pmd-type-{pmd}"
# Refine pmd-type from supported list when the kernel reports
# exactly one mode (typically an SFP/SFP+ with a specific optic
# plugged in) — strictly more accurate than the (port, speed,
# duplex) lookup since the SFP nailed it down for us.
if len(supported) == 1:
eth["pmd-type"] = supported[0]
return eth, speed_bps
def ethernet(iplink):
eth = link(iplink["ifname"])
if eth is None:
eth = {}
"""Return (ethernet container, interface speed in bits/s or None)."""
eth, speed_bps = link(iplink["ifname"])
if stats := statistics(iplink["ifname"]):
eth["statistics"] = stats
return eth
return eth, speed_bps
@@ -159,8 +159,11 @@ def interface(iplink, ipaddr, systemjson=None):
if lg := lag.lag(iplink):
interface["infix-interfaces:lag"] = lg
case "infix-if-type:ethernet":
if eth := ethernet.ethernet(iplink):
eth, speed_bps = ethernet.ethernet(iplink)
if eth:
interface["ieee802-ethernet-interface:ethernet"] = eth
if speed_bps:
interface["speed"] = str(speed_bps)
case "infix-if-type:vxlan":
if vxlan := tun.vxlan(iplink):
interface["infix-interfaces:vxlan"] = vxlan
@@ -4,11 +4,24 @@ ifdef::topdoc[:imagesdir: {topdoc}../../test/case/interfaces/speed_duplex_copper
==== Description
Verify that the interface operates at the expected speed/duplex in two scenarios:
Verify that the interface operates at the expected speed/duplex by
restricting the set of PMD types auto-negotiation may advertise:
1. Fixed configuration host and target are both manually set to a specific speed/duplex
2. Auto-negotiation host advertises selectable modes and the target negotiates
to the highest common speed/duplex.
1. Single-mode advertise — host and target both advertise exactly
one PMD/duplex combination; the link comes up at that mode.
2. Multi-mode advertise — host advertises a set, target advertises
another set; the link comes up at the highest common.
3. Auto-negotiation off — both peers forced to a fixed speed/duplex,
the escape hatch for link partners that don't speak auto-negotiation.
Disabling autoneg also disables Auto-MDIX, so the ends use opposite
MDI/MDI-X pinouts (host mdix on, DUT mdi). The link bounces and can
take a few seconds to settle, so the forced steps poll for it.
The legacy "auto-negotiation: off + fixed speed + fixed duplex"
configuration was retired together with the obsoletion of eth:speed
in IEEE Std 802.3.2-2025; the standards-correct way to pin a link to
a specific mode is to advertise only that mode. See the augment in
infix-ethernet-interface.yang.
==== Topology
@@ -18,16 +31,18 @@ image::topology.svg[Interface Speed Duplex (Copper) topology, align=center, scal
. Set up topology and attach to target DUT
. Enable target interface
. Verify fixed 10/full
. Verify fixed 10/half
. Verify fixed 100/full
. Verify fixed 100/half
. Switch to auto-negotiation mode for target and host
. Verify auto-negotiation to 10/Full only
. Verify auto-negotiation to 10/Half only
. Verify auto-negotiation to 100/Full only
. Verify auto-negotiation to 100/Half only
. Verify auto-negotiation to 10/half + 10/full + 100/half
. Verify auto-negotiation to 10/half + 10/full + 100/half + 100/full + 1000/full
. Advertise 10/full only on both peers
. Advertise 10/half only on both peers
. Advertise 100/full only on both peers
. Advertise 100/half only on both peers
. Switch target back to advertising all supported modes
. Host advertises 10/full only
. Host advertises 10/half only
. Host advertises 100/full only
. Host advertises 100/half only
. Host advertises 10/half + 10/full + 100/half
. Host advertises every mode up to 1G
. Both sides forced to 100/full, autoneg off
. Both sides forced to 10/full, autoneg off
+239 -118
View File
@@ -2,98 +2,233 @@
"""
Interface Speed Duplex (Copper)
Verify that the interface operates at the expected speed/duplex in two scenarios:
Verify that the interface operates at the expected speed/duplex by
restricting the set of PMD types auto-negotiation may advertise:
1. Fixed configuration host and target are both manually set to a specific speed/duplex
2. Auto-negotiation host advertises selectable modes and the target negotiates
to the highest common speed/duplex.
1. Single-mode advertise — host and target both advertise exactly
one PMD/duplex combination; the link comes up at that mode.
2. Multi-mode advertise — host advertises a set, target advertises
another set; the link comes up at the highest common.
3. Auto-negotiation off — both peers forced to a fixed speed/duplex,
the escape hatch for link partners that don't speak auto-negotiation.
Disabling autoneg also disables Auto-MDIX, so the ends use opposite
MDI/MDI-X pinouts (host mdix on, DUT mdi). The link bounces and can
take a few seconds to settle, so the forced steps poll for it.
The legacy "auto-negotiation: off + fixed speed + fixed duplex"
configuration was retired together with the obsoletion of eth:speed
in IEEE Std 802.3.2-2025; the standards-correct way to pin a link to
a specific mode is to advertise only that mode. See the augment in
infix-ethernet-interface.yang.
"""
import infamy
import infamy.iface as iface
import subprocess
from infamy.util import until
ADVERTISE_MODES = {
# Values from ethtool's ETHTOOL_LINK_MODE bit positions
# See: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/ethtool.h
"10half": 0x0001,
"10full": 0x0002,
"100half": 0x0004,
"100full": 0x0008,
"1000full": 0x0020
"10half": 0x0001,
"10full": 0x0002,
"100half": 0x0004,
"100full": 0x0008,
"1000full": 0x0020,
}
# Mapping from (ethtool advertise key) → (IEEE PMD identity, duplex enum).
# Mirrors the migration table in src/confd/share/migrate/1.9/.
TARGET_MODES = {
"10half": ("ieee802-ethernet-phy-type:pmd-type-10BASE-T", "half", 10),
"10full": ("ieee802-ethernet-phy-type:pmd-type-10BASE-T", "full", 10),
"100half": ("ieee802-ethernet-phy-type:pmd-type-100BASE-TX", "half", 100),
"100full": ("ieee802-ethernet-phy-type:pmd-type-100BASE-TX", "full", 100),
"1000full": ("ieee802-ethernet-phy-type:pmd-type-1000BASE-T", "full", 1000),
}
def advertise_host_modes(interface, modes):
mask = 0
for mode in modes:
mask |= ADVERTISE_MODES[mode]
try:
subprocess.run([
"ethtool", "-s", interface,
"advertise", hex(mask)
], check=True)
subprocess.run(["ethtool", "-s", interface, "advertise", hex(mask)],
check=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to advertise modes via ethtool: {e}")
def enable_host_autoneg_full(interface):
"""Restore the host NIC to autoneg-on with Auto-MDIX.
'autoneg on' re-enables negotiation and advertises all supported modes;
each test step sets the host advertise explicitly, so no extra mask
handling is needed here. Separately clear any forced MDI/MDI-X pinout
left by force_host_fixed — best-effort, since not every NIC exposes mdix.
"""
try:
subprocess.run(["ethtool", "-s", interface, "autoneg", "on"], check=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to restore host autoneg: {e}")
subprocess.run(["ethtool", "-s", interface, "mdix", "auto"], check=False)
def force_host_fixed(interface, speed_mbps, duplex, mdix="on"):
"""Pin host to a fixed speed/duplex with auto-negotiation OFF.
Auto-MDIX is disabled in forced mode, so host and DUT take opposite
pinouts; default mdix=on (MDI-X) to pair with the DUT's mdi.
"""
try:
subprocess.run(["ethtool", "-s", interface, "autoneg", "off",
"speed", str(speed_mbps), "duplex", duplex,
"mdix", mdix],
check=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to force host fixed mode: {e}")
def get_target_speed_duplex(target, interface):
data = target.get_data(f"/ietf-interfaces:interfaces/interface[name='{interface}']") \
data = target.get_data(iface.get_xpath(interface)) \
["interfaces"]["interface"][interface]
eth = data.get("ethernet", {})
return eth.get("speed"), eth.get("duplex")
# Operational speed under ietf-interfaces:speed (bits/s, RFC 8343).
speed_bps = data.get("speed")
return speed_bps, eth.get("duplex")
def set_target_advertise(target, interface, mode_keys):
"""Configure the target interface to advertise the given set of PMDs.
mode_keys is a list of host-side mode names (e.g. ['10full', '100full']).
Translates to the corresponding (pmd-type, duplex) for the target.
When all entries share the same duplex, that duplex is also set on the
interface as an additional restriction.
"""
pmds = []
duplexes = set()
for key in mode_keys:
pmd, duplex, _ = TARGET_MODES[key]
if pmd not in pmds:
pmds.append(pmd)
duplexes.add(duplex)
eth = {
"auto-negotiation": {
"infix-ethernet-interface:advertised-pmd-types": pmds,
},
}
if len(duplexes) == 1:
eth["duplex"] = duplexes.pop()
def set_target_speed_duplex(target, interface, speed, duplex):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": interface,
"ethernet": {
"auto-negotiation": {
"enable": False
},
"speed": speed / 1000,
"duplex": duplex
}
}]
}
"ietf-interfaces": {
"interfaces": {
"interface": [{"name": interface, "ethernet": eth}]
}
})
}
})
def set_host_speed_duplex(interface, speed, duplex):
def force_target_fixed(target, interface, mode_key, mdi_x=False):
"""Configure the target with auto-negotiation disabled, pinned to one PMD.
Exercises confd's enable=false escape hatch: the apply path emits
'ethtool --change <if> autoneg off speed N duplex D mdix ...' from the
single advertised-pmd-types entry, the duplex leaf, and the mdi-x leaf.
Default mdi_x=False (MDI) pairs with the host's forced MDI-X.
"""
pmd, duplex, _ = TARGET_MODES[mode_key]
# enable=false requires exactly one advertised-pmd-types entry, but
# put_config_dicts (PATCH) merges leaf-lists, so successive forced
# steps would accumulate entries. Reset the ethernet sub-config first
# (tolerate absence on the first call).
try:
subprocess.run([
"ethtool", "-s", interface,
"speed", str(speed),
"duplex", duplex,
"autoneg", "off"
], check=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to set speed/duplex via ethtool: {e}")
clear_target_advertise(target, interface)
except Exception:
pass
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": interface,
"ethernet": {
"auto-negotiation": {
"enable": False,
"infix-ethernet-interface:advertised-pmd-types": [pmd],
},
"duplex": duplex,
"infix-ethernet-interface:mdi-x": mdi_x,
},
}]
}
}
})
def verify_speed_duplex(target, ns, interface, exp_speed, exp_duplex):
until(lambda: speed_duplex_present(target, interface))
act_speed, act_duplex = get_target_speed_duplex(target, interface)
if act_speed is None or act_duplex is None:
print(f"Could not fetch speed or duplex from target for interface {interface}")
def clear_target_advertise(target, interface):
"""Drop the entire ethernet sub-config on the target.
Targets the parent container rather than the individual leaves because
RESTCONF DELETE on a leaf-list URI without a '=value' key is a silent
no-op (RFC 8040 §3.5.3.2: leaf-list instance URIs must carry the value
as the key — rousette/libyang materialise an empty leaf-list node that
matches no entry). Deleting the container removes all descendants in
one go, which is exactly what this test needs.
"""
target.delete_xpath(iface.get_xpath(interface, "ieee802-ethernet-interface:ethernet"))
def verify_speed_duplex(target, ns, interface, exp_mbps, exp_duplex):
until(lambda: _speed_duplex_present(target, interface))
speed_bps, duplex = get_target_speed_duplex(target, interface)
if speed_bps is None or duplex is None:
print(f"Could not fetch speed/duplex from target for interface {interface}")
test.fail()
exp_speed_gbps = exp_speed / 1000
if float(act_speed) != exp_speed_gbps:
print(f"act_speed: {act_speed}, exp_speed: {exp_speed_gbps}")
act_mbps = int(speed_bps) // 1_000_000
if act_mbps != exp_mbps:
print(f"act_mbps: {act_mbps}, exp_mbps: {exp_mbps}")
test.fail()
if act_duplex.lower() != exp_duplex.lower():
print(f"act_duplex: {act_duplex}, exp_duplex: {exp_duplex}")
if duplex.lower() != exp_duplex.lower():
print(f"act_duplex: {duplex}, exp_duplex: {exp_duplex}")
test.fail()
ns.must_reach("10.0.0.2")
print(f"Verified: {interface} is operating at {act_mbps} Mbps, {duplex} duplex")
print(f"Verified: {interface} is operating at {act_speed} Gbps, {act_duplex} duplex")
def speed_duplex_present(target, interface):
speed, duplex = get_target_speed_duplex(target, interface)
return speed is not None and duplex is not None
def _speed_duplex_present(target, interface):
speed_bps, duplex = get_target_speed_duplex(target, interface)
return speed_bps is not None and duplex is not None
def verify_forced_speed_duplex(target, ns, interface, exp_mbps, exp_duplex):
"""Verify a forced (autoneg off) link reaches exp speed/duplex.
Turning auto-negotiation off bounces the link; it can take a few
seconds to settle, so poll the operational speed/duplex AND a ping
together until both hold instead of checking once.
"""
def settled():
speed_bps, duplex = get_target_speed_duplex(target, interface)
if not speed_bps or not duplex:
return False
if int(speed_bps) // 1_000_000 != exp_mbps:
return False
if duplex.lower() != exp_duplex.lower():
return False
try:
ns.ping("10.0.0.2", timeout=3)
except Exception:
return False
return True
until(settled, attempts=30)
print(f"Verified: {interface} forced to {exp_mbps} Mbps, {exp_duplex} duplex")
def enable_target_interface(target, interface):
target.put_config_dicts({
@@ -102,54 +237,26 @@ def enable_target_interface(target, interface):
"interface": [{
"name": interface,
"enabled": True,
"ipv4": {
"address": [
{
"ip": "10.0.0.2",
"prefix-length": 24
}
]
}
"ipv4": {"address": [{"ip": "10.0.0.2", "prefix-length": 24}]}
}]
}
}
})
def enable_target_autoneg(target, interface):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": interface,
"ethernet": {
"auto-negotiation": {
"enable": True
}
}
}]
}
}
})
def enable_host_autoneg(interface):
subprocess.run(["ethtool", "-s", interface, "autoneg", "on"], check=True)
def cleanup(target, hdata, tdata):
"""
Restore both host and target interfaces to autonegotiation mode
to ensure clean state for future tests.
"""
print("Restoring interfaces to default (autoneg on)")
"""Restore both host and target to 'advertise everything supported'."""
print("Restoring interfaces to default (advertise all)")
try:
enable_host_autoneg(hdata)
enable_host_autoneg_full(hdata)
except Exception as e:
print(f"Host autoneg restore failed: {e}")
print(f"Host restore failed: {e}")
try:
enable_target_interface(target, tdata)
enable_target_autoneg(target, tdata)
clear_target_advertise(target, tdata)
except Exception as e:
print(f"Target autoneg restore failed: {e}")
print(f"Target restore failed: {e}")
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUT"):
@@ -157,64 +264,78 @@ with infamy.Test() as test:
target = env.attach("target", "mgmt")
_, hdata = env.ltop.xlate("host", "data")
_, tdata = env.ltop.xlate("target", "data")
# Append a test cleanup function
test.push_test_cleanup(lambda: cleanup(target, hdata, tdata))
with test.step("Enable target interface"):
enable_target_interface(target, tdata)
with infamy.IsolatedMacVlan(hdata) as ns:
ns.addip("10.0.0.1")
# Fixed mode tests
with test.step("Verify fixed 10/full"):
set_host_speed_duplex(hdata, 10, "full")
set_target_speed_duplex(target, tdata, 10, "full")
# Pinned-mode tests: both peers advertise exactly one mode.
with test.step("Advertise 10/full only on both peers"):
advertise_host_modes(hdata, ["10full"])
set_target_advertise(target, tdata, ["10full"])
verify_speed_duplex(target, ns, tdata, 10, "full")
with test.step("Verify fixed 10/half"):
set_host_speed_duplex(hdata, 10, "half")
set_target_speed_duplex(target, tdata, 10, "half")
with test.step("Advertise 10/half only on both peers"):
advertise_host_modes(hdata, ["10half"])
set_target_advertise(target, tdata, ["10half"])
verify_speed_duplex(target, ns, tdata, 10, "half")
with test.step("Verify fixed 100/full"):
set_host_speed_duplex(hdata, 100, "full")
set_target_speed_duplex(target, tdata, 100, "full")
with test.step("Advertise 100/full only on both peers"):
advertise_host_modes(hdata, ["100full"])
set_target_advertise(target, tdata, ["100full"])
verify_speed_duplex(target, ns, tdata, 100, "full")
with test.step("Verify fixed 100/half"):
set_host_speed_duplex(hdata, 100, "half")
set_target_speed_duplex(target, tdata, 100, "half")
with test.step("Advertise 100/half only on both peers"):
advertise_host_modes(hdata, ["100half"])
set_target_advertise(target, tdata, ["100half"])
verify_speed_duplex(target, ns, tdata, 100, "half")
# Auto-negotiation tests: host advertises, Infix negotiates
with test.step("Switch to auto-negotiation mode for target and host"):
enable_host_autoneg(hdata)
enable_target_autoneg(target, tdata)
# Multi-mode advertise tests: host restricted, target advertises all.
with test.step("Switch target back to advertising all supported modes"):
advertise_host_modes(hdata, ["100half"])
clear_target_advertise(target, tdata)
verify_speed_duplex(target, ns, tdata, 100, "half")
with test.step("Verify auto-negotiation to 10/Full only"):
with test.step("Host advertises 10/full only"):
advertise_host_modes(hdata, ["10full"])
verify_speed_duplex(target, ns, tdata, 10, "full")
with test.step("Verify auto-negotiation to 10/Half only"):
with test.step("Host advertises 10/half only"):
advertise_host_modes(hdata, ["10half"])
verify_speed_duplex(target, ns, tdata, 10, "half")
with test.step("Verify auto-negotiation to 100/Full only"):
with test.step("Host advertises 100/full only"):
advertise_host_modes(hdata, ["100full"])
verify_speed_duplex(target, ns, tdata, 100, "full")
with test.step("Verify auto-negotiation to 100/Half only"):
with test.step("Host advertises 100/half only"):
advertise_host_modes(hdata, ["100half"])
verify_speed_duplex(target, ns, tdata, 100, "half")
with test.step("Verify auto-negotiation to 10/half + 10/full + 100/half"):
with test.step("Host advertises 10/half + 10/full + 100/half"):
advertise_host_modes(hdata, ["10half", "10full", "100half"])
verify_speed_duplex(target, ns, tdata, 100, "half")
with test.step("Verify auto-negotiation to 10/half + 10/full + 100/half + 100/full + 1000/full"):
advertise_host_modes(hdata, ["10half", "10full", "100half", "100full", "1000full"])
with test.step("Host advertises every mode up to 1G"):
advertise_host_modes(hdata, ["10half", "10full", "100half",
"100full", "1000full"])
verify_speed_duplex(target, ns, tdata, 1000, "full")
test.succeed()
# Auto-negotiation off — escape hatch for non-autoneg peers. Both
# ends forced to a fixed mode with autoneg disabled (host mdix on,
# DUT mdi). The link bounces, so verify_forced_speed_duplex polls
# until it settles.
with test.step("Both sides forced to 100/full, autoneg off"):
force_host_fixed(hdata, 100, "full")
force_target_fixed(target, tdata, "100full")
verify_forced_speed_duplex(target, ns, tdata, 100, "full")
with test.step("Both sides forced to 10/full, autoneg off"):
force_host_fixed(hdata, 10, "full")
force_target_fixed(target, tdata, "10full")
verify_forced_speed_duplex(target, ns, tdata, 10, "full")
test.succeed()
@@ -57,7 +57,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -80,7 +80,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -120,7 +120,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -160,7 +160,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -207,7 +207,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -237,7 +237,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -267,7 +267,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
+7 -7
View File
@@ -35,7 +35,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -65,7 +65,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -105,7 +105,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -145,7 +145,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -185,7 +185,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -215,7 +215,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -245,7 +245,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
+41 -41
View File
@@ -1,41 +1,41 @@
⚑ INTERFACE PROTOCOL STATE DATA 
lo loopback UP 
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
br0 bridge  vlan:1u pvid:1
│ ethernet UP 00:a0:85:00:03:00
│ ipv4 169.254.1.1/16 (random)
│ ipv6 fe80::2a0:85ff:fe00:300/64 (link-layer)
├ e3 bridge FORWARDING vlan:1u pvid:1
├ e4 bridge FORWARDING vlan:1u pvid:1
├ veth0b bridge FORWARDING vlan:1u pvid:1
└ veth2b bridge FORWARDING vlan:1u pvid:1
br1 bridge  
│ ethernet UP 00:a0:85:00:03:00
├ veth1b bridge FORWARDING vlan:6u pvid:6
└ veth3b bridge FORWARDING 
e1 ethernet UP 00:a0:85:00:03:01
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
e2 ethernet UP 00:a0:85:00:03:02
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
e3.8 ethernet UP 00:a0:85:00:03:03
│ ipv4 10.1.1.1/32 (static)
└ e3 ethernet UP 00:a0:85:00:03:03
e4.8 ethernet UP 00:a0:85:00:03:04
│ ipv4 10.1.1.1/32 (static)
└ e4 ethernet UP 00:a0:85:00:03:04
e5 ethernet UP 00:a0:85:00:03:05
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
e6 ethernet UP 00:a0:85:00:03:06
ipv4 10.1.1.101/24 (static)
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
e7 ethernet UP 00:a0:85:00:03:07
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
veth0a container container-A 
veth0b veth UP e6:19:75:86:80:dd
veth1a container container-A 
veth1b veth UP 3e:67:0f:15:24:14
veth2a container container-B 
veth2b veth UP b2:fa:30:63:98:f0
veth3a container container-B 
veth3b veth UP b2:1c:fa:a7:45:eb
⚑ INTERFACE PROTOCOL STATE DATA 
lo loopback UP 
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
br0 bridge  vlan: 1u pvid: 1
│ ethernet 00:a0:85:00:03:00
│ ipv4 169.254.1.1/16 (random)
│ ipv6 fe80::2a0:85ff:fe00:300/64 (link-layer)
├ e3 bridge FORWARDING vlan: 1u pvid: 1
├ e4 bridge FORWARDING vlan: 1u pvid: 1
├ veth0b bridge FORWARDING vlan: 1u pvid: 1
└ veth2b bridge FORWARDING vlan: 1u pvid: 1
br1 bridge  
│ ethernet 00:a0:85:00:03:00
├ veth1b bridge FORWARDING vlan: 6u pvid: 6
└ veth3b bridge FORWARDING 
e1 ethernet UP 00:a0:85:00:03:01
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
e2 ethernet UP 00:a0:85:00:03:02
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
e3.8 vlan UP vid: 8
│ ipv4 10.1.1.1/32 (static)
└ e3
e4.8 vlan UP vid: 8
│ ipv4 10.1.1.1/32 (static)
└ e4
e5 ethernet UP 00:a0:85:00:03:05
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
e6 ethernet UP 00:a0:85:00:03:06
ipv4 10.1.1.101/24 (static)
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
e7 ethernet UP 00:a0:85:00:03:07
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
veth0a container container-A 
veth0b veth UP e6:19:75:86:80:dd
veth1a container container-A 
veth1b veth UP 3e:67:0f:15:24:14
veth2a container container-B 
veth2b veth UP b2:fa:30:63:98:f0
veth3a container container-B 
veth3b veth UP b2:1c:fa:a7:45:eb
@@ -57,7 +57,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -87,7 +87,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -110,7 +110,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -151,7 +151,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -199,7 +199,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -236,7 +236,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -266,7 +266,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
+7 -7
View File
@@ -35,7 +35,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -65,7 +65,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -95,7 +95,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -136,7 +136,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -177,7 +177,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -207,7 +207,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -244,7 +244,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -1,51 +1,55 @@
⚑ INTERFACE PROTOCOL STATE DATA 
lo loopback UP 
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
br-0 bridge DOWN 
ethernet DOWN 00:a0:85:00:03:00
br-D bridge  
│ ethernet UP 00:a0:85:00:03:00
│ ipv4 10.0.0.1/8 (static)
│ ipv4 192.168.20.1/24 (static)
│ ipv6 2001:db8::1/64 (static)
│ ipv6 fe80::2a0:85ff:fe00:300/64 (link-layer)
└ veth0a.20 bridge FORWARDING 
br-Q bridge  vlan:20u,30u,40t
│ ethernet UP 00:a0:85:00:03:00
├ e3 bridge FORWARDING vlan:20t,30t,40t
└ veth0b bridge FORWARDING vlan:20t,30t,40t
br-Q.40 ethernet UP 00:a0:85:00:03:00
└ br-Q ethernet UP 00:a0:85:00:03:00
br-X bridge  
│ ethernet UP 00:a0:85:00:03:00
└ e2.30 bridge FORWARDING 
e1 ethernet UP 00:a0:85:00:03:01
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
e2 ethernet UP 00:a0:85:00:03:02
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
e2.30 ethernet UP 00:a0:85:00:03:02
└ e2 ethernet UP 00:a0:85:00:03:02
e3.10 ethernet UP 00:a0:85:00:03:03
└ e3 ethernet UP 00:a0:85:00:03:03
e4 ethernet UP 00:a0:85:00:03:04
ipv6 fe80::2a0:85ff:fe00:304/64 (link-layer)
e5 ethernet UP 00:a0:85:00:03:05
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
e6 ethernet UP 00:a0:85:00:03:06
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
e7 ethernet UP 00:a0:85:00:03:07
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
gre-v4 gre UP 
gre-v6 gre UP 
ipv4 192.168.50.2/16 (static)
gretap-v4 gretap UP f6:d4:96:d8:9f:96
gretap-v6 gretap UP 7a:46:13:bd:fa:e6
veth0a veth UP 6e:d0:98:c4:e7:ef
veth0a.20 ethernet UP 6e:d0:98:c4:e7:ef
veth0a ethernet UP 6e:d0:98:c4:e7:ef
veth0b veth UP 36:da:80:06:7f:99
vxlan-v4 vxlan UP 8a:ea:59:32:df:70
ipv4 192.168.30.2/24 (static)
vxlan-v6 vxlan UP 3e:30:c6:a1:71:64
ipv4 192.168.40.2/24 (static)
⚑ INTERFACE PROTOCOL STATE DATA 
lo loopback UP 
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
br-0 bridge DOWN 
ethernet 00:a0:85:00:03:00
br-D bridge  
│ ethernet 00:a0:85:00:03:00
│ ipv4 10.0.0.1/8 (static)
│ ipv4 192.168.20.1/24 (static)
│ ipv6 2001:db8::1/64 (static)
│ ipv6 fe80::2a0:85ff:fe00:300/64 (link-layer)
└ veth0a.20 bridge FORWARDING 
br-Q bridge  vlan: 20u,30u,40t
│ ethernet 00:a0:85:00:03:00
├ e3 bridge FORWARDING vlan: 20t,30t,40t
└ veth0b bridge FORWARDING vlan: 20t,30t,40t
br-Q.40 vlan UP vid: 40
└ br-Q
br-X bridge  
│ ethernet 00:a0:85:00:03:00
└ e2.30 bridge FORWARDING 
e1 ethernet UP 00:a0:85:00:03:01
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
e2 ethernet UP 00:a0:85:00:03:02
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
e2.30 vlan UP vid: 30
└ e2
e3.10 vlan UP vid: 10
└ e3
e4 ethernet UP 00:a0:85:00:03:04
ipv6 fe80::2a0:85ff:fe00:304/64 (link-layer)
e5 ethernet UP 00:a0:85:00:03:05
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
e6 ethernet UP 00:a0:85:00:03:06
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
e7 ethernet UP 00:a0:85:00:03:07
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
gre-v4 gre UP remote: 192.168.20.2
gre-v6 gre UP remote: 2001:db8::2
ipv4 192.168.50.2/16 (static)
gretap-v4 gre UP remote: 192.168.20.2
ethernet f6:d4:96:d8:9f:96
gretap-v6 gre UP remote: 2001:db8::2
ethernet 7a:46:13:bd:fa:e6
veth0a veth UP 6e:d0:98:c4:e7:ef
veth0a.20 vlan UP vid: 20
└ veth0a
veth0b veth UP 36:da:80:06:7f:99
vxlan-v4 vxlan UP vni: 4 remote: 192.168.20.200
ethernet 8a:ea:59:32:df:70
ipv4 192.168.30.2/24 (static)
vxlan-v6 vxlan UP vni: 6 remote: 2001:db8::200
ethernet 3e:30:c6:a1:71:64
ipv4 192.168.40.2/24 (static)
@@ -1,9 +1,9 @@
name : br-0
type : bridge
index : 9
mtu : 1500
operational status : down
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
name : br-0
type : bridge
index : 9
mtu : 1500
operational status : down
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
@@ -1,11 +1,11 @@
name : br-D
type : bridge
index : 15
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses : 10.0.0.1/8 (static)
192.168.20.1/24 (static)
ipv6 addresses : 2001:db8::1/64 (static)
fe80::2a0:85ff:fe00:300/64 (link-layer)
name : br-D
type : bridge
index : 15
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses : 10.0.0.1/8 (static)
192.168.20.1/24 (static)
ipv6 addresses : 2001:db8::1/64 (static)
fe80::2a0:85ff:fe00:300/64 (link-layer)
@@ -1,9 +1,9 @@
name : br-Q
type : bridge
index : 16
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
name : br-Q
type : bridge
index : 16
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
@@ -1,10 +1,10 @@
name : br-Q.40
type : vlan
index : 17
mtu : 1500
operational status : up
ip forwarding : disabled
lower-layer-if : br-Q
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
name : br-Q.40
type : vlan
index : 17
mtu : 1500
operational status : up
ip forwarding : disabled
lower-layer-if : br-Q
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
@@ -1,9 +1,9 @@
name : br-X
type : bridge
index : 11
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
name : br-X
type : bridge
index : 11
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 00:a0:85:00:03:00
ipv4 addresses :
ipv6 addresses :
@@ -1,10 +1,10 @@
name : gre-v4
type : gre
index : 19
mtu : 1476
operational status : up
ip forwarding : disabled
ipv4 addresses :
ipv6 addresses :
local address : 192.168.20.1
remote address : 192.168.20.2
name : gre-v4
type : gre
index : 19
mtu : 1476
operational status : up
ip forwarding : disabled
ipv4 addresses :
ipv6 addresses :
local address : 192.168.20.1
remote address : 192.168.20.2
@@ -1,10 +1,10 @@
name : gre-v6
type : gre
index : 20
mtu : 1448
operational status : up
ip forwarding : disabled
ipv4 addresses : 192.168.50.2/16 (static)
ipv6 addresses :
local address : 2001:db8::1
remote address : 2001:db8::2
name : gre-v6
type : gre
index : 20
mtu : 1448
operational status : up
ip forwarding : disabled
ipv4 addresses : 192.168.50.2/16 (static)
ipv6 addresses :
local address : 2001:db8::1
remote address : 2001:db8::2
@@ -1,11 +1,11 @@
name : gretap-v4
type : gretap
index : 21
mtu : 1462
operational status : up
ip forwarding : disabled
physical address : f6:d4:96:d8:9f:96
ipv4 addresses :
ipv6 addresses :
local address : 192.168.20.1
remote address : 192.168.20.2
name : gretap-v4
type : gretap
index : 21
mtu : 1462
operational status : up
ip forwarding : disabled
physical address : f6:d4:96:d8:9f:96
ipv4 addresses :
ipv6 addresses :
local address : 192.168.20.1
remote address : 192.168.20.2
@@ -1,11 +1,11 @@
name : gretap-v6
type : gretap
index : 22
mtu : 1434
operational status : up
ip forwarding : disabled
physical address : 7a:46:13:bd:fa:e6
ipv4 addresses :
ipv6 addresses :
local address : 2001:db8::1
remote address : 2001:db8::2
name : gretap-v6
type : gretap
index : 22
mtu : 1434
operational status : up
ip forwarding : disabled
physical address : 7a:46:13:bd:fa:e6
ipv4 addresses :
ipv6 addresses :
local address : 2001:db8::1
remote address : 2001:db8::2
@@ -1,11 +1,11 @@
name : veth0a
type : veth
index : 13
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 6e:d0:98:c4:e7:ef
ipv4 addresses :
ipv6 addresses :
in-octets : 299
out-octets : 17190
name : veth0a
type : veth
index : 13
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 6e:d0:98:c4:e7:ef
ipv4 addresses :
ipv6 addresses :
in-octets : 299
out-octets : 17190
@@ -1,10 +1,10 @@
name : veth0a.20
type : vlan
index : 14
mtu : 1500
operational status : up
ip forwarding : disabled
lower-layer-if : veth0a
physical address : 6e:d0:98:c4:e7:ef
ipv4 addresses :
ipv6 addresses :
name : veth0a.20
type : vlan
index : 14
mtu : 1500
operational status : up
ip forwarding : disabled
lower-layer-if : veth0a
physical address : 6e:d0:98:c4:e7:ef
ipv4 addresses :
ipv6 addresses :
@@ -1,11 +1,11 @@
name : veth0b
type : veth
index : 12
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 36:da:80:06:7f:99
ipv4 addresses :
ipv6 addresses :
in-octets : 17190
out-octets : 299
name : veth0b
type : veth
index : 12
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 36:da:80:06:7f:99
ipv4 addresses :
ipv6 addresses :
in-octets : 17190
out-octets : 299
@@ -1,12 +1,12 @@
name : vxlan-v4
type : vxlan
index : 23
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 8a:ea:59:32:df:70
ipv4 addresses : 192.168.30.2/24 (static)
ipv6 addresses :
local address : 192.168.20.100
remote address : 192.168.20.200
VxLAN id : 4
name : vxlan-v4
type : vxlan
index : 23
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 8a:ea:59:32:df:70
ipv4 addresses : 192.168.30.2/24 (static)
ipv6 addresses :
local address : 192.168.20.100
remote address : 192.168.20.200
VxLAN id : 4
@@ -1,12 +1,12 @@
name : vxlan-v6
type : vxlan
index : 24
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 3e:30:c6:a1:71:64
ipv4 addresses : 192.168.40.2/24 (static)
ipv6 addresses :
local address : 2001:db8::100
remote address : 2001:db8::200
VxLAN id : 6
name : vxlan-v6
type : vxlan
index : 24
mtu : 1500
operational status : up
ip forwarding : disabled
physical address : 3e:30:c6:a1:71:64
ipv4 addresses : 192.168.40.2/24 (static)
ipv6 addresses :
local address : 2001:db8::100
remote address : 2001:db8::200
VxLAN id : 6
@@ -57,7 +57,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -87,7 +87,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -109,7 +109,7 @@
"mtu": 1500
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -156,7 +156,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -186,7 +186,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -216,7 +216,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -246,7 +246,7 @@
]
},
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
}
@@ -35,7 +35,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -65,7 +65,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -95,7 +95,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -134,7 +134,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -164,7 +164,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -194,7 +194,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},
@@ -224,7 +224,7 @@
{
"admin-status": "up",
"ieee802-ethernet-interface:ethernet": {
"auto-negotation": {
"auto-negotiation": {
"enable": false
}
},