2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.natservice.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16 import javax.annotation.PostConstruct;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 public class ExternalNetworksChangeListener
49 extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener> {
50 private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworksChangeListener.class);
51 private final DataBroker dataBroker;
52 private final IMdsalApiManager mdsalManager;
53 private final FloatingIPListener floatingIpListener;
54 private final ExternalRoutersListener externalRouterListener;
55 private final OdlInterfaceRpcService interfaceManager;
56 private final NaptManager naptManager;
57 private final IBgpManager bgpManager;
58 private final VpnRpcService vpnService;
59 private final FibRpcService fibService;
60 private final JobCoordinator coordinator;
61 private NatMode natMode = NatMode.Controller;
64 public ExternalNetworksChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
65 final FloatingIPListener floatingIpListener,
66 final ExternalRoutersListener externalRouterListener,
67 final OdlInterfaceRpcService interfaceManager,
68 final NaptManager naptManager,
69 final IBgpManager bgpManager,
70 final VpnRpcService vpnService,
71 final FibRpcService fibService,
72 final NatserviceConfig config,
73 final JobCoordinator coordinator) {
74 super(Networks.class, ExternalNetworksChangeListener.class);
75 this.dataBroker = dataBroker;
76 this.mdsalManager = mdsalManager;
77 this.floatingIpListener = floatingIpListener;
78 this.externalRouterListener = externalRouterListener;
79 this.interfaceManager = interfaceManager;
80 this.naptManager = naptManager;
81 this.bgpManager = bgpManager;
82 this.vpnService = vpnService;
83 this.fibService = fibService;
84 this.coordinator = coordinator;
86 this.natMode = config.getNatMode();
93 LOG.info("{} init", getClass().getSimpleName());
94 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
98 protected InstanceIdentifier<Networks> getWildCardPath() {
99 return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
103 protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {
108 protected ExternalNetworksChangeListener getDataTreeChangeListener() {
109 return ExternalNetworksChangeListener.this;
113 protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {
114 if (identifier == null || networks == null || networks.getRouterIds().isEmpty()) {
115 LOG.warn("remove : returning without processing since networks/identifier is null: "
116 + "identifier: {}, networks: {}", identifier, networks);
120 for (Uuid routerId: networks.getRouterIds()) {
121 String routerName = routerId.toString();
123 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =
124 NatUtil.buildNaptSwitchIdentifier(routerName);
126 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier);
128 LOG.debug("remove : successful deletion of data in napt-switches container");
133 protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
134 //Check for VPN disassociation
135 Uuid originalVpn = original.getVpnid();
136 Uuid updatedVpn = update.getVpnid();
137 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.getKey(), () -> {
138 WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
139 List<ListenableFuture<Void>> futures = new ArrayList<>();
140 if (originalVpn == null && updatedVpn != null) {
141 //external network is dis-associated from L3VPN instance
142 associateExternalNetworkWithVPN(update, writeFlowInvTx);
143 } else if (originalVpn != null && updatedVpn == null) {
144 //external network is associated with vpn
145 disassociateExternalNetworkFromVPN(update, originalVpn.getValue());
146 //Remove the SNAT entries
147 removeSnatEntries(original, original.getId(), writeFlowInvTx);
149 futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
151 }, NatConstants.NAT_DJC_MAX_RETRIES);
154 private void removeSnatEntries(Networks original, Uuid networkUuid, WriteTransaction writeFlowInvTx) {
155 List<Uuid> routerUuids = original.getRouterIds();
156 for (Uuid routerUuid : routerUuids) {
157 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());
158 if (routerId == NatConstants.INVALID_ID) {
159 LOG.error("removeSnatEntries : Invalid routerId returned for routerName {}", routerUuid.getValue());
162 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
163 if (natMode == NatMode.Controller) {
164 externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), routerId, networkUuid,
165 externalIps, false, original.getVpnid().getValue(), writeFlowInvTx);
170 private void associateExternalNetworkWithVPN(Networks network, WriteTransaction writeFlowInvTx) {
171 List<Uuid> routerIds = network.getRouterIds();
172 for (Uuid routerId : routerIds) {
173 //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());
175 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
176 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
178 if (!optRouterPorts.isPresent()) {
179 LOG.debug("associateExternalNetworkWithVPN : Could not read Router Ports data object with id: {} "
180 + "to handle associate ext nw {}", routerId, network.getId());
183 RouterPorts routerPorts = optRouterPorts.get();
184 List<Ports> interfaces = routerPorts.getPorts();
185 for (Ports port : interfaces) {
186 String portName = port.getPortName();
187 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
188 if (dpnId.equals(BigInteger.ZERO)) {
189 LOG.debug("associateExternalNetworkWithVPN : DPN not found for {}, "
190 + "skip handling of ext nw {} association", portName, network.getId());
193 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
194 for (InternalToExternalPortMap ipMap : intExtPortMapList) {
195 //remove all VPN related entries
196 floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(),
197 ipMap, writeFlowInvTx);
203 for (Uuid routerId : routerIds) {
204 LOG.debug("associateExternalNetworkWithVPN() : for routerId {}", routerId);
205 Uuid networkId = network.getId();
206 if (networkId == null) {
207 LOG.error("associateExternalNetworkWithVPN : networkId is null for the router ID {}", routerId);
210 final String vpnName = network.getVpnid().getValue();
211 if (vpnName == null) {
212 LOG.error("associateExternalNetworkWithVPN : No VPN associated with ext nw {} for router {}",
213 networkId, routerId);
217 BigInteger dpnId = new BigInteger("0");
218 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
219 NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());
220 Optional<RouterToNaptSwitch> rtrToNapt =
221 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
222 if (rtrToNapt.isPresent()) {
223 dpnId = rtrToNapt.get().getPrimarySwitchId();
225 LOG.debug("associateExternalNetworkWithVPN : got primarySwitch as dpnId{} ", dpnId);
226 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
227 LOG.warn("associateExternalNetworkWithVPN : primary napt Switch not found for router {} on dpn: {}",
232 Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());
233 InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
234 .rev160111.intext.ip.map.IpMapping> idBuilder =
235 InstanceIdentifier.builder(IntextIpMap.class)
236 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
237 .intext.ip.map.IpMapping.class,
238 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
239 .intext.ip.map.IpMappingKey(routerIdentifier));
240 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
241 .intext.ip.map.IpMapping> id = idBuilder.build();
242 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
243 .intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
244 if (ipMapping.isPresent()) {
245 List<IpMap> ipMaps = ipMapping.get().getIpMap();
246 for (IpMap ipMap : ipMaps) {
247 String externalIp = ipMap.getExternalIp();
248 LOG.debug("associateExternalNetworkWithVPN : Calling advToBgpAndInstallFibAndTsFlows for dpnId {},"
249 + "vpnName {} and externalIp {}", dpnId, vpnName, externalIp);
250 if (natMode == NatMode.Controller) {
251 externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
252 vpnName, routerIdentifier, routerId.getValue(),
253 externalIp, network.getId(), null /* external-router */,
254 vpnService, fibService, bgpManager, dataBroker, writeFlowInvTx);
258 LOG.warn("associateExternalNetworkWithVPN : No ipMapping present fot the routerId {}", routerId);
261 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
262 // Install 47 entry to point to 21
263 if (natMode == NatMode.Controller) {
264 externalRouterListener.installNaptPfibEntriesForExternalSubnets(routerId.getValue(), dpnId,
267 LOG.debug("associateExternalNetworkWithVPN : Calling externalRouterListener installNaptPfibEntry "
268 + "for dpnId {} and vpnId {}", dpnId, vpnId);
269 externalRouterListener.installNaptPfibEntry(dpnId, vpnId, writeFlowInvTx);
276 private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {
277 List<Uuid> routerIds = network.getRouterIds();
279 for (Uuid routerId : routerIds) {
280 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
281 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
283 if (!optRouterPorts.isPresent()) {
284 LOG.debug("disassociateExternalNetworkFromVPN : Could not read Router Ports data object with id: {} "
285 + "to handle disassociate ext nw {}", routerId, network.getId());
288 RouterPorts routerPorts = optRouterPorts.get();
289 List<Ports> interfaces = routerPorts.getPorts();
290 WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
291 List<ListenableFuture<Void>> futures = new ArrayList<>();
292 for (Ports port : interfaces) {
293 String portName = port.getPortName();
294 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
295 if (dpnId.equals(BigInteger.ZERO)) {
296 LOG.debug("disassociateExternalNetworkFromVPN : DPN not found for {},"
297 + "skip handling of ext nw {} disassociation", portName, network.getId());
300 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
301 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
302 floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(),
303 intExtPortMap, removeFlowInvTx);
306 //final submit call for removeFlowInvTx
307 futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));