Compare commits

...
31 Commits
Author SHA1 Message Date
Joachim Wiberg 85a1bfc999 .github: add support for manually starting a release build
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-31 11:29:36 +01:00
Joachim Wiberg 5ebd473972 Update ChangeLog for Infix v23.10 [skip ci]
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-31 10:09:01 +01:00
Richard AlpeandJoachim Wiberg 12462d5b17 statd: add more ethtool counters to op datastore
Add counters from Ethtool groups to the operational datastore. The
mapping from Linux / Ethtool to YANG is described in the included
document eth-counters.md.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-31 10:01:55 +01:00
Joachim WibergandTobias Waldekranz afbf92c07e configs: drop x86_64_minimal_defconfig
Replaced with full build in GitHub Actions.  No other use-cases for it,
and too much of a hassle to maintain, so remove.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-31 09:28:28 +01:00
Joachim WibergandTobias Waldekranz 552550495a configs: reenable lost bash for netconf builds
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-31 09:28:28 +01:00
Joachim WibergandTobias Waldekranz 6503face19 package/finit: bump to v4.5
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-31 09:28:28 +01:00
Mattias Walström 90d94fe255 Remove ietf-if-vlan-encapsulation, it is replaced by infix-if-vlan
This is a followup for 941fc3158
2023-10-31 09:16:58 +01:00
Joachim WibergandTobias Waldekranz fc5310b3fd confd: adjust path to failure-config
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 12:48:14 +01:00
Joachim WibergandTobias Waldekranz 120e87ac99 confd: sort interfaces according to length and name
A list of interfaces: x10 x9 x8 x7 x6 x5 x4 x1 x2 x3 should be sorted in
order with x10 last.  Using the common 'sort -n' would generate: x1 x10
x2 ... so we use version sort.  This way we can ensure that the order of
bridge ports is natural and what end users expect.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 12:48:14 +01:00
Joachim WibergandTobias Waldekranz 7fd7a2e430 confd: regenerate failure-config and factory-config on each boot
Operational experience shows that the current Infix Fail Secure mode,
introduced in ca9daef, does not work in practice.

The factory datastore in sysrepo is created at boot with the YANG models
and the factory-config file.  When the factory-config file is generated
from older versions of these models, the resulting datastore may fail to
pass the validation and system will end up in an unrecoverable state.

Instead, both the factory-config and failure-config must be created at
every boot to match the YANG models in the active Linux image.  This
ensures loading the YANG models will always work and the system can
proceed to attempt to load startup-config to the running datastore.

If loading startup-config fails we can fall back to failure-config,
which like factory-config, will then provide a way to log in an dianose
the system.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 12:48:14 +01:00
Tobias WaldekranzandJoachim Wiberg c385e2e9c2 uboot: Import latest patches from u-boot-2023.07.y-kkit
Adds enough support for 6393X switchcore to enable netbooting from a
single port.
2023-10-30 11:24:18 +01:00
Tobias WaldekranzandJoachim Wiberg 97747a95ea common/uboot: Use factory-reset and dev-mode buttons, if available
If the bootloader knows about a factory-reset or dev-mode button, use
them to allow stopping the boot process, and to signal the
factory-reset condition to infix.
2023-10-30 11:24:18 +01:00
Tobias WaldekranzandJoachim Wiberg 01e43896df common/uboot: Explicitly separate kernel/user arguments
This way, we avoid arguments intended for userspace to be accidentally
parsed by the kernel.
2023-10-30 11:24:18 +01:00
Tobias WaldekranzandJoachim Wiberg 60c777fb41 common/uboot: If no valid boot media exists, fall back to netboot
This means that a device with a valid bootloader, but a completely
empty eMMC is still salvageable.
2023-10-30 11:24:18 +01:00
Tobias WaldekranzandJoachim Wiberg 194aa5de8a common/uboot: Use correct name of netboot in default order 2023-10-30 11:24:18 +01:00
Tobias WaldekranzandJoachim Wiberg 47fe0529f4 arm-trusted-firmware: Default to 16-bit DDR4 on CN9130 boards 2023-10-30 11:24:18 +01:00
Mattias WalströmandJoachim Wiberg 941fc31581 infix-vlan: Create a custom vlan model
This implements the new model infix-if-vlan.
The new CLI is:

root@infix-00-00-00:/config/interfaces/interface/vlan10/> set vlan id 10 lower-layer-if eth0

with an possible extra option for tag-type, default tag-type is c-vlan.
2023-10-27 10:53:55 +02:00
Joachim Wiberg be8bad9885 doc: add Versioning section to branding document
[skip ci]

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-24 13:51:27 +02:00
Joachim Wiberg e03ab9c81b board/common: add help text for Qemu interface model
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-24 13:37:28 +02:00
Mattias WalströmandJoachim Wiberg f224d0d03d ietf-factory-default: Implement factory reset
fixes #157, fixes #156
2023-10-24 12:25:38 +02:00
Mattias WalströmandJoachim Wiberg d66740250c confd: Add support for timezone-utc-offset
Some deviations has been done the yang model to comply with tzdata
on linux.

This fixes #106
2023-10-20 12:55:02 +02:00
Mattias WalströmandJoachim Wiberg 0db65846c3 Add tzset() before localtime
Without it, the offset generated will always be zero.
But over netconf it will still be correct, most likely
because due to how libyang handles the date-and-time type.
2023-10-20 12:55:02 +02:00
Richard AlpeandJoachim Wiberg 4471c45d3c .github: use defconfig instead of minimal_defconfig
The issues seen in the regression tests looks related to files
missing from minimal defconfig.

Fixes #127.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:18:19 +02:00
Richard AlpeandJoachim Wiberg 5639e5bdd4 statd: ignore interfaces with group = internal
Don't add any info about interfaces which has "group" = "internal" to
the operational datastore.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg 1654773bc6 statd: ignore parent interface for kind dsa
DSA ports such as pX has "link" (parent) set to dsaY. We don't see it
that way from an networking perspective. In this commit we avoid
adding parent to the statd data structure if the linkinfo -> info_kind
is dsa. This means the ports shows up as regular interfaces, which is
what we want.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg 4a84ab95d0 statd: dsa ifaces has type infix-if-type:ethernet
Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg f643b4f9dc statd: break out parent interface code (cosmetic)
A non functional change to prepare for upcoming patches.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg d6152ce6ea cli: add graceful error for missing json in cli-pretty
Print a graceful error message if the json data is missing of invalid.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg 1a3105c06d cli: pretty print existing Ethernet frame stats
Pretty print all Ethernet frame statistics from the operational
datastore. Only in the detailed interface view.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:59 +02:00
Richard AlpeandJoachim Wiberg 14dc3cf8a0 statd: add ethtool frame counters to op datastore
This patch adds the framework for reading ethtool statistics and
inserting it into the operational datastore.

The ethtool data we rely on is "group data" such as "eth-mac" or
"rmon".

This data can be displayed using:
ethtool --json -S e0 --all-groups

The "group data" is still missing for most common drivers, so testing
this will require a firmware which has support for it.

