Convert to JobCoordinator in natservice-impl
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalNetworksChangeListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import 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;
46
47 @Singleton
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;
62
63     @Inject
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;
85         if (config != null) {
86             this.natMode = config.getNatMode();
87         }
88     }
89
90     @Override
91     @PostConstruct
92     public void init() {
93         LOG.info("{} init", getClass().getSimpleName());
94         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
95     }
96
97     @Override
98     protected InstanceIdentifier<Networks> getWildCardPath() {
99         return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
100     }
101
102     @Override
103     protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {
104
105     }
106
107     @Override
108     protected ExternalNetworksChangeListener getDataTreeChangeListener() {
109         return ExternalNetworksChangeListener.this;
110     }
111
112     @Override
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);
117             return;
118         }
119
120         for (Uuid routerId: networks.getRouterIds()) {
121             String routerName = routerId.toString();
122
123             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =
124                     NatUtil.buildNaptSwitchIdentifier(routerName);
125
126             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier);
127
128             LOG.debug("remove : successful deletion of data in napt-switches container");
129         }
130     }
131
132     @Override
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);
148             }
149             futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
150             return futures;
151         }, NatConstants.NAT_DJC_MAX_RETRIES);
152     }
153
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());
160                 return;
161             }
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);
166             }
167         }
168     }
169
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());
174
175             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
176             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
177                 routerPortsId);
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());
181                 continue;
182             }
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());
191                     continue;
192                 }
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);
198                 }
199             }
200         }
201
202         // SNAT
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);
208                 return;
209             }
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);
214                 return;
215             }
216
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();
224             }
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: {}",
228                     routerId, dpnId);
229                 return;
230             }
231
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);
255                     }
256                 }
257             } else {
258                 LOG.warn("associateExternalNetworkWithVPN : No ipMapping present fot the routerId {}", routerId);
259             }
260
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,
265                         writeFlowInvTx);
266                 if (vpnId != -1) {
267                     LOG.debug("associateExternalNetworkWithVPN : Calling externalRouterListener installNaptPfibEntry "
268                             + "for dpnId {} and vpnId {}", dpnId, vpnId);
269                     externalRouterListener.installNaptPfibEntry(dpnId, vpnId, writeFlowInvTx);
270                 }
271             }
272         }
273
274     }
275
276     private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {
277         List<Uuid> routerIds = network.getRouterIds();
278
279         for (Uuid routerId : routerIds) {
280             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
281             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
282                 routerPortsId);
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());
286                 continue;
287             }
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());
298                     continue;
299                 }
300                 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
301                 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
302                     floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(),
303                             intExtPortMap, removeFlowInvTx);
304                 }
305             }
306             //final submit call for removeFlowInvTx
307             futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
308         }
309     }
310 }