Stale table=44 flows remains on VM deletion
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatUtil.java
1 /*
2  * Copyright © 2016, 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import static java.util.Collections.emptyList;
12 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
13 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
14
15 import com.google.common.base.Optional;
16 import com.google.common.base.Preconditions;
17 import com.google.common.base.Splitter;
18 import com.google.common.base.Strings;
19 import com.google.common.collect.Iterables;
20 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21 import java.math.BigInteger;
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.Future;
35 import java.util.concurrent.locks.ReentrantLock;
36 import java.util.stream.Collectors;
37 import org.apache.commons.net.util.SubnetUtils;
38 import org.eclipse.jdt.annotation.NonNull;
39 import org.eclipse.jdt.annotation.Nullable;
40 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
41 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
42 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
43 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
44 import org.opendaylight.controller.sal.common.util.Arguments;
45 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
46 import org.opendaylight.genius.infra.Datastore.Configuration;
47 import org.opendaylight.genius.infra.Datastore.Operational;
48 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
49 import org.opendaylight.genius.infra.TypedReadTransaction;
50 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
51 import org.opendaylight.genius.infra.TypedWriteTransaction;
52 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
53 import org.opendaylight.genius.mdsalutil.ActionInfo;
54 import org.opendaylight.genius.mdsalutil.FlowEntity;
55 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
56 import org.opendaylight.genius.mdsalutil.GroupEntity;
57 import org.opendaylight.genius.mdsalutil.InstructionInfo;
58 import org.opendaylight.genius.mdsalutil.MDSALUtil;
59 import org.opendaylight.genius.mdsalutil.MatchInfo;
60 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
61 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
62 import org.opendaylight.genius.mdsalutil.NwConstants;
63 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
64 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
65 import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
66 import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan;
67 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
68 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid;
69 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
70 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
71 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
72 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
73 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
74 import org.opendaylight.genius.utils.JvmGlobalLocks;
75 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
76 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
77 import org.opendaylight.netvirt.elanmanager.api.IElanService;
78 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
79 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
80 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
81 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
82 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
83 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
84 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
85 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
86 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
87 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
88 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
89 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
90 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
91 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
92 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefixBuilder;
93 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
94 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInputBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpnRouters;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
151 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
152 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
153 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
154 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
155 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
156 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInterfaceOpData;
157 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
158 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListBuilder;
159 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListKey;
160 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
161 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersListBuilder;
162 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersListKey;
163 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
164 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortKey;
165 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
166 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
167 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
168 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
169 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
170 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
171 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
172 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
173 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
174 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
175 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
176 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
177 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
178 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
179 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
180 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
181 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
182 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
183 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
184 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
185 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
186 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
187 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
188 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalSubnets;
189 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
190 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpPortInfo;
191 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
192 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
193 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
194 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
195 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
196 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
197 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterToVpnMapping;
198 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.SnatintIpPortMap;
199 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
200 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
201 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
202 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
203 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCountersKey;
204 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
205 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
206 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
207 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
208 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
209 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
210 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
211 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
212 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
213 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
214 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
215 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
216 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
217 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
218 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
219 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
220 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
221 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
222 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
223 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
224 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
225 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
226 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
227 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
228 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
229 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.to.vpn.mapping.Routermapping;
230 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.to.vpn.mapping.RoutermappingKey;
231 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
232 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
233 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
234 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
235 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
236 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
237 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
238 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
239 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
240 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronVpnPortipPortData;
241 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
242 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
243 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
244 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
245 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
246 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
247 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPortKey;
248 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
249 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
250 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
251 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
252 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
253 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
254 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
255 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
256 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
257 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
258 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
259 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
260 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
261 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
262 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCase;
263 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
264 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
265 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
266 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
267 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
268 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
269 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
270 import org.opendaylight.yangtools.yang.common.RpcResult;
271 import org.slf4j.Logger;
272 import org.slf4j.LoggerFactory;
273
274 public final class NatUtil {
275
276     private static String OF_URI_SEPARATOR = ":";
277     private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);
278     private static final String OTHER_CONFIG_PARAMETERS_DELIMITER = ",";
279     private static final String OTHER_CONFIG_KEY_VALUE_DELIMITER = ":";
280     private static final String PROVIDER_MAPPINGS = "provider_mappings";
281
282     private NatUtil() { }
283
284     /*
285      getCookieSnatFlow() computes and returns a unique cookie value for the NAT flows using the router ID as the
286       reference value.
287      */
288     public static BigInteger getCookieSnatFlow(long routerId) {
289         return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0110000", 16)).add(
290             BigInteger.valueOf(routerId));
291     }
292
293     /*
294       getCookieNaptFlow() computes and returns a unique cookie value for the NAPT flows using the router ID as the
295        reference value.
296     */
297     public static BigInteger getCookieNaptFlow(long routerId) {
298         return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0111000", 16)).add(
299             BigInteger.valueOf(routerId));
300     }
301
302     /*
303         getVpnId() returns the VPN ID from the VPN name
304      */
305     public static long getVpnId(DataBroker broker, @Nullable String vpnName) {
306         if (vpnName == null) {
307             return NatConstants.INVALID_ID;
308         }
309
310         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
311             .instance.to.vpn.id.VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
312         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
313                 .instance.to.vpn.id.VpnInstance> vpnInstance =
314                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
315                         LogicalDatastoreType.CONFIGURATION, id);
316
317         long vpnId = NatConstants.INVALID_ID;
318         if (vpnInstance.isPresent()) {
319             Long vpnIdAsLong = vpnInstance.get().getVpnId();
320             if (vpnIdAsLong != null) {
321                 vpnId = vpnIdAsLong;
322             }
323         }
324         return vpnId;
325     }
326
327     public static long getVpnId(TypedReadTransaction<Configuration> confTx, String vpnName) {
328         if (vpnName == null) {
329             return NatConstants.INVALID_ID;
330         }
331
332         try {
333             return confTx.read(getVpnInstanceToVpnIdIdentifier(vpnName)).get().toJavaUtil().map(
334                 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
335                     .VpnInstance::getVpnId).orElse(NatConstants.INVALID_ID);
336         } catch (InterruptedException | ExecutionException e) {
337             LOG.error("Error retrieving VPN id for {}", vpnName, e);
338         }
339
340         return NatConstants.INVALID_ID;
341     }
342
343     public static Long getNetworkVpnIdFromRouterId(DataBroker broker, long routerId) {
344         //Get the external network ID from the ExternalRouter model
345         Uuid networkId = NatUtil.getNetworkIdFromRouterId(broker, routerId);
346         if (networkId == null) {
347             LOG.error("getNetworkVpnIdFromRouterId : networkId is null");
348             return NatConstants.INVALID_ID;
349         }
350
351         //Get the VPN ID from the ExternalNetworks model
352         Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(broker, networkId);
353         if (vpnUuid == null) {
354             LOG.error("getNetworkVpnIdFromRouterId : vpnUuid is null");
355             return NatConstants.INVALID_ID;
356         }
357         Long vpnId = NatUtil.getVpnId(broker, vpnUuid.getValue());
358         return vpnId;
359     }
360
361     static InstanceIdentifier<RouterPorts> getRouterPortsId(String routerId) {
362         return InstanceIdentifier.builder(FloatingIpInfo.class)
363             .child(RouterPorts.class, new RouterPortsKey(routerId)).build();
364     }
365
366     static InstanceIdentifier<Routermapping> getRouterVpnMappingId(String routerId) {
367         return InstanceIdentifier.builder(RouterToVpnMapping.class)
368             .child(Routermapping.class, new RoutermappingKey(routerId)).build();
369     }
370
371     static InstanceIdentifier<Ports> getPortsIdentifier(String routerId, String portName) {
372         return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
373             .child(Ports.class, new PortsKey(portName)).build();
374     }
375
376     static InstanceIdentifier<InternalToExternalPortMap> getIntExtPortMapIdentifier(String routerId, String portName,
377                                                                                     String internalIp) {
378         return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
379             .child(Ports.class, new PortsKey(portName))
380             .child(InternalToExternalPortMap.class, new InternalToExternalPortMapKey(internalIp)).build();
381     }
382
383     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
384         .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
385         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
386             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
387                     .instance.to.vpn.id.VpnInstance.class,
388                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
389                     .instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
390     }
391
392     @Nullable
393     static String getVpnInstanceFromVpnIdentifier(DataBroker broker, long vpnId) {
394         InstanceIdentifier<VpnIds> id = InstanceIdentifier.builder(VpnIdToVpnInstance.class)
395             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
396         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
397                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(VpnIds::getVpnInstanceName).orElse(null);
398     }
399
400     /*
401        getFlowRef() returns a string identfier for the SNAT flows using the router ID as the reference.
402     */
403     public static String getFlowRef(BigInteger dpnId, short tableId, long routerID, String ip) {
404         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId)
405             .append(NatConstants.FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR)
406             .append(routerID).append(NatConstants.FLOWID_SEPARATOR).append(ip).toString();
407     }
408
409     public static String getFlowRef(BigInteger dpnId, short tableId, InetAddress destPrefix, long vpnId) {
410         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId)
411             .append(NatConstants.FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR)
412             .append(destPrefix.getHostAddress()).append(NatConstants.FLOWID_SEPARATOR).append(vpnId).toString();
413     }
414
415     public static String getNaptFlowRef(BigInteger dpnId, short tableId, String routerID, String ip,
416         int port, String protocol) {
417         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId)
418             .append(NatConstants.FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR)
419             .append(routerID).append(NatConstants.FLOWID_SEPARATOR).append(ip).append(NatConstants.FLOWID_SEPARATOR)
420             .append(port).append(NatConstants.FLOWID_SEPARATOR).append(protocol).toString();
421     }
422
423     @Nullable
424     static Uuid getNetworkIdFromRouterId(DataBroker broker, long routerId) {
425         String routerName = getRouterName(broker, routerId);
426         if (routerName == null) {
427             LOG.error("getNetworkIdFromRouterId - empty routerName received");
428             return null;
429         }
430         return getNetworkIdFromRouterName(broker, routerName);
431     }
432
433     @Nullable
434     static Uuid getNetworkIdFromRouterName(DataBroker broker, String routerName) {
435         if (routerName == null) {
436             LOG.error("getNetworkIdFromRouterName - empty routerName received");
437             return null;
438         }
439         InstanceIdentifier<Routers> id = buildRouterIdentifier(routerName);
440         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
441                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Routers::getNetworkId).orElse(null);
442     }
443
444     static InstanceIdentifier<Routers> buildRouterIdentifier(String routerId) {
445         InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class)
446             .child(Routers.class, new RoutersKey(routerId)).build();
447         return routerInstanceIndentifier;
448     }
449
450     private static InstanceIdentifier<RouterIds> buildRouterIdentifier(Long routerId) {
451         InstanceIdentifier<RouterIds> routerIds = InstanceIdentifier.builder(RouterIdName.class)
452             .child(RouterIds.class, new RouterIdsKey(routerId)).build();
453         return routerIds;
454     }
455
456     /**
457      * Return if SNAT is enabled for the given router.
458      *
459      * @param broker   The DataBroker
460      * @param routerId The router
461      * @return boolean true if enabled, otherwise false
462      */
463     static boolean isSnatEnabledForRouterId(DataBroker broker, String routerId) {
464         InstanceIdentifier<Routers> id = buildRouterIdentifier(routerId);
465         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
466                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Routers::isEnableSnat).orElse(false);
467     }
468
469     @Nullable
470     public static Uuid getVpnIdfromNetworkId(DataBroker broker, Uuid networkId) {
471         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
472         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
473                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Networks::getVpnid).orElse(null);
474     }
475
476     @Nullable
477     public static Uuid getVpnIdfromNetworkId(TypedReadTransaction<Configuration> tx, Uuid networkId) {
478         try {
479             return tx.read(buildNetworkIdentifier(networkId)).get().toJavaUtil().map(Networks::getVpnid).orElse(null);
480         } catch (InterruptedException | ExecutionException e) {
481             LOG.error("Error reading network VPN id for {}", networkId, e);
482             return null;
483         }
484     }
485
486     @Nullable
487     public static ProviderTypes getProviderTypefromNetworkId(DataBroker broker, Uuid networkId) {
488         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
489         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
490                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Networks::getProviderNetworkType).orElse(null);
491     }
492
493     @Nullable
494     public static ProviderTypes getProviderTypefromNetworkId(TypedReadTransaction<Configuration> tx, Uuid networkId) {
495         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
496         try {
497             return tx.read(id).get().toJavaUtil().map(Networks::getProviderNetworkType).orElse(null);
498         } catch (InterruptedException | ExecutionException e) {
499             LOG.error("Error retrieving provider type for {}", networkId, e);
500             return null;
501         }
502     }
503
504     @Nullable
505     static String getAssociatedExternalNetwork(DataBroker dataBroker, String routerId) {
506         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
507         Optional<Routers> routerData =
508                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
509                         LogicalDatastoreType.CONFIGURATION, id);
510         if (routerData.isPresent()) {
511             Uuid networkId = routerData.get().getNetworkId();
512             if (networkId != null) {
513                 return networkId.getValue();
514             }
515         }
516         LOG.info("getAssociatedExternalNetwork : External Network missing for routerid : {}", routerId);
517         return null;
518     }
519
520     private static InstanceIdentifier<Networks> buildNetworkIdentifier(Uuid networkId) {
521         return InstanceIdentifier.builder(ExternalNetworks.class)
522             .child(Networks.class, new NetworksKey(networkId)).build();
523     }
524
525     @Nullable
526     public static BigInteger getPrimaryNaptfromRouterId(DataBroker broker, Long routerId) {
527         // convert routerId to Name
528         String routerName = getRouterName(broker, routerId);
529         if (routerName == null) {
530             LOG.error("getPrimaryNaptfromRouterId - empty routerName received");
531             return null;
532         }
533         return getPrimaryNaptfromRouterName(broker, routerName);
534     }
535
536     @Nullable
537     public static BigInteger getPrimaryNaptfromRouterName(DataBroker broker, String routerName) {
538         if (routerName == null) {
539             LOG.error("getPrimaryNaptfromRouterName - empty routerName received");
540             return null;
541         }
542         InstanceIdentifier<RouterToNaptSwitch> id = buildNaptSwitchIdentifier(routerName);
543         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
544                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(RouterToNaptSwitch::getPrimarySwitchId).orElse(
545                 null);
546     }
547
548     public static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchIdentifier(String routerId) {
549         return InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class,
550             new RouterToNaptSwitchKey(routerId)).build();
551     }
552
553     public static Optional<NaptSwitches> getAllPrimaryNaptSwitches(DataBroker broker) {
554         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
555                 LogicalDatastoreType.CONFIGURATION, getNaptSwitchesIdentifier());
556     }
557
558     @Nullable
559     public static String getRouterName(DataBroker broker, Long routerId) {
560         return getVpnInstanceFromVpnIdentifier(broker, routerId);
561     }
562
563     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String vrfId) {
564         return InstanceIdentifier.builder(VpnInstanceOpData.class)
565             .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vrfId)).build();
566     }
567
568     public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, BigInteger cookie, String flowId) {
569         return new FlowEntityBuilder()
570                 .setDpnId(dpnId)
571                 .setTableId(tableId)
572                 .setCookie(cookie)
573                 .setFlowId(flowId)
574                 .build();
575     }
576
577     public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId) {
578         return new FlowEntityBuilder()
579                 .setDpnId(dpnId)
580                 .setTableId(tableId)
581                 .setFlowId(flowId)
582                 .build();
583     }
584
585     @Nullable
586     public static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
587         String nextHopIp = null;
588         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
589             InstanceIdentifier.builder(DpnEndpoints.class)
590                 .child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
591         Optional<DPNTEPsInfo> tunnelInfo =
592                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
593                         LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
594         if (tunnelInfo.isPresent()) {
595             List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
596             if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
597                 nextHopIp = nexthopIpList.get(0).getIpAddress().stringValue();
598             }
599         }
600         return nextHopIp;
601     }
602
603     @Nullable
604     public static String getVpnRd(DataBroker broker, String vpnName) {
605         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
606             .instance.to.vpn.id.VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
607         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
608                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
609                 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
610                         .VpnInstance::getVrfId).orElse(null);
611     }
612
613     @Nullable
614     public static String getVpnRd(TypedReadTransaction<Configuration> tx, String vpnName) {
615         try {
616             return tx.read(getVpnInstanceToVpnIdIdentifier(vpnName)).get().toJavaUtil().map(
617                 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
618                     .VpnInstance::getVrfId).orElse(null);
619         } catch (InterruptedException | ExecutionException e) {
620             LOG.error("Error reading the VPN VRF id for {}", vpnName, e);
621             return null;
622         }
623     }
624
625     @Nullable
626     public static IpPortExternal getExternalIpPortMap(DataBroker broker, Long routerId, String internalIpAddress,
627                                                       String internalPort, NAPTEntryEvent.Protocol protocol) {
628         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
629         InstanceIdentifier<IpPortMap> ipPortMapId =
630             buildIpToPortMapIdentifier(routerId, internalIpAddress, internalPort, protocolType);
631         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
632                 LogicalDatastoreType.CONFIGURATION, ipPortMapId).toJavaUtil().map(IpPortMap::getIpPortExternal).orElse(
633                 null);
634     }
635
636     private static InstanceIdentifier<IpPortMap> buildIpToPortMapIdentifier(Long routerId, String internalIpAddress,
637                                                                             String internalPort,
638                                                                             ProtocolTypes protocolType) {
639         return InstanceIdentifier.builder(IntextIpPortMap.class)
640             .child(IpPortMapping.class, new IpPortMappingKey(routerId))
641             .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
642             .child(IpPortMap.class, new IpPortMapKey(internalIpAddress + ":" + internalPort)).build();
643     }
644
645     static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
646         return InstanceIdentifier.builder(VpnInterfaces.class)
647             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
648     }
649
650     @Nullable
651     public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
652         /*
653          * NodeConnectorId is of form 'openflow:dpnid:portnum'
654          */
655         String[] split = portId.getValue().split(OF_URI_SEPARATOR);
656         if (split.length != 3) {
657             LOG.error("getDpnFromNodeConnectorId : invalid portid : {}", portId.getValue());
658             return null;
659         }
660         return split[1];
661     }
662
663     public static BigInteger getDpIdFromInterface(
664         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
665             .state.Interface ifState) {
666         String lowerLayerIf = ifState.getLowerLayerIf().get(0);
667         NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
668         return new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
669     }
670
671
672     @Nullable
673     public static String getRouterIdfromVpnInstance(DataBroker broker, String vpnName, String ipAddress) {
674         // returns only router, attached to IPv4 networks
675         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
676             .child(VpnMap.class, new VpnMapKey(new Uuid(vpnName))).build();
677         Optional<VpnMap> optionalVpnMap =
678                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
679                         LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier);
680         if (!optionalVpnMap.isPresent()) {
681             LOG.error("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
682             return null;
683         }
684         List<Uuid> routerIdsList = NeutronUtils.getVpnMapRouterIdsListUuid(optionalVpnMap.get().getRouterIds());
685         if (routerIdsList != null && !routerIdsList.isEmpty()) {
686             for (Uuid routerUuid : routerIdsList) {
687                 InstanceIdentifier<Routers> id = buildRouterIdentifier(routerUuid.getValue());
688                 Optional<Routers> routerData =
689                         SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
690                                 LogicalDatastoreType.CONFIGURATION, id);
691                 if (routerData.isPresent()) {
692                     List<Uuid> subnetIdsList = routerData.get().getSubnetIds();
693                     for (Uuid subnetUuid : subnetIdsList) {
694                         String subnetIp = getSubnetIp(broker, subnetUuid);
695                         SubnetUtils subnet = new SubnetUtils(subnetIp);
696                         if (subnet.getInfo().isInRange(ipAddress)) {
697                             return routerUuid.getValue();
698                         }
699                     }
700                 }
701             }
702         }
703         LOG.info("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
704         return null;
705     }
706
707     @Nullable
708     static Uuid getVpnForRouter(DataBroker broker, String routerId) {
709         Preconditions.checkNotNull(routerId, "dissociateRouter: routerId not found!");
710         InstanceIdentifier<VpnMaps> vpnMapsIdentifier = InstanceIdentifier.builder(VpnMaps.class).build();
711         Optional<VpnMaps> optionalVpnMaps =
712                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
713                         LogicalDatastoreType.CONFIGURATION, vpnMapsIdentifier);
714         if (optionalVpnMaps.isPresent() && optionalVpnMaps.get().getVpnMap() != null) {
715             for (VpnMap vpnMap : optionalVpnMaps.get().nonnullVpnMap()) {
716                 if (routerId.equals(vpnMap.getVpnId().getValue())) {
717                     continue;
718                 }
719                 List<Uuid> routerIdsList = NeutronUtils.getVpnMapRouterIdsListUuid(vpnMap.getRouterIds());
720                 if (routerIdsList.isEmpty()) {
721                     continue;
722                 }
723                 // Skip router vpnId fetching from internet BGP-VPN
724                 if (vpnMap.getNetworkIds() != null && !vpnMap.getNetworkIds().isEmpty()) {
725                     // We only need to check the first network; if it’s not an external network there’s no
726                     // need to check the rest of the VPN’s network list
727                     if (isExternalNetwork(broker, vpnMap.getNetworkIds().iterator().next())) {
728                         continue;
729                     }
730                 }
731                 if (routerIdsList.contains(new Uuid(routerId))) {
732                     return vpnMap.getVpnId();
733                 }
734             }
735         }
736         LOG.debug("getVpnForRouter : VPN not found for routerID:{}", routerId);
737         return null;
738     }
739
740     static long getAssociatedVpn(DataBroker broker, String routerName) {
741         InstanceIdentifier<Routermapping> routerMappingId = NatUtil.getRouterVpnMappingId(routerName);
742         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
743                 LogicalDatastoreType.OPERATIONAL, routerMappingId).toJavaUtil().map(Routermapping::getVpnId).orElse(
744                 NatConstants.INVALID_ID);
745     }
746
747     @Nullable
748     public static String getAssociatedVPN(DataBroker dataBroker, Uuid networkId) {
749         Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
750         if (vpnUuid == null) {
751             LOG.error("getAssociatedVPN : No VPN instance associated with ext network {}", networkId);
752             return null;
753         }
754         return vpnUuid.getValue();
755     }
756
757     @Nullable
758     public static String getAssociatedVPN(TypedReadTransaction<Configuration> tx, Uuid networkId) {
759         Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(tx, networkId);
760         if (vpnUuid == null) {
761             LOG.error("getAssociatedVPN : No VPN instance associated with ext network {}", networkId);
762             return null;
763         }
764         return vpnUuid.getValue();
765     }
766
767     // TODO Clean up the exception handling
768     @SuppressWarnings("checkstyle:IllegalCatch")
769     public static void addPrefixToBGP(DataBroker broker,
770                                       IBgpManager bgpManager,
771                                       IFibManager fibManager,
772                                       String vpnName,
773                                       String rd,
774                                       String prefix,
775                                       String nextHopIp,
776                                       @Nullable String parentVpnRd,
777                                       @Nullable String macAddress,
778                                       long label,
779                                       long l3vni,
780                                       RouteOrigin origin,
781                                       BigInteger dpId) {
782         try {
783             LOG.info("addPrefixToBGP : Adding Fib entry rd {} prefix {} nextHop {} label {}", rd,
784                     prefix, nextHopIp, label);
785             if (nextHopIp == null) {
786                 LOG.error("addPrefixToBGP : prefix {} rd {} failed since nextHopIp cannot be null.",
787                         prefix, rd);
788                 return;
789             }
790
791             addPrefixToInterface(broker, getVpnId(broker, vpnName), null /*interfaceName*/,prefix, parentVpnRd,
792                 dpId, Prefixes.PrefixCue.Nat);
793             fibManager.addOrUpdateFibEntry(rd, macAddress, prefix,
794                     Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, (int)label, l3vni /*l3vni*/,
795                     null /*gatewayMacAddress*/, parentVpnRd, origin, null /*writeTxn*/);
796             if (rd != null && !rd.equalsIgnoreCase(vpnName)) {
797             /* Publish to Bgp only if its an INTERNET VPN */
798                 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, Collections.singletonList(nextHopIp),
799                         VrfEntry.EncapType.Mplsgre, (int) label, 0 /*l3vni*/, 0 /*l2vni*/,
800                         null /*gatewayMac*/);
801             }
802             LOG.info("addPrefixToBGP : Added Fib entry rd {} prefix {} nextHop {} label {}", rd,
803                     prefix, nextHopIp, label);
804         } catch (Exception e) {
805             LOG.error("addPrefixToBGP : Add prefix rd {} prefix {} nextHop {} label {} failed", rd,
806                     prefix, nextHopIp, label, e);
807         }
808     }
809
810     static void addPrefixToInterface(DataBroker broker, long vpnId, @Nullable String interfaceName, String ipPrefix,
811                                      String networkId, BigInteger dpId, Prefixes.PrefixCue prefixCue) {
812         InstanceIdentifier<Prefixes> prefixId = InstanceIdentifier.builder(PrefixToInterface.class)
813                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
814                         .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix
815                         .to._interface.VpnIdsKey(vpnId))
816                 .child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
817         PrefixesBuilder prefixBuilder = new PrefixesBuilder().setDpnId(dpId).setIpAddress(ipPrefix);
818         prefixBuilder.setVpnInterfaceName(interfaceName).setPrefixCue(prefixCue);
819         prefixBuilder.setNetworkId(new Uuid(networkId));
820         try {
821             SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, prefixId,
822                     prefixBuilder.build());
823         } catch (TransactionCommitFailedException e) {
824             LOG.error("addPrefixToInterface : Failed to write prefxi-to-interface for {} vpn-id {} DPN {}",
825                     ipPrefix, vpnId, dpId, e);
826         }
827     }
828
829     public static void deletePrefixToInterface(DataBroker broker, long vpnId, String ipPrefix) {
830         try {
831             SingleTransactionDataBroker.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,
832                     InstanceIdentifier.builder(PrefixToInterface.class)
833                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
834                             .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911
835                             .prefix.to._interface.VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix))
836                     .build());
837         } catch (TransactionCommitFailedException e) {
838             LOG.error("addPrefixToInterface : Failed to write prefxi-to-interface for vpn-id {}",
839                     vpnId, e);
840         }
841     }
842
843     static InstanceIdentifier<Ports> buildPortToIpMapIdentifier(String routerId, String portName) {
844         InstanceIdentifier<Ports> ipPortMapId = InstanceIdentifier.builder(FloatingIpInfo.class)
845             .child(RouterPorts.class, new RouterPortsKey(routerId)).child(Ports.class, new PortsKey(portName)).build();
846         return ipPortMapId;
847     }
848
849     static InstanceIdentifier<RouterPorts> buildRouterPortsIdentifier(String routerId) {
850         InstanceIdentifier<RouterPorts> routerInstanceIndentifier = InstanceIdentifier.builder(FloatingIpInfo.class)
851             .child(RouterPorts.class, new RouterPortsKey(routerId)).build();
852         return routerInstanceIndentifier;
853     }
854
855     @NonNull
856     public static List<Integer> getInternalIpPortListInfo(DataBroker dataBroker, Long routerId,
857                                                           String internalIpAddress, ProtocolTypes protocolType) {
858         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
859                 LogicalDatastoreType.CONFIGURATION,
860                 buildSnatIntIpPortIdentifier(routerId, internalIpAddress, protocolType)).toJavaUtil().map(
861                 IntIpProtoType::getPorts).orElse(emptyList());
862     }
863
864     public static InstanceIdentifier<IntIpProtoType> buildSnatIntIpPortIdentifier(Long routerId,
865                                                                                   String internalIpAddress,
866                                                                                   ProtocolTypes protocolType) {
867         InstanceIdentifier<IntIpProtoType> intIpProtocolTypeId =
868             InstanceIdentifier.builder(SnatintIpPortMap.class)
869                 .child(IntipPortMap.class, new IntipPortMapKey(routerId))
870                 .child(IpPort.class, new IpPortKey(internalIpAddress))
871                 .child(IntIpProtoType.class, new IntIpProtoTypeKey(protocolType)).build();
872         return intIpProtocolTypeId;
873     }
874
875     public static InstanceIdentifier<IpPort> buildSnatIntIpPortIdentifier(Long routerId,
876             String internalIpAddress) {
877         InstanceIdentifier<IpPort> intIpProtocolTypeId =
878             InstanceIdentifier.builder(SnatintIpPortMap.class)
879                 .child(IntipPortMap.class, new IntipPortMapKey(routerId))
880                 .child(IpPort.class, new IpPortKey(internalIpAddress)).build();
881         return intIpProtocolTypeId;
882     }
883
884     @Nullable
885     public static IpPort getInternalIpPortInfo(DataBroker dataBroker, Long routerId,
886                                                           String internalIpAddress) {
887         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
888                 LogicalDatastoreType.CONFIGURATION,
889                 buildSnatIntIpPortIdentifier(routerId, internalIpAddress)).orNull();
890     }
891
892     public static ProtocolTypes getProtocolType(NAPTEntryEvent.Protocol protocol) {
893         ProtocolTypes protocolType = ProtocolTypes.TCP.toString().equals(protocol.toString())
894             ? ProtocolTypes.TCP : ProtocolTypes.UDP;
895         return protocolType;
896     }
897
898     public static InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
899         return InstanceIdentifier.create(NaptSwitches.class);
900     }
901
902     public static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchRouterIdentifier(String routerId) {
903         return InstanceIdentifier.create(NaptSwitches.class)
904             .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerId));
905     }
906
907     public static String getGroupIdKey(String routerName) {
908         return "snatmiss." + routerName;
909     }
910
911     public static long createGroupId(String groupIdKey, IdManagerService idManager) {
912         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
913             .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
914             .build();
915         try {
916             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
917             RpcResult<AllocateIdOutput> rpcResult = result.get();
918             return rpcResult.getResult().getIdValue();
919         } catch (NullPointerException | InterruptedException | ExecutionException e) {
920             LOG.error("createGroupId : Creating Group with Key: {} failed", groupIdKey, e);
921         }
922         return 0;
923     }
924
925     // TODO Clean up the exception handling
926     @SuppressWarnings("checkstyle:IllegalCatch")
927     public static void removePrefixFromBGP(IBgpManager bgpManager, IFibManager fibManager,
928                                            String rd, String prefix, String vpnName, Logger log) {
929         try {
930             LOG.debug("removePrefixFromBGP: Removing Fib entry rd {} prefix {}", rd, prefix);
931             fibManager.removeFibEntry(rd, prefix, null);
932             if (rd != null && !rd.equalsIgnoreCase(vpnName)) {
933                 bgpManager.withdrawPrefix(rd, prefix);
934             }
935             LOG.info("removePrefixFromBGP: Removed Fib entry rd {} prefix {}", rd, prefix);
936         } catch (Exception e) {
937             log.error("removePrefixFromBGP : Delete prefix for rd {} prefix {} vpnName {} failed",
938                     rd, prefix, vpnName, e);
939         }
940     }
941
942     @Nullable
943     public static IpPortMapping getIportMapping(DataBroker broker, long routerId) {
944         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
945                 LogicalDatastoreType.CONFIGURATION, getIportMappingIdentifier(routerId)).orNull();
946     }
947
948     public static InstanceIdentifier<IpPortMapping> getIportMappingIdentifier(long routerId) {
949         return InstanceIdentifier.builder(IntextIpPortMap.class)
950             .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
951     }
952
953     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
954         .natservice.rev160111.intext.ip.map.IpMapping> getIpMappingBuilder(Long routerId) {
955         return InstanceIdentifier.builder(IntextIpMap.class)
956             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map
957                 .IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
958                 .intext.ip.map.IpMappingKey(routerId))
959             .build();
960     }
961
962     @NonNull
963     public static Collection<String> getExternalIpsForRouter(DataBroker dataBroker, Long routerId) {
964         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext
965             .ip.map.IpMapping> ipMappingOptional =
966                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
967                         LogicalDatastoreType.OPERATIONAL, getIpMappingBuilder(routerId));
968         // Ensure there are no duplicates
969         Collection<String> externalIps = new HashSet<>();
970         if (ipMappingOptional.isPresent()) {
971             for (IpMap ipMap : ipMappingOptional.get().nonnullIpMap()) {
972                 externalIps.add(ipMap.getExternalIp());
973             }
974         }
975         return externalIps;
976     }
977
978     @NonNull
979     public static List<String> getExternalIpsForRouter(DataBroker dataBroker, String routerName) {
980         Routers routerData = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
981         if (routerData != null) {
982             return NatUtil.getIpsListFromExternalIps(routerData.getExternalIps());
983         }
984
985         return emptyList();
986     }
987
988     @NonNull
989     public static Map<String, Long> getExternalIpsLabelForRouter(DataBroker dataBroker, Long routerId) {
990         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext
991             .ip.map.IpMapping> ipMappingOptional =
992                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
993                         LogicalDatastoreType.OPERATIONAL, getIpMappingBuilder(routerId));
994         Map<String, Long> externalIpsLabel = new HashMap<>();
995         if (ipMappingOptional.isPresent()) {
996             for (IpMap ipMap : ipMappingOptional.get().nonnullIpMap()) {
997                 externalIpsLabel.put(ipMap.getExternalIp(), ipMap.getLabel());
998             }
999         }
1000         return externalIpsLabel;
1001     }
1002
1003     @Nullable
1004     public static String getLeastLoadedExternalIp(DataBroker dataBroker, long segmentId) {
1005         String leastLoadedExternalIp = null;
1006         InstanceIdentifier<ExternalCounters> id =
1007             InstanceIdentifier.builder(ExternalIpsCounter.class)
1008                 .child(ExternalCounters.class, new ExternalCountersKey(segmentId)).build();
1009         Optional<ExternalCounters> externalCountersData =
1010             MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1011         if (externalCountersData.isPresent()) {
1012             ExternalCounters externalCounter = externalCountersData.get();
1013             short countOfLstLoadExtIp = 32767;
1014             for (ExternalIpCounter externalIpCounter : externalCounter.nonnullExternalIpCounter()) {
1015                 String curExternalIp = externalIpCounter.getExternalIp();
1016                 short countOfCurExtIp = externalIpCounter.getCounter();
1017                 if (countOfCurExtIp < countOfLstLoadExtIp) {
1018                     countOfLstLoadExtIp = countOfCurExtIp;
1019                     leastLoadedExternalIp = curExternalIp;
1020                 }
1021             }
1022         }
1023         return leastLoadedExternalIp;
1024     }
1025
1026     @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS")
1027     @Nullable
1028     public static String[] getSubnetIpAndPrefix(DataBroker dataBroker, Uuid subnetId) {
1029         String subnetIP = getSubnetIp(dataBroker, subnetId);
1030         if (subnetIP != null) {
1031             return getSubnetIpAndPrefix(subnetIP);
1032         }
1033         LOG.error("getSubnetIpAndPrefix : SubnetIP and Prefix missing for subnet : {}", subnetId);
1034         return null;
1035     }
1036
1037     @NonNull
1038     public static String[] getSubnetIpAndPrefix(String subnetString) {
1039         String[] subnetSplit = subnetString.split("/");
1040         String subnetIp = subnetSplit[0];
1041         String subnetPrefix = "0";
1042         if (subnetSplit.length == 2) {
1043             subnetPrefix = subnetSplit[1];
1044         }
1045         return new String[] {subnetIp, subnetPrefix};
1046     }
1047
1048     @Nullable
1049     public static String getSubnetIp(DataBroker dataBroker, Uuid subnetId) {
1050         InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
1051             .builder(Subnetmaps.class)
1052             .child(Subnetmap.class, new SubnetmapKey(subnetId))
1053             .build();
1054         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1055                 LogicalDatastoreType.CONFIGURATION, subnetmapId).toJavaUtil().map(Subnetmap::getSubnetIp).orElse(null);
1056     }
1057
1058     public static String[] getExternalIpAndPrefix(String leastLoadedExtIpAddr) {
1059         String[] leastLoadedExtIpAddrSplit = leastLoadedExtIpAddr.split("/");
1060         String leastLoadedExtIp = leastLoadedExtIpAddrSplit[0];
1061         String leastLoadedExtIpPrefix = String.valueOf(NatConstants.DEFAULT_PREFIX);
1062         if (leastLoadedExtIpAddrSplit.length == 2) {
1063             leastLoadedExtIpPrefix = leastLoadedExtIpAddrSplit[1];
1064         }
1065         return new String[] {leastLoadedExtIp, leastLoadedExtIpPrefix};
1066     }
1067
1068     @NonNull
1069     public static List<BigInteger> getDpnsForRouter(DataBroker dataBroker, String routerUuid) {
1070         InstanceIdentifier id = InstanceIdentifier.builder(NeutronRouterDpns.class)
1071             .child(RouterDpnList.class, new RouterDpnListKey(routerUuid)).build();
1072         Optional<RouterDpnList> routerDpnListData =
1073                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1074                         LogicalDatastoreType.OPERATIONAL, id);
1075         List<BigInteger> dpns = new ArrayList<>();
1076         if (routerDpnListData.isPresent()) {
1077             for (DpnVpninterfacesList dpnVpnInterface : routerDpnListData.get().nonnullDpnVpninterfacesList()) {
1078                 dpns.add(dpnVpnInterface.getDpnId());
1079             }
1080         }
1081         return dpns;
1082     }
1083
1084     public static long getBgpVpnId(DataBroker dataBroker, String routerName) {
1085         long bgpVpnId = NatConstants.INVALID_ID;
1086         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1087         if (bgpVpnUuid != null) {
1088             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1089         }
1090         return bgpVpnId;
1091     }
1092
1093     static org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces
1094             .@Nullable RouterInterface getConfiguredRouterInterface(DataBroker broker, String interfaceName) {
1095         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1096                 LogicalDatastoreType.CONFIGURATION, NatUtil.getRouterInterfaceId(interfaceName)).orNull();
1097     }
1098
1099     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911
1100         .router.interfaces.RouterInterface> getRouterInterfaceId(String interfaceName) {
1101         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight
1102             .netvirt.l3vpn.rev130911.RouterInterfaces.class)
1103             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces
1104                     .RouterInterface.class,
1105                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces
1106                     .RouterInterfaceKey(interfaceName)).build();
1107     }
1108
1109     public static void addToNeutronRouterDpnsMap(String routerName, String interfaceName, BigInteger dpId,
1110         TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
1111
1112         if (dpId.equals(BigInteger.ZERO)) {
1113             LOG.warn("addToNeutronRouterDpnsMap : Could not retrieve dp id for interface {} "
1114                     + "to handle router {} association model", interfaceName, routerName);
1115             return;
1116         }
1117
1118         LOG.debug("addToNeutronRouterDpnsMap : Adding the Router {} and DPN {} for the Interface {} in the "
1119                 + "ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
1120         InstanceIdentifier<DpnVpninterfacesList> dpnVpnInterfacesListIdentifier = getRouterDpnId(routerName, dpId);
1121
1122         Optional<DpnVpninterfacesList> optionalDpnVpninterfacesList = operTx.read(dpnVpnInterfacesListIdentifier).get();
1123         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns
1124             .router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces routerInterface =
1125             new RouterInterfacesBuilder().withKey(new RouterInterfacesKey(interfaceName))
1126             .setInterface(interfaceName).build();
1127         if (optionalDpnVpninterfacesList.isPresent()) {
1128             LOG.debug("addToNeutronRouterDpnsMap : RouterDpnList already present for the Router {} and DPN {} for the "
1129                     + "Interface {} in the ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
1130             operTx.merge(dpnVpnInterfacesListIdentifier
1131                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
1132                             .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
1133                             new RouterInterfacesKey(interfaceName)), routerInterface, CREATE_MISSING_PARENTS);
1134         } else {
1135             LOG.debug("addToNeutronRouterDpnsMap : Building new RouterDpnList for the Router {} and DPN {} for the "
1136                     + "Interface {} in the ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
1137             RouterDpnListBuilder routerDpnListBuilder = new RouterDpnListBuilder();
1138             routerDpnListBuilder.setRouterId(routerName);
1139             DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
1140             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
1141                 .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces> routerInterfaces = new ArrayList<>();
1142             routerInterfaces.add(routerInterface);
1143             dpnVpnList.setRouterInterfaces(routerInterfaces);
1144             routerDpnListBuilder.setDpnVpninterfacesList(Collections.singletonList(dpnVpnList.build()));
1145             operTx.merge(getRouterId(routerName), routerDpnListBuilder.build(), CREATE_MISSING_PARENTS);
1146         }
1147     }
1148
1149     public static void addToDpnRoutersMap(String routerName, String interfaceName, BigInteger dpId,
1150         TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
1151         if (dpId.equals(BigInteger.ZERO)) {
1152             LOG.error("addToDpnRoutersMap : Could not retrieve dp id for interface {} to handle router {} "
1153                     + "association model", interfaceName, routerName);
1154             return;
1155         }
1156
1157         LOG.debug("addToDpnRoutersMap : Adding the DPN {} and router {} for the Interface {} in the ODL-L3VPN : "
1158                 + "DPNRouters map", dpId, routerName, interfaceName);
1159         InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(dpId);
1160
1161         Optional<DpnRoutersList> optionalDpnRoutersList = operTx.read(dpnRoutersListIdentifier).get();
1162
1163         if (optionalDpnRoutersList.isPresent()) {
1164             RoutersList routersList = new RoutersListBuilder().withKey(new RoutersListKey(routerName))
1165                     .setRouter(routerName).build();
1166             List<RoutersList> routersListFromDs = optionalDpnRoutersList.get().nonnullRoutersList();
1167             if (!routersListFromDs.contains(routersList)) {
1168                 LOG.debug("addToDpnRoutersMap : Router {} not present for the DPN {}"
1169                         + " in the ODL-L3VPN : DPNRouters map", routerName, dpId);
1170                 operTx.merge(dpnRoutersListIdentifier
1171                         .child(RoutersList.class, new RoutersListKey(routerName)), routersList, CREATE_MISSING_PARENTS);
1172             } else {
1173                 LOG.debug("addToDpnRoutersMap : Router {} already mapped to the DPN {} in the ODL-L3VPN : "
1174                         + "DPNRouters map", routerName, dpId);
1175             }
1176         } else {
1177             LOG.debug("addToDpnRoutersMap : Building new DPNRoutersList for the Router {} present in the DPN {} "
1178                     + "ODL-L3VPN : DPNRouters map", routerName, dpId);
1179             DpnRoutersListBuilder dpnRoutersListBuilder = new DpnRoutersListBuilder();
1180             dpnRoutersListBuilder.setDpnId(dpId);
1181             RoutersListBuilder routersListBuilder = new RoutersListBuilder();
1182             routersListBuilder.setRouter(routerName);
1183             dpnRoutersListBuilder.setRoutersList(Collections.singletonList(routersListBuilder.build()));
1184             operTx.merge(getDpnRoutersId(dpId), dpnRoutersListBuilder.build(), CREATE_MISSING_PARENTS);
1185         }
1186     }
1187
1188     public static void removeFromNeutronRouterDpnsMap(String routerName, BigInteger dpId,
1189         TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
1190         if (dpId.equals(BigInteger.ZERO)) {
1191             LOG.warn("removeFromNeutronRouterDpnsMap : DPN ID is invalid for the router {} ", routerName);
1192             return;
1193         }
1194
1195         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1196         Optional<DpnVpninterfacesList> optionalRouterDpnList = operTx.read(routerDpnListIdentifier).get();
1197         if (optionalRouterDpnList.isPresent()) {
1198             LOG.debug("removeFromNeutronRouterDpnsMap : Removing the dpn-vpninterfaces-list from the "
1199                     + "odl-l3vpn:neutron-router-dpns model for the router {}", routerName);
1200             operTx.delete(routerDpnListIdentifier);
1201         } else {
1202             LOG.debug("removeFromNeutronRouterDpnsMap : dpn-vpninterfaces-list does not exist in the "
1203                     + "odl-l3vpn:neutron-router-dpns model for the router {}", routerName);
1204         }
1205     }
1206
1207     public static void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,
1208          BigInteger dpId, @NonNull TypedReadWriteTransaction<Operational> operTx) {
1209         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1210         Optional<DpnVpninterfacesList> optionalRouterDpnList;
1211         try {
1212             optionalRouterDpnList = operTx.read(routerDpnListIdentifier).get();
1213         } catch (InterruptedException | ExecutionException e) {
1214             LOG.error("Error reading the router DPN list for {}", routerDpnListIdentifier, e);
1215             optionalRouterDpnList = Optional.absent();
1216         }
1217         if (optionalRouterDpnList.isPresent()) {
1218             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns
1219                     .router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces> routerInterfaces =
1220                     optionalRouterDpnList.get().getRouterInterfaces();
1221             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn
1222                     .list.dpn.vpninterfaces.list.RouterInterfaces routerInterface =
1223                     new RouterInterfacesBuilder().withKey(new RouterInterfacesKey(vpnInterfaceName))
1224                             .setInterface(vpnInterfaceName).build();
1225
1226             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1227                 if (routerInterfaces.isEmpty()) {
1228                     operTx.delete(routerDpnListIdentifier);
1229                 } else {
1230                     operTx.delete(routerDpnListIdentifier.child(
1231                             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
1232                                     .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
1233                             new RouterInterfacesKey(vpnInterfaceName)));
1234                 }
1235             }
1236         }
1237     }
1238
1239     public static void removeFromDpnRoutersMap(DataBroker broker, String routerName, String vpnInterfaceName,
1240         BigInteger curDpnId, OdlInterfaceRpcService ifaceMgrRpcService, TypedReadWriteTransaction<Operational> operTx)
1241         throws ExecutionException, InterruptedException {
1242         /*
1243             1) Get the DpnRoutersList for the DPN.
1244             2) Get the RoutersList identifier for the DPN and router.
1245             3) Get the VPN interfaces for the router (routerList) through which it is connected to the DPN.
1246             4) If the removed VPN interface is the only interface through which the router is connected to the DPN,
1247              then remove RouterList.
1248          */
1249
1250         LOG.debug("removeFromDpnRoutersMap() : Removing the DPN {} and router {} for the Interface {}"
1251             + " in the ODL-L3VPN : DPNRouters map", curDpnId, routerName, vpnInterfaceName);
1252
1253         //Get the dpn-routers-list instance for the current DPN.
1254         InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(curDpnId);
1255         Optional<DpnRoutersList> dpnRoutersListData = operTx.read(dpnRoutersListIdentifier).get();
1256
1257         if (dpnRoutersListData == null || !dpnRoutersListData.isPresent()) {
1258             LOG.error("removeFromDpnRoutersMap : dpn-routers-list is not present for DPN {} "
1259                     + "in the ODL-L3VPN:dpn-routers model", curDpnId);
1260             return;
1261         }
1262
1263         //Get the routers-list instance for the router on the current DPN only
1264         InstanceIdentifier<RoutersList> routersListIdentifier = getRoutersList(curDpnId, routerName);
1265         Optional<RoutersList> routersListData = operTx.read(routersListIdentifier).get();
1266
1267         if (routersListData == null || !routersListData.isPresent()) {
1268             LOG.error("removeFromDpnRoutersMap : routers-list is not present for the DPN {} "
1269                     + "in the ODL-L3VPN:dpn-routers model",
1270                 curDpnId);
1271             return;
1272         }
1273
1274         LOG.debug("removeFromDpnRoutersMap : Get the interfaces for the router {} "
1275                 + "from the NeutronVPN - router-interfaces-map", routerName);
1276         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router
1277             .interfaces.map.RouterInterfaces> routerInterfacesId = getRoutersInterfacesIdentifier(routerName);
1278         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map
1279                 .RouterInterfaces> routerInterfacesData =
1280                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1281                         LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
1282
1283         if (routerInterfacesData == null || !routerInterfacesData.isPresent()) {
1284             LOG.debug("removeFromDpnRoutersMap : Unable to get the routers list for the DPN {}. Possibly all subnets "
1285                     + "removed from router {} OR Router {} has been deleted. Hence DPN router model WILL be cleared ",
1286                 curDpnId, routerName, routerName);
1287             operTx.delete(routersListIdentifier);
1288             return;
1289         }
1290
1291         //Get the VM interfaces for the router on the current DPN only.
1292         List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces
1293             .map.router.interfaces.Interfaces> vmInterfaces = routerInterfacesData.get().getInterfaces();
1294         if (vmInterfaces == null) {
1295             LOG.debug("removeFromDpnRoutersMap : VM interfaces are not present for the router {} in the "
1296                 + "NeutronVPN - router-interfaces-map", routerName);
1297             return;
1298         }
1299
1300         // If the removed VPN interface is the only interface through which the router is connected to the DPN,
1301         // then remove RouterList.
1302         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map
1303                  .router.interfaces.Interfaces vmInterface : vmInterfaces) {
1304             String vmInterfaceName = vmInterface.getInterfaceId();
1305             BigInteger vmDpnId = getDpnForInterface(ifaceMgrRpcService, vmInterfaceName);
1306             if (vmDpnId.equals(BigInteger.ZERO) || !vmDpnId.equals(curDpnId)) {
1307                 LOG.debug("removeFromDpnRoutersMap : DPN ID {} for the removed interface {} is not the same as that of "
1308                         + "the DPN ID {} for the checked interface {}",
1309                     curDpnId, vpnInterfaceName, vmDpnId, vmInterfaceName);
1310                 continue;
1311             }
1312             if (!vmInterfaceName.equalsIgnoreCase(vpnInterfaceName)) {
1313                 LOG.info("removeFromDpnRoutersMap : Router {} is present in the DPN {} through the other interface {} "
1314                     + "Hence DPN router model WOULD NOT be cleared", routerName, curDpnId, vmInterfaceName);
1315                 return;
1316             }
1317         }
1318         LOG.debug("removeFromDpnRoutersMap : Router {} is present in the DPN {} only through the interface {} "
1319             + "Hence DPN router model WILL be cleared. Possibly last VM for the router "
1320             + "deleted in the DPN", routerName, curDpnId, vpnInterfaceName);
1321         operTx.delete(routersListIdentifier);
1322     }
1323
1324     private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
1325         .rev150602.router.interfaces.map.RouterInterfaces> getRoutersInterfacesIdentifier(String routerName) {
1326         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
1327             .rev150602.RouterInterfacesMap.class)
1328             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router
1329                     .interfaces.map.RouterInterfaces.class,
1330                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router
1331                     .interfaces.map.RouterInterfacesKey(new Uuid(routerName))).build();
1332     }
1333
1334     private static InstanceIdentifier<RoutersList> getRoutersList(BigInteger dpnId, String routerName) {
1335         return InstanceIdentifier.builder(DpnRouters.class)
1336             .child(DpnRoutersList.class, new DpnRoutersListKey(dpnId))
1337             .child(RoutersList.class, new RoutersListKey(routerName)).build();
1338     }
1339
1340     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
1341         BigInteger nodeId = BigInteger.ZERO;
1342         try {
1343             GetDpidFromInterfaceInput
1344                 dpIdInput =
1345                 new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
1346             Future<RpcResult<GetDpidFromInterfaceOutput>>
1347                 dpIdOutput =
1348                 interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
1349             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
1350             if (dpIdResult.isSuccessful()) {
1351                 nodeId = dpIdResult.getResult().getDpid();
1352             } else {
1353                 LOG.debug("getDpnForInterface : Could not retrieve DPN Id for interface {}", ifName);
1354             }
1355         } catch (NullPointerException | InterruptedException | ExecutionException e) {
1356             LOG.error("getDpnForInterface : Exception when getting dpn for interface {}", ifName, e);
1357         }
1358         return nodeId;
1359     }
1360
1361     @NonNull
1362     public static List<ActionInfo> getEgressActionsForInterface(OdlInterfaceRpcService odlInterfaceRpcService,
1363                                                                 ItmRpcService itmRpcService,
1364                                                                 IInterfaceManager interfaceManager, String ifName,
1365                                                                 Long tunnelKey, boolean internalTunnelInterface) {
1366         return getEgressActionsForInterface(odlInterfaceRpcService, itmRpcService, interfaceManager,
1367                 ifName, tunnelKey, 0, internalTunnelInterface);
1368     }
1369
1370     @NonNull
1371     public static List<ActionInfo> getEgressActionsForInterface(OdlInterfaceRpcService odlInterfaceRpcService,
1372                                                                 ItmRpcService itmRpcService,
1373                                                                 IInterfaceManager interfaceManager,
1374                                                                 String ifName, @Nullable Long tunnelKey, int pos,
1375                                                                 boolean internalTunnelInterface) {
1376         LOG.debug("getEgressActionsForInterface : called for interface {}", ifName);
1377         GetEgressActionsForInterfaceInputBuilder egressActionsIfmBuilder =
1378                 new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName);
1379         GetEgressActionsForTunnelInputBuilder egressActionsItmBuilder =
1380                 new GetEgressActionsForTunnelInputBuilder().setIntfName(ifName);
1381         if (tunnelKey != null) {
1382             egressActionsIfmBuilder.setTunnelKey(tunnelKey);
1383             egressActionsItmBuilder.setTunnelKey(tunnelKey);
1384         } //init builders, ITM/IFM rpc can be called based on type of interface
1385
1386         try {
1387             List<Action> actions = emptyList();
1388             if (interfaceManager.isItmDirectTunnelsEnabled() && internalTunnelInterface) {
1389                 RpcResult<GetEgressActionsForTunnelOutput> rpcResult =
1390                         itmRpcService.getEgressActionsForTunnel(egressActionsItmBuilder.build()).get();
1391                 if (!rpcResult.isSuccessful()) {
1392                     LOG.error("getEgressActionsForTunnels : RPC Call to Get egress actions for Tunnels {} "
1393                             + "returned with Errors {}", ifName, rpcResult.getErrors());
1394                 } else {
1395                     actions = rpcResult.getResult().nonnullAction();
1396                 }
1397             } else {
1398                 RpcResult<GetEgressActionsForInterfaceOutput> rpcResult =
1399                         odlInterfaceRpcService.getEgressActionsForInterface(egressActionsIfmBuilder.build()).get();
1400                 if (!rpcResult.isSuccessful()) {
1401                     LOG.error("getEgressActionsForInterface : RPC Call to Get egress actions for interface {} "
1402                             + "returned with Errors {}", ifName, rpcResult.getErrors());
1403                 } else {
1404                     actions = rpcResult.getResult().nonnullAction();
1405                 }
1406             }
1407             List<ActionInfo> listActionInfo = new ArrayList<>();
1408             for (Action action : actions) {
1409                 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action
1410                     actionClass = action.getAction();
1411                 if (actionClass instanceof OutputActionCase) {
1412                     listActionInfo.add(new ActionOutput(pos++,
1413                         ((OutputActionCase) actionClass).getOutputAction().getOutputNodeConnector()));
1414                 } else if (actionClass instanceof PushVlanActionCase) {
1415                     listActionInfo.add(new ActionPushVlan(pos++));
1416                 } else if (actionClass instanceof SetFieldCase) {
1417                     if (((SetFieldCase) actionClass).getSetField().getVlanMatch() != null) {
1418                         int vlanVid = ((SetFieldCase) actionClass).getSetField().getVlanMatch().getVlanId()
1419                             .getVlanId().getValue();
1420                         listActionInfo.add(new ActionSetFieldVlanVid(pos++, vlanVid));
1421                     }
1422                 } else if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
1423                     Short tableId = ((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable();
1424                     listActionInfo.add(new ActionNxResubmit(pos++, tableId));
1425                 } else if (actionClass instanceof NxActionRegLoadNodesNodeTableFlowApplyActionsCase) {
1426                     NxRegLoad nxRegLoad =
1427                         ((NxActionRegLoadNodesNodeTableFlowApplyActionsCase) actionClass).getNxRegLoad();
1428                     listActionInfo.add(new ActionRegLoad(pos++, NxmNxReg6.class, nxRegLoad.getDst().getStart(),
1429                         nxRegLoad.getDst().getEnd(), nxRegLoad.getValue().longValue()));
1430                 }
1431             }
1432             return listActionInfo;
1433         } catch (InterruptedException | ExecutionException e) {
1434             LOG.error("Exception when egress actions for interface {}", ifName, e);
1435         }
1436         LOG.error("Error when getting egress actions for interface {}", ifName);
1437         return emptyList();
1438     }
1439
1440     @Nullable
1441     public static Port getNeutronPortForRouterGetewayIp(DataBroker broker, IpAddress targetIP) {
1442         return getNeutronPortForIp(broker, targetIP, NeutronConstants.DEVICE_OWNER_GATEWAY_INF);
1443     }
1444
1445     @NonNull
1446     public static List<Port> getNeutronPorts(DataBroker broker) {
1447         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports>
1448             portsIdentifier = InstanceIdentifier.create(Neutron.class)
1449             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports.class);
1450         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports>
1451                 portsOptional =
1452                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1453                         LogicalDatastoreType.CONFIGURATION, portsIdentifier);
1454
1455         if (!portsOptional.isPresent() || portsOptional.get().getPort() == null) {
1456             LOG.error("getNeutronPorts : No neutron ports found");
1457             return emptyList();
1458         }
1459
1460         return portsOptional.get().getPort();
1461     }
1462
1463     @Nullable
1464     public static Port getNeutronPortForIp(DataBroker broker, IpAddress targetIP, String deviceType) {
1465         List<Port> ports = getNeutronPorts(
1466             broker);
1467
1468         for (Port port : ports) {
1469             if (deviceType.equals(port.getDeviceOwner()) && port.getFixedIps() != null) {
1470                 for (FixedIps ip : port.getFixedIps()) {
1471                     if (Objects.equals(ip.getIpAddress(), targetIP)) {
1472                         return port;
1473                     }
1474                 }
1475             }
1476         }
1477         LOG.error("getNeutronPortForIp : Neutron Port missing for IP:{} DeviceType:{}", targetIP, deviceType);
1478         return null;
1479     }
1480
1481     @Nullable
1482     public static Uuid getSubnetIdForFloatingIp(Port port, IpAddress targetIP) {
1483         if (port == null) {
1484             LOG.error("getSubnetIdForFloatingIp : port is null");
1485             return null;
1486         }
1487         for (FixedIps ip : port.nonnullFixedIps()) {
1488             if (Objects.equals(ip.getIpAddress(), targetIP)) {
1489                 return ip.getSubnetId();
1490             }
1491         }
1492         LOG.error("getSubnetIdForFloatingIp : No Fixed IP configured for targetIP:{}", targetIP);
1493         return null;
1494     }
1495
1496     @Nullable
1497     public static Subnetmap getSubnetMap(DataBroker broker, Uuid subnetId) {
1498         InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier.builder(Subnetmaps.class)
1499             .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
1500         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1501                 LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
1502     }
1503
1504     @NonNull
1505     public static List<Uuid> getSubnetIdsFromNetworkId(DataBroker broker, Uuid networkId) {
1506         InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class)
1507             .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
1508         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1509                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(NetworkMap::getSubnetIdList).orElse(
1510                 emptyList());
1511     }
1512
1513     @Nullable
1514     public static String getSubnetGwMac(DataBroker broker, Uuid subnetId, String vpnName) {
1515         if (subnetId == null) {
1516             LOG.error("getSubnetGwMac : subnetID is null");
1517             return null;
1518         }
1519
1520         InstanceIdentifier<Subnet> subnetInst = InstanceIdentifier.create(Neutron.class).child(Subnets.class)
1521             .child(Subnet.class, new SubnetKey(subnetId));
1522         Optional<Subnet> subnetOpt =
1523                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1524                         LogicalDatastoreType.CONFIGURATION, subnetInst);
1525         if (!subnetOpt.isPresent()) {
1526             LOG.error("getSubnetGwMac : unable to obtain Subnet for id : {}", subnetId);
1527             return null;
1528         }
1529
1530         IpAddress gatewayIp = subnetOpt.get().getGatewayIp();
1531         if (gatewayIp == null) {
1532             LOG.warn("getSubnetGwMac : No GW ip found for subnet {}", subnetId.getValue());
1533             return null;
1534         }
1535
1536         if (null != gatewayIp.getIpv6Address()) {
1537             return null;
1538         }
1539
1540         InstanceIdentifier<VpnPortipToPort> portIpInst = InstanceIdentifier.builder(NeutronVpnPortipPortData.class)
1541             .child(VpnPortipToPort.class, new VpnPortipToPortKey(gatewayIp.getIpv4Address().getValue(), vpnName))
1542             .build();
1543         Optional<VpnPortipToPort> portIpToPortOpt =
1544                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1545                         LogicalDatastoreType.CONFIGURATION, portIpInst);
1546         if (portIpToPortOpt.isPresent()) {
1547             return portIpToPortOpt.get().getMacAddress();
1548         }
1549
1550         InstanceIdentifier<LearntVpnVipToPort> learntIpInst = InstanceIdentifier.builder(LearntVpnVipToPortData.class)
1551             .child(LearntVpnVipToPort.class, new LearntVpnVipToPortKey(gatewayIp.getIpv4Address().getValue(), vpnName))
1552             .build();
1553         Optional<LearntVpnVipToPort> learntIpToPortOpt =
1554                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1555                         LogicalDatastoreType.OPERATIONAL, learntIpInst);
1556         if (learntIpToPortOpt.isPresent()) {
1557             return learntIpToPortOpt.get().getMacAddress();
1558         }
1559
1560         LOG.info("getSubnetGwMac : No resolution was found to GW ip {} in subnet {}", gatewayIp, subnetId.getValue());
1561         return null;
1562     }
1563
1564     public static boolean isIPv6Subnet(String prefix) {
1565         return IpPrefixBuilder.getDefaultInstance(prefix).getIpv6Prefix() != null;
1566     }
1567
1568     static InstanceIdentifier<DpnRoutersList> getDpnRoutersId(BigInteger dpnId) {
1569         return InstanceIdentifier.builder(DpnRouters.class)
1570             .child(DpnRoutersList.class, new DpnRoutersListKey(dpnId)).build();
1571     }
1572
1573     static InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
1574         return InstanceIdentifier.builder(NeutronRouterDpns.class)
1575             .child(RouterDpnList.class, new RouterDpnListKey(routerName))
1576             .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
1577     }
1578
1579     static InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
1580         return InstanceIdentifier.builder(NeutronRouterDpns.class)
1581             .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
1582     }
1583
1584     @Nullable
1585     protected static String getFloatingIpPortMacFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
1586         InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1587         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1588                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
1589                 FloatingIpIdToPortMapping::getFloatingIpPortMacAddress).orElse(null);
1590     }
1591
1592     @Nullable
1593     protected static String getFloatingIpPortMacFromFloatingIpId(TypedReadTransaction<Configuration> confTx,
1594         Uuid floatingIpId) {
1595         try {
1596             return confTx.read(buildfloatingIpIdToPortMappingIdentifier(floatingIpId)).get().toJavaUtil().map(
1597                 FloatingIpIdToPortMapping::getFloatingIpPortMacAddress).orElse(null);
1598         } catch (InterruptedException | ExecutionException e) {
1599             LOG.error("Error reading the floating IP port MAC for {}", floatingIpId, e);
1600             return null;
1601         }
1602     }
1603
1604     @Nullable
1605     protected static Uuid getFloatingIpPortSubnetIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
1606         InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1607         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1608                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
1609                 FloatingIpIdToPortMapping::getFloatingIpPortSubnetId).orElse(null);
1610     }
1611
1612     @Nullable
1613     protected static Uuid getFloatingIpPortSubnetIdFromFloatingIpId(TypedReadTransaction<Configuration> confTx,
1614         Uuid floatingIpId) {
1615         try {
1616             return confTx.read(buildfloatingIpIdToPortMappingIdentifier(floatingIpId)).get().toJavaUtil().map(
1617                 FloatingIpIdToPortMapping::getFloatingIpPortSubnetId).orElse(null);
1618         } catch (InterruptedException | ExecutionException e) {
1619             LOG.error("Error reading the floating IP port subnet for {}", floatingIpId, e);
1620             return null;
1621         }
1622     }
1623
1624     static InstanceIdentifier<FloatingIpIdToPortMapping> buildfloatingIpIdToPortMappingIdentifier(Uuid floatingIpId) {
1625         return InstanceIdentifier.builder(FloatingIpPortInfo.class).child(FloatingIpIdToPortMapping.class, new
1626             FloatingIpIdToPortMappingKey(floatingIpId)).build();
1627     }
1628
1629     @Nullable
1630     static Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
1631         InstanceIdentifier<Interface> ifStateId =
1632             buildStateInterfaceId(interfaceName);
1633         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1634                 LogicalDatastoreType.OPERATIONAL, ifStateId).orNull();
1635     }
1636
1637     static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
1638         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
1639             InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
1640                 .interfaces.rev140508.InterfacesState.class)
1641                 .child(Interface.class,
1642                     new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
1643                         .interfaces.state.InterfaceKey(interfaceName));
1644         return idBuilder.build();
1645     }
1646
1647     @Nullable
1648     public static Routers getRoutersFromConfigDS(DataBroker dataBroker, String routerName) {
1649         InstanceIdentifier<Routers> routerIdentifier = NatUtil.buildRouterIdentifier(routerName);
1650         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1651                 LogicalDatastoreType.CONFIGURATION, routerIdentifier).orNull();
1652     }
1653
1654     @Nullable
1655     public static Routers getRoutersFromConfigDS(TypedReadTransaction<Configuration> confTx, String routerName) {
1656         try {
1657             return confTx.read(NatUtil.buildRouterIdentifier(routerName)).get().orNull();
1658         } catch (InterruptedException | ExecutionException e) {
1659             LOG.error("Error reading router {}", routerName, e);
1660             return null;
1661         }
1662     }
1663
1664     static void createRouterIdsConfigDS(DataBroker dataBroker, long routerId, String routerName) {
1665         if (routerId == NatConstants.INVALID_ID) {
1666             LOG.error("createRouterIdsConfigDS : invalid routerId for routerName {}", routerName);
1667             return;
1668         }
1669         RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(routerId))
1670             .setRouterId(routerId).setRouterName(routerName).build();
1671         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, buildRouterIdentifier(routerId), rtrs);
1672     }
1673
1674     @Nullable
1675     static FlowEntity buildDefaultNATFlowEntityForExternalSubnet(BigInteger dpId, long vpnId, String subnetId,
1676             IdManagerService idManager) {
1677         InetAddress defaultIP = null;
1678         try {
1679             defaultIP = InetAddress.getByName("0.0.0.0");
1680         } catch (UnknownHostException e) {
1681             LOG.error("buildDefaultNATFlowEntityForExternalSubnet : Failed to build FIB Table Flow for "
1682                     + "Default Route to NAT.", e);
1683             return null;
1684         }
1685
1686         List<MatchInfo> matches = new ArrayList<>();
1687         matches.add(MatchEthernetType.IPV4);
1688         //add match for vrfid
1689         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
1690
1691         List<InstructionInfo> instructions = new ArrayList<>();
1692         List<ActionInfo> actionsInfo = new ArrayList<>();
1693         long groupId = createGroupId(NatUtil.getGroupIdKey(subnetId), idManager);
1694         actionsInfo.add(new ActionGroup(groupId));
1695         String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP, vpnId);
1696         instructions.add(new InstructionApplyActions(actionsInfo));
1697         return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
1698                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
1699                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
1700     }
1701
1702     @Nullable
1703     static String getExtGwMacAddFromRouterId(DataBroker broker, long routerId) {
1704         String routerName = getRouterName(broker, routerId);
1705         if (routerName == null) {
1706             LOG.error("getExtGwMacAddFromRouterId : empty routerName received");
1707             return null;
1708         }
1709         return getExtGwMacAddFromRouterName(broker, routerName);
1710     }
1711
1712     @Nullable
1713     static String getExtGwMacAddFromRouterName(DataBroker broker, String routerName) {
1714         InstanceIdentifier<Routers> id = buildRouterIdentifier(routerName);
1715         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1716                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Routers::getExtGwMacAddress).orElse(null);
1717     }
1718
1719     @Nullable
1720     static String getExtGwMacAddFromRouterName(TypedReadTransaction<Configuration> tx, String routerName) {
1721         try {
1722             return tx.read(buildRouterIdentifier(routerName)).get().toJavaUtil().map(
1723                 Routers::getExtGwMacAddress).orElse(null);
1724         } catch (InterruptedException | ExecutionException e) {
1725             LOG.error("Error retrieving external gateway MAC address for router {}", routerName, e);
1726             return null;
1727         }
1728     }
1729
1730     static InstanceIdentifier<Router> buildNeutronRouterIdentifier(Uuid routerUuid) {
1731         InstanceIdentifier<Router> routerInstanceIdentifier = InstanceIdentifier.create(Neutron.class)
1732              .child(org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers.class)
1733              .child(Router.class, new RouterKey(routerUuid));
1734         return routerInstanceIdentifier;
1735     }
1736
1737     @Nullable
1738     public static String getNeutronRouterNamebyUuid(DataBroker broker, Uuid routerUuid) {
1739         InstanceIdentifier<Router> neutronRouterIdentifier = NatUtil.buildNeutronRouterIdentifier(routerUuid);
1740         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1741                 LogicalDatastoreType.CONFIGURATION, neutronRouterIdentifier).toJavaUtil().map(Router::getName).orElse(
1742                 null);
1743     }
1744
1745     @NonNull
1746     public static List<Ports> getFloatingIpPortsForRouter(DataBroker broker, Uuid routerUuid) {
1747         InstanceIdentifier<RouterPorts> routerPortsIdentifier = getRouterPortsId(routerUuid.getValue());
1748         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1749                 LogicalDatastoreType.CONFIGURATION,
1750                 routerPortsIdentifier).toJavaUtil().map(RouterPorts::getPorts).orElse(emptyList());
1751     }
1752
1753     @NonNull
1754     public static List<Uuid> getRouterUuIdsForVpn(DataBroker broker, Uuid vpnUuid) {
1755         InstanceIdentifier<ExternalNetworks> externalNwIdentifier = InstanceIdentifier.create(ExternalNetworks.class);
1756         Optional<ExternalNetworks> externalNwData =
1757                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1758                         LogicalDatastoreType.CONFIGURATION, externalNwIdentifier);
1759         if (externalNwData.isPresent()) {
1760             for (Networks externalNw : externalNwData.get().nonnullNetworks()) {
1761                 if (externalNw.getVpnid() != null && externalNw.getVpnid().equals(vpnUuid)) {
1762                     @Nullable List<Uuid> routerIds = externalNw.getRouterIds();
1763                     return routerIds != null ? routerIds : emptyList();
1764                 }
1765             }
1766         }
1767         return emptyList();
1768     }
1769
1770     public static boolean isIpInSubnet(String ipAddress, String start, String end) {
1771
1772         try {
1773             long ipLo = ipToLong(InetAddress.getByName(start));
1774             long ipHi = ipToLong(InetAddress.getByName(end));
1775             long ipToTest = ipToLong(InetAddress.getByName(ipAddress));
1776             return ipToTest >= ipLo && ipToTest <= ipHi;
1777         } catch (UnknownHostException e) {
1778             LOG.error("isIpInSubnet : failed for IP {}", ipAddress, e);
1779             return false;
1780         }
1781     }
1782
1783     @NonNull
1784     public static Collection<Uuid> getExternalSubnetIdsFromExternalIps(@Nullable List<ExternalIps> externalIps) {
1785         if (externalIps == null) {
1786             return Collections.emptySet();
1787         }
1788
1789         return externalIps.stream().map(ExternalIps::getSubnetId).collect(Collectors.toSet());
1790     }
1791
1792     @NonNull
1793     public static Collection<Uuid> getExternalSubnetIdsForRouter(DataBroker dataBroker, @Nullable String routerName) {
1794         if (routerName == null) {
1795             LOG.error("getExternalSubnetIdsForRouter : empty routerName received");
1796             return Collections.emptySet();
1797         }
1798
1799         InstanceIdentifier<Routers> id = buildRouterIdentifier(routerName);
1800         Optional<Routers> routerData =
1801                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1802                         LogicalDatastoreType.CONFIGURATION, id);
1803         if (routerData.isPresent()) {
1804             return NatUtil.getExternalSubnetIdsFromExternalIps(routerData.get().getExternalIps());
1805         } else {
1806             LOG.warn("getExternalSubnetIdsForRouter : No external router data for router {}", routerName);
1807             return Collections.emptySet();
1808         }
1809     }
1810
1811     @NonNull
1812     protected static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
1813         .subnets.Subnets> getOptionalExternalSubnets(DataBroker dataBroker, Uuid subnetId) {
1814         if (subnetId == null) {
1815             LOG.warn("getOptionalExternalSubnets : subnetId is null");
1816             return Optional.absent();
1817         }
1818
1819         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
1820             .rev160111.external.subnets.Subnets> subnetsIdentifier =
1821                 InstanceIdentifier.builder(ExternalSubnets.class)
1822                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
1823                         .rev160111.external.subnets.Subnets.class, new SubnetsKey(subnetId)).build();
1824         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
1825                 LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
1826     }
1827
1828     @NonNull
1829     protected static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
1830         .subnets.Subnets> getOptionalExternalSubnets(TypedReadTransaction<Configuration> tx, Uuid subnetId) {
1831         if (subnetId == null) {
1832             LOG.warn("getOptionalExternalSubnets : subnetId is null");
1833             return Optional.absent();
1834         }
1835
1836         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
1837             .rev160111.external.subnets.Subnets> subnetsIdentifier =
1838             InstanceIdentifier.builder(ExternalSubnets.class)
1839                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
1840                     .rev160111.external.subnets.Subnets.class, new SubnetsKey(subnetId)).build();
1841         try {
1842             return tx.read(subnetsIdentifier).get();
1843         } catch (InterruptedException | ExecutionException e) {
1844             LOG.error("Error retrieving external subnets on {}", subnetId, e);
1845             return Optional.absent();
1846         }
1847     }
1848
1849     protected static long getExternalSubnetVpnId(DataBroker dataBroker, Uuid subnetId) {
1850         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
1851             .subnets.Subnets> optionalExternalSubnets = NatUtil.getOptionalExternalSubnets(dataBroker,
1852                    subnetId);
1853         if (optionalExternalSubnets.isPresent()) {
1854             return NatUtil.getVpnId(dataBroker, subnetId.getValue());
1855         }
1856
1857         return NatConstants.INVALID_ID;
1858     }
1859
1860     protected static long getExternalSubnetVpnId(TypedReadTransaction<Configuration> tx, Uuid subnetId) {
1861         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
1862             .subnets.Subnets> optionalExternalSubnets = NatUtil.getOptionalExternalSubnets(tx,
1863             subnetId);
1864         if (optionalExternalSubnets.isPresent()) {
1865             return NatUtil.getVpnId(tx, subnetId.getValue());
1866         }
1867
1868         return NatConstants.INVALID_ID;
1869     }
1870
1871     protected static long getExternalSubnetVpnIdForRouterExternalIp(DataBroker dataBroker, String externalIpAddress,
1872             Routers router) {
1873         Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIpAddress, router);
1874         if (externalSubnetId != null) {
1875             return NatUtil.getExternalSubnetVpnId(dataBroker,externalSubnetId);
1876         }
1877
1878         return NatConstants.INVALID_ID;
1879     }
1880
1881     @Nullable
1882     protected static Uuid getExternalSubnetForRouterExternalIp(String externalIpAddress, Routers router) {
1883         externalIpAddress = validateAndAddNetworkMask(externalIpAddress);
1884         for (ExternalIps extIp : router.nonnullExternalIps()) {
1885             String extIpString = validateAndAddNetworkMask(extIp.getIpAddress());
1886             if (extIpString.equals(externalIpAddress)) {
1887                 return extIp.getSubnetId();
1888             }
1889         }
1890         LOG.warn("getExternalSubnetForRouterExternalIp : Missing External Subnet for Ip:{}", externalIpAddress);
1891         return null;
1892     }
1893
1894     private static long ipToLong(InetAddress ip) {
1895         byte[] octets = ip.getAddress();
1896         long result = 0;
1897         for (byte octet : octets) {
1898             result <<= 8;
1899             result |= octet & 0xff;
1900         }
1901         return result;
1902     }
1903
1904     @NonNull
1905     static List<String> getIpsListFromExternalIps(@Nullable List<ExternalIps> externalIps) {
1906         if (externalIps == null) {
1907             return emptyList();
1908         }
1909
1910         return externalIps.stream().map(ExternalIps::getIpAddress).collect(Collectors.toList());
1911     }
1912
1913     // elan-instances config container
1914     @Nullable
1915     public static ElanInstance getElanInstanceByName(String elanInstanceName, DataBroker broker) {
1916         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
1917         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
1918                 LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
1919     }
1920
1921     @Nullable
1922     public static ElanInstance getElanInstanceByName(TypedReadTransaction<Configuration> tx, String elanInstanceName) {
1923         try {
1924             return tx.read(getElanInstanceConfigurationDataPath(elanInstanceName)).get().orNull();
1925         } catch (InterruptedException | ExecutionException e) {
1926             LOG.error("Error retrieving ELAN instance by name {}", elanInstanceName, e);
1927             return null;
1928         }
1929     }
1930
1931     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
1932         return InstanceIdentifier.builder(ElanInstances.class)
1933                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
1934     }
1935
1936     public static long getTunnelIdForNonNaptToNaptFlow(DataBroker dataBroker, NatOverVxlanUtil natOverVxlanUtil,
1937                                                        IElanService elanManager, IdManagerService idManager,
1938                                                        long routerId, String routerName) {
1939         if (elanManager.isOpenStackVniSemanticsEnforced()) {
1940             // Router VNI will be set as tun_id if OpenStackSemantics is enabled
1941             return natOverVxlanUtil.getRouterVni(routerName, routerId).longValue();
1942         } else {
1943             return NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
1944         }
1945     }
1946
1947     public static void makePreDnatToSnatTableEntry(IMdsalApiManager mdsalManager, BigInteger naptDpnId,
1948             short tableId, TypedWriteTransaction<Configuration> confTx) {
1949         LOG.debug("makePreDnatToSnatTableEntry : Create Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
1950                 NwConstants.PDNAT_TABLE, tableId, naptDpnId);
1951
1952         List<Instruction> preDnatToSnatInstructions = new ArrayList<>();
1953         preDnatToSnatInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1954         List<MatchInfo> matches = new ArrayList<>();
1955         matches.add(MatchEthernetType.IPV4);
1956         String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
1957         Flow preDnatToSnatTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.PDNAT_TABLE,flowRef,
1958                 5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE,
1959                 matches, preDnatToSnatInstructions);
1960
1961         mdsalManager.addFlow(confTx, naptDpnId, preDnatToSnatTableFlowEntity);
1962         LOG.debug("makePreDnatToSnatTableEntry : Successfully installed Pre-DNAT flow {} on NAPT DpnId {} ",
1963                 preDnatToSnatTableFlowEntity,  naptDpnId);
1964     }
1965
1966     public static void removePreDnatToSnatTableEntry(TypedReadWriteTransaction<Configuration> confTx,
1967             IMdsalApiManager mdsalManager, BigInteger naptDpnId) throws ExecutionException, InterruptedException {
1968         LOG.debug("removePreDnatToSnatTableEntry : Remove Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
1969                 NwConstants.PDNAT_TABLE, NwConstants.INBOUND_NAPT_TABLE, naptDpnId);
1970         String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
1971         mdsalManager.removeFlow(confTx, naptDpnId, flowRef, NwConstants.PDNAT_TABLE);
1972         LOG.debug("removePreDnatToSnatTableEntry: Successfully removed Pre-DNAT flow {} on NAPT DpnId = {}",
1973                 flowRef, naptDpnId);
1974     }
1975
1976     private static String getFlowRefPreDnatToSnat(BigInteger dpnId, short tableId, String uniqueId) {
1977         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
1978                 + NwConstants.FLOWID_SEPARATOR + uniqueId;
1979     }
1980
1981     public static boolean isFloatingIpPresentForDpn(DataBroker dataBroker, BigInteger dpnId, String rd,
1982                                                     String vpnName, String externalIp,
1983                                                     Boolean isMoreThanOneFipCheckOnDpn) {
1984         InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
1985         Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1986         if (dpnInVpn.isPresent()) {
1987             LOG.debug("isFloatingIpPresentForDpn : vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, "
1988                     + "rd {} and floatingIp {}", vpnName, dpnId, rd, externalIp);
1989             try {
1990                 List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
1991                 if (ipAddressList != null && !ipAddressList.isEmpty()) {
1992                     int floatingIpPresentCount = 0;
1993                     for (IpAddresses ipAddress: ipAddressList) {
1994                         if (!Objects.equals(ipAddress.getIpAddress(), externalIp)
1995                                 && IpAddresses.IpAddressSource.FloatingIP.equals(ipAddress.getIpAddressSource())) {
1996                             floatingIpPresentCount++;
1997                             //Add tunnel table check
1998                             if (isMoreThanOneFipCheckOnDpn && floatingIpPresentCount > 1) {
1999                                 return true;
2000                             }
2001                             //Remove tunnel table check
2002                             if (!isMoreThanOneFipCheckOnDpn) {
2003                                 return true;
2004                             }
2005                         }
2006                     }
2007                 } else {
2008                     LOG.debug("isFloatingIpPresentForDpn : vpn-to-dpn-list does not contain any floating IP for DPN {}",
2009                            dpnId);
2010                     return false;
2011                 }
2012             } catch (NullPointerException e) {
2013                 LOG.error("isFloatingIpPresentForDpn: Exception occurred on getting external IP address from "
2014                         + "vpn-to-dpn-list on Dpn {}", dpnId, e);
2015                 return false;
2016             }
2017         }
2018         return false;
2019     }
2020
2021     private static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
2022         return InstanceIdentifier.builder(VpnInstanceOpData.class)
2023                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
2024                 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
2025     }
2026
2027     @Nullable
2028     public static String getPrimaryRd(String vpnName, TypedReadTransaction<Configuration> tx)
2029         throws ExecutionException, InterruptedException {
2030         return tx.read(getVpnInstanceIdentifier(vpnName)).get().toJavaUtil().map(NatUtil::getPrimaryRd).orElse(null);
2031     }
2032
2033     @Nullable
2034     public static String getPrimaryRd(@Nullable VpnInstance vpnInstance) {
2035         if (vpnInstance == null) {
2036             return null;
2037         }
2038         List<String> rds = getListOfRdsFromVpnInstance(vpnInstance);
2039         return rds.isEmpty() ? vpnInstance.getVpnInstanceName() : rds.get(0);
2040     }
2041
2042     public static InstanceIdentifier<VpnInstance> getVpnInstanceIdentifier(String vpnName) {
2043         return InstanceIdentifier.builder(VpnInstances.class)
2044             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
2045     }
2046
2047     @NonNull
2048     public static List<String> getListOfRdsFromVpnInstance(VpnInstance vpnInstance) {
2049         VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
2050         return vpnConfig.getRouteDistinguisher() != null ? new ArrayList<>(
2051                 vpnConfig.getRouteDistinguisher()) : new ArrayList<>();
2052     }
2053
2054     public static String validateAndAddNetworkMask(String ipAddress) {
2055         return ipAddress.contains("/32") ? ipAddress : ipAddress + "/32";
2056     }
2057
2058     public static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
2059             String vpnInterfaceName, String vpnName) {
2060         return InstanceIdentifier.builder(VpnInterfaceOpData.class).child(VpnInterfaceOpDataEntry.class,
2061         new VpnInterfaceOpDataEntryKey(vpnInterfaceName, vpnName)).build();
2062     }
2063
2064     public static boolean checkForRoutersWithSameExtNetAndNaptSwitch(DataBroker broker, Uuid networkId,
2065                                                                      String routerName, BigInteger dpnId) {
2066         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
2067         Optional<Networks> networkData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
2068
2069         if (networkData != null && networkData.isPresent()) {
2070             List<Uuid> routerUuidList = networkData.get().getRouterIds();
2071             if (routerUuidList != null && !routerUuidList.isEmpty()) {
2072                 for (Uuid routerUuid : routerUuidList) {
2073                     String sharedRouterName = routerUuid.getValue();
2074                     if (!routerName.equals(sharedRouterName)) {
2075                         BigInteger switchDpnId = NatUtil.getPrimaryNaptfromRouterName(broker, sharedRouterName);
2076                         if (switchDpnId != null && switchDpnId.equals(dpnId)) {
2077                             LOG.debug("checkForRoutersWithSameExtNetAndNaptSwitch: external-network {} is "
2078                                     + "associated with other active router {} on NAPT switch {}", networkId,
2079                                     sharedRouterName, switchDpnId);
2080                             return true;
2081                         }
2082                     }
2083                 }
2084             }
2085         }
2086         return false;
2087     }
2088
2089     public static boolean checkForRoutersWithSameExtSubnetAndNaptSwitch(DataBroker broker, Uuid externalSubnetId,
2090                                                                         String routerName, BigInteger dpnId) {
2091         List<Uuid> routerUuidList = getOptionalExternalSubnets(broker, externalSubnetId).toJavaUtil()
2092             .map(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
2093                 .subnets.Subnets::getRouterIds).orElse(emptyList());
2094         if (!routerUuidList.isEmpty()) {
2095             for (Uuid routerUuid : routerUuidList) {
2096                 String sharedRouterName = routerUuid.getValue();
2097                 if (!routerName.equals(sharedRouterName)) {
2098                     BigInteger switchDpnId = NatUtil.getPrimaryNaptfromRouterName(broker, sharedRouterName);
2099                     if (switchDpnId != null && switchDpnId.equals(dpnId)) {
2100                         LOG.debug("checkForRoutersWithSameExtSubnetAndNaptSwitch: external-subnetwork {} is "
2101                                   + "associated with other active router {} on NAPT switch {}", externalSubnetId,
2102                             sharedRouterName, switchDpnId);
2103                         return true;
2104                     }
2105                 }
2106             }
2107         }
2108         return false;
2109     }
2110
2111     public static void installRouterGwFlows(ManagedNewTransactionRunner txRunner, IVpnManager vpnManager,
2112             Routers router, BigInteger primarySwitchId, int addOrRemove) {
2113         ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
2114             List<ExternalIps> externalIps = router.getExternalIps();
2115             List<String> externalIpsSting = new ArrayList<>();
2116
2117             if (externalIps == null || externalIps.isEmpty()) {
2118                 LOG.error("installRouterGwFlows: setupRouterGwFlows no externalIP present");
2119                 return;
2120             }
2121             for (ExternalIps externalIp : externalIps) {
2122                 externalIpsSting.add(externalIp.getIpAddress());
2123             }
2124             Uuid subnetVpnName = externalIps.get(0).getSubnetId();
2125             if (addOrRemove == NwConstants.ADD_FLOW) {
2126                 vpnManager.addRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
2127                         router.getNetworkId(), subnetVpnName.getValue(), tx);
2128                 vpnManager.addArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
2129                         router.getExtGwMacAddress(), primarySwitchId,
2130                         router.getNetworkId());
2131             } else {
2132                 vpnManager.removeRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
2133                         router.getNetworkId(), subnetVpnName.getValue(), tx);
2134                 vpnManager.removeArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
2135                         router.getExtGwMacAddress(), primarySwitchId,
2136                         router.getNetworkId());
2137             }
2138         }), LOG, "Error installing router gateway flows");
2139     }
2140
2141     @SuppressWarnings("checkstyle:IllegalCatch")
2142     public static void removeSNATFromDPN(DataBroker dataBroker, IMdsalApiManager mdsalManager,
2143             IdManagerService idManager, NaptSwitchHA naptSwitchHA, BigInteger dpnId,
2144             String routerName, long routerId, long routerVpnId,
2145             ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx)
2146                     throws ExecutionException, InterruptedException {
2147         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
2148         //remove miss entry to NAPT switch
2149         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
2150         if (extNwProvType == null) {
2151             return;
2152         }
2153         //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
2154         Map<String, Long> externalIpLabel;
2155         if (extNwProvType == ProviderTypes.VXLAN) {
2156             externalIpLabel = null;
2157         } else {
2158             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
2159         }
2160         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2161         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
2162             LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
2163             return;
2164         }
2165         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
2166         boolean naptStatus =
2167             naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
2168                     externalIpCache, confTx);
2169         if (!naptStatus) {
2170             LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
2171                 dpnId, routerName);
2172             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
2173             FlowEntity flowEntity = null;
2174             try {
2175                 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
2176                     NatConstants.DEL_FLOW);
2177                 if (flowEntity == null) {
2178                     LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
2179                             + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
2180                     return;
2181                 }
2182                 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
2183                 mdsalManager.removeFlow(confTx, flowEntity);
2184
2185             } catch (Exception ex) {
2186                 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
2187                     flowEntity, ex);
2188                 return;
2189             }
2190             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
2191                 dpnId, routerName);
2192
2193             //remove group
2194             GroupEntity groupEntity = null;
2195             try {
2196                 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
2197                     GroupTypes.GroupAll, emptyList() /*listBucketInfo*/);
2198                 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
2199                 mdsalManager.removeGroup(groupEntity);
2200             } catch (Exception ex) {
2201                 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
2202                 return;
2203             }
2204             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
2205                 dpnId, routerName);
2206         } else {
2207             naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
2208                     externalIpLabel, confTx);
2209             //remove table 26 flow ppointing to table46
2210             FlowEntity flowEntity = null;
2211             try {
2212                 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
2213                     NatConstants.DEL_FLOW);
2214                 if (flowEntity == null) {
2215                     LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
2216                             routerName, dpnId);
2217                     return;
2218                 }
2219                 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
2220                     + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
2221                 mdsalManager.removeFlow(confTx, flowEntity);
2222
2223             } catch (Exception ex) {
2224                 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
2225                     flowEntity, ex);
2226                 return;
2227             }
2228             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
2229                 dpnId, routerName);
2230
2231             //best effort to check IntExt model
2232             naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
2233         }
2234     }
2235
2236     public static Boolean isOpenStackVniSemanticsEnforcedForGreAndVxlan(IElanService elanManager,
2237                                                                         ProviderTypes extNwProvType) {
2238         if (elanManager.isOpenStackVniSemanticsEnforced() && (extNwProvType == ProviderTypes.GRE
2239                 || extNwProvType == ProviderTypes.VXLAN)) {
2240             return true;
2241         }
2242         return false;
2243     }
2244
2245     public static void addPseudoPortToElanDpn(String elanInstanceName, String pseudoPortId,
2246             BigInteger dpnId, DataBroker dataBroker) {
2247         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
2248                 elanInstanceName, dpnId);
2249         // FIXME: separate this out?
2250         final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
2251         lock.lock();
2252         try {
2253             Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2254                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
2255             List<String> elanInterfaceList;
2256             DpnInterfaces dpnInterface;
2257             if (!dpnInElanInterfaces.isPresent()) {
2258                 elanInterfaceList = new ArrayList<>();
2259             } else {
2260                 dpnInterface = dpnInElanInterfaces.get();
2261                 elanInterfaceList = dpnInterface.getInterfaces();
2262             }
2263             if (!elanInterfaceList.contains(pseudoPortId)) {
2264                 elanInterfaceList.add(pseudoPortId);
2265                 dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
2266                         .withKey(new DpnInterfacesKey(dpnId)).build();
2267                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
2268                     elanDpnInterfaceId, dpnInterface);
2269             }
2270         } catch (ReadFailedException e) {
2271             LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
2272         } catch (TransactionCommitFailedException e) {
2273             LOG.warn("Failed to add elanDpnInterface with error {}", e.getMessage());
2274         } finally {
2275             lock.unlock();
2276         }
2277     }
2278
2279     public static void removePseudoPortFromElanDpn(String elanInstanceName, String pseudoPortId,
2280             BigInteger dpnId, DataBroker dataBroker) {
2281         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
2282                 elanInstanceName, dpnId);
2283         // FIXME: separate this out?
2284         final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
2285         lock.lock();
2286         try {
2287             Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2288                     LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
2289             List<String> elanInterfaceList;
2290             DpnInterfaces dpnInterface;
2291             if (!dpnInElanInterfaces.isPresent()) {
2292                 LOG.info("No interface in any dpn for {}", elanInstanceName);
2293                 return;
2294             }
2295
2296             dpnInterface = dpnInElanInterfaces.get();
2297             elanInterfaceList = dpnInterface.getInterfaces();
2298             if (!elanInterfaceList.contains(pseudoPortId)) {
2299                 LOG.info("Router port not present in DPN {} for VPN {}", dpnId, elanInstanceName);
2300                 return;
2301             }
2302             elanInterfaceList.remove(pseudoPortId);
2303             dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
2304                     .withKey(new DpnInterfacesKey(dpnId)).build();
2305             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
2306                     elanDpnInterfaceId, dpnInterface);
2307         } catch (ReadFailedException e) {
2308             LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
2309         } catch (TransactionCommitFailedException e) {
2310             LOG.warn("Failed to remove elanDpnInterface with error {}", e.getMessage());
2311         } finally {
2312             lock.unlock();
2313         }
2314     }
2315
2316     public static boolean isLastExternalRouter(String networkid, String routerName, NatDataUtil natDataUtil) {
2317         Set<Map.Entry<String,Routers>> extRouter = natDataUtil.getAllRouters();
2318         for (Map.Entry<String,Routers> router : extRouter) {
2319             if (!router.getKey().equals(routerName) && router.getValue().getNetworkId().getValue()
2320                     .equals(networkid)) {
2321                 return false;
2322             }
2323         }
2324         return true;
2325     }
2326
2327     @Nullable
2328     public static LearntVpnVipToPortData getLearntVpnVipToPortData(DataBroker dataBroker) {
2329         try {
2330             return SingleTransactionDataBroker.syncRead(dataBroker,
2331                     LogicalDatastoreType.OPERATIONAL, getLearntVpnVipToPortDataId());
2332         }
2333         catch (ReadFailedException e) {
2334             LOG.warn("Failed to read LearntVpnVipToPortData with error {}", e.getMessage());
2335             return null;
2336         }
2337     }
2338
2339     public static InstanceIdentifier<LearntVpnVipToPortData> getLearntVpnVipToPortDataId() {
2340         InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = InstanceIdentifier
2341                 .builder(LearntVpnVipToPortData.class).build();
2342         return learntVpnVipToPortDataId;
2343     }
2344
2345     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
2346             BigInteger dpId) {
2347         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
2348                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
2349                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
2350     }
2351
2352     public static InstanceIdentifier<Group> getGroupInstanceId(BigInteger dpnId, long groupId) {
2353         return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
2354                 .inventory.rev130819.nodes.Node.class, new NodeKey(new NodeId("openflow:" + dpnId)))
2355                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
2356     }
2357
2358     public static void createGroupIdPool(IdManagerService idManager) {
2359         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
2360                 .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
2361                 .setLow(NatConstants.SNAT_ID_LOW_VALUE)
2362                 .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
2363                 .build();
2364         try {
2365             Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
2366             if (result != null && result.get().isSuccessful()) {
2367                 LOG.debug("createGroupIdPool : GroupIdPool created successfully");
2368             } else {
2369                 LOG.error("createGroupIdPool : Unable to create GroupIdPool");
2370             }
2371         } catch (InterruptedException | ExecutionException e) {
2372             LOG.error("createGroupIdPool : Failed to create PortPool for NAPT Service", e);
2373         }
2374     }
2375
2376     public static boolean getSwitchStatus(DataBroker broker, BigInteger switchId) {
2377         NodeId nodeId = new NodeId("openflow:" + switchId);
2378         LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
2379         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeInstanceId
2380             = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
2381                     .inventory.rev130819.nodes.Node.class, new NodeKey(nodeId)).build();
2382         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeOptional =
2383                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
2384                         LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
2385         if (nodeOptional.isPresent()) {
2386             LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
2387             return true;
2388         }
2389         LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
2390         return false;
2391     }
2392
2393     public static boolean isExternalNetwork(DataBroker broker, Uuid networkId) {
2394         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
2395         Optional<Networks> networkData =
2396                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
2397                         broker, LogicalDatastoreType.CONFIGURATION, id);
2398         return networkData.isPresent();
2399     }
2400
2401     @Nullable
2402     public static String getElanInstancePhysicalNetwok(String elanInstanceName, DataBroker broker) {
2403         ElanInstance elanInstance =  getElanInstanceByName(elanInstanceName, broker);
2404         if (null != elanInstance) {
2405             return elanInstance.getPhysicalNetworkName();
2406         }
2407         return null;
2408
2409     }
2410
2411     public static Map<String, String> getOpenvswitchOtherConfigMap(BigInteger dpnId, DataBroker dataBroker) {
2412         String otherConfigVal = getProviderMappings(dpnId, dataBroker);
2413         return getMultiValueMap(otherConfigVal);
2414     }
2415
2416     public static Map<String, String> getMultiValueMap(String multiKeyValueStr) {
2417         if (Strings.isNullOrEmpty(multiKeyValueStr)) {
2418             return Collections.emptyMap();
2419         }
2420
2421         Map<String, String> valueMap = new HashMap<>();
2422         Splitter splitter = Splitter.on(OTHER_CONFIG_PARAMETERS_DELIMITER);
2423         for (String keyValue : splitter.split(multiKeyValueStr)) {
2424             String[] split = keyValue.split(OTHER_CONFIG_KEY_VALUE_DELIMITER, 2);
2425             if (split.length == 2) {
2426                 valueMap.put(split[0], split[1]);
2427             }
2428         }
2429
2430         return valueMap;
2431     }
2432
2433     public static Optional<Node> getBridgeRefInfo(BigInteger dpnId, DataBroker dataBroker) {
2434         InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.create(BridgeRefInfo.class)
2435                 .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
2436
2437         Optional<BridgeRefEntry> bridgeRefEntry =
2438                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2439                         LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
2440         if (!bridgeRefEntry.isPresent()) {
2441             LOG.info("getBridgeRefInfo : bridgeRefEntry is not present for {}", dpnId);
2442             return Optional.absent();
2443         }
2444
2445         InstanceIdentifier<Node> nodeId =
2446                 bridgeRefEntry.get().getBridgeReference().getValue().firstIdentifierOf(Node.class);
2447
2448         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2449                 LogicalDatastoreType.OPERATIONAL, nodeId);
2450     }
2451
2452     @Nullable
2453     public static String getProviderMappings(BigInteger dpId, DataBroker dataBroker) {
2454         return getBridgeRefInfo(dpId, dataBroker).toJavaUtil().map(node -> getOpenvswitchOtherConfigs(node,
2455                 PROVIDER_MAPPINGS, dataBroker)).orElse(null);
2456     }
2457
2458     @Nullable
2459     public static String getOpenvswitchOtherConfigs(Node node, String key, DataBroker dataBroker) {
2460         OvsdbNodeAugmentation ovsdbNode = node.augmentation(OvsdbNodeAugmentation.class);
2461         if (ovsdbNode == null) {
2462             Optional<Node> nodeFromReadOvsdbNode = readOvsdbNode(node, dataBroker);
2463             if (nodeFromReadOvsdbNode.isPresent()) {
2464                 ovsdbNode = nodeFromReadOvsdbNode.get().augmentation(OvsdbNodeAugmentation.class);
2465             }
2466         }
2467
2468         if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) {
2469             for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) {
2470                 if (Objects.equals(openvswitchOtherConfigs.getOtherConfigKey(), key)) {
2471                     return openvswitchOtherConfigs.getOtherConfigValue();
2472                 }
2473             }
2474         }
2475         LOG.info("getOpenvswitchOtherConfigs : OtherConfigs is not present for ovsdbNode {}", node.getNodeId());
2476         return null;
2477     }
2478
2479     @NonNull
2480     public static Optional<Node> readOvsdbNode(Node bridgeNode, DataBroker dataBroker) {
2481         OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
2482         if (bridgeAugmentation != null) {
2483             InstanceIdentifier<Node> ovsdbNodeIid =
2484                     (InstanceIdentifier<Node>) bridgeAugmentation.getManagedBy().getValue();
2485             return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2486                     LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid);
2487         }
2488         return Optional.absent();
2489
2490     }
2491
2492     @Nullable
2493     public static OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) {
2494         if (node == null) {
2495             return null;
2496         }
2497         return node.augmentation(OvsdbBridgeAugmentation.class);
2498     }
2499
2500     public static String getDefaultFibRouteToSNATForSubnetJobKey(String subnetName, BigInteger dpnId) {
2501         return NatConstants.NAT_DJC_PREFIX + subnetName + dpnId;
2502     }
2503
2504     public static ExternalSubnets getExternalSubnets(DataBroker dataBroker) {
2505         InstanceIdentifier<ExternalSubnets> subnetsIdentifier =
2506                 InstanceIdentifier.builder(ExternalSubnets.class)
2507                 .build();
2508         try {
2509             Optional<ExternalSubnets> optionalExternalSubnets  = SingleTransactionDataBroker
2510                     .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
2511             if (optionalExternalSubnets.isPresent()) {
2512                 return optionalExternalSubnets.get();
2513             }
2514         } catch (ReadFailedException e) {
2515             LOG.error("Failed to read the subnets from the datastore.");
2516         }
2517         return null;
2518
2519     }
2520
2521     public static void addFlow(TypedWriteTransaction<Configuration> confTx, IMdsalApiManager mdsalManager,
2522             BigInteger dpId, short tableId, String flowId, int priority, String flowName, BigInteger cookie,
2523             List<? extends MatchInfoBase> matches, List<InstructionInfo> instructions) {
2524         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
2525                 NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
2526                 instructions);
2527         LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
2528         mdsalManager.addFlow(confTx, flowEntity);
2529     }
2530
2531     public static void removeFlow(TypedReadWriteTransaction<Configuration> confTx, IMdsalApiManager mdsalManager,
2532             BigInteger dpId, short tableId, String flowId) throws ExecutionException, InterruptedException {
2533         LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
2534         mdsalManager.removeFlow(confTx, dpId, flowId, tableId);
2535     }
2536
2537     public static String getIpv6FlowRef(BigInteger dpnId, short tableId, long routerID) {
2538         return new StringBuilder().append(NatConstants.IPV6_FLOWID_PREFIX).append(dpnId).append(NatConstants
2539                 .FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
2540     }
2541
2542     public static String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId,
2543                                                 ItmRpcService itmManager) {
2544         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
2545         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
2546         try {
2547             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager
2548                     .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
2549                             .setDestinationDpid(dstDpId).setTunnelType(tunType).build());
2550             rpcResult = result.get();
2551             if (!rpcResult.isSuccessful()) {
2552                 tunType = TunnelTypeGre.class ;
2553                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
2554                         .setSourceDpid(srcDpId)
2555                         .setDestinationDpid(dstDpId)
2556                         .setTunnelType(tunType)
2557                         .build());
2558                 rpcResult = result.get();
2559                 if (!rpcResult.isSuccessful()) {
2560                     LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
2561                             rpcResult.getErrors());
2562                 } else {
2563                     return rpcResult.getResult().getInterfaceName();
2564                 }
2565                 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
2566                         rpcResult.getErrors());
2567             } else {
2568                 return rpcResult.getResult().getInterfaceName();
2569             }
2570         } catch (InterruptedException | ExecutionException | NullPointerException e) {
2571             LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
2572                     + "between {} and {}", srcDpId, dstDpId);
2573         }
2574         return null;
2575     }
2576
2577     static ReentrantLock lockForNat(final BigInteger dataPath) {
2578         // FIXME: wrap this in an Identifier
2579         return JvmGlobalLocks.getLockForString(NatConstants.NAT_DJC_PREFIX + dataPath);
2580     }
2581
2582     public static void removeSnatEntriesForPort(DataBroker dataBroker, NaptManager naptManager,
2583         IMdsalApiManager mdsalManager, NeutronvpnService neutronVpnService,
2584         String interfaceName, String routerName) {
2585         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
2586         if (routerId == NatConstants.INVALID_ID) {
2587             LOG.error("removeSnatEntriesForPort: routerId not found for routername {}", routerName);
2588             return;
2589         }
2590         BigInteger naptSwitch = getPrimaryNaptfromRouterName(dataBroker, routerName);
2591         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
2592             LOG.error("removeSnatEntriesForPort: NaptSwitch is not elected for router {}"
2593                 + "with Id {}", routerName, routerId);
2594             return;
2595         }
2596         //getInternalIp for port
2597         List<String> fixedIps = getFixedIpsForPort(neutronVpnService, interfaceName);
2598         if (fixedIps == null) {
2599             LOG.error("removeSnatEntriesForPort: Internal Ips not found for InterfaceName {} in router {} with id {}",
2600                 interfaceName, routerName, routerId);
2601             return;
2602         }
2603         List<ProtocolTypes> protocolTypesList = getPortocolList();
2604         for (String internalIp : fixedIps) {
2605             LOG.debug("removeSnatEntriesForPort: Internal Ip retrieved for interface {} is {} in router with Id {}",
2606                 interfaceName, internalIp, routerId);
2607             for (ProtocolTypes protocol : protocolTypesList) {
2608                 List<Integer> portList = NatUtil.getInternalIpPortListInfo(dataBroker, routerId, internalIp, protocol);
2609                 if (portList != null) {
2610                     for (Integer portnum : portList) {
2611                         //build and remove the flow in outbound table
2612                         removeNatFlow(mdsalManager, naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
2613                             routerId, internalIp, portnum, protocol.getName());
2614
2615                         //build and remove the flow in inboundtable
2616
2617                         removeNatFlow(mdsalManager, naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId,
2618                             internalIp, portnum, protocol.getName());
2619
2620                         //Get the external IP address and the port from the model
2621
2622                         NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString())
2623                             ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
2624                         IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
2625                             internalIp, String.valueOf(portnum), proto);
2626                         if (ipPortExternal == null) {
2627                             LOG.error("removeSnatEntriesForPort: Mapping for internalIp {} "
2628                                 + "with port {} is not found in "
2629                                 + "router with Id {}", internalIp, portnum, routerId);
2630                             return;
2631                         }
2632                         String externalIpAddress = ipPortExternal.getIpAddress();
2633                         String internalIpPort = internalIp + ":" + portnum;
2634                         // delete the entry from IntExtIpPortMap DS
2635
2636                         naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
2637                         naptManager.removePortFromPool(internalIpPort, externalIpAddress);
2638
2639                     }
2640                 } else {
2641                     LOG.debug("removeSnatEntriesForPort: No {} session for interface {} with internalIP {} "
2642                             + "in router with id {}",
2643                         protocol, interfaceName, internalIp, routerId);
2644                 }
2645             }
2646             // delete the entry from SnatIntIpPortMap DS
2647             LOG.debug("removeSnatEntriesForPort: Removing InternalIp :{} of router {} from snatint-ip-port-map",
2648                 internalIp, routerId);
2649             naptManager.removeFromSnatIpPortDS(routerId, internalIp);
2650         }
2651     }
2652
2653     private static List<String> getFixedIpsForPort(NeutronvpnService neutronVpnService, String interfname) {
2654         LOG.debug("getFixedIpsForPort: getFixedIpsForPort method is called for interface {}", interfname);
2655         try {
2656             Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
2657                 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
2658                     .setPortId(new Uuid(interfname)).build());
2659
2660             RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
2661             if (!rpcResult.isSuccessful()) {
2662                 LOG.error("getFixedIpsForPort: RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}",
2663                     rpcResult.getErrors());
2664             } else {
2665                 return rpcResult.getResult().getFixedIPs();
2666             }
2667         } catch (InterruptedException | ExecutionException | NullPointerException ex) {
2668             LOG.error("getFixedIpsForPort: Exception while receiving fixedIps for port {}", interfname, ex);
2669         }
2670         return null;
2671     }
2672
2673     private static List<ProtocolTypes> getPortocolList() {
2674         List<ProtocolTypes> protocollist = new ArrayList<>();
2675         protocollist.add(ProtocolTypes.TCP);
2676         protocollist.add(ProtocolTypes.UDP);
2677         return protocollist;
2678     }
2679
2680     private static void removeNatFlow(IMdsalApiManager mdsalManager, BigInteger dpnId, short tableId, Long routerId,
2681         String ipAddress, int ipPort, String protocol) {
2682
2683         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort,
2684             protocol);
2685         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
2686
2687         mdsalManager.removeFlow(snatFlowEntity);
2688         LOG.debug("removeNatFlow: Removed the flow in table {} for the switch with the DPN ID {} for "
2689             + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort);
2690     }
2691
2692     public static String getDpnFromNodeRef(NodeRef node) {
2693         PathArgument pathArgument = Iterables.get(node.getValue().getPathArguments(), 1);
2694         InstanceIdentifier.IdentifiableItem<?, ?> item = Arguments.checkInstanceOf(pathArgument,
2695             InstanceIdentifier.IdentifiableItem.class);
2696         NodeKey key = Arguments.checkInstanceOf(item.getKey(), NodeKey.class);
2697         String dpnKey = key.getId().getValue();
2698         String dpnID = null;
2699         if (dpnKey.contains(NatConstants.COLON_SEPARATOR)) {
2700             dpnID = new BigInteger(dpnKey.split(NatConstants.COLON_SEPARATOR)[1]).toString();
2701         }
2702         return dpnID;
2703     }
2704 }