Use Java declarations instead of Google Collections
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / RouterDpnChangeListener.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.HashMap;
13 import java.util.List;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
18 import org.opendaylight.genius.mdsalutil.BucketInfo;
19 import org.opendaylight.genius.mdsalutil.FlowEntity;
20 import org.opendaylight.genius.mdsalutil.GroupEntity;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
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.idmanager.rev160406.IdManagerService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
30 import org.opendaylight.yangtools.concepts.ListenerRegistration;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public class RouterDpnChangeListener
36     extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
37     implements AutoCloseable {
38
39     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
40     private ListenerRegistration<DataChangeListener> listenerRegistration;
41     private final DataBroker dataBroker;
42     private final IMdsalApiManager mdsalManager;
43     private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
44     private final NaptSwitchHA naptSwitchHA;
45     private final IdManagerService idManager;
46     private final ExternalNetworkGroupInstaller extNetGroupInstaller;
47
48     public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
49                                    final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
50                                    final NaptSwitchHA naptSwitchHA,
51                                    final IdManagerService idManager,
52                                    final ExternalNetworkGroupInstaller extNetGroupInstaller) {
53         super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
54         this.dataBroker = dataBroker;
55         this.mdsalManager = mdsalManager;
56         this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
57         this.naptSwitchHA = naptSwitchHA;
58         this.idManager = idManager;
59         this.extNetGroupInstaller = extNetGroupInstaller;
60     }
61
62     @Override
63     public void init() {
64         LOG.info("{} init", getClass().getSimpleName());
65         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
66     }
67
68     @Override
69     protected RouterDpnChangeListener getDataTreeChangeListener() {
70         return RouterDpnChangeListener.this;
71     }
72
73     @Override
74     protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
75         return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
76             .child(DpnVpninterfacesList.class);
77     }
78
79     @Override
80     protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
81         LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
82         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
83         BigInteger dpnId = dpnInfo.getDpnId();
84         //check router is associated to external network
85         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
86         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
87         if (routerData.isPresent()) {
88             Uuid networkId = routerData.get().getNetworkId();
89             if (networkId != null) {
90                 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
91                 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
92                 Long vpnId;
93                 if (vpnName == null) {
94                     LOG.debug("Internal vpn associated to router {}", routerId);
95                     vpnId = NatUtil.getVpnId(dataBroker, routerId);
96                     if (vpnId == NatConstants.INVALID_ID) {
97                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
98                         return;
99                     }
100                     LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
101                     //Install default entry in FIB to SNAT table
102                     LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...",
103                         dpnId, routerId, vpnId);
104                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
105                 } else {
106                     LOG.debug("External BGP vpn associated to router {}", routerId);
107                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
108                     if (vpnId == NatConstants.INVALID_ID) {
109                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
110                         return;
111                     }
112                     Long routId = NatUtil.getVpnId(dataBroker, routerId);
113                     if (routId == NatConstants.INVALID_ID) {
114                         LOG.error("Invalid routId returned for routerName {}", routerId);
115                         return;
116                     }
117                     LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
118                     //Install default entry in FIB to SNAT table
119                     LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...",
120                         dpnId, routerId, vpnId);
121                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
122                 }
123                 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
124
125                 if (routerData.get().isEnableSnat()) {
126                     LOG.info("SNAT enabled for router {}", routerId);
127                     handleSNATForDPN(dpnId, routerId, vpnId);
128                 } else {
129                     LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
130                 }
131             }
132         } else {
133             LOG.debug("Router {} is not associated with External network", routerId);
134         }
135     }
136
137     @Override
138     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
139         LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
140         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
141         BigInteger dpnId = dpnInfo.getDpnId();
142         //check router is associated to external network
143         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
144         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
145         if (routerData.isPresent()) {
146             Uuid networkId = routerData.get().getNetworkId();
147             if (networkId != null) {
148                 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
149                 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
150                 Long vpnId;
151                 if (vpnName == null) {
152                     LOG.debug("Internal vpn associated to router {}", routerId);
153                     vpnId = NatUtil.getVpnId(dataBroker, routerId);
154                     if (vpnId == NatConstants.INVALID_ID) {
155                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
156                         return;
157                     }
158                     LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
159                     //Remove default entry in FIB
160                     LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
161                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
162                 } else {
163                     LOG.debug("External vpn associated to router {}", routerId);
164                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
165                     if (vpnId == NatConstants.INVALID_ID) {
166                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
167                         return;
168                     }
169                     Long routId = NatUtil.getVpnId(dataBroker, routerId);
170                     if (routId == NatConstants.INVALID_ID) {
171                         LOG.error("Invalid routId returned for routerName {}", routerId);
172                         return;
173                     }
174                     LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
175                     //Remove default entry in FIB
176                     LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
177                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routId);
178                 }
179
180                 if (routerData.get().isEnableSnat()) {
181                     LOG.info("SNAT enabled for router {}", routerId);
182                     removeSNATFromDPN(dpnId, routerId, vpnId);
183                 } else {
184                     LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
185                 }
186             }
187         }
188     }
189
190     @Override
191     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
192                           DpnVpninterfacesList update) {
193         LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
194     }
195
196     // TODO Clean up the exception handling
197     @SuppressWarnings("checkstyle:IllegalCatch")
198     void handleSNATForDPN(BigInteger dpnId, String routerName, Long routerVpnId) {
199         //Check if primary and secondary switch are selected, If not select the role
200         //Install select group to NAPT switch
201         //Install default miss entry to NAPT switch
202         BigInteger naptSwitch;
203         try {
204             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
205             if (routerId == NatConstants.INVALID_ID) {
206                 LOG.error("Invalid routerId returned for routerName {}", routerName);
207                 return;
208             }
209             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
210             if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
211                 LOG.debug("No NaptSwitch is selected for router {}", routerName);
212
213                 naptSwitch = dpnId;
214                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
215                 if (!naptstatus) {
216                     LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
217                     return;
218                 }
219                 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
220
221                 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
222                 if (extRouters != null) {
223                     NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
224                     naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
225                 }
226                 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
227
228                 // Install miss entry (table 26) pointing to table 46
229                 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
230                     routerVpnId, NatConstants.ADD_FLOW);
231                 if (flowEntity == null) {
232                     LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
233                     return;
234                 }
235                 LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
236                 mdsalManager.installFlow(flowEntity);
237                 //Removing primary flows from old napt switch
238                 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
239                     LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
240                     naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
241                 }
242             } else if (naptId.equals(dpnId)) {
243                 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
244             } else {
245
246                 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
247                 naptSwitch = naptId;
248
249                 //installing group
250                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
251                 if (bucketInfo == null) {
252                     LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}",
253                         dpnId, routerName, naptSwitch);
254                     return;
255                 }
256                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
257
258                 // Install miss entry (table 26) pointing to group
259                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
260                 FlowEntity flowEntity =
261                     naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
262                 if (flowEntity == null) {
263                     LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}",
264                         routerName, dpnId, groupId);
265                     return;
266                 }
267                 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
268                 mdsalManager.installFlow(flowEntity);
269             }
270         } catch (Exception ex) {
271             LOG.error("Exception in handleSNATForDPN method : {}", ex);
272         }
273     }
274
275     // TODO Clean up the exception handling
276     @SuppressWarnings("checkstyle:IllegalCatch")
277     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
278         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
279         //remove miss entry to NAPT switch
280         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
281
282         //get ExternalIpIn prior
283         List<String> externalIpCache;
284         //HashMap Label
285         HashMap<String, Long> externalIpLabel;
286         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
287         if (routerId == NatConstants.INVALID_ID) {
288             LOG.error("Invalid routerId returned for routerName {}", routerName);
289             return;
290         }
291         externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
292         externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
293         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
294         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
295             LOG.debug("No naptSwitch is selected for router {}", routerName);
296             return;
297         }
298         try {
299             boolean naptStatus =
300                 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache);
301             if (!naptStatus) {
302                 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
303                     dpnId, routerName);
304                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
305                 FlowEntity flowEntity = null;
306                 try {
307                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
308                         NatConstants.DEL_FLOW);
309                     if (flowEntity == null) {
310                         LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",
311                             routerName, dpnId, groupId);
312                         return;
313                     }
314                     LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}", flowEntity);
315                     mdsalManager.removeFlow(flowEntity);
316
317                 } catch (Exception ex) {
318                     LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
319                         flowEntity, ex);
320                     return;
321                 }
322                 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
323                     dpnId, routerName);
324
325                 //remove group
326                 GroupEntity groupEntity = null;
327                 try {
328                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
329                         GroupTypes.GroupAll, null);
330                     LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
331                     mdsalManager.removeGroup(groupEntity);
332                 } catch (Exception ex) {
333                     LOG.debug("NAT Service : Failed to remove group entity {} : {}", groupEntity, ex);
334                     return;
335                 }
336                 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
337                     dpnId, routerName);
338             } else {
339                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel);
340                 //remove table 26 flow ppointing to table46
341                 FlowEntity flowEntity = null;
342                 try {
343                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
344                         NatConstants.DEL_FLOW);
345                     if (flowEntity == null) {
346                         LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
347                         return;
348                     }
349                     LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with "
350                         + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
351                     mdsalManager.removeFlow(flowEntity);
352
353                 } catch (Exception ex) {
354                     LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
355                         flowEntity, ex);
356                     return;
357                 }
358                 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
359                     dpnId, routerName);
360
361                 //best effort to check IntExt model
362                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
363             }
364         } catch (Exception ex) {
365             LOG.debug("Exception while handling naptSwitch down for router {} : {}", routerName, ex);
366         }
367     }
368 }