mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-29 12:13:01 +02:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4d4d7e4ae | ||
|
|
1adace8acb | ||
|
|
059e22c85f | ||
|
|
58edaf371c | ||
|
|
d2ff58a170 | ||
|
|
40e4b168ff | ||
|
|
bac957d1bf | ||
|
|
015946219b | ||
|
|
6521de28e7 | ||
|
|
c0a79c3e00 | ||
|
|
acb844336f | ||
|
|
c8437f040a | ||
|
|
54a046afb4 | ||
|
|
35eeae55f4 | ||
|
|
a06436a8c8 | ||
|
|
ecc1e24ba9 |
@@ -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";
|
||||
@@ -0,0 +1 @@
|
||||
dcp-sc-28p-b.dtb
|
||||
@@ -1 +1 @@
|
||||
styx-a.dtb
|
||||
dcp-sc-28p-a.dtb
|
||||
@@ -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.
|
||||
|
||||
@@ -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/"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 |
@@ -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):
|
||||
|
||||
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user