Signed-off-by: Richard Alpe <richard@bit42.se>
2023-10-17 18:17:54 +02:00
Joachim Wiberg 9292231674 .github: switch to ncipollo/release-action for latest build
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-17 18:08:07 +02:00
65 changed files with 3193 additions and 1135 deletions
+10 -4
View File
@@ -80,14 +80,20 @@ jobs:
name: Upload Latest Build
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v3
- uses: pyTooling/Actions/releaser@main
- uses: ncipollo/release-action@v1
with:
tag: latest
rm: false
allowUpdates: true
omitName: true
omitBody: true
omitBodyDuringUpdate: true
prerelease: true
tag: "latest"
token: ${{ secrets.GITHUB_TOKEN }}
files: artifact/*
artifacts: "artifact/*"
- name: Summary
run: |
cat <<EOF >> $GITHUB_STEP_SUMMARY
+3 -3
View File
@@ -31,7 +31,7 @@ jobs:
- name: Set Build Variables
id: vars
run: |
target=x86_64-minimal
target=x86_64
echo "dir=infix-$target" >> $GITHUB_OUTPUT
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
- name: Restore Cache of dl/
@@ -52,9 +52,9 @@ jobs:
ccache-x86_64-netconf-
ccache-x86_64-
ccache-
- name: Configure Minimal NETCONF
- name: Configure NETCONF
run: |
make x86_64_minimal_defconfig
make x86_64_defconfig
- name: Build
run: |
make
+10 -1
View File
@@ -4,6 +4,11 @@ on:
push:
tags:
- 'v[0-9]*.*'
workflow_dispatch:
inputs:
version:
required: false
type: string
jobs:
build:
@@ -20,7 +25,11 @@ jobs:
- name: Set Release Variables
id: build
run: |
ver=${GITHUB_REF#refs/tags/v}
if [ -n "${{ inputs.version }}" ]; then
ver=${{ inputs.version }}
else
ver=${GITHUB_REF#refs/tags/v}
fi
echo "ver=${ver}" >> $GITHUB_OUTPUT
if echo $ver | grep -qE '[0-9.]+(-alpha|-beta|-rc)[0-9]*'; then
echo "pre=true" >> $GITHUB_OUTPUT
@@ -1,4 +1,4 @@
label Infix (aarch64)
kernel /boot/Image
fdtdir /boot
append ${bootargs_root} ${bootargs_rauc} ${bootargs_log}
append ${bootargs_root} ${bootargs_log} -- ${bootargs_user}
-4
View File
@@ -73,10 +73,6 @@ if [ "$FIT_IMAGE" = "y" ]; then
fi
if [ "$BR2_TARGET_ROOTFS_SQUASHFS" = "y" ]; then
if [ -z "${NAME##*minimal*}" ]; then
NAME=$(echo "$NAME" | sed 's/-minimal//')
fi
rel=$(ver)
ln -sf rootfs.squashfs "$BINARIES_DIR/${NAME}${rel}.img"
if [ -n "$rel" ]; then
+4
View File
@@ -137,6 +137,10 @@ endchoice
config QEMU_NET_MODEL
string "Interface model"
default "virtio-net-pci"
help
The default, virtio-net-pci, NIC works for most use-cases, but
if you want to play with low-level stuff like ethtool, you
might want to test the Intel 82545EM driver, e1000.
config QEMU_NET_BRIDGE_DEV
string "Bridge device"
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
Q=$@
echo "$Q, are you sure? (y/N)"
read -n1 yorn
if [ x$yorn != "xy" ]; then
echo "Ok, aborting"
exit 1
fi
exit 0
@@ -1,141 +0,0 @@
_cond()
{
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
}
_ident()
{
if [ -n "$1" ]; then
initctl ident | grep -q $1
else
initctl ident
fi
}
_svc()
{
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
}
_enabled()
{
echo "$(_svc enabled)"
}
_available()
{
all=$(mktemp)
ena=$(mktemp)
echo "$(_svc available)" >$all
echo "$(_svc enabled)" >$ena
grep -v -f $ena $all
rm $all $ena
}
# Determine first non-option word. Usually the command
_firstword() {
local firstword i
firstword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
firstword=${COMP_WORDS[i]}
break
fi
done
echo $firstword
}
# Determine last non-option word. Uusally a sub-command
_lastword() {
local lastword i
lastword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
lastword=${COMP_WORDS[i]}
fi
done
echo $lastword
}
_initctl()
{
local cur command
cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"
firstword=$(_firstword)
lastword=$(_lastword)
commands="status cond debug help kill ls log version list enable \
disable touch show cat edit create delete reload start \
stop restart signal cgroup ps top plugins runlevel reboot \
halt poweroff suspend utmp"
cond_cmds="set get clear status dump"
cond_types="hook net pid service task usr"
signals="int term hup stop tstp cont usr1 usr2 pwr"
options="-b --batch \
-c --create \
-d --debug \
-f --force \
-h --help \
-j --json \
-n --noerr \
-1 --once \
-p --plain \
-q --quiet \
-t --no-heading \
-v --verbose \
-V --version"
case "${firstword}" in
enable)
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
;;
disable|touch)
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
;;
show|cat|edit|delete)
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
;;
start|stop|restart|log|status)
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
;;
signal|kill)
if $(_ident "${prev}"); then
COMPREPLY=($(compgen -W "$signals" -- $cur))
else
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
fi
;;
cond)
case "${lastword}" in
set|clear)
compopt -o nospace
COMPREPLY=($(compgen -W "usr/" -- $cur))
;;
get)
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
;;
dump)
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
;;
*)
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
;;
esac
;;
*)
COMPREPLY=($(compgen -W "$commands" -- $cur))
;;
esac
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "$options" -- $cur))
fi
}
complete -F _initctl initctl
+5 -1
View File
@@ -8,9 +8,13 @@
&env {
vendor = "infix";
bootdelay = "-2";
bootcmd = "run ixboot";
bootcmd = "run ixbtn";
boot_targets = "virtio mmc";
ixbtn = /incbin/("scripts/ixbtn.sh");
ixdevmode = /incbin/("scripts/ixdevmode.sh");
ixfactory = /incbin/("scripts/ixfactory.sh");
ixbtn = /incbin/("scripts/ixbtn.sh");
ixboot = /incbin/("scripts/ixboot.sh");
ixbootmedia = /incbin/("scripts/ixbootmedia.sh");
ixbootslot = /incbin/("scripts/ixbootslot.sh");
+11 -1
View File
@@ -1,3 +1,5 @@
setenv valid_media no
for tgt in "${boot_targets}"; do
if test "${tgt}" = "mmc0"; then
setenv devtype "mmc"
@@ -17,7 +19,7 @@ for tgt in "${boot_targets}"; do
env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG
fi
test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "primary secondary dhcp"
test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "primary secondary net"
if test -n "${DEBUG}"; then
setenv bootargs_log "debug"
@@ -25,8 +27,16 @@ for tgt in "${boot_targets}"; do
setenv bootargs_log "loglevel=4"
fi
setenv valid_media yes
run ixbootmedia
fi
done
if test "${valid_media}" = "no"; then
echo "NO BOOTABLE MEDIA FOUND, falling back to netboot"
setenv BOOT_ORDER "net"
setenv bootargs_log "debug"
run ixbootmedia
fi
reset
+7 -1
View File
@@ -14,7 +14,13 @@ if test "${prepared}" = "ok"; then
if iminfo ${ramdisk_addr_r}; then
echo "${slot}: Booting..."
setenv bootargs_rauc "rauc.slot=${slot}"
setenv bootargs_user "rauc.slot=${slot}"
if test "${factory_reset}" = "yes"; then
setenv bootargs_user "${bootargs_user} finit.cond=factory-reset"
fi
if test "${dev_mode}" = "yes"; then
setenv bootargs_user "${bootargs_user} finit.cond=dev-mode"
fi
blkmap create boot
blkmap get boot dev blkmapnum
+13
View File
@@ -0,0 +1,13 @@
setenv dev_mode no
setenv factory_reset no
echo -n "dev-mode: "
run ixdevmode
echo -n "factory-reset: "
run ixfactory
if test "${dev_mode}" = "yes"; then
sleep 1 && run ixboot
else
run ixboot
fi
+3
View File
@@ -0,0 +1,3 @@
if button dev-mode; then
setenv dev_mode yes
fi
+7
View File
@@ -0,0 +1,7 @@
if button factory-reset; then
echo "Keep button pressed for 10 seconds to engage reset"
if sleep 10 && button factory-reset; then
setenv factory_reset yes
echo "FACTORY RESET ENGAGED"
fi
fi
+41 -11
View File
@@ -32,6 +32,16 @@ class Decore():
return Decore.decorate("32", txt, "39")
class Iface:
def get_json_data(self, default, *args):
data = self.data
for arg in args:
if data.get(arg):
data = data.get(arg)
else:
return default
return data
def __init__(self, data):
self.data = data
self.name = data.get('name', '')
@@ -46,8 +56,6 @@ class Iface:
self.in_octets = ''
self.out_octets = ''
self.parent = data.get('ietf-if-extensions:parent-interface', None)
if self.data.get('ietf-ip:ipv4'):
self.mtu = self.data.get('ietf-ip:ipv4').get('mtu', '')
self.ipv4_addr = self.data.get('ietf-ip:ipv4').get('address', '')
@@ -65,6 +73,11 @@ class Iface:
else:
self.bridge = ''
if self.data.get('infix-interfaces:vlan'):
self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
else:
self.lower_if = ''
def is_vlan(self):
return self.data['type'] == "infix-if-type:vlan"
@@ -126,7 +139,7 @@ class Iface:
self.pr_name(pipe="")
self.pr_proto_eth()
if self.parent:
if self.lower_if:
self.pr_proto_ipv4(pipe='│')
self.pr_proto_ipv6(pipe='│')
else:
@@ -134,7 +147,7 @@ class Iface:
self.pr_proto_ipv6()
return
parent = find_iface(_ifaces, self.parent)
parent = find_iface(_ifaces, self.lower_if)
if not parent:
print(f"Error, didn't find parent interface for vlan {self.name}")
sys.exit(1)
@@ -181,6 +194,13 @@ class Iface:
print(f"{'in-octets':<{20}}: {self.in_octets}")
print(f"{'out-octets':<{20}}: {self.out_octets}")
frame = self.get_json_data([], 'ieee802-ethernet-interface:ethernet',
'statistics', 'frame')
if frame:
print(f"")
for key, val in frame.items():
print(f"eth-{key:<{25}}: {val}")
def find_iface(_ifaces, name):
for _iface in [Iface(data) for data in _ifaces]:
@@ -210,7 +230,7 @@ def pr_interface_list(json):
continue
# These interfaces are printed by there parent, such as bridge
if iface.parent:
if iface.lower_if:
continue
if iface.bridge:
continue
@@ -234,11 +254,21 @@ def ietf_interfaces(json, name):
sys.exit(1)
return iface.pr_iface()
def main():
try:
json_data = json.load(sys.stdin)
except json.JSONDecodeError:
print("Error, invalid JSON input")
sys.exit(1)
except Exception as e:
print("Error, unexpected error parsing JSON")
sys.exit(1)
json = json.load(sys.stdin)
if args.module == "ietf-interfaces":
sys.exit(ietf_interfaces(json_data, args.name))
else:
print(f"Error, unknown module {args.module}")
sys.exit(1)
if args.module == "ietf-interfaces":
sys.exit(ietf_interfaces(json, args.name))
else:
print(f"Error, unknown module {args.module}")
sys.exit(1)
if __name__ == "__main__":
main()
+1
View File
@@ -81,6 +81,7 @@ BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_TRACEROUTE=y
BR2_PACKAGE_ULOGD=y
BR2_PACKAGE_BASH=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_IRQBALANCE=y
BR2_PACKAGE_KMOD_TOOLS=y
+1
View File
@@ -77,6 +77,7 @@ BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_TRACEROUTE=y
BR2_PACKAGE_ULOGD=y
BR2_PACKAGE_BASH=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_IRQBALANCE=y
BR2_PACKAGE_KMOD_TOOLS=y
-77
View File
@@ -1,77 +0,0 @@
BR2_x86_64=y
BR2_x86_corei7=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY=y
BR2_DL_DIR="${BR2_EXTERNAL_INFIX_PATH}/dl"
BR2_CCACHE=y
BR2_CCACHE_DIR="${BR2_EXTERNAL_INFIX_PATH}/.ccache"
BR2_ENABLE_DEBUG=y
BR2_GLOBAL_PATCH_DIR="${BR2_EXTERNAL_INFIX_PATH}/patches"
BR2_TARGET_GENERIC_HOSTNAME="infix"
BR2_TARGET_GENERIC_ISSUE="Minfix by KernelKit"
BR2_INIT_FINIT=y
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_ROOTFS_DEVICE_TABLE="system/device_table.txt ${BR2_EXTERNAL_INFIX_PATH}/board/common/xattrs ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/xattrs"
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
BR2_SYSTEM_DHCP="eth0"
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA"
BR2_GENERATE_LOCALE="en_US en_CA"
BR2_TARGET_TZ_INFO=y
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/rootfs"
BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.6"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_DBUS_TRIGGERD=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_RNG_TOOLS=y
BR2_PACKAGE_LIBOPENSSL_BIN=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_ONIGURUMA=y
BR2_PACKAGE_AVAHI=y
BR2_PACKAGE_AVAHI_DAEMON=y
BR2_PACKAGE_AVAHI_DEFAULT_SERVICES=y
BR2_PACKAGE_CHRONY=y
BR2_PACKAGE_DNSMASQ=y
BR2_PACKAGE_ETHTOOL=y
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
BR2_PACKAGE_LLDPD=y
BR2_PACKAGE_OPENRESOLV=y
BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_KMOD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_PWGEN=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_LESS=y
BR2_TARGET_ROOTFS_SQUASHFS=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_SULOGIN=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
BR2_PACKAGE_FINIT_PLUGIN_MODULES_LOAD=y
BR2_PACKAGE_FINIT_PLUGIN_RTC=y
BR2_PACKAGE_FINIT_PLUGIN_TTY=y
BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_NET=y
BR2_PACKAGE_PYTHON3=y
BR2_PACKAGE_PYTHON3_PYC_ONLY=y
# SIGN_ENABLED is not set
# GNS3_APPLIANCE is not set
+125 -1
View File
@@ -4,6 +4,129 @@ Change Log
All notable changes to the project are documented in this file.
[v23.10.0][] - 2023-10-31
-------------------------
> **Note:** upcoming releases will lock the `root` user for system-only
> services. Instead an `admin` user will be the only default user with
> the CLI as its login shell. This user is already available, so please
> consider updating any guidelines or documentation you may have.
### YANG Status
- [ietf-system][]:
- [infix-system][]: MotD (Message of the Day) augment
- [infix-system][]: user login shell augment, default: `/bin/false`
- [infix-system-software][]: system-state/software augment for
remotely querying firmware version information
- [infix-system-software][]: firmware upgrade with `install-bundle` RPC
- [infix-system][]: timezone-name deviation, using with IANA timezones,
deviation for UTC offset, only support per-hour offsets with [tzdata][].
Also, username deviation, clarifying Linux restrictions.
- [infix-system][]: deviations for unsupported features, e.g. RADIUS
- [ietf-interfaces][]:
- [infix-interfaces][]: deviation for `if:phys-address` to allow read-write
- [ietf-ip][]: augmented with IPv4LL similar to standardized IPv6LL
- [infix-ip][]: deviations (`not-supported`) added for IPv4 and IPv6:
- `/if:interfaces/if:interface/ip:ipv4/ip:address/ip:subnet/ip:netmask`
- `/if:interfaces/if:interface/ip:ipv6/ip:address/ip:status`
- `/if:interfaces/if:interface/ip:ipv4/ip:mtu`
- `/if:interfaces/if:interface/ip:ipv6/ip:mtu`
- `/if:interfaces/if:interface/ip:ipv4/ip:neighbor`
- `/if:interfaces/if:interface/ip:ipv6/ip:neighbor`
- ~~[ietf-if-vlan-encapsulation][]:~~ Removed in favor of a native model.
- [infix-if-bridge][]: Linux bridge interfaces with native VLAN support
- [infix-if-type][]: deviation for interface types, limiting number
to supported types only. New identities are derived from default
IANA interface types, ensuring compatibility with other standard
models, e.g., `ieee802-ethernet-interface.yang`
- [infix-if-veth][]: Linux VETH pairs
- [infix-if-vlan][]: Linux VLAN interfaces, e.g. `eth0.10` (New model!)
- Configurable services:
- [ieee802-dot1ab-lldp][]: stripped down to an `enabled` setting
- [infix-services][]: support for enabling mDNS service/device discovery
[tzdata]: https://www.iana.org/time-zones
[ieee802-dot1ab-lldp]: https://github.com/kernelkit/infix/tree/50a550b/src/confd/yang/ieee802-dot1ab-lldp%402022-03-15.yang
[ietf-system]: https://www.rfc-editor.org/rfc/rfc7317.html
[ietf-interfaces]: https://www.rfc-editor.org/rfc/rfc7223.html
[ietf-ip]: https://www.rfc-editor.org/rfc/rfc8344.html
[ietf-if-vlan-encapsulation]: https://www.ietf.org/id/draft-ietf-netmod-sub-intf-vlan-model-08.html
[infix-if-bridge]: https://github.com/kernelkit/infix/blob/fc5310b/src/confd/yang/infix-if-bridge%402023-08-21.yang
[infix-if-type]: https://github.com/kernelkit/infix/tree/fc5310b/src/confd/yang/infix-if-type%402023-08-21.yang
[infix-if-veth]: https://github.com/kernelkit/infix/tree/fc5310b/src/confd/yang/infix-if-veth%402023-06-05.yang
[infix-if-vlan]: https://github.com/kernelkit/infix/blob/fc5310b/src/confd/yang/infix-if-vlan%402023-10-25.yang
[infix-interfaces]: https://github.com/kernelkit/infix/tree/fc5310b/src/confd/yang/infix-interfaces%402023-09-19.yang
[infix-ip]: https://github.com/kernelkit/infix/tree/fc5310b/src/confd/yang/infix-ip%402023-09-14.yang
[infix-services]: https://github.com/kernelkit/infix/blob/fc5310b/src/confd/yang/infix-services%402023-10-16.yang
[infix-system]: https://github.com/kernelkit/infix/blob/fc5310b/src/confd/yang/infix-system%402023-10-19.yang
[infix-system-software]: https://github.com/kernelkit/infix/tree/fc5310b/src/confd/yang/infix-system-software%402023-06-27.yang
### Changes
- Add support for setting/querying IPv4/IPv6 MTU, see #152 for details.
- Add support for *Fail Secure Mode*: if loading `startup-config` fails,
e.g. YANG model validation failure after upgrade, the system now falls back
to load `failure-config` instead of just crashing. This config, along with
`factory-config`, is generated on every boot to match the active image's
YANG models. In case neither config can be loaded, or even bootstrapping
YANG models fail, the system will go into an RMA state -- Return to
Manufacturer, clearly signaled on the console and, on devices that support
it, angry LED signaling. See #154 for more.
- Add support for generating GNS3 appliance file for NETCONF Aarch64.
- Add support for UTC offset (+/- HH:00) in `ietf-system`, PR #174
- Add support for `ietf-factory-default` RPC, PR #175
- Add support for performing factory reset (using #175 RPC) from CLI
- Replace `ietf-if-vlan-encapsulation` YANG model with the native
`infix-if-vlan` model. This fits better with Linux VLAN interfaces and
simplifies the syntax greatly. For details, see PR #179
admin@example:/config/interfaces/interface/eth0.10/> set vlan id 10 lower-layer-if eth0
- The following new NETCONF interface operational counters have been added:
| **YANG** | **Linux / Ethtool** |
|-----------------------------|-----------------------------------|
| `out-frames` | `FramesTransmittedOK` |
| `out-multicast-frames` | `MulticastFramesXmittedOK` |
| `out-broadcast-frames` | `BroadcastFramesXmittedOK` |
| `in-total-frames` | `FramesReceivedOK` |
| | + `FrameCheckSequenceErrors` |
| | + `FramesLostDueToIntMACRcvError` |
| | + `AlignmentErrors` |
| | + `etherStatsOversizePkts` |
| | + `etherStatsJabbers` |
| `in-frames` | `FramesReceivedOK` |
| `in-multicast-frames` | `MulticastFramesReceivedOK` |
| `in-broadcast-frames` | `BroadcastFramesReceivedOK` |
| `in-error-undersize-frames` | `undersize_pkts` |
| `in-error-fcs-frames` | `FrameCheckSequenceErrors` |
- Greatly improved branding support using `make menuconfig`. All the
identifying strings, including firmware image, is in `/etc/os-release`, will
be used in CLI `show system-information`, the WebUI About dialog, and any
prominent areas when booting up (on console), logging in to CLI and WebUI.
- IGMP/MLD snooping is now disabled by default on new bridges. Support
for multicast filtering bridges expected no later than v24.01.
- The SSDP responder, device discovery in Windows, has been removed in favor
of Windows 10 (build 1709) native support for mDNS-SD. Details in #166
- A GreenPAK programmer has been added, not enabled by default. This is a
popular programmable little chip from Renesas. Worth a look!
- The `confd` script `gen-interfaces` can now generate bridges and stand-alone
interfaces with IPv6 (SLAAC) for `factory-config` et al.
- Drop `x86_64_minimal_defconfig`, previously used for regression tests only
- Documentation updates of how IPv4/IPv6 addresses are shown in NETCONF
operational data, as well as the built-in CLI, see #163 for details.
### Fixes
- Fix #106: confd: drop deviation `ietf-system:timezone-utc-offset`
- Fix #151: Operational status broken in v23.09
- Fix #159: Hacky generation of `/etc/resolv.conf` at boot
- Fix #162: VLAN interface without encapsulation is accepted by YANG model
[v23.09.0][] - 2023-10-02
-------------------------
@@ -216,7 +339,8 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
- N/A
[buildroot]: https://buildroot.org/
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v23.08.0...HEAD
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v23.10.0...HEAD
[v23.10.0]: https://github.com/kernelkit/infix/compare/v23.09.0...v23.10.0
[v23.09.0]: https://github.com/kernelkit/infix/compare/v23.08.0...v23.09.0
[v23.08.0]: https://github.com/kernelkit/infix/compare/v23.06.0...v23.08.0
[v23.06.0]: https://github.com/kernelkit/infix/compare/BASE...v23.06.0
+26 -1
View File
@@ -103,7 +103,31 @@ Releases
--------
A release build requires the global variable `INFIX_RELEASE` to be set.
It can be derived from GIT, if the source tree is kept in GIT VCS.
It can be derived from GIT, if the source tree is kept in GIT VCS. First,
let us talk about versioning in general.
### Versioning
Two popular scheme for versioning a product derived from Infix:
1. Track Infix major.minor, e.g. *Foobar v23.08.z*, where `z` is
your patch level. I.e., Foobar v23.08.0 could be based on Infix
v23.08.0, or v23.08.12, it is up to you. Maybe you based it on
v23.08.12 and then back ported changes from v23.10.0, but it was
the first release you made to your customer(s).
2. Start from v1.0.0 and step the major number every time you sync
with a new Infix release, or every time Infix bumps to the next
Buildroot LTS.
The important thing is to be consistent, not only for your own sake,
but also for your end customers. The *major.minor.patch* style is
the most common and often recommended style, which usually maps well
to other systems, e.g. PROFINET GSDML files require this (*VX.Y.Z*).
But you can of course use only two numbers, *major.minor*, as well.
> What could be confusing, however, is if you use the name *Infix*
> with your own versioning scheme.
### `INFIX_RELEASE`
@@ -122,3 +146,4 @@ Infix tree and can be changed by setting the menuconfig branding
variable `INFIX_OEM_PATH` to that of the br2-external. It is also
possible to set the `GIT_VERSION` variable in your `post-build.sh`
script to change how the VCS version is extracted.
+31
View File
@@ -0,0 +1,31 @@
# YANG to Ethtool Mapping
This column contains the mapping between YANG and Linux / Ethtool counters.
```
┌─────────────────────────────────┬──────────────────────────────────┐
│ YANG │ Linux / Ethtool │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-frames │ FramesTransmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-multicast-frames │ MulticastFramesXmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ out-broadcast-frames │ BroadcastFramesXmittedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-total-frames │ FramesReceivedOK, │
│ │ FrameCheckSequenceErrors │
│ │ FramesLostDueToIntMACRcvError │
│ │ AlignmentErrors │
│ │ etherStatsOversizePkts │
│ │ etherStatsJabbers │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-frames │ FramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-multicast-frames │ MulticastFramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-broadcast-frames │ BroadcastFramesReceivedOK │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-error-undersize-frames │ undersize_pkts │
├─────────────────────────────────┼──────────────────────────────────┤
│ in-error-fcs-frames │ FrameCheckSequenceErrors │
└─────────────────────────────────┴──────────────────────────────────┘
```
+2 -1
View File
@@ -1,2 +1,3 @@
d /run/confd/factory.d - - -
d /run/confd/failure.d - - -
d /run/resolvconf/interfaces - - -
+1 -1
View File
@@ -1,5 +1,5 @@
# From https://github.com/troglobit/finit/releases/
sha256 904af0b0d7b22bcbe7772ea5851a0496445bfb3cff5c9a65935fd74745dcba75 finit-4.5-rc5.tar.gz
sha256 ef73d9ba01aefef1a2171483f26339c7aefdf92dd25d7b322f15efa48e78d655 finit-4.5.tar.gz
# Locally calculated
sha256 3a2b964c1772d03ab17b73a389ecce9151e0b190a9247817a2c009b16d356422 LICENSE
+7 -1
View File
@@ -4,7 +4,7 @@
#
################################################################################
FINIT_VERSION = 4.5-rc5
FINIT_VERSION = 4.5
FINIT_SITE = https://github.com/troglobit/finit/releases/download/$(FINIT_VERSION)
FINIT_LICENSE = MIT
FINIT_LICENSE_FILES = LICENSE
@@ -119,6 +119,12 @@ else
FINIT_CONF_OPTS += --disable-alsa-utils-plugin
endif
ifeq ($(BR2_PACKAGE_BASH_COMPLETION),y)
FINIT_CONF_OPTS += --with-bash-completiond-dir
else
FINIT_CONF_OPTS += --without-bash-completiond-dir
endif
ifeq ($(BR2_PACKAGE_DBUS),y)
FINIT_CONF_OPTS += --enable-dbus-plugin
else
@@ -0,0 +1,40 @@
From 4f0e44e9b494485dc63de3264aa99dad5def5f55 Mon Sep 17 00:00:00 2001
From: Henrik Nordstrom <henrik.nordstrom@addiva.se>
Date: Wed, 13 Sep 2023 22:45:00 +0200
Subject: [PATCH 1/2] cn9130: Default DDR4 4GByte 16-bit/die ECC
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
index 82ce07b09..07753ea97 100644
--- a/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
@@ -45,18 +45,18 @@ struct mv_ddr_iface dram_iface_ap0 = {
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0} },
- SPEED_BIN_DDR_2400T, /* speed_bin */
- MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
+ SPEED_BIN_DDR_2400R, /* speed_bin */
+ MV_DDR_DEV_WIDTH_16BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
- MV_DDR_TEMP_LOW} }, /* temperature */
+ MV_DDR_TEMP_HIGH} }, /* temperature */
#if DDR32
MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
#else
MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
#endif
- MV_DDR_CFG_SPD, /* ddr configuration data src */
+ MV_DDR_CFG_DEFAULT, /* ddr configuration data src */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
--
2.34.1
@@ -0,0 +1,29 @@
From da31240645cdf7ae424727ac330fdb6f6b118691 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Mon, 16 Oct 2023 10:52:19 +0200
Subject: [PATCH 2/2] marvell: Allow mv-ddr-marvell to be built from tarball
Build system relies on the mv-ddr-marvell being a valid GIT working
directory, which is not the case when building from a tarball.
Therefore, reduce this requirement from a hard error to a warning.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
plat/marvell/armada/a8k/common/ble/ble.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plat/marvell/armada/a8k/common/ble/ble.mk b/plat/marvell/armada/a8k/common/ble/ble.mk
index 752ab419d..db817e996 100644
--- a/plat/marvell/armada/a8k/common/ble/ble.mk
+++ b/plat/marvell/armada/a8k/common/ble/ble.mk
@@ -31,5 +31,5 @@ $(MV_DDR_LIB): FORCE
# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
$(if $(value MV_DDR_PATH),,$(error "Platform '$(PLAT)' for BLE requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
- $(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
+ $(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(warning "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
@+make -C $(MV_DDR_PATH) --no-print-directory PLAT_INCLUDES="$(MV_DDR_INCLUDES)" PLATFORM=$(PLAT) ARCH=AARCH64 OBJ_DIR=$(BUILD_PLAT)/ble
--
2.34.1
@@ -0,0 +1,156 @@
From 4348261902b60f93c217f07069a2b5613a933c17 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 17 Oct 2023 13:15:58 +0200
Subject: [PATCH 1/5] net: mv88e6xxx: Add reset-gpios support
If the switch's RESETn signal is under the CPUs control, release it
before starting the probe.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/mv88e6xxx.c | 68 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 61 insertions(+), 7 deletions(-)
diff --git a/drivers/net/mv88e6xxx.c b/drivers/net/mv88e6xxx.c
index 64e860e324..1bf7cfd6a6 100644
--- a/drivers/net/mv88e6xxx.c
+++ b/drivers/net/mv88e6xxx.c
@@ -33,6 +33,8 @@
#include <miiphy.h>
#include <net/dsa.h>
+#include <asm-generic/gpio.h>
+
/* Device addresses */
#define DEVADDR_PHY(p) (p)
#define DEVADDR_SERDES 0x0F
@@ -146,6 +148,8 @@ struct mv88e6xxx_priv {
int port_reg_base; /* Base of the switch port registers */
u8 global1; /* Offset of Switch Global 1 registers */
u8 global2; /* Offset of Switch Global 2 registers */
+
+ struct gpio_desc reset;
};
/* Wait for the current SMI indirect command to complete */
@@ -675,6 +679,37 @@ static int mv88e6xxx_probe_mdio(struct udevice *dev)
return ret;
}
+static int mv88e6xxx_probe_reset(struct udevice *dev)
+{
+ struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+ int err;
+
+ if (!CONFIG_IS_ENABLED(DM_GPIO))
+ return 0;
+
+ err = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset, GPIOD_IS_OUT);
+ if (err && (err != -ENOENT))
+ return err;
+
+ if (dm_gpio_is_valid(&priv->reset)) {
+ dm_gpio_set_value(&priv->reset, 0);
+ mdelay(10);
+ }
+
+ return 0;
+}
+
+static void mv88e6xxx_remove_reset(struct udevice *dev)
+{
+ struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&priv->reset)) {
+ dm_gpio_set_value(&priv->reset, 1);
+ dm_gpio_free(dev, &priv->reset);
+ }
+}
+
static int mv88e6xxx_probe(struct udevice *dev)
{
struct dsa_pdata *dsa_pdata = dev_get_uclass_plat(dev);
@@ -684,17 +719,22 @@ static int mv88e6xxx_probe(struct udevice *dev)
if (ofnode_valid(dev_ofnode(dev)) &&
!ofnode_is_enabled(dev_ofnode(dev))) {
dev_dbg(dev, "switch disabled\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
+ ret = mv88e6xxx_probe_reset(dev);
+ if (ret)
+ goto err;
+
/* probe internal mdio bus */
ret = mv88e6xxx_probe_mdio(dev);
if (ret)
- return ret;
+ goto err_remove_reset;
ret = mv88e6xxx_priv_reg_offs_pre_init(dev);
if (ret)
- return ret;
+ goto err_remove_reset;
dev_dbg(dev, "ID=0x%x PORT_BASE=0x%02x GLOBAL1=0x%02x GLOBAL2=0x%02x\n",
priv->id, priv->port_reg_base, priv->global1, priv->global2);
@@ -716,28 +756,40 @@ static int mv88e6xxx_probe(struct udevice *dev)
priv->port_count = 7;
break;
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_remove_reset;
}
ret = mv88e6xxx_switch_reset(dev);
if (ret < 0)
- return ret;
+ goto err_remove_reset;
if (mv88e6xxx_6352_family(dev)) {
val = mv88e6xxx_get_cmode(dev, dsa_pdata->cpu_port);
if (val < 0)
- return val;
+ goto err_remove_reset;
/* initialize serdes */
if (val == PORT_REG_STATUS_CMODE_100BASE_X ||
val == PORT_REG_STATUS_CMODE_1000BASE_X ||
val == PORT_REG_STATUS_CMODE_SGMII) {
ret = mv88e6xxx_serdes_init(dev);
if (ret < 0)
- return ret;
+ goto err_remove_reset;
}
}
return 0;
+
+err_remove_reset:
+ mv88e6xxx_remove_reset(dev);
+err:
+ return ret;
+}
+
+static int mv88e6xxx_remove(struct udevice *dev)
+{
+ mv88e6xxx_remove_reset(dev);
+ return 0;
}
static const struct udevice_id mv88e6xxx_ids[] = {
@@ -750,6 +802,8 @@ U_BOOT_DRIVER(mv88e6xxx) = {
.id = UCLASS_DSA,
.of_match = mv88e6xxx_ids,
.probe = mv88e6xxx_probe,
+ .remove = mv88e6xxx_remove,
.ops = &mv88e6xxx_dsa_ops,
.priv_auto = sizeof(struct mv88e6xxx_priv),
+ .flags = DM_FLAG_OS_PREPARE,
};
--
2.34.1
@@ -0,0 +1,181 @@
From d87aea2f0d0acfa0d54adb20a980256c0ba95023 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 17 Oct 2023 13:20:19 +0200
Subject: [PATCH 2/5] net: mv88e6xxx: Support clause 45 addressing on internal
MDIO bus
This is needed to access SERDES registers on newer chips, like the
6393X.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/mv88e6xxx.c | 113 +++++++++++++++++++++++++++++++++++++---
1 file changed, 106 insertions(+), 7 deletions(-)
diff --git a/drivers/net/mv88e6xxx.c b/drivers/net/mv88e6xxx.c
index 1bf7cfd6a6..eddac332e0 100644
--- a/drivers/net/mv88e6xxx.c
+++ b/drivers/net/mv88e6xxx.c
@@ -114,6 +114,9 @@
#define SMI_CMD_CLAUSE_22 BIT(12)
#define SMI_CMD_CLAUSE_22_OP_READ (2 << 10)
#define SMI_CMD_CLAUSE_22_OP_WRITE (1 << 10)
+#define SMI_CMD_CLAUSE_45_OP_WADDR (0 << 10)
+#define SMI_CMD_CLAUSE_45_OP_WDATA (1 << 10)
+#define SMI_CMD_CLAUSE_45_OP_RDATA (3 << 10)
#define SMI_CMD_ADDR_SHIFT 5
#define SMI_CMD_ADDR_MASK 0x1f
#define SMI_CMD_REG_SHIFT 0
@@ -126,6 +129,18 @@
(SMI_BUSY | SMI_CMD_CLAUSE_22 | SMI_CMD_CLAUSE_22_OP_WRITE) | \
(((addr) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
(((reg) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
+#define XSMI_CMD_WADDR(port, dev) \
+ (SMI_BUSY | SMI_CMD_CLAUSE_45_OP_WADDR) | \
+ (((port) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
+ (((dev) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
+#define XSMI_CMD_WDATA(port, dev) \
+ (SMI_BUSY | SMI_CMD_CLAUSE_45_OP_WDATA) | \
+ (((port) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
+ (((dev) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
+#define XSMI_CMD_RDATA(port, dev) \
+ (SMI_BUSY | SMI_CMD_CLAUSE_45_OP_RDATA) | \
+ (((port) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
+ (((dev) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
/* ID register values for different switch models */
#define PORT_SWITCH_ID_6020 0x0200
@@ -273,7 +288,41 @@ static int mv88e6xxx_phy_wait(struct udevice *dev)
return -ETIMEDOUT;
}
-static int mv88e6xxx_phy_read_indirect(struct udevice *dev, int phyad, int devad, int reg)
+static int mv88e6xxx_phy_read_indirect_c45(struct udevice *dev, int phyad, int devad, int reg)
+{
+ struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+ int res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA, reg);
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ XSMI_CMD_WADDR(phyad, devad));
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_phy_wait(dev);
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ XSMI_CMD_RDATA(phyad, devad));
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_phy_wait(dev);
+ if (res < 0)
+ return res;
+
+ return mv88e6xxx_reg_read(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA);
+}
+
+static int mv88e6xxx_phy_read_indirect_c22(struct udevice *dev, int phyad, int reg)
{
struct mv88e6xxx_priv *priv = dev_get_priv(dev);
int res;
@@ -293,8 +342,16 @@ static int mv88e6xxx_phy_read_indirect(struct udevice *dev, int phyad, int devad
GLOBAL2_REG_PHY_DATA);
}
-static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad,
- int devad, int reg, u16 data)
+static int mv88e6xxx_phy_read_indirect(struct udevice *dev, int phyad, int devad, int reg)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ return mv88e6xxx_phy_read_indirect_c22(dev, phyad, reg);
+
+ return mv88e6xxx_phy_read_indirect_c45(dev, phyad, devad, reg);
+}
+
+static int mv88e6xxx_phy_write_indirect_c22(struct udevice *dev, int phyad,
+ int reg, u16 data)
{
struct mv88e6xxx_priv *priv = dev_get_priv(dev);
int res;
@@ -315,6 +372,50 @@ static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad,
return mv88e6xxx_phy_wait(dev);
}
+static int mv88e6xxx_phy_write_indirect_c45(struct udevice *dev, int phyad,
+ int devad, int reg, u16 data)
+{
+ struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+ int res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA, reg);
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ XSMI_CMD_WADDR(phyad, devad));
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_phy_wait(dev);
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA, data);
+ if (res < 0)
+ return res;
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ XSMI_CMD_WDATA(phyad, devad));
+ if (res < 0)
+ return res;
+
+ return mv88e6xxx_phy_wait(dev);
+}
+
+static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad,
+ int devad, int reg, u16 data)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ return mv88e6xxx_phy_write_indirect_c22(dev, phyad, reg, data);
+
+ return mv88e6xxx_phy_write_indirect_c45(dev, phyad, devad, reg, data);
+}
+
/* Wrapper function to make calls to phy_read_indirect simpler */
static int mv88e6xxx_phy_read(struct udevice *dev, int phy, int reg)
{
@@ -493,15 +594,13 @@ static int mv88e6xxx_priv_reg_offs_pre_init(struct udevice *dev)
static int mv88e6xxx_mdio_read(struct udevice *dev, int addr, int devad, int reg)
{
- return mv88e6xxx_phy_read_indirect(dev->parent, DEVADDR_PHY(addr),
- MDIO_DEVAD_NONE, reg);
+ return mv88e6xxx_phy_read_indirect(dev->parent, DEVADDR_PHY(addr), devad, reg);
}
static int mv88e6xxx_mdio_write(struct udevice *dev, int addr, int devad,
int reg, u16 val)
{
- return mv88e6xxx_phy_write_indirect(dev->parent, DEVADDR_PHY(addr),
- MDIO_DEVAD_NONE, reg, val);
+ return mv88e6xxx_phy_write_indirect(dev->parent, DEVADDR_PHY(addr), devad, reg, val);
}
static const struct mdio_ops mv88e6xxx_mdio_ops = {
--
2.34.1
@@ -0,0 +1,216 @@
From c801299f06f0e5c95bd597fe0ce4ad6c3df9a444 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 17 Oct 2023 13:22:00 +0200
Subject: [PATCH 3/5] net: mv88e6xxx: Add support for 6393X
Only built-in copper PHYs are supported as access ports. Support
10GBASE-R SERDES connection to CPU.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/mv88e6xxx.c | 134 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 130 insertions(+), 4 deletions(-)
diff --git a/drivers/net/mv88e6xxx.c b/drivers/net/mv88e6xxx.c
index eddac332e0..4a4a3ae0b1 100644
--- a/drivers/net/mv88e6xxx.c
+++ b/drivers/net/mv88e6xxx.c
@@ -74,6 +74,7 @@
#define PORT_REG_STATUS_SPEED_1000 2
#define PORT_REG_STATUS_CMODE_MASK 0xF
+#define PORT_REG_STATUS_CMODE_10GBASE_R 0xd
#define PORT_REG_STATUS_CMODE_SGMII 0xa
#define PORT_REG_STATUS_CMODE_1000BASE_X 0x9
#define PORT_REG_STATUS_CMODE_100BASE_X 0x8
@@ -155,6 +156,7 @@
#define PORT_SWITCH_ID_6250 0x2500
#define PORT_SWITCH_ID_6320 0x1150
#define PORT_SWITCH_ID_6352 0x3520
+#define PORT_SWITCH_ID_6393 0x3930
struct mv88e6xxx_priv {
int smi_addr;
@@ -475,6 +477,17 @@ static bool mv88e6xxx_6352_family(struct udevice *dev)
return false;
}
+static bool mv88e6xxx_6393_family(struct udevice *dev)
+{
+ struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+
+ switch (priv->id) {
+ case PORT_SWITCH_ID_6393:
+ return true;
+ }
+ return false;
+}
+
static int mv88e6xxx_get_cmode(struct udevice *dev, u8 port)
{
int res;
@@ -529,7 +542,7 @@ static int mv88e6xxx_switch_reset(struct udevice *dev)
return 0;
}
-static int mv88e6xxx_serdes_init(struct udevice *dev)
+static int mv88e6352_serdes_init(struct udevice *dev)
{
int val;
@@ -549,6 +562,107 @@ static int mv88e6xxx_serdes_init(struct udevice *dev)
return 0;
}
+static int mv88e6393_serdes_erratum_4_6(struct udevice *dev, int port)
+{
+ int val;
+
+ /* mv88e6393x family errata 4.6:
+ * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD
+ * mode or P0_mode is configured for [x]MII.
+ * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1.
+ *
+ * It seems that after this workaround the SERDES is automatically
+ * powered up (the bit is cleared), so power it down.
+ */
+ val = mv88e6xxx_phy_read_indirect(dev, port, MDIO_MMD_PHYXS, 0xf002);
+ if (val < 0)
+ return val;
+
+ val &= ~BIT(5);
+ val |= MDIO_CTRL1_RESET;
+ return mv88e6xxx_phy_write_indirect(dev, port, MDIO_MMD_PHYXS, 0xf002, val);
+}
+
+static int mv88e6393_serdes_erratum_5_2(struct udevice *dev, int port, int cmode)
+{
+ static const struct {
+ u16 dev, reg, val, mask;
+ } fixes[] = {
+ { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
+ { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
+ { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
+ { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
+ { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
+ { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
+ { MDIO_MMD_PHYXS, 0xf002, 0x8000, 0x8000 }
+ };
+ int val, i;
+
+ /* mv88e6393x family errata 5.2:
+ * For optimal signal integrity the following sequence should be applied
+ * to SERDES operating in 10G mode. These registers only apply to 10G
+ * operation and have no effect on other speeds.
+ */
+ if (cmode != PORT_REG_STATUS_CMODE_10GBASE_R)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
+ val = mv88e6xxx_phy_read_indirect(dev, port, fixes[i].dev, fixes[i].reg);
+ if (val < 0)
+ return val;
+
+ val &= ~fixes[i].mask;
+ val |= fixes[i].val;
+
+ val = mv88e6xxx_phy_write_indirect(dev, port, fixes[i].dev, fixes[i].reg, val);
+ if (val < 0)
+ return val;
+ }
+
+ return 0;
+}
+
+static int mv88e6393_serdes_init(struct udevice *dev, int port, int cmode)
+{
+ u16 base;
+ int val;
+
+ val = mv88e6393_serdes_erratum_4_6(dev, port);
+ if (val < 0)
+ return val;
+
+ val = mv88e6393_serdes_erratum_5_2(dev, port, cmode);
+ if (val < 0)
+ return val;
+
+ switch (cmode) {
+ case PORT_REG_STATUS_CMODE_10GBASE_R:
+ base = 0x1000;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ val = mv88e6xxx_phy_read_indirect(dev, port, MDIO_MMD_PHYXS, base);
+ if (val < 0)
+ return val;
+
+ val &= ~MDIO_CTRL1_LPOWER;
+ val |= MDIO_CTRL1_RESET;
+
+ return mv88e6xxx_phy_write_indirect(dev, port, MDIO_MMD_PHYXS, base, val);
+}
+
+static int mv88e6xxx_serdes_init(struct udevice *dev, int cpu_port, int cmode)
+{
+ if (mv88e6xxx_6352_family(dev))
+ return mv88e6352_serdes_init(dev);
+ else if (mv88e6xxx_6393_family(dev))
+ return mv88e6393_serdes_init(dev, cpu_port, cmode);
+
+ return -EOPNOTSUPP;
+}
+
/*
* This function is used to pre-configure the required register
* offsets, so that the indirect register access to the PHY registers
@@ -569,6 +683,15 @@ static int mv88e6xxx_priv_reg_offs_pre_init(struct udevice *dev)
*/
priv->port_reg_base = 0x10;
priv->id = mv88e6xxx_get_switch_id(dev);
+ if (priv->id == 0xfff0) {
+ /*
+ * Look for a newer device in which ports start at
+ * offset 0 (6390/6393 and compatible switches).
+ */
+ priv->port_reg_base = 0;
+ priv->id = mv88e6xxx_get_switch_id(dev);
+ }
+
if (priv->id != 0xfff0) {
priv->global1 = 0x1B;
priv->global2 = 0x1C;
@@ -844,6 +967,7 @@ static int mv88e6xxx_probe(struct udevice *dev)
case PORT_SWITCH_ID_6176:
case PORT_SWITCH_ID_6240:
case PORT_SWITCH_ID_6352:
+ case PORT_SWITCH_ID_6393:
priv->port_count = 11;
break;
case PORT_SWITCH_ID_6020:
@@ -863,15 +987,17 @@ static int mv88e6xxx_probe(struct udevice *dev)
if (ret < 0)
goto err_remove_reset;
- if (mv88e6xxx_6352_family(dev)) {
+ if (mv88e6xxx_6352_family(dev) ||
+ mv88e6xxx_6393_family(dev)) {
val = mv88e6xxx_get_cmode(dev, dsa_pdata->cpu_port);
if (val < 0)
goto err_remove_reset;
/* initialize serdes */
if (val == PORT_REG_STATUS_CMODE_100BASE_X ||
val == PORT_REG_STATUS_CMODE_1000BASE_X ||
- val == PORT_REG_STATUS_CMODE_SGMII) {
- ret = mv88e6xxx_serdes_init(dev);
+ val == PORT_REG_STATUS_CMODE_SGMII ||
+ val == PORT_REG_STATUS_CMODE_10GBASE_R) {
+ ret = mv88e6xxx_serdes_init(dev, dsa_pdata->cpu_port, val);
if (ret < 0)
goto err_remove_reset;
}
--
2.34.1
@@ -0,0 +1,54 @@
From 5013dadfd3ba92eba930f8ea0f88c0f34b8c55a5 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Fri, 20 Oct 2023 13:19:41 +0200
Subject: [PATCH 4/5] i2c: pcf8575: Properly address chip
These devices hold a simple shift register that is accessed without
any "register" setup.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/gpio/pcf8575_gpio.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/pcf8575_gpio.c b/drivers/gpio/pcf8575_gpio.c
index d5930d941f..bc0275b901 100644
--- a/drivers/gpio/pcf8575_gpio.c
+++ b/drivers/gpio/pcf8575_gpio.c
@@ -49,9 +49,15 @@ static int pcf8575_i2c_write(struct udevice *dev, unsigned int word)
{
struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
u8 buf[2] = { word & 0xff, word >> 8, };
+ struct i2c_msg wmsg = {
+ .addr = chip->chip_addr,
+ .flags = 0,
+ .buf = buf,
+ .len = dev_get_driver_data(dev),
+ };
int ret;
- ret = dm_i2c_write(dev, 0, buf, dev_get_driver_data(dev));
+ ret = dm_i2c_xfer(dev, &wmsg, 1);
if (ret)
printf("%s i2c write failed to addr %x\n", __func__,
chip->chip_addr);
@@ -63,9 +69,15 @@ static int pcf8575_i2c_read(struct udevice *dev)
{
struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
u8 buf[2] = {0x00, 0x00};
+ struct i2c_msg rmsg = {
+ .addr = chip->chip_addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = dev_get_driver_data(dev),
+ };
int ret;
- ret = dm_i2c_read(dev, 0, buf, dev_get_driver_data(dev));
+ ret = dm_i2c_xfer(dev, &rmsg, 1);
if (ret) {
printf("%s i2c read failed from addr %x\n", __func__,
chip->chip_addr);
--
2.34.1
@@ -0,0 +1,576 @@
From c0495a607652aef38a4d4480ebdb6dd45e3dd9b9 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 24 Oct 2023 22:23:44 +0200
Subject: [PATCH 5/5] arm64: mvebu: a8k: Add eFuse support
Add support for reading and burning LD and HD fuses. Use a specialized
commandline implementation over the standard "fuse" command because:
- We want to reference fuses by the die and module they belong to,
rather than a plain integer bank ID.
- Our lines are wider than 32 bits, meaning that we would have to use
similar tactics as arch/arm/mach-mvebu/efuse.c in order to support
fuse programming, which is cumbersome.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
arch/arm/mach-mvebu/Kconfig | 7 +
arch/arm/mach-mvebu/armada8k/Makefile | 2 +
arch/arm/mach-mvebu/armada8k/efuse.c | 516 ++++++++++++++++++++++++++
3 files changed, 525 insertions(+)
create mode 100644 arch/arm/mach-mvebu/armada8k/efuse.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index ac484c73f6..45584b4282 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -421,6 +421,13 @@ config MVEBU_EFUSE_VHV_GPIO_ACTIVE_LOW
bool "VHV_Enable GPIO is Active Low"
depends on MVEBU_EFUSE_VHV_GPIO != ""
+config MVEBU_8K_EFUSE
+ bool "Enable eFuse support"
+ depends on ARMADA_8K
+ select HEX_DUMP
+ help
+ Enable support for reading and writing eFuses on mvebu SoCs.
+
config SECURED_MODE_IMAGE
bool "Build image for trusted boot"
default false
diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile
index 0a4756717a..c1be059b85 100644
--- a/arch/arm/mach-mvebu/armada8k/Makefile
+++ b/arch/arm/mach-mvebu/armada8k/Makefile
@@ -3,3 +3,5 @@
# Copyright (C) 2016 Stefan Roese <sr@denx.de>
obj-y = cpu.o cache_llc.o dram.o
+
+obj-$(CONFIG_MVEBU_8K_EFUSE) += efuse.o
diff --git a/arch/arm/mach-mvebu/armada8k/efuse.c b/arch/arm/mach-mvebu/armada8k/efuse.c
new file mode 100644
index 0000000000..5438d4466d
--- /dev/null
+++ b/arch/arm/mach-mvebu/armada8k/efuse.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc>
+ */
+
+#include <command.h>
+#include <common.h>
+#include <errno.h>
+#include <hexdump.h>
+
+#include <asm/io.h>
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+enum mvebu_efuse_mod {
+ MVEBU_EFUSE_MOD_LD0,
+ MVEBU_EFUSE_MOD_LD1,
+ MVEBU_EFUSE_MOD_HD,
+};
+
+struct mvebu_efuse_ld {
+ u32 array[256 / 32];
+#define MVEBU_EFUSE_LD_PARITY_BIT BIT(31)
+ u32 burn;
+};
+
+struct mvebu_efuse_hd_line {
+ u32 array[2];
+#define MVEBU_EFUSE_HD_ECC_MASK 0xfe000000
+ u32 lock;
+ u32 pad;
+};
+
+struct mvebu_efuse_hd {
+#define MVEBU_EFUSE_HD_LINES 64
+ struct mvebu_efuse_hd_line line[MVEBU_EFUSE_HD_LINES];
+};
+
+struct mvebu_efuse_die {
+ union {
+ struct {
+ u32 resvd0;
+ u32 resvd1;
+ u32 ctrl;
+ };
+
+ u8 pad_ctrl[0xf00];
+ };
+
+ union {
+ struct mvebu_efuse_ld ld;
+ u8 pad_ld[0x100];
+ };
+
+ union {
+ struct mvebu_efuse_hd hd;
+ };
+};
+
+static const struct mvebu_efuse_die __iomem *mvebu_efuse_dies[] = {
+ (void __iomem *)0xf06f8000,
+ (void __iomem *)0xf2400000,
+};
+
+static void mvebu_efuse_program_set(const struct mvebu_efuse_die __iomem *die,
+ bool enable)
+{
+ if (enable)
+ setbits_le32(&die->ctrl, BIT(31));
+ else
+ clrbits_le32(&die->ctrl, BIT(31));
+}
+
+static void mvebu_efuse_secure_set(const struct mvebu_efuse_die __iomem *die,
+ bool enable)
+{
+ if (enable)
+ setbits_le32(&die->ctrl, BIT(7));
+ else
+ clrbits_le32(&die->ctrl, BIT(7));
+}
+
+static void mvebu_efuse_ld_select(const struct mvebu_efuse_die __iomem *die,
+ bool ld1)
+{
+ if (ld1)
+ setbits_le32(&die->ctrl, BIT(6));
+ else
+ clrbits_le32(&die->ctrl, BIT(6));
+}
+
+static void mvebu_efuse_ld_read(const struct mvebu_efuse_die __iomem *die,
+ bool ld1, struct mvebu_efuse_ld *ld)
+{
+ size_t i;
+
+ mvebu_efuse_ld_select(die, ld1);
+
+ for (i = 0; i < ARRAY_SIZE(ld->array); i++) {
+ ld->array[i] = readl(&die->ld.array[i]);
+ if (i & 1)
+ ld->array[i] &= ~MVEBU_EFUSE_LD_PARITY_BIT;
+ }
+}
+
+static int mvebu_efuse_ld_write(const struct mvebu_efuse_die __iomem *die,
+ bool ld1, bool secure, const struct mvebu_efuse_ld *ld)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(ld->array); i++)
+ if ((i & 1) && (ld->array[i] & MVEBU_EFUSE_LD_PARITY_BIT))
+ return -EINVAL;
+
+ mvebu_efuse_ld_select(die, ld1);
+ mvebu_efuse_program_set(die, true);
+ mvebu_efuse_secure_set(die, secure);
+
+ for (i = 0; i < ARRAY_SIZE(ld->array); i++)
+ writel(ld->array[i], &die->ld.array[i]);
+
+ writel(0, &die->ld.burn);
+ mdelay(1);
+
+ mvebu_efuse_program_set(die, false);
+ return 0;
+}
+
+static int mvebu_efuse_hd_read_line(const struct mvebu_efuse_die __iomem *die,
+ u8 line, struct mvebu_efuse_hd_line *hdl)
+{
+ if (line >= ARRAY_SIZE(die->hd.line))
+ return -ERANGE;
+
+ hdl->array[0] = readl(&die->hd.line[line].array[0]);
+ hdl->array[1] = readl(&die->hd.line[line].array[1]);
+ hdl->array[1] &= ~MVEBU_EFUSE_HD_ECC_MASK;
+ hdl->lock = readl(&die->hd.line[line].lock);
+ return 0;
+}
+
+static int mvebu_efuse_hd_write_line(const struct mvebu_efuse_die __iomem *die,
+ u8 line, const struct mvebu_efuse_hd_line *hdl)
+{
+ if (line >= ARRAY_SIZE(die->hd.line))
+ return -ERANGE;
+
+ if (hdl->array[1] & MVEBU_EFUSE_HD_ECC_MASK)
+ return -EINVAL;
+
+ mvebu_efuse_program_set(die, true);
+
+ writel(hdl->array[0], &die->hd.line[line].array[0]);
+ writel(hdl->array[1], &die->hd.line[line].array[1]);
+ writel(0, &die->hd.line[line].lock);
+ mdelay(1);
+
+ mvebu_efuse_program_set(die, false);
+ return 0;
+}
+
+
+/*
+ * Commandline interface
+ */
+
+static int mvefuse_die(const char *diestr,
+ const struct mvebu_efuse_die __iomem **diep)
+{
+ if (!strcmp(diestr, "ap")) {
+ *diep = mvebu_efuse_dies[0];
+ } else if (!strcmp(diestr, "cp0")) {
+ *diep = mvebu_efuse_dies[1];
+ } else {
+ printf("\"%s\" is not a valid die\n", diestr);
+ return CMD_RET_USAGE;
+ }
+
+ return 0;
+}
+
+static int mvefuse_mod(const char *fuse, enum mvebu_efuse_mod *modp)
+{
+ if (!strcmp(fuse, "ld0")) {
+ *modp = MVEBU_EFUSE_MOD_LD0;
+ } else if (!strcmp(fuse, "ld1")) {
+ *modp = MVEBU_EFUSE_MOD_LD1;
+ } else if (!strncmp(fuse, "hd", 2)) {
+ *modp = MVEBU_EFUSE_MOD_HD;
+ } else {
+ printf("\"%s\" is not a valid fuse\n", fuse);
+ return CMD_RET_USAGE;
+ }
+
+ return 0;
+}
+
+#define MVEFUSE_LINE_ALL 0xff
+
+static int mvefuse_line(const char *fuse, u8 *linep)
+{
+ unsigned long line;
+
+ if (!strcmp(fuse, "hd")) {
+ *linep = MVEFUSE_LINE_ALL;
+ return 0;
+ }
+
+ line = simple_strtoul(&fuse[2], NULL, 0);
+ if (line >= MVEBU_EFUSE_HD_LINES) {
+ printf("\"%s\" is not valid HD fuse\n", fuse);
+ return CMD_RET_USAGE;
+ }
+
+ *linep = line;
+ return 0;
+}
+
+static int mvefuse_parse(char * const *argv,
+ const struct mvebu_efuse_die __iomem **diep,
+ enum mvebu_efuse_mod *modp,
+ u8 *linep)
+{
+ int err;
+
+ err = mvefuse_die(argv[0], diep);
+ if (err)
+ return err;
+
+ err = mvefuse_mod(argv[1], modp);
+ if (err)
+ return err;
+
+ if (*modp != MVEBU_EFUSE_MOD_HD)
+ return 0;
+
+ return mvefuse_line(argv[1], linep);
+}
+
+static int do_mvefuse_md_ld(const struct mvebu_efuse_die __iomem *die,
+ bool ld1)
+{
+ struct mvebu_efuse_ld ld;
+
+ mvebu_efuse_ld_read(die, ld1, &ld);
+
+ print_hex_dump("", DUMP_PREFIX_OFFSET, 16, 4,
+ ld.array, sizeof(ld.array), false);
+ return 0;
+}
+
+static int do_mvefuse_md_hd_line(const struct mvebu_efuse_die __iomem *die,
+ u8 line)
+{
+ struct mvebu_efuse_hd_line hdl;
+ int err;
+
+ err = mvebu_efuse_hd_read_line(die, line, &hdl);
+ if (err) {
+ printf("Unable to read HD line %u: %d\n", line, err);
+ return CMD_RET_FAILURE;
+ }
+
+ printf("%08x %08x %s\n", hdl.array[0], hdl.array[1],
+ hdl.lock ? "[LOCKED]" : "");
+ return 0;
+}
+
+static int do_mvefuse_md_hd_all(const struct mvebu_efuse_die __iomem *die)
+{
+ u8 line;
+ int err;
+
+ for (line = 0; line < MVEBU_EFUSE_HD_LINES; line++) {
+ printf("Line %02u: ", line);
+ err = do_mvefuse_md_hd_line(die, line);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int do_mvefuse_md(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const *argv)
+{
+ const struct mvebu_efuse_die __iomem *die;
+ enum mvebu_efuse_mod mod;
+ u8 line;
+ int err;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ err = mvefuse_parse(&argv[1], &die, &mod, &line);
+ if (err)
+ return err;
+
+ switch (mod) {
+ case MVEBU_EFUSE_MOD_LD0:
+ return do_mvefuse_md_ld(die, false);
+ case MVEBU_EFUSE_MOD_LD1:
+ return do_mvefuse_md_ld(die, true);
+ case MVEBU_EFUSE_MOD_HD:
+ if (line == MVEFUSE_LINE_ALL)
+ return do_mvefuse_md_hd_all(die);
+ else
+ return do_mvefuse_md_hd_line(die, line);
+ }
+
+ return CMD_RET_FAILURE;
+}
+
+static int do_mvefuse_mw_ld(const struct mvebu_efuse_die __iomem *die,
+ bool ld1, int argc, char *const *argv,
+ bool interactive)
+{
+ struct mvebu_efuse_ld ld;
+ bool secure = false;
+ size_t i;
+ int err;
+
+ mvebu_efuse_ld_read(die, ld1, &ld);
+
+ switch (argc) {
+ case 9:
+ if (!strcmp(argv[8], "lock"))
+ secure = true;
+ else
+ return CMD_RET_USAGE;
+
+ /* fallthrough */
+ case 8:
+ for (i = 0; i < ARRAY_SIZE(ld.array); i++)
+ ld.array[i] |= hextoul(argv[i], NULL);
+
+ break;
+
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ if (interactive) {
+ printf("The following values will be written%s into %s:\n",
+ secure ? ", and PERMANENTLY LOCKED," : "",
+ ld1 ? "LD1" : "LD0");
+
+ print_hex_dump("", DUMP_PREFIX_OFFSET, 16, 4,
+ ld.array, sizeof(ld.array), false);
+
+ puts("WARNING: This operation is irreversible\n"
+ "Are you sure you want to continue? (y/N)\n");
+
+ if (!confirm_yesno()) {
+ puts("Programming aborted\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+
+ err = mvebu_efuse_ld_write(die, ld1, secure, &ld);
+ if (err) {
+ printf("Failed to program %s: %d\n", ld1 ? "LD1" : "LD0", err);
+ return CMD_RET_FAILURE;
+ }
+
+ return 0;
+}
+
+static int do_mvefuse_mw_hd_line(const struct mvebu_efuse_die __iomem *die,
+ u8 line, int argc, char *const *argv,
+ bool interactive)
+{
+ struct mvebu_efuse_hd_line hdl;
+ int err;
+
+ mvebu_efuse_hd_read_line(die, line, &hdl);
+ if (hdl.lock) {
+ printf("Unable to program LOCKED line HD%u\n", line);
+ return CMD_RET_FAILURE;
+ }
+
+ switch (argc) {
+ case 3:
+ /* In contrast to the LD fuse array, HD fuse lines are
+ * always locked when programmed, make sure the user
+ * is aware of this by requiring the "lock" keyword to
+ * be specified. */
+ if (strcmp(argv[2], "lock"))
+ return CMD_RET_USAGE;
+
+ hdl.array[0] |= hextoul(argv[0], NULL);
+ hdl.array[1] |= hextoul(argv[1], NULL);
+ break;
+
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ if (interactive) {
+ printf("The following values will be PERMANENTLY written into HD%u:\n",
+ line);
+
+ printf("%08x %08x\n", hdl.array[0], hdl.array[1]);
+
+ puts("WARNING: This operation is irreversible\n"
+ "Are you sure you want to continue? (y/N)\n");
+
+ if (!confirm_yesno()) {
+ puts("Programming aborted\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+
+ err = mvebu_efuse_hd_write_line(die, line, &hdl);
+ if (err) {
+ printf("Failed to program HD%u: %d\n", line, err);
+ return CMD_RET_FAILURE;
+ }
+
+ return 0;
+}
+
+static int do_mvefuse_mw(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const *argv)
+{
+ const struct mvebu_efuse_die __iomem *die;
+ enum mvebu_efuse_mod mod;
+ bool interactive = true;
+ u8 line;
+ int err;
+
+ /* Pop off "md" */
+ argv++, argc--;
+
+ if (argc && (!strcmp("-y", argv[0]))) {
+ interactive = false;
+ argv++, argc--;
+ }
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ err = mvefuse_parse(argv, &die, &mod, &line);
+ if (err)
+ return err;
+
+ /* Pop off <die> and <fuse> */
+ argv++, argc--;
+ argv++, argc--;
+
+ switch (mod) {
+ case MVEBU_EFUSE_MOD_LD0:
+ return do_mvefuse_mw_ld(die, false, argc, argv, interactive);
+ case MVEBU_EFUSE_MOD_LD1:
+ return do_mvefuse_mw_ld(die, true, argc, argv, interactive);
+ case MVEBU_EFUSE_MOD_HD:
+ if (line == MVEFUSE_LINE_ALL)
+ return CMD_RET_USAGE;
+ else
+ return do_mvefuse_mw_hd_line(die, line, argc, argv, interactive);
+ }
+
+ return CMD_RET_FAILURE;
+}
+
+static int do_mvefuse_unlocked(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const argv[])
+{
+ const struct mvebu_efuse_die __iomem *die;
+ struct mvebu_efuse_hd_line hdl;
+ enum mvebu_efuse_mod mod;
+ u8 line;
+ int err;
+
+ if (argc != 3)
+ return CMD_RET_USAGE;
+
+ err = mvefuse_parse(&argv[1], &die, &mod, &line);
+ if (err)
+ return err;
+
+ if (mod != MVEBU_EFUSE_MOD_HD) {
+ printf("Only HD fuse lines have individual lock bits\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (line == MVEFUSE_LINE_ALL) {
+ printf("Only an individual fuse line can be tested\n");
+ return CMD_RET_FAILURE;
+ }
+
+ err = mvebu_efuse_hd_read_line(die, line, &hdl);
+ if (err) {
+ printf("Unable to read HD%u: %d\n", line, err);
+ return CMD_RET_FAILURE;
+ }
+
+ return !!hdl.lock;
+}
+
+U_BOOT_CMD_WITH_SUBCMDS(
+ mvefuse, "Marvell eFuse Access",
+ "md <die> <fuse> - Dump the contents of <fuse> from <die>\n"
+ "mvefuse mw [-y] <die> <fuse> <words...> [lock] - Program <words..> into\n"
+ " <fuse> in <die>, optionally permanently locking it\n"
+ "mvefuse unlocked <die> hd<0-63> - Test if an HD fuse line on <die> is \n"
+ " unlocked\n"
+ "\n"
+ "<die>: ap|cp0\n"
+ "<fuse>: ld0|ld1|hd<0-63>\n",
+
+ U_BOOT_SUBCMD_MKENT(md, 3, 1, do_mvefuse_md),
+ U_BOOT_SUBCMD_MKENT(mw, 12, 1, do_mvefuse_mw),
+ U_BOOT_SUBCMD_MKENT(unlocked, 3, 1, do_mvefuse_unlocked));
--
2.34.1
-13
View File
@@ -1,13 +0,0 @@
Index: uboot-2023.07.02/arch/arm/dts/cn9130-crb.dtsi
===================================================================
--- uboot-2023.07.02.orig/arch/arm/dts/cn9130-crb.dtsi
+++ uboot-2023.07.02/arch/arm/dts/cn9130-crb.dtsi
@@ -239,7 +239,7 @@
&cp0_eth0 {
status = "okay";
- phy-mode = "sfi";
+ phy-mode = "10gbase-r";
};
&cp0_eth1 {
+14 -5
View File
@@ -1,20 +1,26 @@
# Defaults for testing bootstrap script -*-conf-*-
#set -x
TESTING=true
PATH=.:$PATH
INIT_DATA=/etc/sysrepo/factory-default.json
SEARCH=/usr/share/yang/modules/confd:/usr/share/yang/modules/libnetconf2:/usr/share/yang/modules/libyang:/usr/share/yang/modules/netopeer2:/usr/share/yang/modules/sysrepo
CFG_PATH_=/tmp/confd
CFG_PATH_=/tmp/confd/cfg
RUN_PATH_=/tmp/confd/run
FACTORY_DEFAULTS_D=../share/factory.d
FAILURE_DEFAULTS_D=../share/failure.d
FACTORY_D=$CFG_PATH_/factory.d
FAILURE_D=$CFG_PATH_/failure.d
FACTORY_D=$RUN_PATH_/factory.d
FAILURE_D=$RUN_PATH_/failure.d
FACTORY_CFG=$CFG_PATH_/factory-config.cfg
FAILURE_CFG=$CFG_PATH_/failure-config.cfg
FACTORY_GEN=$RUN_PATH_/factory-config.gen
FAILURE_GEN=$RUN_PATH_/failure-config.gen
FACTORY_CFG=$RUN_PATH_/factory-config.cfg
FAILURE_CFG=$RUN_PATH_/failure-config.cfg
STARTUP_CFG=$CFG_PATH_/startup-config.cfg
# Uncomment this line in to create a bridge (br0) with all (classified
@@ -26,3 +32,6 @@ STARTUP_CFG=$CFG_PATH_/startup-config.cfg
# Default hostname in Fail Secure mode, plus last three octets in the base
# MAC address, e.g. "failed-c0-ff-ee".
FAIL_HOSTNAME="failed"
# Only needed for testing
mkdir -p "$CFG_PATH_" "$RUN_PATH_" "$FACTORY_D" "$FAILURE_D"
+44 -46
View File
@@ -1,14 +1,14 @@
#!/bin/sh
# Bootstrap sysrepo db with all modules required by confd
# Bootstrap system factory-config, failure-config and sysrepo db.
#
# 1. Load all yang models with /cfg/factory-config
# 2. [ if /cfg/startup-config is missing :: copy {factory} -> /cfg/startup-config ]
# 3. Import /cfg/startup -> {startup} ]
# 4. Clear running-config :: import NULL -> {running}
# 5. Start sysrepo-plugind
# 6. Activate startup-config by :: copy {startup} -> {running}
# The system factory-config and failure-config are derived from default
# settings snippets, from /usr/share/confd/factory.d, and some generated
# snippets, e.g., device unique password, hostname (based on base MAC
# address), and number of interfaces.
#
# It's all really simple ... this script takes care of 1-4
# The resulting factory-config is used to create the syrepo db (below)
# {factory} datastore. Hence, the factory-config file must match the
# the YANG models of the active image.
#
# /etc/confdrc controls the behavior or most of the gen-scripts,
@@ -27,17 +27,30 @@ fi
# shellcheck disable=SC1090
. "$RC"
FACTORY_GEN="$(dirname "$FACTORY_CFG")/$(basename "$FACTORY_CFG" .cfg).gen"
FAILURE_GEN="$(dirname "$FAILURE_CFG")/$(basename "$FAILURE_CFG" .cfg).gen"
# shellcheck disable=SC2046,SC2086
collate()
{
gen=$1; shift
cfg=$1; shift
dir=$*
# Generate device's factory-config at first boot or on override
if [ ! -f "$FACTORY_GEN" ] || [ "$FACTORY_OVERRIDE" = "true" ]; then
mkdir -p "$FACTORY_D"
rm -f "$gen"
jq -s 'reduce .[] as $item ({}; . * $item)' $(find $dir -name '*.json' | sort) >"$gen"
chmod 444 "$gen"
# Save the original templates (from the original image) used to create factory-config
for file in $(find "$FACTORY_DEFAULTS_D" -type f); do
cp "$file" "$FACTORY_D"
done
if [ ! -f "$cfg" ]; then
cp "$gen" "$cfg"
fi
}
# TODO: Look for statically defined factory-config, based on the
# system's product ID, or just custom site-specific factory.
#
# If we haven't found a more specific, better match, settle for
# factory-config.gen as the system's factory-config.
factory()
{
gen=$1
# Create an overlay for /etc/hostname to change the default in an br2-external
gen-hostname >"$FACTORY_D/20-hostname.json"
@@ -52,26 +65,17 @@ if [ ! -f "$FACTORY_GEN" ] || [ "$FACTORY_OVERRIDE" = "true" ]; then
rm -f "$FACTORY_GEN"
# shellcheck disable=SC2046
jq -s 'reduce .[] as $item ({}; . * $item)' \
$(find "$FACTORY_D" -name '*.json' | sort) >"$FACTORY_GEN"
jq -s 'reduce .[] as $item ({}; . * $item)' \
$(find "$FACTORY_DEFAULTS_D" "$FACTORY_D" -name '*.json' | sort) \
>"$FACTORY_GEN"
chmod 444 "$FACTORY_GEN"
# TODO: Look for statically defined factory-config, based on the
# system's product ID, or just custom site-specific factory.
collate "$FACTORY_GEN" "$FACTORY_CFG" "$FACTORY_DEFAULTS_D" "$FACTORY_D"
}
# If we haven't found a more specific, better match, settle for
# factory-config.gen as the system's factory-config.
[ -h "$FACTORY_CFG" ] || ln -sf "$(basename "$FACTORY_GEN")" "$FACTORY_CFG"
fi
# Generate device's failure-config at first boot
if [ ! -f "$FAILURE_GEN" ] || [ "$FAILURE_OVERRIDE" = "true" ]; then
mkdir -p "$FAILURE_D"
# Save the original templates (from the original image) used to create failure-config
for file in $(find "$FAILURE_DEFAULTS_D" -type f); do
cp "$file" "$FAILURE_D"
done
failure()
{
gen=$1
gen-hostname "$FAIL_HOSTNAME" >"$FAILURE_D/20-hostname.json"
gen-interfaces >"$FAILURE_D/20-interfaces.json"
@@ -81,14 +85,11 @@ if [ ! -f "$FAILURE_GEN" ] || [ "$FAILURE_OVERRIDE" = "true" ]; then
# Optional failure/error config to generate (or override) for br2-externals
[ -x "$(command -v gen-err-custom)" ] && gen-err-custom >"$FAILURE_D/30-error.json"
rm -f "$FAILURE_GEN"
# shellcheck disable=SC2046
jq -s 'reduce .[] as $item ({}; . * $item)' \
$(find "$FAILURE_D" -name '*.json' | sort) >"$FAILURE_GEN"
chmod 444 "$FAILURE_GEN"
collate "$FAILURE_GEN" "$FAILURE_CFG" "$FAILURE_DEFAULTS_D" "$FAILURE_D"
}
[ -h "$FAILURE_CFG" ] || ln -sf "$(basename "$FAILURE_GEN")" "$FAILURE_CFG"
fi
factory "$FACTORY_GEN"
failure "$FAILURE_GEN"
if [ -n "$TESTING" ]; then
echo "Done."
@@ -147,11 +148,7 @@ sysrepoctl -s $SEARCH \
-i ietf-yang-push@2019-09-09.yang -g wheel -p 0660 \
-e on-change \
-i iana-if-type@2023-01-26.yang -g wheel -p 0660 \
-i ietf-if-extensions@2023-01-26.yang -g wheel -p 0660 \
-e sub-interfaces \
-i ieee802-dot1q-types@2022-10-29.yang -g wheel -p 0660 \
-i ietf-if-vlan-encapsulation@2023-01-26.yang \
-g wheel -p 0660 \
-i infix-ip@2023-09-14.yang -g wheel -p 0660 \
-i infix-if-type@2023-08-21.yang -g wheel -p 0660 \
-i infix-interfaces@2023-09-19.yang -g wheel -p 0660 \
@@ -160,8 +157,9 @@ sysrepoctl -s $SEARCH \
-i infix-lldp@2023-08-23.yang -g wheel -p 0660 \
-i infix-dhcp-client@2023-05-22.yang -g wheel -p 0660 \
-i infix-shell-type@2023-08-21.yang -g wheel -p 0660 \
-i infix-system@2023-08-15.yang -g wheel -p 0660 \
-i infix-system@2023-10-19.yang -g wheel -p 0660 \
-i infix-services@2023-10-16.yang -g wheel -p 0660 \
-i ieee802-ethernet-interface@2019-06-21.yang -g wheel -p 0660 \
-I "${INIT_DATA}"
rc=$?
+2 -2
View File
@@ -85,13 +85,13 @@ phys_ifaces=$(ip -d -j link show | jq -r '
select(.link_type == "ether") |
select(.group != "internal") |
select(has("parentbus")) |
.ifname')
.ifname' | sort -V)
ports=$(ip -d -j link show group port | jq -r '
.[] |
select(.link_type == "ether") |
select(.group != "internal") |
select(has("parentbus")) |
.ifname')
.ifname' | sort -V)
ifaces=""
for phy in $phys_ifaces; do
found=""
+12 -6
View File
@@ -15,15 +15,21 @@ if [ "$1" = "-b" ]; then
else
bootstrap=false
fi
config=$1
fn=/cfg/${config}.cfg
if [ -f "$config" ]; then
fn="$config"
else
if [ -f "/cfg/${config}.cfg" ]; then
fn="/cfg/${config}.cfg"
else
fn="/run/confd/${config}.cfg"
fi
fi
if [ ! -f "$fn" ]; then
if [ ! -f "$config" ]; then
logger -sik -p user.error "No such file, $fn, aborting!"
exit 1
fi
fn=$config
logger -sik -p user.error "No such file, $fn, aborting!"
exit 1
fi
if ! sysrepocfg -v3 -I"$fn" -f json; then
+13 -10
View File
@@ -6,15 +6,24 @@ INIT_DATA=/etc/sysrepo/factory-default.json
SEARCH=/usr/share/yang/modules/confd:/usr/share/yang/modules/libnetconf2:/usr/share/yang/modules/libyang:/usr/share/yang/modules/netopeer2:/usr/share/yang/modules/sysrepo
CFG_PATH_=/cfg
RUN_PATH_=/run/confd
# Static defaults, base Infix and any br2-external derivative.
FACTORY_DEFAULTS_D=/usr/share/confd/factory.d
FAILURE_DEFAULTS_D=/usr/share/confd/failure.d
FACTORY_D=$CFG_PATH_/factory.d
FAILURE_D=$CFG_PATH_/failure.d
# Generated config snippets, e.g., hostname, password, and interfaces.
FACTORY_D=$RUN_PATH_/factory.d
FAILURE_D=$RUN_PATH_/failure.d
FACTORY_CFG=$CFG_PATH_/factory-config.cfg
FAILURE_CFG=$CFG_PATH_/failure-config.cfg
# The default config snippets and generated snippets are collated into
# RAM-only name-config.gen , which are candidates for name-config.cfg
FACTORY_GEN=$RUN_PATH_/factory-config.gen
FAILURE_GEN=$RUN_PATH_/failure-config.gen
# The resulting .cfg files can be peristent (factory-config) or not.
FACTORY_CFG=$RUN_PATH_/factory-config.cfg
FAILURE_CFG=$RUN_PATH_/failure-config.cfg
STARTUP_CFG=$CFG_PATH_/startup-config.cfg
# Uncomment this line in to create a bridge (br0) with all (classified
@@ -26,9 +35,3 @@ STARTUP_CFG=$CFG_PATH_/startup-config.cfg
# Default hostname in Fail Secure mode, plus last three octets in the base
# MAC address, e.g. "failed-c0-ff-ee".
FAIL_HOSTNAME="failed"
# Uncomment to regenerate factory-config (except hostkeys) on each boot.
#FACTORY_OVERRIDE=true
# Uncomment to regenerate failure-config (except hostkeys) on each boot.
#FAILURE_OVERRIDE=true
+1
View File
@@ -28,6 +28,7 @@ confd_plugin_la_SOURCES = \
dagger.c dagger.h \
ietf-interfaces.c \
ietf-system.c \
ietf-factory-default.c \
infix-dhcp.c \
infix-services.c \
infix-factory.c \
+3
View File
@@ -116,6 +116,9 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
rc = infix_factory_init(&confd);
if (rc)
goto err;
rc = ietf_factory_default_init(&confd);
if(rc)
goto err;
rc = infix_system_sw_init(&confd);
if (rc)
goto err;
+3
View File
@@ -132,6 +132,9 @@ int ietf_system_init(struct confd *confd);
/* infix-dhcp.c */
int infix_dhcp_init(struct confd *confd);
/* ietf-factory-default */
int ietf_factory_default_init(struct confd *confd);
/* infix-factory.c */
int infix_factory_init(struct confd *confd);
+22
View File
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#include "core.h"
static int factory_reset(sr_session_ctx_t *session, uint32_t sub_id, const char *xpath,
const sr_val_t *input, const size_t input_cnt, sr_event_t event,
unsigned request_id, sr_val_t **output, size_t *output_cnt, void *priv)
{
DEBUG("%s", xpath);
return systemf("factory -y");
}
int ietf_factory_default_init(struct confd *confd)
{
int rc;
REGISTER_RPC(confd->session, "/ietf-factory-default:factory-reset", factory_reset, NULL, &confd->fsub);
return SR_ERR_OK;
fail:
ERROR("failed: %s", sr_strerror(rc));
return rc;
}
+33 -50
View File
@@ -168,43 +168,37 @@ static int ifchange_cand_infer_vlan(sr_session_ctx_t *session, const char *path)
goto out_free_ifname;
err = srx_nitems(session, &cnt,
"%s/ietf-if-extensions:parent-interface", xpath);
"%s/infix-if-vlan:vlan"
"/lower-layer-if", xpath);
if (!err && !cnt) {
inferred.data.string_val = ifname;
err = srx_set_item(session, &inferred, 0,
"%s/ietf-if-extensions:parent-interface", xpath);
"%s/infix-if-vlan:vlan"
"/lower-layer-if", xpath);
if (err)
goto out_free_ifname;
}
err = srx_nitems(session, &cnt,
"%s"
"/ietf-if-extensions:encapsulation"
"/ietf-if-vlan-encapsulation:dot1q-vlan"
"/outer-tag/tag-type", xpath);
"%s/infix-if-vlan:vlan"
"/tag-type", xpath);
if (!err && !cnt) {
inferred.data.string_val = "ieee802-dot1q-types:c-vlan";
err = srx_set_item(session, &inferred, 0,
"%s"
"/ietf-if-extensions:encapsulation"
"/ietf-if-vlan-encapsulation:dot1q-vlan"
"/outer-tag/tag-type", xpath);
"%s/infix-if-vlan:vlan"
"/tag-type", xpath);
if (err)
goto out_free_ifname;
}
err = srx_nitems(session, &cnt,
"%s"
"/ietf-if-extensions:encapsulation"
"/ietf-if-vlan-encapsulation:dot1q-vlan"
"/outer-tag/vlan-id", xpath);
"%s/infix-if-vlan:vlan"
"/id", xpath);
if (!err && !cnt) {
inferred.data.string_val = vidstr;
err = srx_set_item(session, &inferred, 0,
"%s"
"/ietf-if-extensions:encapsulation"
"/ietf-if-vlan-encapsulation:dot1q-vlan"
"/outer-tag/vlan-id", xpath);
"%s/infix-if-vlan:vlan"
"/id", xpath);
if (err)
goto out_free_ifname;
}
@@ -891,38 +885,36 @@ static int netdag_gen_veth(struct dagger *net, struct lyd_node *dif,
static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
struct lyd_node *cif, FILE *ip)
{
const char *parent = lydx_get_cattr(cif, "parent-interface");
const char *ifname = lydx_get_cattr(cif, "name");
struct lydx_diff typed, vidd;
struct lyd_node *otag;
struct lyd_node *vlan;
const char *lower_if;
const char *proto;
int err;
DEBUG("ifname %s parent %s", ifname, parent);
err = dagger_add_dep(net, ifname, parent);
if (err)
return ERR_IFACE(cif, err, "Unable to add dep \"%s\"", parent);
otag = lydx_get_descendant(lyd_child(dif ? : cif),
"encapsulation",
"dot1q-vlan",
"outer-tag",
NULL);
if (!otag) {
vlan = lydx_get_descendant(lyd_child(dif ? : cif), "vlan", NULL);
if (!vlan) {
/*
* Note: this is only an error if outer-tag is missing
* Note: this is only an error if vlan subcontext is missing
* from cif, otherwise it just means the interface had a
* a change that was not related to the VLAN config.
*/
if (!dif)
ERROR("%s: missing mandatory outer-tag", ifname);
ERROR("%s: missing mandatory vlan", ifname);
return 0;
}
lower_if = lydx_get_cattr(vlan, "lower-layer-if");
DEBUG("ifname %s lower if %s\n", ifname, lower_if);
fprintf(ip, "link add dev %s down link %s type vlan", ifname, parent);
err = dagger_add_dep(net, ifname, lower_if);
if (err)
return ERR_IFACE(cif, err, "Unable to add dep \"%s\"", lower_if);
if (lydx_get_diff(lydx_get_child(otag, "tag-type"), &typed)) {
fprintf(ip, "link add dev %s down link %s type vlan", ifname, lower_if);
if (lydx_get_diff(lydx_get_child(vlan, "tag-type"), &typed)) {
proto = bridge_tagtype2str(typed.new);
if (!proto)
return ERR_IFACE(cif, -ENOSYS, "Unsupported tag type \"%s\"", typed.new);
@@ -930,7 +922,7 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
fprintf(ip, " proto %s", proto);
}
if (lydx_get_diff(lydx_get_child(otag, "vlan-id"), &vidd))
if (lydx_get_diff(lydx_get_child(vlan, "id"), &vidd))
fprintf(ip, " id %s", vidd.new);
fputc('\n', ip);
@@ -996,24 +988,15 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
{
const char *iftype = lydx_get_cattr(cif, "type");
if (!strcmp(iftype, "infix-if-type:bridge")) {
if (is_phys_addr_deleted(dif))
return true;
} else if (!strcmp(iftype, "infix-if-type:vlan")) {
if (strcmp(iftype, "infix-if-type:ethernet")) {
if (is_phys_addr_deleted(dif))
return true;
}
if (lydx_get_cattr(dif, "parent-interface") ||
lydx_get_descendant(lyd_child(dif),
"encapsulation",
"dot1q-vlan",
"outer-tag",
NULL))
if (!strcmp(iftype, "infix-if-type:vlan")) {
if (lydx_get_descendant(lyd_child(dif), "vlan", NULL))
return true;
} else if (!strcmp(iftype, "infix-if-type:veth")) {
if (is_phys_addr_deleted(dif))
return true;
if (lydx_get_descendant(lyd_child(dif), "peer", NULL))
return true;
/*
+15 -5
View File
@@ -96,6 +96,7 @@ static char *fmtime(time_t t, char *buf, size_t len)
struct tm tm;
size_t i, n;
tzset();
localtime_r(&t, &tm);
n = strftime(buf, len, isofmt, &tm);
i = n - 5;
@@ -300,6 +301,8 @@ static int change_clock(sr_session_ctx_t *session, uint32_t sub_id, const char *
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
{
char *timezone;
char *tz_utc_offset;
char tz_name[14];
switch (event) {
case SR_EV_ENABLED: /* first time, on register. */
@@ -328,13 +331,20 @@ static int change_clock(sr_session_ctx_t *session, uint32_t sub_id, const char *
default:
return SR_ERR_OK;
}
tz_utc_offset = srx_get_str(session, XPATH_BASE_"/clock/timezone-utc-offset");
timezone = srx_get_str(session, XPATH_BASE_"/clock/timezone-name");
if (!timezone && !tz_utc_offset) {
snprintf(tz_name,sizeof(tz_name),"Etc/UTC");
timezone = tz_name;
}
/* XXX: add support also for /ietf-system:system/clock/timezone-utc-offset (deviation) */
timezone = srx_get_str(session, XPATH_BASE_"/clock/timezone-name");
if (!timezone) {
ERROR("Failed reading timezone-name");
return SR_ERR_VALIDATION_FAILED;
if (tz_utc_offset) {
int8_t offset = atol(tz_utc_offset);
/* When using Etc/GMT offsets, the +/- is inverted in tzdata. */
snprintf(tz_name,sizeof(tz_name), "Etc/GMT%s%.2d", offset>-1?"":"+", -offset);
timezone = tz_name;
}
remove("/etc/localtime+");
@@ -0,0 +1,928 @@
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";
}
}
}
}
}
}
@@ -1,535 +0,0 @@
module ietf-if-extensions {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-if-extensions";
prefix if-ext;
import ietf-yang-types {
prefix yang;
reference "RFC 6991: Common YANG Data Types";
}
import ietf-interfaces {
prefix if;
reference
"RFC 8343: A YANG Data Model For Interface Management";
}
import iana-if-type {
prefix ianaift;
reference "RFC 7224: IANA Interface Type YANG Module";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Editor: Robert Wilton
<mailto:rwilton@cisco.com>";
description
"This module contains common definitions for extending the IETF
interface YANG model (RFC 8343) with common configurable layer 2
properties.
Copyright (c) 2023 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Revised BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX
(https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
for full legal notices.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.";
revision 2023-01-26 {
description
"Initial revision.";
reference
"RFC XXXX, Common Interface Extension YANG Data Models";
}
feature link-flap-suppression {
description
"This feature indicates that configurable interface link
delay is supported, which is a feature is used to limit the
propagation of very short interface link state flaps.";
reference "RFC XXXX, Section 2.1 Link Flap Suppression";
}
feature dampening {
description
"This feature indicates that the device supports interface
dampening, which is a feature that is used to limit the
propagation of interface link state flaps over longer
periods.";
reference "RFC XXXX, Section 2.2 Dampening";
}
feature loopback {
description
"This feature indicates that configurable interface loopback is
supported.";
reference "RFC XXXX, Section 2.4 Loopback";
}
feature max-frame-size {
description
"This feature indicates that the device supports configuring or
reporting the maximum frame size on interfaces.";
reference "RFC XXXX, Section 2.5 Maximum Frame Size";
}
feature sub-interfaces {
description
"This feature indicates that the device supports the
instantiation of sub-interfaces. Sub-interfaces are defined
as logical child interfaces that allow features and forwarding
decisions to be applied to a subset of the traffic processed
on the specified parent interface.";
reference "RFC XXXX, Section 2.6 Sub-interface";
}
/*
* Define common identities to help allow interface types to be
* assigned properties.
*/
identity sub-interface {
description
"Base type for generic sub-interfaces.
New or custom interface types can derive from this type to
inherit generic sub-interface configuration.";
reference "RFC XXXX, Section 2.6 Sub-interface";
}
identity ethSubInterface{
base ianaift:l2vlan;
base sub-interface;
description
"This identity represents the child sub-interface of any
interface types that uses Ethernet framing (with or without
802.1Q tagging).";
}
identity loopback {
description "Base identity for interface loopback options";
reference "RFC XXXX, Section 2.4";
}
identity internal {
base loopback;
description
"All egress traffic on the interface is internally looped back
within the interface to be received on the ingress path.";
reference "RFC XXXX, Section 2.4";
}
identity line {
base loopback;
description
"All ingress traffic received on the interface is internally
looped back within the interface to the egress path.";
reference "RFC XXXX, Section 2.4";
}
identity connector {
base loopback;
description
"The interface has a physical loopback connector attached that
loops all egress traffic back into the interface's ingress
path, with equivalent semantics to loopback internal.";
reference "RFC XXXX, Section 2.4";
}
identity forwarding-mode {
description "Base identity for forwarding-mode options.";
reference "RFC XXXX, Section 2.7";
}
identity physical {
base forwarding-mode;
description
"Physical layer forwarding. This includes DWDM or OTN based
optical switching.";
reference "RFC XXXX, Section 2.7";
}
identity data-link {
base forwarding-mode;
description
"Layer 2 based forwarding, such as Ethernet/VLAN based
switching, or L2VPN services.";
reference "RFC XXXX, Section 2.7";
}
identity network {
base forwarding-mode;
description
"Network layer based forwarding, such as IP, MPLS, or L3VPNs.";
reference "RFC XXXX, Section 2.7";
}
/*
* Augments the IETF interfaces model with leaves to configure
* and monitor link-flap-suppression on an interface.
*/
augment "/if:interfaces/if:interface" {
description
"Augments the IETF interface model with optional common
interface level commands that are not formally covered by any
specific standard.";
/*
* Defines standard YANG for the Link Flap Suppression feature.
*/
container link-flap-suppression {
if-feature "link-flap-suppression";
description
"Holds link flap related feature configuration.";
leaf down {
type uint32;
units milliseconds;
description
"Delays the propagation of a 'loss of carrier signal' event
that would cause the interface state to go down, i.e. the
command allows short link flaps to be suppressed. The
configured value indicates the minimum time interval (in
milliseconds) that the link signal must be continuously
down before the interface state is brought down. If not
configured, the behavior on loss of link signal is
vendor/interface specific, but with the general
expectation that there should be little or no delay.";
}
leaf up {
type uint32;
units milliseconds;
description
"Defines the minimum time interval (in milliseconds) that
the link signal must be continuously present and error
free before the interface state is allowed to transition
from down to up. If not configured, the behavior is
vendor/interface specific, but with the general
expectation that sufficient default delay should be used
to ensure that the interface is stable when enabled before
being reported as being up. Configured values that are
too low for the hardware capabilties may be rejected.";
}
leaf carrier-transitions {
type yang:counter64;
units transitions;
config false;
description
"Defines the number of times the underlying link state
has changed to, or from, state up. This counter should be
incremented even if the high layer interface state changes
are being suppressed by a running link flap suppression
timer.";
}
leaf timer-running {
type enumeration {
enum none {
description
"No link flap suppression timer is running.";
}
enum up {
description
"link-flap-suppression up timer is running. The
underlying link state is up, but interface state is
not reported as up.";
}
enum down {
description
"link-flap-suppression down timer is running.
Interface state is reported as up, but the underlying
link state is actually down.";
}
}
config false;
description
"Reports whether a link flap suppression timer is actively
running, in which case the interface state does not match
the underlying link state.";
}
reference "RFC XXXX, Section 2.1 Link Flap Suppression";
}
/*
* Augments the IETF interfaces model with a container to hold
* generic interface dampening
*/
container dampening {
if-feature "dampening";
presence
"Enable interface link flap dampening with default settings
(that are vendor/device specific).";
description
"Interface dampening limits the propagation of interface link
state flaps over longer periods.";
reference "RFC XXXX, Section 2.2 Dampening";
leaf half-life {
type uint32;
units seconds;
description
"The time (in seconds) after which a penalty would be half
its original value. Once the interface has been assigned
a penalty, the penalty is decreased at a decay rate
equivalent to the half-life. For some devices, the
allowed values may be restricted to particular multiples
of seconds. The default value is vendor/device
specific.";
reference "RFC XXXX, Section 2.3.2 Half-Life Period";
}
leaf reuse {
type uint32;
description
"Penalty value below which a stable interface is
unsuppressed (i.e. brought up) (no units). The default
value is vendor/device specific. The penalty value for a
link up->down state change is 1000 units.";
reference "RFC XXXX, Section 2.2.3 Reuse Threshold";
}
leaf suppress {
type uint32;
description
"Limit at which an interface is suppressed (i.e. held down)
when its penalty exceeds that limit (no units). The value
must be greater than the reuse threshold. The default
value is vendor/device specific. The penalty value for a
link up->down state change is 1000 units.";
reference "RFC XXXX, Section 2.2.1 Suppress Threshold";
}
leaf max-suppress-time {
type uint32;
units seconds;
description
"Maximum time (in seconds) that an interface can be
suppressed before being unsuppressed if no further link
up->down state change penalties have been applied. This
value effectively acts as a ceiling that the penalty value
cannot exceed. The default value is vendor/device
specific.";
reference "RFC XXXX, Section 2.2.4 Maximum Suppress Time";
}
leaf penalty {
type uint32;
config false;
description
"The current penalty value for this interface. When the
penalty value exceeds the 'suppress' leaf then the
interface is suppressed (i.e. held down).";
reference "RFC XXXX, Section 2.2 Dampening";
}
leaf suppressed {
type boolean;
config false;
description
"Represents whether the interface is suppressed (i.e. held
down) because the 'penalty' leaf value exceeds the
'suppress' leaf.";
reference "RFC XXXX, Section 2.2 Dampening";
}
leaf time-remaining {
when '../suppressed = "true"' {
description
"Only suppressed interfaces have a time remaining.";
}
type uint32;
units seconds;
config false;
description
"For a suppressed interface, this leaf represents how long
(in seconds) that the interface will remain suppressed
before it is allowed to go back up again.";
reference "RFC XXXX, Section 2.2 Dampening";
}
}
/*
* Various types of interfaces support a configurable layer 2
* encapsulation, any that are supported by YANG should be
* listed here.
*
* Different encapsulations can hook into the common encaps-type
* choice statement.
*/
container encapsulation {
when
"derived-from-or-self(../if:type,
'ianaift:ethernetCsmacd') or
derived-from-or-self(../if:type,
'ianaift:ieee8023adLag') or
derived-from-or-self(../if:type, 'ianaift:pos') or
derived-from-or-self(../if:type,
'ianaift:atmSubInterface') or
derived-from-or-self(../if:type, 'ianaift:l2vlan') or
derived-from-or-self(../if:type, 'ethSubInterface')" {
description
"All interface types that can have a configurable L2
encapsulation.";
}
description
"Holds the OSI layer 2 encapsulation associated with an
interface.";
choice encaps-type {
description
"Extensible choice of layer 2 encapsulations";
reference "RFC XXXX, Section 2.3 Encapsulation";
}
}
/*
* Various types of interfaces support loopback configuration,
* any that are supported by YANG should be listed here.
*/
leaf loopback {
when "derived-from-or-self(../if:type,
'ianaift:ethernetCsmacd') or
derived-from-or-self(../if:type, 'ianaift:sonet') or
derived-from-or-self(../if:type, 'ianaift:atm') or
derived-from-or-self(../if:type, 'ianaift:otnOtu')" {
description
"All interface types that support loopback configuration.";
}
if-feature "loopback";
type identityref {
base loopback;
}
description "Enables traffic loopback.";
reference "RFC XXXX, Section 2.4 Loopback";
}
/*
* Allows the maximum frame size to be configured or reported.
*/
leaf max-frame-size {
if-feature "max-frame-size";
type uint32 {
range "64 .. max";
}
description
"The maximum size of layer 2 frames that may be transmitted
or received on the interface (including any frame header,
maximum frame payload size, and frame checksum sequence).
If configured, the max-frame-size also limits the maximum
frame size of any child sub-interfaces. The MTU available
to higher layer protocols is restricted to the maximum frame
payload size, and MAY be further restricted by explicit
layer 3 or protocol specific MTU configuration.";
reference "RFC XXXX, Section 2.5 Maximum Frame Size";
}
/*
* Augments the IETF interfaces model with a leaf that indicates
* which mode, or layer, is being used to forward the traffic.
*/
leaf forwarding-mode {
type identityref {
base forwarding-mode;
}
config false;
description
"The forwarding mode that the interface is operating in.";
reference "RFC XXXX, Section 2.7 Forwarding Mode";
}
}
/*
* Add generic support for sub-interfaces.
*
* This should be extended to cover all interface types that are
* child interfaces of other interfaces.
*/
augment "/if:interfaces/if:interface" {
when "derived-from(if:type, 'sub-interface') or
derived-from-or-self(if:type, 'ianaift:l2vlan') or
derived-from-or-self(if:type, 'ianaift:atmSubInterface') or
derived-from-or-self(if:type, 'ianaift:frameRelay')" {
description
"Any ianaift:types that explicitly represent sub-interfaces
or any types that derive from the sub-interface identity.";
}
if-feature "sub-interfaces";
description
"Adds a parent interface field to interfaces that model
sub-interfaces.";
leaf parent-interface {
type if:interface-ref;
mandatory true;
description
"This is the reference to the parent interface of this
sub-interface.";
reference "RFC XXXX, Section 2.6 Sub-interface";
}
}
/*
* Add discard counter for unknown sub-interface encapsulation
*/
augment "/if:interfaces/if:interface/if:statistics" {
when "derived-from-or-self(../if:type,
'ianaift:ethernetCsmacd') or
derived-from-or-self(../if:type,
'ianaift:ieee8023adLag') or
derived-from-or-self(../if:type, 'ianaift:ifPwType')" {
description
"Applies to interfaces that can demultiplex ingress frames to
sub-interfaces.";
}
if-feature "sub-interfaces";
description
"Augment the interface model statistics with a sub-interface
demux discard counter.";
leaf in-discard-unknown-encaps {
type yang:counter64;
units frames;
description
"A count of the number of frames that were well formed, but
otherwise discarded because their encapsulation does not
classify the frame to the interface or any child
sub-interface. E.g., a frame might be discarded because the
it has an unknown VLAN Id, or does not have a VLAN Id when
one is expected.
For consistency, frames counted against this counter are
also counted against the IETF interfaces statistics. In
particular, they are included in in-octets and in-discards,
but are not included in in-unicast-pkts, in-multicast-pkts
or in-broadcast-pkts, because they are not delivered to a
higher layer.
Discontinuities in the values of this counter can occur at
re-initialization of the management system, and at other
times as indicated by the value of the 'discontinuity-time'
leaf defined in the ietf-interfaces YANG module
(RFC 8343).";
}
}
}
@@ -1,155 +0,0 @@
module ietf-if-vlan-encapsulation {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-if-vlan-encapsulation";
prefix if-vlan;
import ietf-interfaces {
prefix if;
reference
"RFC 8343: A YANG Data Model For Interface Management";
}
import iana-if-type {
prefix ianaift;
reference
"RFC 7224: IANA Interface Type YANG Module";
}
import ieee802-dot1q-types {
prefix dot1q-types;
revision-date 2022-10-29;
reference
"IEEE Std 802.1Q-2022: IEEE Standard for Local and
metropolitan area networks -- Bridges and Bridged Networks";
}
import ietf-if-extensions {
prefix if-ext;
reference
"RFC XXXX: Common Interface Extension YANG Data Models";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Editor: Robert Wilton
<mailto:rwilton@cisco.com>";
description
"This YANG module models configuration to classify IEEE 802.1Q
VLAN tagged Ethernet traffic by exactly matching the tag type
and VLAN identifier of one or two 802.1Q VLAN tags in the frame.
Copyright (c) 2023 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Revised BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX
(https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
for full legal notices.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.";
revision 2023-01-26 {
description
"Latest draft revision";
reference
"RFC XXXX: Sub-interface VLAN YANG Data Models";
}
augment "/if:interfaces/if:interface/if-ext:encapsulation/"
+ "if-ext:encaps-type" {
when "derived-from-or-self(../if:type,
'ianaift:ethernetCsmacd') or
derived-from-or-self(../if:type,
'ianaift:ieee8023adLag') or
derived-from-or-self(../if:type, 'ianaift:l2vlan') or
derived-from-or-self(../if:type,
'if-ext:ethSubInterface')" {
description
"Applies only to Ethernet-like interfaces and
sub-interfaces.";
}
description
"Augment the generic interface encapsulation with basic 802.1Q
VLAN tag classifications";
case dot1q-vlan {
container dot1q-vlan {
description
"Classifies 802.1Q VLAN tagged Ethernet frames to a
sub-interface (or interface) by exactly matching the
number of tags, tag type(s) and VLAN identifier(s).
Only frames matching the classification configured on a
sub-interface/interface are processed on that
sub-interface/interface.
Frames that do not match any sub-interface are processed
directly on the parent interface, if it is associated with
a forwarding instance, otherwise they are dropped.";
container outer-tag {
must 'tag-type = "dot1q-types:s-vlan" or '
+ 'tag-type = "dot1q-types:c-vlan"' {
error-message
"Only C-VLAN and S-VLAN tags can be matched.";
description
"For IEEE 802.1Q interoperability, only C-VLAN and
S-VLAN tags are matched.";
}
description
"Specifies the VLAN tag values to match against the
outermost (first) 802.1Q VLAN tag in the frame.";
uses dot1q-types:dot1q-tag-classifier-grouping;
}
container second-tag {
must '../outer-tag/tag-type = "dot1q-types:s-vlan" and '
+ 'tag-type = "dot1q-types:c-vlan"' {
error-message
"When matching two 802.1Q VLAN tags, the outermost
(first) tag in the frame MUST be specified and be of
S-VLAN type and the second tag in the frame must be of
C-VLAN tag type.";
description
"For IEEE 802.1Q interoperability, when matching two
802.1Q VLAN tags, it is REQUIRED that the outermost
tag exists and is an S-VLAN, and the second tag is a
C-VLAN.";
}
presence "Classify frames that have two 802.1Q VLAN tags.";
description
"Specifies the VLAN tag values to match against the
second outermost 802.1Q VLAN tag in the frame.";
uses dot1q-types:dot1q-tag-classifier-grouping;
}
}
}
}
}
@@ -0,0 +1,49 @@
submodule infix-if-vlan {
yang-version 1.1;
belongs-to infix-interfaces {
prefix infix-if;
}
import ietf-interfaces {
prefix if;
}
import infix-if-type {
prefix infixift;
}
import ieee802-dot1q-types {
prefix dot1q-types;
}
contact "kernelkit@googlegroups.com";
description
"This module implements VLAN (8021q) encapsulation";
revision 2023-10-25 {
description "Initial revision";
}
augment "/if:interfaces/if:interface" {
when "derived-from-or-self(if:type, 'infixift:vlan')" {
description "Only shown for if:type vlan";
}
description "Augment to add 802.1Q VLAN tag classifications";
container vlan {
description "Configure 802.1q/802.1ad VLANs";
leaf tag-type {
type dot1q-types:dot1q-tag-type;
default dot1q-types:c-vlan;
description "VLAN type";
}
leaf id {
type dot1q-types:vlanid;
mandatory true;
description "VLAN Id";
}
leaf lower-layer-if {
type if:interface-ref;
mandatory true;
description "Base interface for VLAN";
}
}
}
}
@@ -13,6 +13,7 @@ module infix-interfaces {
include infix-if-base;
include infix-if-bridge;
include infix-if-veth;
include infix-if-vlan;
organization "KernelKit";
contact "kernelkit@googlegroups.com";
@@ -19,6 +19,13 @@ module infix-system {
contact "kernelkit@googlegroups.com";
description "Infix augments and deviations to ietf-system.";
revision 2023-10-19 {
description "Change deviation for timezone-utc-offset from unsupported to Etc+/-HOUR
- Unit is set to hours (tzdata compatibility)
- Range is -12 .. 14";
reference "internal";
}
revision 2023-08-15 {
description "Add support for user login shell.
@@ -76,8 +83,14 @@ module infix-system {
}
}
deviation "/sys:system/sys:clock/sys:timezone/sys:timezone-utc-offset" {
deviate not-supported;
deviation "/sys:system/sys:clock/sys:timezone/sys:timezone-utc-offset/sys:timezone-utc-offset" {
description "Timezone UTC offset should be set in hours, not minutes";
deviate replace {
type int16 {
range "-12 .. 14";
}
units "hours";
}
}
deviation "/sys:system/sys:radius" {
+5
View File
@@ -305,6 +305,11 @@
<ACTION sym="script">jq -C . /cfg/startup-config.cfg</ACTION>
</COMMAND>
</COMMAND>
<COMMAND name="factory-reset" help="Restore the system to factory state">
<ACTION sym="script" interactive="true">/bin/yorn "This will restore the device to factory state"</ACTION>
<ACTION sym="rpc@infix">/ietf-factory-default:factory-reset</ACTION>
</COMMAND>
<COMMAND name="follow" help="Monitor a log file, use Ctrl-C to abort">
<PARAM name="fn" ptype="/LOGFILES" help="Optional log file to monitor, default: syslog"/>
+2 -1
View File
@@ -4,7 +4,8 @@ LDLIBS += -lsysrepo -lev -lyang -ljansson -lite -lsrx
TARGET = statd
SRC = statd.c shared.c shared.h \
iface-ip-link.c iface-ip-link.h \
iface-ip-addr.c iface-ip-addr.h
iface-ip-addr.c iface-ip-addr.h \
iface-ethtool.c iface-ethtool.h
all: $(TARGET)
+204
View File
@@ -0,0 +1,204 @@
#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>
#include <srx/lyx.h>
#include <srx/common.h>
#include <srx/helpers.h>
#include "shared.h"
static json_t *json_get_ethtool(const char *ifname)
{
char cmd[512] = {}; /* Size is arbitrary */
snprintf(cmd, sizeof(cmd), "ethtool --json -S %s --all-groups 2>/dev/null", ifname);
return json_get_output(cmd);
}
/* We print errors here, but don't return them */
static void ly_add_lld(const struct ly_ctx *ctx, struct lyd_node *node, char *xpath,
json_t *json, const char *yang, const char *ethtool)
{
json_t *j_val;
int err;
j_val = json_object_get(json, ethtool);
if (!j_val)
return;
if (!json_is_integer(j_val)) {
ERROR("Error, expecting integer value for '%s'\n", ethtool);
return;
}
err = lydx_new_path(ctx, &node, xpath, (char *)yang, "%lld",
json_integer_value(j_val));
if (err)
ERROR("Error, adding ethtool '%s' to data tree, libyang error %d", yang, err);
}
static uint64_t json_get_lld(json_t *json, int *found, const char *name)
{
json_t *j_val;
j_val = json_object_get(json, name);
if (!j_val)
return 0;
if (!json_is_integer(j_val)) {
ERROR("Error, expecting integer value for '%s'\n", name);
return 0;
}
(*found)++;
return json_integer_value(j_val);
}
static void ly_add_in_tot_frames(const struct ly_ctx *ctx, struct lyd_node *node,
char *xpath, json_t *j_mac, json_t *j_rmon)
{
char *yang = "in-total-frames";
long long int tot = 0;
int found = 0;
int err;
tot += json_get_lld(j_mac, &found, "FramesReceivedOK");
tot += json_get_lld(j_mac, &found, "FrameCheckSequenceErrors");
tot += json_get_lld(j_mac, &found, "FramesLostDueToIntMACRcvError");
tot += json_get_lld(j_mac, &found, "AlignmentErrors");
tot += json_get_lld(j_rmon, &found, "etherStatsOversizePkts");
tot += json_get_lld(j_rmon, &found, "etherStatsJabbers");
/* Don't add 0 counters for missing data (missing != 0) */
if (!found)
return;
err = lydx_new_path(ctx, &node, xpath, yang, "%lld", tot);
if (err)
ERROR("Error, adding ethtool '%s', libyang error %d", yang, err);
}
static void ly_add_in_err_oz_frames(const struct ly_ctx *ctx, struct lyd_node *node,
char *xpath, json_t *j_rmon)
{
char *yang = "in-error-oversize-frames";
long long int tot = 0;
int found = 0;
int err;
tot += json_get_lld(j_rmon, &found, "etherStatsOversizePkts");
tot += json_get_lld(j_rmon, &found, "etherStatsJabbers");
/* Don't add 0 counters for missing data (missing != 0) */
if (!found)
return;
err = lydx_new_path(ctx, &node, xpath, yang, "%lld", tot);
if (err)
ERROR("Error, adding ethtool '%s', libyang error %d", yang, err);
}
static int ly_add_eth_stats(const struct ly_ctx *ctx, struct lyd_node **parent,
const char *ifname, json_t *j_iface)
{
char xpath_base[XPATH_BASE_MAX] = {};
char xpath[XPATH_MAX] = {};
struct lyd_node *frame = NULL;
struct lyd_node *stat = NULL;
struct lyd_node *eth = NULL;
json_t *j_mac;
json_t *j_rmon;
int err;
j_mac = json_object_get(j_iface, "eth-mac");
if (!j_mac)
return SR_ERR_OK;
j_rmon = json_object_get(j_iface, "rmon");
if (!j_rmon)
return SR_ERR_OK;
snprintf(xpath_base, sizeof(xpath_base),
"%s/interface[name='%s']/ieee802-ethernet-interface:ethernet",
XPATH_IFACE_BASE, ifname);
err = lyd_new_path(*parent, ctx, xpath_base, NULL, 0, &eth);
if (err) {
ERROR("Failed adding 'eth' node (%s), libyang error %d: %s",
xpath_base, err, ly_errmsg(ctx));
return SR_ERR_LY;
}
snprintf(xpath, sizeof(xpath), "%s/statistics", xpath_base);
err = lyd_new_path(eth, ctx, xpath, NULL, 0, &stat);
if (err) {
ERROR("Failed adding 'stat' node (%s), libyang error %d: %s",
xpath, err, ly_errmsg(ctx));
return SR_ERR_LY;
}
snprintf(xpath, sizeof(xpath), "%s/statistics/frame", xpath_base);
err = lyd_new_path(stat, ctx, xpath, NULL, 0, &frame);
if (err) {
ERROR("Failed adding 'frame' node (%s), libyang error %d: %s",
xpath, err, ly_errmsg(ctx));
return SR_ERR_LY;
}
ly_add_lld(ctx, frame, xpath, j_mac, "out-frames", "FramesTransmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "out-multicast-frames", "MulticastFramesXmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "out-broadcast-frames", "BroadcastFramesXmittedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-frames", "FramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-multicast-frames", "MulticastFramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-broadcast-frames", "BroadcastFramesReceivedOK");
ly_add_lld(ctx, frame, xpath, j_mac, "in-error-fcs-frames", "FrameCheckSequenceErrors");
ly_add_lld(ctx, frame, xpath, j_mac, "in-error-undersize-frames", "undersize_pkts");
ly_add_lld(ctx, frame, xpath, j_mac, "in-error-mac-internal-frames",
"FramesLostDueToIntMACRcvError");
ly_add_in_tot_frames(ctx, frame, xpath, j_mac, j_rmon);
ly_add_in_err_oz_frames(ctx, frame, xpath, j_rmon);
return SR_ERR_OK;
}
int ly_add_ethtool(const struct ly_ctx *ctx, struct lyd_node **parent, char *ifname)
{
json_t *j_iface;
json_t *j_root;
int err;
j_root = json_get_ethtool(ifname);
if (!j_root) {
ERROR("Error, parsing ethtool JSON");
return SR_ERR_SYS;
}
if (json_array_size(j_root) != 1) {
ERROR("Error, expected JSON array of single iface");
json_decref(j_root);
return SR_ERR_SYS;
}
j_iface = json_array_get(j_root, 0);
if (!j_iface) {
ERROR("Error, getting JSON interface");
json_decref(j_root);
return SR_ERR_SYS;
}
err = ly_add_eth_stats(ctx, parent, ifname, j_iface);
if (err) {
ERROR("Error, adding ethtool statistics data");
json_decref(j_root);
return err;
}
json_decref(j_root);
return SR_ERR_OK;
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef STATD_IFACE_ETHTOOL_H_
#define STATD_IFACE_ETHTOOL_H_
#include <srx/lyx.h>
int ly_add_ethtool(const struct ly_ctx *ctx, struct lyd_node **parent, char *ifname);
#endif
+112 -14
View File
@@ -81,6 +81,8 @@ static const char *get_yang_link_type(char *xpath, json_t *iface)
return "infix-if-type:vlan";
if (strcmp(kind, "bridge") == 0)
return "infix-if-type:bridge";
if (strcmp(kind, "dsa") == 0)
return "infix-if-type:ethernet";
/**
* We could return ethernetCsmacd here, but it might hide some
@@ -226,6 +228,77 @@ static int ly_add_ip_link_br(const struct ly_ctx *ctx, struct lyd_node **parent,
return SR_ERR_OK;
}
static int ip_link_kind_is_dsa(json_t *j_iface)
{
json_t *j_linkinfo;
json_t *j_val;
j_linkinfo = json_object_get(j_iface, "linkinfo");
if (!j_linkinfo)
return 0;
j_val = json_object_get(j_linkinfo, "info_kind");
if (!j_val)
return 0;
if (!json_is_string(j_val))
return 0;
if (strcmp("dsa", json_string_value(j_val)) != 0)
return 0;
/* This interface has linkinfo -> info_kind = "dsa" */
return 1;
}
static int ly_add_ip_link_parent(const struct ly_ctx *ctx, struct lyd_node **parent,
char *xpath, json_t *j_iface)
{
struct lyd_node *vlan_node;
char *vlan_xpath;
json_t *j_val;
int err;
j_val = json_object_get(j_iface, "link");
if (!j_val) {
/* Interface has no parent */
return SR_ERR_OK;
}
if (ip_link_kind_is_dsa(j_iface)) {
/* Skip adding parent interface data for dsa child */
return SR_ERR_OK;
}
if (!json_is_string(j_val)) {
ERROR("Expected a JSON string for 'link'");
return SR_ERR_SYS;
}
err = asprintf(&vlan_xpath, "%s/infix-interfaces:vlan", xpath);
if (err == -1) {
ERROR("Error, creating vlan xpath");
return SR_ERR_SYS;
}
err = lyd_new_path(*parent, ctx, vlan_xpath, NULL, 0, &vlan_node);
if (err) {
ERROR("Failed adding 'lower-layer-if' node (%s), libyang error %d: %s",
vlan_xpath, err, ly_errmsg(ctx));
free(vlan_xpath);
return SR_ERR_LY;
}
err = lydx_new_path(ctx, &vlan_node, vlan_xpath, "lower-layer-if",
"%s", json_string_value(j_val));
if (err) {
ERROR("Error, adding 'lower-layer-if' to data tree, libyang error %d", err);
free(vlan_xpath);
return SR_ERR_LY;
}
free(vlan_xpath);
return SR_ERR_OK;
}
static int ly_add_ip_link_data(const struct ly_ctx *ctx, struct lyd_node **parent,
char *xpath, json_t *j_iface)
{
@@ -291,20 +364,10 @@ static int ly_add_ip_link_data(const struct ly_ctx *ctx, struct lyd_node **paren
return err;
}
j_val = json_object_get(j_iface, "link");
if (j_val) {
if (!json_is_string(j_val)) {
ERROR("Expected a JSON string for 'link'");
return SR_ERR_SYS;
}
err = lydx_new_path(ctx, parent, xpath,
"ietf-if-extensions:parent-interface", "%s",
json_string_value(j_val));
if (err) {
ERROR("Error, adding 'link' to data tree, libyang error %d", err);
return SR_ERR_LY;
}
err = ly_add_ip_link_parent(ctx, parent, xpath, j_iface);
if (err) {
ERROR("Error, adding parent iface to data tree, libyang error %d", err);
return err;
}
return SR_ERR_OK;
@@ -345,3 +408,38 @@ int ly_add_ip_link(const struct ly_ctx *ctx, struct lyd_node **parent, char *ifn
return SR_ERR_OK;
}
/* Returns 1 if the group is "group", 0 if it's not and -1 on error */
int ip_link_check_group(char *ifname, const char *group)
{
json_t *j_iface;
json_t *j_root;
json_t *j_val;
j_root = json_get_ip_link(ifname);
if (!j_root) {
ERROR("Error, parsing ip-link JSON");
return -1;
}
if (json_array_size(j_root) != 1) {
ERROR("Error, expected JSON array of single iface");
json_decref(j_root);
return -1;
}
j_iface = json_array_get(j_root, 0);
j_val = json_object_get(j_iface, "group");
if (!json_is_string(j_val)) {
ERROR("Error, expected a JSON string for 'group'");
json_decref(j_root);
return -1;
}
if (strcmp(json_string_value(j_val), group) == 0) {
json_decref(j_root);
return 1;
}
json_decref(j_root);
return 0;
}
+1
View File
@@ -3,6 +3,7 @@
#include <srx/lyx.h>
int ip_link_check_group(char *ifname, const char *group);
int ly_add_ip_link(const struct ly_ctx *ctx, struct lyd_node **parent, char *ifname);
#endif
+2 -8
View File
@@ -13,20 +13,14 @@ json_t *json_get_output(const char *cmd)
proc = popenf("re", cmd);
if (!proc) {
ERROR("Error, running ip link command");
ERROR("Error, running command %s", cmd);
return NULL;
}
j_root = json_loadf(proc, 0, &j_err);
pclose(proc);
if (!j_root) {
ERROR("Error, parsing ip link JSON");
return NULL;
}
if (!json_is_array(j_root)) {
ERROR("Expected a JSON array from ip link");
json_decref(j_root);
ERROR("Error, parsing command JSON (%s)", cmd);
return NULL;
}
+1
View File
@@ -4,6 +4,7 @@
#include <jansson.h>
#define XPATH_MAX PATH_MAX
#define XPATH_BASE_MAX 2046 /* Size is arbitrary */
#define XPATH_IFACE_BASE "/ietf-interfaces:interfaces"
json_t *json_get_output(const char *cmd);
+18 -3
View File
@@ -25,6 +25,7 @@
#include "shared.h"
#include "iface-ip-link.h"
#include "iface-ip-addr.h"
#include "iface-ethtool.h"
#define SOCK_RMEM_SIZE 1000000 /* Arbitrary chosen, default = 212992 */
#define NL_BUF_SIZE 4096 /* Arbitrary chosen */
@@ -139,14 +140,28 @@ static int sr_ifaces_cb(sr_session_ctx_t *session, uint32_t, const char *path,
return SR_ERR_INTERNAL;
}
/* Skip internal interfaces (such as dsa0) */
if (ip_link_check_group(sub->ifname, "internal") == 1) {
err = SR_ERR_OK;
goto out;
}
err = ly_add_ip_link(ctx, parent, sub->ifname);
if (err)
if (err) {
ERROR("Error, adding ip link info");
goto out;
}
err = ly_add_ip_addr(ctx, parent, sub->ifname);
if (err)
ERROR("Error, adding ip link info");
if (err) {
ERROR("Error, adding ip addr info");
goto out;
}
err = ly_add_ethtool(ctx, parent, sub->ifname);
if (err)
ERROR("Error, adding ethtool info");
out:
sr_release_context(con);
return err;
+23
View File
@@ -189,6 +189,29 @@
]
}
},
{
"TEST-DESCR": "Interface ieee802-ethernet-interface stats",
"name": "e13",
"type": "infix-if-type:ethernet",
"oper-status": "up",
"if-index": 4,
"phys-address": "02:ee:00:00:12:00",
"statistics": {
"in-octets": "11",
"out-octets": "22"
},
"ieee802-ethernet-interface:ethernet": {
"statistics": {
"frame": {
"in-frames": "1111",
"out-frames": "2222"
}
}
},
"ietf-ip:ipv4": {
"mtu": 1500
}
},
{
"TEST-DESCR": "Interface with VLAN on top",
"name": "e20",
+3 -8
View File
@@ -21,14 +21,9 @@ with infamy.Test() as test:
{
"name": f"{tport}.10",
"type": "infix-if-type:vlan",
"parent-interface": tport,
"encapsulation": {
"dot1q-vlan": {
"outer-tag": {
"tag-type": "ieee802-dot1q-types:c-vlan",
"vlan-id": 10,
}
}
"vlan": {
"id": 10,
"lower-layer-if": tport,
},
"ipv4": {
+2
View File
@@ -1,3 +1,5 @@
---
- case: hostname.py
- case: add_delete_user.py
- case: timezone.py
- case: timezone_utc_offset.py
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
import random, string
import time
import infamy
import lxml
with infamy.Test() as test:
with test.step("Initialize"):
env = infamy.Env(infamy.std_topology("1x1"))
target = env.attach("target", "mgmt")
with test.step("Set timezone"):
target.put_config_dict("ietf-system", {
"system": {
"clock": {
"timezone-name": "Australia/Perth" # always +8:00, no DTS
}
}
})
with test.step("Verify current time."):
root = target.get_dict("/ietf-system:system-state/clock",as_xml=True)
current_datetime = root.find('.//{urn:ietf:params:xml:ns:yang:ietf-system}current-datetime').text
offset=current_datetime[-6:]
assert(offset == "+08:00")
test.succeed()
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python3
import infamy
import lxml
with infamy.Test() as test:
with test.step("Initialize"):
env = infamy.Env(infamy.std_topology("1x1"))
target = env.attach("target", "mgmt")
with test.step("Set timezone UTC offset"):
target.put_config_dict("ietf-system", {
"system": {
"clock": {
"timezone-utc-offset": "12"
}
}
})
with test.step("Verify current time."):
root = target.get_dict("/ietf-system:system-state/clock",as_xml=True)
current_datetime = root.find('.//{urn:ietf:params:xml:ns:yang:ietf-system}current-datetime').text
offset=current_datetime[-6:]
assert(offset == "+12:00")
test.succeed()
+3 -8
View File
@@ -41,14 +41,9 @@ with infamy.Test() as test:
"name": "vlan10",
"type": "infix-if-type:vlan",
"enabled": True,
"parent-interface": "br0",
"encapsulation": {
"dot1q-vlan": {
"outer-tag": {
"tag-type": "ieee802-dot1q-types:c-vlan",
"vlan-id": 10,
}
}
"vlan": {
"lower-layer-if": "br0",
"id": 10,
},
"ipv4": {
"address": [
+26 -14
View File
@@ -147,7 +147,7 @@ class Device(object):
pieces.append("</get-data>")
return self._ncc_make_rpc("".join(pieces), msg_id=msg_id)
def _get(self, xpath, getter):
def _get(self, xpath, getter, as_xml=False):
# Figure out which modules we are referencing
mods = self._modules_in_xpath(xpath)
@@ -155,30 +155,42 @@ class Device(object):
xmlns = " ".join([f"xmlns:{m['name']}=\"{m['namespace']}\"" for m in mods])
filt = f"<filter type=\"xpath\" select=\"{xpath}\" {xmlns} />"
# pylint: disable=c-extension-no-member
cfg = lxml.etree.tostring(getter(filter=filt).data_ele[0])
data=getter(filter=filt).data_ele[0]
if as_xml:
return data
else:
cfg = lxml.etree.tostring(data)
return self.ly.parse_data_mem(cfg, "xml", parse_only=True)
return self.ly.parse_data_mem(cfg, "xml", parse_only=True)
def _get_data(self, xpath):
def _get_data(self, xpath,as_xml=False):
"""Local member wrapper for netconf-client <get-data> RPC"""
# pylint: disable=protected-access
(raw, ele) = self.ncc._send_rpc(self._ncc_get_data_rpc(filter=xpath))
data = NccGetDataReply(raw, ele)
# pylint: disable=c-extension-no-member
cfg = lxml.etree.tostring(data.data_ele[0])
return self.ly.parse_data_mem(cfg, "xml", parse_only=True)
if(as_xml):
return data
else:
# pylint: disable=c-extension-no-member
cfg = lxml.etree.tostring(data.data_ele[0])
return self.ly.parse_data_mem(cfg, "xml", parse_only=True)
def get(self, xpath):
def get(self, xpath, as_xml=False):
"""RPC <get> (legacy NETCONF) fetches config:false data"""
return self._get(xpath, self.ncc.get)
return self._get(xpath, self.ncc.get, as_xml)
def get_dict(self, xpath):
def get_dict(self, xpath,as_xml=False):
"""Return Python dictionary of <get> RPC data"""
return self.get(xpath).print_dict()
if(as_xml):
return self.get(xpath, as_xml=True)
else:
return self.get(xpath).print_dict()
def get_data(self, xpath):
def get_data(self, xpath, as_xml=False):
"""RPC <get-data> to fetch operational data"""
return self._get_data(xpath).print_dict()
if(as_xml):
return self._get_data(xpath,as_xml)
else:
return self._get_data(xpath).print_dict()
def get_config(self, xpath):
return self._get(xpath, self.ncc.get_config)