From c8d5124a818a9b45b4a5be7f7de68f42455e0331 Mon Sep 17 00:00:00 2001
From: Alex ubuntu vm <alexdecb@yahoo.es>
Date: Mon, 22 Apr 2024 15:33:32 +0200
Subject: [PATCH] switches: restructured the file that defines the topology

---
 configs/networkTopology.json       |   8 ++
 configs/sampleFile.json            |  12 +--
 configs/switchConfig.json          |   8 ++
 src/switch/cmd/l2sm-vxlans/main.go | 133 +++++++++++++++++++++++------
 4 files changed, 127 insertions(+), 34 deletions(-)
 create mode 100644 configs/networkTopology.json
 create mode 100644 configs/switchConfig.json

diff --git a/configs/networkTopology.json b/configs/networkTopology.json
new file mode 100644
index 0000000..f9088bf
--- /dev/null
+++ b/configs/networkTopology.json
@@ -0,0 +1,8 @@
+{
+  "Nodes": [
+    {"name": "l2sm1", "nodeIP": "10.1.14.29"},{"name": "l2sm2", "nodeIP": "10.1.72.109"}
+  ],
+  "Links": [
+    {"endpointA": "l2sm1", "endpointB": "l2sm2"}
+  ]
+}
diff --git a/configs/sampleFile.json b/configs/sampleFile.json
index b66ca57..8f6038a 100644
--- a/configs/sampleFile.json
+++ b/configs/sampleFile.json
@@ -1,12 +1,12 @@
 [
     {
-        "name": "<NODE_SWITCH_1>",
-        "nodeIP": "<IP_SWITCH_1>",
-        "neighborNodes": ["<NODE_SWITCH_2>"]
+        "name": "l2sm1",
+        "nodeIP": "10.1.14.34",
+        "neighborNodes": ["l2sm2"]
     },
     {
-        "name": "<NODE_SWITCH_2>",
-        "nodeIP": "<IP_SWITCH_2>",
-        "neighborNodes": ["<NODE_SWITCH_1>"]
+        "name": "l2sm2",
+        "nodeIP": "10.1.72.84",
+        "neighborNodes": ["l2sm1"]
     }
 ]
diff --git a/configs/switchConfig.json b/configs/switchConfig.json
new file mode 100644
index 0000000..f9088bf
--- /dev/null
+++ b/configs/switchConfig.json
@@ -0,0 +1,8 @@
+{
+  "Nodes": [
+    {"name": "l2sm1", "nodeIP": "10.1.14.29"},{"name": "l2sm2", "nodeIP": "10.1.72.109"}
+  ],
+  "Links": [
+    {"endpointA": "l2sm1", "endpointB": "l2sm2"}
+  ]
+}
diff --git a/src/switch/cmd/l2sm-vxlans/main.go b/src/switch/cmd/l2sm-vxlans/main.go
index 3c3434d..7573f78 100644
--- a/src/switch/cmd/l2sm-vxlans/main.go
+++ b/src/switch/cmd/l2sm-vxlans/main.go
@@ -5,15 +5,24 @@ import (
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"ovs-switch/pkg/ovs"
 )
 
 type Node struct {
-	Name          string `json:"name"`
-	NodeIP        string `json:"nodeIP"`
-	NeighborNodes []Node `json:"neighborNodes"`
+	Name          string   `json:"name"`
+	NodeIP        string   `json:"nodeIP"`
+	NeighborNodes []string `json:"neighborNodes"`
+}
+
+type Link struct {
+	EndpointNodeA string `json:"endpointA"`
+	EndpointNodeB string `json:"endpointB"`
+}
+
+type Topology struct {
+	Nodes []Node `json:"Nodes"`
+	Links []Link `json:"Links"`
 }
 
 // Script that takes two required arguments:
