Compare commits

..

2 commits

Author SHA1 Message Date
79eb8cc175
Merge branch 'feature-51'
All checks were successful
Documentation / publish (push) Successful in 1m28s
2026-10-05 20:15:19 +02:00
a73bf97697
f-51: netif: poser l'adresse VTEP locale des VXLAN #51
All checks were successful
Documentation / publish (push) Successful in 2m55s
Release Pipeline / set-release-target (push) Successful in 3s
Release Pipeline / upload-assets (run-dnsmasq-in-netns.sh, scripts/run-dnsmasq-in-netns.sh) (push) Successful in 7s
Release Pipeline / checksums (push) Successful in 9s
Release Pipeline / upload-assets (agent.service, systemd/agent.service) (push) Successful in 8s
Release Pipeline / upload-assets (dhcp@.service, systemd/dhcp@.service) (push) Successful in 7s
Release Pipeline / upload-assets (dnsmasq@.service, systemd/dnsmasq@.service) (push) Successful in 7s
Release Pipeline / upload-assets (metadata@.service, systemd/metadata@.service) (push) Successful in 7s
Release Pipeline / upload-assets (run-dhcp-in-netns.sh, scripts/run-dhcp-in-netns.sh) (push) Successful in 7s
Release Pipeline / build (agent, amd64, linux) (push) Successful in 0s
Release Pipeline / build (dhcp, amd64, linux) (push) Successful in 0s
Release Pipeline / build (metadata, amd64, linux) (push) Successful in 0s
Release Pipeline / release (push) Successful in 32s
Release Pipeline / publish (push) Successful in 0s
Release Pipeline / build (push) Successful in 2m12s
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
2026-10-04 19:56:42 +02:00
2 changed files with 92 additions and 0 deletions

View file

@ -1,14 +1,31 @@
package netif
import (
"fmt"
"net"
"syscall"
"github.com/vishvananda/netlink"
)
const (
scopeUniverse = 0
addressSecondary = 0x01
)
func CreateVxlan(name string, vxlanID int, localIface string, mtu int) error {
link, err := netlink.LinkByName(localIface)
if err != nil {
return err
}
addrs, err := netlink.AddrList(link, syscall.AF_INET)
if err != nil {
return err
}
local, err := vtepAddress(localIface, addrs)
if err != nil {
return err
}
vxlan := &netlink.Vxlan{
LinkAttrs: netlink.LinkAttrs{
Name: name,
@ -17,7 +34,18 @@ func CreateVxlan(name string, vxlanID int, localIface string, mtu int) error {
VxlanId: vxlanID,
Port: 4789,
VtepDevIndex: link.Attrs().Index,
SrcAddr: local,
Learning: false,
}
return netlink.LinkAdd(vxlan)
}
func vtepAddress(iface string, addrs []netlink.Addr) (net.IP, error) {
for _, a := range addrs {
if a.IPNet == nil || a.IP.To4() == nil || a.Scope != scopeUniverse || a.Flags&addressSecondary != 0 {
continue
}
return a.IP.To4(), nil
}
return nil, fmt.Errorf("no primary global IPv4 address on %s for the VXLAN local endpoint", iface)
}

View file

@ -0,0 +1,64 @@
package netif
import (
"net"
"strings"
"testing"
"github.com/vishvananda/netlink"
)
func addr(cidr string, scope, flags int) netlink.Addr {
ip, network, err := net.ParseCIDR(cidr)
if err != nil {
panic(err)
}
network.IP = ip
return netlink.Addr{IPNet: network, Scope: scope, Flags: flags}
}
func TestVtepAddress_PicksThePrimaryGlobalIPv4(t *testing.T) {
addrs := []netlink.Addr{
addr("127.0.0.1/8", 254, 0),
addr("169.254.0.3/28", 0, 0x01),
addr("192.168.14.11/24", 0, 0x80),
addr("192.168.14.99/24", 0, 0x01),
}
got, err := vtepAddress("br-000000", addrs)
if err != nil || got.String() != "192.168.14.11" {
t.Errorf("vtepAddress = %v, %v, want 192.168.14.11", got, err)
}
}
func TestVtepAddress_SkipsLinkScopeAndSecondaryAddresses(t *testing.T) {
addrs := []netlink.Addr{
addr("169.254.0.3/28", 253, 0),
addr("192.168.14.99/24", 0, 0x01),
addr("192.168.14.12/24", 0, 0),
}
got, err := vtepAddress("br-000000", addrs)
if err != nil || got.String() != "192.168.14.12" {
t.Errorf("vtepAddress = %v, %v, want 192.168.14.12", got, err)
}
}
func TestVtepAddress_RefusesAnInterfaceWithoutUsableAddress(t *testing.T) {
for name, addrs := range map[string][]netlink.Addr{
"no address": nil,
"only secondary": {addr("192.168.14.99/24", 0, 0x01)},
"only link": {addr("169.254.0.3/28", 253, 0)},
"only IPv6": {addr("fd00::11/64", 0, 0)},
} {
_, err := vtepAddress("br-000000", addrs)
if err == nil || !strings.Contains(err.Error(), "no primary global IPv4 address on br-000000") {
t.Errorf("%s: error = %v", name, err)
}
}
}
func TestVtepAddress_ReturnsAFourByteAddress(t *testing.T) {
got, err := vtepAddress("br-000000", []netlink.Addr{addr("192.168.14.11/24", 0, 0)})
if err != nil || len(got) != 4 {
t.Errorf("vtepAddress = %v (%d bytes), %v", got, len(got), err)
}
}