Added a new config parameter for selecting SNAT.
[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 java.math.BigInteger;
12 import java.util.List;
13 import javax.annotation.PostConstruct;
14 import javax.inject.Inject;
15 import javax.inject.Singleton;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
19 import org.opendaylight.genius.mdsalutil.MDSALUtil;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
22 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 @Singleton
45 public class ExternalNetworksChangeListener
46         extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener> {
47     private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworksChangeListener.class);
48     private final DataBroker dataBroker;
49     private final IMdsalApiManager mdsalManager;
50     private final FloatingIPListener floatingIpListener;
51     private final ExternalRoutersListener externalRouterListener;
52     private final OdlInterfaceRpcService interfaceManager;
53     private final NaptManager naptManager;
54     private final IBgpManager bgpManager;
55     private final VpnRpcService vpnService;
56     private final FibRpcService fibService;
57     private NatMode natMode = NatMode.Controller;
58
59     @Inject
60     public ExternalNetworksChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
61                                           final FloatingIPListener floatingIpListener,
62                                           final ExternalRoutersListener externalRouterListener,
63                                           final OdlInterfaceRpcService interfaceManager,
64                                           final NaptManager naptManager,
65                                           final IBgpManager bgpManager,
66                                           final VpnRpcService vpnService,
67                                           final FibRpcService fibService,
68                                           final NatserviceConfig config) {
69         super(Networks.class, ExternalNetworksChangeListener.class);
70         this.dataBroker = dataBroker;
71         this.mdsalManager = mdsalManager;
72         this.floatingIpListener = floatingIpListener;
73         this.externalRouterListener = externalRouterListener;
74         this.interfaceManager = interfaceManager;
75         this.naptManager = naptManager;
76         this.bgpManager = bgpManager;
77         this.vpnService = vpnService;
78         this.fibService = fibService;
79         if (config != null) {
80             this.natMode = config.getNatMode();
81         }
82     }
83
84     @Override
85     @PostConstruct
86     public void init() {
87         LOG.info("{} init", getClass().getSimpleName());
88         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
89     }
90
91     @Override
92     protected InstanceIdentifier<Networks> getWildCardPath() {
93         return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
94     }
95
96     @Override
97     protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {
98
99     }
100
101     @Override
102     protected ExternalNetworksChangeListener getDataTreeChangeListener() {
103         return ExternalNetworksChangeListener.this;
104     }
105
106     @Override
107     protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {
108         if (identifier == null || networks == null || networks.getRouterIds().isEmpty()) {
109             LOG.info("ExternalNetworksChangeListener:remove:: returning without processing since "
110                 + "networks/identifier is null");
111             return;
112         }
113
114         for (Uuid routerId: networks.getRouterIds()) {
115             String routerName = routerId.toString();
116
117             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =
118                     getRouterToNaptSwitchInstanceIdentifier(routerName);
119
120             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier);
121
122             LOG.debug("ExternalNetworksChangeListener:delete:: successful deletion of data in "
123                 + "napt-switches container");
124         }
125     }
126
127     private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier(String routerName) {
128         return  InstanceIdentifier.builder(NaptSwitches.class)
129                         .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
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         if (originalVpn == null && updatedVpn != null) {
138             //external network is dis-associated from L3VPN instance
139             associateExternalNetworkWithVPN(update);
140         } else if (originalVpn != null && updatedVpn == null) {
141             //external network is associated with vpn
142             disassociateExternalNetworkFromVPN(update, originalVpn.getValue());
143             //Remove the SNAT entries
144             removeSnatEntries(original, original.getId());
145         }
146     }
147
148     private void removeSnatEntries(Networks original, Uuid networkUuid) {
149         List<Uuid> routerUuids = original.getRouterIds();
150         for (Uuid routerUuid : routerUuids) {
151             Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());
152             if (routerId == NatConstants.INVALID_ID) {
153                 LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerUuid.getValue());
154                 return;
155             }
156             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
157             if (natMode == NatMode.Controller) {
158                 externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps,
159                         false, original.getVpnid().getValue());
160             }
161         }
162     }
163
164     private void associateExternalNetworkWithVPN(Networks network) {
165         List<Uuid> routerIds = network.getRouterIds();
166         for (Uuid routerId : routerIds) {
167             //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());
168
169             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
170             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
171                 routerPortsId);
172             if (!optRouterPorts.isPresent()) {
173                 LOG.debug("Could not read Router Ports data object with id: {} to handle associate ext nw {}",
174                     routerId, network.getId());
175                 continue;
176             }
177             RouterPorts routerPorts = optRouterPorts.get();
178             List<Ports> interfaces = routerPorts.getPorts();
179             for (Ports port : interfaces) {
180                 String portName = port.getPortName();
181                 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
182                 if (dpnId.equals(BigInteger.ZERO)) {
183                     LOG.debug("DPN not found for {}, skip handling of ext nw {} association",
184                         portName, network.getId());
185                     continue;
186                 }
187                 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
188                 for (InternalToExternalPortMap ipMap : intExtPortMapList) {
189                     //remove all VPN related entries
190                     floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(),
191                             ipMap);
192                 }
193             }
194         }
195
196         // SNAT
197         for (Uuid routerId : routerIds) {
198             LOG.debug("NAT Service : associateExternalNetworkWithVPN() for routerId {}",  routerId);
199             Uuid networkId = network.getId();
200             if (networkId == null) {
201                 LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
202                 return;
203             }
204             final String vpnName = network.getVpnid().getValue();
205             if (vpnName == null) {
206                 LOG.error("NAT Service : No VPN associated with ext nw {} for router {}", networkId, routerId);
207                 return;
208             }
209
210             BigInteger dpnId = new BigInteger("0");
211             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
212                 NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());
213             Optional<RouterToNaptSwitch> rtrToNapt =
214                 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
215             if (rtrToNapt.isPresent()) {
216                 dpnId = rtrToNapt.get().getPrimarySwitchId();
217             }
218             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", dpnId);
219             if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
220                 LOG.debug("NAT Service : primary napt Switch not found for router {} in "
221                     + "associateExternalNetworkWithVPN", routerId);
222                 return;
223             }
224
225             Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());
226             InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
227                 .rev160111.intext.ip.map.IpMapping> idBuilder =
228                 InstanceIdentifier.builder(IntextIpMap.class)
229                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
230                         .intext.ip.map.IpMapping.class,
231                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
232                             .intext.ip.map.IpMappingKey(routerIdentifier));
233             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
234                 .intext.ip.map.IpMapping> id = idBuilder.build();
235             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
236                 .intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
237             if (ipMapping.isPresent()) {
238                 List<IpMap> ipMaps = ipMapping.get().getIpMap();
239                 for (IpMap ipMap : ipMaps) {
240                     String externalIp = ipMap.getExternalIp();
241                     LOG.debug("NAT Service : got externalIp as {}", externalIp);
242                     LOG.debug("NAT Service : About to call advToBgpAndInstallFibAndTsFlows for dpnId {}, "
243                         + "vpnName {} and externalIp {}", dpnId, vpnName, externalIp);
244                     if (natMode == NatMode.Controller) {
245                         externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
246                                 vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), routerId.getValue(),
247                                 externalIp, null /* external-router */, vpnService, fibService, bgpManager, dataBroker,
248                                 LOG);
249                     }
250                 }
251             } else {
252                 LOG.warn("NAT Service : No ipMapping present fot the routerId {}", routerId);
253             }
254
255             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
256             // Install 47 entry to point to 21
257             if (natMode == NatMode.Controller) {
258                 externalRouterListener.installNaptPfibEntriesForExternalSubnets(routerId.getValue(), dpnId);
259                 if (vpnId != -1) {
260                     LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for dpnId {} "
261                             + "and vpnId {}", dpnId, vpnId);
262                     externalRouterListener.installNaptPfibEntry(dpnId, vpnId);
263                 }
264             }
265         }
266
267     }
268
269     private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {
270         List<Uuid> routerIds = network.getRouterIds();
271
272         for (Uuid routerId : routerIds) {
273             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
274             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
275                 routerPortsId);
276             if (!optRouterPorts.isPresent()) {
277                 LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate ext nw {}",
278                     routerId, network.getId());
279                 continue;
280             }
281             RouterPorts routerPorts = optRouterPorts.get();
282             List<Ports> interfaces = routerPorts.getPorts();
283             for (Ports port : interfaces) {
284                 String portName = port.getPortName();
285                 BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
286                 if (dpnId.equals(BigInteger.ZERO)) {
287                     LOG.debug("DPN not found for {}, skip handling of ext nw {} disassociation",
288                         portName, network.getId());
289                     continue;
290                 }
291                 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
292                 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
293                     floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(),
294                             intExtPortMap);
295                 }
296             }
297         }
298     }
299
300 }