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