Fix logging issues in neutronvpn
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronNetworkChangeListener.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.Objects;
14 import javax.annotation.Nonnull;
15 import javax.annotation.PostConstruct;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.netvirt.elanmanager.api.IElanService;
23 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegmentsBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 @Singleton
48 public class NeutronNetworkChangeListener
49         extends AsyncDataTreeChangeListenerBase<Network, NeutronNetworkChangeListener> {
50     private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkChangeListener.class);
51     private final DataBroker dataBroker;
52     private final NeutronvpnManager nvpnManager;
53     private final NeutronvpnNatManager nvpnNatManager;
54     private final IElanService elanService;
55     private final NeutronvpnUtils neutronvpnUtils;
56
57     @Inject
58     public NeutronNetworkChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
59                                         final NeutronvpnNatManager neutronvpnNatManager,
60                                         final IElanService elanService, final NeutronvpnUtils neutronvpnUtils) {
61         super(Network.class, NeutronNetworkChangeListener.class);
62         this.dataBroker = dataBroker;
63         nvpnManager = neutronvpnManager;
64         nvpnNatManager = neutronvpnNatManager;
65         this.elanService = elanService;
66         this.neutronvpnUtils = neutronvpnUtils;
67     }
68
69     @Override
70     @PostConstruct
71     public void init() {
72         LOG.info("{} init", getClass().getSimpleName());
73         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
74     }
75
76     @Override
77     protected InstanceIdentifier<Network> getWildCardPath() {
78         return InstanceIdentifier.create(Neutron.class).child(Networks.class).child(Network.class);
79     }
80
81     @Override
82     protected NeutronNetworkChangeListener getDataTreeChangeListener() {
83         return NeutronNetworkChangeListener.this;
84     }
85
86
87     @Override
88     protected void add(InstanceIdentifier<Network> identifier, Network input) {
89         LOG.trace("Adding Network : key: {}, value={}", identifier, input);
90         String networkId = input.getUuid().getValue();
91         if (!NeutronvpnUtils.isNetworkTypeSupported(input)) {
92             LOG.error("Neutronvpn doesn't support the provider type for given network {}", networkId);
93             return;
94         }
95         Class<? extends NetworkTypeBase> networkType = input.getAugmentation(NetworkProviderExtension.class)
96                 .getNetworkType();
97         if (NeutronvpnUtils.isVlanOrVxlanNetwork(networkType)
98                 && NeutronUtils.getSegmentationIdFromNeutronNetwork(input, networkType) == null) {
99             LOG.error("Segmentation ID is null for configured provider network {} of type {}. Abandoning any further "
100                     + "processing for the network", input.getUuid().getValue(), networkType);
101             return;
102         }
103
104         neutronvpnUtils.addToNetworkCache(input);
105         // Create ELAN instance for this network
106         ElanInstance elanInstance = createElanInstance(input);
107
108         if (NeutronvpnUtils.getIsExternal(input)) {
109             // Create ELAN interface and IETF interfaces for the physical network
110             elanService.createExternalElanNetwork(elanInstance);
111             ProviderTypes providerNwType = NeutronvpnUtils.getProviderNetworkType(input);
112             if (providerNwType == null) {
113                 LOG.error("Unable to get Network Provider Type for network {}", networkId);
114                 return;
115             }
116             LOG.trace("External Network Provider Type for network {} is {}", networkId, providerNwType.getName());
117             nvpnNatManager.addExternalNetwork(input);
118             if (NeutronvpnUtils.isFlatOrVlanNetwork(input)) {
119                 nvpnManager.createL3InternalVpn(input.getUuid(), null, null, null, null, null, null, null);
120                 nvpnManager.createExternalVpnInterfaces(input.getUuid());
121             }
122         }
123     }
124
125     @Override
126     protected void remove(InstanceIdentifier<Network> identifier, Network input) {
127         LOG.trace("Removing Network : key: {}, value={}", identifier, input);
128         if (NeutronvpnUtils.getIsExternal(input)) {
129             if (NeutronvpnUtils.isFlatOrVlanNetwork(input)) {
130                 nvpnManager.removeExternalVpnInterfaces(input.getUuid());
131                 nvpnManager.removeVpn(input.getUuid());
132             }
133             nvpnNatManager.removeExternalNetwork(input);
134         }
135         //Delete ELAN instance for this network
136         String elanInstanceName = input.getUuid().getValue();
137         ElanInstance elanInstance = elanService.getElanInstance(elanInstanceName);
138         if (elanInstance != null) {
139             elanService.deleteExternalElanNetwork(elanInstance);
140             deleteElanInstance(elanInstanceName);
141         }
142         neutronvpnUtils.removeFromNetworkCache(input);
143     }
144
145     @Override
146     protected void update(InstanceIdentifier<Network> identifier, Network original, Network update) {
147         LOG.trace("Updating Network : key: {}, original value={}, update value={}", identifier, original, update);
148         neutronvpnUtils.addToNetworkCache(update);
149         String elanInstanceName = original.getUuid().getValue();
150         Class<? extends SegmentTypeBase> origSegmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(original);
151         String origSegmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(original);
152         String origPhysicalNetwork = NeutronvpnUtils.getPhysicalNetworkName(original);
153         Class<? extends SegmentTypeBase> updateSegmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(update);
154         String updateSegmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(update);
155         String updatePhysicalNetwork = NeutronvpnUtils.getPhysicalNetworkName(update);
156         Boolean origExternal = NeutronvpnUtils.getIsExternal(original);
157         Boolean updateExternal = NeutronvpnUtils.getIsExternal(update);
158         Boolean origIsFlatOrVlanNetwork = NeutronvpnUtils.isFlatOrVlanNetwork(original);
159         Boolean updateIsFlatOrVlanNetwork = NeutronvpnUtils.isFlatOrVlanNetwork(update);
160
161         if (!Objects.equals(origSegmentType, updateSegmentType)
162                 || !Objects.equals(origSegmentationId, updateSegmentationId)
163                 || !Objects.equals(origPhysicalNetwork, updatePhysicalNetwork)
164                 || !Objects.equals(origExternal, updateExternal)) {
165             if (origExternal && origIsFlatOrVlanNetwork && (!updateExternal || !updateIsFlatOrVlanNetwork)) {
166                 nvpnManager.removeExternalVpnInterfaces(original.getUuid());
167                 nvpnManager.removeVpn(original.getUuid());
168                 nvpnNatManager.removeExternalNetwork(original);
169             }
170
171             ElanInstance elanInstance = elanService.getElanInstance(elanInstanceName);
172             if (elanInstance != null) {
173                 elanService.deleteExternalElanNetwork(elanInstance);
174                 elanInstance = updateElanInstance(elanInstanceName, updateSegmentType, updateSegmentationId,
175                         updatePhysicalNetwork, update);
176                 if (updateExternal) {
177                     elanService.updateExternalElanNetwork(elanInstance);
178                 }
179             }
180
181             if (updateExternal && updateIsFlatOrVlanNetwork && !origExternal) {
182                 nvpnNatManager.addExternalNetwork(update);
183                 nvpnManager.createL3InternalVpn(update.getUuid(), null, null, null, null, null, null, null);
184                 nvpnManager.createExternalVpnInterfaces(update.getUuid());
185             }
186         }
187     }
188
189     @Nonnull
190     private List<ElanSegments> buildSegments(Network input) {
191         Long numSegments = NeutronUtils.getNumberSegmentsFromNeutronNetwork(input);
192         List<ElanSegments> segments = new ArrayList<>();
193
194         for (long index = 0L; index < numSegments; index++) {
195             ElanSegmentsBuilder elanSegmentsBuilder = new ElanSegmentsBuilder();
196             elanSegmentsBuilder.setSegmentationId(0L);
197             if (NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index) != null) {
198                 try {
199                     elanSegmentsBuilder.setSegmentationId(
200                             Long.valueOf(NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index)));
201                 } catch (NumberFormatException error) {
202                     LOG.error("Failed to get the segment id for network {}", input);
203                 }
204             }
205             if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVxlan.class)) {
206                 elanSegmentsBuilder.setSegmentType(SegmentTypeVxlan.class);
207             } else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVlan.class)) {
208                 elanSegmentsBuilder.setSegmentType(SegmentTypeVlan.class);
209             } else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeFlat.class)) {
210                 elanSegmentsBuilder.setSegmentType(SegmentTypeFlat.class);
211             }
212             elanSegmentsBuilder.setSegmentationIndex(index);
213             segments.add(elanSegmentsBuilder.build());
214             LOG.debug("Added segment {} to ELANInstance", segments.get((int)index - 1));
215         }
216         return segments;
217     }
218
219     private ElanInstance createElanInstance(Network input) {
220         String elanInstanceName = input.getUuid().getValue();
221         InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
222         Optional<ElanInstance> existingElanInstance = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
223                 id);
224         if (existingElanInstance.isPresent()) {
225             return existingElanInstance.get();
226         }
227         Class<? extends SegmentTypeBase> segmentType = NeutronvpnUtils.getSegmentTypeFromNeutronNetwork(input);
228         String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(input);
229         String physicalNetworkName = NeutronvpnUtils.getPhysicalNetworkName(input);
230         long elanTag = elanService.retrieveNewElanTag(elanInstanceName);
231         ElanInstance elanInstance = createElanInstanceBuilder(elanInstanceName, segmentType, segmentationId,
232                 physicalNetworkName, input).setElanTag(elanTag).build();
233         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, elanInstance);
234         LOG.debug("ELANInstance {} created with elan tag {} and segmentation ID {}", elanInstanceName, elanTag,
235                 segmentationId);
236         return elanInstance;
237     }
238
239     private ElanInstanceBuilder createElanInstanceBuilder(String elanInstanceName, Class<? extends SegmentTypeBase>
240             segmentType, String segmentationId, String physicalNetworkName, Network network) {
241         Boolean isExternal = NeutronvpnUtils.getIsExternal(network);
242         List<ElanSegments> segments = buildSegments(network);
243         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
244         if (segmentType != null) {
245             elanInstanceBuilder.setSegmentType(segmentType);
246             if (segmentationId != null) {
247                 elanInstanceBuilder.setSegmentationId(Long.valueOf(segmentationId));
248             }
249             if (physicalNetworkName != null) {
250                 elanInstanceBuilder.setPhysicalNetworkName(physicalNetworkName);
251             }
252         }
253
254         elanInstanceBuilder.setElanSegments(segments);
255         elanInstanceBuilder.setExternal(isExternal);
256         elanInstanceBuilder.setKey(new ElanInstanceKey(elanInstanceName));
257         return elanInstanceBuilder;
258     }
259
260     private void deleteElanInstance(String elanInstanceName) {
261         InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
262         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
263         LOG.debug("ELANInstance {} deleted", elanInstanceName);
264     }
265
266     private ElanInstance updateElanInstance(String elanInstanceName, Class<? extends SegmentTypeBase> segmentType,
267                                             String segmentationId, String physicalNetworkName, Network network) {
268
269         ElanInstance elanInstance = createElanInstanceBuilder(elanInstanceName, segmentType, segmentationId,
270                 physicalNetworkName, network).build();
271         InstanceIdentifier<ElanInstance> id = createElanInstanceIdentifier(elanInstanceName);
272         MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, id, elanInstance);
273         return elanInstance;
274     }
275
276     private InstanceIdentifier<ElanInstance> createElanInstanceIdentifier(String elanInstanceName) {
277         InstanceIdentifier<ElanInstance> id = InstanceIdentifier.builder(ElanInstances.class)
278                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
279         return id;
280     }
281 }