Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux: add lag support and bonding plugin for non-lag cases #1624

Open
wants to merge 46 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a44affc
Linux: add lag support (borrowed from frr)
jbemmel Dec 8, 2024
352c0d2
Refactored, move lag bond creation to linux.j2
jbemmel Dec 8, 2024
a64fb60
Move to MLAG PR
jbemmel Dec 8, 2024
1bf6110
Undo changes to image version
jbemmel Dec 8, 2024
34f52f5
Move FRR bond logic to generic Linux template
jbemmel Dec 8, 2024
7910184
Update docs
jbemmel Dec 10, 2024
0a84671
Adjust title
jbemmel Dec 10, 2024
8926656
Add iproute2 for good measure (in case we ever change the Ubuntu base…
jbemmel Dec 10, 2024
b100be6
Use single brackets that work with 'sh' shell too
jbemmel Dec 10, 2024
eebe516
Update test case - with a bond should be the same as without, modulo …
jbemmel Dec 10, 2024
0858461
Treat lag links with a VLAN as LAN, not p2p
jbemmel Dec 10, 2024
f55c560
In case of active-standby mlag, do create the interface (else link be…
jbemmel Dec 10, 2024
0b80781
lag: Remove active-backup as a valid value
jbemmel Dec 11, 2024
f9dc794
Remove special handling of active-backup in lag module
jbemmel Dec 11, 2024
5fd5c33
Replace active-standby lag with bonding plugin
jbemmel Dec 11, 2024
9f819d8
Start of a bonding plugin for Linux active-standby bonds
jbemmel Dec 12, 2024
95f8d2d
bonding - data model extensions
jbemmel Dec 12, 2024
732e3b9
Reuse lag module create_bond_dev macro for bonding plugin
jbemmel Dec 12, 2024
becb920
For frr, simply defer to linux.j2
jbemmel Dec 12, 2024
5c3fb69
Reformat attributes section
jbemmel Dec 12, 2024
6cdc4df
Fix missing )
jbemmel Dec 12, 2024
8cec816
bonding: Restore p2p link
jbemmel Dec 12, 2024
77f94c4
Rename neighbor interfaces
jbemmel Dec 12, 2024
8682d9a
Add lag/bonding param to macro
jbemmel Dec 12, 2024
3a88fbb
Set default params={}
jbemmel Dec 12, 2024
556c0f1
bonding - define default mode
jbemmel Dec 12, 2024
1cb4cea
bonding - set intf down before up
jbemmel Dec 12, 2024
c844d13
Include lag changes from latest PR
jbemmel Dec 15, 2024
1bba22f
Only configure xmit_hash_policy when needed
jbemmel Dec 15, 2024
f31c698
Also include bonding plugin modes
jbemmel Dec 15, 2024
05c3030
Fix trailing spaces
jbemmel Dec 15, 2024
4ef1127
Cleanup, shorten line length
jbemmel Dec 15, 2024
21eaede
Update error
jbemmel Dec 15, 2024
45855f5
Add bonding priority parameter
jbemmel Dec 15, 2024
bde450a
Add 'primary' option to select a link as primary
jbemmel Dec 15, 2024
780a022
Final touches
jbemmel Dec 15, 2024
d64f767
Add docs
jbemmel Dec 15, 2024
3b6d4f6
Fix clab configuration case; don't create bond devices twice
jbemmel Dec 15, 2024
fe428ab
Undo changes
jbemmel Dec 15, 2024
2a5721f
Install both ethtool and iproute2
jbemmel Dec 15, 2024
7ee9bbd
Undo merge with LAG PR
jbemmel Dec 15, 2024
b001e10
Undo merge
jbemmel Dec 15, 2024
b8afe68
Remove duplicate case
jbemmel Dec 15, 2024
42717da
Undo change in ifindex matching, rework test case
jbemmel Dec 15, 2024
ba639a6
Set device down before changing bond master
jbemmel Dec 15, 2024
e4439bf
Rename test case
jbemmel Dec 15, 2024
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
4 changes: 4 additions & 0 deletions docs/caveats.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ We're not testing Fortinet implementation as part of the regular integration tes
* Junos cannot have more than one loopback interface per routing instance. Using **loopback** links on Junos devices will result in configuration errors.
* Junos configuration template configures BFD timers within routing protocol configuration, not on individual interfaces

(caveats-linux)=
## Generic Linux lag module caveats
* The lag module requires the `ip` command to be available on the Linux host

(caveats-vptx)=
## Juniper vPTX

Expand Down
3 changes: 2 additions & 1 deletion docs/module/lag.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ LAG is currently supported on these platforms:
| Cumulus 5.x (NVUE) | ✅ | ✅ | ❌ | ❌ |
| Dell OS10 | ✅ | ✅ | ✅ | ✅ |
| FRR | ✅ | ✅ | ❌ | ❌ |
| Generic Linux hosts [❗](caveats-linux) | ✅ | ✅ | ❌ | ❌ |

## Parameters

Expand All @@ -31,7 +32,7 @@ The following parameters can be set on individual links:

* **lag.members**: Mandatory list of links that form the LAG. It uses the [same format as the topology **links** list](link-formats).
* **lag.ifindex**: Optional parameter that controls the naming of the LAG (bonding, port-channel) interface.
* **lag.mlag**: Optional Boolean or dict with peer link parameters; see [below](mlag)
* **lag.mlag**: Optional dict with peer link parameters; see [below](mlag)

This configuration module creates a virtual link with the link type set to **lag** between the **lag.members** and appends the links described in the **lag.members** list to the topology **links** list.

Expand Down
1 change: 1 addition & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
plugins/bgp.domain.md
plugins/bgp.session.md
plugins/bgp.policy.md
plugins/bonding.md
plugins/ebgp.multihop.md
plugins/bgp.originate.md
plugins/check.config.md
Expand Down
66 changes: 66 additions & 0 deletions docs/plugins/bonding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
(plugin-bonding)=
# Host-side link bonding

Linux networking has long supported *bonding*, the ability to use multiple links simultaneously. Netlab supports bonding with LACP through the *lag* module,
this plugin adds support for the other bonding modes (that don't require any special configuration on peers)

```eval_rst
.. contents:: Table of Contents
:depth: 2
:local:
:backlinks: none
```

## Using the Plugin

* Add `plugin: [ bonding ]` to the lab topology.
* Include the **bonding.ifindex** attribute in any links that need to be bonded

### Supported attributes

The plugin adds the following attributes:
* **bonding.mode** (string, one of active-backup, balance-tlb, or balance-alb) -- the bonding mode to use, default `active-backup`

Additional interface level attributes:
* **bonding.ifindex** (int,mandatory) -- the interface index for the bonding device; links with matching ifindex are bonded together
* **bonding.primary** (bool) -- optional flag to mark this interface as primary, default *False*

## Examples

(active-backup-bonding)=
### Connect a host to a pair of switches using active-backup bonding

```yaml
plugin: [ bonding ]

bonding.mode: active-backup # Default

vlans:
v1:

groups:
_auto_create: True
hosts:
members: [ h1 ]
device: linux
switches:
members: [ s1, s2 ]
module: [ vlan ]

links:
- s1:
s2:
vlan.trunk: [ v1 ]

# Bonded interfaces eth1/eth2
- s1:
h1:
bonding.ifindex: 1
- s2:
h1:
bonding:
ifindex: 1
primary: True # Use this interface as primary
```

Note how there are no bonding specific modules enabled on the switches
11 changes: 11 additions & 0 deletions netsim/ansible/templates/initial/linux/ubuntu.j2
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,21 @@ if systemctl is-active --quiet lldpd.service; then
else
if "$NEED_APT_UPDATE"; then
apt-get update -qq
NEED_APT_UPDATE=
fi
apt-get install -qq lldpd
fi

{% if 'lag' in module|default([]) %}
#
# Install ethtool and iproute2(ip) for lag support
#
if "$NEED_APT_UPDATE"; then
apt-get update -qq
fi
apt-get install -qq ethtool iproute2
{% endif %}

cat <<CONFIG >/etc/lldpd.d/system.conf
configure lldp tx-interval 30
configure lldp tx-hold 3
Expand Down
9 changes: 7 additions & 2 deletions netsim/ansible/templates/initial/linux/vanilla.j2
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% from "lag/linux.j2" import create_bond_dev with context %}

### One-Shot configuration (non-Ubuntu VM or container)
#
# Disable IPv4 and IPv6 forwarding
Expand All @@ -24,9 +26,12 @@ ip -6 addr add {{ loopback.ipv6 }} dev lo
{% endif %}
{% endif %}
#
# Interface addressing
# Interface addressing, create any bond devices
#
{% for l in interfaces|default([]) %}
{% if l.type in ['lag','bond'] %}
{{ create_bond_dev(l) }}
{% endif %}
ip link set dev {{ l.ifname }} up
{% if l.ipv4 is defined %}
set +e
Expand All @@ -41,7 +46,7 @@ ip -6 addr del {{ l.ipv6 }} dev {{ l.ifname }} 2>/dev/null
set -e
ip -6 addr add {{ l.ipv6 }} dev {{ l.ifname }}
{% endif %}
{% if l.mtu is defined %}
{% if l.mtu is defined and l.type!='lag' %}
ip link set {{ l.ifname }} mtu {{ l.mtu }}
{% endif %}
{% endfor %}
Expand Down
43 changes: 1 addition & 42 deletions netsim/ansible/templates/lag/frr.j2
Original file line number Diff line number Diff line change
@@ -1,42 +1 @@
#!/bin/bash
#
set -e # Exit immediately when any command fails
#
{% if node_provider != 'clab' %}
modprobe bonding miimon=100 mode=802.3ad lacp_rate=fast
{% endif %}
#
# Create bonds for LAGs, if any. Requires kernel bonding module loaded
#
{% for l in interfaces if 'lag' in l %}
{% if l.type=='lag' %}
{% set _m = l.lag.mode|default(lag.mode) %}
{% if _m=="802.3ad" %}
{% set _lacp = l.lag.lacp|default(lag.lacp) %}
{% set lacp_act = 'off' if _lacp=='off' else 'on' %}
{% set lacp_rate = (' lacp_rate ' + _lacp) if _lacp!='off' else '' %}
{% set _m = _m + " xmit_hash_policy encap3+4" + lacp_rate %}
{% if node_provider == 'clab' %}
{% set _m = _m + " lacp_active " + lacp_act %}
{% endif %}
{% endif %}
ip link add dev {{l.ifname}} type bond mode {{_m}}
{% endif %}
ip link set dev {{ l.ifname }} down
{% endfor %}

{% for l in interfaces if 'lag' in l and l.type != 'lag' %}
{% if l.type=='p2p' %}
{% if node_provider != 'clab' %}
ethtool -s {{ l.ifname }} autoneg off speed 1000 duplex full
{% endif %}
ip link set dev {{ l.ifname }} master {%
for i in interfaces if i.type=='lag' and i.linkindex==l.lag._parentindex %}{{ i.ifname }}
{% endfor %}
{% endif %}
ip link set dev {{ l.ifname }} up
{% endfor %}
{% for l in interfaces if 'lag' in l and l.type == 'lag' %}
ip link set dev {{ l.ifname }} up
{% endfor %}
exit 0
{% include "linux.j2" %}
52 changes: 52 additions & 0 deletions netsim/ansible/templates/lag/linux.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{% macro create_bond_dev(l) %}
{% if l.type in ['lag','bond'] %}
{% set _m = l.lag.mode|default(l.bonding.mode|default("802.3ad")) %}
{% if _m=="802.3ad" %}
{% set _lacp = l.lag.lacp|default('fast') %}
{% set lacp_act = 'off' if _lacp=='off' else 'on' %}
{% set lacp_rate = (' lacp_rate ' + _lacp) if _lacp!='off' else '' %}
{% set _m = _m + lacp_rate %}
{% if node_provider == 'clab' %}
{% set _m = _m + " lacp_active " + lacp_act %}
{% endif %}
{% elif l.bonding.primary is defined %}
{% set _m = _m + " primary " + l.bonding.primary %}
{% endif %}
{% if _m in ["802.3ad","balance-xor","balance-alb","balance-tlb"] %}
{% set _m = _m + " xmit_hash_policy encap3+4" %}
{% endif %}
{% if node_provider != 'clab' %}
#
# Make sure 'bonding' module is loaded
#
if [ ! -e /sys/module/bonding ]; then
modprobe bonding miimon=100 mode=802.3ad lacp_rate=fast
fi
{% endif %}
if [ ! -e /sys/class/net/{{l.ifname}} ]; then
ip link add dev {{l.ifname}} type bond mode {{ _m }}
fi
{% endif %}
{% endmacro -%}
#!/bin/bash
#
set -e # Exit immediately when any command fails
#
# Bond devices are created by 'initial' module - add members
#
{% for l in interfaces if 'lag' in l and l.type != 'lag' %}
{% if l.type=='p2p' %}
{% if node_provider != 'clab' %}
ethtool -s {{ l.ifname }} autoneg off speed 1000 duplex full
{% endif %}
ip link set dev {{ l.ifname }} down
ip link set dev {{ l.ifname }} master {%
for i in interfaces if i.type=='lag' and i.linkindex==l.lag._parentindex %}{{ i.ifname }}
{% endfor %}
{% endif %}
ip link set dev {{ l.ifname }} up
{% endfor %}
{% for l in interfaces if 'lag' in l and l.type == 'lag' %}
ip link set dev {{ l.ifname }} up
{% endfor %}
exit 0
3 changes: 2 additions & 1 deletion netsim/augment/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,8 @@ def transform(link_list: typing.Optional[Box], defaults: Box, nodes: Box, pools:
continue

set_link_bridge_name(link,defaults)
link_default_pools = ['p2p','lan'] if link.type in ['p2p','lag'] else ['lan']
link_default_pools = ['p2p','lan'] if link.type=='p2p' or (
link.type=='lag' and not 'vlan' in link) else ['lan']
assign_link_prefix(link,link_default_pools,pools,nodes,link._linkname)
copy_link_gateway(link,nodes)
assign_interface_addresses(link,pools,nodes,defaults)
Expand Down
3 changes: 3 additions & 0 deletions netsim/devices/linux.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
description: Generic Linux host
interface_name: eth{ifindex}
lag_interface_name: "bond{lag.ifindex}"
mgmt_if: eth0
role: host
features:
Expand All @@ -9,6 +10,8 @@ features:
ipv6: true
server: true
relay: true
lag:
jbemmel marked this conversation as resolved.
Show resolved Hide resolved
passive: False
libvirt:
image: generic/ubuntu2004
group_vars:
Expand Down
25 changes: 25 additions & 0 deletions netsim/extra/bonding/defaults.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# bonding plugin attributes
#
---
bonding:
mode: active-backup # Default bond mode

devices:
linux:
features.bonding: True
frr:
features.bonding: True

attributes:
global:
bonding:
# Subset of Linux bonding modes that use autonomous ports and no LACP
mode: { type: str, valid_values: [ active-backup, balance-tlb, balance-alb ] }
node:
bonding:
mode:
interface:
bonding:
ifindex: { type: int, min_value: 0, _required: True }
mode: { copy: global }
primary: bool # Optional flag to use this interface as primary for bonding
1 change: 1 addition & 0 deletions netsim/extra/bonding/frr.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% include linux.j2 %}
23 changes: 23 additions & 0 deletions netsim/extra/bonding/linux.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% from "templates/lag/linux.j2" import create_bond_dev with context %}
#!/bin/bash

set -e

# Check if the 'ip' command is available, if not install it
if ! command -v ip 2>&1 >/dev/null
then
echo "Trying to install the 'ip' and 'ethtool' commands..."
apt-get -qq update
apt-get -qq install ethtool iproute2
fi

{# Bonding device is created by 'initial' module #}
{% for intf in interfaces|default([]) if intf.bonding.members is defined %}
ip link set dev {{ intf.ifname }} down
{% for member in intf.bonding.members %}
ip link set dev {{ member }} down
ip link set dev {{ member }} master {{ intf.ifname }}
ip link set dev {{ member }} up
{% endfor %}
ip link set dev {{ intf.ifname }} up
{% endfor %}
Loading
Loading