c8367f09a1fec60e339e176c9a108bc6406baebb
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / CentralizedSwitchChangeListener.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.netvirt.vpnmanager;
10
11 import java.math.BigInteger;
12 import java.util.List;
13 import java.util.Objects;
14 import java.util.concurrent.ExecutionException;
15 import javax.annotation.PostConstruct;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
26 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * CentralizedSwitchChangeListener detect changes in switch:router mapping and
38  * update flows accordingly.<br>
39  * The centralized switch a.k.a NAPT switch is currently defined using models
40  * residing in natservice bundle. As the roles of centralized switch will grow
41  * beyond NAT use cases, the associated models and logic need to be renamed
42  * and moved to either vpnmanager or new bundle as part of Carbon model changes
43  *
44  */
45 @Singleton
46 public class CentralizedSwitchChangeListener
47         extends AsyncDataTreeChangeListenerBase<RouterToNaptSwitch, CentralizedSwitchChangeListener> {
48
49     private static final Logger LOG = LoggerFactory.getLogger(CentralizedSwitchChangeListener.class);
50
51     private final DataBroker dataBroker;
52     private final ManagedNewTransactionRunner txRunner;
53     private final IVpnManager vpnManager;
54     private final ExternalRouterDataUtil externalRouterDataUtil;
55     private final VpnUtil vpnUtil;
56
57     @Inject
58     public CentralizedSwitchChangeListener(final DataBroker dataBroker, final IVpnManager vpnManager,
59             final ExternalRouterDataUtil externalRouterDataUtil, final VpnUtil vpnUtil) {
60         super(RouterToNaptSwitch.class, CentralizedSwitchChangeListener.class);
61         this.dataBroker = dataBroker;
62         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
63         this.vpnManager = vpnManager;
64         this.externalRouterDataUtil = externalRouterDataUtil;
65         this.vpnUtil = vpnUtil;
66     }
67
68     @Override
69     @PostConstruct
70     public void init() {
71         LOG.info("{} init", getClass().getSimpleName());
72         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
73     }
74
75     @Override
76     protected InstanceIdentifier<RouterToNaptSwitch> getWildCardPath() {
77         return InstanceIdentifier.create(NaptSwitches.class).child(RouterToNaptSwitch.class);
78     }
79
80     @Override
81     protected void remove(InstanceIdentifier<RouterToNaptSwitch> key, RouterToNaptSwitch routerToNaptSwitch) {
82         LOG.debug("Removing {}", routerToNaptSwitch);
83         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
84                         setupRouterGwFlows(routerToNaptSwitch, tx, NwConstants.DEL_FLOW)), LOG,
85                 "Error processing switch removal for {}", routerToNaptSwitch);
86     }
87
88     @Override
89     protected void update(InstanceIdentifier<RouterToNaptSwitch> key, RouterToNaptSwitch origRouterToNaptSwitch,
90             RouterToNaptSwitch updatedRouterToNaptSwitch) {
91         LOG.debug("Updating old {} new {}", origRouterToNaptSwitch, updatedRouterToNaptSwitch);
92         if (!Objects.equals(updatedRouterToNaptSwitch.getPrimarySwitchId(),
93                 origRouterToNaptSwitch.getPrimarySwitchId())) {
94             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
95                 setupRouterGwFlows(origRouterToNaptSwitch, tx, NwConstants.DEL_FLOW);
96                 setupRouterGwFlows(updatedRouterToNaptSwitch, tx, NwConstants.ADD_FLOW);
97             }), LOG, "Error updating switch {} to {}", origRouterToNaptSwitch, updatedRouterToNaptSwitch);
98         }
99     }
100
101     @Override
102     protected void add(InstanceIdentifier<RouterToNaptSwitch> key, RouterToNaptSwitch routerToNaptSwitch) {
103         LOG.debug("Adding {}", routerToNaptSwitch);
104         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
105                         setupRouterGwFlows(routerToNaptSwitch, tx, NwConstants.ADD_FLOW)), LOG,
106                 "Error processing switch addition for {}", routerToNaptSwitch);
107     }
108
109     @Override
110     protected CentralizedSwitchChangeListener getDataTreeChangeListener() {
111         return this;
112     }
113
114     private void setupRouterGwFlows(RouterToNaptSwitch routerToNaptSwitch, WriteTransaction writeTx, int addOrRemove)
115             throws ExecutionException, InterruptedException {
116         Routers router = null;
117         if (addOrRemove == NwConstants.ADD_FLOW) {
118             router = vpnUtil.getExternalRouter(routerToNaptSwitch.getRouterName());
119         }
120         else {
121             router = externalRouterDataUtil.getRouter(routerToNaptSwitch.getRouterName());
122         }
123         if (router == null) {
124             LOG.warn("No router data found for router id {}", routerToNaptSwitch.getRouterName());
125             return;
126         }
127
128         BigInteger primarySwitchId = routerToNaptSwitch.getPrimarySwitchId();
129         Uuid extNetworkId = router.getNetworkId();
130         String extGwMacAddress = router.getExtGwMacAddress();
131         String routerName = router.getRouterName();
132         List<ExternalIps> externalIps = router.getExternalIps();
133         if (externalIps.isEmpty()) {
134             LOG.error("CentralizedSwitchChangeListener: setupRouterGwFlows no externalIP present");
135             return;
136         }
137
138         for (ExternalIps extIp: router.getExternalIps()) {
139             Uuid subnetVpnName = extIp.getSubnetId();
140             if (addOrRemove == NwConstants.ADD_FLOW) {
141                 vpnManager.addRouterGwMacFlow(routerName, extGwMacAddress, primarySwitchId, extNetworkId,
142                         subnetVpnName.getValue(), writeTx);
143                 externalRouterDataUtil.addtoRouterMap(router);
144             } else {
145                 vpnManager.removeRouterGwMacFlow(routerName, extGwMacAddress, primarySwitchId, extNetworkId,
146                         subnetVpnName.getValue(), writeTx);
147                 externalRouterDataUtil.removeFromRouterMap(router);
148             }
149         }
150
151         if (addOrRemove == NwConstants.ADD_FLOW) {
152             vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
153                     VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
154                     extGwMacAddress, primarySwitchId, extNetworkId, writeTx);
155         } else {
156             vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
157                     VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
158                     extGwMacAddress, primarySwitchId, extNetworkId);
159         }
160     }
161 }