BUG 9166 - Fix Netvirt L2GW Illegal state exception
[ovsdb.git] / utils / southbound-utils / src / main / java / org / opendaylight / ovsdb / utils / southbound / utils / SouthboundUtils.java
1 /*
2  * Copyright (c) 2015 - 2017 Red Hat, Inc. and others.  All rights reserved.
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
9 package org.opendaylight.ovsdb.utils.southbound.utils;
10
11 import java.math.BigInteger;
12 import java.net.Inet4Address;
13 import java.net.Inet6Address;
14 import java.net.InetAddress;
15 import java.net.NetworkInterface;
16 import java.net.UnknownHostException;
17 import java.security.InvalidParameterException;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Enumeration;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.ovsdb.utils.config.ConfigProperties;
29 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdk;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkr;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhost;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhostuser;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhostuserclient;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGeneve;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre64;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre64;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeLisp;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypePatch;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeSystem;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeTap;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlanGpe;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow10;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow11;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow12;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow13;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow14;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow15;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeBase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeSecure;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeStandalone;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentationBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntry;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
101 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
102 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
103 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
104 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
105 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
106 import org.slf4j.Logger;
107 import org.slf4j.LoggerFactory;
108
109 import com.google.common.collect.ImmutableBiMap;
110
111 public class SouthboundUtils {
112     private static final Logger LOG = LoggerFactory.getLogger(SouthboundUtils.class);
113     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
114     public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
115     private final MdsalUtils mdsalUtils;
116     public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
117     public static short OPENFLOW_PORT = 6653;
118     public static final String OVSDB_URI_PREFIX = "ovsdb";
119     public static final String BRIDGE_URI_PREFIX = "bridge";
120     private static final String DISABLE_IN_BAND = "disable-in-band";
121     private static final String PATCH_PORT_TYPE = "patch";
122     // External ID key used for mapping between an OVSDB port and an interface name
123     private static final String EXTERNAL_INTERFACE_ID_KEY = "iface-id";
124
125     private static final String FORMAT = "(\\d+)\\.(\\d+)\\.(\\d+)";
126     private static final Pattern PATTERN = Pattern.compile(FORMAT);
127
128
129     public SouthboundUtils(MdsalUtils mdsalUtils) {
130         this.mdsalUtils = mdsalUtils;
131     }
132
133     public static final ImmutableBiMap<String, Class<? extends InterfaceTypeBase>> OVSDB_INTERFACE_TYPE_MAP
134             = new ImmutableBiMap.Builder<String, Class<? extends InterfaceTypeBase>>()
135             .put("internal", InterfaceTypeInternal.class)
136             .put("vxlan", InterfaceTypeVxlan.class)
137             .put("vxlan-gpe", InterfaceTypeVxlanGpe.class)
138             .put("patch", InterfaceTypePatch.class)
139             .put("system", InterfaceTypeSystem.class)
140             .put("tap", InterfaceTypeTap.class)
141             .put("geneve", InterfaceTypeGeneve.class)
142             .put("gre", InterfaceTypeGre.class)
143             .put("ipsec_gre", InterfaceTypeIpsecGre.class)
144             .put("gre64", InterfaceTypeGre64.class)
145             .put("ipsec_gre64", InterfaceTypeIpsecGre64.class)
146             .put("lisp", InterfaceTypeLisp.class)
147             .put("dpdk", InterfaceTypeDpdk.class)
148             .put("dpdkr", InterfaceTypeDpdkr.class)
149             .put("dpdkvhost", InterfaceTypeDpdkvhost.class)
150             .put("dpdkvhostuser", InterfaceTypeDpdkvhostuser.class)
151             .put("dpdkvhostuserclient", InterfaceTypeDpdkvhostuserclient.class)
152             .build();
153
154     public static final ImmutableBiMap<Class<? extends OvsdbBridgeProtocolBase>,String> OVSDB_PROTOCOL_MAP
155             = new ImmutableBiMap.Builder<Class<? extends OvsdbBridgeProtocolBase>,String>()
156             .put(OvsdbBridgeProtocolOpenflow10.class,"OpenFlow10")
157             .put(OvsdbBridgeProtocolOpenflow11.class,"OpenFlow11")
158             .put(OvsdbBridgeProtocolOpenflow12.class,"OpenFlow12")
159             .put(OvsdbBridgeProtocolOpenflow13.class,"OpenFlow13")
160             .put(OvsdbBridgeProtocolOpenflow14.class,"OpenFlow14")
161             .put(OvsdbBridgeProtocolOpenflow15.class,"OpenFlow15")
162             .build();
163
164     private static final ImmutableBiMap<Class<? extends OvsdbFailModeBase>,String> OVSDB_FAIL_MODE_MAP
165             = new ImmutableBiMap.Builder<Class<? extends OvsdbFailModeBase>,String>()
166             .put(OvsdbFailModeStandalone.class,"standalone")
167             .put(OvsdbFailModeSecure.class,"secure")
168             .build();
169
170     public static NodeId createNodeId(IpAddress ip, PortNumber port) {
171         String uriString = OVSDB_URI_PREFIX + "://"
172                 + String.valueOf(ip.getValue()) + ":" + port.getValue();
173         Uri uri = new Uri(uriString);
174         return new NodeId(uri);
175     }
176
177     public static Node createNode(ConnectionInfo key) {
178         NodeBuilder nodeBuilder = new NodeBuilder();
179         nodeBuilder.setNodeId(createNodeId(key.getRemoteIp(), key.getRemotePort()));
180         nodeBuilder.addAugmentation(OvsdbNodeAugmentation.class, createOvsdbAugmentation(key));
181         return nodeBuilder.build();
182     }
183
184     public static OvsdbNodeAugmentation createOvsdbAugmentation(ConnectionInfo key) {
185         OvsdbNodeAugmentationBuilder ovsdbNodeBuilder = new OvsdbNodeAugmentationBuilder();
186         ovsdbNodeBuilder.setConnectionInfo(key);
187         return ovsdbNodeBuilder.build();
188     }
189
190     public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
191         return InstanceIdentifier
192                 .create(NetworkTopology.class)
193                 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
194                 .child(Node.class,new NodeKey(nodeId));
195     }
196
197     public static InstanceIdentifier<Node> createInstanceIdentifier(NodeKey ovsdbNodeKey, String bridgeName) {
198         return createInstanceIdentifier(createManagedNodeId(ovsdbNodeKey.getNodeId(), bridgeName));
199     }
200
201     public static NodeId createManagedNodeId(NodeId ovsdbNodeId, String bridgeName) {
202         return new NodeId(ovsdbNodeId.getValue()
203                 + "/" + BRIDGE_URI_PREFIX + "/" + bridgeName);
204     }
205
206     public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key) {
207         return createInstanceIdentifier(key.getRemoteIp(), key.getRemotePort());
208     }
209
210     public static InstanceIdentifier<Node> createInstanceIdentifier(IpAddress ip, PortNumber port) {
211         InstanceIdentifier<Node> path = InstanceIdentifier
212                 .create(NetworkTopology.class)
213                 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
214                 .child(Node.class,createNodeKey(ip,port));
215         LOG.debug("Created ovsdb path: {}",path);
216         return path;
217     }
218
219     public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key,OvsdbBridgeName bridgeName) {
220         return createInstanceIdentifier(createManagedNodeId(key, bridgeName));
221     }
222
223     public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key, String bridgeName) {
224         return createInstanceIdentifier(key, new OvsdbBridgeName(bridgeName));
225     }
226
227     public InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
228
229         InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
230                 .create(NetworkTopology.class)
231                 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
232                 .child(Node.class,node.getKey())
233                 .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
234
235         LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
236         return terminationPointPath;
237     }
238
239     public static NodeKey createNodeKey(IpAddress ip, PortNumber port) {
240         return new NodeKey(createNodeId(ip, port));
241     }
242
243     public static NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) {
244         return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), bridgeName);
245     }
246
247     public static NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) {
248         return new NodeId(createNodeId(ip,port).getValue()
249                 + "/" + BRIDGE_URI_PREFIX + "/" + bridgeName.getValue());
250     }
251
252     public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
253         NodeKey nodeKey = iid.firstKeyOf(Node.class);
254         return nodeKey.getNodeId();
255     }
256
257     public ConnectionInfo getConnectionInfo(Node ovsdbNode) {
258         ConnectionInfo connectionInfo = null;
259         OvsdbNodeAugmentation ovsdbNodeAugmentation = extractOvsdbNode(ovsdbNode);
260         if (ovsdbNodeAugmentation != null) {
261             connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
262         }
263         return connectionInfo;
264     }
265
266     public OvsdbNodeAugmentation extractOvsdbNode(Node node) {
267         return node.getAugmentation(OvsdbNodeAugmentation.class);
268     }
269
270     public static IpAddress createIpAddress(InetAddress address) {
271         IpAddress ip = null;
272         if (address instanceof Inet4Address) {
273             ip = createIpAddress((Inet4Address)address);
274         } else if (address instanceof Inet6Address) {
275             ip = createIpAddress((Inet6Address)address);
276         }
277         return ip;
278     }
279
280     public static IpAddress createIpAddress(Inet4Address address) {
281         return IetfInetUtil.INSTANCE.ipAddressFor(address);
282     }
283
284     public static IpAddress createIpAddress(Inet6Address address) {
285         Ipv6Address ipv6 = new Ipv6Address(address.getHostAddress());
286         return new IpAddress(ipv6);
287     }
288
289     public static ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) {
290         InetAddress inetAddress = null;
291         try {
292             inetAddress = InetAddress.getByName(addressStr);
293         } catch (UnknownHostException e) {
294             LOG.warn("Could not allocate InetAddress", e);
295         }
296
297         IpAddress address = createIpAddress(inetAddress);
298         PortNumber port = new PortNumber(Integer.parseInt(portStr));
299
300         LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
301                 .setRemoteIp(address)
302                 .setRemotePort(port)
303                 .build());
304         return new ConnectionInfoBuilder()
305                 .setRemoteIp(address)
306                 .setRemotePort(port)
307                 .build();
308     }
309
310     public static String connectionInfoToString(final ConnectionInfo connectionInfo) {
311         return String.valueOf(
312                 connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
313     }
314
315     public boolean addOvsdbNode(final ConnectionInfo connectionInfo) {
316         return addOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
317     }
318
319     public boolean addOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
320         boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
321                 createInstanceIdentifier(connectionInfo),
322                 createNode(connectionInfo));
323         if (timeout != 0) {
324             try {
325                 Thread.sleep(timeout);
326             } catch (InterruptedException e) {
327                 LOG.warn("Interrupted while waiting after adding OVSDB node {}",
328                         connectionInfoToString(connectionInfo), e);
329             }
330         }
331         return result;
332     }
333
334     public Node getOvsdbNode(final ConnectionInfo connectionInfo) {
335         return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
336                 createInstanceIdentifier(connectionInfo));
337     }
338
339     public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) {
340         return deleteOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
341     }
342
343     public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
344         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
345                 createInstanceIdentifier(connectionInfo));
346         if (timeout != 0) {
347             try {
348                 Thread.sleep(timeout);
349             } catch (InterruptedException e) {
350                 LOG.warn("Interrupted while waiting after deleting OVSDB node {}",
351                         connectionInfoToString(connectionInfo), e);
352             }
353         }
354         return result;
355     }
356
357     public Node connectOvsdbNode(final ConnectionInfo connectionInfo) {
358         return connectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
359     }
360
361     public Node connectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
362         addOvsdbNode(connectionInfo, timeout);
363         Node node = getOvsdbNode(connectionInfo);
364         LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
365         return node;
366     }
367
368     public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) {
369         return disconnectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
370     }
371
372     public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
373         deleteOvsdbNode(connectionInfo, timeout);
374         LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
375         return true;
376     }
377
378     public List<ControllerEntry> createControllerEntry(String controllerTarget) {
379         List<ControllerEntry> controllerEntriesList = new ArrayList<>();
380         controllerEntriesList.add(new ControllerEntryBuilder()
381                 .setTarget(new Uri(controllerTarget))
382                 .build());
383         return controllerEntriesList;
384     }
385
386     /**
387      * Extract the <code>store</code> type data store contents for the particular bridge identified by
388      * <code>bridgeName</code>.
389      *
390      * @param connectionInfo address for the node
391      * @param bridgeName name of the bridge
392      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
393      * @return <code>store</code> type data store contents
394      */
395     public OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName,
396                                               LogicalDatastoreType store) {
397         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null;
398         Node bridgeNode = getBridgeNode(connectionInfo, bridgeName, store);
399         if (bridgeNode != null) {
400             ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
401         }
402         return ovsdbBridgeAugmentation;
403     }
404
405     /**
406      * extract the <code>LogicalDataStoreType.OPERATIONAL</code> type data store contents for the particular bridge
407      * identified by <code>bridgeName</code>
408      *
409      * @param connectionInfo address for the node
410      * @param bridgeName name of the bridge
411      * @see <code>NetvirtIT.getBridge(ConnectionInfo, String, LogicalDatastoreType)</code>
412      * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
413      */
414     public OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName) {
415         return getBridge(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
416     }
417
418     /**
419      * Extract the node contents from <code>store</code> type data store for the
420      * bridge identified by <code>bridgeName</code>.
421      *
422      * @param connectionInfo address for the node
423      * @param bridgeName name of the bridge
424      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
425      * @return <code>store</code> type data store contents
426      */
427     public Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName, LogicalDatastoreType store) {
428         InstanceIdentifier<Node> bridgeIid = createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
429         return mdsalUtils.read(store, bridgeIid);
430     }
431
432     public Node getBridgeNode(Node node, String bridgeName) {
433         OvsdbBridgeAugmentation bridge = extractBridgeAugmentation(node);
434         if (bridge != null && bridge.getBridgeName().getValue().equals(bridgeName)) {
435             return node;
436         } else {
437             return readBridgeNode(node, bridgeName);
438         }
439     }
440
441     public Node readBridgeNode(Node node, String name) {
442         Node ovsdbNode = node;
443         if (extractNodeAugmentation(ovsdbNode) == null) {
444             ovsdbNode = readOvsdbNode(node);
445             if (ovsdbNode == null) {
446                 return null;
447             }
448         }
449         Node bridgeNode = null;
450         ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode);
451         if (connectionInfo != null) {
452             InstanceIdentifier<Node> bridgeIid =
453                     createInstanceIdentifier(node.getKey(), name);
454             bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
455         }
456         return bridgeNode;
457     }
458
459     public OvsdbNodeAugmentation extractNodeAugmentation(Node node) {
460         return node.getAugmentation(OvsdbNodeAugmentation.class);
461     }
462
463     public OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) {
464         if (node == null) {
465             return null;
466         }
467         return node.getAugmentation(OvsdbBridgeAugmentation.class);
468     }
469
470     public Node readOvsdbNode(Node bridgeNode) {
471         Node ovsdbNode = null;
472         OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
473         if (bridgeAugmentation != null) {
474             InstanceIdentifier<Node> ovsdbNodeIid =
475                     (InstanceIdentifier<Node>) bridgeAugmentation.getManagedBy().getValue();
476             ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid);
477         }else{
478             LOG.debug("readOvsdbNode: Provided node is not a bridge node : {}",bridgeNode);
479         }
480         return ovsdbNode;
481     }
482
483     public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName) {
484         return deleteBridge(connectionInfo, bridgeName, OVSDB_UPDATE_TIMEOUT);
485     }
486
487     public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName, long timeout) {
488         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
489                 createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName)));
490         if (timeout != 0) {
491             try {
492                 Thread.sleep(timeout);
493             } catch (InterruptedException e) {
494                 LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e);
495             }
496         }
497         return result;
498     }
499
500     public List<ProtocolEntry> createMdsalProtocols() {
501         List<ProtocolEntry> protocolList = new ArrayList<>();
502         ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
503                 OVSDB_PROTOCOL_MAP.inverse();
504         protocolList.add(new ProtocolEntryBuilder().setProtocol(mapper.get("OpenFlow13")).build());
505         return protocolList;
506     }
507
508     public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
509                              final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
510                              final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
511                              final Class<? extends DatapathTypeBase> dpType,
512                              final List<BridgeExternalIds> externalIds,
513                              final List<ControllerEntry> controllerEntries,
514                              final List<BridgeOtherConfigs> otherConfigs,
515                              final String dpid) throws InterruptedException {
516         return addBridge(connectionInfo, bridgeIid, bridgeName, bridgeNodeId, setProtocolEntries, failMode,
517                 setManagedBy, dpType, externalIds, controllerEntries, otherConfigs, dpid);
518     }
519
520     /*
521      * base method for adding test bridges.  Other helper methods used to create bridges should utilize this method.
522      *
523      * @param connectionInfo
524      * @param bridgeIid if passed null, one is created
525      * @param bridgeName cannot be null
526      * @param bridgeNodeId if passed null, one is created based on <code>bridgeIid</code>
527      * @param setProtocolEntries toggles whether default protocol entries are set for the bridge
528      * @param failMode toggles whether default fail mode is set for the bridge
529      * @param setManagedBy toggles whether to setManagedBy for the bridge
530      * @param dpType if passed null, this parameter is ignored
531      * @param externalIds if passed null, this parameter is ignored
532      * @param otherConfig if passed null, this parameter is ignored
533      * @return success of bridge addition
534      * @throws InterruptedException
535      */
536     public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
537                              final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
538                              final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
539                              final Class<? extends DatapathTypeBase> dpType,
540                              final List<BridgeExternalIds> externalIds,
541                              final List<ControllerEntry> controllerEntries,
542                              final List<BridgeOtherConfigs> otherConfigs,
543                              final String dpid, long timeout) throws InterruptedException {
544
545         NodeBuilder bridgeNodeBuilder = new NodeBuilder();
546         if (bridgeIid == null) {
547             bridgeIid = createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
548         }
549         if (bridgeNodeId == null) {
550             bridgeNodeId = createManagedNodeId(bridgeIid);
551         }
552         bridgeNodeBuilder.setNodeId(bridgeNodeId);
553         OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
554         ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
555         if (setProtocolEntries) {
556             ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
557         }
558         if (failMode != null) {
559             ovsdbBridgeAugmentationBuilder.setFailMode(failMode);
560         }
561         if (setManagedBy) {
562             setManagedBy(ovsdbBridgeAugmentationBuilder, connectionInfo);
563         }
564         if (dpType != null) {
565             ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
566         }
567         if (externalIds != null) {
568             ovsdbBridgeAugmentationBuilder.setBridgeExternalIds(externalIds);
569         }
570         if (controllerEntries != null) {
571             ovsdbBridgeAugmentationBuilder.setControllerEntry(controllerEntries);
572         }
573         if (otherConfigs != null) {
574             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs);
575         }
576         if (dpid != null && !dpid.isEmpty()) {
577             DatapathId datapathId = new DatapathId(dpid);
578             ovsdbBridgeAugmentationBuilder.setDatapathId(datapathId);
579         }
580         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
581         LOG.debug("Built with the intent to store bridge data {}",
582                 ovsdbBridgeAugmentationBuilder.toString());
583         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
584                 bridgeIid, bridgeNodeBuilder.build());
585         if (timeout != 0) {
586             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
587         }
588         return result;
589     }
590
591     /**
592      * Set the controllers of an existing bridge node
593      * @param ovsdbNode where the bridge is
594      * @param bridgeName Name of the bridge
595      * @param controllers controller strings
596      * @return success if the write to md-sal was successful
597      */
598     public boolean setBridgeController(Node ovsdbNode, String bridgeName, List<String> controllers) {
599         return setBridgeController(ovsdbNode, bridgeName, controllers, null, null);
600     }
601     /**
602      * Set the controllers of an existing bridge node
603      * @param ovsdbNode where the bridge is
604      * @param bridgeName Name of the bridge
605      * @param controllers controller strings
606      * @param maxBackoff Max backoff in milliseconds
607      * @param inactivityProbe inactivity probe in milliseconds
608      * @return success if the write to md-sal was successful
609      */
610     public boolean setBridgeController(Node ovsdbNode, String bridgeName, List<String> controllers,
611             Long maxBackoff, Long inactivityProbe) {
612         LOG.debug("setBridgeController: ovsdbNode: {}, bridgeNode: {}, controller(s): {}",
613                 ovsdbNode, bridgeName, controllers);
614
615         InstanceIdentifier<Node> bridgeNodeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName);
616         Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
617         if (bridgeNode == null) {
618             LOG.info("setBridgeController could not find bridge in configuration {}", bridgeNodeIid);
619             return false;
620         }
621
622         OvsdbBridgeAugmentation bridgeAug = extractBridgeAugmentation(bridgeNode);
623
624         //Only add controller entries that do not already exist on this bridge
625         List<ControllerEntry> existingControllerEntries = bridgeAug.getControllerEntry();
626         List<ControllerEntry> newControllerEntries = new ArrayList<>();
627         if(existingControllerEntries != null) {
628             NEW_ENTRY_LOOP:
629             for (ControllerEntry newEntry : createControllerEntries(controllers, maxBackoff, inactivityProbe)) {
630                 for (ControllerEntry existingEntry : existingControllerEntries) {
631                     if (newEntry.getTarget().equals(existingEntry.getTarget())) {
632                         continue NEW_ENTRY_LOOP;
633                     }
634                 }
635                 newControllerEntries.add(newEntry);
636             }
637         } else {
638             newControllerEntries = createControllerEntries(controllers,maxBackoff, inactivityProbe);
639         }
640
641         if(newControllerEntries.isEmpty()) {
642             return true;
643         }
644
645         NodeBuilder nodeBuilder = new NodeBuilder(bridgeNode);
646         OvsdbBridgeAugmentationBuilder augBuilder = new OvsdbBridgeAugmentationBuilder(bridgeAug);
647
648         augBuilder.setControllerEntry(newControllerEntries);
649         nodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, augBuilder.build());
650         InstanceIdentifier<Node> bridgeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName);
651         return mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid, nodeBuilder.build());
652     }
653
654     public boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
655             final Class<? extends DatapathTypeBase> dpType, String mac) {
656         return addBridge(ovsdbNode, bridgeName, controllersStr, dpType, mac, null, null);
657     }
658
659     public boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
660                              final Class<? extends DatapathTypeBase> dpType, String mac,
661                              Long maxBackoff, Long inactivityProbe) {
662         List<BridgeOtherConfigs> otherConfigs = new ArrayList<>();
663         if (mac != null) {
664             BridgeOtherConfigsBuilder macOtherConfigBuilder = new BridgeOtherConfigsBuilder();
665             macOtherConfigBuilder.setBridgeOtherConfigKey("hwaddr");
666             macOtherConfigBuilder.setBridgeOtherConfigValue(mac);
667             otherConfigs.add(macOtherConfigBuilder.build());
668         }
669
670         return addBridge(ovsdbNode, bridgeName, controllersStr, dpType, otherConfigs, null, null);
671     }
672
673     public boolean addBridge(Node ovsdbNode, String bridgeName, List<String> controllersStr,
674                              final Class<? extends DatapathTypeBase> dpType,
675                              List<BridgeOtherConfigs> otherConfigs,
676                              Long maxBackoff, Long inactivityProbe) {
677         boolean result;
678
679         LOG.info("addBridge: node: {}, bridgeName: {}, controller(s): {}", ovsdbNode, bridgeName, controllersStr);
680         ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode);
681         if (connectionInfo != null) {
682             NodeBuilder bridgeNodeBuilder = new NodeBuilder();
683             InstanceIdentifier<Node> bridgeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName);
684             NodeId bridgeNodeId = createManagedNodeId(bridgeIid);
685             bridgeNodeBuilder.setNodeId(bridgeNodeId);
686             OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
687             ovsdbBridgeAugmentationBuilder.setControllerEntry(createControllerEntries(
688                     controllersStr, maxBackoff, inactivityProbe));
689             ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
690             ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
691             ovsdbBridgeAugmentationBuilder.setFailMode( OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
692             // TODO: Currently netvirt relies on this function to set disabled-in-band=true. However,
693             // TODO (cont): a better design would be to have netvirt pass that in. That way this function
694             // TODO (cont): can take a null otherConfigs to erase other_configs.
695             if (otherConfigs == null) {
696                 otherConfigs = new ArrayList<>();
697             }
698             BridgeOtherConfigsBuilder bridgeOtherConfigsBuilder = new BridgeOtherConfigsBuilder();
699             bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(DISABLE_IN_BAND);
700             bridgeOtherConfigsBuilder.setBridgeOtherConfigValue("true");
701             otherConfigs.add(bridgeOtherConfigsBuilder.build());
702             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs);
703             setManagedByForBridge(ovsdbBridgeAugmentationBuilder, ovsdbNode.getKey());
704             if (dpType != null) {
705                 ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
706             }
707             if (isOvsdbNodeDpdk(ovsdbNode)) {
708                 ovsdbBridgeAugmentationBuilder.setDatapathType(DatapathTypeNetdev.class);
709             }
710             bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
711
712             Node node = bridgeNodeBuilder.build();
713             result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, bridgeIid, node);
714             LOG.info("addBridge: result: {}", result);
715         } else {
716             throw new InvalidParameterException("Could not find ConnectionInfo");
717         }
718         return result;
719     }
720
721
722     private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
723                               final ConnectionInfo connectionInfo) {
724         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(connectionInfo);
725         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
726     }
727
728     public boolean addTerminationPoint(
729             Node bridgeNode, String portName, String type, Map<String, String> options,
730             Map<String, String> externalIds) {
731         return addTerminationPoint(bridgeNode, portName, type, options, externalIds, null);
732     }
733
734     public boolean addTerminationPoint(
735             Node bridgeNode, String portName, String type, Map<String, String> options, Map<String, String> externalIds,
736             Long ofPort) {
737         InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName);
738         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
739
740         tpAugmentationBuilder.setName(portName);
741         tpAugmentationBuilder.setOfport(ofPort);
742         if (type != null) {
743             tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type));
744         }
745
746         if (options != null && options.size() > 0) {
747             List<Options> optionsList = new ArrayList<>();
748             for (Map.Entry<String, String> entry : options.entrySet()) {
749                 OptionsBuilder optionsBuilder = new OptionsBuilder();
750                 optionsBuilder.setKey(new OptionsKey(entry.getKey()));
751                 optionsBuilder.setOption(entry.getKey());
752                 optionsBuilder.setValue(entry.getValue());
753                 optionsList.add(optionsBuilder.build());
754             }
755             tpAugmentationBuilder.setOptions(optionsList);
756         }
757
758         if (externalIds != null && externalIds.size() > 0) {
759             List<InterfaceExternalIds> externalIdsList = new ArrayList<>();
760             for (Map.Entry<String, String> entry : externalIds.entrySet()) {
761                 InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = new InterfaceExternalIdsBuilder();
762                 interfaceExternalIdsBuilder.setKey(new InterfaceExternalIdsKey(entry.getKey()));
763                 interfaceExternalIdsBuilder.setExternalIdKey(entry.getKey());
764                 interfaceExternalIdsBuilder.setExternalIdValue(entry.getValue());
765                 externalIdsList.add(interfaceExternalIdsBuilder.build());
766             }
767             tpAugmentationBuilder.setInterfaceExternalIds(externalIdsList);
768         }
769
770         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
771         tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
772         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
773         /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */
774         return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
775     }
776
777     public Boolean addTerminationPoint(Node bridgeNode, String portName, String type) {
778         return addTerminationPoint(bridgeNode, portName, type, Collections.EMPTY_MAP, null);
779     }
780
781     public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName,
782                                        String type, Map<String, String> options) {
783         InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
784                 bridgeNode, portName);
785         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
786
787         tpAugmentationBuilder.setName(portName);
788         if (type != null) {
789             tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type));
790         }
791
792         List<Options> optionsList = new ArrayList<>();
793         for (Map.Entry<String, String> entry : options.entrySet()) {
794             OptionsBuilder optionsBuilder = new OptionsBuilder();
795             optionsBuilder.setKey(new OptionsKey(entry.getKey()));
796             optionsBuilder.setOption(entry.getKey());
797             optionsBuilder.setValue(entry.getValue());
798             optionsList.add(optionsBuilder.build());
799         }
800         tpAugmentationBuilder.setOptions(optionsList);
801
802         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
803         tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
804         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
805         /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */
806         return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
807     }
808
809     public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type) {
810         InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName);
811         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder =
812                 new OvsdbTerminationPointAugmentationBuilder();
813
814         tpAugmentationBuilder.setName(portName);
815         if (type != null) {
816             tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type));
817         }
818         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
819         tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
820         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
821         return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
822     }
823
824     public Boolean addPatchTerminationPoint(Node node, String bridgeName, String portName, String peerPortName) {
825         Map<String, String> option = new HashMap<>();
826         option.put("peer", peerPortName);
827         return addTerminationPoint(node, bridgeName, portName, PATCH_PORT_TYPE, option);
828     }
829
830     private String getControllerIPAddress() {
831         String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
832         if (addressString != null) {
833             try {
834                 if (InetAddress.getByName(addressString) != null) {
835                     return addressString;
836                 }
837             } catch (UnknownHostException e) {
838                 LOG.error("Host {} is invalid", addressString, e);
839             }
840         }
841
842         addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
843         if (addressString != null) {
844             try {
845                 if (InetAddress.getByName(addressString) != null) {
846                     return addressString;
847                 }
848             } catch (UnknownHostException e) {
849                 LOG.error("Host {} is invalid", addressString, e);
850             }
851         }
852
853         return null;
854     }
855
856     private short getControllerOFPort() {
857         short openFlowPort = OPENFLOW_PORT;
858         String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
859         if (portString != null) {
860             try {
861                 openFlowPort = Short.parseShort(portString);
862             } catch (NumberFormatException e) {
863                 LOG.warn("Invalid port:{}, use default({})", portString,
864                         openFlowPort, e);
865             }
866         }
867         return openFlowPort;
868     }
869
870     public List<String> getControllersFromOvsdbNode(Node node) {
871         List<String> controllersStr = new ArrayList<>();
872
873         String controllerIpStr = getControllerIPAddress();
874         if (controllerIpStr != null) {
875             // If codepath makes it here, the ip address to be used was explicitly provided.
876             // Being so, also fetch openflowPort provided via ConfigProperties.
877             controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL
878                     + ":" + controllerIpStr + ":" + getControllerOFPort());
879         } else {
880             // Check if ovsdb node has manager entries
881             OvsdbNodeAugmentation ovsdbNodeAugmentation = extractOvsdbNode(node);
882             if (ovsdbNodeAugmentation != null) {
883                 List<ManagerEntry> managerEntries = ovsdbNodeAugmentation.getManagerEntry();
884                 if (managerEntries != null && !managerEntries.isEmpty()) {
885                     for (ManagerEntry managerEntry : managerEntries) {
886                         if (managerEntry == null || managerEntry.getTarget() == null) {
887                             continue;
888                         }
889                         String[] tokens = managerEntry.getTarget().getValue().split(":");
890                         if (tokens.length == 3 && tokens[0].equalsIgnoreCase("tcp")) {
891                             controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL
892                                     + ":" + tokens[1] + ":" + getControllerOFPort());
893                         } else if (tokens[0].equalsIgnoreCase("ptcp")) {
894                             ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
895                             if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
896                                 controllerIpStr = String.valueOf(connectionInfo.getLocalIp().getValue());
897                                 controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL
898                                         + ":" + controllerIpStr + ":" + OPENFLOW_PORT);
899                             } else {
900                                 LOG.warn("Ovsdb Node does not contain connection info: {}", node);
901                             }
902                         } else {
903                             LOG.trace("Skipping manager entry {} for node {}",
904                                     managerEntry.getTarget(), node.getNodeId().getValue());
905                         }
906                     }
907                 } else {
908                     LOG.warn("Ovsdb Node does not contain manager entries : {}", node);
909                 }
910             }
911         }
912
913         if (controllersStr.isEmpty()) {
914             // Neither user provided ip nor ovsdb node has manager entries. Lets use local machine ip address.
915             LOG.debug("Use local machine ip address as a OpenFlow Controller ip address");
916             controllerIpStr = getLocalControllerHostIpAddress();
917             if (controllerIpStr != null) {
918                 controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL
919                         + ":" + controllerIpStr + ":" + OPENFLOW_PORT);
920             }
921         }
922
923         if (controllersStr.isEmpty()) {
924             LOG.warn("Failed to determine OpenFlow controller ip address");
925         } else if (LOG.isDebugEnabled()) {
926             controllerIpStr = "";
927             for (String currControllerIpStr : controllersStr) {
928                 controllerIpStr += " " + currControllerIpStr;
929             }
930             LOG.debug("Found {} OpenFlow Controller(s) :{}", controllersStr.size(), controllerIpStr);
931         }
932
933         return controllersStr;
934     }
935
936     private String getLocalControllerHostIpAddress() {
937         String ipaddress = null;
938         try{
939             for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();){
940                 NetworkInterface iface = ifaces.nextElement();
941
942                 for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
943                     InetAddress inetAddr = inetAddrs.nextElement();
944                     if (!inetAddr.isLoopbackAddress() && inetAddr.isSiteLocalAddress()) {
945                         ipaddress = inetAddr.getHostAddress();
946                         break;
947                     }
948                 }
949             }
950         }catch (Exception e){
951             LOG.warn("Exception while fetching local host ip address ", e);
952         }
953         return ipaddress;
954     }
955
956     public long getDataPathId(Node node) {
957         long dpid = 0L;
958         String datapathId = getDatapathId(node);
959         if (datapathId != null) {
960             dpid = new BigInteger(datapathId.replaceAll(":", ""), 16).longValue();
961         }
962         return dpid;
963     }
964
965     public String getDataPathIdStr(final Node node) {
966         if (node != null) {
967             long dpId = getDataPathId(node);
968             if (dpId != 0) {
969                 return String.valueOf(dpId);
970             }
971         }
972
973         return null;
974     }
975
976     public String getDatapathId(Node node) {
977         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
978         return getDatapathId(ovsdbBridgeAugmentation);
979     }
980
981     public String getDatapathId(OvsdbBridgeAugmentation ovsdbBridgeAugmentation) {
982         String datapathId = null;
983         if (ovsdbBridgeAugmentation != null && ovsdbBridgeAugmentation.getDatapathId() != null) {
984             datapathId = ovsdbBridgeAugmentation.getDatapathId().getValue();
985         }
986         return datapathId;
987     }
988
989     public String extractBridgeName(Node node) {
990         return node.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue();
991     }
992
993     public boolean isBridgeOnOvsdbNode(Node ovsdbNode, String bridgeName) {
994         boolean found = false;
995         OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode);
996         if (ovsdbNodeAugmentation != null) {
997             List<ManagedNodeEntry> managedNodes = ovsdbNodeAugmentation.getManagedNodeEntry();
998             if (managedNodes != null) {
999                 for (ManagedNodeEntry managedNode : managedNodes) {
1000                     InstanceIdentifier<?> bridgeIid = managedNode.getBridgeRef().getValue();
1001                     if (bridgeIid.toString().contains(bridgeName)) {
1002                         found = true;
1003                         break;
1004                     }
1005                 }
1006             }
1007         }
1008         return found;
1009     }
1010
1011     public OvsdbBridgeAugmentation getBridgeFromConfig(Node node, String bridge) {
1012         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null;
1013         InstanceIdentifier<Node> bridgeIid =
1014                 createInstanceIdentifier(node.getKey(), bridge);
1015         Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeIid);
1016         if (bridgeNode != null) {
1017             ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
1018         }
1019         return ovsdbBridgeAugmentation;
1020     }
1021
1022     private void setManagedByForBridge(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
1023                                        NodeKey ovsdbNodeKey) {
1024         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(ovsdbNodeKey.getNodeId());
1025         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
1026     }
1027
1028     public boolean isOvsdbNodeDpdk(Node ovsdbNode) {
1029         boolean found = false;
1030         OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode);
1031         if (ovsdbNodeAugmentation != null) {
1032             List<InterfaceTypeEntry> ifTypes = ovsdbNodeAugmentation.getInterfaceTypeEntry();
1033             if (ifTypes != null) {
1034                 for (InterfaceTypeEntry ifType : ifTypes) {
1035                     if (ifType.getInterfaceType().equals(InterfaceTypeDpdk.class)) {
1036                         found = true;
1037                         break;
1038                     }
1039                 }
1040             }
1041         }
1042         return found;
1043     }
1044
1045     private List<ControllerEntry> createControllerEntries(List<String> controllersStr,
1046             Long maxBackoff, Long inactivityProbe) {
1047         List<ControllerEntry> controllerEntries = new ArrayList<>();
1048         if (controllersStr != null) {
1049             for (String controllerStr : controllersStr) {
1050                 ControllerEntryBuilder controllerEntryBuilder = new ControllerEntryBuilder();
1051                 controllerEntryBuilder.setTarget(new Uri(controllerStr));
1052                 if (maxBackoff != null) {
1053                     controllerEntryBuilder.setMaxBackoff(maxBackoff);
1054                 }
1055                 if (inactivityProbe != null) {
1056                     controllerEntryBuilder.setInactivityProbe(inactivityProbe);
1057                 }
1058                 controllerEntries.add(controllerEntryBuilder.build());
1059             }
1060         }
1061         return controllerEntries;
1062     }
1063
1064     public OvsdbTerminationPointAugmentation extractTerminationPointAugmentation(Node bridgeNode, String portName) {
1065         if (bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class) != null) {
1066             List<OvsdbTerminationPointAugmentation> tpAugmentations = extractTerminationPointAugmentations(bridgeNode);
1067             for (OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation : tpAugmentations) {
1068                 if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1069                     return ovsdbTerminationPointAugmentation;
1070                 }
1071             }
1072         }
1073         return null;
1074     }
1075
1076     public List<OvsdbTerminationPointAugmentation> extractTerminationPointAugmentations( Node node ) {
1077         List<OvsdbTerminationPointAugmentation> tpAugmentations = new ArrayList<>();
1078         if (node == null) {
1079             LOG.error("extractTerminationPointAugmentations: Node value is null");
1080             return Collections.emptyList();
1081         }
1082         List<TerminationPoint> terminationPoints = node.getTerminationPoint();
1083         if(terminationPoints != null && !terminationPoints.isEmpty()){
1084             for(TerminationPoint tp : terminationPoints){
1085                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
1086                         tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1087                 if (ovsdbTerminationPointAugmentation != null) {
1088                     tpAugmentations.add(ovsdbTerminationPointAugmentation);
1089                 }
1090             }
1091         }
1092         return tpAugmentations;
1093     }
1094
1095     /**
1096      * Extract the <code>OvsdbTerminationPointAugmentation</code> for the particular <code>node</code> identified by
1097      * <code>portName</code>.
1098      *
1099      * @param node
1100      * @param portName
1101      * @return
1102      */
1103     public OvsdbTerminationPointAugmentation getTerminationPointOfBridge(Node node, String portName) {
1104         OvsdbTerminationPointAugmentation tpAugmentation = extractTerminationPointAugmentation(node,portName);
1105         if(tpAugmentation == null){
1106             List<OvsdbTerminationPointAugmentation> tpAugmentations = readTerminationPointAugmentations(node);
1107             if(tpAugmentations != null){
1108                 for(OvsdbTerminationPointAugmentation ovsdbTpAugmentation : tpAugmentations){
1109                     if(ovsdbTpAugmentation.getName().equals(portName)){
1110                         return ovsdbTpAugmentation;
1111                     }
1112                 }
1113             }
1114         }
1115         return tpAugmentation;
1116     }
1117
1118     /**
1119      * read the list of <code>OvsdbTerminationPointAugmentation</code> for the particular <code>node</code>.
1120      *
1121      * @param node
1122      * @return
1123      */
1124     public List<OvsdbTerminationPointAugmentation> readTerminationPointAugmentations(Node node) {
1125         if (node == null) {
1126             LOG.error("readTerminationPointAugmentations: Node value is null");
1127             return Collections.emptyList();
1128         }
1129         Node operNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier
1130                 .create(NetworkTopology.class)
1131                 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
1132                 .child(Node.class, new NodeKey(node.getNodeId())));
1133         if (operNode != null) {
1134             return extractTerminationPointAugmentations(operNode);
1135         }
1136         return new ArrayList<>();
1137     }
1138
1139     /**
1140      * Get all OVSDB nodes from topology.
1141      * @return a list of nodes or null if the topology could not found
1142      */
1143     public List<Node> getOvsdbNodes() {
1144         InstanceIdentifier<Topology> inst = InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
1145                 new TopologyKey(OVSDB_TOPOLOGY_ID));
1146         Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, inst);
1147         return topology != null ? topology.getNode() : null;
1148     }
1149
1150     /**
1151      * Get OpenvSwitch other-config by key.
1152      * @param node OVSDB node
1153      * @param key key to extract from other-config
1154      * @return the value for key or null if key not found
1155      */
1156     public String getOpenvswitchOtherConfig(Node node, String key) {
1157         OvsdbNodeAugmentation ovsdbNode = node.getAugmentation(OvsdbNodeAugmentation.class);
1158         if (ovsdbNode == null) {
1159             Node nodeFromReadOvsdbNode = readOvsdbNode(node);
1160             if (nodeFromReadOvsdbNode != null) {
1161                 ovsdbNode = nodeFromReadOvsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
1162             }
1163         }
1164
1165         if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) {
1166             for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) {
1167                 if (openvswitchOtherConfigs.getOtherConfigKey().equals(key)) {
1168                     return openvswitchOtherConfigs.getOtherConfigValue();
1169                 }
1170             }
1171         }
1172
1173         return null;
1174     }
1175
1176     public static TerminationPoint getTerminationPointByExternalId(final Node bridgeNode, final String interfaceName) {
1177         if (bridgeNode.getTerminationPoint() != null) {
1178             for (TerminationPoint tp : bridgeNode.getTerminationPoint()) {
1179                 OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1180                 String externalIdValue = getExternalInterfaceIdValue(ovsdbTp);
1181                 if (externalIdValue != null && externalIdValue.equals(interfaceName)) {
1182                     LOG.debug("Found matching termination point with iface-id {} on bridgeNode {}, returning tp {}",
1183                             interfaceName, bridgeNode, tp);
1184                     return tp;
1185                 }
1186             }
1187         }
1188         return null;
1189     }
1190
1191     // This utility shouldn't be called often, as it reads all OVSDB nodes each time - not good for scale
1192     public Node getNodeByTerminationPointExternalId(final String interfaceName) {
1193         List<Node> nodes = getOvsdbNodes();
1194         if (nodes != null) {
1195             for (Node node : nodes) {
1196                 TerminationPoint tp = getTerminationPointByExternalId(node, interfaceName);
1197                 if (tp != null) {
1198                     return node;
1199                 }
1200             }
1201         }
1202         return null;
1203     }
1204
1205     public static String getExternalInterfaceIdValue(final OvsdbTerminationPointAugmentation ovsdbTp) {
1206         if (ovsdbTp != null) {
1207             List<InterfaceExternalIds> ifaceExtIds = ovsdbTp.getInterfaceExternalIds();
1208             if (ifaceExtIds != null) {
1209                 for (InterfaceExternalIds entry : ifaceExtIds) {
1210                     if (entry.getExternalIdKey().equals(EXTERNAL_INTERFACE_ID_KEY)) {
1211                         return entry.getExternalIdValue();
1212                     }
1213                 }
1214             }
1215         }
1216         return null;
1217     }
1218
1219     public String getDatapathIdFromNodeInstanceId(InstanceIdentifier<Node> nodeInstanceId) {
1220         Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
1221         String dpId = node != null ? getDataPathIdStr(node) : null;
1222         if (dpId != null) {
1223             return dpId;
1224         }
1225         return null;
1226     }
1227
1228     public static boolean compareDbVersionToMinVersion(final String dbVersion, final String minVersion) {
1229         final Matcher dbVersionMatcher = PATTERN.matcher(dbVersion);
1230         final Matcher minVersionMatcher = PATTERN.matcher(minVersion);
1231         LOG.debug("dbVersion {}, minVersion {}", dbVersion, minVersion);
1232         if (!dbVersionMatcher.find()){
1233             LOG.error("Invalid DB version format {}", dbVersion);
1234             return false;
1235         }
1236         if (!minVersionMatcher.find()){
1237             LOG.error("Invalid Min DB version format {}", minVersion);
1238             return false;
1239         }
1240
1241         if (dbVersion != null && !dbVersion.isEmpty() && minVersion != null
1242                 && !minVersion.isEmpty()) {
1243             if (Integer.valueOf(dbVersionMatcher.group(1)).equals(Integer.valueOf(minVersionMatcher.group(1))) &&
1244                    Integer.valueOf(dbVersionMatcher.group(2)).equals(Integer.valueOf(minVersionMatcher.group(2))) &&
1245                    Integer.valueOf(dbVersionMatcher.group(3)).equals(Integer.valueOf(minVersionMatcher.group(3)))) {
1246                 return true;
1247             }
1248
1249             if (Integer.valueOf(dbVersionMatcher.group(1)).intValue() > Integer.valueOf(minVersionMatcher.group(1)).intValue()) {
1250                 return true;
1251             }
1252
1253             if (Integer.valueOf(dbVersionMatcher.group(1)).intValue() < Integer.valueOf(minVersionMatcher.group(1)).intValue()) {
1254                 return false;
1255             }
1256
1257             // major version is equal
1258             if (Integer.valueOf(dbVersionMatcher.group(2)).intValue() > Integer.valueOf(minVersionMatcher.group(2)).intValue()) {
1259                 return true;
1260             }
1261             if (Integer.valueOf(dbVersionMatcher.group(2)).intValue() < Integer.valueOf(minVersionMatcher.group(2)).intValue()) {
1262                 return false;
1263             }
1264
1265            if (Integer.valueOf(dbVersionMatcher.group(3)).intValue() > Integer.valueOf(minVersionMatcher.group(3)).intValue()) {
1266                 return true;
1267             }
1268         }
1269         return false;
1270     }
1271 }