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