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.BucketInfo;
20 import org.opendaylight.genius.mdsalutil.FlowEntity;
21 import org.opendaylight.genius.mdsalutil.GroupEntity;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
31 import org.opendaylight.yangtools.concepts.ListenerRegistration;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import com.google.common.base.Optional;
38 public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
39 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
40 private ListenerRegistration<DataChangeListener> listenerRegistration;
41 private final DataBroker dataBroker;
42 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
43 private NaptSwitchHA naptSwitchHA;
44 private IMdsalApiManager mdsalManager;
45 private IdManagerService idManager;
47 public RouterDpnChangeListener (final DataBroker db) {
48 super(DpnVpninterfacesList.class);
53 void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
54 this.defaultRouteProgrammer = defaultRouteProgrammer;
57 void setNaptSwitchHA(NaptSwitchHA switchHA) {
58 naptSwitchHA = switchHA;
61 void setMdsalManager(IMdsalApiManager mdsalManager) {
62 this.mdsalManager = mdsalManager;
65 public void setIdManager(IdManagerService idManager) {
66 this.idManager = idManager;
70 public void close() throws Exception {
71 if (listenerRegistration != null) {
73 listenerRegistration.close();
74 } catch (final Exception e) {
75 LOG.error("Error when cleaning up DataChangeListener.", e);
77 listenerRegistration = null;
79 LOG.info("Router ports Listener Closed");
82 private void registerListener(final DataBroker db) {
84 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
85 getWildCardPath(), RouterDpnChangeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
86 } catch (final Exception e) {
87 LOG.error("RouterPorts DataChange listener registration fail!", e);
88 throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
92 private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
93 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
97 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
98 LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
99 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
100 BigInteger dpnId = dpnInfo.getDpnId();
101 //check router is associated to external network
102 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
103 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
104 if (routerData.isPresent()) {
105 Uuid networkId = routerData.get().getNetworkId();
106 if(networkId != null) {
107 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
108 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker,routerId);
110 if (vpnName == null) {
111 LOG.debug("Internal vpn associated to router {}",routerId);
112 vpnId = NatUtil.getVpnId(dataBroker,routerId);
113 if (vpnId == NatConstants.INVALID_ID) {
114 LOG.error("Invalid vpnId 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 router {} with vpn {}...", dpnId,routerId,vpnId);
120 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
122 LOG.debug("External BGP vpn associated to router {}",routerId);
123 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
124 if (vpnId == NatConstants.INVALID_ID) {
125 LOG.error("Invalid vpnId returned for routerName {}", routerId);
128 Long routId = NatUtil.getVpnId(dataBroker, routerId);
129 if (routId == NatConstants.INVALID_ID) {
130 LOG.error("Invalid routId returned for routerName {}",routerId);
133 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
134 //Install default entry in FIB to SNAT table
135 LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
136 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
139 if (routerData.get().isEnableSnat()) {
140 LOG.info("SNAT enabled for router {}", routerId);
141 handleSNATForDPN(dpnId, routerId ,vpnId);
143 LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
147 LOG.debug("Router {} is not associated with External network", routerId);
152 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
153 LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
154 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
155 BigInteger dpnId = dpnInfo.getDpnId();
156 //check router is associated to external network
157 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
158 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
159 if (routerData.isPresent()) {
160 Uuid networkId = routerData.get().getNetworkId();
161 if (networkId != null) {
162 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
163 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
165 if (vpnName == null) {
166 LOG.debug("Internal vpn associated to router {}", routerId);
167 vpnId = NatUtil.getVpnId(dataBroker, routerId);
168 if (vpnId == NatConstants.INVALID_ID) {
169 LOG.error("Invalid vpnId returned for routerName {}", routerId);
172 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
173 //Remove default entry in FIB
174 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
175 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
177 LOG.debug("External vpn associated to router {}", routerId);
178 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
179 if (vpnId == NatConstants.INVALID_ID) {
180 LOG.error("Invalid vpnId returned for routerName {}", routerId);
183 Long routId = NatUtil.getVpnId(dataBroker, routerId);
184 if (routId == NatConstants.INVALID_ID) {
185 LOG.error("Invalid routId returned for routerName {}",routerId);
188 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
189 //Remove default entry in FIB
190 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
191 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
194 if (routerData.get().isEnableSnat()) {
195 LOG.info("SNAT enabled for router {}", routerId);
196 removeSNATFromDPN(dpnId, routerId, vpnId);
198 LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
205 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
206 LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
208 void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
209 //Check if primary and secondary switch are selected, If not select the role
210 //Install select group to NAPT switch
211 //Install default miss entry to NAPT switch
212 BigInteger naptSwitch;
214 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
215 if (routerId == NatConstants.INVALID_ID) {
216 LOG.error("Invalid routerId returned for routerName {}", routerName);
219 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
220 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
221 LOG.debug("No NaptSwitch is selected for router {}", routerName);
224 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
226 LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
229 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
231 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
233 // Install miss entry (table 26) pointing to table 46
234 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.ADD_FLOW);
235 if (flowEntity == null) {
236 LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
239 LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
240 mdsalManager.installFlow(flowEntity);
241 //Removing primary flows from old napt switch
242 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
243 LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
244 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
246 } else if (naptId.equals(dpnId)) {
247 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
250 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
254 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
255 if (bucketInfo == null) {
256 LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}", dpnId, routerName,
260 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
262 // Install miss entry (table 26) pointing to group
263 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
264 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
265 if (flowEntity == null) {
266 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}", routerName, dpnId, groupId);
269 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
270 mdsalManager.installFlow(flowEntity);
272 } catch (Exception ex) {
273 LOG.error("Exception in handleSNATForDPN method : {}", ex);
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.getPrimaryNaptfromRouterId(dataBroker, routerId);
294 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
295 LOG.debug("No naptSwitch is selected for router {}", routerName);
299 boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache);
301 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
303 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
304 FlowEntity flowEntity = null;
306 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
307 if (flowEntity == null) {
308 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
311 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
312 mdsalManager.removeFlow(flowEntity);
314 } catch (Exception ex) {
315 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
318 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
321 GroupEntity groupEntity = null;
323 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
324 GroupTypes.GroupAll, null);
325 LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
326 mdsalManager.removeGroup(groupEntity);
327 } catch (Exception ex) {
328 LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
331 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
333 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch,externalIpLabel);
334 //remove table 26 flow ppointing to table46
335 FlowEntity flowEntity = null;
337 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
338 if (flowEntity == null) {
339 LOG.debug("Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
342 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
343 ,routerName,dpnId,naptSwitch);
344 mdsalManager.removeFlow(flowEntity);
346 } catch (Exception ex) {
347 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
350 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
352 //best effort to check IntExt model
353 naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
355 } catch (Exception ex) {
356 LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);