Migrate NAT to genius/vniutils
[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, NatOverVxlanUtil natOverVxlanUtil,
1948                                                        IElanService elanManager, IdManagerService idManager,
1949                                                        long routerId, String routerName) {
1950         if (elanManager.isOpenStackVniSemanticsEnforced()) {
1951             // Router VNI will be set as tun_id if OpenStackSemantics is enabled
1952             return natOverVxlanUtil.getRouterVni(routerName, routerId).longValue();
1953         } else {
1954             return NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
1955         }
1956     }
1957
1958     public static void makePreDnatToSnatTableEntry(IMdsalApiManager mdsalManager, BigInteger naptDpnId,
1959             short tableId, TypedWriteTransaction<Configuration> confTx) {
1960         LOG.debug("makePreDnatToSnatTableEntry : Create Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
1961                 NwConstants.PDNAT_TABLE, tableId, naptDpnId);
1962
1963         List<Instruction> preDnatToSnatInstructions = new ArrayList<>();
1964         preDnatToSnatInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
1965         List<MatchInfo> matches = new ArrayList<>();
1966         matches.add(MatchEthernetType.IPV4);
1967         String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
1968         Flow preDnatToSnatTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.PDNAT_TABLE,flowRef,
1969                 5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE,
1970                 matches, preDnatToSnatInstructions);
1971
1972         mdsalManager.addFlow(confTx, naptDpnId, preDnatToSnatTableFlowEntity);
1973         LOG.debug("makePreDnatToSnatTableEntry : Successfully installed Pre-DNAT flow {} on NAPT DpnId {} ",
1974                 preDnatToSnatTableFlowEntity,  naptDpnId);
1975     }
1976
1977     public static void removePreDnatToSnatTableEntry(TypedReadWriteTransaction<Configuration> confTx,
1978             IMdsalApiManager mdsalManager, BigInteger naptDpnId) throws ExecutionException, InterruptedException {
1979         LOG.debug("removePreDnatToSnatTableEntry : Remove Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
1980                 NwConstants.PDNAT_TABLE, NwConstants.INBOUND_NAPT_TABLE, naptDpnId);
1981         String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
1982         mdsalManager.removeFlow(confTx, naptDpnId, flowRef, NwConstants.PDNAT_TABLE);
1983         LOG.debug("removePreDnatToSnatTableEntry: Successfully removed Pre-DNAT flow {} on NAPT DpnId = {}",
1984                 flowRef, naptDpnId);
1985     }
1986
1987     private static String getFlowRefPreDnatToSnat(BigInteger dpnId, short tableId, String uniqueId) {
1988         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
1989                 + NwConstants.FLOWID_SEPARATOR + uniqueId;
1990     }
1991
1992     public static boolean isFloatingIpPresentForDpn(DataBroker dataBroker, BigInteger dpnId, String rd,
1993                                                     String vpnName, String externalIp,
1994                                                     Boolean isMoreThanOneFipCheckOnDpn) {
1995         InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
1996         Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1997         if (dpnInVpn.isPresent()) {
1998             LOG.debug("isFloatingIpPresentForDpn : vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, "
1999                     + "rd {} and floatingIp {}", vpnName, dpnId, rd, externalIp);
2000             try {
2001                 List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
2002                 if (ipAddressList != null && !ipAddressList.isEmpty()) {
2003                     int floatingIpPresentCount = 0;
2004                     for (IpAddresses ipAddress: ipAddressList) {
2005                         if (!Objects.equals(ipAddress.getIpAddress(), externalIp)
2006                                 && IpAddresses.IpAddressSource.FloatingIP.equals(ipAddress.getIpAddressSource())) {
2007                             floatingIpPresentCount++;
2008                             //Add tunnel table check
2009                             if (isMoreThanOneFipCheckOnDpn && floatingIpPresentCount > 1) {
2010                                 return true;
2011                             }
2012                             //Remove tunnel table check
2013                             if (!isMoreThanOneFipCheckOnDpn) {
2014                                 return true;
2015                             }
2016                         }
2017                     }
2018                 } else {
2019                     LOG.debug("isFloatingIpPresentForDpn : vpn-to-dpn-list does not contain any floating IP for DPN {}",
2020                            dpnId);
2021                     return false;
2022                 }
2023             } catch (NullPointerException e) {
2024                 LOG.error("isFloatingIpPresentForDpn: Exception occurred on getting external IP address from "
2025                         + "vpn-to-dpn-list on Dpn {}", dpnId, e);
2026                 return false;
2027             }
2028         }
2029         return false;
2030     }
2031
2032     private static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
2033         return InstanceIdentifier.builder(VpnInstanceOpData.class)
2034                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
2035                 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
2036     }
2037
2038     @Nullable
2039     public static String getPrimaryRd(String vpnName, TypedReadTransaction<Configuration> tx)
2040         throws ExecutionException, InterruptedException {
2041         return tx.read(getVpnInstanceIdentifier(vpnName)).get().toJavaUtil().map(NatUtil::getPrimaryRd).orElse(null);
2042     }
2043
2044     public static String getPrimaryRd(DataBroker dataBroker, String vpnName) {
2045         InstanceIdentifier<VpnInstance> id  = getVpnInstanceIdentifier(vpnName);
2046         Optional<VpnInstance> vpnInstance =
2047                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2048                         LogicalDatastoreType.CONFIGURATION, id);
2049         if (vpnInstance.isPresent()) {
2050             return getPrimaryRd(vpnInstance.get());
2051         }
2052         return vpnName;
2053     }
2054
2055     @Nullable
2056     public static String getPrimaryRd(@Nullable VpnInstance vpnInstance) {
2057         if (vpnInstance == null) {
2058             return null;
2059         }
2060         List<String> rds = getListOfRdsFromVpnInstance(vpnInstance);
2061         return rds.isEmpty() ? vpnInstance.getVpnInstanceName() : rds.get(0);
2062     }
2063
2064     public static InstanceIdentifier<VpnInstance> getVpnInstanceIdentifier(String vpnName) {
2065         return InstanceIdentifier.builder(VpnInstances.class)
2066             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
2067     }
2068
2069     @Nonnull
2070     public static List<String> getListOfRdsFromVpnInstance(VpnInstance vpnInstance) {
2071         VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
2072         return vpnConfig.getRouteDistinguisher() != null ? new ArrayList<>(
2073                 vpnConfig.getRouteDistinguisher()) : new ArrayList<>();
2074     }
2075
2076     public static long getVpnIdFromExternalSubnet(DataBroker dataBroker, String routerName, String externalIpAddress) {
2077         if (routerName != null) {
2078             Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
2079             if (extRouter != null) {
2080                 return getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIpAddress, extRouter);
2081             }
2082         }
2083
2084         return NatConstants.INVALID_ID;
2085     }
2086
2087     public static String validateAndAddNetworkMask(String ipAddress) {
2088         return ipAddress.contains("/32") ? ipAddress : ipAddress + "/32";
2089     }
2090
2091     public static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
2092             String vpnInterfaceName, String vpnName) {
2093         return InstanceIdentifier.builder(VpnInterfaceOpData.class).child(VpnInterfaceOpDataEntry.class,
2094         new VpnInterfaceOpDataEntryKey(vpnInterfaceName, vpnName)).build();
2095     }
2096
2097     @Nullable
2098     public static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
2099         InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(rd);
2100         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
2101                  broker, LogicalDatastoreType.OPERATIONAL, id).orNull();
2102     }
2103
2104     public static boolean checkForRoutersWithSameExtNetAndNaptSwitch(DataBroker broker, Uuid networkId,
2105                                                                      String routerName, BigInteger dpnId) {
2106         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
2107         Optional<Networks> networkData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
2108
2109         if (networkData != null && networkData.isPresent()) {
2110             List<Uuid> routerUuidList = networkData.get().getRouterIds();
2111             if (routerUuidList != null && !routerUuidList.isEmpty()) {
2112                 for (Uuid routerUuid : routerUuidList) {
2113                     String sharedRouterName = routerUuid.getValue();
2114                     if (!routerName.equals(sharedRouterName)) {
2115                         BigInteger switchDpnId = NatUtil.getPrimaryNaptfromRouterName(broker, sharedRouterName);
2116                         if (switchDpnId != null && switchDpnId.equals(dpnId)) {
2117                             LOG.debug("checkForRoutersWithSameExtNetAndNaptSwitch: external-network {} is "
2118                                     + "associated with other active router {} on NAPT switch {}", networkId,
2119                                     sharedRouterName, switchDpnId);
2120                             return true;
2121                         }
2122                     }
2123                 }
2124             }
2125         }
2126         return false;
2127     }
2128
2129     public static boolean checkForRoutersWithSameExtSubnetAndNaptSwitch(DataBroker broker, Uuid externalSubnetId,
2130                                                                         String routerName, BigInteger dpnId) {
2131         List<Uuid> routerUuidList = getOptionalExternalSubnets(broker, externalSubnetId).toJavaUtil()
2132             .map(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
2133                 .subnets.Subnets::getRouterIds).orElse(emptyList());
2134         if (!routerUuidList.isEmpty()) {
2135             for (Uuid routerUuid : routerUuidList) {
2136                 String sharedRouterName = routerUuid.getValue();
2137                 if (!routerName.equals(sharedRouterName)) {
2138                     BigInteger switchDpnId = NatUtil.getPrimaryNaptfromRouterName(broker, sharedRouterName);
2139                     if (switchDpnId != null && switchDpnId.equals(dpnId)) {
2140                         LOG.debug("checkForRoutersWithSameExtSubnetAndNaptSwitch: external-subnetwork {} is "
2141                                   + "associated with other active router {} on NAPT switch {}", externalSubnetId,
2142                             sharedRouterName, switchDpnId);
2143                         return true;
2144                     }
2145                 }
2146             }
2147         }
2148         return false;
2149     }
2150
2151     public static void installRouterGwFlows(ManagedNewTransactionRunner txRunner, IVpnManager vpnManager,
2152             Routers router, BigInteger primarySwitchId, int addOrRemove) {
2153         ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
2154             List<ExternalIps> externalIps = router.getExternalIps();
2155             List<String> externalIpsSting = new ArrayList<>();
2156
2157             if (externalIps == null || externalIps.isEmpty()) {
2158                 LOG.error("installRouterGwFlows: setupRouterGwFlows no externalIP present");
2159                 return;
2160             }
2161             for (ExternalIps externalIp : externalIps) {
2162                 externalIpsSting.add(externalIp.getIpAddress());
2163             }
2164             Uuid subnetVpnName = externalIps.get(0).getSubnetId();
2165             if (addOrRemove == NwConstants.ADD_FLOW) {
2166                 vpnManager.addRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
2167                         router.getNetworkId(), subnetVpnName.getValue(), tx);
2168                 vpnManager.addArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
2169                         router.getExtGwMacAddress(), primarySwitchId,
2170                         router.getNetworkId());
2171             } else {
2172                 vpnManager.removeRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
2173                         router.getNetworkId(), subnetVpnName.getValue(), tx);
2174                 vpnManager.removeArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
2175                         router.getExtGwMacAddress(), primarySwitchId,
2176                         router.getNetworkId());
2177             }
2178         }), LOG, "Error installing router gateway flows");
2179     }
2180
2181     @SuppressWarnings("checkstyle:IllegalCatch")
2182     public static void removeSNATFromDPN(DataBroker dataBroker, IMdsalApiManager mdsalManager,
2183             IdManagerService idManager, NaptSwitchHA naptSwitchHA, BigInteger dpnId,
2184             String routerName, long routerId, long routerVpnId,
2185             ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx)
2186                     throws ExecutionException, InterruptedException {
2187         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
2188         //remove miss entry to NAPT switch
2189         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
2190         if (extNwProvType == null) {
2191             return;
2192         }
2193         //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
2194         Map<String, Long> externalIpLabel;
2195         if (extNwProvType == ProviderTypes.VXLAN) {
2196             externalIpLabel = null;
2197         } else {
2198             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
2199         }
2200         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2201         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
2202             LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
2203             return;
2204         }
2205         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
2206         boolean naptStatus =
2207             naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
2208                     externalIpCache, confTx);
2209         if (!naptStatus) {
2210             LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
2211                 dpnId, routerName);
2212             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
2213             FlowEntity flowEntity = null;
2214             try {
2215                 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
2216                     NatConstants.DEL_FLOW);
2217                 if (flowEntity == null) {
2218                     LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
2219                             + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
2220                     return;
2221                 }
2222                 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
2223                 mdsalManager.removeFlow(confTx, flowEntity);
2224
2225             } catch (Exception ex) {
2226                 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
2227                     flowEntity, ex);
2228                 return;
2229             }
2230             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
2231                 dpnId, routerName);
2232
2233             //remove group
2234             GroupEntity groupEntity = null;
2235             try {
2236                 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
2237                     GroupTypes.GroupAll, emptyList() /*listBucketInfo*/);
2238                 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
2239                 mdsalManager.removeGroup(groupEntity);
2240             } catch (Exception ex) {
2241                 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
2242                 return;
2243             }
2244             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
2245                 dpnId, routerName);
2246         } else {
2247             naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
2248                     externalIpLabel, confTx);
2249             //remove table 26 flow ppointing to table46
2250             FlowEntity flowEntity = null;
2251             try {
2252                 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
2253                     NatConstants.DEL_FLOW);
2254                 if (flowEntity == null) {
2255                     LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
2256                             routerName, dpnId);
2257                     return;
2258                 }
2259                 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
2260                     + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
2261                 mdsalManager.removeFlow(confTx, flowEntity);
2262
2263             } catch (Exception ex) {
2264                 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
2265                     flowEntity, ex);
2266                 return;
2267             }
2268             LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
2269                 dpnId, routerName);
2270
2271             //best effort to check IntExt model
2272             naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
2273         }
2274     }
2275
2276     public static Boolean isOpenStackVniSemanticsEnforcedForGreAndVxlan(IElanService elanManager,
2277                                                                         ProviderTypes extNwProvType) {
2278         if (elanManager.isOpenStackVniSemanticsEnforced() && (extNwProvType == ProviderTypes.GRE
2279                 || extNwProvType == ProviderTypes.VXLAN)) {
2280             return true;
2281         }
2282         return false;
2283     }
2284
2285     public static void addPseudoPortToElanDpn(String elanInstanceName, String pseudoPortId,
2286             BigInteger dpnId, DataBroker dataBroker) {
2287         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
2288                 elanInstanceName,dpnId);
2289         try {
2290             synchronized (elanInstanceName.intern()) {
2291                 Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2292                         LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
2293                 List<String> elanInterfaceList;
2294                 DpnInterfaces dpnInterface;
2295                 if (!dpnInElanInterfaces.isPresent()) {
2296                     elanInterfaceList = new ArrayList<>();
2297                 } else {
2298                     dpnInterface = dpnInElanInterfaces.get();
2299                     elanInterfaceList = dpnInterface.getInterfaces();
2300                 }
2301                 if (!elanInterfaceList.contains(pseudoPortId)) {
2302                     elanInterfaceList.add(pseudoPortId);
2303                     dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
2304                             .withKey(new DpnInterfacesKey(dpnId)).build();
2305                     SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
2306                             elanDpnInterfaceId, dpnInterface);
2307                 }
2308             }
2309         } catch (ReadFailedException e) {
2310             LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
2311         } catch (TransactionCommitFailedException e) {
2312             LOG.warn("Failed to add elanDpnInterface with error {}", e.getMessage());
2313         }
2314     }
2315
2316     public static void removePseudoPortFromElanDpn(String elanInstanceName, String pseudoPortId,
2317             BigInteger dpnId, DataBroker dataBroker) {
2318         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
2319                 elanInstanceName,dpnId);
2320         try {
2321             synchronized (elanInstanceName.intern()) {
2322                 Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2323                         LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
2324                 List<String> elanInterfaceList;
2325                 DpnInterfaces dpnInterface;
2326                 if (!dpnInElanInterfaces.isPresent()) {
2327                     LOG.info("No interface in any dpn for {}", elanInstanceName);
2328                     return;
2329                 } else {
2330                     dpnInterface = dpnInElanInterfaces.get();
2331                     elanInterfaceList = dpnInterface.getInterfaces();
2332                 }
2333                 if (!elanInterfaceList.contains(pseudoPortId)) {
2334                     LOG.info("Router port not present in DPN {} for VPN {}", dpnId, elanInstanceName);
2335                     return;
2336                 }
2337                 elanInterfaceList.remove(pseudoPortId);
2338                 dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
2339                         .withKey(new DpnInterfacesKey(dpnId)).build();
2340                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
2341                         elanDpnInterfaceId, dpnInterface);
2342             }
2343         } catch (ReadFailedException e) {
2344             LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
2345         } catch (TransactionCommitFailedException e) {
2346             LOG.warn("Failed to remove elanDpnInterface with error {}", e.getMessage());
2347         }
2348
2349     }
2350
2351     public static DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId,
2352             DataBroker broker) {
2353         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId =
2354                 getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
2355         DpnInterfaces dpnInterfaces = null;
2356         try {
2357             dpnInterfaces = SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.OPERATIONAL,
2358                     elanDpnInterfacesId);
2359         }
2360         catch (ReadFailedException e) {
2361             LOG.warn("Failed to read ElanDpnInterfacesList with error {}", e.getMessage());
2362         }
2363         return dpnInterfaces;
2364     }
2365
2366     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
2367             InstanceIdentifier<T> path) {
2368         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
2369             return tx.read(datastoreType, path).get();
2370         } catch (InterruptedException | ExecutionException e) {
2371             throw new RuntimeException(e);
2372         }
2373     }
2374
2375     public static boolean isLastExternalRouter(String networkid, String routerName, NatDataUtil natDataUtil) {
2376         Set<Map.Entry<String,Routers>> extRouter = natDataUtil.getAllRouters();
2377         for (Map.Entry<String,Routers> router : extRouter) {
2378             if (!router.getKey().equals(routerName) && router.getValue().getNetworkId().getValue()
2379                     .equals(networkid)) {
2380                 return false;
2381             }
2382         }
2383         return true;
2384     }
2385
2386     public static InstanceIdentifier<ExtRouters> buildExtRouters() {
2387         InstanceIdentifier<ExtRouters> extRouterInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class)
2388                 .build();
2389         return extRouterInstanceIndentifier;
2390     }
2391
2392     @Nullable
2393     public static LearntVpnVipToPortData getLearntVpnVipToPortData(DataBroker dataBroker) {
2394         try {
2395             return SingleTransactionDataBroker.syncRead(dataBroker,
2396                     LogicalDatastoreType.OPERATIONAL, getLearntVpnVipToPortDataId());
2397         }
2398         catch (ReadFailedException e) {
2399             LOG.warn("Failed to read LearntVpnVipToPortData with error {}", e.getMessage());
2400             return null;
2401         }
2402     }
2403
2404     public static InstanceIdentifier<LearntVpnVipToPortData> getLearntVpnVipToPortDataId() {
2405         InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = InstanceIdentifier
2406                 .builder(LearntVpnVipToPortData.class).build();
2407         return learntVpnVipToPortDataId;
2408     }
2409
2410     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
2411             BigInteger dpId) {
2412         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
2413                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
2414                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
2415     }
2416
2417     public static InstanceIdentifier<Group> getGroupInstanceId(BigInteger dpnId, long groupId) {
2418         return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
2419                 .inventory.rev130819.nodes.Node.class, new NodeKey(new NodeId("openflow:" + dpnId)))
2420                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
2421     }
2422
2423     public static void createGroupIdPool(IdManagerService idManager) {
2424         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
2425                 .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
2426                 .setLow(NatConstants.SNAT_ID_LOW_VALUE)
2427                 .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
2428                 .build();
2429         try {
2430             Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
2431             if (result != null && result.get().isSuccessful()) {
2432                 LOG.debug("createGroupIdPool : GroupIdPool created successfully");
2433             } else {
2434                 LOG.error("createGroupIdPool : Unable to create GroupIdPool");
2435             }
2436         } catch (InterruptedException | ExecutionException e) {
2437             LOG.error("createGroupIdPool : Failed to create PortPool for NAPT Service", e);
2438         }
2439     }
2440
2441     public static boolean getSwitchStatus(DataBroker broker, BigInteger switchId) {
2442         NodeId nodeId = new NodeId("openflow:" + switchId);
2443         LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
2444         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeInstanceId
2445             = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
2446                     .inventory.rev130819.nodes.Node.class, new NodeKey(nodeId)).build();
2447         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeOptional =
2448                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
2449                         LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
2450         if (nodeOptional.isPresent()) {
2451             LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
2452             return true;
2453         }
2454         LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
2455         return false;
2456     }
2457
2458     public static boolean isExternalNetwork(DataBroker broker, Uuid networkId) {
2459         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
2460         Optional<Networks> networkData =
2461                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
2462                         broker, LogicalDatastoreType.CONFIGURATION, id);
2463         return networkData.isPresent();
2464     }
2465
2466     @Nullable
2467     public static String getElanInstancePhysicalNetwok(String elanInstanceName, DataBroker broker) {
2468         ElanInstance elanInstance =  getElanInstanceByName(elanInstanceName, broker);
2469         if (null != elanInstance) {
2470             return elanInstance.getPhysicalNetworkName();
2471         }
2472         return null;
2473
2474     }
2475
2476     public static Map<String, String> getOpenvswitchOtherConfigMap(BigInteger dpnId, DataBroker dataBroker) {
2477         String otherConfigVal = getProviderMappings(dpnId, dataBroker);
2478         return getMultiValueMap(otherConfigVal);
2479     }
2480
2481     public static Map<String, String> getMultiValueMap(String multiKeyValueStr) {
2482         if (Strings.isNullOrEmpty(multiKeyValueStr)) {
2483             return Collections.emptyMap();
2484         }
2485
2486         Map<String, String> valueMap = new HashMap<>();
2487         Splitter splitter = Splitter.on(OTHER_CONFIG_PARAMETERS_DELIMITER);
2488         for (String keyValue : splitter.split(multiKeyValueStr)) {
2489             String[] split = keyValue.split(OTHER_CONFIG_KEY_VALUE_DELIMITER, 2);
2490             if (split.length == 2) {
2491                 valueMap.put(split[0], split[1]);
2492             }
2493         }
2494
2495         return valueMap;
2496     }
2497
2498     public static Optional<Node> getBridgeRefInfo(BigInteger dpnId, DataBroker dataBroker) {
2499         InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.create(BridgeRefInfo.class)
2500                 .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
2501
2502         Optional<BridgeRefEntry> bridgeRefEntry =
2503                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2504                         LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
2505         if (!bridgeRefEntry.isPresent()) {
2506             LOG.info("getBridgeRefInfo : bridgeRefEntry is not present for {}", dpnId);
2507             return Optional.absent();
2508         }
2509
2510         InstanceIdentifier<Node> nodeId =
2511                 bridgeRefEntry.get().getBridgeReference().getValue().firstIdentifierOf(Node.class);
2512
2513         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2514                 LogicalDatastoreType.OPERATIONAL, nodeId);
2515     }
2516
2517     @Nullable
2518     public static String getProviderMappings(BigInteger dpId, DataBroker dataBroker) {
2519         return getBridgeRefInfo(dpId, dataBroker).toJavaUtil().map(node -> getOpenvswitchOtherConfigs(node,
2520                 PROVIDER_MAPPINGS, dataBroker)).orElse(null);
2521     }
2522
2523     @Nullable
2524     public static String getOpenvswitchOtherConfigs(Node node, String key, DataBroker dataBroker) {
2525         OvsdbNodeAugmentation ovsdbNode = node.augmentation(OvsdbNodeAugmentation.class);
2526         if (ovsdbNode == null) {
2527             Optional<Node> nodeFromReadOvsdbNode = readOvsdbNode(node, dataBroker);
2528             if (nodeFromReadOvsdbNode.isPresent()) {
2529                 ovsdbNode = nodeFromReadOvsdbNode.get().augmentation(OvsdbNodeAugmentation.class);
2530             }
2531         }
2532
2533         if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) {
2534             for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) {
2535                 if (Objects.equals(openvswitchOtherConfigs.getOtherConfigKey(), key)) {
2536                     return openvswitchOtherConfigs.getOtherConfigValue();
2537                 }
2538             }
2539         }
2540         LOG.info("getOpenvswitchOtherConfigs : OtherConfigs is not present for ovsdbNode {}", node.getNodeId());
2541         return null;
2542     }
2543
2544     @Nonnull
2545     public static Optional<Node> readOvsdbNode(Node bridgeNode, DataBroker dataBroker) {
2546         OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
2547         if (bridgeAugmentation != null) {
2548             InstanceIdentifier<Node> ovsdbNodeIid =
2549                     (InstanceIdentifier<Node>) bridgeAugmentation.getManagedBy().getValue();
2550             return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
2551                     LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid);
2552         }
2553         return Optional.absent();
2554
2555     }
2556
2557     @Nullable
2558     public static OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) {
2559         if (node == null) {
2560             return null;
2561         }
2562         return node.augmentation(OvsdbBridgeAugmentation.class);
2563     }
2564
2565     // Use Objects.requireNonNullElse instead with JDK9+
2566     @Nonnull
2567     public static <T> T requireNonNullElse(@Nullable T obj, @Nonnull T defaultObj) {
2568         return obj != null ? obj : requireNonNull(defaultObj);
2569     }
2570
2571     public static String getDefaultFibRouteToSNATForSubnetJobKey(String subnetName, BigInteger dpnId) {
2572         return NatConstants.NAT_DJC_PREFIX + subnetName + dpnId;
2573     }
2574 }