mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
cli: layered show interface, IEEE 802.3.2-2025 ethernet model
Import ieee802-ethernet-interface@2025-09-10.yang, from IEEE 802.3.2-2025, and companion ieee802-ethernet-phy-type.yang, replacing the 2019 revision. Operational interface speed moves to ietf-interfaces:speed, RFC 8343, eth:speed is now obsolete. Bump infix-interfaces.yang revision to track the upgrade. The CLI 'show interface' command renders interfaces as bottom-up layered protocol rows. Ethernet interfaces a new IEEE link-mode row (1000baseT, 10GbaseLR, ...) is added with 'duplex: full|half' in the DATA column. Without link the ethernet row is the first row. Tunnels and wifi follow the same layering: gre/vxlan rows carry remote:/vni: tokens with optional ethernet sub-row for the L2-bearing variants; wifi rows carry 'station' or 'access-point' ssid:, signal:, stations: tokens. admin@bpi-76-8f-c2:/> show interface ⚑ INTERFACE PROTOCOL STATE DATA ⇅ lo loopback UP ipv4 127.0.0.1/8 (static) ipv6 ::1/128 (static) ⇅ br0 bridge DOWN │ ethernet 32:2e:3f:76:8f:c2 │ ipv4 192.168.0.1/24 (static) ⇅ ├ lan0 bridge LOWER-DOWN ⇅ ├ lan1 bridge LOWER-DOWN ⇅ ├ lan2 bridge LOWER-DOWN ⇅ └ lan3 bridge LOWER-DOWN ⇅ gre0 gre UP remote: 198.51.100.7 ipv4 10.255.0.1/30 (static) ⇅ sfp1 ethernet DOWN ca:59:f0:77:80:5b ⇅ wan 1000baseT UP duplex: full ethernet 32:2e:3f:76:8f:c2 ipv4 192.168.0.235/24 (dhcp) ipv6 fe80::302e:3fff:fe76:8fc2/64 (link-layer) ⇅ wan.10 vlan UP vid: 10 │ ipv4 10.0.10.1/24 (static) └ wan ⇅ wan.10.20 vlan UP vid: 20 │ ipv4 10.0.10.20/28 (static) └ wan.10 ⇅ wifi0 wifi UP station ssid: corp-net signal: good ethernet dc:a6:32:00:11:22 ipv4 192.168.7.42/24 (dhcp) yanger populates phy-type and pmd-type from a static ETHTOOL link-mode identity table keyed on (port, speed, duplex). Both leaves are populated for unambiguous media (copper, DAC, copper-T); for generic fiber where the (port, speed, duplex) tuple can map to multiple PMDs (SR vs LR vs ER, etc.) only the phy-type family identity is emitted — guessing the PMD would be misleading. cli_pretty prefers pmd-type (specific) and falls back to phy-type (family) for display. yanger also emits ietf-interfaces:speed and fixes a long-standing 'auto-negotation' typo (yanger had never matched ethtool's correctly- spelled JSON field, so operational auto-negotiation always read 'unknown'). Filling the WG's gap on fixed-speed config ------------------------------------------ IEEE Std 802.3.2-2025 obsoleted the eth:speed leaf without providing a config-true replacement; the standards-correct way to express what older Infix configurations called 'fixed speed' is to restrict the set of PMDs auto-negotiation may advertise. Augment auto-negotiation with two leaf-lists: auto-negotiation/advertised-pmd-types config-true, leaf-list of pmd-type ethernet/supported-pmd-types config-false, leaf-list of pmd-type Pinning a port to a single mode is now expressed as a single-entry advertised-pmd-types list. The kernel-supported set is exposed as operational state for diagnosis — SFP/SFP+ cages report the inserted module's capabilities, narrowing the list to a single PMD when the optic only supports one mode (as suggested by @wkz in PR review). When the supported list collapses to a single entry, yanger uses it to refine the operational pmd-type leaf — more accurate than the (port, speed, duplex) lookup for fiber. confd C apply path (src/confd/src/ieee802-ethernet-interface.c) translates each advertised pmd-type identity to the corresponding ETHTOOL_LINK_MODE_*_BIT_*, ORs them into a mask, and emits 'ethtool --change <if> autoneg on advertise 0x<mask>'. An empty list keeps the historical default of advertising every supported mode. The (legacy) 'auto-negotiation/enable = false' + speed/duplex branch is removed — it has no model representation any more. cli_pretty's detail view gains 'advertised' and 'supported' rows listing the PMDs in each set. A new _pr_label_list() helper unifies multi-row rendering across these new rows and the pre-existing ipv4/ipv6 address rows. The detailed interface view also gains a 'link mode' row carrying the pmd-type / phy-type-derived label. Migration of existing startup configurations -------------------------------------------- Bump confd version 1.8 → 1.9 to trigger the migration on upgrade. share/migrate/1.9/10-ethernet-advertise.sh translates old configs of the form ethernet { auto-negotiation { enable false; } speed S; duplex D; } into ethernet { auto-negotiation { advertised-pmd-types [PMD]; } duplex D; } mapping (S, D) → PMD via a static lookup covering the copper-T speeds the deprecated speed leaf historically supported (10/100/1000/2.5G/ 5G/10G). Interfaces that don't disable auto-negotiation, or that lack a speed leaf, are passed through untouched. Closes #530 Closes #805 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+51
-19
@@ -98,40 +98,72 @@ 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 of speed/duplex is the desired default for almost all
|
||||
use-cases, but sometimes a port must come up at a specific speed —
|
||||
typically when interoperating with legacy hardware that does not
|
||||
auto-negotiate, or that does so poorly. IEEE Std 802.3.2-2025 retired
|
||||
the older *disable auto-negotiation, then set fixed speed/duplex*
|
||||
idiom; the standards-correct way to express the same intent is to
|
||||
**restrict the set of PMD types auto-negotiation may advertise**.
|
||||
When only one PMD is advertised, the link pins to that mode against
|
||||
any cooperating peer.
|
||||
|
||||
> [!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.
|
||||
Each entry in `auto-negotiation/advertised-pmd-types` is an IEEE
|
||||
PMD-type identity (`ieee802-ethernet-phy-type:pmd-type-*`). Half- vs
|
||||
full-duplex pinning is expressed by the orthogonal `duplex` leaf.
|
||||
|
||||
The example below configures port eth3 to fixed speed 100 Mbit/s
|
||||
half-duplex mode.
|
||||
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.
|
||||
Listing multiple PMD identities advertises that set; the peer's
|
||||
auto-negotiation picks the highest mutually-supported mode.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When pinning to a specific link mode, ensure both sides of the link
|
||||
> agree on at least one common (PMD, duplex) combination. If they
|
||||
> don't, the link will not come up.
|
||||
|
||||
> [!NOTE]
|
||||
> Earlier Infix releases used `auto-negotiation/enable=false` with
|
||||
> `speed` and `duplex` leaves to express the same thing. That syntax
|
||||
> is retired together with the IEEE obsoletion of `eth:speed`; existing
|
||||
> `startup-config.cfg` snippets are automatically migrated to the new
|
||||
> shape on upgrade.
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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
@@ -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"
|
||||
@@ -0,0 +1,2 @@
|
||||
migratedir = $(pkgdatadir)/migrate/1.9
|
||||
dist_migrate_DATA = 10-ethernet-advertise.sh
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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:<{20}}:")
|
||||
return
|
||||
first = True
|
||||
for value in values:
|
||||
key = label if first else ''
|
||||
colon = ':' if first else ' '
|
||||
print(f"{key:<{20}}{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
|
||||
@@ -1549,16 +1600,27 @@ class Iface:
|
||||
if self.lower_if:
|
||||
print(f"{'lower-layer-if':<{20}}: {self.lower_if}")
|
||||
|
||||
if self.autoneg != 'unknown':
|
||||
val = "on" if self.autoneg else "off"
|
||||
print(f"{'auto-negotiation':<{20}}: {val}")
|
||||
if label := self._phy_label():
|
||||
print(f"{'link mode':<{20}}: {label}")
|
||||
|
||||
if self.speed:
|
||||
mbps = int(self.speed) // 1_000_000
|
||||
print(f"{'speed':<{20}}: {mbps}")
|
||||
|
||||
if self.duplex:
|
||||
print(f"{'duplex':<{20}}: {self.duplex}")
|
||||
|
||||
if self.speed:
|
||||
mbs = float(self.speed) * 1000
|
||||
print(f"{'speed':<{20}}: {int(mbs)}")
|
||||
if self.autoneg != 'unknown':
|
||||
val = "on" if self.autoneg else "off"
|
||||
print(f"{'auto-negotiation':<{20}}: {val}")
|
||||
|
||||
if self.advertised:
|
||||
self._pr_label_list('advertised',
|
||||
[self._pmd_label(pmd) for pmd in self.advertised])
|
||||
|
||||
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}")
|
||||
@@ -1589,31 +1651,13 @@ class Iface:
|
||||
print(f"{'lacp partner state':<{20}}: {', '.join(self.lacp_pstate)}")
|
||||
print(f"{'link failure count':<{20}}: {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}")
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
[7m⚑ INTERFACE PROTOCOL STATE DATA [0m
|
||||
lo loopback [32mUP [39m
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
br0 bridge [33m [39mvlan:1u pvid:1
|
||||
│ ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
│ ipv4 169.254.1.1/16 (random)
|
||||
│ ipv6 fe80::2a0:85ff:fe00:300/64 (link-layer)
|
||||
├ e3 bridge [32mFORWARDING [39mvlan:1u pvid:1
|
||||
├ e4 bridge [32mFORWARDING [39mvlan:1u pvid:1
|
||||
├ veth0b bridge [32mFORWARDING [39mvlan:1u pvid:1
|
||||
└ veth2b bridge [32mFORWARDING [39mvlan:1u pvid:1
|
||||
br1 bridge [33m [39m
|
||||
│ ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
├ veth1b bridge [32mFORWARDING [39mvlan:6u pvid:6
|
||||
└ veth3b bridge [32mFORWARDING [39m
|
||||
e1 ethernet [32mUP [39m00:a0:85:00:03:01
|
||||
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
|
||||
e2 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
|
||||
e3.8 ethernet [32mUP [39m00:a0:85:00:03:03
|
||||
│ ipv4 10.1.1.1/32 (static)
|
||||
└ e3 ethernet [32mUP [39m00:a0:85:00:03:03
|
||||
e4.8 ethernet [32mUP [39m00:a0:85:00:03:04
|
||||
│ ipv4 10.1.1.1/32 (static)
|
||||
└ e4 ethernet [32mUP [39m00:a0:85:00:03:04
|
||||
e5 ethernet [32mUP [39m00:a0:85:00:03:05
|
||||
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
|
||||
e6 ethernet [32mUP [39m00:a0:85:00:03:06
|
||||
ipv4 10.1.1.101/24 (static)
|
||||
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
|
||||
e7 ethernet [32mUP [39m00:a0:85:00:03:07
|
||||
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
|
||||
[100mveth0a container container-A [0m
|
||||
veth0b veth [32mUP [39me6:19:75:86:80:dd
|
||||
[100mveth1a container container-A [0m
|
||||
veth1b veth [32mUP [39m3e:67:0f:15:24:14
|
||||
[100mveth2a container container-B [0m
|
||||
veth2b veth [32mUP [39mb2:fa:30:63:98:f0
|
||||
[100mveth3a container container-B [0m
|
||||
veth3b veth [32mUP [39mb2:1c:fa:a7:45:eb
|
||||
[7m⚑ INTERFACE PROTOCOL STATE DATA [0m
|
||||
lo loopback [32mUP [39m
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
br0 bridge [33m [39mvlan: 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 [32mFORWARDING [39mvlan: 1u pvid: 1
|
||||
├ e4 bridge [32mFORWARDING [39mvlan: 1u pvid: 1
|
||||
├ veth0b bridge [32mFORWARDING [39mvlan: 1u pvid: 1
|
||||
└ veth2b bridge [32mFORWARDING [39mvlan: 1u pvid: 1
|
||||
br1 bridge [33m [39m
|
||||
│ ethernet 00:a0:85:00:03:00
|
||||
├ veth1b bridge [32mFORWARDING [39mvlan: 6u pvid: 6
|
||||
└ veth3b bridge [32mFORWARDING [39m
|
||||
e1 ethernet [32mUP [39m00:a0:85:00:03:01
|
||||
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
|
||||
e2 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
|
||||
e3.8 vlan [32mUP [39mvid: 8
|
||||
│ ipv4 10.1.1.1/32 (static)
|
||||
└ e3
|
||||
e4.8 vlan [32mUP [39mvid: 8
|
||||
│ ipv4 10.1.1.1/32 (static)
|
||||
└ e4
|
||||
e5 ethernet [32mUP [39m00:a0:85:00:03:05
|
||||
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
|
||||
e6 ethernet [32mUP [39m00:a0:85:00:03:06
|
||||
ipv4 10.1.1.101/24 (static)
|
||||
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
|
||||
e7 ethernet [32mUP [39m00:a0:85:00:03:07
|
||||
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
|
||||
[100mveth0a container container-A [0m
|
||||
veth0b veth [32mUP [39me6:19:75:86:80:dd
|
||||
[100mveth1a container container-A [0m
|
||||
veth1b veth [32mUP [39m3e:67:0f:15:24:14
|
||||
[100mveth2a container container-B [0m
|
||||
veth2b veth [32mUP [39mb2:fa:30:63:98:f0
|
||||
[100mveth3a container container-B [0m
|
||||
veth3b veth [32mUP [39mb2: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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@
|
||||
[7m⚑ INTERFACE PROTOCOL STATE DATA [0m
|
||||
lo loopback [32mUP [39m
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
br-0 bridge [31mDOWN [39m
|
||||
ethernet [31mDOWN [39m00:a0:85:00:03:00
|
||||
br-D bridge [33m [39m
|
||||
│ ethernet [32mUP [39m00: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 [32mFORWARDING [39m
|
||||
br-Q bridge [33m [39mvlan:20u,30u,40t
|
||||
│ ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
├ e3 bridge [32mFORWARDING [39mvlan:20t,30t,40t
|
||||
└ veth0b bridge [32mFORWARDING [39mvlan:20t,30t,40t
|
||||
br-Q.40 ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
└ br-Q ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
br-X bridge [33m [39m
|
||||
│ ethernet [32mUP [39m00:a0:85:00:03:00
|
||||
└ e2.30 bridge [32mFORWARDING [39m
|
||||
e1 ethernet [32mUP [39m00:a0:85:00:03:01
|
||||
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
|
||||
e2 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
|
||||
e2.30 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
└ e2 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
e3.10 ethernet [32mUP [39m00:a0:85:00:03:03
|
||||
└ e3 ethernet [32mUP [39m00:a0:85:00:03:03
|
||||
e4 ethernet [32mUP [39m00:a0:85:00:03:04
|
||||
ipv6 fe80::2a0:85ff:fe00:304/64 (link-layer)
|
||||
e5 ethernet [32mUP [39m00:a0:85:00:03:05
|
||||
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
|
||||
e6 ethernet [32mUP [39m00:a0:85:00:03:06
|
||||
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
|
||||
e7 ethernet [32mUP [39m00:a0:85:00:03:07
|
||||
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
|
||||
gre-v4 gre [32mUP [39m
|
||||
gre-v6 gre [32mUP [39m
|
||||
ipv4 192.168.50.2/16 (static)
|
||||
gretap-v4 gretap [32mUP [39mf6:d4:96:d8:9f:96
|
||||
gretap-v6 gretap [32mUP [39m7a:46:13:bd:fa:e6
|
||||
veth0a veth [32mUP [39m6e:d0:98:c4:e7:ef
|
||||
veth0a.20 ethernet [32mUP [39m6e:d0:98:c4:e7:ef
|
||||
└ veth0a ethernet [32mUP [39m6e:d0:98:c4:e7:ef
|
||||
veth0b veth [32mUP [39m36:da:80:06:7f:99
|
||||
vxlan-v4 vxlan [32mUP [39m8a:ea:59:32:df:70
|
||||
ipv4 192.168.30.2/24 (static)
|
||||
vxlan-v6 vxlan [32mUP [39m3e:30:c6:a1:71:64
|
||||
ipv4 192.168.40.2/24 (static)
|
||||
[7m⚑ INTERFACE PROTOCOL STATE DATA [0m
|
||||
lo loopback [32mUP [39m
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
br-0 bridge [31mDOWN [39m
|
||||
ethernet 00:a0:85:00:03:00
|
||||
br-D bridge [33m [39m
|
||||
│ 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 [32mFORWARDING [39m
|
||||
br-Q bridge [33m [39mvlan: 20u,30u,40t
|
||||
│ ethernet 00:a0:85:00:03:00
|
||||
├ e3 bridge [32mFORWARDING [39mvlan: 20t,30t,40t
|
||||
└ veth0b bridge [32mFORWARDING [39mvlan: 20t,30t,40t
|
||||
br-Q.40 vlan [32mUP [39mvid: 40
|
||||
└ br-Q
|
||||
br-X bridge [33m [39m
|
||||
│ ethernet 00:a0:85:00:03:00
|
||||
└ e2.30 bridge [32mFORWARDING [39m
|
||||
e1 ethernet [32mUP [39m00:a0:85:00:03:01
|
||||
ipv6 fe80::2a0:85ff:fe00:301/64 (link-layer)
|
||||
e2 ethernet [32mUP [39m00:a0:85:00:03:02
|
||||
ipv6 fe80::2a0:85ff:fe00:302/64 (link-layer)
|
||||
e2.30 vlan [32mUP [39mvid: 30
|
||||
└ e2
|
||||
e3.10 vlan [32mUP [39mvid: 10
|
||||
└ e3
|
||||
e4 ethernet [32mUP [39m00:a0:85:00:03:04
|
||||
ipv6 fe80::2a0:85ff:fe00:304/64 (link-layer)
|
||||
e5 ethernet [32mUP [39m00:a0:85:00:03:05
|
||||
ipv6 fe80::2a0:85ff:fe00:305/64 (link-layer)
|
||||
e6 ethernet [32mUP [39m00:a0:85:00:03:06
|
||||
ipv6 fe80::2a0:85ff:fe00:306/64 (link-layer)
|
||||
e7 ethernet [32mUP [39m00:a0:85:00:03:07
|
||||
ipv6 fe80::2a0:85ff:fe00:307/64 (link-layer)
|
||||
gre-v4 gre [32mUP [39mremote: 192.168.20.2
|
||||
gre-v6 gre [32mUP [39mremote: 2001:db8::2
|
||||
ipv4 192.168.50.2/16 (static)
|
||||
gretap-v4 gre [32mUP [39mremote: 192.168.20.2
|
||||
ethernet f6:d4:96:d8:9f:96
|
||||
gretap-v6 gre [32mUP [39mremote: 2001:db8::2
|
||||
ethernet 7a:46:13:bd:fa:e6
|
||||
veth0a veth [32mUP [39m6e:d0:98:c4:e7:ef
|
||||
veth0a.20 vlan [32mUP [39mvid: 20
|
||||
└ veth0a
|
||||
veth0b veth [32mUP [39m36:da:80:06:7f:99
|
||||
vxlan-v4 vxlan [32mUP [39mvni: 4 remote: 192.168.20.200
|
||||
ethernet 8a:ea:59:32:df:70
|
||||
ipv4 192.168.30.2/24 (static)
|
||||
vxlan-v6 vxlan [32mUP [39mvni: 6 remote: 2001:db8::200
|
||||
ethernet 3e:30:c6:a1:71:64
|
||||
ipv4 192.168.40.2/24 (static)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user