diff --git a/cmd/evpn-test.go b/cmd/evpn-test.go index 748a158c..eacfaded 100644 --- a/cmd/evpn-test.go +++ b/cmd/evpn-test.go @@ -13,76 +13,769 @@ import ( "github.com/spf13/cobra" ) -// NewEvpnCommand tests the EVPN functionality command -func NewEvpnCommand() *cobra.Command { - var ( - addr string - ) + +func CreateLogicalBridge() *cobra.Command { + var addr string + var name string + var vlanID uint32 + var vni uint32 + cmd := &cobra.Command{ - Use: "evpn", - Aliases: []string{"g"}, - Short: "Tests DPU evpn functionality", - Args: cobra.NoArgs, + Use: "create-lb", + Short: "Create a logical bridge", + Long: "Create a logical bridge with the specified name, VLAN ID, and VNI", Run: func(cmd *cobra.Command, args []string) { - evpnClient, err := network.New(addr) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewBridge(addr) if err != nil { log.Fatalf("could create gRPC client: %v", err) } + defer cancel() - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + resp, err := evpnClient.CreateLogicalBridge(ctx, name, vlanID, vni) + if err != nil { + log.Fatalf("failed to create logical bridge: %v", err) + } + + log.Printf(" Created Logical Bridge \n name: %s,\n vlan: %u,\n vni: %u,\n status: %s\n", resp.GetName(), resp.GetSpec().GetVlanId(), + resp.GetSpec().GetVni(), resp.GetStatus()) + + }, + } + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the logical bridge") + cmd.Flags().Uint32VarP(&vlanID, "vlan-id", "v", 0, "Specify the VLAN ID") + cmd.Flags().Uint32VarP(&vni, "vni","i", 0, "Specify the VNI") + + cmd.MarkFlagRequired("addr") + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("vlan-id") + cmd.MarkFlagRequired("vni") + + return cmd +} +func DeleteLogicalBridge() *cobra.Command { + var addr string + var name string + var allow_missing bool + + cmd := &cobra.Command{ + Use: "delete-lb", + Short: "Delete a logical bridge", + Long: "Delete a logical bridge with the specified name", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewBridge(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } defer cancel() - // create all - obj0, err := evpnClient.CreateInterface(ctx) + resp, err := evpnClient.DeleteLogicalBridge(ctx, name, allow_missing) if err != nil { - log.Fatalf("could not create interface: %v", err) + log.Fatalf("failed to delete logical bridge: %v", err) } - log.Printf("%s", obj0) - obj1, err := evpnClient.CreateVpc(ctx) + + log.Printf("Deleted Logical Bridge: %s\n", resp) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().BoolVarP(&allow_missing, "allow_missing", "a",false, "Specify allow missing") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} +func GetLogicalBridge() *cobra.Command { + var addr string + var name string + + cmd := &cobra.Command{ + Use: "get-lb", + Short: "Show details of a logical bridge", + Long: "Show details of a logical bridge with the specified name", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewBridge(addr) if err != nil { - log.Fatalf("could not create vpc: %v", err) + log.Fatalf("could not create gRPC client: %v", err) } - log.Printf("%s", obj1) - obj11, err := evpnClient.CreateTunnel(ctx) + defer cancel() + + resp, err := evpnClient.GetLogicalBridge(ctx, name) if err != nil { - log.Fatalf("could not create vpc: %v", err) + log.Fatalf("failed to get logical bridge: %v", err) } - log.Printf("%s", obj11) - // get all - obj2, err := evpnClient.GetInterface(ctx) + + log.Printf(" Created Logical Bridge \n name: %s,\n vlan: %u,\n vni: %u,\n status: %s\n", resp.GetName(), resp.GetSpec().GetVlanId(), + resp.GetSpec().GetVni(), resp.GetStatus()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} + +func ListLogicalBridges() *cobra.Command { + var addr string + var pageSize int32 + var pageToken string + cmd := &cobra.Command{ + Use: "list-lbs", + Short: "Show details of all logical bridges", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewBridge(addr) if err != nil { - log.Fatalf("could not get interface: %v", err) + log.Fatalf("could not create gRPC client: %v", err) } - log.Printf("%s", obj2) - obj3, err := evpnClient.GetVpc(ctx) + defer cancel() + + for { + resp, err := evpnClient.ListLogicalBridges(ctx, pageSize, pageToken) + if err != nil { + log.Fatalf("Failed to get items: %v", err) + } + // Process the server response + for _, item := range resp.LogicalBridges { + log.Printf(" Created Logical Bridge \n name: %s,\n vlan: %u,\n vni: %u,\n status: %s\n", item.GetName(), item.GetSpec().GetVlanId(), + item.GetSpec().GetVni(), item.GetStatus()) + } + + // Check if there are more pages to retrieve + if resp.NextPageToken == "" { + // No more pages, break the loop + break + } + // Update the page token for the next request + pageToken = resp.NextPageToken + } + }, + } + + cmd.Flags().Int32VarP(&pageSize, "pagesize", "s", 0, "Specify page size") + cmd.Flags().StringVarP(&pageToken, "pagetoken", "t", "", "Specify the token") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + return cmd +} +func UpdateLogicalBridge() *cobra.Command { + var addr string + var name string + var update_mask []string + cmd := &cobra.Command{ + Use: "update-lb", + Short: "update the logical bridge", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewBridge(addr) if err != nil { - log.Fatalf("could not get vpc: %v", err) + log.Fatalf("could not create gRPC client: %v", err) } - log.Printf("%s", obj3) - obj33, err := evpnClient.GetTunnel(ctx) + defer cancel() + + resp, err := evpnClient.UpdateLogicalBridge(ctx, name, update_mask) if err != nil { - log.Fatalf("could not get vpc: %v", err) + log.Fatalf("failed to update logical bridge: %v", err) } - log.Printf("%s", obj33) - // delete all - obj4, err := evpnClient.DeleteInterface(ctx) + + log.Printf(" Updated Logical Bridge \n name: %s,\n vlan: %u,\n vni: %u,\n status: %s\n", resp.GetName(), resp.GetSpec().GetVlanId(), + resp.GetSpec().GetVni(), resp.GetStatus()) + }, + } + cmd.Flags().StringVar(&name, "name","", "name of the logical bridge") + cmd.Flags().StringSliceVar(&update_mask, "update-mask", nil, "update mask") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + return cmd + +} +func CreateBridgePort() *cobra.Command { + var addr string + var name string + var mac string + var bridgePortType string + var logicalBridges []string + + cmd := &cobra.Command{ + Use: "create-bp", + Short: "Create a bridge port", + Long: "Create a BridgePort with the specified name, MAC address, type, and VLAN IDs", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewPort(addr) if err != nil { - log.Fatalf("could not delete interface: %v", err) + log.Fatalf("could not create gRPC client: %v", err) } - log.Printf("%s", obj4) - obj5, err := evpnClient.DeleteVpc(ctx) + defer cancel() + // grpc call to create the bridge port + bridgePort, err := evpnClient.CreateBridgePort(ctx, name, mac, bridgePortType, logicalBridges) if err != nil { - log.Fatalf("could not delete vpc: %v", err) + log.Fatalf("could not create Bridge Port: %v", err) } - log.Printf("%s", obj5) - obj55, err := evpnClient.DeleteTunnel(ctx) + log.Printf("Created Bridge Port:\n status: %s\n, type: %s\n, name: %s\n, bridges: %s\n, mac: %s\n", bridgePort.GetStatus().GetOperStatus(), bridgePort.GetSpec().GetPtype(), + bridgePort.GetName(), bridgePort.GetSpec().GetLogicalBridges(), bridgePort.GetSpec().GetMacAddress()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().StringVar(&mac, "mac", "", "Specify the MAC address") + cmd.Flags().StringVarP(&bridgePortType, "type", "t", "", "Specify the type (access or trunk)") + cmd.Flags().StringSliceVar(&logicalBridges, "logicalBridges", []string{}, "Specify VLAN IDs (multiple values supported)") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + cmd.MarkFlagRequired("mac") + cmd.MarkFlagRequired("type") + + // Define allowed choices for the "type" Flag + cmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"access", "trunk"}, cobra.ShellCompDirectiveNoFileComp + }) + + return cmd +} + +func DeleteBridgePort() *cobra.Command { + var addr string + var name string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "delete-bp", + Short: "Delete a bridge port", + Long: "Delete a BridgePort with the specified name", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewPort(addr) if err != nil { - log.Fatalf("could not delete vpc: %v", err) + log.Fatalf("could not create gRPC client: %v", err) } - log.Printf("%s", obj55) + defer cancel() + + // grpc call to create the bridge port + _, err = evpnClient.DeleteBridgePort(ctx, name, allowMissing) + if err != nil { + log.Fatalf("DeleteBridgePort: Error occurred while deleting Bridge Port: %q", err) + } + log.Printf("Deleted BridgePort ") }, } - flags := cmd.Flags() - flags.StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "Specify if missing allowed") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + return cmd +} +func GetBridgePort() *cobra.Command { + var addr string + var name string + + cmd := &cobra.Command{ + Use: "get-bp", + Short: "Show details of a bridge port", + Long: "Show details of a BridgePort with the specified name", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewPort(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + bridgePort, err := evpnClient.GetBridgePort(ctx, name) + if err != nil { + log.Fatalf("GetBridgePort: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("Bridge Port:\n status: %s\n, type: %s\n, name: %s\n, bridges: %s\n, mac: %s\n", bridgePort.GetStatus().GetOperStatus(), bridgePort.GetSpec().GetPtype(), + bridgePort.GetName(), bridgePort.GetSpec().GetLogicalBridges(), bridgePort.GetSpec().GetMacAddress()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} +func ListBridgePorts() *cobra.Command { + var addr string + var pageSize int32 + var pageToken string + + cmd:= &cobra.Command{ + Use: "list-bps", + Short: "Show details of all bridge ports", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewPort(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + for { + resp, err := evpnClient.ListBridgePorts(ctx, pageSize, pageToken) + if err != nil { + log.Fatalf("Failed to get items: %v", err) + } + // Process the server response + for _, bridgePort := range resp.BridgePorts { + log.Printf("Bridge Port:\n status: %s\n, type: %s\n, name: %s\n, bridges: %s\n, mac: %s\n", bridgePort.GetStatus().GetOperStatus(), bridgePort.GetSpec().GetPtype(), + bridgePort.GetName(), bridgePort.GetSpec().GetLogicalBridges(), bridgePort.GetSpec().GetMacAddress()) + } + + // Check if there are more pages to retrieve + if resp.NextPageToken == "" { + // No more pages, break the loop + break + } + // Update the page token for the next request + pageToken = resp.NextPageToken + } + + }, + } + cmd.Flags().Int32VarP(&pageSize, "pagesize", "s", 0, "Specify page size") + cmd.Flags().StringVarP(&pageToken, "pagetoken", "t", "", "Specify the token") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + return cmd +} +func UpdateBridgePort() *cobra.Command { + var addr string + var name string + var update_mask []string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "update-bp", + Short: "Update the bridge port", + Long: "updates the Bridge Port with updated mask" , + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewPort(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + bridgePort, err := evpnClient.UpdateBridgePort(ctx, name,update_mask,allowMissing) + if err != nil { + log.Fatalf("UpdateBridgePort: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("Bridge Port:\n status: %s\n, type: %s\n, name: %s\n, bridges: %s\n, mac: %s\n", bridgePort.GetStatus().GetOperStatus(), bridgePort.GetSpec().GetPtype(), + bridgePort.GetName(), bridgePort.GetSpec().GetLogicalBridges(), bridgePort.GetSpec().GetMacAddress()) + }, + } + cmd.Flags().StringVar(&name, "name","", "name of the Bridge Port") + cmd.Flags().StringSliceVar(&update_mask, "update-mask", nil, "update mask") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "allow the missing") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + return cmd +} +func CreateVRF() *cobra.Command { + var addr string + var name string + var vni uint32 + var loopback string + var vtep string + + cmd := &cobra.Command{ + Use: "create-vrf", + Short: "Create a VRF", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewVRF(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + vrf, err := evpnClient.CreateVrf(ctx, name, vni, loopback, vtep) + if err != nil { + log.Fatalf("failed to create logical bridge: %v", err) + } + log.Printf("Created VRF with name: %s\n, vni : %u\n, vtep ip : %s\n, loopback ip: %s\n", vrf.GetName(), vrf.GetSpec().GetVni(), + vrf.GetSpec().GetVtepIpPrefix(), vrf.GetSpec().GetLoopbackIpPrefix()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Descriptive name") + cmd.Flags().Uint32VarP(&vni, "vni","v",0, "Must be unique ") + cmd.Flags().StringVar(&loopback, "loopback", "", "Loopback IP address") + cmd.Flags().StringVar(&vtep, "vtep", "", "VTEP IP address") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("vni") + cmd.MarkFlagRequired("loopback") + + return cmd +} + +func DeleteVRF() *cobra.Command { + var addr string + var name string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "delete-vrf", + Short: "Delete a VRF", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewVRF(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + _, err = evpnClient.DeleteVrf(ctx, name, allowMissing) + if err != nil { + log.Fatalf("DeleteVRF: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("Deleted VRF with VPort ID: %s\n", name ) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "Specify the name of the BridgePort") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + return cmd +} +func GetVRF() *cobra.Command { + var addr string + var name string + + cmd := &cobra.Command{ + Use: "get-vrf", + Short: "Show details of a VRF", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewVRF(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + vrf, err := evpnClient.GetVrf(ctx, name) + if err != nil { + log.Fatalf("DeleteVRF: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("VRF with name: %s\n, operation status: %d\n,vni : %u\n, vtep ip : %s\n, loopback ip: %s\n", vrf.GetName(), vrf.GetStatus().GetOperStatus(), + vrf.GetSpec().GetVni(), vrf.GetSpec().GetVtepIpPrefix(), vrf.GetSpec().GetLoopbackIpPrefix()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the vrf") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} +func ListVRFs() *cobra.Command { + var addr string + var pageSize int32 + var pageToken string + + cmd := &cobra.Command{ + Use: "list-vrfs", + Short: "Show details of all Vrfs", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewVRF(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + for { + resp, err := evpnClient.ListVrfs(ctx, pageSize, pageToken) + if err != nil { + log.Fatalf("Failed to get items: %v", err) + } + // Process the server response + for _, vrf := range resp.Vrfs { + log.Printf("VRF with name: %s\n, operation status: %d\n,vni : %u\n, vtep ip : %s\n, loopback ip: %s\n", vrf.GetName(), vrf.GetStatus().GetOperStatus(), + vrf.GetSpec().GetVni(), vrf.GetSpec().GetVtepIpPrefix(), vrf.GetSpec().GetLoopbackIpPrefix()) + } + + // Check if there are more pages to retrieve + if resp.NextPageToken == "" { + // No more pages, break the loop + break + } + // Update the page token for the next request + pageToken = resp.NextPageToken + } + }, + } + cmd.Flags().Int32VarP(&pageSize, "pagesize", "s", 0, "Specify page size") + cmd.Flags().StringVarP(&pageToken, "pagetoken", "t", "", "Specify the token") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + return cmd +} +func UpdateVRF() *cobra.Command { + var addr string + var name string + var update_mask []string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "update-vrf", + Short: "update the VRF", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewVRF(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + vrf, err := evpnClient.UpdateVrf(ctx, name, update_mask, allowMissing) + if err != nil { + log.Fatalf("GetBridgePort: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("Updated VRF with name: %s\n, operation status: %d\n,vni : %u\n, vtep ip : %s\n, loopback ip: %s\n", vrf.GetName(), vrf.GetStatus().GetOperStatus(), + vrf.GetSpec().GetVni(), vrf.GetSpec().GetVtepIpPrefix(), vrf.GetSpec().GetLoopbackIpPrefix()) + }, + } + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the vrf") + cmd.Flags().StringSliceVar(&update_mask, "update-mask", nil, "update mask") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "allow the missing") + + return cmd +} + +func CreateSVI() *cobra.Command { + var addr string + var name string + var vrf string + var logicalBridge string + var mac string + var gwIPs []string + var ebgp bool + var remoteAS uint32 + + cmd := &cobra.Command{ + Use: "create-svi", + Short: "Create a SVI", + Long: "Create an using name, vrf,logical bridges, mac, gateway ip's and enable bgp ", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewSVI(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + svi, err := evpnClient.CreateSvi(ctx, name, vrf, logicalBridge, mac, gwIPs, ebgp, remoteAS) + if err != nil { + log.Fatalf("failed to create logical bridge: %v", err) + } + + log.Printf("CreateSVI: Created SVI \n name: %s,\n status: %d,\n Vrf: %s,\n LogicalBridge: %s,\n MacAddress: %s,\n EnableBgp: %d,\n GwIPs: %s,\nremoteAS: %u\n", + svi.GetName(),svi.GetSpec().GetVrf(), svi.GetSpec().GetLogicalBridge(), svi.GetSpec().GetMacAddress(), svi.GetSpec().GetEnableBgp(), svi.GetSpec().GetGwIpPrefix(), svi.GetSpec().GetRemoteAs()) + }, + } + cmd.Flags().StringVar(&vrf, "vrf","", "Must be unique") + cmd.Flags().StringVar(&logicalBridge, "logicalBridge","", "Pair of vni and vlan_id must be unique") + cmd.Flags().StringVar(&mac, "mac", "", "GW MAC address, random MAC assigned if not specified") + cmd.Flags().StringSliceVar(&gwIPs, "gw-ips", nil, "List of GW IP addresses") + cmd.Flags().BoolVar(&ebgp, "ebgp", false, "Enable eBGP in VRF for tenants connected through this SVI") + cmd.Flags().Uint32VarP(&remoteAS, "remote-as","", 0, "The remote AS") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + + cmd.MarkFlagRequired("vrf") + cmd.MarkFlagRequired("logicalBridge") + cmd.MarkFlagRequired("mac") + cmd.MarkFlagRequired("gw-ips") + + return cmd +} +func DeleteSVI() *cobra.Command { + var addr string + var name string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "delete-svi", + Short: "Delete a SVI", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewSVI(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + _, err = evpnClient.DeleteSvi(ctx, name, allowMissing) + if err != nil { + log.Fatalf("failed to create logical bridge: %v", err) + } + + log.Printf("Deleted SVI ") + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "Specify the name of the BridgePort") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} +func GetSVI() *cobra.Command { + var addr string + var name string + + cmd := &cobra.Command{ + Use: "get-svi", + Short: "Show details of a SVI", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewSVI(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + svi, err := evpnClient.GetSvi(ctx, name) + if err != nil { + log.Fatalf("GetSVI: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("CreateSVI: Created SVI \n name: %s,\n status: %d,\n Vrf: %s,\n LogicalBridge: %s,\n MacAddress: %s,\n EnableBgp: %d,\n GwIPs: %s,\nremoteAS: %u\n", + svi.GetName(),svi.GetSpec().GetVrf(), svi.GetSpec().GetLogicalBridge(), svi.GetSpec().GetMacAddress(), svi.GetSpec().GetEnableBgp(), svi.GetSpec().GetGwIpPrefix(), svi.GetSpec().GetRemoteAs()) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Specify the name of the BridgePort") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.MarkFlagRequired("name") + + return cmd +} +func ListSVIs() *cobra.Command { + var addr string + var pageSize int32 + var pageToken string + + cmd := &cobra.Command{ + Use: "list-svis", + Short: "Show details of all SVIs", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewSVI(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + for { + resp, err := evpnClient.ListSvis(ctx, pageSize, pageToken) + if err != nil { + log.Fatalf("Failed to get items: %v", err) + } + // Process the server response + for _, svi := range resp.Svis { + log.Printf("CreateSVI: Created SVI \n name: %s,\n status: %d,\n Vrf: %s,\n LogicalBridge: %s,\n MacAddress: %s,\n EnableBgp: %d,\n GwIPs: %s,\nremoteAS: %u\n", + svi.GetName(),svi.GetSpec().GetVrf(), svi.GetSpec().GetLogicalBridge(), svi.GetSpec().GetMacAddress(), svi.GetSpec().GetEnableBgp(), svi.GetSpec().GetGwIpPrefix(), svi.GetSpec().GetRemoteAs()) + } + + // Check if there are more pages to retrieve + if resp.NextPageToken == "" { + // No more pages, break the loop + break + } + // Update the page token for the next request + pageToken = resp.NextPageToken + } + }, + } + + cmd.Flags().Int32VarP(&pageSize, "pageSize", "s", 0, "Specify the name of the BridgePort") + cmd.Flags().StringVarP(&pageToken, "pageToken", "p", "", "Specify the page token") + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + return cmd +} + +func UpdateSVI() *cobra.Command { + var addr string + var name string + var update_mask []string + var allowMissing bool + + cmd := &cobra.Command{ + Use: "update-svi", + Short: "update the SVI", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + evpnClient, err := network.NewSVI(addr) + if err != nil { + log.Fatalf("could not create gRPC client: %v", err) + } + defer cancel() + + // grpc call to create the bridge port + svi, err := evpnClient.UpdateSvi(ctx, name, update_mask, allowMissing) + if err != nil { + log.Fatalf("GetBridgePort: Error occurred while creating Bridge Port: %q", err) + } + log.Printf("CreateSVI: Created SVI \n name: %s,\n status: %d,\n Vrf: %s,\n LogicalBridge: %s,\n MacAddress: %s,\n EnableBgp: %d,\n GwIPs: %s,\nremoteAS: %u\n", + svi.GetName(),svi.GetSpec().GetVrf(), svi.GetSpec().GetLogicalBridge(), svi.GetSpec().GetMacAddress(), svi.GetSpec().GetEnableBgp(), svi.GetSpec().GetGwIpPrefix(), svi.GetSpec().GetRemoteAs()) + + }, + } + cmd.Flags().StringVar(&addr, "addr", "localhost:50151", "address of OPI gRPC server") + cmd.Flags().StringSliceVar(&update_mask, "update-mask", nil, "update mask") + cmd.Flags().BoolVarP(&allowMissing, "allow_missing", "a",false, "allow the missing") + return cmd +} + +// NewEvpnCommand tests the EVPN functionality command +func NewEvpnCommand() *cobra.Command { + + cmd := &cobra.Command{ + Use: "evpn", + Aliases: []string{"g"}, + Short: "Tests DPU evpn functionality", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + if err != nil { + log.Fatalf("[ERROR] %s", err.Error()) + } + }, + } + //Bridge cli's + cmd.AddCommand(CreateLogicalBridge()) + cmd.AddCommand(DeleteLogicalBridge()) + cmd.AddCommand(GetLogicalBridge()) + cmd.AddCommand(ListLogicalBridges()) + cmd.AddCommand(UpdateLogicalBridge()) + //Port cli's + cmd.AddCommand(CreateBridgePort()) + cmd.AddCommand(DeleteBridgePort()) + cmd.AddCommand(GetBridgePort()) + cmd.AddCommand(ListBridgePorts()) + cmd.AddCommand(UpdateBridgePort()) + //VRF cli's + cmd.AddCommand(CreateVRF()) + cmd.AddCommand(DeleteVRF()) + cmd.AddCommand(GetVRF()) + cmd.AddCommand(ListVRFs()) + cmd.AddCommand(UpdateVRF()) + //SVI cli's + cmd.AddCommand(CreateSVI()) + cmd.AddCommand(DeleteSVI()) + cmd.AddCommand(GetSVI()) + cmd.AddCommand(ListSVIs()) + cmd.AddCommand(UpdateSVI()) + return cmd } diff --git a/main.go b/main.go index a2adeac4..dc1f8ffb 100644 --- a/main.go +++ b/main.go @@ -39,5 +39,6 @@ func newCommand() *cobra.Command { c.AddCommand(cmd.NewTestCommand()) c.AddCommand(cmd.NewStatsCommand()) c.AddCommand(cmd.NewStorageTestCommand()) + c.AddCommand(cmd.NewEvpnCommand()) return c } diff --git a/network/evpn.go b/network/evpn.go index 3b7cf8a4..b8e2c4ac 100644 --- a/network/evpn.go +++ b/network/evpn.go @@ -8,51 +8,129 @@ import ( "context" "errors" "log" - + "fmt" + "net" + "strconv" + "strings" grpcOpi "github.com/opiproject/godpu/grpc" - pb "github.com/opiproject/opi-api/network/cloud/v1alpha1/gen/go" + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" pc "github.com/opiproject/opi-api/network/opinetcommon/v1alpha1/gen/go" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/fieldmaskpb" ) -// PbEvpnClientGetter defines the function type used to retrieve an evpn protobuf client -type PbEvpnClientGetter func(c grpc.ClientConnInterface) pb.CloudInfraServiceClient +type PbEvpnBridgeClientGetter func(c grpc.ClientConnInterface) pb.LogicalBridgeServiceClient +type PbEvpnPortClientGetter func(c grpc.ClientConnInterface) pb.BridgePortServiceClient +type PbEvpnVRFClientGetter func(c grpc.ClientConnInterface) pb.VrfServiceClient +type PbEvpnSVIClientGetter func(c grpc.ClientConnInterface) pb.SviServiceClient type evpnClientImpl struct { - getEvpnClient PbEvpnClientGetter + //getEvpnClient PbEvpnClientGetter + getEvpnBridgeClient PbEvpnBridgeClientGetter + getEvpnPortClient PbEvpnPortClientGetter + getEvpnVRFClient PbEvpnVRFClientGetter + getEvpnSVIClient PbEvpnSVIClientGetter grpcOpi.Connector } // EvpnClient is an interface for querying evpn data from an OPI server type EvpnClient interface { - // CreateSubnet(ctx context.Context) (*pb.Subnet, error) - // DeleteSubnet(ctx context.Context) (*emptypb.Empty, error) - CreateInterface(ctx context.Context) (*pb.Interface, error) - GetInterface(ctx context.Context) (*pb.Interface, error) - DeleteInterface(ctx context.Context) (*emptypb.Empty, error) - CreateVpc(ctx context.Context) (*pb.Vpc, error) - GetVpc(ctx context.Context) (*pb.Vpc, error) - DeleteVpc(ctx context.Context) (*emptypb.Empty, error) - CreateTunnel(ctx context.Context) (*pb.Tunnel, error) - GetTunnel(ctx context.Context) (*pb.Tunnel, error) - DeleteTunnel(ctx context.Context) (*emptypb.Empty, error) + + //Logical Bridge interfaces + CreateLogicalBridge(ctx context.Context,name string, vlan_id uint32,vni uint32) (*pb.LogicalBridge, error) + DeleteLogicalBridge(ctx context.Context,name string, allow_missing bool) (*emptypb.Empty, error) + GetLogicalBridge(ctx context.Context,name string) (*pb.LogicalBridge, error) + ListLogicalBridges(ctx context.Context,pageSize int32, pageToken string) (*pb.ListLogicalBridgesResponse, error) + UpdateLogicalBridge(ctx context.Context,name string, update_mask []string) (*pb.LogicalBridge, error) + + //Bridge Port Interfaces + CreateBridgePort(ctx context.Context,name string, mac string, bridgePortType string, logicalBridges []string) (*pb.BridgePort, error) + DeleteBridgePort(ctx context.Context, name string, allowMissing bool ) (*emptypb.Empty, error) + GetBridgePort(ctx context.Context, name string) (*pb.BridgePort, error) + ListBridgePorts(ctx context.Context, pageSize int32, pageToken string) (*pb.ListBridgePortsResponse, error) + UpdateBridgePort(ctx context.Context, name string, update_mask []string, allowMissing bool) (*pb.BridgePort, error) + + //VRF Interfaces + CreateVrf(ctx context.Context, name string, vni uint32, loopback string, vtep string) (*pb.Vrf, error) + DeleteVrf(ctx context.Context, name string, allow_missing bool) (*emptypb.Empty, error) + GetVrf(ctx context.Context, name string) (*pb.Vrf, error) + ListVrfs(ctx context.Context, pageSize int32, pageToken string) (*pb.ListVrfsResponse, error) + UpdateVrf(ctx context.Context, name string, update_mask []string, allowMissing bool) (*pb.Vrf, error) + + //SVI Interfaces + CreateSvi(ctx context.Context, name string, vrf string, logicalBridge string, mac string, gwIPs []string, ebgp bool, remoteAS uint32) (*pb.Svi, error) + DeleteSvi(ctx context.Context, name string, allow_missing bool) (*emptypb.Empty, error) + GetSvi(ctx context.Context, name string) (*pb.Svi, error) + ListSvis(ctx context.Context, pageSize int32, pageToken string) (*pb.ListSvisResponse, error) + UpdateSvi(ctx context.Context, name string, update_mask []string, allowMissing bool) (*pb.Svi, error) + +} + + + +func NewBridge(addr string) (EvpnClient, error) { + c, err := grpcOpi.New(addr) + if err != nil { + return nil, err + } + + // Default is to use the OPI grpc client and the pb client generated from the protobuf spec + + return NewBridgeWithArgs(c, pb.NewLogicalBridgeServiceClient) +} +func NewBridgeWithArgs(c grpcOpi.Connector, getter PbEvpnBridgeClientGetter) (EvpnClient, error) { + if c == nil { + return nil, errors.New("grpc connector is nil") + } + + if getter == nil { + return nil, errors.New("protobuf client getter is nil") + } + + return evpnClientImpl{ + getEvpnBridgeClient: getter, + Connector: c, + }, nil +} + +func NewPort(addr string) (EvpnClient, error) { + c, err := grpcOpi.New(addr) + if err != nil { + return nil, err + } + + // Default is to use the OPI grpc client and the pb client generated from the protobuf spec + + return NewPortWithArgs(c, pb.NewBridgePortServiceClient) } +func NewPortWithArgs(c grpcOpi.Connector, getter PbEvpnPortClientGetter) (EvpnClient, error) { + if c == nil { + return nil, errors.New("grpc connector is nil") + } + + if getter == nil { + return nil, errors.New("protobuf client getter is nil") + } -// New creates an evpn client for use with OPI server at the given address -func New(addr string) (EvpnClient, error) { + return evpnClientImpl{ + getEvpnPortClient: getter, + Connector: c, + }, nil +} + +func NewVRF(addr string) (EvpnClient, error) { c, err := grpcOpi.New(addr) if err != nil { return nil, err } // Default is to use the OPI grpc client and the pb client generated from the protobuf spec - return NewWithArgs(c, pb.NewCloudInfraServiceClient) + + return NewVRFWithArgs(c, pb.NewVrfServiceClient) } -// NewWithArgs creates an evpn client for use with OPI server using the given gRPC client and the given function for -// retrieving an evpn protobuf client -func NewWithArgs(c grpcOpi.Connector, getter PbEvpnClientGetter) (EvpnClient, error) { +func NewVRFWithArgs(c grpcOpi.Connector, getter PbEvpnVRFClientGetter) (EvpnClient, error) { if c == nil { return nil, errors.New("grpc connector is nil") } @@ -62,13 +140,113 @@ func NewWithArgs(c grpcOpi.Connector, getter PbEvpnClientGetter) (EvpnClient, er } return evpnClientImpl{ - getEvpnClient: getter, + getEvpnVRFClient: getter, Connector: c, }, nil } -// CreateInterface creates an interface an OPI server -func (c evpnClientImpl) CreateInterface(ctx context.Context) (*pb.Interface, error) { +func NewSVI(addr string) (EvpnClient, error) { + c, err := grpcOpi.New(addr) + if err != nil { + return nil, err + } + + // Default is to use the OPI grpc client and the pb client generated from the protobuf spec + + return NewSVIWithArgs(c, pb.NewSviServiceClient) +} + +func NewSVIWithArgs(c grpcOpi.Connector, getter PbEvpnSVIClientGetter) (EvpnClient, error) { + if c == nil { + return nil, errors.New("grpc connector is nil") + } + + if getter == nil { + return nil, errors.New("protobuf client getter is nil") + } + + return evpnClientImpl{ + getEvpnSVIClient: getter, + Connector: c, + }, nil +} + +// utils + +// Function to convert IPv4 address from net.IP to uint32 +func ip4ToInt(ip net.IP) uint32 { + return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3]) +} + +// Function to parse IP address and prefix from a string of the form "IP/PREFIX" +func parseIPAndPrefix(ipPrefixStr string) (*pc.IPPrefix, error) { + parts := strings.Split(ipPrefixStr, "/") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid IP address with prefix: %s", ipPrefixStr) + } + + ipAddress := parts[0] + prefixLength64, err := strconv.ParseInt(parts[1], 10, 32) + + if err != nil { + return nil, fmt.Errorf("failed to parse prefix length: %s", err) + } + + prefixLength := int32(prefixLength64) + + ip := net.ParseIP(ipAddress) + if ip == nil { + return nil, fmt.Errorf("invalid IP address: %s", ipAddress) + } + + addressFamily := int32(0) + var ipv4Addr uint32 + var ipv6Addr []byte + + if ip.To4() != nil { + addressFamily = 1 // IPv4 + ipv4Addr = ip4ToInt(ip.To4()) + return &pc.IPPrefix{ + Addr: &pc.IPAddress{ + Af: pc.IpAf(addressFamily), + V4OrV6: &pc.IPAddress_V4Addr{ + V4Addr: ipv4Addr, + }, + }, + Len: prefixLength, + }, nil + } else { + addressFamily = 2 // IPv6 + ipv6Addr = ip.To16() + return &pc.IPPrefix{ + Addr: &pc.IPAddress{ + Af: pc.IpAf(addressFamily), + V4OrV6: &pc.IPAddress_V6Addr{ + V6Addr: ipv6Addr, + }, + }, + Len: prefixLength, + }, nil + } + + + } + +// Function to parse an array of IP prefixes from strings to pb.IPPrefix messages +func parseIPPrefixes(ipPrefixesStr []string) ([]*pc.IPPrefix, error) { + var ipPrefixes []*pc.IPPrefix + for _, ipPrefixStr := range ipPrefixesStr { + ipPrefix, err := parseIPAndPrefix(ipPrefixStr) + if err != nil { + return nil, fmt.Errorf("failed to parse IP prefix: %v", err) + } + ipPrefixes = append(ipPrefixes, ipPrefix) + } + return ipPrefixes, nil + } + +// CreateLogicalBridge creates an Logical Bridge an OPI server +func (c evpnClientImpl) CreateLogicalBridge(ctx context.Context,name string, vlan_id uint32,vni uint32) (*pb.LogicalBridge, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) @@ -76,27 +254,27 @@ func (c evpnClientImpl) CreateInterface(ctx context.Context) (*pb.Interface, err } defer closer() - client := c.getEvpnClient(conn) + client := c.getEvpnBridgeClient(conn) - data, err := client.CreateInterface(ctx, &pb.CreateInterfaceRequest{ - Parent: "todo", - InterfaceId: "testinterface", - Interface: &pb.Interface{ - Spec: &pb.InterfaceSpec{ - Ifid: 11, + data, err := client.CreateLogicalBridge(ctx, &pb.CreateLogicalBridgeRequest{ + LogicalBridge : &pb.LogicalBridge{ + Name: name, + Spec: &pb.LogicalBridgeSpec{ + VlanId: vlan_id, + Vni: vni, }, }, }) if err != nil { - log.Printf("error creating evpn: %s\n", err) + log.Printf("error creating logical bridge: %s\n", err) return nil, err } return data, nil } -// GetInterface creates an interface an OPI server -func (c evpnClientImpl) GetInterface(ctx context.Context) (*pb.Interface, error) { +// DeleteLogicalBridge deletes an Logical Bridge an OPI server +func (c evpnClientImpl) DeleteLogicalBridge(ctx context.Context,name string, allow_missing bool) (*emptypb.Empty, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) @@ -104,21 +282,128 @@ func (c evpnClientImpl) GetInterface(ctx context.Context) (*pb.Interface, error) } defer closer() - client := c.getEvpnClient(conn) + client := c.getEvpnBridgeClient(conn) + + data, err := client.DeleteLogicalBridge(ctx, &pb.DeleteLogicalBridgeRequest{ + Name: name, + AllowMissing: allow_missing, + },) + if err != nil { + log.Printf("error deleting logical bridge: %s\n", err) + return nil, err + } + + return data,nil +} - data, err := client.GetInterface(ctx, &pb.GetInterfaceRequest{ - Name: "//network.opiproject.org/interfaces/testinterface", +// GetLogicalBridge get Logical Bridge details from OPI server +func (c evpnClientImpl) GetLogicalBridge(ctx context.Context,name string) (*pb.LogicalBridge, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnBridgeClient(conn) + + data, err := client.GetLogicalBridge(ctx, &pb.GetLogicalBridgeRequest{ + Name: name, + },) + if err != nil { + log.Printf("error getting logical bridge: %s\n", err) + return nil, err + } + + return data,nil +} + +// ListLogicalBridges list all Logical Bridge details from OPI server +func (c evpnClientImpl) ListLogicalBridges(ctx context.Context,pageSize int32, pageToken string) (*pb.ListLogicalBridgesResponse, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnBridgeClient(conn) + + data, err := client.ListLogicalBridges(ctx, &pb.ListLogicalBridgesRequest{ + PageSize: pageSize, + PageToken: pageToken, + },) + if err != nil { + log.Printf("error List logical bridge: %s\n", err) + return nil, err + } + + return data,nil +} + +// UpdateLogicalBridge update Logical Bridge on OPI server +func (c evpnClientImpl) UpdateLogicalBridge(ctx context.Context,name string, update_mask []string) (*pb.LogicalBridge, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnBridgeClient(conn) + Bridge:= &pb.LogicalBridge{ + Name: name, + } + data, err := client.UpdateLogicalBridge(ctx, &pb.UpdateLogicalBridgeRequest{ + LogicalBridge: Bridge, + UpdateMask: &fieldmaskpb.FieldMask{Paths: update_mask}, + },) + if err != nil { + log.Printf("error Update logical bridge: %s\n", err) + return nil, err + } + + return data,nil +} + +// CreateBridgePort creates an Bridge Port an OPI server +func (c evpnClientImpl) CreateBridgePort(ctx context.Context,name string, mac string, bridgePortType string, logicalBridges []string) (*pb.BridgePort, error) { + var typeOfPort pb.BridgePortType + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnPortClient(conn) + if bridgePortType == "access" { + typeOfPort = pb.BridgePortType_ACCESS + } else if bridgePortType == "trunk" { + typeOfPort = pb.BridgePortType_TRUNK + } else { + typeOfPort = pb.BridgePortType_UNKNOWN + } + data, err := client.CreateBridgePort(ctx, &pb.CreateBridgePortRequest{ + BridgePort: &pb.BridgePort{ + Name: name, + Spec : &pb.BridgePortSpec{ + MacAddress: []byte(mac), + Ptype: typeOfPort, + LogicalBridges: logicalBridges, + }, + }, }) if err != nil { - log.Printf("error getting evpn: %s\n", err) + log.Printf("error creating Bridge Port: %s\n", err) return nil, err } return data, nil } -// DeleteInterface creates an interface an OPI server -func (c evpnClientImpl) DeleteInterface(ctx context.Context) (*emptypb.Empty, error) { +// DeleteBridgePort delete an Bridge Port an OPI server +func (c evpnClientImpl) DeleteBridgePort(ctx context.Context, name string, allowMissing bool ) (*emptypb.Empty, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) @@ -126,21 +411,90 @@ func (c evpnClientImpl) DeleteInterface(ctx context.Context) (*emptypb.Empty, er } defer closer() - client := c.getEvpnClient(conn) + client := c.getEvpnPortClient(conn) + data, err := client.DeleteBridgePort(ctx, &pb.DeleteBridgePortRequest{ + Name: name, + AllowMissing: allowMissing, + },) + if err != nil { + log.Printf("error deleting Bridge Port: %s\n", err) + return nil, err + } - data, err := client.DeleteInterface(ctx, &pb.DeleteInterfaceRequest{ - Name: "//network.opiproject.org/interfaces/testinterface", - }) + return data, nil +} + +// GetBridgePort Get Bridge Port details +func (c evpnClientImpl) GetBridgePort(ctx context.Context, name string) (*pb.BridgePort, error) { + conn, closer, err := c.NewConn() if err != nil { - log.Printf("error deleting evpn: %s\n", err) + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnPortClient(conn) + data, err := client.GetBridgePort(ctx, &pb.GetBridgePortRequest{ + Name: name, + },) + if err != nil { + log.Printf("error getting Bridge Port: %s\n", err) + return nil, err + } + + return data, nil +} + +// ListBridgePorts list all the Bridge Port an OPI server +func (c evpnClientImpl) ListBridgePorts(ctx context.Context, pageSize int32, pageToken string) (*pb.ListBridgePortsResponse, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnPortClient(conn) + data, err := client.ListBridgePorts(ctx, &pb.ListBridgePortsRequest{ + PageSize: pageSize, + PageToken: pageToken, + },) + if err != nil { + log.Printf("error list Bridge Port: %s\n", err) + return nil, err + } + + return data, nil +} + +// UpdateBridgePort update the Bridge Port on OPI server +func (c evpnClientImpl) UpdateBridgePort(ctx context.Context, name string, update_mask []string, allowMissing bool) (*pb.BridgePort, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + + client := c.getEvpnPortClient(conn) + Port:= &pb.BridgePort{ + Name: name, + } + data, err := client.UpdateBridgePort(ctx, &pb.UpdateBridgePortRequest{ + BridgePort: Port, + UpdateMask: &fieldmaskpb.FieldMask{Paths: update_mask}, + AllowMissing: allowMissing, + },) + if err != nil { + log.Printf("error updating Bridge Port: %s\n", err) return nil, err } return data, nil } -// CreateVpc creates an Vpc an OPI server -func (c evpnClientImpl) CreateVpc(ctx context.Context) (*pb.Vpc, error) { +// CreateVrf Create vrf on OPI Server +func (c evpnClientImpl) CreateVrf(ctx context.Context, name string, vni uint32, loopback string, vtep string) (*pb.Vrf, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) @@ -148,71 +502,129 @@ func (c evpnClientImpl) CreateVpc(ctx context.Context) (*pb.Vpc, error) { } defer closer() - client := c.getEvpnClient(conn) + client := c.getEvpnVRFClient(conn) + ipLoopback, err := parseIPAndPrefix(loopback) + if err != nil { + log.Printf("parseIPAndPrefix: error creating vrf: %s\n", err) + return nil, err + } + ipVtep, err := parseIPAndPrefix(vtep) + if err != nil { + log.Printf("parseIPAndPrefix: error creating vrf: %s\n", err) + return nil, err + } + data, err := client.CreateVrf(ctx, &pb.CreateVrfRequest{ + Vrf : &pb.Vrf{ + Name: name, + Spec: &pb.VrfSpec{ + Vni: vni, + LoopbackIpPrefix: ipLoopback, + VtepIpPrefix: ipVtep, - data, err := client.CreateVpc(ctx, &pb.CreateVpcRequest{ - Parent: "todo", - VpcId: "testVpc", - Vpc: &pb.Vpc{ - Spec: &pb.VpcSpec{ - V4RouteTableNameRef: "1000", }, }, }) if err != nil { - log.Printf("error creating evpn: %s\n", err) + log.Printf("error creating vrf: %s\n", err) return nil, err } return data, nil } -// GetVpc creates an Vpc an OPI server -func (c evpnClientImpl) GetVpc(ctx context.Context) (*pb.Vpc, error) { +// DeleteVrf update the vrf on OPI server +func (c evpnClientImpl) DeleteVrf(ctx context.Context, name string, allow_missing bool) (*emptypb.Empty, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) return nil, err } defer closer() + client := c.getEvpnVRFClient(conn) + data, err := client.DeleteVrf(ctx, &pb.DeleteVrfRequest{ + Name: name, + AllowMissing: allow_missing, + }) + if err != nil { + log.Printf("error deleting vrf: %s\n", err) + return nil, err + } - client := c.getEvpnClient(conn) + return data, nil +} - data, err := client.GetVpc(ctx, &pb.GetVpcRequest{ - Name: "//network.opiproject.org/vpcs/testVpc", - }) +// GetVrf get vrf details from OPI server +func (c evpnClientImpl) GetVrf(ctx context.Context, name string) (*pb.Vrf, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + client := c.getEvpnVRFClient(conn) + data, err := client.GetVrf(ctx, &pb.GetVrfRequest{ + Name: name, + }) if err != nil { - log.Printf("error getting evpn: %s\n", err) + log.Printf("error getting vrf: %s\n", err) return nil, err } return data, nil } -// DeleteVpc creates an Vpc an OPI server -func (c evpnClientImpl) DeleteVpc(ctx context.Context) (*emptypb.Empty, error) { +// ListVrfs list all vrf's with details from OPI server +func (c evpnClientImpl) ListVrfs(ctx context.Context, pageSize int32, pageToken string) (*pb.ListVrfsResponse, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) return nil, err } defer closer() + client := c.getEvpnVRFClient(conn) + data, err := client.ListVrfs(ctx, &pb.ListVrfsRequest{ + PageSize: pageSize, + PageToken: pageToken, + }) + if err != nil { + log.Printf("error list Vrf: %s\n", err) + return nil, err + } - client := c.getEvpnClient(conn) + return data, nil +} - data, err := client.DeleteVpc(ctx, &pb.DeleteVpcRequest{ - Name: "//network.opiproject.org/vpcs/testVpc", +// UpdateVrf update the vrf on OPI server +func (c evpnClientImpl) UpdateVrf(ctx context.Context, name string, update_mask []string,allowMissing bool) (*pb.Vrf, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + client := c.getEvpnVRFClient(conn) + vrf, err := client.GetVrf(ctx, &pb.GetVrfRequest{ + Name: name, }) if err != nil { - log.Printf("error deleting evpn: %s\n", err) + log.Printf("error updating vrf: %s\n", err) + return nil, err + } + data, err := client.UpdateVrf(ctx, &pb.UpdateVrfRequest{ + Vrf: vrf, + UpdateMask: &fieldmaskpb.FieldMask{Paths: update_mask}, + AllowMissing: allowMissing, + }) + if err != nil { + log.Printf("error creating evpn: %s\n", err) return nil, err } return data, nil } -// CreateTunnel creates an Tunnel an OPI server -func (c evpnClientImpl) CreateTunnel(ctx context.Context) (*pb.Tunnel, error) { +// CreateSvi create svi on OPI server +func (c evpnClientImpl) CreateSvi(ctx context.Context, name string, vrf string, logicalBridge string, mac string, gwIPs []string, ebgp bool, remoteAS uint32) (*pb.Svi, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) @@ -220,75 +632,123 @@ func (c evpnClientImpl) CreateTunnel(ctx context.Context) (*pb.Tunnel, error) { } defer closer() - client := c.getEvpnClient(conn) - - data, err := client.CreateTunnel(ctx, &pb.CreateTunnelRequest{ - Parent: "todo", - TunnelId: "testTunnel", - Tunnel: &pb.Tunnel{ - Spec: &pb.TunnelSpec{ - VpcNameRef: "//network.opiproject.org/subnets/testbridge", - LocalIp: &pc.IPAddress{ - Af: pc.IpAf_IP_AF_INET, - V4OrV6: &pc.IPAddress_V4Addr{V4Addr: 336860161}, - }, - Encap: &pc.Encap{ - Type: pc.EncapType_ENCAP_TYPE_VXLAN, - Value: &pc.EncapVal{ - Val: &pc.EncapVal_Vnid{Vnid: 100}, - }, - }, + client := c.getEvpnSVIClient(conn) + + gw_prefixes, err:= parseIPPrefixes(gwIPs) + if err != nil { + log.Printf("error parsing GwIPs: %s\n", err) + return nil, err + } + data, err := client.CreateSvi(ctx, &pb.CreateSviRequest{ + Svi : &pb.Svi{ + Name: name, + Spec: &pb.SviSpec{ + Vrf: vrf, + LogicalBridge: logicalBridge, + MacAddress: []byte(mac), + GwIpPrefix:gw_prefixes, + EnableBgp: ebgp, + RemoteAs: remoteAS, + }, }, }) if err != nil { - log.Printf("error creating evpn: %s\n", err) + log.Printf("error creating svi: %s\n", err) return nil, err } return data, nil } -// GetTunnel creates an Tunnel an OPI server -func (c evpnClientImpl) GetTunnel(ctx context.Context) (*pb.Tunnel, error) { +// DeleteSvi delete the svi on OPI server +func (c evpnClientImpl) DeleteSvi(ctx context.Context, name string, allow_missing bool) (*emptypb.Empty, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) return nil, err } defer closer() + client := c.getEvpnSVIClient(conn) + data, err := client.DeleteSvi(ctx, &pb.DeleteSviRequest{ + Name: name, + AllowMissing: allow_missing, + }) + if err != nil { + log.Printf("error deleting svi: %s\n", err) + return nil, err + } - client := c.getEvpnClient(conn) + return data, nil +} - data, err := client.GetTunnel(ctx, &pb.GetTunnelRequest{ - Name: "//network.opiproject.org/tunnels/testTunnel", - }) +// GetSvi get svi details from OPI server +func (c evpnClientImpl) GetSvi(ctx context.Context, name string) (*pb.Svi, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + client := c.getEvpnSVIClient(conn) + data, err := client.GetSvi(ctx, &pb.GetSviRequest{ + Name: name, + }) if err != nil { - log.Printf("error getting evpn: %s\n", err) + log.Printf("error getting svi: %s\n", err) return nil, err } return data, nil } -// DeleteTunnel creates an Tunnel an OPI server -func (c evpnClientImpl) DeleteTunnel(ctx context.Context) (*emptypb.Empty, error) { +// ListSvis get all the svi's from OPI server +func (c evpnClientImpl) ListSvis(ctx context.Context, pageSize int32, pageToken string) (*pb.ListSvisResponse, error) { conn, closer, err := c.NewConn() if err != nil { log.Printf("error creating connection: %s\n", err) return nil, err } defer closer() + client := c.getEvpnSVIClient(conn) + data, err := client.ListSvis(ctx, &pb.ListSvisRequest{ + PageSize: pageSize, + PageToken: pageToken, + }) + if err != nil { + log.Printf("error list svis: %s\n", err) + return nil, err + } - client := c.getEvpnClient(conn) + return data, nil +} - data, err := client.DeleteTunnel(ctx, &pb.DeleteTunnelRequest{ - Name: "//network.opiproject.org/tunnels/testTunnel", +// UpdateSvi update the svi on OPI server +func (c evpnClientImpl) UpdateSvi(ctx context.Context, name string, update_mask []string, allowMissing bool) (*pb.Svi, error) { + conn, closer, err := c.NewConn() + if err != nil { + log.Printf("error creating connection: %s\n", err) + return nil, err + } + defer closer() + client := c.getEvpnSVIClient(conn) + svi, err := client.GetSvi(ctx, &pb.GetSviRequest{ + Name: name, }) if err != nil { - log.Printf("error deleting evpn: %s\n", err) + log.Printf("error getting svi: %s\n", err) + return nil, err + } + data, err := client.UpdateSvi(ctx, &pb.UpdateSviRequest{ + Svi: svi, + UpdateMask: &fieldmaskpb.FieldMask{Paths: update_mask}, + AllowMissing: allowMissing, + }) + if err != nil { + log.Printf("error updating svi: %s\n", err) return nil, err } return data, nil } +