@@ -21,6 +30,8 @@ type Node struct {
 // the second one is the path to the configuration file, in reference to the code.
 func main() {
 
+	//configDir, _, fileType, err := takeArguments()
+
 	configDir, nodeName, fileType, err := takeArguments()
 
 	bridge := ovs.FromName("brtun")
@@ -30,14 +41,30 @@ func main() {
 		return
 	}
 
-	nodes, err := readFile(configDir)
-
 	switch fileType {
 	case "topology":
-		err = createTopology(bridge, nodes, nodeName)
+		var topology Topology
+
+		err = readFile(configDir, &topology)
+
+		if err != nil {
+			fmt.Println("Error with the provided file. Error:", err)
+			return
+		}
+
+		fmt.Println(topology)
+		err = createTopology(bridge, topology, nodeName)
 
 	case "neighbors":
-		err = connectToNeighbors(bridge, nodes[0])
+		var node Node
+		err := readFile(configDir, &node)
+
+		if err != nil {
+			fmt.Println("Error with the provided file. Error:", err)
+			return
+		}
+
+		err = connectToNeighbors(bridge, node)
 	}
 
 	if err != nil {
@@ -58,7 +85,7 @@ func takeArguments() (string, string, string, error) {
 	switch {
 	case *nodeName == "":
 		return "", "", "", errors.New("node name is not defined")
-	case *fileType != "topology" || *fileType != "neighbors":
+	case *fileType != "topology" && *fileType != "neighbors":
 		return "", "", "", errors.New("file type not supported. Available types: 'topology' and 'neighbors'")
 	case configDir == "":
 		return "", "", "", errors.New("config directory is not defined")
@@ -67,47 +94,97 @@ func takeArguments() (string, string, string, error) {
 	return configDir, *nodeName, *fileType, nil
 }
 
-func createTopology(bridge ovs.Bridge, nodes []Node, nodeName string) error {
+/**
+Example:
+{
+    "Nodes": [
+        {
+            "name": "l2sm1",
+            "nodeIP": "10.1.14.53"
+        },
+        {
+            "name": "l2sm2",
+            "nodeIP": "10.1.14.90"
+        }
+    ],
+    "Links": [
+        {
+            "endpointA": "l2sm1",
+            "endpointB": "l2sm2"
+        }
+    ]
+}
 
-	// Search for the corresponding node in the configuration, according to the first passed parameter.
-	// Once the node is found, create a bridge for every neighbour node defined.
-	// The bridge is created with the nodeIp and neighborNodeIP and VNI. The VNI is generated in the l2sm-controller thats why its set to 'flow'.
-	for _, node := range nodes {
-		if node.Name == nodeName {
-			//nodeIP := strings.TrimSpace(node.NodeIP)
-			connectToNeighbors(bridge, node)
+*/
+func createTopology(bridge ovs.Bridge, topology Topology, nodeName string) error {
+
+	nodeMap := make(map[string]string)
+	for _, node := range topology.Nodes {
+		nodeMap[node.Name] = node.NodeIP
+	}
+
+	localIp := nodeMap[nodeName]
+
+	for vxlanNumber, link := range topology.Links {
+		vxlanId := fmt.Sprintf("vxlan%d", vxlanNumber)
+		var remoteIp string
+		switch nodeName {
+		case link.EndpointNodeA:
+			remoteIp = nodeMap[link.EndpointNodeB]
+		case link.EndpointNodeB:
+			remoteIp = nodeMap[link.EndpointNodeA]
+		default:
+			break
 		}
+		err := bridge.CreateVxlan(ovs.Vxlan{VxlanId: vxlanId, LocalIp: localIp, RemoteIp: remoteIp, UdpPort: "7000"})
+
+		if err != nil {
+			return fmt.Errorf("could not create vxlan between node %s and node %s", link.EndpointNodeA, link.EndpointNodeB)
+		} else {
+			fmt.Printf("Created vxlan between node %s and node %s.\n", link.EndpointNodeA, link.EndpointNodeB)
+		}
+
 	}
 	return nil
+
 }
 
-func readFile(configDir string) ([]Node, error) {
+func readFile(configDir string, dataStruct interface{}) error {
+
 	/// Read file and save in memory the JSON info
-	data, err := ioutil.ReadFile(configDir)
+	data, err := os.ReadFile(configDir)
 	if err != nil {
 		fmt.Println("No input file was found.", err)
-		return nil, err
+		return err
 	}
 
-	var nodes []Node
-	err = json.Unmarshal(data, &nodes)
+	err = json.Unmarshal(data, &dataStruct)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	return nodes, nil
+	return nil
 
 }
 
+/**
+Example:
+
+        {
+            "Name": "l2sm1",
+            "nodeIP": "10.1.14.53",
+			"neighborNodes":["10.4.2.3","10.4.2.5"]
+		}
+*/
 func connectToNeighbors(bridge ovs.Bridge, node Node) error {
-	for vxlanNumber, neighbor := range node.NeighborNodes {
+	for vxlanNumber, neighborIp := range node.NeighborNodes {
 		vxlanId := fmt.Sprintf("vxlan%d", vxlanNumber)
-		err := bridge.CreateVxlan(ovs.Vxlan{VxlanId: vxlanId, LocalIp: node.NodeIP, RemoteIp: neighbor.NodeIP, UdpPort: "7000"})
+		err := bridge.CreateVxlan(ovs.Vxlan{VxlanId: vxlanId, LocalIp: node.NodeIP, RemoteIp: neighborIp, UdpPort: "7000"})
 
 		if err != nil {
-			return fmt.Errorf("could not create vxlan between node %s and node %s", node.Name, neighbor)
+			return fmt.Errorf("could not create vxlan with neighbor %s", neighborIp)
 		} else {
-			fmt.Printf("Created vxlan between node %s and node %s.\n", node.Name, neighbor)
+			fmt.Printf("Created vxlan with neighbor %s", neighborIp)
 		}
 	}
 	return nil
-- 
GitLab