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