Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/statd/python/yanger/ietf_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ def add_software(out):
installer_status = HOST.run_json(["rauc-installation-status"], {})
if installer_status.get("operation", {}):
installer["operation"] = installer_status["operation"]
if installer_status.get("last-error"):
installer["last-error"] = installer_status["last-error"]
if "progress" in installer_status:
progress = {}

Expand Down
2 changes: 1 addition & 1 deletion test/case/dhcp/server_boot/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
until(lambda: client.lease() == (SERVER, SUBNET_FILE))

with test.step("Verify static host gets its own boot file"):
ns.run(["ip", "link", "set", "iface", "address", HOST_MAC])
until(lambda: ns.run(["ip", "link", "set", "iface", "address", HOST_MAC], check=True))
until(lambda: client.lease() == (SERVER, HOST_FILE))

with test.step("Remove subnet and host boot, verify client falls back to global boot file and server"):
Expand Down
4 changes: 4 additions & 0 deletions test/case/interfaces/Readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ include::igmp_vlan/Readme.adoc[]

<<<

include::igmp_basic_3duts/Readme.adoc[]

<<<

include::static_multicast_filters/Readme.adoc[]

<<<
Expand Down
3 changes: 3 additions & 0 deletions test/case/interfaces/igmp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
- name: IGMP VLAN
case: igmp_vlan/test.py

- name: IGMP Basic 3 DUTs
case: igmp_basic_3duts/test.py

- name: Static Multicast Filters
case: static_multicast_filters/test.py
49 changes: 49 additions & 0 deletions test/case/interfaces/igmp_basic_3duts/test.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
=== IGMP Basic 3 DUTs

ifdef::topdoc[:imagesdir: {topdoc}../../test/case/interfaces/igmp_basic_3duts]

==== Description

The same check as IGMP basic, spread over three bridges in a chain so
that each DUT only needs a single port facing the host. A multicast sender sits
behind dut1, a non-member behind dut2, and the receiver behind dut3.
The membership report from the receiver must propagate through dut3
and dut2 up to the querier on dut1 before dut2 prunes the group from
its own host port.

....
10.0.0.1
.-----------. .----------------. .-----------.
| dut1 | | dut2 | | dut3 |
'-data-link-'-------'-west-data-east-'-------'-link-data-'
| | | 10.0.0.0/24
.-data1-. .-data2-. .-data3-.
| msend | | !memb | | mrecv |
'-------' '-------' '-------'
.2 .3 .4
HOST
....

With no membership the group 224.1.1.1 is flooded to both `!memb` and
`mrecv`. Once `mrecv` joins, dut2 and dut1 learn the group on their
links toward dut3, and `!memb` no longer receives it.

==== Topology

image::topology.svg[IGMP Basic 3 DUTs topology, align=center, scaledwidth=75%]

==== Sequence

. Set up topology and attach to target DUTs
. Configure bridges with IGMP snooping on all DUTs, querier on dut1 with 10.0.0.1/24
. Verify host:data1, host:data2 and host:data3 can reach 10.0.0.1
. Start multicast sender on host:data1, group 224.1.1.1
. Verify group 224.1.1.1 is flooded to host:data2 and host:data3
. Join multicast group 224.1.1.1 on host:data3
. Verify dut3 has learned group 224.1.1.1 on dut3:data
. Verify dut2 has learned group 224.1.1.1 on dut2:east
. Verify dut1 has learned group 224.1.1.1 on dut1:link
. Verify group 224.1.1.1 is still received on host:data3
. Verify group 224.1.1.1 is no longer received on host:data2


123 changes: 123 additions & 0 deletions test/case/interfaces/igmp_basic_3duts/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""IGMP basic with three DUTs

The same check as IGMP basic, spread over three bridges in a chain so
that each DUT only needs a single port facing the host. A multicast sender sits
behind dut1, a non-member behind dut2, and the receiver behind dut3.
The membership report from the receiver must propagate through dut3
and dut2 up to the querier on dut1 before dut2 prunes the group from
its own host port.

....
10.0.0.1
.-----------. .----------------. .-----------.
| dut1 | | dut2 | | dut3 |
'-data-link-'-------'-west-data-east-'-------'-link-data-'
| | | 10.0.0.0/24
.-data1-. .-data2-. .-data3-.
| msend | | !memb | | mrecv |
'-------' '-------' '-------'
.2 .3 .4
HOST
....

