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