Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / 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.vpnservice.natservice.internal;
9
10 import java.math.BigInteger;
11 import java.util.List;
12
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
18 import org.opendaylight.vpnservice.mdsalutil.*;
19 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
27 import org.opendaylight.yangtools.concepts.ListenerRegistration;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import com.google.common.base.Optional;
33
34 public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
35     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
36     private ListenerRegistration<DataChangeListener> listenerRegistration;
37     private final DataBroker dataBroker;
38     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
39     private NaptSwitchHA naptSwitchHA;
40     private IMdsalApiManager mdsalManager;
41     private IdManagerService idManager;
42
43     public RouterDpnChangeListener (final DataBroker db) {
44         super(DpnVpninterfacesList.class);
45         dataBroker = db;
46         registerListener(db);
47     }
48
49     void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
50         this.defaultRouteProgrammer = defaultRouteProgrammer;
51     }
52
53     void setNaptSwitchHA(NaptSwitchHA switchHA) {
54         naptSwitchHA = switchHA;
55     }
56
57     void setMdsalManager(IMdsalApiManager mdsalManager) {
58         this.mdsalManager = mdsalManager;
59     }
60
61     public void setIdManager(IdManagerService idManager) {
62         this.idManager = idManager;
63     }
64
65     @Override
66     public void close() throws Exception {
67         if (listenerRegistration != null) {
68             try {
69                 listenerRegistration.close();
70             } catch (final Exception e) {
71                 LOG.error("Error when cleaning up DataChangeListener.", e);
72             }
73             listenerRegistration = null;
74         }
75         LOG.info("Router ports Listener Closed");
76     }
77
78     private void registerListener(final DataBroker db) {
79         try {
80             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
81                     getWildCardPath(), RouterDpnChangeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
82         } catch (final Exception e) {
83             LOG.error("RouterPorts DataChange listener registration fail!", e);
84             throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
85         }
86     }
87
88     private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
89         return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
90     }
91
92     @Override
93     protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
94         LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
95         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
96         BigInteger dpnId = dpnInfo.getDpnId();
97         //check router is associated to external network
98         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
99         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
100         if (routerData.isPresent()) {
101             Uuid networkId = routerData.get().getNetworkId();
102             if(networkId != null) {
103                 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
104                 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker,routerId);
105                 Long vpnId;
106                 if (vpnName == null) {
107                     LOG.debug("Internal vpn associated to router {}",routerId);
108                     vpnId = NatUtil.getVpnId(dataBroker,routerId);
109                     if (vpnId == NatConstants.INVALID_ID) {
110                         LOG.error("Invalid vpnId returned for routerName {}",routerId);
111                         return;
112                     }
113                     LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
114                     //Install default entry in FIB to SNAT table
115                     LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...", dpnId,routerId,vpnId);
116                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
117                 } else {
118                     LOG.debug("External BGP vpn associated to router {}",routerId);
119                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
120                     if (vpnId == NatConstants.INVALID_ID) {
121                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
122                         return;
123                     }
124                     Long routId = NatUtil.getVpnId(dataBroker, routerId);
125                     if (routId == NatConstants.INVALID_ID) {
126                         LOG.error("Invalid routId returned for routerName {}",routerId);
127                         return;
128                     }
129                     LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
130                     //Install default entry in FIB to SNAT table
131                     LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
132                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
133                 }
134
135                 if (routerData.get().isEnableSnat()) {
136                     LOG.info("SNAT enabled for router {}", routerId);
137                     handleSNATForDPN(dpnId, routerId ,vpnId);
138                 } else {
139                     LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
140                 }
141             }
142         } else {
143             LOG.debug("Router {} is not associated with External network", routerId);
144         }
145     }
146
147     @Override
148     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
149         LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
150         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
151         BigInteger dpnId = dpnInfo.getDpnId();
152         //check router is associated to external network
153         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
154         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
155         if (routerData.isPresent()) {
156             Uuid networkId = routerData.get().getNetworkId();
157             if (networkId != null) {
158                 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
159                 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
160                 Long vpnId;
161                 if (vpnName == null) {
162                     LOG.debug("Internal vpn associated to router {}", routerId);
163                     vpnId = NatUtil.getVpnId(dataBroker, routerId);
164                     if (vpnId == NatConstants.INVALID_ID) {
165                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
166                         return;
167                     }
168                     LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
169                     //Remove default entry in FIB
170                     LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
171                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
172                 } else {
173                     LOG.debug("External vpn associated to router {}", routerId);
174                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
175                     if (vpnId == NatConstants.INVALID_ID) {
176                         LOG.error("Invalid vpnId returned for routerName {}", routerId);
177                         return;
178                     }
179                     Long routId = NatUtil.getVpnId(dataBroker, routerId);
180                     if (routId == NatConstants.INVALID_ID) {
181                         LOG.error("Invalid routId returned for routerName {}",routerId);
182                         return;
183                     }
184                     LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
185                     //Remove default entry in FIB
186                     LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
187                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
188                 }
189
190                 if (routerData.get().isEnableSnat()) {
191                     LOG.info("SNAT enabled for router {}", routerId);
192                     removeSNATFromDPN(dpnId, routerId, vpnId);
193                 } else {
194                     LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
195                 }
196             }
197         }
198     }
199
200     @Override
201     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
202         LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
203     }
204     void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
205         //Check if primary and secondary switch are selected, If not select the role
206         //Install select group to NAPT switch
207         //Install default miss entry to NAPT switch
208         BigInteger naptSwitch;
209         try {
210             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
211             if (routerId == NatConstants.INVALID_ID) {
212                 LOG.error("Invalid routerId returned for routerName {}", routerName);
213                 return;
214             }
215             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
216             if (naptId == null || naptId.equals(BigInteger.ZERO)) {
217                 LOG.debug("No NaptSwitch is selected for router {}", routerName);
218
219                 naptSwitch = dpnId;
220                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
221                 if (!naptstatus) {
222                     LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
223                     return;
224                 }
225                 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
226
227                 //installing group
228                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
229                 naptSwitchHA.installSnatGroupEntry(naptSwitch, bucketInfo, routerName);
230
231                 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
232
233             } else {
234                 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
235                 naptSwitch = naptId;
236
237                 //installing group
238                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
239                 if (bucketInfo == null) {
240                     LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}", dpnId, routerName,
241                             naptSwitch);
242                     return;
243                 }
244                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
245             }
246             // Install miss entry (table 26) pointing to group
247             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
248             FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
249             if (flowEntity == null) {
250                 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}", routerName, dpnId, groupId);
251                 return;
252             }
253             LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
254             mdsalManager.installFlow(flowEntity);
255         } catch (Exception ex) {
256             LOG.error("Exception in handleSNATForDPN method : {}", ex);
257         }
258     }
259
260     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
261         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
262         //remove miss entry to NAPT switch
263         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
264
265         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
266         if (routerId == NatConstants.INVALID_ID) {
267             LOG.error("Invalid routerId returned for routerName {}",routerName);
268             return;
269         }
270         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
271         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
272             LOG.debug("No naptSwitch is selected for router {}", routerName);
273             return;
274         }
275         try {
276             boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId);
277             if (!naptStatus) {
278                 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
279                         dpnId, routerName);
280             } else {
281                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch);
282             }
283         } catch (Exception ex) {
284             LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);
285         }
286
287         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
288         FlowEntity flowEntity = null;
289         try {
290             flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
291             if (flowEntity == null) {
292                 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
293                 return;
294             }
295             LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
296             mdsalManager.removeFlow(flowEntity);
297
298         } catch (Exception ex) {
299             LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
300             return;
301         }
302         LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
303
304         //remove group
305         GroupEntity groupEntity = null;
306         try {
307             groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
308                     GroupTypes.GroupAll, null);
309             LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
310             mdsalManager.removeGroup(groupEntity);
311         } catch (Exception ex) {
312             LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
313             return;
314         }
315         LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
316     }
317 }