diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 42d3a75..f20ca66 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -37,7 +37,7 @@ jobs: - metadata - metacli - agent - - netns + - vpc uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} diff --git a/cmd/netns/main.go b/cmd/netns/main.go deleted file mode 100644 index e1729f7..0000000 --- a/cmd/netns/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "git.g3e.fr/syonad/two/internal/netns" -) - -var ( - netns_name = flag.String("netns", "", "Network namespace à faire") - action = flag.String("action", "", "Action a faire") -) - -func main() { - flag.Parse() - - switch *action { - case "create": - err := netns.Create(*netns_name) - if err != nil { - fmt.Println(err) - } - case "delete": - err := netns.Delete(*netns_name) - if err != nil { - fmt.Println(err) - } - case "check": - if netns.Exist(*netns_name) { - fmt.Printf("netns %s exist\n", *netns_name) - } else { - fmt.Printf("netns %s do not exist\n", *netns_name) - } - default: - fmt.Printf("Available commande:\n - create\n - delete\n - check\n") - os.Exit(1) - } -} diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go new file mode 100644 index 0000000..52d8133 --- /dev/null +++ b/cmd/vpc/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "flag" + "fmt" + "os" + + configuration "git.g3e.fr/syonad/two/internal/config/agent" + "git.g3e.fr/syonad/two/internal/vpc" + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" +) + +var ( + netns = flag.String("netns", "", "Network namespace à faire") + name = flag.String("name", "", "interface name") + action = flag.String("action", "", "Action a faire") + conf_file = flag.String("conf", "/etc/two/agent.yml", "configuration file") +) + +var DB *badger.DB + +func main() { + flag.Parse() + + conf, err := configuration.LoadConfig(*conf_file) + if err != nil { + fmt.Println(err) + return + } + + DB = kv.InitDB(kv.Config{ + Path: conf.Database.Path, + }, false) + defer DB.Close() + + switch *action { + case "create": + kv.AddInDB(DB, "vpc/"+*name+"/state", "creating") + if err := vpc.CreateVPC(DB, *name); err != nil { + fmt.Println(err) + } + case "delete": + kv.AddInDB(DB, "vpc/"+*name+"/state", "deleting") + if err := vpc.DeleteVPC(DB, *name); err != nil { + fmt.Println(err) + } + if state, err := kv.GetFromDB(DB, "vpc/"+*name+"/state"); err != nil { + fmt.Println(err) + os.Exit(1) + } else if state == "deleted" { + kv.DeleteInDB(DB, "vpc/"+*name) + } + default: + fmt.Printf("Available commande:\n - create\n - delete\n - check\n") + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index 26bd137..7430e72 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,8 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/vishvananda/netlink v1.3.1 // indirect + github.com/vishvananda/netns v0.0.5 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect diff --git a/go.sum b/go.sum index 0d19489..73d16f3 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,10 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= +github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= @@ -51,6 +55,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= diff --git a/internal/netif/bridge.go b/internal/netif/bridge.go new file mode 100644 index 0000000..a4754a3 --- /dev/null +++ b/internal/netif/bridge.go @@ -0,0 +1,38 @@ +package netif + +import ( + "github.com/vishvananda/netlink" +) + +func CreateBridge(name string, mtu int) error { + br := &netlink.Bridge{ + LinkAttrs: netlink.LinkAttrs{ + Name: name, + MTU: mtu, + }, + } + + if err := netlink.LinkAdd(br); err != nil { + return err + } + + if err := netlink.LinkSetUp(br); err != nil { + return err + } + + return nil +} + +func BridgeSetMaster(iface, bridge string) error { + link, err := netlink.LinkByName(iface) + if err != nil { + return err + } + + br, err := netlink.LinkByName(bridge) + if err != nil { + return err + } + + return netlink.LinkSetMaster(link, br) +} diff --git a/internal/netif/delete.go b/internal/netif/delete.go new file mode 100644 index 0000000..9b06c55 --- /dev/null +++ b/internal/netif/delete.go @@ -0,0 +1,13 @@ +package netif + +import ( + "github.com/vishvananda/netlink" +) + +func DeleteLink(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkDel(link) +} diff --git a/internal/netif/upDown.go b/internal/netif/upDown.go new file mode 100644 index 0000000..6d27cc2 --- /dev/null +++ b/internal/netif/upDown.go @@ -0,0 +1,21 @@ +package netif + +import ( + "github.com/vishvananda/netlink" +) + +func LinkSetUp(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkSetUp(link) +} + +func LinkSetDown(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkSetDown(link) +} diff --git a/internal/netif/veth.go b/internal/netif/veth.go new file mode 100644 index 0000000..0056c60 --- /dev/null +++ b/internal/netif/veth.go @@ -0,0 +1,48 @@ +package netif + +import ( + "fmt" + "runtime" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" +) + +func CreateVethToNetns(rootIf, nsIf, netnsPath string, mtu int) error { + // Obligatoire : netns lié au thread + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // Ouvrir le netns cible + ns, err := netns.GetFromPath(netnsPath) + if err != nil { + return fmt.Errorf("open netns: %w, %s", err, netnsPath) + } + defer ns.Close() + + // Créer le veth dans le netns courant + veth := &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{ + Name: rootIf, + MTU: mtu, + }, + PeerName: nsIf, + } + + if err := netlink.LinkAdd(veth); err != nil { + return fmt.Errorf("link add: %w", err) + } + + // Récupérer l'interface peer + peer, err := netlink.LinkByName(nsIf) + if err != nil { + return fmt.Errorf("peer not found: %w", err) + } + + // Déplacer le peer dans le netns cible + if err := netlink.LinkSetNsFd(peer, int(ns)); err != nil { + return fmt.Errorf("set ns: %w", err) + } + + return nil +} diff --git a/internal/vpc/create.go b/internal/vpc/create.go new file mode 100644 index 0000000..3c3ad87 --- /dev/null +++ b/internal/vpc/create.go @@ -0,0 +1,61 @@ +package vpc + +import ( + "git.g3e.fr/syonad/two/internal/netif" + "git.g3e.fr/syonad/two/internal/netns" + "git.g3e.fr/syonad/two/pkg/db/kv" + + "github.com/dgraph-io/badger/v4" +) + +func CreateVPC(db *badger.DB, name string) error { + // missing + // search data in db + // change state in db + + // create netns + if state, err := kv.GetFromDB(db, "vpc/"+name+"/state"); err != nil { + return err + } else if state == "creating" { + if err := netns.Create(name); err != nil { + return err + } + + // create veth public for this netns + if err := netif.CreateVethToNetns("veth"+name+"ext", "vethpublicint", "/var/run/netns/"+name, 9000); err != nil { + return err + } + + // create public bridge in netns + if err := netns.Call(name, func() error { + return netif.CreateBridge("br-public", 1500) + }); err != nil { + return err + } + + // set veth to ext public bridge + if err := netif.BridgeSetMaster("veth"+name+"ext", "br-public"); err != nil { + return err + } + + // set veth to int public bridge + if err := netns.Call(name, func() error { + return netif.BridgeSetMaster("vethpublicint", "br-public") + }); err != nil { + return err + } + + // set set ext veth up + if err := netif.LinkSetUp("veth" + name + "ext"); err != nil { + return nil + } + // set set int veth up + if err := netns.Call(name, func() error { + return netif.LinkSetUp("vethpublicint") + }); err != nil { + return err + } + kv.AddInDB(db, "vpc/"+name+"/state", "created") + } + return nil +} diff --git a/internal/vpc/delete.go b/internal/vpc/delete.go new file mode 100644 index 0000000..a05e807 --- /dev/null +++ b/internal/vpc/delete.go @@ -0,0 +1,26 @@ +package vpc + +import ( + "git.g3e.fr/syonad/two/internal/netif" + "git.g3e.fr/syonad/two/internal/netns" + "git.g3e.fr/syonad/two/pkg/db/kv" + + "github.com/dgraph-io/badger/v4" +) + +func DeleteVPC(db *badger.DB, name string) error { + if state, err := kv.GetFromDB(db, "vpc/"+name+"/state"); err != nil { + return err + } else if state == "deleting" { + if err := netif.DeleteLink(name + "-ext"); err != nil { + return err + } + + if err := netns.Delete(name); err != nil { + return err + } + kv.AddInDB(db, "vpc/"+name+"/state", "deleted") + } + + return nil +}