Refactor of the OVSDB Plugin
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / impl / BridgeConfigurationManagerImpl.java
1 /*
2  * Copyright (C) 2013 Red Hat, Inc.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Authors : Madhu Venugopal, Brent Salisbury, Sam Hague
9  */
10 package org.opendaylight.ovsdb.openstack.netvirt.impl;
11
12 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
13 import org.opendaylight.controller.sal.core.Node;
14 import org.opendaylight.controller.sal.utils.Status;
15 import org.opendaylight.controller.sal.utils.StatusCode;
16 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
17 import org.opendaylight.ovsdb.lib.notation.Row;
18 import org.opendaylight.ovsdb.lib.notation.UUID;
19 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
23 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
24 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
25 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
26 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
27 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
28 import org.opendaylight.ovsdb.schema.openvswitch.Port;
29
30 import com.google.common.base.Preconditions;
31 import com.google.common.collect.Lists;
32 import com.google.common.collect.Maps;
33 import org.apache.commons.lang3.tuple.ImmutablePair;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41
42 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager {
43     static final Logger logger = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
44
45     // The implementation for each of these services is resolved by the OSGi Service Manager
46     private volatile org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService configurationService;
47     private volatile NetworkingProviderManager networkingProviderManager;
48     private volatile OvsdbConfigurationService ovsdbConfigurationService;
49
50     public BridgeConfigurationManagerImpl() {
51     }
52
53     @Override
54     public String getBridgeUuid(Node node, String bridgeName) {
55         Preconditions.checkNotNull(ovsdbConfigurationService);
56         try {
57              Map<String, Row> bridgeTable =
58                      ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
59             if (bridgeTable == null) return null;
60             for (String key : bridgeTable.keySet()) {
61                 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
62                 if (bridge.getName().equals(bridgeName)) return key;
63             }
64         } catch (Exception e) {
65             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
66         }
67         return null;
68     }
69
70     @Override
71     public boolean isNodeNeutronReady(Node node) {
72         Preconditions.checkNotNull(configurationService);
73         return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
74     }
75
76     @Override
77     public boolean isNodeOverlayReady(Node node) {
78         Preconditions.checkNotNull(ovsdbConfigurationService);
79         return this.isNodeNeutronReady(node)
80                && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
81     }
82
83     @Override
84     public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
85         Preconditions.checkNotNull(ovsdbConfigurationService);
86         for (UUID portsUUID : bridge.getPortsColumn().getData()) {
87             try {
88                 Row portRow = ovsdbConfigurationService.getRow(node,
89                                                         ovsdbConfigurationService.getTableName(node, Port.class),
90                                                         portsUUID.toString());
91
92                 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
93                 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
94                     return true;
95                 }
96             } catch (Exception e) {
97                 logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
98             }
99         }
100
101         return false;
102     }
103
104     @Override
105     public boolean isNodeTunnelReady(Node node) {
106         Preconditions.checkNotNull(configurationService);
107         Preconditions.checkNotNull(networkingProviderManager);
108
109         /* Is br-int created? */
110         Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
111         if (intBridge == null) {
112             return false;
113         }
114
115         if (networkingProviderManager == null) {
116             logger.error("Provider Network Manager is not available");
117             return false;
118         }
119         if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
120             /* Is br-net created? */
121             Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
122             if (netBridge == null) {
123                 return false;
124             }
125
126             if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
127                 return false;
128             }
129         }
130         return true;
131     }
132
133     @Override
134     public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
135         Preconditions.checkNotNull(ovsdbConfigurationService);
136         Preconditions.checkNotNull(networkingProviderManager);
137
138         /* is br-int created */
139         Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
140         if (intBridge == null) {
141             logger.trace("isNodeVlanReady: node: {}, br-int missing", node);
142             return false;
143         }
144
145         if (networkingProviderManager == null) {
146             logger.error("Provider Network Manager is not available");
147             return false;
148         }
149         if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
150             /* is br-net created? */
151             Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
152
153             if (netBridge == null) {
154                 logger.trace("isNodeVlanReady: node: {}, br-net missing", node);
155                 return false;
156             }
157
158             if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
159                 logger.trace("isNodeVlanReady: node: {}, patch missing", node);
160                 return false;
161             }
162
163             /* Check if physical device is added to br-net. */
164             String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
165             if (isPortOnBridge(node, netBridge, phyNetName)) {
166                 return true;
167             }
168         } else {
169             /* Check if physical device is added to br-int. */
170             String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
171             if (isPortOnBridge(node, intBridge, phyNetName)) {
172                 return true;
173             }
174         }
175
176         logger.trace("isNodeVlanReady: node: {}, eth missing", node);
177         return false;
178     }
179
180     @Override
181     public void prepareNode(Node node) {
182         Preconditions.checkNotNull(networkingProviderManager);
183
184         try {
185             this.createIntegrationBridge(node);
186         } catch (Exception e) {
187             logger.error("Error creating Integration Bridge on " + node.toString(), e);
188             return;
189         }
190         if (networkingProviderManager == null) {
191             logger.error("Error creating internal network. Provider Network Manager unavailable");
192             return;
193         }
194         networkingProviderManager.getProvider(node).initializeFlowRules(node);
195     }
196
197     /*
198      * Check if the full network setup is available. If not, create it.
199      */
200     @Override
201     public boolean createLocalNetwork (Node node, NeutronNetwork network) {
202         boolean isCreated = false;
203         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
204             if (!this.isNodeVlanReady(node, network)) {
205                 try {
206                     isCreated = this.createBridges(node, network);
207                 } catch (Exception e) {
208                     logger.error("Error creating internal net network ", node, e);
209                 }
210             } else {
211                 isCreated = true;
212             }
213         } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
214                    network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
215             if (!this.isNodeTunnelReady(node)) {
216                 try {
217                     isCreated = this.createBridges(node, network);
218                 } catch (Exception e) {
219                     logger.error("Error creating internal net network ", node, e);
220                 }
221             } else {
222                 isCreated = true;
223             }
224         }
225         return isCreated;
226     }
227
228     @Override
229     public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
230         String phyIf = null;
231         try {
232             Map<String, Row> ovsTable =
233                     ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
234
235             if (ovsTable == null) {
236                 logger.error("OpenVSwitch table is null for Node {} ", node);
237                 return null;
238             }
239
240             // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
241             // The specification does not restrict the number of rows so we choose the first we find.
242             for (Row row : ovsTable.values()) {
243                 String providerMaps;
244                 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
245                 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
246
247                 if (configs == null) {
248                     logger.debug("OpenVSwitch table is null for Node {} ", node);
249                     continue;
250                 }
251
252                 providerMaps = configs.get(configurationService.getProviderMappingsKey());
253                 if (providerMaps == null) {
254                     providerMaps = configurationService.getDefaultProviderMapping();
255                 }
256
257                 if (providerMaps != null) {
258                     for (String map : providerMaps.split(",")) {
259                         String[] pair = map.split(":");
260                         if (pair[0].equals(physicalNetwork)) {
261                             phyIf = pair[1];
262                             break;
263                         }
264                     }
265                 }
266
267                 if (phyIf != null) {
268                     break;
269                 }
270             }
271         } catch (Exception e) {
272             logger.error("Unable to find physical interface for Node: {}, Network {}",
273                          node, physicalNetwork, e);
274         }
275
276         if (phyIf == null) {
277             logger.error("Physical interface not found for Node: {}, Network {}",
278                          node, physicalNetwork);
279         }
280
281         return phyIf;
282     }
283
284     @Override
285     public List<String> getAllPhysicalInterfaceNames(Node node) {
286         List<String> phyIfName = Lists.newArrayList();
287
288         try {
289             Map<String, Row> ovsTable =
290                     ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
291
292             if (ovsTable == null) {
293                 logger.error("OpenVSwitch table is null for Node {} ", node);
294                 return null;
295             }
296
297             // While there is only one entry in the HashMap, we can't access it by index...
298             for (Row row : ovsTable.values()) {
299                 String bridgeMaps;
300                 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
301                 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
302
303                 if (configs == null) {
304                     logger.debug("OpenVSwitch table is null for Node {} ", node);
305                     continue;
306                 }
307
308                 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
309                 if (bridgeMaps == null) {
310                     bridgeMaps = configurationService.getDefaultProviderMapping();
311                 }
312
313                 if (bridgeMaps != null) {
314                     for (String map : bridgeMaps.split(",")) {
315                         String[] pair = map.split(":");
316                         phyIfName.add(pair[1]);
317                     }
318                 }
319             }
320         } catch (Exception e) {
321             logger.error("Unable to find physical interface for Node: {}",
322                          node, e);
323         }
324
325         logger.debug("Physical interface for Node: {}, If: {}",
326                      node, phyIfName);
327
328         return phyIfName;
329     }
330
331     /**
332      * Returns the Bridge for a given node and bridgeName
333      */
334     public Bridge getBridge (Node node, String bridgeName) {
335         Preconditions.checkNotNull(ovsdbConfigurationService);
336         try {
337             Map<String, Row> bridgeTable =
338                     ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
339             if (bridgeTable != null) {
340                 for (String key : bridgeTable.keySet()) {
341                     Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
342                     if (bridge.getName().equals(bridgeName)) {
343                         return bridge;
344                     }
345                 }
346             }
347         } catch (Exception e) {
348             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
349         }
350         return null;
351     }
352
353     /**
354      * Returns true if a patch port exists between the Integration Bridge and Network Bridge
355      */
356     private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
357         Preconditions.checkNotNull(ovsdbConfigurationService);
358
359         boolean isPatchCreated = false;
360
361         String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
362         if (isPortOnBridge(node, intBridge, portName)) {
363             portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
364             if (isPortOnBridge(node, netBridge, portName)) {
365                 isPatchCreated = true;
366             }
367         }
368
369         return isPatchCreated;
370     }
371
372     /**
373      * Creates the Integration Bridge
374      */
375     private void createIntegrationBridge (Node node) throws Exception {
376         Preconditions.checkNotNull(ovsdbConfigurationService);
377
378         String brInt = configurationService.getIntegrationBridgeName();
379
380         Status status = this.addBridge(node, brInt, null, null);
381         if (!status.isSuccess()) {
382             logger.debug("Integration Bridge Creation Status: {}", status);
383         }
384     }
385
386     /**
387      * Create and configure bridges for all network types and OpenFlow versions.
388      *
389        OF 1.0 vlan:
390        Bridge br-int
391             Port patch-net
392                 Interface patch-net
393                     type: patch
394                     options: {peer=patch-int}
395             Port br-int
396                 Interface br-int
397                     type: internal
398        Bridge br-net
399             Port "eth1"
400                 Interface "eth1"
401             Port patch-int
402                 Interface patch-int
403                     type: patch
404                     options: {peer=patch-net}
405             Port br-net
406                 Interface br-net
407                     type: internal
408
409        OF 1.0 tunnel:
410        Bridge br-int
411             Port patch-net
412                 Interface patch-net
413                     type: patch
414                     options: {peer=patch-int}
415             Port br-int
416                 Interface br-int
417                     type: internal
418        Bridge "br-net"
419             Port patch-int
420                 Interface patch-int
421                     type: patch
422                     options: {peer=patch-net}
423             Port br-net
424                 Interface br-net
425                     type: internal
426
427        OF 1.3 vlan:
428        Bridge br-int
429             Port "eth1"
430                 Interface "eth1"
431             Port br-int
432                 Interface br-int
433                     type: internal
434
435        OF 1.3 tunnel:
436        Bridge br-int
437             Port br-int
438                 Interface br-int
439                     type: internal
440      */
441     private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
442         Preconditions.checkNotNull(ovsdbConfigurationService);
443         Preconditions.checkNotNull(networkingProviderManager);
444         Status status;
445
446         logger.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
447
448         if (networkingProviderManager == null) {
449             logger.error("Provider Network Manager is not available");
450             return false;
451         }
452         if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) { /* indicates OF 1.0 */
453             String brInt = configurationService.getIntegrationBridgeName();
454             String brNet = configurationService.getNetworkBridgeName();
455             String patchNet = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brNet));
456             String patchInt = configurationService.getPatchPortName(new ImmutablePair<>(brNet, brInt));
457
458             status = this.addBridge(node, brInt, patchNet, patchInt);
459             if (!status.isSuccess()) {
460                 logger.debug("{} Bridge Creation Status: {}", brInt, status);
461                 return false;
462             }
463             status = this.addBridge(node, brNet, patchInt, patchNet);
464             if (!status.isSuccess()) {
465                 logger.debug("{} Bridge Creation Status: {}", brNet, status);
466                 return false;
467             }
468
469             /* For vlan network types add physical port to br-net. */
470             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
471                 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
472                 status = addPortToBridge(node, brNet, phyNetName);
473                 if (!status.isSuccess()) {
474                     logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
475                     return false;
476                 }
477             }
478         } else {
479             String brInt = configurationService.getIntegrationBridgeName();
480             status = this.addBridge(node, brInt, null, null);
481             if (!status.isSuccess()) {
482                 logger.debug("{} Bridge Creation Status: {}", brInt, status);
483                 return false;
484             }
485
486             /* For vlan network types add physical port to br-int. */
487             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
488                 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
489                 status = addPortToBridge(node, brInt, phyNetName);
490                 if (!status.isSuccess()) {
491                     logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
492                     return false;
493                 }
494             }
495         }
496
497         logger.debug("createNetNetwork: node: {}, status: success", node);
498         return true;
499     }
500
501     /**
502      * Add a Port to a Bridge
503      */
504     private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
505         Preconditions.checkNotNull(ovsdbConfigurationService);
506
507         logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
508
509         String bridgeUUID = this.getBridgeUuid(node, bridgeName);
510         if (bridgeUUID == null) {
511             logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
512             return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
513         }
514
515         /* Check if the port already exists. */
516         Row row = ovsdbConfigurationService
517                 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
518         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
519         if (bridge != null) {
520             if (isPortOnBridge(node, bridge, portName)) {
521                 logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
522                 return new Status(StatusCode.SUCCESS);
523             }
524         } else {
525             logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
526             return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
527         }
528
529         Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
530         port.setName(portName);
531         StatusWithUuid statusWithUuid =
532                 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
533         if (!statusWithUuid.isSuccess()) {
534             logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
535             return statusWithUuid;
536         }
537
538         String portUUID = statusWithUuid.getUuid().toString();
539         String interfaceUUID = null;
540         int timeout = 6;
541         while ((interfaceUUID == null) && (timeout > 0)) {
542             Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
543             port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
544             Set<UUID> interfaces = port.getInterfacesColumn().getData();
545             if (interfaces == null || interfaces.size() == 0) {
546                 // Wait for the OVSDB update to sync up the Local cache.
547                 Thread.sleep(500);
548                 timeout--;
549                 continue;
550             }
551             interfaceUUID = interfaces.toArray()[0].toString();
552             Row intf = ovsdbConfigurationService.getRow(node,
553                                                 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
554             if (intf == null) {
555                 interfaceUUID = null;
556             }
557         }
558
559         if (interfaceUUID == null) {
560             logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
561             return new Status(StatusCode.INTERNALERROR);
562         }
563
564         return new Status(StatusCode.SUCCESS);
565     }
566
567     /**
568      * Add a Patch Port to a Bridge
569      */
570     private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
571         Preconditions.checkNotNull(ovsdbConfigurationService);
572
573         logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
574                      node, bridgeUUID, portName, peerPortName);
575
576         /* Check if the port already exists. */
577         Row bridgeRow = ovsdbConfigurationService.getRow(node,
578                                                   ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
579         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
580         if (bridge != null) {
581             if (isPortOnBridge(node, bridge, portName)) {
582                 logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
583                 return new Status(StatusCode.SUCCESS);
584             }
585         } else {
586             logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
587             return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
588         }
589
590         Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
591         patchPort.setName(portName);
592         // Create patch port and interface
593         StatusWithUuid statusWithUuid =
594                 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
595         if (!statusWithUuid.isSuccess()) return statusWithUuid;
596
597         String patchPortUUID = statusWithUuid.getUuid().toString();
598
599         String interfaceUUID = null;
600         int timeout = 6;
601         while ((interfaceUUID == null) && (timeout > 0)) {
602             Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
603             patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
604             Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
605             if (interfaces == null || interfaces.size() == 0) {
606                 // Wait for the OVSDB update to sync up the Local cache.
607                 Thread.sleep(500);
608                 timeout--;
609                 continue;
610             }
611             interfaceUUID = interfaces.toArray()[0].toString();
612         }
613
614         if (interfaceUUID == null) {
615             return new Status(StatusCode.INTERNALERROR);
616         }
617
618         Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
619         intf.setType("patch");
620         Map<String, String> options = Maps.newHashMap();
621         options.put("peer", peerPortName);
622         intf.setOptions(options);
623         return ovsdbConfigurationService.updateRow(node,
624                                             intf.getSchema().getName(),
625                                             patchPortUUID,
626                                             interfaceUUID,
627                                             intf.getRow());
628     }
629
630     /**
631      * Add Bridge to a Node
632      */
633     private Status addBridge(Node node, String bridgeName,
634                              String localPatchName, String remotePatchName) throws Exception {
635         Preconditions.checkNotNull(ovsdbConfigurationService);
636
637         String bridgeUUID = this.getBridgeUuid(node, bridgeName);
638         Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
639         Set<String> failMode = new HashSet<>();
640         failMode.add("secure");
641         bridge.setFailMode(failMode);
642
643         Set<String> protocols = new HashSet<>();
644         if (networkingProviderManager == null) {
645             logger.error("Provider Network Manager is not available");
646             return new Status(StatusCode.INTERNALERROR);
647         }
648
649         /* ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
650          * or, alternatively it should not attempt to add set unsupported fields
651          */
652
653         try {
654             if (!networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
655                 protocols.add(Constants.OPENFLOW13);
656             } else {
657                 protocols.add(Constants.OPENFLOW10);
658             }
659             bridge.setProtocols(protocols);
660         } catch (SchemaVersionMismatchException e) {
661             logger.info(e.toString());
662         }
663
664         if (bridgeUUID == null) {
665             bridge.setName(bridgeName);
666
667             StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
668                                                                          bridge.getSchema().getName(),
669                                                                          null,
670                                                                          bridge.getRow());
671             if (!statusWithUuid.isSuccess()) return statusWithUuid;
672             bridgeUUID = statusWithUuid.getUuid().toString();
673             Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
674             port.setName(bridgeName);
675             Status status = ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
676             logger.debug("addBridge: Inserting Bridge {} {} with protocols {} and status {}",
677                          bridgeName, bridgeUUID, protocols, status);
678         } else {
679             Status status = ovsdbConfigurationService.updateRow(node,
680                                                          bridge.getSchema().getName(),
681                                                          null,
682                                                          bridgeUUID,
683                                                          bridge.getRow());
684             logger.debug("addBridge: Updating Bridge {} {} with protocols {} and status {}",
685                          bridgeName, bridgeUUID, protocols, status);
686         }
687
688         ovsdbConfigurationService.setOFController(node, bridgeUUID);
689
690         if (localPatchName != null &&
691             remotePatchName != null &&
692             networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
693             return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
694         }
695         return new Status(StatusCode.SUCCESS);
696     }
697
698
699 }