6 "github.com/vishvananda/netlink"
10 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
15 var log = logf.Log.WithName("ovn")
17 // CreateVlan creates VLAN with vlanID
18 func CreateVlan(vlanID, interfaceName, logicalInterfaceName string) error {
19 if interfaceName == "" || vlanID == "" || logicalInterfaceName == "" {
20 return fmt.Errorf("CreateVlan invalid parameters: %v %v %v", interfaceName, vlanID, logicalInterfaceName)
22 _, err := netlink.LinkByName(logicalInterfaceName)
26 stdout, stderr, err := RunIP("link", "add", "link", interfaceName, "name", logicalInterfaceName, "type", "vlan", "id", vlanID)
28 log.Error(err, "Failed to create Vlan", "stdout", stdout, "stderr", stderr)
31 stdout, stderr, err = RunIP("link", "set", logicalInterfaceName, "alias", "nfn-"+logicalInterfaceName)
33 log.Error(err, "Failed to create Vlan", "stdout", stdout, "stderr", stderr)
36 stdout, stderr, err = RunIP("link", "set", "dev", logicalInterfaceName, "up")
38 log.Error(err, "Failed to enable Vlan", "stdout", stdout, "stderr", stderr)
44 // DeleteVlan deletes VLAN with logicalInterface Name
45 func DeleteVlan(logicalInterfaceName string) error {
46 if logicalInterfaceName == "" {
47 return fmt.Errorf("DeleteVlan invalid parameters")
49 stdout, stderr, err := RunIP("link", "del", "dev", logicalInterfaceName)
51 log.Error(err, "Failed to create Vlan", "stdout", stdout, "stderr", stderr)
57 // GetVlan returns a list of VLAN configured on the node
58 func GetVlan() []string {
60 links, err := netlink.LinkList()
64 for _, l := range links {
65 if strings.Contains(l.Attrs().Alias, "nfn-") {
66 intfList = append(intfList, l.Attrs().Name)
72 // CreatePnBridge creates Provider network bridge and mappings
73 func CreatePnBridge(nwName, brName, intfName string) error {
74 if nwName == "" || brName == "" || intfName == "" {
75 return fmt.Errorf("CreatePnBridge invalid parameters")
78 stdout, stderr, err := RunOVSVsctl("--may-exist", "add-br", brName)
80 log.Error(err, "Failed to create Bridge", "stdout", stdout, "stderr", stderr)
83 stdout, stderr, err = RunOVSVsctl("--may-exist", "add-port", brName, intfName)
85 log.Error(err, "Failed to add port to Bridge", "stdout", stdout, "stderr", stderr)
88 stdout, stderr, err = RunOVSVsctl("set", "bridge", brName, "external_ids:nfn="+nwName)
90 log.Error(err, "Failed to set nfn-alias", "stdout", stdout, "stderr", stderr)
93 // Update ovn-bridge-mappings
94 updateOvnBridgeMapping(brName, nwName, "add")
98 // DeletePnBridge creates Provider network bridge and mappings
99 func DeletePnBridge(nwName, brName string) error {
100 if nwName == "" || brName == "" {
101 return fmt.Errorf("DeletePnBridge invalid parameters")
104 stdout, stderr, err := RunOVSVsctl("--if-exist", "del-br", brName)
106 log.Error(err, "Failed to delete Bridge", "stdout", stdout, "stderr", stderr)
109 updateOvnBridgeMapping(brName, nwName, "delete")
114 // GetPnBridge returns Provider networks with external ids
115 func GetPnBridge(externalID string) []string {
116 if externalID == "" {
117 log.Error(fmt.Errorf("GetBridge invalid parameters"), "Invalid")
119 stdout, stderr, err := RunOVSVsctl("list-br")
121 log.Error(err, "No bridges found", "stdout", stdout, "stderr", stderr)
124 brNames := strings.Split(stdout, "\n")
126 for _, name := range brNames {
127 stdout, stderr, err = RunOVSVsctl("get", "bridge", name, "external_ids:"+externalID)
129 if !strings.Contains(stderr, "no key") {
130 log.Error(err, "Unknown error reading external_ids", "stdout", stdout, "stderr", stderr)
137 brList = append(brList, name)
143 // Update ovn-bridge-mappings
144 func updateOvnBridgeMapping(brName, nwName, action string) error {
145 stdout, stderr, err := RunOVSVsctl("get", "open", ".", "external-ids:ovn-bridge-mappings")
147 if !strings.Contains(stderr, "no key") {
148 log.Error(err, "Failed to get ovn-bridge-mappings", "stdout", stdout, "stderr", stderr)
152 // Convert csv string to map
153 mm := make(map[string]string)
155 am := strings.Split(stdout, ",")
156 for _, label := range am {
157 l := strings.Split(label, ":")
159 log.Error(fmt.Errorf("Syntax error label: %v", label), "ovnBridgeMapping")
162 mm[strings.TrimSpace(l[0])] = strings.TrimSpace(l[1])
167 } else if action == "delete" {
171 stdout, stderr, err = RunOVSVsctl("remove", "open", ".", "external-ids", "ovn-bridge-mappings")
173 log.Error(err, "Failed to remove ovn-bridge-mappings", "stdout", stdout, "stderr", stderr)
179 return fmt.Errorf("Invalid action %s", action)
182 for key, value := range mm {
183 mapping = mapping + fmt.Sprintf("%s:%s,", key, value)
186 mapping = mapping[:len(mapping)-1]
187 extIDMap := "external-ids:ovn-bridge-mappings=" + mapping
189 stdout, stderr, err = RunOVSVsctl("set", "open", ".", extIDMap)
191 log.Error(err, "Failed to set ovn-bridge-mappings", "stdout", stdout, "stderr", stderr)
197 func parseOvnNetworkObject(ovnnetwork string) ([]map[string]interface{}, error) {
198 var ovnNet []map[string]interface{}
200 if ovnnetwork == "" {
201 return nil, fmt.Errorf("parseOvnNetworkObject:error")
204 if err := json.Unmarshal([]byte(ovnnetwork), &ovnNet); err != nil {
205 return nil, fmt.Errorf("parseOvnNetworkObject: failed to load ovn network err: %v | ovn network: %v", err, ovnnetwork)
211 func setupDistributedRouter(name string) error {
213 // Create a single common distributed router for the cluster.
214 stdout, stderr, err := RunOVNNbctl("--", "--may-exist", "lr-add", name, "--", "set", "logical_router", name, "external_ids:ovn4nfv-cluster-router=yes")
216 log.Error(err, "Failed to create a single common distributed router for the cluster", "stdout", stdout, "stderr", stderr)
219 // Create a logical switch called "ovn4nfv-join" that will be used to connect gateway routers to the distributed router.
220 // The "ovn4nfv-join" will be allocated IP addresses in the range 100.64.1.0/24.
221 stdout, stderr, err = RunOVNNbctl("--may-exist", "ls-add", "ovn4nfv-join")
223 log.Error(err, "Failed to create logical switch called \"ovn4nfv-join\"", "stdout", stdout, "stderr", stderr)
226 // Connect the distributed router to "ovn4nfv-join".
227 routerMac, stderr, err := RunOVNNbctl("--if-exist", "get", "logical_router_port", "rtoj-"+name, "mac")
229 log.Error(err, "Failed to get logical router port rtoj-", "name", name, "stdout", stdout, "stderr", stderr)
233 routerMac = generateMac()
234 stdout, stderr, err = RunOVNNbctl("--", "--may-exist", "lrp-add", name, "rtoj-"+name, routerMac, "100.64.1.1/24", "--", "set", "logical_router_port", "rtoj-"+name, "external_ids:connect_to_ovn4nfvjoin=yes")
236 log.Error(err, "Failed to add logical router port rtoj", "name", name, "stdout", stdout, "stderr", stderr)
240 // Connect the switch "ovn4nfv-join" to the router.
241 stdout, stderr, err = RunOVNNbctl("--", "--may-exist", "lsp-add", "ovn4nfv-join", "jtor-"+name, "--", "set", "logical_switch_port", "jtor-"+name, "type=router", "options:router-port=rtoj-"+name, "addresses="+"\""+routerMac+"\"")
243 log.Error(err, "Failed to add logical switch port to logical router", "stdout", stdout, "stderr", stderr)
249 // generateMac generates mac address.
250 func generateMac() string {
252 newRand := rand.New(rand.NewSource(time.Now().UnixNano()))
253 mac := fmt.Sprintf("%s:%02x:%02x:%02x", prefix, newRand.Intn(255), newRand.Intn(255), newRand.Intn(255))
257 // NextIP returns IP incremented by 1
258 func NextIP(ip net.IP) net.IP {
260 return intToIP(i.Add(i, big.NewInt(1)))
263 func ipToInt(ip net.IP) *big.Int {
264 if v := ip.To4(); v != nil {
265 return big.NewInt(0).SetBytes(v)
267 return big.NewInt(0).SetBytes(ip.To16())
270 func intToIP(i *big.Int) net.IP {
271 return net.IP(i.Bytes())