339af486b29b86630d459585f0ef926d6cba30e3
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronSubnetChangeListener.java
1 /*
2  * Copyright (c) 2016, 2017 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.neutronvpn;
9
10 import com.google.common.base.Optional;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Set;
14 import javax.annotation.PostConstruct;
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.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 @Singleton
41 public class NeutronSubnetChangeListener extends AsyncDataTreeChangeListenerBase<Subnet, NeutronSubnetChangeListener> {
42     private static final Logger LOG = LoggerFactory.getLogger(NeutronSubnetChangeListener.class);
43     private final DataBroker dataBroker;
44     private final NeutronvpnManager nvpnManager;
45     private final NeutronExternalSubnetHandler externalSubnetHandler;
46     private final NeutronvpnUtils neutronvpnUtils;
47     private final IVpnManager vpnManager;
48
49     @Inject
50     public NeutronSubnetChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
51             final NeutronExternalSubnetHandler externalSubnetHandler, final NeutronvpnUtils neutronvpnUtils,
52                                        final IVpnManager vpnManager) {
53         super(Subnet.class, NeutronSubnetChangeListener.class);
54         this.dataBroker = dataBroker;
55         this.nvpnManager = neutronvpnManager;
56         this.externalSubnetHandler = externalSubnetHandler;
57         this.neutronvpnUtils = neutronvpnUtils;
58         this.vpnManager = vpnManager;
59     }
60
61     @Override
62     @PostConstruct
63     public void init() {
64         LOG.info("{} init", getClass().getSimpleName());
65         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
66     }
67
68     @Override
69     protected InstanceIdentifier<Subnet> getWildCardPath() {
70         return InstanceIdentifier.create(Neutron.class).child(Subnets.class).child(Subnet.class);
71     }
72
73     @Override
74     protected NeutronSubnetChangeListener getDataTreeChangeListener() {
75         return NeutronSubnetChangeListener.this;
76     }
77
78
79     @Override
80     protected void add(InstanceIdentifier<Subnet> identifier, Subnet input) {
81         LOG.trace("Adding Subnet : key: {}, value={}", identifier, input);
82         Uuid networkId = input.getNetworkId();
83         Uuid subnetId = input.getUuid();
84         Network network = neutronvpnUtils.getNeutronNetwork(networkId);
85         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
86             LOG.warn("neutron vpn received a subnet add() for a network without a provider extension augmentation "
87                             + "or with an unsupported network type for the subnet {} which is part of network {}",
88                     subnetId.getValue(), network);
89             return;
90         }
91         neutronvpnUtils.addToSubnetCache(input);
92         handleNeutronSubnetCreated(input, network);
93         externalSubnetHandler.handleExternalSubnetAdded(network, subnetId, null);
94     }
95
96     @Override
97     protected void remove(InstanceIdentifier<Subnet> identifier, Subnet input) {
98         LOG.trace("Removing subnet : key: {}, value={}", identifier, input);
99         Uuid networkId = input.getNetworkId();
100         Uuid subnetId = input.getUuid();
101         Network network = neutronvpnUtils.getNeutronNetwork(networkId);
102         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
103             LOG.warn("neutron vpn received a subnet remove() for a network without a provider extension augmentation "
104                             + "or with an unsupported network type for the subnet {} which is part of network {}",
105                     subnetId.getValue(), network);
106             return;
107         }
108         handleNeutronSubnetDeleted(subnetId, networkId, input.getCidr().stringValue());
109         externalSubnetHandler.handleExternalSubnetRemoved(network, subnetId);
110         neutronvpnUtils.removeFromSubnetCache(input);
111     }
112
113     @Override
114     protected void update(InstanceIdentifier<Subnet> identifier, Subnet original, Subnet update) {
115         LOG.trace("Updating Subnet : key: {}, original value={}, update value={}", identifier, original, update);
116         neutronvpnUtils.addToSubnetCache(update);
117     }
118
119     private void handleNeutronSubnetCreated(Subnet subnet, Network network) {
120         Uuid networkId = network.getUuid();
121         Uuid subnetId = subnet.getUuid();
122         ProviderTypes providerType = NeutronvpnUtils.getProviderNetworkType(network);
123         String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(network);
124         boolean isExternalNetwork = NeutronvpnUtils.getIsExternal(network);
125         nvpnManager.createSubnetmapNode(subnetId, subnet.getCidr().stringValue(), subnet.getTenantId(), networkId,
126                 providerType != null ? NetworkAttributes.NetworkType.valueOf(providerType.getName()) : null,
127                 segmentationId != null ? Long.parseLong(segmentationId) : 0L, isExternalNetwork);
128         createSubnetToNetworkMapping(subnetId, networkId);
129     }
130
131     private void handleNeutronSubnetDeleted(Uuid subnetId, Uuid networkId, String subnetCidr) {
132         Uuid vpnId = neutronvpnUtils.getVpnForNetwork(networkId);
133         if (vpnId != null) {
134             LOG.warn("Subnet {} deleted without disassociating network {} from VPN {}. Ideally, please disassociate "
135                     + "network from VPN before deleting neutron subnet.", subnetId.getValue(), networkId.getValue(),
136                     vpnId.getValue());
137             Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
138             if (subnetmap != null) {
139                 nvpnManager.removeSubnetFromVpn(vpnId, subnetId, null /* internet-vpn-id */);
140             } else {
141                 LOG.error("Subnetmap for subnet {} not found", subnetId.getValue());
142             }
143             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
144             if (!routeTargets.isEmpty()) {
145                 vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetCidr, subnetId.getValue());
146             }
147         }
148         if (networkId != null) {
149             deleteSubnetToNetworkMapping(subnetId, networkId);
150         }
151         nvpnManager.deleteSubnetMapNode(subnetId);
152     }
153
154     // TODO Clean up the exception handling
155     @SuppressWarnings("checkstyle:IllegalCatch")
156     private void createSubnetToNetworkMapping(Uuid subnetId, Uuid networkId) {
157         try {
158             InstanceIdentifier<NetworkMap>  networkMapIdentifier = NeutronvpnUtils.buildNetworkMapIdentifier(networkId);
159             Optional<NetworkMap> optionalNetworkMap = SingleTransactionDataBroker.syncReadOptional(dataBroker,
160                     LogicalDatastoreType.CONFIGURATION, networkMapIdentifier);
161             NetworkMapBuilder nwMapBuilder;
162             if (optionalNetworkMap.isPresent()) {
163                 nwMapBuilder = new NetworkMapBuilder(optionalNetworkMap.get());
164             } else {
165                 nwMapBuilder = new NetworkMapBuilder().withKey(new NetworkMapKey(networkId)).setNetworkId(networkId);
166                 LOG.debug("Adding a new network node in NetworkMaps DS for network {}", networkId.getValue());
167             }
168             List<Uuid> subnetIdList = nwMapBuilder.getSubnetIdList() != null
169                     ? new ArrayList<>(nwMapBuilder.getSubnetIdList()) : new ArrayList<>();
170             subnetIdList.add(subnetId);
171             nwMapBuilder.setSubnetIdList(subnetIdList);
172             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier, nwMapBuilder
173                     .build());
174             LOG.debug("Created subnet-network mapping for subnet {} network {}", subnetId.getValue(),
175                     networkId.getValue());
176         } catch (ReadFailedException | RuntimeException e) {
177             LOG.error("Create subnet-network mapping failed for subnet {} network {}", subnetId.getValue(),
178                     networkId.getValue());
179         }
180     }
181
182     // TODO Clean up the exception handling
183     @SuppressWarnings("checkstyle:IllegalCatch")
184     private void deleteSubnetToNetworkMapping(Uuid subnetId, Uuid networkId) {
185         try {
186             InstanceIdentifier<NetworkMap>  networkMapIdentifier = NeutronvpnUtils.buildNetworkMapIdentifier(networkId);
187             Optional<NetworkMap> optionalNetworkMap = SingleTransactionDataBroker.syncReadOptional(dataBroker,
188                     LogicalDatastoreType.CONFIGURATION, networkMapIdentifier);
189             if (optionalNetworkMap.isPresent()) {
190                 NetworkMapBuilder nwMapBuilder = new NetworkMapBuilder(optionalNetworkMap.get());
191                 List<Uuid> subnetIdList = new ArrayList<>(nwMapBuilder.getSubnetIdList());
192                 if (subnetIdList.remove(subnetId)) {
193                     if (subnetIdList.isEmpty()) {
194                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier);
195                         LOG.debug("Deleted network node in NetworkMaps DS for subnet {} network {}",
196                                 subnetId.getValue(), networkId.getValue());
197                     } else {
198                         nwMapBuilder.setSubnetIdList(subnetIdList);
199                         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier,
200                                 nwMapBuilder.build());
201                         LOG.debug("Deleted subnet-network mapping for subnet {} network {}", subnetId.getValue(),
202                                 networkId.getValue());
203                     }
204                 } else {
205                     LOG.error("Subnet {} is not mapped to network {}", subnetId.getValue(), networkId.getValue());
206                 }
207             } else {
208                 LOG.error("network {} not present for subnet {} ", networkId, subnetId);
209             }
210         } catch (ReadFailedException | RuntimeException e) {
211             LOG.error("Delete subnet-network mapping failed for subnet {} network {}", subnetId.getValue(),
212                     networkId.getValue());
213         }
214     }
215 }
216