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