With no membership the group 224.1.1.1 is flooded to both `!memb` and
`mrecv`. Once `mrecv` joins, dut2 and dut1 learn the group on their
links toward dut3, and `!memb` no longer receives it.
"""

import infamy
import infamy.iface as iface
import infamy.multicast as mcast
from infamy.util import until, parallel

query_interval = 4


def bridge(ports, address=None):
br0 = {
"name": "br0",
"enabled": True,
"type": "infix-if-type:bridge",
"bridge": {
"multicast": {
"snooping": True,
"query-interval": query_interval
}
}
}
if address:
br0["ipv4"] = {"address": [{"ip": address, "prefix-length": 24}]}

return {
"ietf-interfaces": {
"interfaces": {
"interface": [br0] + [{
"name": port,
"enabled": True,
"bridge-port": {"bridge": "br0"}
} for port in ports]
}
}
}


with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
dut1, dut2, dut3 = parallel(lambda: env.attach("dut1", "mgmt"),
lambda: env.attach("dut2", "mgmt"),
lambda: env.attach("dut3", "mgmt"))
_, d1data = env.ltop.xlate("dut1", "data")
_, d1link = env.ltop.xlate("dut1", "link")
_, d2data = env.ltop.xlate("dut2", "data")
_, d2west = env.ltop.xlate("dut2", "west")
_, d2east = env.ltop.xlate("dut2", "east")
_, d3data = env.ltop.xlate("dut3", "data")
_, d3link = env.ltop.xlate("dut3", "link")

_, hsend = env.ltop.xlate("host", "data1")
_, hnojoin = env.ltop.xlate("host", "data2")
_, hreceive = env.ltop.xlate("host", "data3")
Comment on lines +71 to +81

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: We do not have to this anymore, since e4535aa, you can just subscript a device to translate logical port names to physical ones:

dut1["data"]

I created #1705 to be done with this once and for all.


with test.step("Configure bridges with IGMP snooping on all DUTs, querier on dut1 with 10.0.0.1/24"):
parallel(lambda: dut1.put_config_dicts(bridge([d1data, d1link], "10.0.0.1")),
lambda: dut2.put_config_dicts(bridge([d2data, d2west, d2east])),
lambda: dut3.put_config_dicts(bridge([d3data, d3link])))

with infamy.IsolatedMacVlan(hsend) as send_ns, \
infamy.IsolatedMacVlan(hnojoin) as nojoin_ns, \
infamy.IsolatedMacVlan(hreceive) as receive_ns:

with test.step("Verify host:data1, host:data2 and host:data3 can reach 10.0.0.1"):
send_ns.addip("10.0.0.2")
nojoin_ns.addip("10.0.0.3")
receive_ns.addip("10.0.0.4")
parallel(lambda: send_ns.must_reach("10.0.0.1"),
lambda: nojoin_ns.must_reach("10.0.0.1"),
lambda: receive_ns.must_reach("10.0.0.1"))

with test.step("Start multicast sender on host:data1, group 224.1.1.1"):
with mcast.MCastSender(send_ns, "224.1.1.1"):
with test.step("Verify group 224.1.1.1 is flooded to host:data2 and host:data3"):
parallel(lambda: nojoin_ns.must_receive("ip dst 224.1.1.1"),
lambda: receive_ns.must_receive("ip dst 224.1.1.1"))

with test.step("Join multicast group 224.1.1.1 on host:data3"):
with mcast.MCastReceiver(receive_ns, "224.1.1.1"):
with test.step("Verify dut3 has learned group 224.1.1.1 on dut3:data"):
until(lambda: iface.exist_bridge_multicast_filter(dut3, "224.1.1.1", d3data, "br0"), attempts=10)

with test.step("Verify dut2 has learned group 224.1.1.1 on dut2:east"):
until(lambda: iface.exist_bridge_multicast_filter(dut2, "224.1.1.1", d2east, "br0"), attempts=10)

with test.step("Verify dut1 has learned group 224.1.1.1 on dut1:link"):
until(lambda: iface.exist_bridge_multicast_filter(dut1, "224.1.1.1", d1link, "br0"), attempts=10)

with test.step("Verify group 224.1.1.1 is still received on host:data3"):
receive_ns.must_receive("ip dst 224.1.1.1")

with test.step("Verify group 224.1.1.1 is no longer received on host:data2"):
nojoin_ns.must_not_receive("ip dst 224.1.1.1")

test.succeed()
43 changes: 43 additions & 0 deletions test/case/interfaces/igmp_basic_3duts/topology.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
graph "igmp-basic-3duts" {
layout="neato";
overlap="false";
esep="+40";

node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];

host [
label="host | { <mgmt1> mgmt1 | <data1> data1 | <mgmt2> mgmt2 | <data2> data2 | <mgmt3> mgmt3 | <data3> data3 }",
pos="0,10!",
requires="controller",
];

dut1 [
label="{ <mgmt> mgmt | <data> data | <link> link } | dut1 \n\n(br0)\n10.0.0.1/24",
pos="12,20!",
requires="infix",
];

dut2 [
label="{ <west> west | <mgmt> mgmt | <data> data | <east> east } | dut2 \n\n(br0)",
pos="12,10!",
requires="infix",
];

dut3 [
label="{ <link> link | <mgmt> mgmt | <data> data } | dut3 \n\n(br0)",
pos="12,0!",
requires="infix",
];

host:mgmt1 -- dut1:mgmt [requires="mgmt", color="lightgray"]
host:mgmt2 -- dut2:mgmt [requires="mgmt", color="lightgray"]
host:mgmt3 -- dut3:mgmt [requires="mgmt", color="lightgray"]

host:data1 -- dut1:data [color=black, fontcolor=black, taillabel="10.0.0.2/24"]
host:data2 -- dut2:data [color=black, fontcolor=black, taillabel="10.0.0.3/24"]
host:data3 -- dut3:data [color=black, fontcolor=black, taillabel="10.0.0.4/24"]

dut1:link -- dut2:west [color=black]
dut2:east -- dut3:link [color=black]
}
115 changes: 115 additions & 0 deletions test/case/interfaces/igmp_basic_3duts/topology.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions test/case/interfaces/wifi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,5 @@
- name: WiFi repeater with two SSIDs in VLANs over a 4-address (WDS) backhaul
case: wifi_wds_repeater/test.py

- name: WiFi station set up from a scan-only interface
case: wifi_station_from_scan/test.py

- name: WiFi channel survey on a connected radio
case: wifi_channel_survey/test.py
Loading
Loading