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 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;
35 public class RouterDpnChangeListener
36 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
37 implements AutoCloseable {
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;
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;
64 LOG.info("{} init", getClass().getSimpleName());
65 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
69 protected RouterDpnChangeListener getDataTreeChangeListener() {
70 return RouterDpnChangeListener.this;
74 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
75 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
76 .child(DpnVpninterfacesList.class);
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);
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);
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);
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);
112 Long routId = NatUtil.getVpnId(dataBroker, routerId);
113 if (routId == NatConstants.INVALID_ID) {
114 LOG.error("Invalid routId returned for routerName {}", routerId);
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);
123 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
125 if (routerData.get().isEnableSnat()) {
126 LOG.info("SNAT enabled for router {}", routerId);
127 handleSNATForDPN(dpnId, routerId, vpnId);
129 LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
133 LOG.debug("Router {} is not associated with External network", routerId);
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);
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);
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);
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);
169 Long routId = NatUtil.getVpnId(dataBroker, routerId);
170 if (routId == NatConstants.INVALID_ID) {
171 LOG.error("Invalid routId returned for routerName {}", routerId);
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);
180 if (routerData.get().isEnableSnat()) {
181 LOG.info("SNAT enabled for router {}", routerId);
182 removeSNATFromDPN(dpnId, routerId, vpnId);
184 LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
191 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
192 DpnVpninterfacesList update) {
193 LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
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;
204 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
205 if (routerId == NatConstants.INVALID_ID) {
206 LOG.error("Invalid routerId returned for routerName {}", routerName);
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);
214 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
216 LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
219 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
221 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
222 if (extRouters != null) {
223 NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
224 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
226 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
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);
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);
242 } else if (naptId.equals(dpnId)) {
243 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
246 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
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);
256 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
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);
267 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
268 mdsalManager.installFlow(flowEntity);
270 } catch (Exception ex) {
271 LOG.error("Exception in handleSNATForDPN method : {}", ex);
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
282 //get ExternalIpIn prior
283 List<String> externalIpCache;
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);
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);
300 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache);
302 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
304 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
305 FlowEntity flowEntity = null;
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);
314 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}", flowEntity);
315 mdsalManager.removeFlow(flowEntity);
317 } catch (Exception ex) {
318 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
322 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
326 GroupEntity groupEntity = null;
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);
336 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
339 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel);
340 //remove table 26 flow ppointing to table46
341 FlowEntity flowEntity = null;
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);
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);
353 } catch (Exception ex) {
354 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
358 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
361 //best effort to check IntExt model
362 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
364 } catch (Exception ex) {
365 LOG.debug("Exception while handling naptSwitch down for router {} : {}", routerName, ex);