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 java.math.BigInteger;
11 import java.util.List;
12 import java.util.HashMap;
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.AsyncDataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
19 import org.opendaylight.genius.mdsalutil.*;
20 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 import com.google.common.base.Optional;
35 public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
36 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
37 private ListenerRegistration<DataChangeListener> listenerRegistration;
38 private final DataBroker dataBroker;
39 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
40 private NaptSwitchHA naptSwitchHA;
41 private IMdsalApiManager mdsalManager;
42 private IdManagerService idManager;
44 public RouterDpnChangeListener (final DataBroker db) {
45 super(DpnVpninterfacesList.class);
50 void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
51 this.defaultRouteProgrammer = defaultRouteProgrammer;
54 void setNaptSwitchHA(NaptSwitchHA switchHA) {
55 naptSwitchHA = switchHA;
58 void setMdsalManager(IMdsalApiManager mdsalManager) {
59 this.mdsalManager = mdsalManager;
62 public void setIdManager(IdManagerService idManager) {
63 this.idManager = idManager;
67 public void close() throws Exception {
68 if (listenerRegistration != null) {
70 listenerRegistration.close();
71 } catch (final Exception e) {
72 LOG.error("Error when cleaning up DataChangeListener.", e);
74 listenerRegistration = null;
76 LOG.info("Router ports Listener Closed");
79 private void registerListener(final DataBroker db) {
81 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
82 getWildCardPath(), RouterDpnChangeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
83 } catch (final Exception e) {
84 LOG.error("RouterPorts DataChange listener registration fail!", e);
85 throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
89 private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
90 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
94 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
95 LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
96 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
97 BigInteger dpnId = dpnInfo.getDpnId();
98 //check router is associated to external network
99 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
100 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
101 if (routerData.isPresent()) {
102 Uuid networkId = routerData.get().getNetworkId();
103 if(networkId != null) {
104 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
105 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker,routerId);
107 if (vpnName == null) {
108 LOG.debug("Internal vpn associated to router {}",routerId);
109 vpnId = NatUtil.getVpnId(dataBroker,routerId);
110 if (vpnId == NatConstants.INVALID_ID) {
111 LOG.error("Invalid vpnId returned for routerName {}",routerId);
114 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
115 //Install default entry in FIB to SNAT table
116 LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...", dpnId,routerId,vpnId);
117 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
119 LOG.debug("External BGP vpn associated to router {}",routerId);
120 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
121 if (vpnId == NatConstants.INVALID_ID) {
122 LOG.error("Invalid vpnId returned for routerName {}", routerId);
125 Long routId = NatUtil.getVpnId(dataBroker, routerId);
126 if (routId == NatConstants.INVALID_ID) {
127 LOG.error("Invalid routId returned for routerName {}",routerId);
130 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
131 //Install default entry in FIB to SNAT table
132 LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
133 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
136 if (routerData.get().isEnableSnat()) {
137 LOG.info("SNAT enabled for router {}", routerId);
138 handleSNATForDPN(dpnId, routerId ,vpnId);
140 LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
144 LOG.debug("Router {} is not associated with External network", routerId);
149 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
150 LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
151 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
152 BigInteger dpnId = dpnInfo.getDpnId();
153 //check router is associated to external network
154 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
155 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
156 if (routerData.isPresent()) {
157 Uuid networkId = routerData.get().getNetworkId();
158 if (networkId != null) {
159 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
160 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
162 if (vpnName == null) {
163 LOG.debug("Internal vpn associated to router {}", routerId);
164 vpnId = NatUtil.getVpnId(dataBroker, routerId);
165 if (vpnId == NatConstants.INVALID_ID) {
166 LOG.error("Invalid vpnId returned for routerName {}", routerId);
169 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
170 //Remove default entry in FIB
171 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
172 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
174 LOG.debug("External vpn associated to router {}", routerId);
175 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
176 if (vpnId == NatConstants.INVALID_ID) {
177 LOG.error("Invalid vpnId returned for routerName {}", routerId);
180 Long routId = NatUtil.getVpnId(dataBroker, routerId);
181 if (routId == NatConstants.INVALID_ID) {
182 LOG.error("Invalid routId returned for routerName {}",routerId);
185 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
186 //Remove default entry in FIB
187 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
188 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
191 if (routerData.get().isEnableSnat()) {
192 LOG.info("SNAT enabled for router {}", routerId);
193 removeSNATFromDPN(dpnId, routerId, vpnId);
195 LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
202 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
203 LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
205 void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
206 //Check if primary and secondary switch are selected, If not select the role
207 //Install select group to NAPT switch
208 //Install default miss entry to NAPT switch
209 BigInteger naptSwitch;
211 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
212 if (routerId == NatConstants.INVALID_ID) {
213 LOG.error("Invalid routerId returned for routerName {}", routerName);
216 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
217 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
218 LOG.debug("No NaptSwitch is selected for router {}", routerName);
221 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
223 LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
226 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
228 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
230 // Install miss entry (table 26) pointing to table 46
231 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.ADD_FLOW);
232 if (flowEntity == null) {
233 LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
236 LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
237 mdsalManager.installFlow(flowEntity);
238 //Removing primary flows from old napt switch
239 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
240 LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
241 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
243 } else if (naptId.equals(dpnId)) {
244 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
247 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
251 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
252 if (bucketInfo == null) {
253 LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}", dpnId, routerName,
257 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
259 // Install miss entry (table 26) pointing to group
260 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
261 FlowEntity flowEntity = 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 {}", routerName, dpnId, groupId);
266 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
267 mdsalManager.installFlow(flowEntity);
269 } catch (Exception ex) {
270 LOG.error("Exception in handleSNATForDPN method : {}", ex);
274 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
275 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
276 //remove miss entry to NAPT switch
277 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
279 //get ExternalIpIn prior
280 List<String> externalIpCache;
282 HashMap<String,Long> externalIpLabel;
283 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
284 if (routerId == NatConstants.INVALID_ID) {
285 LOG.error("Invalid routerId returned for routerName {}",routerName);
288 externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
289 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker,routerId);
290 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
291 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
292 LOG.debug("No naptSwitch is selected for router {}", routerName);
296 boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache);
298 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
300 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
301 FlowEntity flowEntity = null;
303 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
304 if (flowEntity == null) {
305 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
308 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
309 mdsalManager.removeFlow(flowEntity);
311 } catch (Exception ex) {
312 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
315 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
318 GroupEntity groupEntity = null;
320 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
321 GroupTypes.GroupAll, null);
322 LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
323 mdsalManager.removeGroup(groupEntity);
324 } catch (Exception ex) {
325 LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
328 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
330 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch,externalIpLabel);
331 //remove table 26 flow ppointing to table46
332 FlowEntity flowEntity = null;
334 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
335 if (flowEntity == null) {
336 LOG.debug("Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
339 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
340 ,routerName,dpnId,naptSwitch);
341 mdsalManager.removeFlow(flowEntity);
343 } catch (Exception ex) {
344 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
347 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
349 //best effort to check IntExt model
350 naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
352 } catch (Exception ex) {
353 LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);