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