diff --git a/cmd/agent/main.go b/cmd/agent/main.go index b61bb6f..faa6139 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -36,7 +36,7 @@ func main() { apiAddr := fmt.Sprintf("%s:%d", cfg.Api.Address, cfg.Api.Port) promAddr := fmt.Sprintf("%s:%d", cfg.Prometheus.Address, cfg.Prometheus.Port) - d := dispatcher.New(q, db) + d := dispatcher.New(q, db, cfg.Interfaces) go agentapi.New(d, db).Start(apiAddr) go promserver.Start(promAddr, registry) diff --git a/internal/api/agent/models.go b/internal/api/agent/models.go index bd09c76..e826082 100644 --- a/internal/api/agent/models.go +++ b/internal/api/agent/models.go @@ -13,19 +13,19 @@ type SubnetCreateRequest struct { Name string `json:"name"` VPC string `json:"vpc"` VxlanID int `json:"vxlan_id"` - LocalIP string `json:"local_ip"` + IfaceType string `json:"iface_type"` GatewayIP string `json:"gateway_ip"` CIDR string `json:"cidr"` } type Subnet struct { - Name string `json:"name"` - State string `json:"state"` - VPC string `json:"vpc"` - VxlanID int `json:"vxlan_id"` - LocalIP string `json:"local_ip"` - GatewayIP string `json:"gateway_ip"` - CIDR string `json:"cidr"` + Name string `json:"name"` + State string `json:"state"` + VPC string `json:"vpc"` + VxlanID int `json:"vxlan_id"` + LocalIface string `json:"local_iface"` + GatewayIP string `json:"gateway_ip"` + CIDR string `json:"cidr"` } type ErrorResponse struct { diff --git a/internal/api/agent/subnets.go b/internal/api/agent/subnets.go index b251c3c..263c9ce 100644 --- a/internal/api/agent/subnets.go +++ b/internal/api/agent/subnets.go @@ -31,16 +31,16 @@ func (s *Server) postSubnet(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid request body"}) return } - if req.Name == "" || req.VPC == "" || req.LocalIP == "" || req.GatewayIP == "" || req.CIDR == "" { + if req.Name == "" || req.VPC == "" || req.IfaceType == "" || req.GatewayIP == "" || req.CIDR == "" { w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(ErrorResponse{Error: "name, vpc, local_ip, gateway_ip and cidr are required"}) + json.NewEncoder(w).Encode(ErrorResponse{Error: "name, vpc, iface_type, gateway_ip and cidr are required"}) return } s.dispatcher.Dispatch(dispatcher.CreateSubnetCommand{ Name: req.Name, VPC: req.VPC, VxlanID: req.VxlanID, - LocalIP: req.LocalIP, + IfaceType: req.IfaceType, GatewayIP: req.GatewayIP, CIDR: req.CIDR, }) @@ -50,9 +50,7 @@ func (s *Server) postSubnet(w http.ResponseWriter, r *http.Request) { State: "creating", VPC: req.VPC, VxlanID: req.VxlanID, - LocalIP: req.LocalIP, GatewayIP: req.GatewayIP, CIDR: req.CIDR, }) } - diff --git a/internal/dispatcher/dispatcher.go b/internal/dispatcher/dispatcher.go index 937adf2..f240245 100644 --- a/internal/dispatcher/dispatcher.go +++ b/internal/dispatcher/dispatcher.go @@ -8,21 +8,22 @@ import ( ) type Command interface { - Execute(db *badger.DB) error + Execute(db *badger.DB, interfaces map[string]string) error } type Dispatcher struct { - queue *worker.Queue - db *badger.DB + queue *worker.Queue + db *badger.DB + interfaces map[string]string } -func New(queue *worker.Queue, db *badger.DB) *Dispatcher { - return &Dispatcher{queue: queue, db: db} +func New(queue *worker.Queue, db *badger.DB, interfaces map[string]string) *Dispatcher { + return &Dispatcher{queue: queue, db: db, interfaces: interfaces} } func (d *Dispatcher) Dispatch(cmd Command) { d.queue.Submit(func() { - if err := cmd.Execute(d.db); err != nil { + if err := cmd.Execute(d.db, d.interfaces); err != nil { log.Printf("command error (%T): %v", cmd, err) } }) diff --git a/internal/dispatcher/subnet_commands.go b/internal/dispatcher/subnet_commands.go index b23949e..dcb0398 100644 --- a/internal/dispatcher/subnet_commands.go +++ b/internal/dispatcher/subnet_commands.go @@ -14,16 +14,20 @@ type CreateSubnetCommand struct { Name string VPC string VxlanID int - LocalIP string + IfaceType string GatewayIP string CIDR string } -func (c CreateSubnetCommand) Execute(db *badger.DB) error { +func (c CreateSubnetCommand) Execute(db *badger.DB, interfaces map[string]string) error { + localIface, ok := interfaces[c.IfaceType] + if !ok { + return fmt.Errorf("unknown iface_type %q: not found in config", c.IfaceType) + } kv.AddInDB(db, "subnet/"+c.Name+"/state", "creating") kv.AddInDB(db, "subnet/"+c.Name+"/vpc", c.VPC) kv.AddInDB(db, "subnet/"+c.Name+"/vxlan_id", strconv.Itoa(c.VxlanID)) - kv.AddInDB(db, "subnet/"+c.Name+"/local_ip", c.LocalIP) + kv.AddInDB(db, "subnet/"+c.Name+"/local_iface", localIface) kv.AddInDB(db, "subnet/"+c.Name+"/gateway_ip", c.GatewayIP) kv.AddInDB(db, "subnet/"+c.Name+"/cidr", c.CIDR) return subnet.CreateSubnet(db, c.Name) @@ -33,7 +37,7 @@ type DeleteSubnetCommand struct { Name string } -func (c DeleteSubnetCommand) Execute(db *badger.DB) error { +func (c DeleteSubnetCommand) Execute(db *badger.DB, _ map[string]string) error { kv.AddInDB(db, "subnet/"+c.Name+"/state", "deleting") if err := subnet.DeleteSubnet(db, c.Name); err != nil { fmt.Println(err) diff --git a/internal/dispatcher/vpc_commands.go b/internal/dispatcher/vpc_commands.go index 195b014..2c316a3 100644 --- a/internal/dispatcher/vpc_commands.go +++ b/internal/dispatcher/vpc_commands.go @@ -10,7 +10,7 @@ type CreateVPCCommand struct { Name string } -func (c CreateVPCCommand) Execute(db *badger.DB) error { +func (c CreateVPCCommand) Execute(db *badger.DB, _ map[string]string) error { kv.AddInDB(db, "vpc/"+c.Name+"/state", "creating") return vpc.CreateVPC(db, c.Name) } @@ -19,7 +19,7 @@ type DeleteVPCCommand struct { Name string } -func (c DeleteVPCCommand) Execute(db *badger.DB) error { +func (c DeleteVPCCommand) Execute(db *badger.DB, _ map[string]string) error { kv.AddInDB(db, "vpc/"+c.Name+"/state", "deleting") if err := vpc.DeleteVPC(db, c.Name); err != nil { return err diff --git a/internal/netif/vxlan.go b/internal/netif/vxlan.go index eacae7c..6523f37 100644 --- a/internal/netif/vxlan.go +++ b/internal/netif/vxlan.go @@ -1,20 +1,22 @@ package netif import ( - "net" - "github.com/vishvananda/netlink" ) -func CreateVxlan(name string, vxlanID int, localIP net.IP) error { +func CreateVxlan(name string, vxlanID int, localIface string) error { + link, err := netlink.LinkByName(localIface) + if err != nil { + return err + } vxlan := &netlink.Vxlan{ LinkAttrs: netlink.LinkAttrs{ Name: name, }, - VxlanId: vxlanID, - Port: 4789, - SrcAddr: localIP, - Learning: false, + VxlanId: vxlanID, + Port: 4789, + VtepDevIndex: link.Attrs().Index, + Learning: false, } return netlink.LinkAdd(vxlan) } diff --git a/internal/subnet/create.go b/internal/subnet/create.go index 9bfe02a..1ed514e 100644 --- a/internal/subnet/create.go +++ b/internal/subnet/create.go @@ -40,13 +40,9 @@ func CreateSubnet(db *badger.DB, subnetName string) error { return fmt.Errorf("parse vxlan_id: %w", err) } - localIPStr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/local_ip") + localIface, err := kv.GetFromDB(db, "subnet/"+subnetName+"/local_iface") if err != nil { - return fmt.Errorf("get local_ip: %w", err) - } - localIP := net.ParseIP(localIPStr) - if localIP == nil { - return fmt.Errorf("invalid local_ip: %s", localIPStr) + return fmt.Errorf("get local_iface: %w", err) } gatewayIPStr, err := kv.GetFromDB(db, "subnet/"+subnetName+"/gateway_ip") @@ -90,7 +86,7 @@ func CreateSubnet(db *badger.DB, subnetName string) error { } // vxlan - if err := netif.CreateVxlan(vxlanIface, vxlanID, localIP); err != nil { + if err := netif.CreateVxlan(vxlanIface, vxlanID, localIface); err != nil { return fmt.Errorf("create vxlan: %w", err) }