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