{"id":16139400,"url":"https://github.com/networkop/xdp-xconnect","last_synced_at":"2025-03-18T16:31:09.633Z","repository":{"id":43125748,"uuid":"343565597","full_name":"networkop/xdp-xconnect","owner":"networkop","description":"Cross-connect Linux interfaces with XDP","archived":false,"fork":false,"pushed_at":"2022-03-16T21:19:38.000Z","size":83,"stargazers_count":67,"open_issues_count":1,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-16T22:01:44.759Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/networkop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-01T21:44:01.000Z","updated_at":"2025-03-14T21:59:54.000Z","dependencies_parsed_at":"2022-08-23T18:10:50.877Z","dependency_job_id":null,"html_url":"https://github.com/networkop/xdp-xconnect","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/networkop%2Fxdp-xconnect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/networkop%2Fxdp-xconnect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/networkop%2Fxdp-xconnect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/networkop%2Fxdp-xconnect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/networkop","download_url":"https://codeload.github.com/networkop/xdp-xconnect/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244259917,"owners_count":20424635,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T23:48:57.621Z","updated_at":"2025-03-18T16:31:09.327Z","avatar_url":"https://github.com/networkop.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cross-connect Linux interfaces with XDP redirect\n\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/networkop/xdp-xconnect)](https://goreportcard.com/report/github.com/networkop/xdp-xconnect)\n[![GoDoc](https://godoc.org/istio.io/istio?status.svg)](https://pkg.go.dev/github.com/networkop/xdp-xconnect)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![Build Status](https://github.com/networkop/xdp-xconnect/actions/workflows/ci.yml/badge.svg)\n\n![](icon.png)\n\n`xdp-xconnect` daemon is a long-running process that uses a YAML file as its configuration API. For example:\n\n```yaml\nlinks:\n    eth0: tap0\n    veth2: veth3\n```\n\nGiven the above YAML file, local Linux interfaces will be cross-connected (`eth0\u003c-\u003etap0` and `veth2\u003c-\u003eveth3`) with the following command:\n\n```\nsudo xdp-xconnect -conf config.yaml\n```\n\nThis command will block, listening to any changes to the file and will perform \"warm\" reconfigurations on the fly.\n\n\u003e Note: due to its nature (loading eBPF progs, maps and interacting with netlink), `xdp-xconnect` requires `NET_ADMIN` capabilities (root privileges are used for simplicity).\n\n## Theory\n\nEach pair of interfaces will have an eBPF program attached to its XDP hook and will use `bpf_redirect_map` eBPF [helper function](https://man7.org/linux/man-pages/man7/bpf-helpers.7.html) to redirect packets directly to the receive queue of the peer interface. For mode details read [this](https://github.com/xdp-project/xdp-tutorial/tree/master/packet03-redirecting).\n\n\n## Prerequisites\n\nLinux Kernel version \u003e 4.14 (introduced veth XDP support)\nGo\n\n## Installation\n\nBinary:\n\n```\ngo install github.com/networkop/xdp-xconnect@latest\n```\n\nDocker:\n\n```\ndocker pull networkop/xdp-xconnect\n```\n\n## Usage\n\nBinary:\n\n```\nsudo xdp-xconnect -conf input.yaml\n```\n\nDocker:\n\n```\ndocker run --net host -v$(pwd):/xc --privileged networkop/xdp-xconnect -conf /xc/input.yaml\n```\n\nGo code:\n\n\n```go\nimport \"github.com/networkop/xdp-xconnect/pkg/xdp\"\n\nfunc main() {\n\n    input := map[string]string{\"eth1\":\"tap1\"}\n\n    app, err := xdp.NewXconnectApp(input)\n    // handle error\n\n    updateCh := make(chan map[string]string, 1)\n\n    app.Launch(ctx, updateCh)\n}\n```\n\n## Demo\n\nCreate three network namespaces and three veth links:\n\n\n```\nsudo ip link add dev xconnect-1 type veth peer name xc-1\nsudo ip link add dev xconnect-2 type veth peer name xc-2\nsudo ip link add dev xconnect-3 type veth peer name xc-3\nsudo ip netns add ns1\nsudo ip netns add ns2\nsudo ip netns add ns3\n```\n\nMove one side of each veth link into a correponding namespace and configure an IP address from `169.254.0.0/16` subnet:\n\n```\nsudo ip link set xc-1 netns ns1\nsudo ip link set xc-2 netns ns2\nsudo ip link set xc-3 netns ns3\nsudo ip netns exec ns1 ip addr add 169.254.1.10/24 dev xc-1\nsudo ip netns exec ns2 ip addr add 169.254.1.20/24 dev xc-2\nsudo ip netns exec ns3 ip addr add 169.254.1.30/24 dev xc-3\n```\n\nBring up both sides of veth links\n\n```\nsudo ip link set dev xconnect-1 up\nsudo ip link set dev xconnect-2 up\nsudo ip link set dev xconnect-3 up\nsudo ip netns exec ns1 ip link set dev xc-1 up\nsudo ip netns exec ns2 ip link set dev xc-2 up\nsudo ip netns exec ns3 ip link set dev xc-3 up\n```\n\nAt this point there should be no connectivity between IPs in individual namespaces, i.e. the following commands will return no output:\n\n```\nsudo ip netns exec ns1 ping 169.254.1.20 \u0026\nsudo ip netns exec ns1 ping 169.254.1.30 \u0026\n```\n\nStart the `xdp-xconnect` app with and connect `xconnect-1` to itself (see [first.yaml](testdata/first.yaml)):\n\n```\ncp testdata/first.yaml testdata/input.yaml\nsudo go run ./main.go -conf testdata/input.yaml \u0026\n\n2021/03/03 20:08:41 Parsing config file: testdata/input.yaml\n2021/03/03 20:08:41 App configuration: {Links:map[xconnect-1:xconnect-1]}\n```\n\nNow update the configuration by replacing the file to connect the first two interfaces (see [second.yaml](testdata/second.yaml)):\n\n\n```\ncp testdata/second.yaml testdata/input.yaml\n\n2021/03/03 20:12:16 Parsing config file: testdata/input.yaml\n2021/03/03 20:12:16 Error parsing the configuration file: EOF\n2021/03/03 20:12:16 Parsing config file: testdata/input.yaml\n2021/03/03 20:12:16 App configuration: {Links:map[xconnect-1:xconnect-2]}\n64 bytes from 169.254.1.20: icmp_seq=113 ttl=64 time=0.068 ms\n64 bytes from 169.254.1.20: icmp_seq=114 ttl=64 time=0.068 ms\n64 bytes from 169.254.1.20: icmp_seq=115 ttl=64 time=0.075 ms\n```\n\nThis proves that the first and second links are now connected. Now swap the connection over to the third link (see [third.yaml](testdata/third.yaml)):\n\n```\ncp testdata/third.yaml testdata/input.yaml\n\n2021/03/03 20:13:53 Parsing config file: testdata/input.yaml\n2021/03/03 20:13:53 Error parsing the configuration file: EOF\n2021/03/03 20:13:53 Parsing config file: testdata/input.yaml\n2021/03/03 20:13:53 App configuration: {Links:map[xconnect-1:xconnect-3]\n64 bytes from 169.254.1.30: icmp_seq=207 ttl=64 time=0.075 ms\n64 bytes from 169.254.1.30: icmp_seq=208 ttl=64 time=0.070 ms\n64 bytes from 169.254.1.30: icmp_seq=209 ttl=64 time=0.071 ms\n64 bytes from 169.254.1.30: icmp_seq=210 ttl=64 time=0.071 ms\n```\n\nPing replies now come from the third link. Let's see what happens if we provide the malformed input (see [bad.yaml](testdata/bad.yaml))\n\n```\ncp testdata/bad.yaml testdata/input.yaml\n\n2021/03/03 20:15:46 Parsing config file: testdata/input.yaml\n2021/03/03 20:15:46 App configuration: {Links:map[xconnect-1:xconnect-asd]}\n2021/03/03 20:15:46 Error updating eBPF: 1 error occurred:\n\t* Link not found\n\n64 bytes from 169.254.1.30: icmp_seq=317 ttl=64 time=0.065 ms\n64 bytes from 169.254.1.30: icmp_seq=318 ttl=64 time=0.065 ms\n64 bytes from 169.254.1.30: icmp_seq=319 ttl=64 time=0.064 m\n```\n\nThe app detected the error and cross-connect continues working with its last known configuration. Finally, we can terminate the application which will cleanup all of the configured state:\n\n\n```\nfg\n[1]  + 1095444 running    sudo go run ./main.go -conf testdata/input.yaml\n^C\n2021/03/03 20:16:44 Received syscall:interrupt\n2021/03/03 20:16:44 ctx.Done\n```\n\nDon't forget to cleanup test interfaces and namespaces:\n\n```\nsudo ip link del dev xconnect-1\nsudo ip link del dev xconnect-2\nsudo ip link del dev xconnect-3\nsudo ip netns del ns1\nsudo ip netns del ns2\nsudo ip netns del ns3\n```\n\n\n\n## Additional Reading and References\n\nhttps://github.com/xdp-project/xdp-tutorial\n\nhttps://docs.cilium.io/en/stable/bpf/\n\nhttps://qmonnet.github.io/whirl-offload/2020/04/12/llvm-ebpf-asm/\n\nhttps://github.com/takehaya/goxdp-template\n\nhttps://github.com/hrntknr/nfNat\n\nhttps://github.com/takehaya/Vinbero\n\nhttps://github.com/tcfw/vpc\n\nhttps://github.com/florianl/tc-skeleton\n\nhttps://github.com/cloudflare/rakelimit\n\nhttps://github.com/b3a-dev/ebpf-geoip-demo\n\nhttps://github.com/lmb/ship-bpf-with-go\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetworkop%2Fxdp-xconnect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetworkop%2Fxdp-xconnect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetworkop%2Fxdp-xconnect/lists"}