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