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

New link struct - Vxlan #1532

Merged
merged 44 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7bb5cd4
init
steiler Aug 16, 2023
11a03a1
push vxlan interface to container, rename and bring it up
steiler Aug 17, 2023
376c0e3
implement vxlan-stitch
steiler Aug 18, 2023
0827764
update doc
steiler Aug 29, 2023
0721747
remove vethcleanup and replace with general remove on links
steiler Aug 30, 2023
1719074
add debug log message
steiler Aug 30, 2023
a5fad50
fix test
steiler Aug 30, 2023
1f69cd7
vxlan tests
steiler Aug 30, 2023
127e3da
protect from race
steiler Aug 30, 2023
73bbd91
please deepsource
steiler Aug 30, 2023
85433b5
tools vxlan create to also use new link struct
steiler Sep 7, 2023
65cfc01
Merge branch 'main' into vxlanNewLinkStruct
hellt Sep 30, 2023
30cdcf1
added vxlan test to ci
hellt Sep 30, 2023
b51def3
set mtu in srl config only if is not the default 9500 values
hellt Oct 1, 2023
c57a0c2
move func to netlink utils
hellt Oct 1, 2023
5784bf0
fix descr
hellt Oct 1, 2023
3c45511
additional comments to funcs
hellt Oct 1, 2023
96dcc43
capitilize MTU
hellt Oct 1, 2023
5d3ed47
Make Endpoints accessible for LinkVeth struct
hellt Oct 1, 2023
54863c4
remove temp container in cleanup
hellt Oct 1, 2023
f012b82
make cases look less busy
hellt Oct 1, 2023
dbec975
capitalize
hellt Oct 1, 2023
ab45cdb
change default vxlan port
hellt Oct 1, 2023
3d89049
some renaming to keep func names consistent
hellt Oct 2, 2023
14b4161
set udp port to default if not set
hellt Oct 2, 2023
2a4b777
refactored startup and overlay config handling
hellt Oct 2, 2023
52d182c
remove log message
hellt Oct 2, 2023
ddfc256
refactor vxlan test using native clab constructs
hellt Oct 2, 2023
f3d263f
silence complexity check
hellt Oct 2, 2023
a95c2df
increase connectivity timer for tests
hellt Oct 2, 2023
dda79fb
added step to verify vxlan link params and skip traffic test in CI
hellt Oct 4, 2023
b2a903a
use link aliases for long names
hellt Oct 4, 2023
1079743
use the right link
hellt Oct 4, 2023
1fc47c0
started refactoring vxlan stitched test
hellt Oct 5, 2023
de394ed
use linear host link resolving process
hellt Oct 5, 2023
f49fe78
adapt stitch tests
hellt Oct 5, 2023
a6475d6
use any to check for netnsid in ci
hellt Oct 5, 2023
1ab2dc1
fix link deletion
steiler Oct 6, 2023
8458f0b
reorg
steiler Oct 6, 2023
5d23d12
please deepsource
steiler Oct 6, 2023
f7965ff
carve out GetRouteForIP helper func
hellt Oct 6, 2023
6d6ebb8
removed vxlan params (learning l2/3 miss
hellt Oct 6, 2023
485d6be
parallelize vxlan tests
hellt Oct 6, 2023
19dc2f1
added logname parser func
hellt Oct 6, 2023
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
12 changes: 11 additions & 1 deletion .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,14 @@ jobs:
path: ./tests/coverage/*
retention-days: 7

# create a job that downloads coverage artifact and uses codecov to upload it
vxlan-tests:
uses: ./.github/workflows/vxlan-tests.yml
needs:
- unit-test
- staticcheck
- build-containerlab

# a job that downloads coverage artifact and uses codecov to upload it
coverage:
runs-on: ubuntu-22.04
needs:
Expand All @@ -418,6 +425,7 @@ jobs:
- ceos-basic-tests
- srlinux-basic-tests
- ixiac-one-basic-tests
- vxlan-tests
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -473,11 +481,13 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v')
needs:
- docs-test
- unit-test
- smoke-tests
- ceos-basic-tests
- srlinux-basic-tests
- ixiac-one-basic-tests
- ext-container-tests
- vxlan-tests
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/vxlan-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: vxlan-test

"on":
workflow_call:

jobs:
vxlan-tests:
runs-on: ubuntu-22.04
strategy:
matrix:
runtime:
- "docker"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/download-artifact@v3
with:
name: containerlab

- name: Move containerlab to usr/bin
run: sudo mv ./containerlab /usr/bin/containerlab && sudo chmod a+x /usr/bin/containerlab

- uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: pip
cache-dependency-path: "tests/requirements.txt"

- name: Install robotframework
run: |
pip install -r tests/requirements.txt

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Run tests
run: |
bash ./tests/rf-run.sh ${{ matrix.runtime }} ./tests/08-vxlan/

# upload test reports as a zip file
- uses: actions/upload-artifact@v3
if: always()
with:
name: 08-vxlan-log
path: ./tests/out/*.html

# upload coverage report from unit tests, as they are then
# merged with e2e tests coverage
- uses: actions/upload-artifact@v3
if: always()
with:
name: coverage
path: ./tests/coverage/*
retention-days: 7
66 changes: 30 additions & 36 deletions clab/clab.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,14 @@ func (c *CLab) DeleteNodes(ctx context.Context, workers uint, serialNodes map[st
close(concurrentChan)
close(serialChan)

// also call delete on the special nodes
for _, n := range c.GetSpecialLinkNodes() {
err := n.Delete(ctx)
if err != nil {
log.Warn(err)
}
}

wg.Wait()
}

Expand Down Expand Up @@ -663,38 +671,9 @@ func (c *CLab) GetNodeRuntime(contName string) (runtime.ContainerRuntime, error)
return nil, fmt.Errorf("could not find a container matching name %q", contName)
}

// VethCleanup iterates over links found in clab topology to initiate removal of dangling veths
// in host networking namespace or attached to linux bridge.
// See https://github.com/srl-labs/containerlab/issues/842 for the reference.
func (c *CLab) VethCleanup(ctx context.Context) error {
hostBasedEndpoints := []links.Endpoint{}

// collect the endpoints of regular nodes
for _, n := range c.Nodes {
if n.Config().IsRootNamespaceBased || n.Config().NetworkMode == "host" {
hostBasedEndpoints = append(hostBasedEndpoints, n.GetEndpoints()...)
}
}

// collect the endpoints of the fake nodes
hostBasedEndpoints = append(hostBasedEndpoints, links.GetHostLinkNode().GetEndpoints()...)
hostBasedEndpoints = append(hostBasedEndpoints, links.GetMgmtBrLinkNode().GetEndpoints()...)

var joinedErr error
for _, ep := range hostBasedEndpoints {
// finally remove all the collected endpoints
log.Debugf("removing endpoint %s", ep.String())
err := ep.Remove()
if err != nil {
joinedErr = errors.Join(joinedErr, err)
}
}

return joinedErr
}
Comment on lines -666 to -694
Copy link
Member

Choose a reason for hiding this comment

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

we need to find a solution for this removed func. While working on the vlxan-stich I see that when I remove the lab, the host link remains.
This was the reason to have this func.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The Remove() function is implemented on the vxlan link and forwarded to the local endpoint. The local endpoint is actually a generic endpoint. My thinking as of now is, that the removal is triggered but executed in the wrong namespace, that of the container not in the host namespace.
Let me verify.


// ResolveLinks resolves raw links to the actual link types and stores them in the CLab.Links map.
func (c *CLab) ResolveLinks() error {
// GetLinkNodes returns all CLab.Nodes nodes as links.Nodes enriched with the special nodes - host and mgmt-net.
// The CLab nodes are copied to a new map and thus clab.Node interface is converted to link.Node.
func (c *CLab) GetLinkNodes() map[string]links.Node {
// resolveNodes is a map of all nodes in the topology
// that is artificially created to combat circular dependencies.
// If no circ deps were in place we could've used c.Nodes map instead.
Expand All @@ -704,17 +683,32 @@ func (c *CLab) ResolveLinks() error {
resolveNodes[k] = v
}

// add the virtual host and mgmt-bridge nodes to the resolve nodes
specialNodes := c.GetSpecialLinkNodes()
for _, n := range specialNodes {
resolveNodes[n.GetShortName()] = n
}

return resolveNodes
}

// GetSpecialLinkNodes returns a map of special nodes that are used to resolve links.
// Special nodes are host and mgmt-bridge nodes that are not typically present in the topology file
// but are required to resolve links.
func (c *CLab) GetSpecialLinkNodes() map[string]links.Node {
// add the virtual host and mgmt-bridge nodes to the resolve nodes
specialNodes := map[string]links.Node{
"host": links.GetHostLinkNode(),
"mgmt-net": links.GetMgmtBrLinkNode(),
}
for _, n := range specialNodes {
resolveNodes[n.GetShortName()] = n
}

return specialNodes
}

// ResolveLinks resolves raw links to the actual link types and stores them in the CLab.Links map.
func (c *CLab) ResolveLinks() error {
resolveParams := &links.ResolveParams{
Nodes: resolveNodes,
Nodes: c.GetLinkNodes(),
MgmtBridgeName: c.Config.Mgmt.Bridge,
NodesFilter: c.nodeFilter,
}
Expand Down
24 changes: 0 additions & 24 deletions clab/netlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package clab
import (
"fmt"
"net"
"strings"

"github.com/containernetworking/plugins/pkg/ns"
"github.com/google/uuid"
Expand Down Expand Up @@ -316,26 +315,3 @@ func genIfName() string {
s, _ := uuid.New().MarshalText() // .MarshalText() always return a nil error
return string(s[:8])
}

// GetLinksByNamePrefix returns a list of links whose name matches a prefix.
func GetLinksByNamePrefix(prefix string) ([]netlink.Link, error) {
// filtered list of interfaces
if prefix == "" {
return nil, fmt.Errorf("prefix is not specified")
}
var fls []netlink.Link

ls, err := netlink.LinkList()
if err != nil {
return nil, err
}
for _, l := range ls {
if strings.HasPrefix(l.Attrs().Name, prefix) {
fls = append(fls, l)
}
}
if len(fls) == 0 {
return nil, fmt.Errorf("no links found by specified prefix %s", prefix)
}
return fls, nil
}
5 changes: 0 additions & 5 deletions cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,5 @@ func destroyLab(ctx context.Context, c *clab.CLab) (err error) {
}
}

// Remove any dangling veths from host netns or bridges
err = c.VethCleanup(ctx)
if err != nil {
return fmt.Errorf("error during veth cleanup procedure, %w", err)
}
return err
}
55 changes: 44 additions & 11 deletions cmd/vxlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
package cmd

import (
"context"
"fmt"
"net"

"github.com/jsimonetti/rtnetlink/rtnl"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/srl-labs/containerlab/clab"
"github.com/srl-labs/containerlab/links"
"github.com/srl-labs/containerlab/utils"
"github.com/vishvananda/netlink"
)

Expand Down Expand Up @@ -57,6 +59,9 @@ var vxlanCreateCmd = &cobra.Command{
Use: "create",
Short: "create vxlan interface",
RunE: func(cmd *cobra.Command, args []string) error {

ctx := context.Background()

if _, err := netlink.LinkByName(cntLink); err != nil {
return fmt.Errorf("failed to lookup link %q: %v",
cntLink, err)
Expand All @@ -76,20 +81,48 @@ var vxlanCreateCmd = &cobra.Command{
parentDev = r.Interface.Name
}

vxlanCfg := clab.VxLAN{
Name: "vx-" + cntLink,
ID: vxlanID,
ParentIf: parentDev,
Remote: net.ParseIP(vxlanRemote),
MTU: vxlanMTU,
UDPPort: vxlanUDPPort,
vxlraw := &links.LinkVxlanRaw{
Remote: vxlanRemote,
Vni: vxlanID,
ParentInterface: parentDev,
LinkCommonParams: links.LinkCommonParams{
MTU: vxlanMTU,
},
UdpPort: vxlanUDPPort,
NoLearning: true,
NoL2Miss: true,
NoL3Miss: true,
LinkType: links.LinkTypeVxlanStitch,
Endpoint: *links.NewEndpointRaw(
"host",
cntLink,
"",
),
}

rp := &links.ResolveParams{
Nodes: map[string]links.Node{
"host": links.GetHostLinkNode(),
},
VxlanIfaceNameOverwrite: cntLink,
}

if err := clab.AddVxLanInterface(vxlanCfg); err != nil {
link, err := vxlraw.Resolve(rp)
if err != nil {
return err
}

return clab.BindIfacesWithTC(vxlanCfg.Name, cntLink)
var vxl *links.VxlanStitched
var ok bool
if vxl, ok = link.(*links.VxlanStitched); !ok {
return fmt.Errorf("not a VxlanStitched link")
}

err = vxl.DeployWithExistingVeth(ctx)
if err != nil {
return err
}
return nil
},
}

Expand All @@ -100,7 +133,7 @@ var vxlanDeleteCmd = &cobra.Command{
var ls []netlink.Link
var err error

ls, err = clab.GetLinksByNamePrefix(delPrefix)
ls, err = utils.GetLinksByNamePrefix(delPrefix)

if err != nil {
return err
Expand Down
39 changes: 38 additions & 1 deletion docs/manual/topo-def-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,51 @@ In comparison to the veth type, no bridge or other namespace is required to be r
- node: <NodeA-Name> # mandatory
interface: <NodeA-Interface-Name> # mandatory
mac: <NodeA-Interface-Mac> # optional
host-interface: <interface-name # mandatory
host-interface: <interface-name> # mandatory
mtu: <link-mtu> # optional
vars: <link-variables> # optional (used in templating)
labels: <link-labels> # optional (used in templating)
```

The `host-interface` parameter defines the name of the veth interface in the host's network namespace.

###### vxlan
The vxlan type results in a vxlan tunnel interface that is created in the host namespace and subsequently pushed into the nodes network namespace.

```yaml
links:
- type: vxlan
endpoint: # mandatory
node: <Node-Name> # mandatory
interface: <Node-Interface-Name> # mandatory
mac: <Node-Interface-Mac> # optional
remote: <Remote-VTEP-IP> # mandatory
vni: <VNI> # mandatory
udp-port: <VTEP-UDP-Port> # mandatory
mtu: <link-mtu> # optional
vars: <link-variables> # optional (used in templating)
labels: <link-labels> # optional (used in templating)
```

###### vxlan-stitched
The vxlan-stitched type results in a veth pair linking the host namespace and the nodes namespace and a vxlan tunnel that also terminates in the host namespace.
In addition to these interfaces, tc rules are being provisioned to stitch the vxlan tunnel and the host based veth interface together.

```yaml
links:
- type: vxlan-stitch
endpoint: # mandatory
node: <Node-Name> # mandatory
interface: <Node-Interface-Name> # mandatory
mac: <Node-Interface-Mac> # optional
remote: <Remote-VTEP-IP> # mandatory
vni: <VNI> # mandatory
udp-port: <VTEP-UDP-Port> # mandatory
mtu: <link-mtu> # optional
vars: <link-variables> # optional (used in templating)
labels: <link-labels> # optional (used in templating)
```

#### Kinds

Kinds define the behavior and the nature of a node, it says if the node is a specific containerized Network OS, virtualized router or something else. We go into details of kinds in its own [document section](kinds/index.md), so here we will discuss what happens when `kinds` section appears in the topology definition:
Expand Down
6 changes: 6 additions & 0 deletions links/endpoint_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ type EndpointBridge struct {
EndpointGeneric
}

func NewEndpointBridge(eg *EndpointGeneric) *EndpointBridge {
return &EndpointBridge{
EndpointGeneric: *eg,
}
}

func (e *EndpointBridge) Verify(p *VerifyLinkParams) error {
var errs []error
err := CheckEndpointUniqueness(e)
Expand Down
Loading
Loading