Compare commits

..
16 Commits
Author SHA1 Message Date
Joachim Wiberg a4d4d7e4ae doc: update release date for v24.09
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-30 10:30:25 +02:00
Tobias WaldekranzandGitHub 1adace8acb Merge pull request #664 from kernelkit/styx-rename
board/aarch64: styx: Update board name
2024-09-30 10:24:06 +02:00
Tobias Waldekranz 059e22c85f board/aarch64: styx: Update board name
Now that the name question has been settled, call the board by its
proper name. Provide symlinks to keep older bootloaders happy.
2024-09-30 09:28:08 +02:00
Joachim WibergandGitHub 58edaf371c Merge pull request #657 from addiva-elektronik/verify_all_interface_types 2024-09-28 09:11:41 +02:00
Ahmed Karic d2ff58a170 test: add a test to verify all interfaces
The test ensures that all interface types can be successfully created
and retrieved from the operational datastore. It also functions as a
regression test for issue #618 and will apply to all future interface
variants.

Fixes #622
2024-09-27 17:53:48 +02:00
Joachim WibergandGitHub 40e4b168ff Merge pull request #661 from kernelkit/veth-delete
Fix test issues after adding veth-delete test

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 17:40:30 +02:00
Joachim Wiberg bac957d1bf cli: minor, fix tcpdump permissions from exec as admin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 16:55:24 +02:00
Joachim Wiberg 015946219b confd: fix possible NULL ptr deref
Introduced in 35eeae55.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 16:43:42 +02:00
Joachim Wiberg 6521de28e7 confd: check for control-plane-protocol before migration
Refactor 0f9d429 to first check if the .cfg file has any routing
protocol active before converting the type's value.

This fixes a regression in the release cycle that otherwise would
cause a fresh startup-config, created from a plain factory-config
from v24.08, to be converted to an empty file.

Inspired by this fix, the same mitigation, albeit highyl unlikely,
has been applied to the v1.0 user shell type migration.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 16:37:16 +02:00
Joachim Wiberg c0a79c3e00 test: return None instead of 404 Exception for missing XPaths
Fixes to following exception calling iface.interface_exist(target, veth0): requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://[fe80::2a0:85ff:fe00:201%d2a]:443/restconf/ds/ietf-datastores%3Aoperational/ietf-interfaces%3Ainterfaces/interface=veth0a/name

Removing interface veth0a, and then checking operational if it has been
properly removed, should not cause an exception.  Better to return None
object instead.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 16:37:16 +02:00
Joachim Wiberg acb844336f doc: update ChangeLog
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 13:22:38 +02:00
Joachim Wiberg c8437f040a test: verify VETH pairs can be removed
Verify a VETH pair can be removed after a couple of dummy operations to
step the dagger generation past the initial where the pair is created.

NOTE: Infamy currenly lacks support for removing chunks of configuraion
      e.g., a dut.del_config_dict(), or similar, and delete_xpath() is
      not valid for configurations with dependencies like VETH pairs.

Issue #658

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 13:08:26 +02:00
Joachim Wiberg 54a046afb4 test: check if JSON data before searching it
Fix None.get() value assertion for missing data.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 13:02:59 +02:00
Joachim Wiberg 35eeae55f4 confd: skip veth peer also when deleting interfaces
When adding interfaces over NETCONF/RESTCONF, confd has a check to
ensure the peer end is skipped, since creating one end also create
the other.

This patch adds the corresponding skip when deleting a VETH pair.

