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.ExternalSubnets;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
33 import org.opendaylight.yangtools.concepts.ListenerRegistration;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public class RouterDpnChangeListener
39 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
40 implements AutoCloseable {
42 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
43 private ListenerRegistration<DataChangeListener> listenerRegistration;
44 private final DataBroker dataBroker;
45 private final IMdsalApiManager mdsalManager;
46 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
47 private final NaptSwitchHA naptSwitchHA;
48 private final IdManagerService idManager;
49 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
51 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
52 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
53 final NaptSwitchHA naptSwitchHA,
54 final IdManagerService idManager,
55 final ExternalNetworkGroupInstaller extNetGroupInstaller) {
56 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
57 this.dataBroker = dataBroker;
58 this.mdsalManager = mdsalManager;
59 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
60 this.naptSwitchHA = naptSwitchHA;
61 this.idManager = idManager;
62 this.extNetGroupInstaller = extNetGroupInstaller;
67 LOG.info("{} init", getClass().getSimpleName());
68 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
72 protected RouterDpnChangeListener getDataTreeChangeListener() {
73 return RouterDpnChangeListener.this;
77 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
78 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
79 .child(DpnVpninterfacesList.class);
83 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
84 LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
85 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
86 BigInteger dpnId = dpnInfo.getDpnId();
87 //check router is associated to external network
88 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
89 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
90 if (routerData.isPresent()) {
91 Routers router = routerData.get();
92 Uuid networkId = router.getNetworkId();
93 if (networkId != null) {
94 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
95 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
97 if (vpnName == null) {
98 LOG.debug("Internal vpn associated to router {}", routerId);
99 vpnId = NatUtil.getVpnId(dataBroker, routerId);
100 if (vpnId == NatConstants.INVALID_ID) {
101 LOG.error("Invalid vpnId returned for routerName {}", routerId);
104 LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
105 //Install default entry in FIB to SNAT table
106 LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...",
107 dpnId, routerId, vpnId);
108 installDefaultNatRouteForRouterExternalSubnets(dpnId,
109 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
110 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
112 LOG.debug("External BGP vpn associated to router {}", routerId);
113 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
114 if (vpnId == NatConstants.INVALID_ID) {
115 LOG.error("Invalid vpnId returned for routerName {}", routerId);
118 Long routId = NatUtil.getVpnId(dataBroker, routerId);
119 if (routId == NatConstants.INVALID_ID) {
120 LOG.error("Invalid routId returned for routerName {}", routerId);
123 LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
124 //Install default entry in FIB to SNAT table
125 LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...",
126 dpnId, routerId, vpnId);
127 installDefaultNatRouteForRouterExternalSubnets(dpnId,
128 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
129 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
131 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
133 if (router.isEnableSnat()) {
134 LOG.info("SNAT enabled for router {}", routerId);
135 handleSNATForDPN(dpnId, routerId, vpnId);
137 LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
141 LOG.debug("Router {} is not associated with External network", routerId);
146 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
147 LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
148 final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
149 BigInteger dpnId = dpnInfo.getDpnId();
150 //check router is associated to external network
151 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
152 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
153 if (routerData.isPresent()) {
154 Routers router = routerData.get();
155 Uuid networkId = router.getNetworkId();
156 if (networkId != null) {
157 LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
158 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
160 if (vpnName == null) {
161 LOG.debug("Internal vpn associated to router {}", routerId);
162 vpnId = NatUtil.getVpnId(dataBroker, routerId);
163 if (vpnId == NatConstants.INVALID_ID) {
164 LOG.error("Invalid vpnId returned for routerName {}", routerId);
167 LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
168 //Remove default entry in FIB
169 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
170 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
172 LOG.debug("External vpn associated to router {}", routerId);
173 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
174 if (vpnId == NatConstants.INVALID_ID) {
175 LOG.error("Invalid vpnId returned for routerName {}", routerId);
178 Long routId = NatUtil.getVpnId(dataBroker, routerId);
179 if (routId == NatConstants.INVALID_ID) {
180 LOG.error("Invalid routId returned for routerName {}", routerId);
183 LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
184 //Remove default entry in FIB
185 LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
186 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routId);
189 if (router.isEnableSnat()) {
190 LOG.info("SNAT enabled for router {}", routerId);
191 removeSNATFromDPN(dpnId, routerId, vpnId);
193 LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
200 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
201 DpnVpninterfacesList update) {
202 LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
205 // TODO Clean up the exception handling
206 @SuppressWarnings("checkstyle:IllegalCatch")
207 void handleSNATForDPN(BigInteger dpnId, String routerName, Long routerVpnId) {
208 //Check if primary and secondary switch are selected, If not select the role
209 //Install select group to NAPT switch
210 //Install default miss entry to NAPT switch
211 BigInteger naptSwitch;
213 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
214 if (routerId == NatConstants.INVALID_ID) {
215 LOG.error("Invalid routerId returned for routerName {}", routerName);
218 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
219 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
220 LOG.debug("No NaptSwitch is selected for router {}", routerName);
223 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
225 LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
228 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
230 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
231 if (extRouters != null) {
232 NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
233 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
235 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
237 // Install miss entry (table 26) pointing to table 46
238 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
239 routerVpnId, NatConstants.ADD_FLOW);
240 if (flowEntity == null) {
241 LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
244 LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
245 mdsalManager.installFlow(flowEntity);
246 //Removing primary flows from old napt switch
247 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
248 LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
249 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
251 } else if (naptId.equals(dpnId)) {
252 LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
255 LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
259 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
260 if (bucketInfo == null) {
261 LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}",
262 dpnId, routerName, naptSwitch);
265 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
267 // Install miss entry (table 26) pointing to group
268 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
269 FlowEntity flowEntity =
270 naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
271 if (flowEntity == null) {
272 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}",
273 routerName, dpnId, groupId);
276 LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
277 mdsalManager.installFlow(flowEntity);
279 } catch (Exception ex) {
280 LOG.error("Exception in handleSNATForDPN method : {}", ex);
284 // TODO Clean up the exception handling
285 @SuppressWarnings("checkstyle:IllegalCatch")
286 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
287 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
288 //remove miss entry to NAPT switch
289 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
291 //get ExternalIpIn prior
292 List<String> externalIpCache;
294 HashMap<String, Long> externalIpLabel;
295 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
296 if (routerId == NatConstants.INVALID_ID) {
297 LOG.error("Invalid routerId returned for routerName {}", routerName);
300 externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
301 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
302 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
303 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
304 LOG.debug("No naptSwitch is selected for router {}", routerName);
309 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache);
311 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
313 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
314 FlowEntity flowEntity = null;
316 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
317 NatConstants.DEL_FLOW);
318 if (flowEntity == null) {
319 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",
320 routerName, dpnId, groupId);
323 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}", flowEntity);
324 mdsalManager.removeFlow(flowEntity);
326 } catch (Exception ex) {
327 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
331 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
335 GroupEntity groupEntity = null;
337 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
338 GroupTypes.GroupAll, null);
339 LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
340 mdsalManager.removeGroup(groupEntity);
341 } catch (Exception ex) {
342 LOG.debug("NAT Service : Failed to remove group entity {} : {}", groupEntity, ex);
345 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
348 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel);
349 //remove table 26 flow ppointing to table46
350 FlowEntity flowEntity = null;
352 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
353 NatConstants.DEL_FLOW);
354 if (flowEntity == null) {
355 LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
358 LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with "
359 + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
360 mdsalManager.removeFlow(flowEntity);
362 } catch (Exception ex) {
363 LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
367 LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
370 //best effort to check IntExt model
371 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
373 } catch (Exception ex) {
374 LOG.debug("Exception while handling naptSwitch down for router {} : {}", routerName, ex);
378 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, List<Uuid> externalSubnetIds) {
379 if (externalSubnetIds == null) {
380 LOG.debug("NAT Service : No external subnets for router");
384 for (Uuid subnetId : externalSubnetIds) {
385 InstanceIdentifier<Subnets> subnetsIdentifier = InstanceIdentifier.create(ExternalSubnets.class)
386 .child(Subnets.class, new SubnetsKey(subnetId));
387 Optional<Subnets> externalSubnet = NatUtil.read(dataBroker,
388 LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
389 if (externalSubnet.isPresent()) {
390 long vpnIdForSubnet = NatUtil.getVpnId(dataBroker, externalSubnet.get().getVpnId().getValue());
391 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
392 LOG.debug("NAT Service : Installing default routes in FIB on dpn {} for subnetId {} with vpnId {}",
393 dpnId, subnetId, vpnIdForSubnet);
394 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet,
395 subnetId.getValue(), idManager);
397 LOG.debug("NAT Service : No VPN ID for subnetId {}, cannot installing default routes flows in FIB",
401 LOG.warn("NAT Service : No external subnet found for Uuid {}", subnetId);