diff --git a/src/switch/README.md b/src/switch/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ea76469a606c53981920828543911d3229e00867 --- /dev/null +++ b/src/switch/README.md @@ -0,0 +1,5 @@ +1. Modify the api/v1/ned.proto +2. Generate protofiles: +```bash +protoc -I=api/v1 --go_out=paths=source_relative:./pkg/nedpb api/v1/ned.proto +``` \ No newline at end of file diff --git a/src/switch/api/v1/ned.proto b/src/switch/api/v1/ned.proto new file mode 100644 index 0000000000000000000000000000000000000000..2a3e6a96b1a8d57918fb310d63981883cf929257 --- /dev/null +++ b/src/switch/api/v1/ned.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; + +package nedpb; + +option go_package = "l2sm.local/ovs-switch/pkg/nedpb"; + +service VxlanService { + // Creates a VxLAN with the specified IP address. + rpc CreateVxlan(CreateVxlanRequest) returns (CreateVxlanResponse); + + // Attaches the specified interface to the bridge. + rpc AttachInterface(AttachInterfaceRequest) returns (AttachInterfaceResponse); +} + +message CreateVxlanRequest { + // The IP address to attach to the VxLAN. + string ip_address = 1; +} + +message CreateVxlanResponse { + // Indicates if the VxLAN was created successfully. + bool success = 1; + // Optional message providing additional information. + string message = 2; +} + +message AttachInterfaceRequest { + // The name of the interface to attach to the bridge. + string interface_name = 1; +} + +message AttachInterfaceResponse { + // The OpenFlow ID of the attached interface. + int64 interface_num = 1; + // The node name from the environment variable. + string node_name = 2; +} diff --git a/src/switch/cmd/grpc-server/main.go b/src/switch/cmd/grpc-server/main.go new file mode 100644 index 0000000000000000000000000000000000000000..85bcee32db04af50b9c5a7722df49ee8b2279d1d --- /dev/null +++ b/src/switch/cmd/grpc-server/main.go @@ -0,0 +1,76 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + "os" + + "google.golang.org/grpc" + + // Adjust the import path based on your module path + + "l2sm.local/ovs-switch/pkg/nedpb" + "l2sm.local/ovs-switch/pkg/ovs" +) + +// server is used to implement nedpb.VxlanServiceServer +type server struct { + nedpb.UnimplementedVxlanServiceServer +} + +// CreateVxlan implements nedpb.VxlanServiceServer +func (s *server) CreateVxlan(ctx context.Context, req *nedpb.CreateVxlanRequest) (*nedpb.CreateVxlanResponse, error) { + ipAddress := req.GetIpAddress() + + // Implement your logic to create a VxLAN with the given IP address + // For example, call a function from pkg/ovs/vsctl.go + // success, message := ovs.CreateVxlan(ipAddress) + + // Placeholder implementation + bridge := ovs.FromName("brtun") + bridge.CreateVxlan(ovs.Vxlan{"", "", ipAddress, ""}) + message := fmt.Sprintf("VxLAN with IP %s created successfully", ipAddress) + + return &nedpb.CreateVxlanResponse{ + Success: success, + Message: message, + }, nil +} + +// AttachInterface implements nedpb.VxlanServiceServer +func (s *server) AttachInterface(ctx context.Context, req *nedpb.AttachInterfaceRequest) (*nedpb.AttachInterfaceResponse, error) { + interfaceName := req.GetInterfaceName() + + // Implement your logic to attach the interface to the bridge + // For example, call a function from pkg/ovs/vsctl.go + // openflowID, err := ovs.AttachInterface(interfaceName) + + // Placeholder implementation + nodeName := os.Getenv("NODE_NAME") + + return &nedpb.AttachInterfaceResponse{ + OpenflowId: openflowID, + NodeName: nodeName, + }, nil +} + +func main() { + // Listen on a TCP port + lis, err := net.Listen("tcp", ":50051") // Choose your port + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + // Create a gRPC server + grpcServer := grpc.NewServer() + + // Register the server + nedpb.RegisterVxlanServiceServer(grpcServer, &server{}) + + log.Printf("gRPC server listening on :50051") + if err := grpcServer.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} diff --git a/src/switch/cmd/l2sm-add-port/main.go b/src/switch/cmd/l2sm-add-port/main.go index 353c462d08e6e57297259734e770ac2a9c9e450e..bc6a59806c106f0d1329be70e068c486bb87d34f 100644 --- a/src/switch/cmd/l2sm-add-port/main.go +++ b/src/switch/cmd/l2sm-add-port/main.go @@ -4,7 +4,8 @@ import ( "errors" "flag" "fmt" - "ovs-switch/pkg/ovs" + + "l2sm.local/ovs-switch/pkg/ovs" ) // Script that takes two required arguments: @@ -21,7 +22,7 @@ func main() { return } - bridge.AddPort(portName) + err = bridge.AddPort(portName) if err != nil { fmt.Println("Port not added: ", err) diff --git a/src/switch/cmd/l2sm-init/main.go b/src/switch/cmd/l2sm-init/main.go index 5c9a8212a804f34ad54314ed55f7ee85ea776e6c..0ecafa360227263dbb562a810728a4bb255984bc 100644 --- a/src/switch/cmd/l2sm-init/main.go +++ b/src/switch/cmd/l2sm-init/main.go @@ -5,8 +5,9 @@ import ( "flag" "fmt" "os/exec" - "ovs-switch/pkg/ovs" "regexp" + + "l2sm.local/ovs-switch/pkg/ovs" ) // Script that takes two required arguments: @@ -14,7 +15,7 @@ import ( // the second one is the path to the configuration file, in reference to the code. func main() { - vethNumber, controllerIP, err := takeArguments() + vethNumber, controllerIP, switchName, err := takeArguments() if err != nil { fmt.Println("Error with the arguments. Error:", err) @@ -23,7 +24,7 @@ func main() { fmt.Println("Initializing switch, connected to controller: ", controllerIP) - bridge, err := initializeSwitch(controllerIP) + bridge, err := initializeSwitch(switchName, controllerIP) if err != nil { @@ -43,22 +44,22 @@ func main() { fmt.Printf("Switch initialized, current state: ", bridge) } -func takeArguments() (int, string, error) { +func takeArguments() (int, string, string, error) { vethNumber := flag.Int("n_veths", 0, "number of pod interfaces that are going to be attached to the switch") controllerIP := flag.String("controller_ip", "", "ip where the SDN controller is listening using the OpenFlow13 protocol. Required") - + switchName := flag.String("switch_name", "", "name of the switch that will be used to set a custom datapath id. If not set, a randome datapath will be assigned") flag.Parse() switch { case *controllerIP == "": - return 0, "", errors.New("controller IP is not defined") + return 0, "", "", errors.New("controller IP is not defined") } - return *vethNumber, *controllerIP, nil + return *vethNumber, *controllerIP, *switchName, nil } -func initializeSwitch(controllerIP string) (ovs.Bridge, error) { +func initializeSwitch(switchName, controllerIP string) (ovs.Bridge, error) { re := regexp.MustCompile(`\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b`) if !re.MatchString(controllerIP) { @@ -68,7 +69,8 @@ func initializeSwitch(controllerIP string) (ovs.Bridge, error) { controller := fmt.Sprintf("tcp:%s:6633", controllerIP) - bridge, err := ovs.NewBridge(ovs.Bridge{Name: "brtun", Controller: controller, Protocol: "OpenFlow13"}) + datapathId := ovs.GenerateDatapathID(switchName) + bridge, err := ovs.NewBridge(ovs.Bridge{Name: "brtun", Controller: controller, Protocol: "OpenFlow13", DatapathId: datapathId}) return bridge, err } diff --git a/src/switch/cmd/l2sm-init/main_test.go b/src/switch/cmd/l2sm-init/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bd26d7f70b41b567cc23d0371e6bfba0594adfcf --- /dev/null +++ b/src/switch/cmd/l2sm-init/main_test.go @@ -0,0 +1,98 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + "os/exec" + "testing" + + "l2sm.local/ovs-switch/pkg/ovs" +) + +// Mock implementation of ovs.Bridge for testing purposes +type MockBridge struct { + Name string + Controller string + Protocol string + DatapathId string +} + +func (b *MockBridge) AddPort(port string) error { + return nil +} + +func (b *MockBridge) String() string { + return fmt.Sprintf("MockBridge{Name: %s, Controller: %s, Protocol: %s, DatapathId: %s}", b.Name, b.Controller, b.Protocol, b.DatapathId) +} + +// Override ovs.NewBridge for testing +var NewBridge = func(b ovs.Bridge) (ovs.Bridge, error) { + return ovs.Bridge{ + Name: b.Name, + Controller: b.Controller, + Protocol: b.Protocol, + DatapathId: b.DatapathId, + }, nil +} + +func TestTakeArguments(t *testing.T) { + // Backup original command line arguments + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + tests := []struct { + args []string + expectedErr error + }{ + {[]string{"cmd", "-n_veths", "5", "-controller_ip", "192.168.1.1", "-switch_name", "switch1"}, nil}, + {[]string{"cmd", "-n_veths", "5", "-controller_ip", ""}, errors.New("controller IP is not defined")}, + } + + for _, test := range tests { + os.Args = test.args + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + _, _, _, err := takeArguments() + if err != nil && err.Error() != test.expectedErr.Error() { + t.Errorf("Expected error: %v, got: %v", test.expectedErr, err) + } + } +} + +func TestInitializeSwitch(t *testing.T) { + // Mock exec.Command for testing + oldExecCommand := exec.Command + defer func() { exec.Command = oldExecCommand }() + + exec.Command = func(name string, arg ...string) *exec.Cmd { + cmd := oldExecCommand("echo", "192.168.1.1") + return cmd + } + + tests := []struct { + switchName string + controllerIP string + expectedErr error + }{ + {"switch1", "192.168.1.1", nil}, + {"switch1", "invalid-ip", nil}, + } + + for _, test := range tests { + bridge, err := initializeSwitch(test.switchName, test.controllerIP) + if err != nil && err.Error() != test.expectedErr.Error() { + t.Errorf("Expected error: %v, got: %v", test.expectedErr, err) + } + if bridge == nil { + t.Errorf("Expected bridge to be initialized, got nil") + } + } +} + +func TestGenerateDatapathID(t *testing.T) { + + datapathID := generateDatapathID("pod") + fmt.Println(datapathID) +} diff --git a/src/switch/cmd/l2sm-vxlans/main.go b/src/switch/cmd/l2sm-vxlans/main.go index 016d2436a48e0600c02e2de27b9892867daebdf8..8e486cd90347e321a9c9db80e0520c40faa00349 100644 --- a/src/switch/cmd/l2sm-vxlans/main.go +++ b/src/switch/cmd/l2sm-vxlans/main.go @@ -7,7 +7,8 @@ import ( "fmt" "net" "os" - "ovs-switch/pkg/ovs" + + "l2sm.local/ovs-switch/pkg/ovs" ) type Node struct { @@ -66,6 +67,10 @@ func main() { } err = connectToNeighbors(bridge, node) + if err != nil { + fmt.Println("Could not connect neighbors: ", err) + return + } } if err != nil { diff --git a/src/switch/cmd/l2sm-vxlans/main_test.go b/src/switch/cmd/l2sm-vxlans/main_test.go index 4ee7c33f0219ab9ea8cb0da9cb544edbb57250c6..47737f76b4d03d743007d56a62b3d80a21b4e275 100644 --- a/src/switch/cmd/l2sm-vxlans/main_test.go +++ b/src/switch/cmd/l2sm-vxlans/main_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "ovs-switch/pkg/ovs" + "l2sm.local/ovs-switch/pkg/ovs" ) func TestCreateTopology(t *testing.T) { diff --git a/src/switch/go.mod b/src/switch/go.mod index ba5ccbb23213db1f98ee3dac41d5468dc509bcdd..fca2823355c2813a5d5b2b348541cd6732da9fd0 100644 --- a/src/switch/go.mod +++ b/src/switch/go.mod @@ -1,9 +1,16 @@ -module ovs-switch +module l2sm.local/ovs-switch go 1.21.7 require github.com/eclipse/paho.mqtt.golang v1.4.3 +require ( + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/mock v1.6.0 // indirect @@ -11,7 +18,8 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect + google.golang.org/grpc v1.67.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/src/switch/go.sum b/src/switch/go.sum index f3cb5d3b425b85fbeab9f19fa387d626a66b5326..ba494d14b837aca4f8f34c86d5414f3090826157 100644 --- a/src/switch/go.sum +++ b/src/switch/go.sum @@ -21,24 +21,37 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/switch/pkg/nedpb/ned.pb.go b/src/switch/pkg/nedpb/ned.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..7a03427b916b1d3a3c42bf1e85733726371ea72a --- /dev/null +++ b/src/switch/pkg/nedpb/ned.pb.go @@ -0,0 +1,374 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc v5.28.2 +// source: ned.proto + +package nedpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CreateVxlanRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The IP address to attach to the VxLAN. + IpAddress string `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` +} + +func (x *CreateVxlanRequest) Reset() { + *x = CreateVxlanRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ned_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateVxlanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateVxlanRequest) ProtoMessage() {} + +func (x *CreateVxlanRequest) ProtoReflect() protoreflect.Message { + mi := &file_ned_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateVxlanRequest.ProtoReflect.Descriptor instead. +func (*CreateVxlanRequest) Descriptor() ([]byte, []int) { + return file_ned_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateVxlanRequest) GetIpAddress() string { + if x != nil { + return x.IpAddress + } + return "" +} + +type CreateVxlanResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Indicates if the VxLAN was created successfully. + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + // Optional message providing additional information. + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *CreateVxlanResponse) Reset() { + *x = CreateVxlanResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ned_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateVxlanResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateVxlanResponse) ProtoMessage() {} + +func (x *CreateVxlanResponse) ProtoReflect() protoreflect.Message { + mi := &file_ned_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateVxlanResponse.ProtoReflect.Descriptor instead. +func (*CreateVxlanResponse) Descriptor() ([]byte, []int) { + return file_ned_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateVxlanResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *CreateVxlanResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type AttachInterfaceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the interface to attach to the bridge. + InterfaceName string `protobuf:"bytes,1,opt,name=interface_name,json=interfaceName,proto3" json:"interface_name,omitempty"` +} + +func (x *AttachInterfaceRequest) Reset() { + *x = AttachInterfaceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ned_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttachInterfaceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttachInterfaceRequest) ProtoMessage() {} + +func (x *AttachInterfaceRequest) ProtoReflect() protoreflect.Message { + mi := &file_ned_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttachInterfaceRequest.ProtoReflect.Descriptor instead. +func (*AttachInterfaceRequest) Descriptor() ([]byte, []int) { + return file_ned_proto_rawDescGZIP(), []int{2} +} + +func (x *AttachInterfaceRequest) GetInterfaceName() string { + if x != nil { + return x.InterfaceName + } + return "" +} + +type AttachInterfaceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The OpenFlow ID of the attached interface. + OpenflowId int64 `protobuf:"varint,1,opt,name=openflow_id,json=openflowId,proto3" json:"openflow_id,omitempty"` + // The node name from the environment variable. + NodeName string `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` +} + +func (x *AttachInterfaceResponse) Reset() { + *x = AttachInterfaceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ned_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttachInterfaceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttachInterfaceResponse) ProtoMessage() {} + +func (x *AttachInterfaceResponse) ProtoReflect() protoreflect.Message { + mi := &file_ned_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttachInterfaceResponse.ProtoReflect.Descriptor instead. +func (*AttachInterfaceResponse) Descriptor() ([]byte, []int) { + return file_ned_proto_rawDescGZIP(), []int{3} +} + +func (x *AttachInterfaceResponse) GetOpenflowId() int64 { + if x != nil { + return x.OpenflowId + } + return 0 +} + +func (x *AttachInterfaceResponse) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +var File_ned_proto protoreflect.FileDescriptor + +var file_ned_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x6e, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x6e, 0x65, 0x64, + 0x70, 0x62, 0x22, 0x33, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x78, 0x6c, 0x61, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x70, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x70, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x49, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x78, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x3f, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x17, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x6e, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x32, 0xa6, 0x01, 0x0a, + 0x0c, 0x56, 0x78, 0x6c, 0x61, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, + 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x78, 0x6c, 0x61, 0x6e, 0x12, 0x19, 0x2e, 0x6e, + 0x65, 0x64, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x78, 0x6c, 0x61, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6e, 0x65, 0x64, 0x70, 0x62, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x78, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x6e, 0x65, 0x64, 0x70, 0x62, 0x2e, 0x41, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6e, 0x65, 0x64, 0x70, 0x62, 0x2e, 0x41, 0x74, + 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x6c, 0x32, 0x73, 0x6d, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x2f, 0x6f, 0x76, 0x73, 0x2d, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x6e, 0x65, 0x64, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ned_proto_rawDescOnce sync.Once + file_ned_proto_rawDescData = file_ned_proto_rawDesc +) + +func file_ned_proto_rawDescGZIP() []byte { + file_ned_proto_rawDescOnce.Do(func() { + file_ned_proto_rawDescData = protoimpl.X.CompressGZIP(file_ned_proto_rawDescData) + }) + return file_ned_proto_rawDescData +} + +var file_ned_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_ned_proto_goTypes = []any{ + (*CreateVxlanRequest)(nil), // 0: nedpb.CreateVxlanRequest + (*CreateVxlanResponse)(nil), // 1: nedpb.CreateVxlanResponse + (*AttachInterfaceRequest)(nil), // 2: nedpb.AttachInterfaceRequest + (*AttachInterfaceResponse)(nil), // 3: nedpb.AttachInterfaceResponse +} +var file_ned_proto_depIdxs = []int32{ + 0, // 0: nedpb.VxlanService.CreateVxlan:input_type -> nedpb.CreateVxlanRequest + 2, // 1: nedpb.VxlanService.AttachInterface:input_type -> nedpb.AttachInterfaceRequest + 1, // 2: nedpb.VxlanService.CreateVxlan:output_type -> nedpb.CreateVxlanResponse + 3, // 3: nedpb.VxlanService.AttachInterface:output_type -> nedpb.AttachInterfaceResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_ned_proto_init() } +func file_ned_proto_init() { + if File_ned_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_ned_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*CreateVxlanRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ned_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*CreateVxlanResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ned_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*AttachInterfaceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ned_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*AttachInterfaceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ned_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_ned_proto_goTypes, + DependencyIndexes: file_ned_proto_depIdxs, + MessageInfos: file_ned_proto_msgTypes, + }.Build() + File_ned_proto = out.File + file_ned_proto_rawDesc = nil + file_ned_proto_goTypes = nil + file_ned_proto_depIdxs = nil +} diff --git a/src/switch/pkg/ovs/utils.go b/src/switch/pkg/ovs/utils.go new file mode 100644 index 0000000000000000000000000000000000000000..57b7b323a4275594b205299cde7b72b82abd8243 --- /dev/null +++ b/src/switch/pkg/ovs/utils.go @@ -0,0 +1,26 @@ +package ovs + +import ( + "crypto/sha256" + "encoding/hex" +) + +// generateDatapathID generates a datapath ID from the switch name +func GenerateDatapathID(switchName string) string { + // Create a new SHA256 hash object + hash := sha256.New() + + // Write the switch name to the hash object + hash.Write([]byte(switchName)) + + // Get the hashed bytes + hashedBytes := hash.Sum(nil) + + // Take the first 8 bytes of the hash to create a 64-bit ID + dpidBytes := hashedBytes[:8] + + // Convert the bytes to a hexadecimal string + dpid := hex.EncodeToString(dpidBytes) + + return dpid +} diff --git a/src/switch/pkg/ovs/vsctl.go b/src/switch/pkg/ovs/vsctl.go index 8df0a16597b480d4607052b486dc87d1a2a09c32..f3f1283542ba22b7758c71c84d54688df4c88b4c 100644 --- a/src/switch/pkg/ovs/vsctl.go +++ b/src/switch/pkg/ovs/vsctl.go @@ -19,6 +19,7 @@ type Bridge struct { Controller string Name string Protocol string + DatapathId string Ports []Port } @@ -58,11 +59,18 @@ func NewBridge(bridgeConf Bridge) (Bridge, error) { return bridge, errors.New("could not set brtun interface up") } + if bridgeConf.DatapathId != "" { + err := exec.Command("ovs-vsctl", "set", "bridge", bridge.Name, fmt.Sprintf("other-config:datapath-id=%s", bridgeConf.DatapathId)).Run() + if err != nil { + return bridge, errors.New("could not set custom datapath id") + } + } + protocolString := fmt.Sprintf("protocols=%s", bridgeConf.Protocol) err = exec.Command("ovs-vsctl", "set", "bridge", "brtun", protocolString).Run() if err != nil { - return bridge, errors.New("could not set brtun messaing protocol to OpenFlow13") + return bridge, errors.New("could not set brtun messaging protocol to OpenFlow13") } bridge.Protocol = bridgeConf.Protocol diff --git a/src/switch/setup_switch.sh b/src/switch/setup_switch.sh index 5bc2dfe286a2dbbc5beb488d8723e3392fff3566..cb16ee060165e54402863c12f42e8a1c7f213e13 100644 --- a/src/switch/setup_switch.sh +++ b/src/switch/setup_switch.sh @@ -6,7 +6,7 @@ ovs-vsctl --db=unix:/var/run/openvswitch/db.sock --no-wait init ovs-vswitchd --pidfile=/var/run/openvswitch/ovs-vswitchd.pid --detach -l2sm-init --n_veths=$NVETHS --controller_ip=$CONTROLLERIP +l2sm-init --n_veths=$NVETHS --controller_ip=$CONTROLLERIP --switch_name=$NODENAME sleep 20