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