Fixes #658

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 13:00:02 +02:00
Joachim Wiberg a06436a8c8 .github: fix missing arch + version in legal-info tarball
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 08:44:36 +02:00
Joachim Wiberg ecc1e24ba9 board/common: bundle helpful README in release tarballs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-27 07:54:45 +02:00
28 changed files with 643 additions and 37 deletions
+2 -2
View File
@@ -87,8 +87,8 @@ jobs:
ln -s ${{ steps.vars.outputs.dir }} images
tar chfz ${{ steps.vars.outputs.tgz }} ${{ steps.vars.outputs.dir }}
mv legal-info legal-info-$target
tar chfz legal-info-$target.tar.gz legal-info-$target
mv legal-info legal-info-${{ matrix.target }}-${{ steps.vars.outputs.ver }}
tar chfz legal-info-${{ matrix.target }}-${{ steps.vars.outputs.ver }}.tar.gz legal-info-${{ matrix.target }}-${{ steps.vars.outputs.ver }}
- uses: actions/upload-artifact@v4
with:
@@ -3,14 +3,13 @@
* Copyright (C) 2021 Marvell International Ltd.
* Copyright (C) 2024 Addiva Elektronik AB
*
* Device tree for Styx board
.*/
* Device tree for revision A of DCP-SC-28P
*/
#include "styx.dtsi"
#include "dcp-sc-28p.dtsi"
/ {
model = "Styx (rev A)";
compatible = "styx,styx-a",
"styx,styx",
compatible = "styx,dcp-sc-28p-a",
"styx,dcp-sc-28p",
"marvell,armada-ap807-quad",
"marvell,armada-ap807";
};
@@ -3,13 +3,13 @@
* Copyright (C) 2021 Marvell International Ltd.
* Copyright (C) 2024 Addiva Elektronik AB
*
* Device tree for Styx board
* Device tree for revision B of DCP-SC-28P
*/
#include "styx.dtsi"
#include "dcp-sc-28p.dtsi"
/ {
model = "Styx";
compatible = "styx,styx-b",
compatible = "styx,dcp-sc-28p-b",
"styx,dcp-sc-28p",
"marvell,armada-ap807-quad",
"marvell,armada-ap807";
};
@@ -1,5 +1,5 @@
#ifndef _STYX_MPP_H
#define _STYX_MPP_H
#ifndef _DCP_SC_28P_MPP_H
#define _DCP_SC_28P_MPP_H
#define SFP0_TX_DISABLE(X) X( "mpp0", cp0_gpio1, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
#define SFP1_TX_DISABLE(X) X( "mpp1", cp0_gpio1, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)
@@ -73,4 +73,4 @@
#define MPP_GPIO_REF_NO_CHIP(_mpp, _chip, _no, _flags) <_no (_flags)>
#define MPP_IRQ_REF(_mpp, _chip, _no, _flags) <&_chip _no (_flags)>
#endif /* _STYX_MPP_H */
#endif /* _DCP_SC_28P_MPP_H */
@@ -3,7 +3,7 @@
* Copyright (C) 2021 Marvell International Ltd.
* Copyright (C) 2023 Addiva Elektronik AB
*
* Device tree for Styx board
* Device tree base for DCP-SC-28P
*/
#include <dt-bindings/input/input.h>
@@ -12,13 +12,10 @@
#include "../marvell/cn9130-patched.dtsi"
#include "styx-mpp.h"
#include "dcp-sc-28p-mpp.h"
/ {
model = "Styx";
compatible = "styx,styx",
"marvell,armada-ap807-quad",
"marvell,armada-ap807";
model = "DCP-SC-28P";
chosen {
stdout-path = "serial0:115200n8";
+1
View File
@@ -0,0 +1 @@
dcp-sc-28p-b.dtb
+1 -1
View File
@@ -1 +1 @@
styx-a.dtb
dcp-sc-28p-a.dtb
+130
View File
@@ -0,0 +1,130 @@
Welcome to Infix!
=================
Nice to meet ❤️ you! If you are reading this then you have possibly
just downloaded and unpacked a release build and are curious about how
to proceed from here.
To test Infix You need a Linux 🐧 system with Qemu or GNS3 installed.
We recommend Debian based systems, like Ubuntu and Linux Mint.
> For a pain-free experience we recommend enabling CPU virtualization in
> your BIOS/UEFI, which for many computers is disabled by default.
From this point we assume you have your x86_64/AMD64 based Linux system
up and running. Time to start your favorite terminal application! 😃
Installing Qemu
---------------
This README focus on getting you started with Qemu. From a terminal,
install (at least) the x86/x86_64 emulator. The 'virt-manager' is a
package that helps pull in other dependencies you may need:
$ sudo apt install qemu-system-x86 virt-manager
That's it.
Running Infix in Qemu
---------------------
Depending on how your Linux installation is set up, the following may
require being run with superuser privileges, i.e., you may need to
repend the command with 'sudo'.
$ ./qemu.sh
You should now see the Infix init system booting up. When the final
"Please press Enter to activate this console." is shown, press Enter
and the login: prompt is displayed.
The default credentials for the demo builds is
login: admin
password: admin
Infix -- a Network Operating System v24.09.0-rc1 (hvc0)
infix-00-00-00 login: admin
Password:
.-------.
| . . | Infix -- a Network Operating System
|-. v .-| https://kernelkit.org
'-'---'-'
Run the command 'cli' for interactive OAM
admin@infix-00-00-00:~$
You're in! Play around in your sandbox as much as you like, if you
run into problems or have questions, please see the documentation,
and don't hesitate to get in touch with us! 😃
- https://github.com/kernelkit/infix/tree/main/doc
Customizing your "Hardware"
---------------------------
For more Ethernet ports in your emulated system you need to change the
Qemu configuration used for Infix. This can be done using a menuconfig
interface, which requires the following extra package:
$ sudo apt install kconfig-frontends
We can now enter the configuration:
$ ./qemu.sh -c
Go down to *Networking*, select *TAP*, now you can change the *Number of
TAPs*, e.g. to 10. Exit and save the configuration, then you can start
Qemu again:
./qemu.sh
> Make sure to do a factory reset from the CLI, otherwise you will be
> stuck with that single interface from before.
Errors on Console
-----------------
If you see the following line printed one or more times, don't panic.
LABEL=var: Can't lookup blockdev
See the Customizing section above. To silence the error you need to
create another writable partition for Infix to store logs, container
images, etc. Look for the 'var' keyword, you can adjust the size of
the partition.
Graphical Network Simulator 3 (GNS3)
------------------------------------
GNS3 is a very powerful front-end to Qemu which takes care of creating
virtual links between network devices running in Qemu. This README is
only link to the material you need. This directory holds the appliance
file, .gns3a, that references image files also in this directory, that
you need to load into GNS3.
The necessary extra packages are available through the offical PPA. If
you don't know what a PPA is, read up on that first:
- https://launchpad.net/~gns3/+archive/ubuntu/ppa
There's a lot of tutorials and guides online, start here:
- https://docs.gns3.com/docs/
About
-----
Infix is a free, Linux based, immutable Network Operating System (NOS)
built on Buildroot, and sysrepo. A powerful mix that ease porting to
different platforms, simplify long-term maintenance, and provide easy
management using NETCONF, RESTCONF, or the built-in command line
interface (CLI) from a console or SSH login.
+3
View File
@@ -102,3 +102,6 @@ rm -f "$BINARIES_DIR/qemu.cfg"
CONFIG_="CONFIG_" BR2_CONFIG="$BINARIES_DIR/qemu.cfg" \
"$O/build/buildroot-config/conf" --olddefconfig "$BINARIES_DIR/Config.in"
rm -f "$BINARIES_DIR/qemu.cfg.old" "$BINARIES_DIR/.config.old"
# Quick intro for beginners, with links to more information
cp "$BR2_EXTERNAL_INFIX_PATH/board/common/README.txt" "$BINARIES_DIR/"
+1 -1
View File
@@ -31,7 +31,7 @@ BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/styx-a styx/styx-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci"
BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/dcp-sc-28p-a styx/dcp-sc-28p-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci"
BR2_LINUX_KERNEL_CUSTOM_DTS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/dts"
BR2_LINUX_KERNEL_DTB_KEEP_DIRNAME=y
BR2_LINUX_KERNEL_INSTALL_TARGET=y
+1 -1
View File
@@ -31,7 +31,7 @@ BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.52"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/styx-a styx/styx-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci"
BR2_LINUX_KERNEL_INTREE_DTS_NAME="alder/alder styx/dcp-sc-28p-a styx/dcp-sc-28p-b marvell/armada-3720-espressobin marvell/armada-3720-espressobin-emmc marvell/armada-3720-espressobin-v7 marvell/armada-3720-espressobin-v7-emmc marvell/armada-3720-espressobin-ultra marvell/cn9130-crb-A marvell/cn9130-crb-B microchip/sparx5_pcb135_emmc_no_psci"
BR2_LINUX_KERNEL_CUSTOM_DTS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/dts"
BR2_LINUX_KERNEL_DTB_KEEP_DIRNAME=y
BR2_LINUX_KERNEL_INSTALL_TARGET=y
+17 -3
View File
@@ -4,7 +4,7 @@ Change Log
All notable changes to the project are documented in this file.
[v24.09.0][] - 2024-09-27
[v24.09.0][] - 2024-09-30
-------------------------
**News:** this release enhances the integration of all types of static
@@ -17,6 +17,14 @@ adjusting the administrative distance of all types of static routes has
also been added to facilitate site specific adaptations. Please see the
documentation for details.
### Known Issues
- The CLI command `show interfaces` may for some terminal resolutions
not display all interfaces (on systems with >20 interfaces). This
problem is limited to the console port and only occurs for smaller
terminals (30-50 rows height). Calling `show ifaces` from the shell,
dumping `/ietf-interfaces:interfaces` XPath using `sysrepocfg`, or
using the CLI from an SSH session, is not affected. Issue #659
### Changes
- Upgrade Buildroot to 2024.02.6 (LTS)
- Upgrade Linux kernel to 6.6.52 (LTS)
@@ -68,12 +76,18 @@ documentation for details.
in the kernel. This has resulted in a complete overhaul of route
management, using FRRouting for all routes, including DHCP and IPv4LL
routes, presentation in the CLI, and also support for custom route
preference for static routes.
preference for static routes
- Fix #658: deleting VETH pairs does not work unless rebooting first.
Creating a VETH pair, followed by at least one other reconfiguration
before removing the pair, causes `confd` to fail when applying the
interface changes (tries to delete both ends of the pair)
- Spellcheck path to `/var/lib/containers` when unpacking OCI archives
on container upgrade
- cli: restore `tcpdump` permissions for administrator level users,
regression introduced in v24.08.0
- The timeout before giving up on loading the `startup-config` at boot
is now 1 minute, just like operations via other front-ends (NETCONF
and RESTCONF). This was previously (incorrectly) set to 10 seconds.
and RESTCONF). This was previously (incorrectly) set to 10 seconds
[Frr]: https://frrouting.org/
@@ -2,8 +2,9 @@
# Migrate infix-shell-type:bash -> infix-system:bash
file=$1
temp=$1.tmp
jq '.["ietf-system:system"].authentication.user |= map(.["infix-system:shell"] |= gsub("infix-shell-type:"; ""))' "$file" > "$temp"
mv "$temp" "$file"
temp=${file}.tmp
if jq -e '.["ietf-system:system"]?.authentication?.user? | length > 0' "$file" > /dev/null 2>&1; then
jq '.["ietf-system:system"].authentication.user |= map(.["infix-system:shell"] |= gsub("infix-shell-type:"; ""))' "$file" > "$temp"
mv "$temp" "$file"
fi
@@ -1,7 +1,19 @@
#!/bin/sh
# migrate ietf-routing-type => infix-routing-type
file=$1
temp=$1.tmp
jq '(.["ietf-routing:routing"]."control-plane-protocols"."control-plane-protocol"[] | select(.type == "ietf-ospf:ospfv2").type) |= "infix-routing:ospfv2"' "$file" > "$temp"
jq '(.["ietf-routing:routing"]."control-plane-protocols"."control-plane-protocol"[] | select(.type == "static").type) |= "infix-routing:static"' "$temp" > "$file"
migrate_routing_type()
{
file=$1
match=$2
replace=$3
if jq -e '.["ietf-routing:routing"]?."control-plane-protocols"?."control-plane-protocol"?[] | length > 0' "$file" > /dev/null 2>&1; then
jq --arg match "${match}" --arg replace "${replace}" '
(.["ietf-routing:routing"]."control-plane-protocols"."control-plane-protocol"[] |
select(.type == $match).type) |= $replace' "${file}" > "${file}.tmp"
mv "${file}.tmp" "${file}"
fi
}
migrate_routing_type "$1" "ietf-ospf:ospfv2" "infix-routing:ospfv2"
migrate_routing_type "$1" "static" "infix-routing:static"
+5
View File
@@ -136,6 +136,11 @@ void dagger_skip_iface(struct dagger *d, const char *ifname)
touchf("%s/%d/skip/%s", d->path, d->next, ifname);
}
void dagger_skip_current_iface(struct dagger *d, const char *ifname)
{
touchf("%s/%d/skip/%s", d->path, d->current, ifname);
}
int dagger_should_skip(struct dagger *d, const char *ifname)
{
return fexistf("%s/%d/skip/%s", d->path, d->next, ifname);
+1
View File
@@ -28,6 +28,7 @@ int dagger_evolve(struct dagger *d);
int dagger_evolve_or_abandon(struct dagger *d);
void dagger_skip_iface(struct dagger *d, const char *ifname);
void dagger_skip_current_iface(struct dagger *d, const char *ifname);
int dagger_should_skip(struct dagger *d, const char *ifname);
int dagger_should_skip_current(struct dagger *d, const char *ifname);
int dagger_is_bootstrap(struct dagger *d);
+16
View File
@@ -1648,6 +1648,7 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
struct lyd_node *cif, bool fixed)
{
const char *ifname = lydx_get_cattr(dif, "name");
const char *iftype = lydx_get_cattr(dif, "type");
FILE *ip;
DEBUG_IFACE(dif, "");
@@ -1656,6 +1657,21 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
if (dagger_should_skip_current(net, ifname))
return 0;
if (iftype && !strcmp(iftype, "infix-if-type:veth")) {
struct lyd_node *node;
const char *peer;
node = lydx_get_descendant(lyd_child(dif), "veth", NULL);
if (!node)
return -EINVAL;
peer = lydx_get_cattr(node, "peer");
if (!peer)
return -EINVAL;
dagger_skip_current_iface(net, peer);
}
ip = dagger_fopen_current(net, "exit", ifname, 50, "exit.ip");
if (!ip)
return -EIO;
+1 -1
View File
@@ -528,7 +528,7 @@
count=${KLISH_PARAM_cnt:+-c $KLISH_PARAM_cnt}
size=${KLISH_PARAM_sz:+-s $KLISH_PARAM_sz}
verbose=${KLISH_PARAM_verbose:+-vvv}
tcpdump -ln $count $size $verbose -i $KLISH_PARAM_iface $KLISH_PARAM_expr
doas tcpdump -ln $count $size $verbose -i $KLISH_PARAM_iface $KLISH_PARAM_expr
</ACTION>
</COMMAND>
@@ -26,6 +26,9 @@
- name: bridge_vlan
case: bridge_vlan/test.py
- name: veth_delete
case: veth_delete/test.py
- name: ipv4_autoconf
case: ipv4_autoconf/test.py
@@ -49,3 +52,6 @@
- name: vlan_qos
case: vlan_qos/test.py
- name: verify_all_interface_types
case: verify_all_interface_types/test.py
@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""
```
lo br-0 br-Q.40 br-D br-X
| | | | |
o o eth-Q.10 br-Q veth0a.20 eth-X.30
\ / \ | |
eth-Q veth0b veth0a eth-X
`---------'
```
Verify that all interface types can be created:
1. Ethernet/Etherlike (ethX)
2. Loopback (lo)
3. Empty bridge (br-0)
4. Ethernet/Etherlike (ethQ) as a bridge port in br-Q
5. VETH pair: veth0a <--> veth0b, veth0b as a bridge port in br-Q
6. VLAN:
1. ethQ.10 (VLAN 10) on top of an Ethernet/Etherlike interface (ethQ)
2. br-Q.40 (VLAN 40) on top of a bridge (br-Q)
3. veth0a.20 (VLAN 20) on top of a VETH interface (veth0a) as a bridge port in br-D
4. ethX.30 (VLAN 30) as a bridge port in br-X
"""
import infamy
import infamy.iface as iface
def verify_interface(target, interface, expected_type):
assert iface.interface_exist(target, interface), f"Interface <{interface}> does not exist."
expected_type = f"infix-if-type:{expected_type}"
actual_type = iface._iface_get_param(target, interface, "type")
if expected_type == "infix-if-type:etherlike" and actual_type == "infix-if-type:ethernet":
return # Allow 'etherlike' to match 'ethernet'
assert actual_type == expected_type, f"Assertion failed! expected tpye: {expected_type}, actual type {actual_type}"
with infamy.Test() as test:
with test.step("Initialize"):
env = infamy.Env()
target = env.attach("target", "mgmt")
_, eth_Q = env.ltop.xlate("target", "ethQ")
_, eth_X = env.ltop.xlate("target", "ethX")
eth_Q_10 = f"{eth_Q}.10"
eth_X_30 = f"{eth_X}.30"
br_0 = "br-0"
br_X = "br-X"
br_D = "br-D"
br_Q = "br-Q"
veth_a = "veth0a"
veth_b = "veth0b"
veth_a_20 = f"{veth_a}.20"
br_Q_40 = f"{br_Q}.40"
loopback = "lo"
with test.step("Configure an empty bridge"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": br_0,
"type": "infix-if-type:bridge",
"enabled": True,
}
]
}
})
with test.step("Configure bridge brX and associated interfaces"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": br_X,
"type": "infix-if-type:bridge",
"enabled": True
},
{
"name": eth_X_30,
"type": "infix-if-type:vlan",
"enabled": True,
"vlan": {
"lower-layer-if": eth_X,
"id": 30
},
"infix-interfaces:bridge-port": {
"bridge": br_X
}
}
]
}
})
with test.step("Configure VETH pair"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": veth_a,
"type": "infix-if-type:veth",
"enabled": True,
"infix-interfaces:veth": {
"peer": veth_b
}
},
{
"name": veth_b,
"type": "infix-if-type:veth",
"enabled": True,
"infix-interfaces:veth": {
"peer": veth_a
}
}
]
}
})
with test.step("Configure bridge brD and associated interfaces"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": br_D,
"type": "infix-if-type:bridge",
"enabled": True,
},
{
"name": veth_a_20,
"type": "infix-if-type:vlan",
"enabled": True,
"vlan": {
"lower-layer-if": "veth0a",
"id": 20
},
"infix-interfaces:bridge-port": {
"bridge": br_D
}
}
]
}
})
with test.step("Configure br-Q and associated interfaces"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": br_Q,
"type": "infix-if-type:bridge",
"enabled": True,
},
{
"name": eth_Q,
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": br_Q
}
},
{
"name": veth_b,
"type": "infix-if-type:veth",
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": br_Q
}
},
{
"name": eth_Q_10,
"type": "infix-if-type:vlan",
"enabled": True,
"vlan": {
"lower-layer-if": eth_Q,
"id": 10
}
},
{
"name": br_Q_40,
"type": "infix-if-type:vlan",
"enabled": True,
"vlan": {
"lower-layer-if": br_Q,
"id": 40
}
}
]
}
})
interfaces_to_verify = {
loopback: "loopback",
eth_X: "etherlike",
eth_Q: "etherlike",
br_0: "bridge",
br_Q: "bridge",
br_X: "bridge",
br_D: "bridge",
veth_b: "veth",
veth_a: "veth",
veth_a_20: "vlan",
eth_Q_10: "vlan",
eth_X_30: "vlan",
br_Q_40: "vlan"
}
for interface, iface_type in interfaces_to_verify.items():
with test.step(f"Verify {iface_type} interface {interface}"):
verify_interface(target, interface, iface_type)
test.succeed()
@@ -0,0 +1,25 @@
graph "1x3" {
layout="neato";
overlap="false";
esep="+80";
node [shape=record, fontname="monospace"];
edge [color="cornflowerblue", penwidth="2"];
host [
label="host | { <tgt> tgt | <dummy0> dummy0 | <dummy1> dummy1 }",
pos="0,12!",
kind="controller",
];
target [
label="{ <mgmt> mgmt | <Dport> Dport | <Qport> Qport } | target",
pos="10,12!",
kind="infix",
];
host:tgt -- target:mgmt [kind=mgmt]
host:dummy0 -- target:ethQ [color=black]
host:dummy1 -- target:ethX [color=black]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,35 @@
=== Verify that VETH pairs can be deleted
==== Description
```
veth0b veth0a e1 e2
`---------'
```
Each test step to create, add address, or delete an interace is distinct
from any other step. This to trigger a new configuration "generation".
==== Topology
ifdef::topdoc[]
image::../../test/case/ietf_interfaces/veth_delete/topology.png[Verify that VETH pairs can be deleted topology]
endif::topdoc[]
ifndef::topdoc[]
ifdef::testgroup[]
image::veth_delete/topology.png[Verify that VETH pairs can be deleted topology]
endif::testgroup[]
ifndef::testgroup[]
image::topology.png[Verify that VETH pairs can be deleted topology]
endif::testgroup[]
endif::topdoc[]
==== Test sequence
. Initialize
. Create VETH pair
. Verify VETH pair exists
. Set IP address on target:eth0 (dummy op)
. Set IP address on target:eth1 (dummy op)
. Reset configuration
. Verify target:eth0 and target:eth1 still exist
. Verify VETH pair have been removed
<<<
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""Verify that VETH pairs can be deleted
```
veth0b veth0a e1 e2
`---------'
```
Each test step to create, add address, or delete an interace is distinct
from any other step. This to trigger a new configuration "generation".
"""
import infamy
import infamy.iface as iface
with infamy.Test() as test:
with test.step("Initialize"):
env = infamy.Env()
target = env.attach("target", "mgmt")
_, eth0 = env.ltop.xlate("target", "eth0")
_, eth1 = env.ltop.xlate("target", "eth1")
veth0a = "veth0a"
veth0b = "veth0b"
with test.step("Create VETH pair"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": veth0a,
"type": "infix-if-type:veth",
"enabled": True,
"infix-interfaces:veth": {
"peer": veth0b
}
},
{
"name": veth0b,
"type": "infix-if-type:veth",
"enabled": True,
"infix-interfaces:veth": {
"peer": veth0a
}
}
]
}
})
with test.step("Verify VETH pair exists"):
assert iface.interface_exist(target, veth0a), \
f"Interface <{veth0a}> does not exist."
assert iface.interface_exist(target, veth0b), \
f"Interface <{veth0b}> does not exist."
with test.step("Set IP address on target:eth0 (dummy op)"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [{
"name": f"{eth0}",
"ipv4": {
"address": [{
"ip": "10.0.0.1",
"prefix-length": 24
}]
}
}]
}
})
with test.step("Set IP address on target:eth1 (dummy op)"):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [{
"name": f"{eth1}",
"ipv4": {
"address": [{
"ip": "20.0.0.1",
"prefix-length": 24
}]
}
}]
}
})
# TODO: need target.del_config_dict() or similar for VETH _pairs_,
# because both interfaces must be removed at the same time.
# with test.step("Delete VETH pair"):
# xpath = f"/ietf-interfaces:interfaces/interface[name='{veth0a}']"
# target.delete_xpath(xpath)
# XXX: temporary workaround
with test.step("Reset configuration"):
# Calls target.test_reset() to apply safe-config
target = env.attach("target", "mgmt")
with test.step("Verify target:eth0 and target:eth1 still exist"):
assert iface.interface_exist(target, eth0), \
f"Interface {eth0} missing!"
assert iface.interface_exist(target, eth1), \
f"Interface {eth1} missing!"
with test.step("Verify VETH pair have been removed"):
assert not iface.interface_exist(target, veth0a), \
f"Interface <{veth0a}> still exists!"
assert not iface.interface_exist(target, veth0b), \
f"Interface <{veth0b}> still exists!"
test.succeed()
@@ -0,0 +1,25 @@
graph "1x3" {
layout="neato";
overlap="false";
esep="+80";
node [shape=record, fontname="monospace"];
edge [color="cornflowerblue", penwidth="2"];
host [
label="host | { <tgt> tgt | <dummy0> dummy0 | <dummy1> dummy1 }",
pos="0,12!",
kind="controller",
];
target [
label="{ <mgmt> mgmt | <eth0> eth0 | <eth1> eth1 } | target",
pos="10,12!",
kind="infix",
];
host:tgt -- target:mgmt [kind=mgmt]
host:dummy0 -- target:eth0 [color=black]
host:dummy1 -- target:eth1 [color=black]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

+2
View File
@@ -25,6 +25,8 @@ def _iface_extract_param(json_content, param):
def _iface_get_param(target, iface, param=None):
"""Fetch target dict for iface and extract param from JSON"""
content = target.get_data(get_iface_xpath(iface, param))
if content is None:
return None
return _iface_extract_param(content, param)
def interface_exist(target, iface):
+7 -1
View File
@@ -207,7 +207,13 @@ class Device(Transport):
dspath = f"{dspath}/{path}"
url = f"{self.restconf_url}{dspath}"
return self._get_raw(url, parse)
try:
return self._get_raw(url, parse)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return None
else:
raise e
def get_running(self, path=None):
"""Wrapper function to get running datastore"""