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