Skip to content

Commit

Permalink
Fix vxlan tools link deployment (#2213)
Browse files Browse the repository at this point in the history
* added debug with vscode notes

* check for error during tools vxlan create on ep.deploy and do not create veth link when host is used

* deploy stitched link instead of using ep.Deploy

* remove unused params

* remove unused tc code
  • Loading branch information
hellt authored Sep 30, 2024
1 parent ce81640 commit f4ca6b9
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 110 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ build-debug:
mkdir -p $(BIN_DIR)
go build -o $(BINARY) -gcflags=all="-N -l" -race -cover main.go

build-dlv-debug:
mkdir -p $(BIN_DIR)
go build -o $(BINARY) -gcflags=all="-N -l" main.go


build-with-podman:
mkdir -p $(BIN_DIR)
Expand Down
92 changes: 0 additions & 92 deletions clab/tc.go

This file was deleted.

10 changes: 6 additions & 4 deletions cmd/vxlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var vxlanCmd = &cobra.Command{
var vxlanCreateCmd = &cobra.Command{
Use: "create",
Short: "create vxlan interface",
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
ctx := context.Background()

if _, err := netlink.LinkByName(cntLink); err != nil {
Expand Down Expand Up @@ -108,8 +108,10 @@ var vxlanCreateCmd = &cobra.Command{
return fmt.Errorf("not a VxlanStitched link")
}

for _, ep := range vxl.GetEndpoints() {
ep.Deploy(ctx)
// deploy the vxlan with existing link. The first endpoint is the host endpoint
err = vxl.DeployWithExistingVeth(ctx, vxl.GetEndpoints()[0])
if err != nil {
return err
}

return nil
Expand All @@ -119,7 +121,7 @@ var vxlanCreateCmd = &cobra.Command{
var vxlanDeleteCmd = &cobra.Command{
Use: "delete",
Short: "delete vxlan interface",
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
var ls []netlink.Link
var err error

Expand Down
88 changes: 88 additions & 0 deletions docs/manual/dev/debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Debugging

There is a point where you realized that putting another `fmt.Println("here100500")` is not enough. You need to have a debugger to inspect the state of your program.

## Debugging in VSCode

Debugging containerlab in VSCode relies on the [Go Dlv integration with VSCode](https://github.com/golang/vscode-go/wiki/debugging) and can be split into two categories:

1. Debugging using the root user
2. Debugging using the non-`root` user

Since containerlab requires the superuser privileges to run, the workflow will be slightly different depending on if operate as a `root` user already or not.

We will document the workflow for the latter (non-root user) case, as this is the most common scenario. In the non-root user case a developer should create a debug configuration file and optionally a task file to build the binary. The reason for the build step is rooted in a fact that we would need to build the binary first as our user, and then the debugger will be called as a `root` user and execute the binary with the debug mode.

### Create a debug configuration

The debug configuration defined in the `launch.json` file will contain the important fields such as `asRoot` and `console`, both needed for the debugging as a root user.

Here is an example of a configuration file that launches `containerlab tools vxlan create` command in the debug mode:

```json
{
"version": "0.2.0",
"configurations": [
{
"name": "tools vxlan create",
"type": "go",
"request": "launch",
"mode": "exec",
"console": "integratedTerminal",
"asRoot": true,
"program": "${workspaceFolder}/bin/containerlab",
"args": [
"tools",
"vxlan",
"create",
"--remote",
"10.0.0.20",
"-l",
"ens3"
],
"preLaunchTask": "delete vx-ens3 interface",
}
]
}
```

The debug config is run in the `exec` mode, which means that the debugger expects a program to be built first. This is why we need to create a task file to build the binary first.

The build happens via the `preLaunchTask` field, that references the task in a `tasks.json` file.

### Create a task file to build the binary

The [task file](https://code.visualstudio.com/docs/editor/tasks) provides the means to define arbitrary tasks that can be executed via VSCode UI and as well hooked up in the debug configuration.

Here is a simple task file that contains two tasks - one is building the binary with the debug information, and the other is a simple command that removes a test interface that the `tools vxlan create` command creates. The only task you need is the build task, but we wanted to show you how to define additional tasks that might be required before your run containerlab in the debug mode to cleanup from the previous execution.

The dependencies between the tasks are defined in the `dependsOn` field, and this is how you can first build the binary and then run the preparation step.

```json
{
"version": "2.0.0",
"tasks": [
{
"label": "delete vx-ens3 interface",
"type": "shell",
"command": "sudo ip link delete vx-ens3",
"presentation": {
"reveal": "always",
"panel": "new"
},
"dependsOn": "make build-dlv-debug",
"problemMatcher": []
},
{
"label": "make build-dlv-debug",
"type": "shell",
"command": "make",
"args": [
"build-dlv-debug"
],
}
]
}
```

Reach out via [Discord](https://discord.gg/vAyddtaEV9) to get help if you get stuck.
33 changes: 23 additions & 10 deletions links/link_vxlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func (lr *LinkVxlanRaw) Resolve(params *ResolveParams) (Link, error) {
}
}

// resolveStitchedVEthComponent creates the veth link and return it, the endpoint that is
// supposed to be stitched is returned seperately for further processing.
// resolveStitchedVEthComponent creates the veth link and returns it, the endpoint that is
// supposed to be stitched is returned separately for further processing.
func (lr *LinkVxlanRaw) resolveStitchedVEthComponent(params *ResolveParams) (*LinkVEth, Endpoint, error) {
var err error

Expand Down Expand Up @@ -85,16 +85,29 @@ func (lr *LinkVxlanRaw) resolveStitchedVxlan(params *ResolveParams) (Link, error
return nil, err
}

// prepare the veth struct
vethLink, stitchEp, err := lr.resolveStitchedVEthComponent(params)
if err != nil {
return nil, err
var vethLink *LinkVEth
var stitchEp Endpoint

// if the endpoint is host, we don't need to create the veth link
// the stitch endpoint is just a host endpoint with the passed interface name
if lr.Endpoint.Node == "host" {
// a fake endpoint used only to print the host interface name in the outputs
// it is not deployed as it meant to exist
epHost := NewEndpointHost(NewEndpointGeneric(vxlanLink.localEndpoint.GetNode(), params.VxlanIfaceNameOverwrite, nil))
vethLink, stitchEp, err = nil, epHost, nil
} else {
// otherwise we need to create the veth link
vethLink, stitchEp, err = lr.resolveStitchedVEthComponent(params)
if err != nil {
return nil, err
}

}

// return the stitched vxlan link
stitchedLink := NewVxlanStitched(vxlanLink, vethLink, stitchEp)
vxlanStitchedLink := NewVxlanStitched(vxlanLink, vethLink, stitchEp)

return stitchedLink, nil
return vxlanStitchedLink, nil
}

func (lr *LinkVxlanRaw) resolveVxlan(params *ResolveParams, stitched bool) (*LinkVxlan, error) {
Expand All @@ -109,7 +122,7 @@ func (lr *LinkVxlanRaw) resolveVxlan(params *ResolveParams, stitched bool) (*Lin
}

ip := net.ParseIP(lr.Remote)
// if the returned ip is nil, an error occured.
// if the returned ip is nil, an error occurred.
// we consider, that we maybe have a textual hostname
// e.g. dns name so we try to resolve the string next
if ip == nil {
Expand Down Expand Up @@ -182,7 +195,7 @@ func (lr *LinkVxlanRaw) resolveLocalEndpoint(stitched bool, params *ResolveParam
vxlanRawEp.Iface = fmt.Sprintf("vx-%s", params.VxlanIfaceNameOverwrite)
}

// in the stiched vxlan mode we create vxlan interface in the host node namespace
// in the stitched vxlan mode we create vxlan interface in the host node namespace
vxlanRawEp.Node = "host"
vxlanRawEp.MAC = ""

Expand Down
8 changes: 4 additions & 4 deletions links/link_vxlan_stitched.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ type VxlanStitched struct {
vxlanLink *LinkVxlan
vethLink *LinkVEth
// the veth does not distinguish between endpoints. but we
// need to know which endpoint is the one used for
// stitching therefore we get that endpoint seperately
// need to know which endpoint is the one used for
// stitching therefore we get that endpoint separately
vethStitchEp Endpoint
}

Expand All @@ -33,14 +33,14 @@ func NewVxlanStitched(vxlan *LinkVxlan, veth *LinkVEth, vethStitchEp Endpoint) *
return vxlanStitched
}

// DeployWithExistingVeth provisons the stitched vxlan link whilst the
// DeployWithExistingVeth provisions the stitched vxlan link whilst the
// veth interface does already exist, hence it is not created as part of this
// deployment.
func (l *VxlanStitched) DeployWithExistingVeth(ctx context.Context, ep Endpoint) error {
return l.internalDeploy(ctx, ep, true)
}

// Deploy provisions the stitched vxlan link with all its underlaying sub-links.
// Deploy provisions the stitched vxlan link with all its underlying sub-links.
func (l *VxlanStitched) Deploy(ctx context.Context, ep Endpoint) error {
return l.internalDeploy(ctx, ep, false)
}
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ nav:
- manual/dev/index.md
- Documentation: manual/dev/doc.md
- Testing: manual/dev/test.md
- Debugging: manual/dev/debug.md
- Command reference:
- deploy: cmd/deploy.md
- destroy: cmd/destroy.md
Expand Down

0 comments on commit f4ca6b9

Please sign in to comment.