mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-01 13:23:01 +02:00
Merge pull request #833 from kernelkit/mdns-settings
Expand mDNS settings
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
net.ipv4.ip_forward=1
|
||||
net.ipv4.ip_forward_update_priority=0
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
@@ -1 +1,32 @@
|
||||
# Router defaults
|
||||
net.ipv4.conf.default.rp_filter=0
|
||||
net.ipv4.conf.all.rp_filter=0
|
||||
|
||||
net.ipv4.conf.lo.rp_filter=0
|
||||
|
||||
net.ipv4.icmp_errors_use_inbound_ifaddr=1
|
||||
net.ipv4.conf.all.ignore_routes_with_linkdown=1
|
||||
|
||||
# Use neigh information on selection of nexthop for multipath hops
|
||||
net.ipv4.fib_multipath_use_neigh=1
|
||||
|
||||
# Sane ARP defaults for a switch/router
|
||||
net.ipv4.conf.default.arp_announce=2
|
||||
net.ipv4.conf.all.arp_announce=2
|
||||
|
||||
net.ipv4.conf.default.arp_notify=1
|
||||
net.ipv4.conf.all.arp_notify=1
|
||||
|
||||
net.ipv4.conf.default.arp_ignore=1
|
||||
net.ipv4.conf.all.arp_ignore=1
|
||||
|
||||
# IP Routing
|
||||
net.ipv4.ip_forward=1
|
||||
net.ipv4.ip_forward_update_priority=0
|
||||
|
||||
net.ipv4.conf.all.forwarding=0
|
||||
net.ipv4.conf.default.forwarding=0
|
||||
|
||||
# Multicast group subscriptions
|
||||
net.ipv4.igmp_max_memberships=1000
|
||||
net.ipv4.neigh.default.mcast_solicit=10
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# Router defaults
|
||||
net.ipv6.route.max_size=131072
|
||||
net.ipv6.conf.all.ignore_routes_with_linkdown=1
|
||||
|
||||
# IP Routing
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
net.ipv6.conf.default.forwarding=0
|
||||
|
||||
# IPv6 SLAAC
|
||||
net.ipv6.conf.all.autoconf=0
|
||||
net.ipv6.conf.default.autoconf=0
|
||||
|
||||
# Keep permanent addresses on an admin down
|
||||
net.ipv6.conf.all.keep_addr_on_down=1
|
||||
net.ipv6.conf.default.keep_addr_on_down=1
|
||||
|
||||
# Multicast group subscriptions
|
||||
net.ipv6.mld_max_msf=512
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
Many of the defaults here are are taken from the Frr recommendations [1].
|
||||
Below are relevant excerpts from the kernel documentation.
|
||||
|
||||
|
||||
accept_ra, accept Router Advertisements; autoconfigure using them, also
|
||||
determines whether or not to transmit Router Solicitations.
|
||||
If and only if the functional setting is to accept Router
|
||||
Advertisements, Router Solicitations will be transmitted.
|
||||
|
||||
0 - Do not accept Router Advertisements.
|
||||
|
||||
1 - Accept Router Advertisements if forwarding is disabled.
|
||||
|
||||
2 - Overrule forwarding behaviour. Accept Router Advertisements even
|
||||
if forwarding is enabled.
|
||||
|
||||
Default:
|
||||
- enabled if local forwarding is disabled
|
||||
- disabled if local forwarding is enabled
|
||||
|
||||
|
||||
accept_ra_pinfo, learn Prefix Information in Router Advertisement.
|
||||
|
||||
Default:
|
||||
- enabled if accept_ra is enabled
|
||||
- disabled if accept_ra is disabled
|
||||
|
||||
|
||||
autoconf, autoconfigure IPv6 addresses using Prefix Information in
|
||||
Router Advertisements.
|
||||
|
||||
Default:
|
||||
- enabled if accept_ra_pinfo is enabled
|
||||
- disabled if accept_ra_pinfo is disabled
|
||||
|
||||
|
||||
arp_announce, define restriction level for announcing the local source
|
||||
address from IP packets in ARP requests sent on interface:
|
||||
|
||||
0 - (default) Use any local address, configured on any interface
|
||||
|
||||
1 - Try to avoid local addresses that are not in the target’s subnet
|
||||
for this interface. Useful when target hosts reachable via this
|
||||
interface require the source IP address in ARP requests to be part
|
||||
of their logical network configured on the receiving interface.
|
||||
When we generate the request we will check all our subnets that
|
||||
include the target IP and will preserve the source address if it
|
||||
is from such subnet. If there is no such subnet we select source
|
||||
address according to the rules for level 2.
|
||||
|
||||
2 - Always use the best local address for this target. In this mode we
|
||||
ignore the source address in the IP packet and try to select local
|
||||
address that we prefer for talks with the target host. Such local
|
||||
address is selected by looking for primary IP addresses on all our
|
||||
subnets on the outgoing interface that include the target address.
|
||||
If no suitable local address is found we select the first local
|
||||
address we have on the outgoing interface or on all other
|
||||
interfaces, with the hope we will receive reply for our request
|
||||
and even sometimes no matter the source IP address we announce.
|
||||
|
||||
|
||||
arp_notify, define mode for notification of address and device changes.
|
||||
|
||||
0 - (default): do nothing
|
||||
1 - generate gratuitous arp requests when device is brought up or
|
||||
hardware address changes.
|
||||
|
||||
|
||||
arp_ignore, define different modes for sending replies in response to
|
||||
received ARP requests that resolve local target addresses:
|
||||
|
||||
0 - (default): reply for any local target IP address, configured on
|
||||
any interface
|
||||
|
||||
1 - reply only if the target IP address is a local address configured
|
||||
on the incoming interface
|
||||
|
||||
2 - reply only if the target IP address is local address configured on
|
||||
the incoming interface and both with the sender’s IP address are part
|
||||
from same subnet on this interface
|
||||
|
||||
3 - do not reply for local addresses configured with scope host, only
|
||||
resolutions for global and link addresses are replied
|
||||
|
||||
4-7 - reserved
|
||||
|
||||
8 - do not reply for all local addresses
|
||||
|
||||
|
||||
arp_accept, define behavior for accepting gratuitous ARP (garp) frames
|
||||
from devices that are not already present in the ARP table:
|
||||
|
||||
0 - don’t create new entries in the ARP table
|
||||
|
||||
1 - create new entries in the ARP table
|
||||
|
||||
2 - create new entries only if the source IP address is in the same
|
||||
subnet as an address configured on the interface that received
|
||||
the garp message.
|
||||
|
||||
Both replies and requests type gratuitous arp will trigger the ARP
|
||||
table to be updated, if this setting is on. If the ARP table already
|
||||
contains the IP address of the gratuitous arp frame, the arp table
|
||||
will be updated regardless if this setting is on or off.
|
||||
|
||||
|
||||
icmp_errors_use_inbound_ifaddr
|
||||
|
||||
0 - (default): icmp error messages are sent with the primary address
|
||||
of the exiting interface.
|
||||
|
||||
1 - the message will be sent with the primary address of the interface
|
||||
that received the packet that caused the icmp error. This is the
|
||||
behaviour many network administrators will expect from a router.
|
||||
And it can make debugging complicated network layouts much easier.
|
||||
|
||||
Note, if no primary address exists for the interface selected, then
|
||||
the primary address of the first non-loopback interface that has one
|
||||
will be used regardless of this setting.
|
||||
|
||||
|
||||
rp_filter, reverse path source filtering:
|
||||
|
||||
0 - (default): no source validation.
|
||||
|
||||
1 - Strict mode as defined in RFC3704, 'Strict Reverse Path'. Each
|
||||
incoming packet is tested against the FIB and if the interface is
|
||||
not the best reverse path the packet check will fail. By default
|
||||
failed packets are discarded.
|
||||
|
||||
2 - Loose mode as defined in RFC3704, 'Loose Reverse Path'. Each
|
||||
incoming packet’s source address is also tested against the FIB
|
||||
and if the source address is not reachable via any interface the
|
||||
packet check will fail.
|
||||
|
||||
Current recommended practice in RFC3704 is to enable strict mode to
|
||||
prevent IP spoofing from DDos attacks. If using asymmetric routing or
|
||||
other complicated routing, then loose mode is recommended.
|
||||
|
||||
The max value from conf/{all,interface}/rp_filter is used when doing
|
||||
source validation on the {interface}.
|
||||
|
||||
|
||||
|
||||
[1]: https://github.com/FRRouting/frr/blob/master/doc/user/Useful_Sysctl_Settings.md
|
||||
+7
-1
@@ -8,10 +8,15 @@ All notable changes to the project are documented in this file.
|
||||
|
||||
### Changes
|
||||
|
||||
- NTP client status is now availible in YANG.
|
||||
- NTP client status is now availible in YANG
|
||||
- Add support for more mDNS settings: allow/deny interfaces, acting
|
||||
as "reflector" and filtering of reflected services. Issue #678
|
||||
- Review of default `sysctl` settings, issue #829
|
||||
|
||||
### Fixes
|
||||
|
||||
- Minor cleanup of Networking Guide
|
||||
|
||||
|
||||
[v24.11.1][] - 2024-11-29
|
||||
-------------------------
|
||||
@@ -1418,6 +1423,7 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
|
||||
|
||||
[buildroot]: https://buildroot.org/
|
||||
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v24.11.0...HEAD
|
||||
[v24.12.0]: https://github.com/kernelkit/infix/compare/v24.11.0...v24.12.0
|
||||
[v24.11.1]: https://github.com/kernelkit/infix/compare/v24.11.0...v24.11.1
|
||||
[v24.11.0]: https://github.com/kernelkit/infix/compare/v24.10.0...v24.11.0
|
||||
[v24.10.2]: https://github.com/kernelkit/infix/compare/v24.10.1...v24.10.2
|
||||
|
||||
+92
-58
@@ -1,21 +1,21 @@
|
||||
Discover Infix Units
|
||||
====================
|
||||
# Discover Devices
|
||||
|
||||
Infix advertises itself via the [mDNS-SD](#mdns-sd) and [LLDP](#lldp)
|
||||
discovery protocols. mDNS-SD has good client support in Windows, macOS
|
||||
and on Linux systems. More on these protocols later.
|
||||
|
||||
An even simpler method is available when directly attached to an Infix
|
||||
device:
|
||||
|
||||
```
|
||||
.----. Ethernet .-------.
|
||||
| PC +---------------------+ Infix |
|
||||
'----' if1 eth0 '-------'
|
||||
.----. Ethernet .-------.
|
||||
| PC +---------------------+ Infix |
|
||||
'----' if1 e1 '-------'
|
||||
```
|
||||
Figure 1: PC directly connected over Ethernet to Infix unit (here eth0).
|
||||
|
||||
|
||||
When you wish to discover the IP address of an Infix switch, the simplest
|
||||
way is probably to *ping the IPv6 all-hosts* address (ff02::1) over a
|
||||
directly connected Ethernet cable. The unit's link-local IPv6 address is
|
||||
seen in the response.
|
||||
|
||||
In the example below, the PC is connected to Infix via interface *tap0*
|
||||
(*tap0* is *if1* in Figure 1) and Infix responds with address
|
||||
With IPv6 you can *ping the all-hosts* address (ff02::1), the device's
|
||||
link-local IPv6 address is then seen in the response. In the following
|
||||
example, the PC here uses *tap0* as *if1*, Infix responds with address
|
||||
*fe80::ff:fec0:ffed*.
|
||||
|
||||
```
|
||||
@@ -31,7 +31,11 @@ rtt min/avg/max/mdev = 0.389/0.455/0.558/0.073 ms
|
||||
linux-pc:#
|
||||
```
|
||||
|
||||
The PC could connect then connect to Infix, e.g., using SSH.
|
||||
> [!TIP]
|
||||
> The `-L` option ignores local responses from the PC.
|
||||
|
||||
This address can then be used to connect to the device, e.g., using SSH.
|
||||
Notice the syntax `username@address%interface`:
|
||||
|
||||
```
|
||||
linux-pc:# ssh admin@fe80::ff:fec0:ffed%tap0
|
||||
@@ -39,17 +43,13 @@ admin@fe80::ff:fec0:ffed%tap0's password: admin
|
||||
admin@infix-c0-ff-ee:~$
|
||||
```
|
||||
|
||||
## Discovery mechanisms available in Infix
|
||||
|
||||
Infix advertises its presence via the [mDNS](#mdns) and [LLDP](#lldp)
|
||||
discovery protocols.
|
||||
## LLDP
|
||||
|
||||
Infix supports LLDP (IEEE 802.1AB). For a device with factory default
|
||||
settings, the link-local IPv6 address can be read from the Management
|
||||
Address TLV using *tcpdump* or other sniffing tools[^1]:
|
||||
|
||||
### LLDP
|
||||
|
||||
Infix supports LLDP (IEEE 802.1AB). For a unit with factory default
|
||||
settings, the PC can readout the link-local IPv6 address from the
|
||||
Management Address TLV using *tcpdump* or other sniffing tools[^1].
|
||||
```
|
||||
linux-pc:# tcpdump -i tap0 -Qin -v ether proto 0x88cc
|
||||
tcpdump: listening on tap0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
|
||||
@@ -83,11 +83,12 @@ tcpdump: listening on tap0, link-type EN10MB (Ethernet), snapshot length 262144
|
||||
linux-pc:#
|
||||
```
|
||||
|
||||
If the unit has an IPv4 address assigned, it is shown in an additional
|
||||
If the device has an IPv4 address assigned, it is shown in an additional
|
||||
Management Address TLV.
|
||||
|
||||
> **Note** The Management Addresses shown by LLDP are not
|
||||
> necessarily associated with the port transmitting the LLDP message.
|
||||
> [!NOTE]
|
||||
> The Management Addresses shown by LLDP are not necessarily associated
|
||||
> with the port transmitting the LLDP message.
|
||||
|
||||
In the example below, the IPv4 address (10.0.1.1) happens to be
|
||||
assigned to *eth0*, while the IPv6 address (2001:db8::1) is not.
|
||||
@@ -130,10 +131,6 @@ tcpdump: listening on tap0, link-type EN10MB (Ethernet), snapshot length 262144
|
||||
linux-pc:#
|
||||
```
|
||||
|
||||
[^1]: [lldpd: implementation of IEEE 802.1ab
|
||||
(LLDP)](https://github.com/lldp/lldpd) includes *lldpcli*, which
|
||||
is handy to sniff and display LLDP packets.
|
||||
|
||||
The LLDP service can be disabled using the following commands.
|
||||
|
||||
```
|
||||
@@ -143,13 +140,38 @@ admin@infix-c0-ff-ee:/config/> leave
|
||||
admin@infix-c0-ff-ee:/>
|
||||
```
|
||||
|
||||
### mDNS
|
||||
|
||||
DNS-SD/mDNS can be used to discover Infix units and services. Infix
|
||||
units present their IP addresses, services and hostname within the
|
||||
.local domain. This method has good client support in Apple and Linux
|
||||
systems. On Linux, tools such as *avahi-browse* or *mdns-scan*[^2] can
|
||||
be used to search for devices advertising their services via mDNS.
|
||||
## mDNS-SD
|
||||
|
||||
DNS-SD/mDNS-SD can be used to discover Infix devices and services. By
|
||||
default, Infix use the `.local` domain for advertising services. Some
|
||||
networks use `.lan` instead, so this configurable:
|
||||
|
||||
```
|
||||
admin@infix-c0-ff-ee:/> configure
|
||||
admin@infix-c0-ff-ee:/config/> edit mdns
|
||||
admin@infix-c0-ff-ee:/config/mdns/> set domain lan
|
||||
```
|
||||
|
||||
Other available settings include limiting the interfaces mDNS responder
|
||||
acts on:
|
||||
|
||||
```
|
||||
admin@infix-c0-ff-ee:/config/> set interfaces allow e1
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
admin@infix-c0-ff-ee:/config/> set interfaces deny wan
|
||||
```
|
||||
|
||||
The `allow` and `deny` settings are complementary, `deny` always wins.
|
||||
|
||||
----
|
||||
|
||||
In Linux, tools such as *avahi-browse* or *mdns-scan*[^2] can be used to
|
||||
search for devices advertising their services via mDNS.
|
||||
|
||||
```
|
||||
linux-pc:# avahi-browse -ar
|
||||
@@ -181,9 +203,15 @@ linux-pc:# avahi-browse -ar
|
||||
linux-pc:#
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> The `-t` option is also very useful, it stops browsing automatically
|
||||
> when a "more or less complete list" has been printed. However, some
|
||||
> devices on the LAN may be in deep sleep so run the command again if
|
||||
> you cannot find the device you are looking for.
|
||||
|
||||
Additionally, *avahi-resolve-host-name* can be used to verify domain
|
||||
name mappings for IP addresses. By default, it translates from IPv4
|
||||
addresses. This function allows users to confirm that addresses are
|
||||
name mappings for IP addresses. By default, it translates from IPv4
|
||||
addresses. This function allows users to confirm that addresses are
|
||||
mapped correctly.
|
||||
|
||||
```
|
||||
@@ -219,20 +247,21 @@ linux-pc:#
|
||||
```
|
||||
|
||||
To disable mDNS/mDNS-SD, type the commands:
|
||||
|
||||
```
|
||||
admin@infix-c0-ff-ee:/> configure
|
||||
admin@infix-c0-ff-ee:/config/> no mdns
|
||||
admin@infix-c0-ff-ee:/config/> leave
|
||||
```
|
||||
|
||||
#### Human-Friendly Hostname Alias
|
||||
### Human-Friendly Hostname Alias
|
||||
|
||||
Each Infix unit will advertise itself as *infix.local*, in addition to
|
||||
its full hostname (e.g., *infix-c0-ff-ee.local* or *foo.local*). This
|
||||
alias works seamlessly on a network with a single Infix device, and
|
||||
makes it easy to connect when the exact hostname is not known in
|
||||
advance. The examples below show how the alias can be used for
|
||||
actions such as pinging or establishing an SSH connection:
|
||||
Each Infix deviuce advertise itself as *infix.local*, in addition to its
|
||||
full hostname (e.g., *infix-c0-ff-ee.local* or *foo.local*). This alias
|
||||
works seamlessly on a network with a single Infix device, and makes it
|
||||
easy to connect when the exact hostname is not known in advance. The
|
||||
examples below show how the alias can be used for actions such as
|
||||
pinging or establishing an SSH connection:
|
||||
|
||||
```
|
||||
linux-pc:# ping infix.local -c 3
|
||||
@@ -254,30 +283,33 @@ linux-pc:# ssh admin@infix.local
|
||||
|
||||
Run the command 'cli' for interactive OAM
|
||||
|
||||
linux-pc:#
|
||||
admin@infix-c0-ff-ee:~$
|
||||
```
|
||||
|
||||
When multiple Infix devices are present on the LAN the alias will not
|
||||
uniquely identify a device; *infix.local* will refer to any of the
|
||||
Infix devices, likely the one that first appeared.
|
||||
|
||||
> When multiple Infix units are present, use the full hostname (e.g.,
|
||||
> *infix-c0-ff-ee.local* or *foo.local*) rather than the alias
|
||||
> infix.local to deterministically connect to a unit.
|
||||
> [!NOTE]
|
||||
> When multiple Infix devices are present on the LAN, use the full name,
|
||||
> e.g., *infix-c0-ff-ee.local* or *foo.local* rather than the alias
|
||||
> *infix.local* to deterministically connect to the device.
|
||||
|
||||
|
||||
#### Netbrowse service to find all your devices
|
||||
### Browse Network Using *network.local*
|
||||
|
||||
Another mDNS alias that all Infix devices can advertise is
|
||||
*network.local*. This is a web service which basically runs avahi-browse
|
||||
and displays a table of other Infix devices and their services.
|
||||
Another mDNS alias that all Infix devices advertise is *network.local*.
|
||||
This is a web service which basically runs `avahi-browse` and displays a
|
||||
table of other Infix devices and their services.
|
||||
|
||||

|
||||
|
||||
With multiple Infix devices on the LAN, one will be your portal to
|
||||
access all others, if it goes down another will take its place.
|
||||
With multiple Infix devices on the LAN, one will take the role of your
|
||||
portal to access all others, if it goes down another takes its place.
|
||||
|
||||
To disable the netbrowse service, and the *network.local* alias, the
|
||||
following commands can be used:
|
||||
|
||||
To disable the netbrowse service, the following commands can be used:
|
||||
```
|
||||
admin@infix-c0-ff-ee:/> configure
|
||||
admin@infix-c0-ff-ee:/config/> edit web
|
||||
@@ -285,6 +317,8 @@ admin@infix-c0-ff-ee:/config/web/> no netbrowse
|
||||
admin@infix-c0-ff-ee:/config/web/> leave
|
||||
```
|
||||
|
||||
|
||||
[^1]: E.g., [lldpd](https://github.com/lldp/lldpd) which includes the
|
||||
*lldpcli* too, handy to sniff and display LLDP packets.
|
||||
[^2]: [mdns-scan](http://0pointer.de/lennart/projects/mdns-scan/): a
|
||||
tool for scanning for mDNS/DNS-SD published services on the local
|
||||
network
|
||||
tool for scanning for mDNS/DNS-SD services on the local network.
|
||||
|
||||
+56
-54
@@ -43,18 +43,18 @@ it. In this example, traffic assigned to the VLAN in question would be
|
||||
diverted to the VLAN interface before entering the bridge, while all
|
||||
other traffic would be bridged as usual.
|
||||
|
||||
| **Type** | **Yang Model** | **Description** |
|
||||
|----------|----------------------------|---------------------------------------------------------------|
|
||||
| bridge | infix-if-bridge | SW implementation of an IEEE 802.1Q bridge |
|
||||
| ip | ietf-ip, infix-ip | IP address to the subordinate interface |
|
||||
| vlan | infix-if-vlan | Capture all traffic belonging to a specific 802.1Q VID |
|
||||
| lag[^1] | infix-if-lag | Bonds multiple interfaces into one, creating a link aggregate |
|
||||
| lo | ietf-interfaces | Software loopback interface |
|
||||
| eth | ieee802-ethernet-interface | Physical Ethernet device/port. |
|
||||
| | infix-ethernet-interface | |
|
||||
| veth | infix-if-veth | Virtual Ethernet pair, typically one end is in a container |
|
||||
| *common* | ietf-interfaces, | Properties common to all interface types |
|
||||
| | infix-interfaces | |
|
||||
| **Type** | **Yang Model** | **Description** |
|
||||
|----------|----------------------------|--------------------------------------------------------------|
|
||||
| bridge | infix-if-bridge | SW implementation of an IEEE 802.1Q bridge |
|
||||
| ip | ietf-ip, infix-ip | IP address to the subordinate interface |
|
||||
| vlan | infix-if-vlan | Capture all traffic belonging to a specific 802.1Q VID |
|
||||
| lag[^1] | infix-if-lag | Bond multiple interfaces into one, creating a link aggregate |
|
||||
| lo | ietf-interfaces | Software loopback interface |
|
||||
| eth | ieee802-ethernet-interface | Physical Ethernet device/port. |
|
||||
| | infix-ethernet-interface | |
|
||||
| veth | infix-if-veth | Virtual Ethernet pair, typically one end is in a container |
|
||||
| *common* | ietf-interfaces, | Properties common to all interface types |
|
||||
| | infix-interfaces | |
|
||||
|
||||
|
||||
## Data Plane
|
||||
@@ -154,9 +154,9 @@ fabric!
|
||||
#### MAC Bridge
|
||||
|
||||
In Infix ports are by default not switch ports, unless the customer
|
||||
specific factory config sets it up this way. To enable switching
|
||||
between ports you create a bridge and then add ports to that
|
||||
bridge. That's it.
|
||||
specific factory config sets it up this way. To enable switching, with
|
||||
offloading if you have a switch chipset, between ports you create a
|
||||
bridge and then add ports to that bridge. Like this:
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
@@ -170,13 +170,15 @@ admin@example:/config/> leave
|
||||
Here we add two ports to bridge `br0`: `eth0` and `eth1`.
|
||||
|
||||
> [!TIP]
|
||||
> Infix has many built-in helpers controlled by convention. Example,
|
||||
> naming your bridge `brN`, where `N` is a number, hints Infix to set
|
||||
> interface type automatically and unlocks all bridge features. Other
|
||||
> "magic" names are `vethNA`, where `N` is a number and `A` is a letter
|
||||
> ('a' for access port and 'b' for bridge side is common), and `ethN.M`
|
||||
> for VLAN M on top of `ethN`, or `dockerN` to create an IP masquerading
|
||||
> container bridge.
|
||||
> The CLI has several built-in helpers governed by convention. E.g.,
|
||||
> naming bridges `brN`, where `N` is a number, the type is *inferred*
|
||||
> automatically and unlocks all bridge features. Other conventions are
|
||||
> `vethNA`, where `N` is a number and `A` is a letter ('a' for access
|
||||
> port and 'b' for bridge side is common), and `ethN.M` for VLAN M on
|
||||
> top of `ethN`, or `dockerN` for a IP masquerading container bridge.
|
||||
>
|
||||
> Note, this inference only works with the CLI, configuring networking
|
||||
> over NETCONF or RESTCONF requires setting the type explicitly.
|
||||
|
||||

|
||||
|
||||
@@ -187,11 +189,11 @@ bridge should be used instead.
|
||||
|
||||
#### VLAN Filtering Bridge
|
||||
|
||||
By default bridges in Linux do not filter based on VLAN tags. It can be
|
||||
enabled in Infix when creating a bridge by adding a port to a VLAN as a
|
||||
tagged or untagged member. Use the port default VID (PVID) setting to
|
||||
control VLAN association for traffic ingressing a port untagged (default
|
||||
PVID: 1).
|
||||
By default bridges in Linux do not filter based on VLAN tags. This can
|
||||
be enabled when creating a bridge by adding a port to a VLAN as a tagged
|
||||
or untagged member. Use the port default VID (PVID) setting to control
|
||||
VLAN association for traffic ingressing a port untagged (default PVID:
|
||||
1).
|
||||
|
||||
```
|
||||
admin@example:/config/> edit interface br0
|
||||
@@ -283,15 +285,15 @@ br0 224.1.1.1 e3, e2
|
||||
br0 ff02::6a br0
|
||||
```
|
||||
|
||||
It is a small LAN, so our bridge has already become the elected IGMP
|
||||
querier. We see it is ours because the timeout is `None`, and we
|
||||
recognize our IP address. We can also see two ports that have joined
|
||||
the same IPv4 multicast group, 224.1.1.1, and one join from Infix itself
|
||||
for the IPv6 group ff02::6a.
|
||||
This is a rather small LAN, so our bridge has already become the elected
|
||||
IGMP querier. We see it is ours because the timeout is `None`, and we
|
||||
recognize the IP address the system has detected, as ours. We can also
|
||||
see two ports that have joined the same IPv4 multicast group, 224.1.1.1,
|
||||
and one join from the system itself for the IPv6 group ff02::6a.
|
||||
|
||||
Now, let's see what happens when we add another bridge, with VLAN
|
||||
filtering enabled. We skip the boring parts about how to move ports
|
||||
e4-e7 to `br1` and assign them to VLANs, and again, focus on the
|
||||
Now, let us see what happens when we add another bridge, this time with
|
||||
VLAN filtering enabled. We skip the boring parts about how to move
|
||||
ports e4-e7 to `br1` and assign them to VLANs, and again, focus on the
|
||||
multicast bits only:
|
||||
|
||||
```
|
||||
@@ -303,7 +305,7 @@ admin@example:/config/interface/br1/> leave
|
||||
admin@example:/> copy running-config startup-config
|
||||
```
|
||||
|
||||
Let's see what we get:
|
||||
Let us see what we get:
|
||||
|
||||
```
|
||||
admin@example:/> show ip multicast
|
||||
@@ -404,15 +406,15 @@ an IGMP/MLD fast-leave port.
|
||||
|
||||
#### Forwarding of IEEE Reserved Group Addresses
|
||||
|
||||
Addresses in range `01:80:C2:00:00:0X` are used by various bridge
|
||||
signaling protocols, and are not forwarded by default. Still, it is
|
||||
sometimes useful to let the bridge forward such packets, and Infix
|
||||
supports this by specifying protocol names or the last address
|
||||
*nibble* as decimal value `0..15`.
|
||||
Addresses in the range `01:80:C2:00:00:0X` are used by various bridge
|
||||
signaling protocols, and are not forwarded by default. Still, it is
|
||||
sometimes useful to let the bridge forward such packets, this can be
|
||||
done by specifying protocol names or the last address *nibble* as
|
||||
decimal value `0..15`:
|
||||
|
||||
```
|
||||
admin@example:/config/> edit interface br0 bridge
|
||||
admin@example:/config/interface/br0/bridge/> set ieee-group-forward <?>
|
||||
admin@example:/config/interface/br0/bridge/> set ieee-group-forward # Tap the ? ley for alternatives
|
||||
[0..15] List of IEEE link-local protocols to forward, e.g., STP, LLDP
|
||||
dot1x 802.1X Port-Based Network Access Control.
|
||||
lacp 802.3 Slow Protocols, e.g., LACP.
|
||||
@@ -430,7 +432,7 @@ admin@example:/config/interface/br0/bridge/>
|
||||
|
||||
### VLAN Interfaces
|
||||
|
||||
Creating a VLAN can be done in many ways. This section assumes VLAN
|
||||
Creating a VLAN can be done in many ways. This section assumes VLAN
|
||||
interfaces created atop another Linux interface. E.g., the VLAN
|
||||
interfaces created on top of the Ethernet interface or bridge in the
|
||||
picture below.
|
||||
@@ -472,7 +474,7 @@ top of a bridge interface *br0* is named *vlan10*.
|
||||
|
||||
> [!NOTE]
|
||||
> If you name your VLAN interface `foo0.N` or `vlanN`, where `N` is a
|
||||
> number, Infix will set the interface type automatically for you.
|
||||
> number, the CLI infers the interface type automatically.
|
||||
|
||||
|
||||
### Physical Ethernet Interfaces
|
||||
@@ -638,7 +640,8 @@ admin@example:/config/>
|
||||
This section details IP Addresses And Other Per-Interface IP settings.
|
||||
|
||||
Infix support several network interface types, each can be assigned one
|
||||
or more IP addresses, both IPv4 and IPv6 are supported.
|
||||
or more IP addresses, both IPv4 and IPv6 are supported. (There is no
|
||||
concept of a "primary" address.)
|
||||
|
||||

|
||||
|
||||
@@ -1226,7 +1229,7 @@ currently supported, namely `ipv4` and `ipv6`.
|
||||
[4]: https://www.rfc-editor.org/rfc/rfc3442
|
||||
[0]: https://frrouting.org/
|
||||
|
||||
[^1]: Please note, link aggregates are not yet supported in Infix.
|
||||
[^1]: Please note, link aggregates are not yet supported.
|
||||
[^2]: Link-local IPv6 addresses are implicitly enabled when enabling
|
||||
IPv6. IPv6 can be enabled/disabled per interface in the
|
||||
[ietf-ip][2] YANG model.
|
||||
@@ -1237,11 +1240,10 @@ currently supported, namely `ipv4` and `ipv6`.
|
||||
[^4]: A YANG deviation was previously used to make it possible to set
|
||||
`phys-address`, but this has been replaced with the more flexible
|
||||
`custom-phys-address`.
|
||||
[^5]: Infix MAC bridges on Marvell Linkstreet devices are currently
|
||||
limited to use a single MAC database, causing issues if the same
|
||||
MAC address appears on different MAC bridges.
|
||||
[^6]: Ethernet counters are described in
|
||||
*ieee802-ethernet-interface.yang* and
|
||||
*infix-ethernet-interface.yang*. [Ethernet
|
||||
Counters](eth-counters.md) page provides additional details on
|
||||
statistics support.
|
||||
[^5]: MAC bridges on Marvell Linkstreet devices are currently limited to
|
||||
a single MAC database, this may be a problem if the same MAC address
|
||||
appears in different MAC bridges.
|
||||
[^6]: Ethernet counters are described in *ieee802-ethernet-interface.yang*
|
||||
and *infix-ethernet-interface.yang*. There is a dedicated document on
|
||||
[Ethernet Counters](eth-counters.md) that provide additional details
|
||||
on the statistics support.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
AVAHI_ARGS="-l notice"
|
||||
@@ -1 +1,2 @@
|
||||
service [2345] name:mdns avahi-daemon -s -l notice -- Avahi mDNS-SD daemon
|
||||
service <!> name:mdns env:-/etc/default/avahi \
|
||||
[2345] avahi-daemon -s $AVAHI_ARGS -- Avahi mDNS-SD daemon
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# <!>: dropbear does not honor SIGHUP.
|
||||
# -R: Create hostkeys if needed.
|
||||
# -F: Run in foreground.
|
||||
service [2345] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||
service <!> env:-/etc/default/dropbear \
|
||||
[2345] dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
service [2345] <usr/mkcert> env:-/etc/default/nginx nginx -g 'daemon off;' $NGINX_ARGS -- Web server
|
||||
service <usr/mkcert> env:-/etc/default/nginx \
|
||||
[2345] nginx -g 'daemon off;' $NGINX_ARGS -- Web server
|
||||
|
||||
@@ -176,21 +176,81 @@ static int hostname_change(sr_session_ctx_t *session, uint32_t sub_id, const cha
|
||||
return mdns_records("update", all);
|
||||
}
|
||||
|
||||
static void fput_list(FILE *fp, struct lyd_node *cfg, const char *list, const char *heading)
|
||||
{
|
||||
const char *prefix = heading;
|
||||
struct lyd_node *node;
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(cfg), node, list) {
|
||||
fprintf(fp, "%s%s", prefix, lyd_get_value(node));
|
||||
prefix = ",";
|
||||
}
|
||||
|
||||
if (prefix != heading)
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
#define AVAHI_CONF "/etc/avahi/avahi-daemon.conf"
|
||||
|
||||
static void mdns_conf(struct lyd_node *cfg)
|
||||
{
|
||||
struct lyd_node *ctx;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(AVAHI_CONF, "w");
|
||||
if (!fp) {
|
||||
ERRNO("failed creating %s", AVAHI_CONF);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "# Generated by Infix confd\n"
|
||||
"[server]\n"
|
||||
"domain-name=%s\n"
|
||||
"use-ipv4=yes\n"
|
||||
"use-ipv6=yes\n", lydx_get_cattr(cfg, "domain"));
|
||||
|
||||
ctx = lydx_get_descendant(lyd_child(cfg), "interfaces", NULL);
|
||||
if (ctx) {
|
||||
fput_list(fp, ctx, "allow", "allow-interfaces=");
|
||||
fput_list(fp, ctx, "deny", "deny-interfaces=");
|
||||
}
|
||||
|
||||
fprintf(fp,
|
||||
"ratelimit-interval-usec=1000000\n"
|
||||
"ratelimit-burst=1000\n");
|
||||
|
||||
fprintf(fp, "\n[wide-area]\n");
|
||||
/* nop */
|
||||
fprintf(fp, "\n[publish]\n");
|
||||
/* nop */
|
||||
fprintf(fp, "\n[reflector]\n");
|
||||
ctx = lydx_get_descendant(lyd_child(cfg), "reflector", NULL);
|
||||
if (ctx) {
|
||||
fprintf(fp, "enable-reflector=%s\n", lydx_is_enabled(ctx, "enabled") ? "on" : "off");
|
||||
fput_list(fp, ctx, "service-filter", "reflect-filters=");
|
||||
}
|
||||
|
||||
fprintf(fp, "\n[rlimits]\n");
|
||||
/* nop */
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void mdns_cname(sr_session_ctx_t *session)
|
||||
{
|
||||
int ena = srx_enabled(session, "/infix-services:mdns/enabled");
|
||||
|
||||
if (ena) {
|
||||
int www = srx_enabled(session, "/infix-services:web/netbrowse/enabled");
|
||||
char *name = fgetkey("/etc/os-release", "DEFAULT_HOSTNAME");
|
||||
const char *hostname = fgetkey("/etc/os-release", "DEFAULT_HOSTNAME");
|
||||
|
||||
if (name || www) {
|
||||
if (hostname || www) {
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/etc/default/mdns-alias", "w");
|
||||
if (fp) {
|
||||
fprintf(fp, "MDNS_ALIAS_ARGS=\"%s%s %s\"\n",
|
||||
name ?: "", name ? ".local" : "",
|
||||
hostname ?: "", hostname ? ".local" : "",
|
||||
www ? "network.local" : "");
|
||||
fclose(fp);
|
||||
} else {
|
||||
@@ -217,6 +277,9 @@ static int mdns_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
|
||||
|
||||
ena = lydx_is_enabled(srv, "enabled");
|
||||
if (ena) {
|
||||
/* Generate/update avahi-daemon.conf */
|
||||
mdns_conf(srv);
|
||||
|
||||
/* Generate/update basic mDNS service records */
|
||||
mdns_records("update", all);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ MODULES=(
|
||||
"infix-dhcp-client@2024-09-20.yang"
|
||||
"infix-meta@2024-10-18.yang"
|
||||
"infix-system@2024-11-27.yang"
|
||||
"infix-services@2024-05-30.yang"
|
||||
"infix-services@2024-12-02.yang"
|
||||
"ieee802-ethernet-interface@2019-06-21.yang"
|
||||
"infix-ethernet-interface@2024-02-27.yang"
|
||||
"infix-factory-default@2023-06-28.yang"
|
||||
|
||||
@@ -3,10 +3,21 @@ module infix-services {
|
||||
namespace "urn:ietf:params:xml:ns:yang:infix-services";
|
||||
prefix infix-svc;
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix services, generic.";
|
||||
|
||||
revision 2024-12-02 {
|
||||
description "Expand mdns options: domain, allow/deny interfaces, reflector.";
|
||||
reference "internal";
|
||||
}
|
||||
revision 2024-05-30 {
|
||||
description "Add support for RESTCONF enable/disable as a web service.";
|
||||
reference "internal";
|
||||
@@ -35,6 +46,63 @@ module infix-services {
|
||||
description "Globally enable or disable mDNS/SD on all interfaces.";
|
||||
type boolean;
|
||||
}
|
||||
|
||||
leaf domain {
|
||||
description "LAN domain name to register host name and services in.
|
||||
|
||||
Most common is .local, but some also use .lan, or .office,
|
||||
usually this setting can be left as-is.";
|
||||
default "local";
|
||||
type inet:domain-name;
|
||||
}
|
||||
|
||||
container interfaces {
|
||||
description "Filter interfaces to act on.";
|
||||
|
||||
leaf-list allow {
|
||||
description "Enabled on interfaces, can be combined with deny-interfaces.
|
||||
|
||||
By default all, except loopback and point-to-point links.";
|
||||
type if:interface-ref;
|
||||
}
|
||||
|
||||
leaf-list deny {
|
||||
description "Disabled on interfaces (always wins).
|
||||
|
||||
Other not specified interfaces will be used, except loopback
|
||||
and point-to-point, unless combined with allow-interfaces.
|
||||
|
||||
This option takes precedence over allow-interfaces.";
|
||||
type if:interface-ref;
|
||||
}
|
||||
}
|
||||
|
||||
container reflector {
|
||||
description "Reflect incoming mDNS requests to local interfaces.";
|
||||
|
||||
leaf enabled {
|
||||
description "Enable mDNS reflector on local interfaces.";
|
||||
type boolean;
|
||||
}
|
||||
|
||||
leaf-list service-filter {
|
||||
description "Filter mDNS service names to reflect.
|
||||
|
||||
Example, for AirPlay and AirTunes, use:
|
||||
|
||||
- _airplay._tcp.local
|
||||
- _raop._tcp.local
|
||||
|
||||
For AirPrint use:
|
||||
|
||||
- _printer._tcp.local
|
||||
- _ipp._tcp.local
|
||||
- _pdl-datastream._tcp.local
|
||||
|
||||
By default all services are reflected.";
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container web {
|
||||
|
||||
@@ -3,4 +3,7 @@
|
||||
|
||||
<<<
|
||||
|
||||
include::mdns_allow_deny/Readme.adoc[]
|
||||
|
||||
include::services_basic/Readme.adoc[]
|
||||
|
||||
|
||||
@@ -6,4 +6,6 @@
|
||||
# are transparent with respect to IEEE link-local multicast.
|
||||
#- name: services_basic
|
||||
# case: services_basic/test.py
|
||||
[]
|
||||
|
||||
- name: mdns_allow_deny
|
||||
case: mdns_allow_deny/test.py
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
=== mDNS allow/deny interfaces
|
||||
==== Description
|
||||
Verify the mDNS responder interface allow/deny configuration. Both
|
||||
settings can be used independently and in concert. We verify operation
|
||||
with three scenarios:
|
||||
|
||||
1. Allow p2, no mDNS traffic should be received on p1 and p3
|
||||
2. Deny p2, mDNS traffic should only be received on p1 and p3
|
||||
3. Allow p1 and p3, deny p2 and p3, traffic only on p1
|
||||
|
||||
==== Topology
|
||||
ifdef::topdoc[]
|
||||
image::../../test/case/infix_services/mdns_allow_deny/topology.svg[mDNS allow/deny interfaces topology]
|
||||
endif::topdoc[]
|
||||
ifndef::topdoc[]
|
||||
ifdef::testgroup[]
|
||||
image::mdns_allow_deny/topology.svg[mDNS allow/deny interfaces topology]
|
||||
endif::testgroup[]
|
||||
ifndef::testgroup[]
|
||||
image::topology.svg[mDNS allow/deny interfaces topology]
|
||||
endif::testgroup[]
|
||||
endif::topdoc[]
|
||||
==== Test sequence
|
||||
. Set up topology and attach to target DUT
|
||||
. Configure device
|
||||
. Allow mDNS on a single interface: p2
|
||||
. Deny mDNS on a single interface: p2
|
||||
. Allow mDNS on p1, p3 deny on p2, p3
|
||||
|
||||
|
||||
<<<
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""mDNS allow/deny interfaces
|
||||
|
||||
Verify the mDNS responder interface allow/deny configuration. Both
|
||||
settings can be used independently and in concert. We verify operation
|
||||
with three scenarios:
|
||||
|
||||
1. Allow p2, no mDNS traffic should be received on p1 and p3
|
||||
2. Deny p2, mDNS traffic should only be received on p1 and p3
|
||||
3. Allow p1 and p3, deny p2 and p3, traffic only on p1
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import infamy
|
||||
from infamy.util import parallel
|
||||
|
||||
|
||||
def mdns_scan(tgt):
|
||||
"""Trigger Avahi to send traffic on allowed interfaces"""
|
||||
time.sleep(2)
|
||||
tgt.runsh("logger -t scan 'calling avahi-browse ...'")
|
||||
tgt.runsh("avahi-browse -lat")
|
||||
|
||||
|
||||
def check(ns, expr, must):
|
||||
"""Wrap netns.must_receive() with common defaults"""
|
||||
return ns.must_receive(expr, timeout=3, must=must)
|
||||
|
||||
|
||||
with infamy.Test() as test:
|
||||
with test.step("Set up topology and attach to target DUT"):
|
||||
env = infamy.Env()
|
||||
dut = env.attach("dut", "mgmt")
|
||||
ssh = env.attach("dut", "mgmt", "ssh")
|
||||
_, p1 = env.ltop.xlate("dut", "p1")
|
||||
_, p2 = env.ltop.xlate("dut", "p2")
|
||||
_, p3 = env.ltop.xlate("dut", "p3")
|
||||
_, eth1 = env.ltop.xlate("host", "eth1")
|
||||
_, eth2 = env.ltop.xlate("host", "eth2")
|
||||
_, eth3 = env.ltop.xlate("host", "eth3")
|
||||
|
||||
with test.step("Configure device"):
|
||||
dut.put_config_dicts(
|
||||
{
|
||||
"ietf-interfaces": {
|
||||
"interfaces": {
|
||||
"interface": [
|
||||
{
|
||||
"name": p1,
|
||||
"enabled": True,
|
||||
"ipv4": {
|
||||
"address": [
|
||||
{
|
||||
"ip": "10.0.1.1",
|
||||
"prefix-length": 24
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"name": p2,
|
||||
"enabled": True,
|
||||
"ipv4": {
|
||||
"address": [
|
||||
{
|
||||
"ip": "10.0.2.1",
|
||||
"prefix-length": 24
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"name": p3,
|
||||
"enabled": True,
|
||||
"ipv4": {
|
||||
"address": [
|
||||
{
|
||||
"ip": "10.0.3.1",
|
||||
"prefix-length": 24
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
"ietf-system": {
|
||||
"system": {
|
||||
"hostname": "dut"
|
||||
}
|
||||
},
|
||||
"infix-services": {
|
||||
"mdns": {
|
||||
"enabled": True
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
with infamy.IsolatedMacVlan(eth1) as ns1, \
|
||||
infamy.IsolatedMacVlan(eth2) as ns2, \
|
||||
infamy.IsolatedMacVlan(eth3) as ns3:
|
||||
ns1.addip("10.0.1.2")
|
||||
ns2.addip("10.0.2.2")
|
||||
ns3.addip("10.0.3.2")
|
||||
|
||||
EXPR1 = "host 10.0.1.1 and port 5353"
|
||||
EXPR2 = "host 10.0.2.1 and port 5353"
|
||||
EXPR3 = "host 10.0.3.1 and port 5353"
|
||||
|
||||
with test.step("Allow mDNS on a single interface: p2"):
|
||||
dut.put_config_dict("infix-services", {
|
||||
"mdns": {
|
||||
"interfaces": {
|
||||
"allow": [p2],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
parallel(lambda: mdns_scan(ssh),
|
||||
lambda: check(ns1, EXPR1, False),
|
||||
lambda: check(ns2, EXPR2, True),
|
||||
lambda: check(ns3, EXPR3, False))
|
||||
|
||||
with test.step("Deny mDNS on a single interface: p2"):
|
||||
dut.delete_xpath("/infix-services:mdns/interfaces")
|
||||
dut.put_config_dict("infix-services", {
|
||||
"mdns": {
|
||||
"interfaces": {
|
||||
"deny": [p2],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
parallel(lambda: mdns_scan(ssh),
|
||||
lambda: check(ns1, EXPR1, True),
|
||||
lambda: check(ns2, EXPR2, False),
|
||||
lambda: check(ns3, EXPR3, True))
|
||||
|
||||
with test.step("Allow mDNS on p1, p3 deny on p2, p3"):
|
||||
dut.delete_xpath("/infix-services:mdns/interfaces")
|
||||
dut.put_config_dict("infix-services", {
|
||||
"mdns": {
|
||||
"interfaces": {
|
||||
"allow": [p1, p3],
|
||||
"deny": [p2, p3],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
parallel(lambda: mdns_scan(ssh),
|
||||
lambda: check(ns1, EXPR1, True),
|
||||
lambda: check(ns2, EXPR2, False),
|
||||
lambda: check(ns3, EXPR3, False))
|
||||
|
||||
test.succeed()
|
||||
@@ -0,0 +1,26 @@
|
||||
graph "1x4" {
|
||||
layout="neato";
|
||||
overlap="false";
|
||||
esep="+80";
|
||||
|
||||
node [shape=record, fontname="DejaVu Sans Mono, Book"];
|
||||
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
|
||||
|
||||
host [
|
||||
label="host | { <mgmt> mgmt | <eth1> eth1 | <eth2> eth2 | <eth3> eth3 }",
|
||||
pos="0,12!",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
dut [
|
||||
label="{ <mgmt> mgmt | <p1> p1 | <p2> p2 | <p3> p3 } | dut \n\n(br0)\n10.0.p.1/24",
|
||||
pos="10,12!",
|
||||
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:mgmt -- dut:mgmt [kind=mgmt, color="lightgray"]
|
||||
host:eth1 -- dut:p1 [color=black, fontcolor=black, taillabel="10.0.1.2/24"]
|
||||
host:eth2 -- dut:p2 [color=black, fontcolor=black, taillabel="10.0.2.2/24"]
|
||||
host:eth3 -- dut:p3 [color=black, fontcolor=black, taillabel="10.0.3.2/24"]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<!-- Title: 1x4 Pages: 1 -->
|
||||
<svg width="465pt" height="101pt"
|
||||
viewBox="0.00 0.00 465.03 101.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 97)">
|
||||
<title>1x4</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-97 461.03,-97 461.03,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="black" points="0,-0.5 0,-92.5 100,-92.5 100,-0.5 0,-0.5"/>
|
||||
<text text-anchor="middle" x="25" y="-42.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
|
||||
<polyline fill="none" stroke="black" points="50,-0.5 50,-92.5 "/>
|
||||
<text text-anchor="middle" x="75" y="-77.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="50,-69.5 100,-69.5 "/>
|
||||
<text text-anchor="middle" x="75" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">eth1</text>
|
||||
<polyline fill="none" stroke="black" points="50,-46.5 100,-46.5 "/>
|
||||
<text text-anchor="middle" x="75" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">eth2</text>
|
||||
<polyline fill="none" stroke="black" points="50,-23.5 100,-23.5 "/>
|
||||
<text text-anchor="middle" x="75" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">eth3</text>
|
||||
</g>
|
||||
<!-- dut -->
|
||||
<g id="node2" class="node">
|
||||
<title>dut</title>
|
||||
<polygon fill="none" stroke="black" points="300.03,-0.5 300.03,-92.5 457.03,-92.5 457.03,-0.5 300.03,-0.5"/>
|
||||
<text text-anchor="middle" x="325.03" y="-77.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="300.03,-69.5 350.03,-69.5 "/>
|
||||
<text text-anchor="middle" x="325.03" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">p1</text>
|
||||
<polyline fill="none" stroke="black" points="300.03,-46.5 350.03,-46.5 "/>
|
||||
<text text-anchor="middle" x="325.03" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">p2</text>
|
||||
<polyline fill="none" stroke="black" points="300.03,-23.5 350.03,-23.5 "/>
|
||||
<text text-anchor="middle" x="325.03" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">p3</text>
|
||||
<polyline fill="none" stroke="black" points="350.03,-0.5 350.03,-92.5 "/>
|
||||
<text text-anchor="middle" x="403.53" y="-65.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">dut </text>
|
||||
<text text-anchor="middle" x="403.53" y="-34.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">(br0)</text>
|
||||
<text text-anchor="middle" x="403.53" y="-19.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">10.0.p.1/24</text>
|
||||
</g>
|
||||
<!-- host--dut -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt--dut:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M100,-81.5C100,-81.5 299.53,-81.5 299.53,-81.5"/>
|
||||
</g>
|
||||
<!-- host--dut -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:eth1--dut:p1</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M100,-58.5C100,-58.5 299.53,-58.5 299.53,-58.5"/>
|
||||
<text text-anchor="middle" x="141" y="-62.3" font-family="DejaVu Serif, Book" font-size="14.00">10.0.1.2/24</text>
|
||||
</g>
|
||||
<!-- host--dut -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:eth2--dut:p2</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M100,-34.5C100,-34.5 299.53,-34.5 299.53,-34.5"/>
|
||||
<text text-anchor="middle" x="141" y="-38.3" font-family="DejaVu Serif, Book" font-size="14.00">10.0.2.2/24</text>
|
||||
</g>
|
||||
<!-- host--dut -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>host:eth3--dut:p3</title>
|
||||
<path fill="none" stroke="black" stroke-width="2" d="M100,-11.5C100,-11.5 299.53,-11.5 299.53,-11.5"/>
|
||||
<text text-anchor="middle" x="141" y="-15.3" font-family="DejaVu Serif, Book" font-size="14.00">10.0.3.2/24</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -17,7 +17,7 @@ endif::testgroup[]
|
||||
endif::topdoc[]
|
||||
==== Test sequence
|
||||
. Set up topology and attach to target DUT
|
||||
. Set IPv4 address 10.0.0.10/24 on target:data and disable MDNS and LLDP
|
||||
. Set IPv4 address 10.0.0.10/24 on target:data and disable mDNS and LLDP
|
||||
. Enable mDNS and LLDP and toggle target:data DOWN and UP to trigger service
|
||||
. Verify on host:data there are packets from 10.0.0.10:5354 (mDNS)
|
||||
. Verify on host:data there are LLDP packets sent from 10.0.0.10
|
||||
|
||||
@@ -71,7 +71,7 @@ with infamy.Test() as test:
|
||||
env = infamy.Env()
|
||||
target = env.attach("target", "mgmt")
|
||||
|
||||
with test.step("Set IPv4 address 10.0.0.10/24 on target:data and disable MDNS and LLDP"):
|
||||
with test.step("Set IPv4 address 10.0.0.10/24 on target:data and disable mDNS and LLDP"):
|
||||
_, tport = env.ltop.xlate("target", "data")
|
||||
|
||||
target.put_config_dict("ietf-interfaces", {
|
||||
|
||||
+10
-4
@@ -389,21 +389,27 @@ class Device(Transport):
|
||||
raise ValueError(f"Failed parsing xpath:{xpath}")
|
||||
|
||||
module = match.group('module')
|
||||
modpath = f"/{match.group('module')}:{match.group('path')}"
|
||||
path = match.group('path')
|
||||
modpath = f"/{module}:{path}"
|
||||
|
||||
# Fetch current config
|
||||
old = self.get_config_dict(modpath)
|
||||
new = copy.deepcopy(old)
|
||||
|
||||
libyang.xpath_del(new, xpath)
|
||||
# Perform deletion
|
||||
if not libyang.xpath_del(new, xpath):
|
||||
raise ValueError(f"Failed to delete specified xpath: {xpath}")
|
||||
|
||||
# Parse old and new data to generate the diff
|
||||
mod = self.ly.get_module(module)
|
||||
oldd = mod.parse_data_dict(old, no_state=True)
|
||||
newd = mod.parse_data_dict(new, no_state=True)
|
||||
oldd = mod.parse_data_dict(old, no_state=True, validate=False)
|
||||
newd = mod.parse_data_dict(new, no_state=True, validate=False)
|
||||
|
||||
lyd = oldd.diff(newd)
|
||||
if lyd is None:
|
||||
raise ValueError(f"Failed generating diff for xpath:{xpath}")
|
||||
|
||||
# Apply the configuration change
|
||||
return self.put_config(lyd.print_mem("xml", with_siblings=True,
|
||||
pretty=False))
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ class IsolatedMacVlans:
|
||||
self.sleeper.kill()
|
||||
self.sleeper.wait()
|
||||
|
||||
for n in range(100):
|
||||
for _ in range(100):
|
||||
promisc = False
|
||||
for parent in self.ifmap.keys():
|
||||
iplink = subprocess.run(f"ip -d -j link show dev {parent}".split(),
|
||||
@@ -190,12 +190,13 @@ class IsolatedMacVlans:
|
||||
|
||||
def runsh(self, script, *args, **kwargs):
|
||||
return self.run("/bin/sh", text=True, input=script,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *args, **kwargs)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
*args, **kwargs)
|
||||
|
||||
def addroute(self, subnet, nexthop, proto="ipv4", prefix_length=""):
|
||||
p=proto[3]
|
||||
p = proto[3]
|
||||
if prefix_length:
|
||||
prefix_length=f"/{prefix_length}"
|
||||
prefix_length = f"/{prefix_length}"
|
||||
|
||||
self.runsh(f"""
|
||||
set -ex
|
||||
@@ -203,7 +204,7 @@ class IsolatedMacVlans:
|
||||
""", check=True)
|
||||
|
||||
def addip(self, ifname, addr, prefix_length=24, proto="ipv4"):
|
||||
p=proto[3]
|
||||
p = proto[3]
|
||||
|
||||
self.runsh(f"""
|
||||
set -ex
|
||||
@@ -211,15 +212,14 @@ class IsolatedMacVlans:
|
||||
ip -{p} addr add {addr}/{prefix_length} dev {ifname}
|
||||
""", check=True)
|
||||
|
||||
|
||||
def traceroute(self, addr):
|
||||
res=self.runsh(f"""
|
||||
res = self.runsh(f"""
|
||||
set -ex
|
||||
traceroute -n {addr}
|
||||
""", check=True)
|
||||
result=[]
|
||||
result = []
|
||||
for line in res.stdout.splitlines()[2:]:
|
||||
l=line.split()
|
||||
l = line.split()
|
||||
result.append(l)
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user