Remove DS operation part of Yang Consumer Thread
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatVpnMapsChangeListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.natservice.internal;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.netvirt.natservice.internal.NatUtil.requireNonNullElse;
12
13 import com.google.common.base.Optional;
14 import java.math.BigInteger;
15 import java.util.Collections;
16 import java.util.Objects;
17 import java.util.concurrent.ExecutionException;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 @Singleton
39 public class NatVpnMapsChangeListener extends AsyncDataTreeChangeListenerBase<VpnMap, NatVpnMapsChangeListener> {
40     private static final Logger LOG = LoggerFactory.getLogger(NatVpnMapsChangeListener.class);
41     private final DataBroker dataBroker;
42     private final ManagedNewTransactionRunner txRunner;
43     private final FloatingIPListener floatingIpListener;
44     private final OdlInterfaceRpcService interfaceManager;
45     private final ExternalRoutersListener externalRoutersListener;
46
47     @Inject
48     public NatVpnMapsChangeListener(final DataBroker dataBroker,
49                                final FloatingIPListener floatingIpListener,
50                                final OdlInterfaceRpcService interfaceManager,
51                                final ExternalRoutersListener externalRoutersListener) {
52         super(VpnMap.class, NatVpnMapsChangeListener.class);
53         this.dataBroker = dataBroker;
54         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
55         this.floatingIpListener = floatingIpListener;
56         this.interfaceManager = interfaceManager;
57         this.externalRoutersListener = externalRoutersListener;
58     }
59
60     public void init() {
61         LOG.info("{} init", getClass().getSimpleName());
62         registerListener(dataBroker);
63     }
64
65     @Override
66     protected InstanceIdentifier<VpnMap> getWildCardPath() {
67         return InstanceIdentifier.create(VpnMaps.class).child(VpnMap.class);
68     }
69
70     private void registerListener(final DataBroker db) {
71         registerListener(LogicalDatastoreType.CONFIGURATION, db);
72     }
73
74     @Override
75     protected void add(InstanceIdentifier<VpnMap> identifier, VpnMap vpnMap) {
76         Uuid vpnUuid = vpnMap.getVpnId();
77         String vpnName = vpnUuid.getValue();
78         vpnMap.getRouterIds().stream()
79                 .filter(router -> !(Objects.equals(router.getRouterId(), vpnUuid)))
80                 .forEach(router -> {
81                     String routerName = router.getRouterId().getValue();
82                     LOG.info("REMOVE: Router {} is disassociated from Vpn {}", routerName, vpnName);
83                     onRouterAssociatedToVpn(vpnName, routerName);
84                 });
85     }
86
87     @Override
88     protected void remove(InstanceIdentifier<VpnMap> identifier, VpnMap vpnMap) {
89         Uuid vpnUuid = vpnMap.getVpnId();
90         String vpnName = vpnUuid.getValue();
91         vpnMap.getRouterIds().stream()
92                 .filter(router -> !(Objects.equals(router.getRouterId(), vpnUuid)))
93                 .forEach(router -> {
94                     String routerName = router.getRouterId().getValue();
95                     LOG.info("REMOVE: Router {} is disassociated from Vpn {}", routerName, vpnName);
96                     onRouterDisassociatedFromVpn(vpnName, routerName);
97                 });
98     }
99
100     @Override
101     protected void update(InstanceIdentifier<VpnMap> identifier, VpnMap original, VpnMap updated) {
102         Uuid vpnUuid = updated.getVpnId();
103         String vpnName = vpnUuid.getValue();
104
105         updated.getRouterIds().stream()
106                 .filter(router -> ! original.getRouterIds().contains(router))
107                 .filter(router -> !(Objects.equals(router.getRouterId(), updated.getVpnId())))
108                 .forEach(router -> {
109                     String routerName = router.getRouterId().getValue();
110                     onRouterAssociatedToVpn(vpnName, routerName);
111                 });
112
113         original.getRouterIds().stream()
114                 .filter(router -> ! updated.getRouterIds().contains(router))
115                 .filter(router -> !(Objects.equals(router.getRouterId(), original.getVpnId())))
116                 .forEach(router -> {
117                     String routerName = router.getRouterId().getValue();
118                     onRouterDisassociatedFromVpn(vpnName, routerName);
119                 });
120     }
121
122     @Override
123     protected NatVpnMapsChangeListener getDataTreeChangeListener() {
124         return this;
125     }
126
127     public void onRouterAssociatedToVpn(String vpnName, String routerName) {
128
129         //check router is associated to external network
130         String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
131         if (extNetwork != null) {
132             try {
133                 LOG.debug("onRouterAssociatedToVpn : Router {} is associated with ext nw {}", routerName, extNetwork);
134                 handleDNATConfigurationForRouterAssociation(routerName, vpnName, extNetwork);
135                 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
136                 if (extNetworkUuid == null) {
137                     LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
138                             routerName);
139                     return;
140                 }
141                 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
142                         extNetworkUuid);
143                 if (extNwProvType == null) {
144                     LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
145                     return;
146                 }
147                 long routerId = NatUtil.getVpnId(dataBroker, routerName);
148                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
149                     tx -> externalRoutersListener.changeLocalVpnIdToBgpVpnId(routerName, routerId, vpnName, tx,
150                                 extNwProvType)).get();
151             } catch (InterruptedException | ExecutionException e) {
152                 LOG.error("Error changling local VPN identifier to BGP VPN identifier", e);
153             }
154         } else {
155             LOG.debug("onRouterAssociatedToVpn : Ignoring the Router {} association with VPN {} "
156                     + "since it is not external router", routerName, vpnName);
157         }
158     }
159
160     /**
161      * router disassociation from vpn.
162      */
163
164     public void onRouterDisassociatedFromVpn(String vpnName, String routerName) {
165
166         //check router is associated to external network
167         String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
168         if (extNetwork != null) {
169             try {
170                 LOG.debug("onRouterDisassociatedFromVpn : Router {} is associated with ext nw {}", routerName,
171                         extNetwork);
172                 handleDNATConfigurationForRouterDisassociation(routerName, vpnName, extNetwork);
173                 Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
174                 if (extNetworkUuid == null) {
175                     LOG.error("onRouterDisassociatedFromVpn : Unable to retrieve external network Uuid for router {}",
176                             routerName);
177                     return;
178                 }
179                 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
180                         extNetworkUuid);
181                 if (extNwProvType == null) {
182                     LOG.error("onRouterDisassociatedFromVpn : External Network Provider Type missing");
183                     return;
184                 }
185                 long routerId = NatUtil.getVpnId(dataBroker, routerName);
186                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
187                     tx -> externalRoutersListener.changeBgpVpnIdToLocalVpnId(routerName, routerId, vpnName, tx,
188                                 extNwProvType)).get();
189             } catch (InterruptedException | ExecutionException e) {
190                 LOG.error("Error changing BGP VPN identifier to local VPN identifier", e);
191             }
192         } else {
193             LOG.debug("onRouterDisassociatedFromVpn : Ignoring the Router {} association with VPN {} "
194                     + "since it is not external router", routerName, vpnName);
195         }
196     }
197
198     void handleDNATConfigurationForRouterAssociation(String routerName, String vpnName, String externalNetwork)
199             throws ExecutionException, InterruptedException {
200         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
201         Optional<RouterPorts> optRouterPorts =
202                 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
203         if (!optRouterPorts.isPresent()) {
204             LOG.debug("handleDNATConfigurationForRouterAssociation : Could not read Router Ports data "
205                     + "object with id: {} to handle associate vpn {}", routerName, vpnName);
206             return;
207         }
208         Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
209         for (Ports port : requireNonNullElse(optRouterPorts.get().getPorts(), Collections.<Ports>emptyList())) {
210             String portName = port.getPortName();
211             BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
212             if (dpnId.equals(BigInteger.ZERO)) {
213                 LOG.warn("handleDNATConfigurationForRouterAssociation : DPN not found for {}, "
214                         + "skip handling of router {} association with vpn {}", portName, routerName, vpnName);
215                 continue;
216             }
217
218             for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
219                     Collections.<InternalToExternalPortMap>emptyList())) {
220                 //remove all NAT related entries with routerName
221                 //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, null,
222                 // intExtPortMap.getInternalIp(), externalIp);
223                 //Create NAT entries with VPN Id
224                 LOG.debug("handleDNATConfigurationForRouterAssociation : Updating DNAT flows with VPN metadata {} ",
225                         vpnName);
226                 floatingIpListener.createNATOnlyFlowEntries(dpnId, routerName, vpnName, networkId, intExtPortMap);
227             }
228         }
229     }
230
231     void handleDNATConfigurationForRouterDisassociation(String routerName, String vpnName, String externalNetwork)
232             throws ExecutionException, InterruptedException {
233         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
234         Optional<RouterPorts> optRouterPorts =
235                 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
236         if (!optRouterPorts.isPresent()) {
237             LOG.error("handleDNATConfigurationForRouterDisassociation : Could not read Router Ports "
238                     + "data object with id: {} to handle disassociate vpn {}", routerName, vpnName);
239             return;
240         }
241         Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
242         for (Ports port : requireNonNullElse(optRouterPorts.get().getPorts(), Collections.<Ports>emptyList())) {
243             String portName = port.getPortName();
244             BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
245             if (dpnId.equals(BigInteger.ZERO)) {
246                 LOG.debug("handleDNATConfigurationForRouterDisassociation : DPN not found for {}, "
247                         + "skip handling of router {} association with vpn {}", portName, routerName, vpnName);
248                 continue;
249             }
250             for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
251                     Collections.<InternalToExternalPortMap>emptyList())) {
252                 //remove all NAT related entries with routerName
253                 //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, vpnName,
254                 // intExtPortMap.getInternalIp(), externalIp);
255                 //Create NAT entries with VPN Id
256                 floatingIpListener.createNATOnlyFlowEntries(dpnId, routerName, null, networkId, intExtPortMap);
257             }
258         }
259     }
260
261 }