GENIUS-164 Fix-Table 0 not programmed occasionally
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / itmdirecttunnels / renderer / ovs / utilities / DirectTunnelUtils.java
1 /*
2  * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities;
9
10 import com.google.common.collect.ImmutableMap;
11 import com.google.common.collect.ImmutableMap.Builder;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.concurrent.ExecutionException;
19 import java.util.function.Predicate;
20 import java.util.regex.Pattern;
21 import javax.annotation.Nonnull;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24
25 import org.opendaylight.genius.infra.Datastore.Configuration;
26 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
27 import org.opendaylight.genius.infra.TypedWriteTransaction;
28 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
29 import org.opendaylight.genius.itm.globals.ITMConstants;
30 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
31 import org.opendaylight.genius.itm.impl.ItmUtils;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.genius.mdsalutil.matches.MatchInPort;
42 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBfd;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlanGpe;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.BridgeTunnelInfo;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.IfIndexesTunnelMap;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.OvsBridgeRefInfo;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210._if.indexes.tunnel.map.IfIndexTunnel;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210._if.indexes.tunnel.map.IfIndexTunnelKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsState;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfd;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
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.opendaylight.yangtools.yang.common.OperationFailedException;
105 import org.opendaylight.yangtools.yang.common.RpcError;
106 import org.opendaylight.yangtools.yang.common.RpcResult;
107 import org.slf4j.Logger;
108 import org.slf4j.LoggerFactory;
109
110 @Singleton
111 public final class DirectTunnelUtils {
112
113     private static final Logger LOG = LoggerFactory.getLogger(DirectTunnelUtils.class);
114
115     private static final String BFD_PARAM_ENABLE = "enable";
116     private static final String BFD_PARAM_MIN_TX = "min_tx";
117     private static final String BFD_PARAM_FORWARDING_IF_RX = "forwarding_if_rx";
118     // BFD parameters
119     private static final String BFD_ENABLE_KEY = "enable";
120     private static final String BFD_ENABLE_VALUE = "true";
121     public static final String BFD_OP_STATE = "state";
122     public static final String BFD_STATE_UP = "up";
123     private static final String BFD_MIN_TX_VAL = "100";
124     private static final String BFD_FORWARDING_IF_RX_VAL = "true";
125
126     // Tunnel options
127     public static final String TUNNEL_OPTIONS_KEY = "key";
128     public static final String TUNNEL_OPTIONS_LOCAL_IP = "local_ip";
129     public static final String TUNNEL_OPTIONS_REMOTE_IP = "remote_ip";
130     public static final String TUNNEL_OPTIONS_DESTINATION_PORT = "dst_port";
131     public static final String TUNNEL_OPTIONS_TOS = "tos";
132
133     // Option values for VxLAN-GPE + NSH tunnels
134     public static final String TUNNEL_OPTIONS_EXTS = "exts";
135     public static final String TUNNEL_OPTIONS_NSI = "nsi";
136     public static final String TUNNEL_OPTIONS_NSP = "nsp";
137     public static final String TUNNEL_OPTIONS_NSHC1 = "nshc1";
138     public static final String TUNNEL_OPTIONS_NSHC2 = "nshc2";
139     public static final String TUNNEL_OPTIONS_NSHC3 = "nshc3";
140     public static final String TUNNEL_OPTIONS_NSHC4 = "nshc4";
141
142     // Option values for VxLAN-GPE + NSH tunnels
143     public static final String TUNNEL_OPTIONS_VALUE_FLOW = "flow";
144     public static final String TUNNEL_OPTIONS_VALUE_GPE = "gpe";
145     // UDP port for VxLAN-GPE Tunnels
146     public static final String TUNNEL_OPTIONS_VALUE_GPE_DESTINATION_PORT = "4880";
147
148     //tos option value for tunnels
149     public static final String TUNNEL_OPTIONS_TOS_VALUE_INHERIT = "inherit";
150
151     private static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
152
153     private static final long INVALID_ID = 0;
154     private final KeyedLocks<String> tunnelLocks = new KeyedLocks<>();
155
156     // To keep the mapping between Tunnel Types and Tunnel Interfaces
157
158     public static final ImmutableMap<Class<? extends TunnelTypeBase>,
159             Class<? extends InterfaceTypeBase>> TUNNEL_TYPE_MAP = new ImmutableMap
160             .Builder<Class<? extends TunnelTypeBase>, Class<? extends InterfaceTypeBase>>()
161             .put(TunnelTypeGre.class, InterfaceTypeGre.class)
162             .put(TunnelTypeVxlan.class, InterfaceTypeVxlan.class)
163             .put(TunnelTypeVxlanGpe.class, InterfaceTypeVxlan.class).build();
164
165     private static final String TUNNEL_PORT_REGEX = "tun[0-9a-f]{11}";
166     private static final Pattern TUNNEL_PORT_PATTERN = Pattern.compile(TUNNEL_PORT_REGEX);
167     public  static final Predicate<String> TUNNEL_PORT_PREDICATE =
168         portName -> TUNNEL_PORT_PATTERN.matcher(portName).matches();
169
170     private final IdManagerService idManagerService;
171     private final IMdsalApiManager mdsalApiManager;
172
173     @Inject
174     public DirectTunnelUtils(final IdManagerService idManagerService, final IMdsalApiManager mdsalApiManager) {
175         this.idManagerService = idManagerService;
176         this.mdsalApiManager = mdsalApiManager;
177     }
178
179     public KeyedLocks<String> getTunnelLocks() {
180         return tunnelLocks;
181     }
182
183     public BigInteger getDpnId(DatapathId datapathId) {
184         if (datapathId != null) {
185             String dpIdStr = datapathId.getValue().replace(":", "");
186             return new BigInteger(dpIdStr, 16);
187         }
188         return null;
189     }
190
191     public static BigInteger getDpnFromNodeConnectorId(NodeConnectorId portId) {
192         /*
193          * NodeConnectorId is of form 'openflow:dpnid:portnum'
194          */
195         return new BigInteger(portId.getValue().split(ITMConstants.OF_URI_SEPARATOR)[1]);
196     }
197
198     public static long getPortNumberFromNodeConnectorId(NodeConnectorId portId) {
199         String portNo = getPortNoFromNodeConnectorId(portId);
200         try {
201             return Long.parseLong(portNo);
202         } catch (NumberFormatException ex) {
203             LOG.error("Unable to retrieve port number from nodeconnector id for {} ", portId, ex);
204             return ITMConstants.INVALID_PORT_NO;
205         }
206     }
207
208     private static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
209         /*
210          * NodeConnectorId is of form 'openflow:dpnid:portnum'
211          */
212         return portId.getValue().split(ITMConstants.OF_URI_SEPARATOR)[2];
213     }
214
215     // Convert Interface Oper State to Tunnel Oper state
216     public static TunnelOperStatus convertInterfaceToTunnelOperState(Interface.OperStatus opState) {
217
218         java.util.Optional<TunnelOperStatus> tunnelOperStatus = TunnelOperStatus.forName(opState.getName());
219         if (tunnelOperStatus.isPresent()) {
220             return tunnelOperStatus.get();
221         }
222         return TunnelOperStatus.Ignore;
223     }
224
225     public static InstanceIdentifier<OvsBridgeTunnelEntry> getBridgeTunnelEntryIdentifier(
226             OvsBridgeEntryKey bridgeEntryKey, OvsBridgeTunnelEntryKey bridgeInterfaceEntryKey) {
227         return InstanceIdentifier.builder(BridgeTunnelInfo.class)
228                 .child(OvsBridgeEntry.class, bridgeEntryKey)
229                 .child(OvsBridgeTunnelEntry.class, bridgeInterfaceEntryKey).build();
230
231     }
232
233     public static InstanceIdentifier<OvsBridgeRefEntry>
234         getOvsBridgeRefEntryIdentifier(OvsBridgeRefEntryKey bridgeRefEntryKey) {
235         return InstanceIdentifier.builder(OvsBridgeRefInfo.class)
236                 .child(OvsBridgeRefEntry.class, bridgeRefEntryKey).build();
237     }
238
239     public static InstanceIdentifier<DpnsTeps> createDpnTepsInstanceIdentifier(BigInteger sourceDpnId) {
240         return InstanceIdentifier.builder(DpnTepsState.class).child(DpnsTeps.class,
241             new DpnsTepsKey(sourceDpnId)).build();
242     }
243
244     public static InstanceIdentifier<OvsBridgeEntry> getOvsBridgeEntryIdentifier(OvsBridgeEntryKey bridgeEntryKey) {
245         return InstanceIdentifier.builder(BridgeTunnelInfo.class).child(OvsBridgeEntry.class, bridgeEntryKey).build();
246     }
247
248     public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(
249             org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021
250                     .network.topology.topology.NodeKey nodekey, String portName) {
251         InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier.create(NetworkTopology.class)
252                 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
253                 .child(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021
254                         .network.topology.topology.Node.class, nodekey)
255                 .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
256
257         LOG.debug("Termination point InstanceIdentifier generated : {}", terminationPointPath);
258         return terminationPointPath;
259     }
260
261     public static List<InterfaceBfd> getBfdParams(IfTunnel ifTunnel) {
262         List<InterfaceBfd> bfdParams = new ArrayList<>();
263         bfdParams.add(getIfBfdObj(BFD_PARAM_ENABLE,ifTunnel != null ? ifTunnel.isMonitorEnabled().toString()
264                 : "false"));
265         bfdParams.add(getIfBfdObj(BFD_PARAM_MIN_TX, ifTunnel != null &&  ifTunnel.getMonitorInterval() != null
266                 ? ifTunnel.getMonitorInterval().toString() : BFD_MIN_TX_VAL));
267         bfdParams.add(getIfBfdObj(BFD_PARAM_FORWARDING_IF_RX, BFD_FORWARDING_IF_RX_VAL));
268         return bfdParams;
269     }
270
271     public List<InterfaceBfd> getBfdParams(RemoteDpns remoteDpn) {
272         List<InterfaceBfd> bfdParams = new ArrayList<>();
273         bfdParams.add(getIfBfdObj(BFD_PARAM_ENABLE, remoteDpn != null ? remoteDpn.isMonitoringEnabled().toString()
274             : "false"));
275         bfdParams.add(getIfBfdObj(BFD_PARAM_MIN_TX, remoteDpn != null && remoteDpn.getMonitoringInterval() != null
276             ? remoteDpn.getMonitoringInterval().toString() : BFD_MIN_TX_VAL));
277         bfdParams.add(getIfBfdObj(BFD_PARAM_FORWARDING_IF_RX, BFD_FORWARDING_IF_RX_VAL));
278         LOG.debug("getBfdParams {}", bfdParams);
279         return bfdParams;
280     }
281
282     private static InterfaceBfd getIfBfdObj(String key, String value) {
283         InterfaceBfdBuilder bfdBuilder = new InterfaceBfdBuilder();
284         bfdBuilder.setBfdKey(key).withKey(new InterfaceBfdKey(key)).setBfdValue(value);
285         return bfdBuilder.build();
286     }
287
288     public static boolean bfdMonitoringEnabled(List<InterfaceBfd> interfaceBfds) {
289         if (interfaceBfds != null && !interfaceBfds.isEmpty()) {
290             for (InterfaceBfd interfaceBfd : interfaceBfds) {
291                 if (BFD_ENABLE_KEY.equalsIgnoreCase(interfaceBfd.getBfdKey())) {
292                     return BFD_ENABLE_VALUE.equalsIgnoreCase(interfaceBfd.getBfdValue());
293                 }
294             }
295         }
296         return false;
297     }
298
299     public static boolean changeInBfdMonitoringDetected(OvsdbTerminationPointAugmentation tpOld,
300                                                         OvsdbTerminationPointAugmentation tpNew) {
301         return tpOld != null
302                 && bfdMonitoringEnabled(tpNew.getInterfaceBfd()) != bfdMonitoringEnabled(tpOld.getInterfaceBfd());
303     }
304
305     public static boolean ifBfdStatusNotEqual(OvsdbTerminationPointAugmentation tpOld,
306                                               OvsdbTerminationPointAugmentation tpNew) {
307         return tpNew.getInterfaceBfdStatus() != null
308                 && (tpOld == null || !tpNew.getInterfaceBfdStatus().equals(tpOld.getInterfaceBfdStatus()));
309     }
310
311     public int allocateId(String poolName, String idKey)
312             throws InterruptedException, ExecutionException , OperationFailedException {
313         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
314         RpcResult<AllocateIdOutput> rpcResult = idManagerService.allocateId(getIdInput).get();
315         if (rpcResult.isSuccessful()) {
316             return rpcResult.getResult().getIdValue().intValue();
317         } else {
318             Optional<RpcError> rpcError = rpcResult.getErrors().stream().findFirst();
319             String msg = String.format("RPC Call to Get Unique Id returned with Errors for the key %s", idKey);
320             if (rpcError.isPresent()) {
321                 throw new OperationFailedException(msg, rpcError.get());
322             }
323             else {
324                 throw new OperationFailedException(msg);
325             }
326         }
327     }
328
329     public static void createBridgeTunnelEntryInConfigDS(BigInteger dpId, String childInterface) {
330         OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
331         OvsBridgeTunnelEntryKey bridgeTunnelEntryKey = new OvsBridgeTunnelEntryKey(childInterface);
332         InstanceIdentifier<OvsBridgeTunnelEntry> bridgeTunnelEntryIid =
333                 getBridgeTunnelEntryIdentifier(bridgeEntryKey, bridgeTunnelEntryKey);
334         OvsBridgeTunnelEntryBuilder entryBuilder = new OvsBridgeTunnelEntryBuilder().withKey(bridgeTunnelEntryKey)
335                 .setTunnelName(childInterface);
336         ITMBatchingUtils.write(bridgeTunnelEntryIid, entryBuilder.build(), ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
337     }
338
339     public void addTunnelIngressFlow(TypedWriteTransaction<Configuration> tx, BigInteger dpnId, long portNo,
340         String interfaceName, int ifIndex) {
341         LOG.debug("Adding tunnel ingress flow for {}", interfaceName);
342         List<MatchInfoBase> matches = new ArrayList<>();
343
344         List<InstructionInfo> mkInstructions = new ArrayList<>();
345         matches.add(new MatchInPort(dpnId, portNo));
346         mkInstructions.add(new InstructionWriteMetadata(MetaDataUtil.getLportTagMetaData(ifIndex)
347             .or(BigInteger.ONE), MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG));
348         short tableId = NwConstants.INTERNAL_TUNNEL_TABLE;
349         mkInstructions.add(new InstructionGotoTable(tableId));
350
351         String flowRef =
352             getTunnelInterfaceFlowRef(dpnId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, interfaceName);
353
354         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef,
355             ITMConstants.DEFAULT_FLOW_PRIORITY, interfaceName, 0, 0, NwConstants.COOKIE_VM_INGRESS_TABLE, matches,
356             mkInstructions);
357         mdsalApiManager.addFlow(tx, flowEntity);
358     }
359
360     public void removeTunnelIngressFlow(TypedReadWriteTransaction<Configuration> tx, BigInteger dpnId,
361         String interfaceName) throws ExecutionException, InterruptedException {
362         LOG.debug("Removing tunnel ingress flow for {}", interfaceName);
363         String flowRef =
364             getTunnelInterfaceFlowRef(dpnId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, interfaceName);
365
366         mdsalApiManager.removeFlow(tx, dpnId, flowRef, NwConstants.VLAN_INTERFACE_INGRESS_TABLE);
367     }
368
369     private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
370         return String.valueOf(dpnId) + tableId + ifName;
371     }
372
373     public void addTunnelPortToBridge(IfTunnel ifTunnel, InstanceIdentifier<?> bridgeIid,
374                                       org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
375                                               .interfaces.rev140508.interfaces.Interface iface, String portName) {
376         LOG.debug("adding tunnel port {} to bridge {}", portName, bridgeIid);
377
378         Class<? extends InterfaceTypeBase> type =
379                 DirectTunnelUtils.TUNNEL_TYPE_MAP.get(ifTunnel.getTunnelInterfaceType());
380         if (type == null) {
381             LOG.warn("Unknown Tunnel Type obtained while creating interface: {}", iface);
382             return;
383         }
384
385         int vlanId = 0;
386         IfL2vlan ifL2vlan = iface.augmentation(IfL2vlan.class);
387         if (ifL2vlan != null && ifL2vlan.getVlanId() != null) {
388             vlanId = ifL2vlan.getVlanId().getValue();
389         }
390
391         Builder<String, String> options = new ImmutableMap.Builder<>();
392
393         // Options common to any kind of tunnel
394         options.put(TUNNEL_OPTIONS_KEY, TUNNEL_OPTIONS_VALUE_FLOW);
395         IpAddress localIp = ifTunnel.getTunnelSource();
396         options.put(DirectTunnelUtils.TUNNEL_OPTIONS_LOCAL_IP, localIp.getIpv4Address().getValue());
397
398         IpAddress remoteIp = ifTunnel.getTunnelDestination();
399         options.put(DirectTunnelUtils.TUNNEL_OPTIONS_REMOTE_IP, remoteIp.getIpv4Address().getValue());
400
401         options.put(DirectTunnelUtils.TUNNEL_OPTIONS_TOS, DirectTunnelUtils.TUNNEL_OPTIONS_TOS_VALUE_INHERIT);
402
403         // Specific options for each type of tunnel
404         if (ifTunnel.getTunnelInterfaceType().equals(TunnelTypeVxlanGpe.class)) {
405             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_EXTS, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_GPE);
406             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSI, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
407             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSP, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
408             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC1, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
409             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC2, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
410             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC3, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
411             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_NSHC4, DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_FLOW);
412             // VxLAN-GPE interfaces will not use the default UDP port to avoid problems with other meshes
413             options.put(DirectTunnelUtils.TUNNEL_OPTIONS_DESTINATION_PORT,
414                     DirectTunnelUtils.TUNNEL_OPTIONS_VALUE_GPE_DESTINATION_PORT);
415         }
416         addTerminationPoint(bridgeIid, portName, vlanId, type, options.build(), ifTunnel);
417     }
418
419     private void addTerminationPoint(InstanceIdentifier<?> bridgeIid, String portName, int vlanId,
420                                      Class<? extends InterfaceTypeBase> type, Map<String, String> options,
421                                      IfTunnel ifTunnel) {
422         final InstanceIdentifier<TerminationPoint> tpIid = DirectTunnelUtils.createTerminationPointInstanceIdentifier(
423                 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(
424                         org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
425                                 .network.topology.rev131021.network.topology.topology.Node.class)), portName);
426         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
427
428         tpAugmentationBuilder.setName(portName);
429
430         if (type != null) {
431             tpAugmentationBuilder.setInterfaceType(type);
432         }
433
434         if (options != null) {
435             List<Options> optionsList = new ArrayList<>();
436             for (Map.Entry<String, String> entry : options.entrySet()) {
437                 OptionsBuilder optionsBuilder = new OptionsBuilder();
438                 optionsBuilder.withKey(new OptionsKey(entry.getKey()));
439                 optionsBuilder.setOption(entry.getKey());
440                 optionsBuilder.setValue(entry.getValue());
441                 optionsList.add(optionsBuilder.build());
442             }
443             tpAugmentationBuilder.setOptions(optionsList);
444         }
445
446         if (vlanId != 0) {
447             tpAugmentationBuilder.setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access);
448             tpAugmentationBuilder.setVlanTag(new VlanId(vlanId));
449         }
450
451         if (ifTunnel.isMonitorEnabled()
452                 && TunnelMonitoringTypeBfd.class.isAssignableFrom(ifTunnel.getMonitorProtocol())) { //checkBfdMonEnabled
453             List<InterfaceBfd> bfdParams = DirectTunnelUtils.getBfdParams(ifTunnel);
454             tpAugmentationBuilder.setInterfaceBfd(bfdParams);
455         }
456
457         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
458         tpBuilder.withKey(InstanceIdentifier.keyOf(tpIid));
459         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
460
461         ITMBatchingUtils.write(tpIid, tpBuilder.build(), ITMBatchingUtils.EntityType.TOPOLOGY_CONFIG);
462     }
463
464     public void removeLportTagInterfaceMap(String infName)
465             throws ExecutionException, InterruptedException, OperationFailedException {
466         // workaround to get the id to remove from lport tag interface map
467         Integer ifIndex = allocateId(IfmConstants.IFM_IDPOOL_NAME, infName);
468         releaseId(IfmConstants.IFM_IDPOOL_NAME, infName);
469         LOG.debug("removing lport tag to interface map for {}", infName);
470         InstanceIdentifier<IfIndexTunnel> id = InstanceIdentifier.builder(IfIndexesTunnelMap.class)
471                 .child(IfIndexTunnel.class, new IfIndexTunnelKey(ifIndex)).build();
472         ITMBatchingUtils.delete(id, ITMBatchingUtils.EntityType.DEFAULT_OPERATIONAL);
473     }
474
475     private void releaseId(String poolName, String idKey) throws InterruptedException, ExecutionException,
476             OperationFailedException {
477         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
478         ListenableFuture<RpcResult<ReleaseIdOutput>> result = idManagerService.releaseId(idInput);
479         RpcResult<ReleaseIdOutput> rpcResult = result.get();
480         if (!rpcResult.isSuccessful()) {
481             LOG.error("RPC Call to release Id with Key {} returned with Errors {}", idKey, rpcResult.getErrors());
482             Optional<RpcError> rpcError = rpcResult.getErrors().stream().findFirst();
483             String msg = String.format("RPC Call to release Id returned with Errors for the key %s", idKey);
484             if (rpcError.isPresent()) {
485                 throw new OperationFailedException(msg, rpcError.get());
486             }
487             else {
488                 throw new OperationFailedException(msg);
489             }
490         }
491     }
492
493     public void deleteTunnelStateEntry(String interfaceName) {
494         LOG.debug(" deleteTunnelStateEntry tunnels state for {}", interfaceName);
495         InstanceIdentifier<StateTunnelList> stateTnlId =
496                 ItmUtils.buildStateTunnelListId(new StateTunnelListKey(interfaceName));
497         ITMBatchingUtils.delete(stateTnlId, ITMBatchingUtils.EntityType.DEFAULT_OPERATIONAL);
498     }
499
500     public void updateBfdConfiguration(BigInteger srcDpnId, RemoteDpns remoteDpn,
501                                        @Nonnull com.google.common.base.Optional<OvsBridgeRefEntry> ovsBridgeRefEntry) {
502         if (ovsBridgeRefEntry.isPresent()) {
503             LOG.debug("creating bridge interface on dpn {}", srcDpnId);
504             InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
505                 (InstanceIdentifier<OvsdbBridgeAugmentation>) ovsBridgeRefEntry.get()
506                     .getOvsBridgeReference().getValue();
507             updateBfdParamtersForTerminationPoint(bridgeIid, remoteDpn);
508         }
509     }
510
511     public void updateBfdParamtersForTerminationPoint(InstanceIdentifier<?> bridgeIid, RemoteDpns remoteDpn) {
512         final InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
513             InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(
514                 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
515                     .network.topology.rev131021.network.topology.topology.Node.class)), remoteDpn.getTunnelName());
516         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
517         List<InterfaceBfd> bfdParams = getBfdParams(remoteDpn);
518         tpAugmentationBuilder.setInterfaceBfd(bfdParams);
519         LOG.debug("OvsdbTerminationPointAugmentation: {}", tpAugmentationBuilder);
520         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
521         tpBuilder.withKey(InstanceIdentifier.keyOf(tpIid));
522         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
523         ITMBatchingUtils.update(tpIid, tpBuilder.build(), ITMBatchingUtils.EntityType.TOPOLOGY_CONFIG);
524     }
525 }