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.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.genius.idmanager.rev160406.IdManagerService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
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 public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
37 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
38 private ListenerRegistration<DataChangeListener> listenerRegistration;
39 private final DataBroker dataBroker;
40 private final IMdsalApiManager mdsalManager;
41 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
42 private final NaptSwitchHA naptSwitchHA;
43 private final IdManagerService idManager;
44 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
46 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
47 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
48 final NaptSwitchHA naptSwitchHA,
49 final IdManagerService idManager,
50 final ExternalNetworkGroupInstaller extNetGroupInstaller) {
51 super(DpnVpninterfacesList.class);
52 this.dataBroker = dataBroker;
53 this.mdsalManager = mdsalManager;
54 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
55 this.naptSwitchHA = naptSwitchHA;
56 this.idManager = idManager;
57 this.extNetGroupInstaller = extNetGroupInstaller;
61 LOG.info("{} init", getClass().getSimpleName());
62 listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
63 getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
66 private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
67 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
71 public void close() throws Exception {
72 if (listenerRegistration != null) {
73 listenerRegistration.close();
74 listenerRegistration = null;
76 LOG.info("{} close", getClass().getSimpleName());
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 {}...", dpnId,routerId,vpnId);
103 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
105 LOG.debug("External BGP vpn associated to router {}",routerId);
106 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
107 if (vpnId == NatConstants.INVALID_ID) {
108 LOG.error("Invalid vpnId returned for routerName {}", routerId);
111 Long routId = NatUtil.getVpnId(dataBroker, routerId);
112 if (routId == NatConstants.INVALID_ID) {
113 LOG.error("Invalid routId returned for routerName {}",routerId);
116 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
117 //Install default entry in FIB to SNAT table
118 LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
119 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
121 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
123 if (routerData.get().isEnableSnat()) {
124 LOG.info("SNAT enabled for router {}", routerId);
125 handleSNATForDPN(dpnId, routerId ,vpnId);
127 LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
131 LOG.debug("Router {} is not associated with External network", routerId);
136 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
137 LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
138 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
139 BigInteger dpnId = dpnInfo.getDpnId();
140 //check router is associated to external network
141 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
142 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
143 if (routerData.isPresent()) {
144 Uuid networkId = routerData.get().getNetworkId();
145 if (networkId != null) {
146 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
147 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
149 if (vpnName == null) {
150 LOG.debug("Internal vpn associated to router {}", routerId);
151 vpnId = NatUtil.getVpnId(dataBroker, routerId);
152 if (vpnId == NatConstants.INVALID_ID) {
153 LOG.error("Invalid vpnId returned for routerName {}", routerId);
156 LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
157 //Remove default entry in FIB
158 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
159 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
161 LOG.debug("External vpn associated to router {}", routerId);
162 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
163 if (vpnId == NatConstants.INVALID_ID) {
164 LOG.error("Invalid vpnId returned for routerName {}", routerId);
167 Long routId = NatUtil.getVpnId(dataBroker, routerId);
168 if (routId == NatConstants.INVALID_ID) {
169 LOG.error("Invalid routId 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 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
178 if (routerData.get().isEnableSnat()) {
179 LOG.info("SNAT enabled for router {}", routerId);
180 removeSNATFromDPN(dpnId, routerId, vpnId);
182 LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
189 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
190 LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
192 void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
193 //Check if primary and secondary switch are selected, If not select the role
194 //Install select group to NAPT switch
195 //Install default miss entry to NAPT switch
196 BigInteger naptSwitch;
198 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
199 if (routerId == NatConstants.INVALID_ID) {
200 LOG.error("Invalid routerId returned for routerName {}", routerName);
203 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
204 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
205 LOG.debug("No NaptSwitch is selected for router {}", routerName);
208 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
210 LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
213 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
215 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
217 // Install miss entry (table 26) pointing to table 46
218 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.ADD_FLOW);
219 if (flowEntity == null) {
220 LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
223 LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
224 mdsalManager.installFlow(flowEntity);
225 //Removing primary flows from old napt switch
226 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
227 LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
228 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
230 } else if (naptId.equals(dpnId)) {
231 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
234 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
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,
244 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
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);
253 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
254 mdsalManager.installFlow(flowEntity);
256 } catch (Exception ex) {
257 LOG.error("Exception in handleSNATForDPN method : {}", ex);
261 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
262 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
263 //remove miss entry to NAPT switch
264 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
266 //get ExternalIpIn prior
267 List<String> externalIpCache;
269 HashMap<String,Long> externalIpLabel;
270 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
271 if (routerId == NatConstants.INVALID_ID) {
272 LOG.error("Invalid routerId returned for routerName {}",routerName);
275 externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
276 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker,routerId);
277 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
278 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
279 LOG.debug("No naptSwitch is selected for router {}", routerName);
283 boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache);
285 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
287 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
288 FlowEntity flowEntity = null;
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);
295 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
296 mdsalManager.removeFlow(flowEntity);
298 } catch (Exception ex) {
299 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
302 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
305 GroupEntity groupEntity = null;
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);
315 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
317 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch,externalIpLabel);
318 //remove table 26 flow ppointing to table46
319 FlowEntity flowEntity = null;
321 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
322 if (flowEntity == null) {
323 LOG.debug("Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
326 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
327 ,routerName,dpnId,naptSwitch);
328 mdsalManager.removeFlow(flowEntity);
330 } catch (Exception ex) {
331 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
334 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
336 //best effort to check IntExt model
337 naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
339 } catch (Exception ex) {
340 LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);