Exception during netvirt CSIT
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / SubnetOpDpnManager.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.vpnmanager;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Optional;
15 import java.util.concurrent.ExecutionException;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
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.netvirt.l3vpn.rev130911.PortOpData;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesKey;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.Uint64;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @Singleton
43 public class SubnetOpDpnManager {
44     private static final Logger LOG = LoggerFactory.getLogger(SubnetOpDpnManager.class);
45
46     private final DataBroker broker;
47
48     @Inject
49     public SubnetOpDpnManager(final DataBroker db) {
50         broker = db;
51     }
52
53     @Nullable
54     private SubnetToDpn addDpnToSubnet(Uuid subnetId, Uint64 dpnId) {
55         try {
56             InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
57                 InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
58                     new SubnetOpDataEntryKey(subnetId)).build();
59             InstanceIdentifier<SubnetToDpn> dpnOpId =
60                 subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
61             Optional<SubnetToDpn> optionalSubDpn = SingleTransactionDataBroker.syncReadOptional(broker,
62                     LogicalDatastoreType.OPERATIONAL, dpnOpId);
63             if (optionalSubDpn.isPresent()) {
64                 LOG.error("addDpnToSubnet: Cannot create, SubnetToDpn for subnet {} as DPN {}"
65                         + " already seen in datastore", subnetId.getValue(), dpnId);
66                 return null;
67             }
68             SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder().withKey(new SubnetToDpnKey(dpnId));
69             Map<VpnInterfacesKey, VpnInterfaces> vpnInterfaceMap = new HashMap<>();
70             subDpnBuilder.setVpnInterfaces(vpnInterfaceMap);
71             SubnetToDpn subDpn = subDpnBuilder.build();
72             SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn,
73                     VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
74             LOG.info("addDpnToSubnet: Created SubnetToDpn entry for subnet {} with DPNId {} ", subnetId.getValue(),
75                     dpnId);
76             return subDpn;
77         } catch (TransactionCommitFailedException ex) {
78             LOG.error("addDpnToSubnet: Creation of SubnetToDpn for subnet {} with DpnId {} failed",
79                     subnetId.getValue(), dpnId, ex);
80         } catch (InterruptedException | ExecutionException e) {
81             LOG.error("addDpnToSubnet: Failed to read data store for subnet {} dpn {}", subnetId.getValue(),
82                     dpnId);
83         }
84         return null;
85     }
86
87     private void removeDpnFromSubnet(Uuid subnetId, Uint64 dpnId) {
88         try {
89             InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
90                 InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
91                     new SubnetOpDataEntryKey(subnetId)).build();
92             InstanceIdentifier<SubnetToDpn> dpnOpId =
93                 subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
94             Optional<SubnetToDpn> optionalSubDpn = SingleTransactionDataBroker.syncReadOptional(broker,
95                     LogicalDatastoreType.OPERATIONAL, dpnOpId);
96             if (!optionalSubDpn.isPresent()) {
97                 LOG.warn("removeDpnFromSubnet: Cannot delete, SubnetToDpn for subnet {} DPN {} not available"
98                         + " in datastore", subnetId.getValue(), dpnId);
99                 return;
100             }
101             LOG.trace("removeDpnFromSubnet: Deleting SubnetToDpn entry for subnet {} with DPNId {}",
102                     subnetId.getValue(), dpnId);
103             SingleTransactionDataBroker.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId,
104                     VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
105         } catch (TransactionCommitFailedException ex) {
106             LOG.error("removeDpnFromSubnet: Deletion of SubnetToDpn for subnet {} with DPN {} failed",
107                     subnetId.getValue(), dpnId, ex);
108         } catch (InterruptedException | ExecutionException e) {
109             LOG.error("removeDpnFromSubnet: Failed to read data store for subnet {} dpn {}", subnetId, dpnId);
110         }
111     }
112
113     public SubnetToDpn addInterfaceToDpn(Uuid subnetId, Uint64 dpnId, String intfName) {
114         SubnetToDpn subDpn = null;
115         try {
116             // Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
117             InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
118                 InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
119                     new SubnetOpDataEntryKey(subnetId)).build();
120             //Please use a synchronize block here as we donot need a cluster-wide lock
121             InstanceIdentifier<SubnetToDpn> dpnOpId =
122                 subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
123             Optional<SubnetToDpn> optionalSubDpn = SingleTransactionDataBroker.syncReadOptional(broker,
124                     LogicalDatastoreType.OPERATIONAL, dpnOpId);
125             if (!optionalSubDpn.isPresent()) {
126                 // Create a new DPN Entry
127                 subDpn = addDpnToSubnet(subnetId, dpnId);
128             } else {
129                 subDpn = optionalSubDpn.get();
130             }
131             SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(subDpn);
132             Map<VpnInterfacesKey, VpnInterfaces> vpnInterfaceMap = new HashMap<>();
133             vpnInterfaceMap = subDpnBuilder.getVpnInterfaces() != null
134                     ? new HashMap<>(subDpnBuilder.getVpnInterfaces()) : vpnInterfaceMap;
135             VpnInterfaces vpnIntfs =
136                 new VpnInterfacesBuilder().withKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
137             vpnInterfaceMap.put(vpnIntfs.key(), vpnIntfs);
138             subDpnBuilder.setVpnInterfaces(vpnInterfaceMap);
139             subDpn = subDpnBuilder.build();
140             SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn,
141                     VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
142             LOG.info("addInterfaceToDpn: Created SubnetToDpn entry for subnet {} with DPNId {} intfName {}",
143                     subnetId.getValue(), dpnId, intfName);
144         } catch (TransactionCommitFailedException ex) {
145             LOG.error("addInterfaceToDpn: Addition of Interface {} for SubnetToDpn on subnet {} with DPN {} failed",
146                     intfName, subnetId.getValue(), dpnId, ex);
147         } catch (InterruptedException | ExecutionException e) {
148             LOG.error("addInterfaceToDpn: Failed to read data store for interface {} subnet {} dpn {}", intfName,
149                     subnetId, dpnId);
150         }
151         return subDpn;
152     }
153
154     public void addPortOpDataEntry(String intfName, Uuid subnetId, @Nullable Uint64 dpnId) {
155         try {
156             // Add to PortOpData as well.
157             PortOpDataEntryBuilder portOpBuilder = null;
158             PortOpDataEntry portOpEntry = null;
159             InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
160                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
161                     new PortOpDataEntryKey(intfName)).build();
162             Optional<PortOpDataEntry> optionalPortOp = SingleTransactionDataBroker.syncReadOptional(broker,
163                     LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
164             if (!optionalPortOp.isPresent()) {
165                 // Create PortOpDataEntry only if not present
166                 portOpBuilder =
167                     new PortOpDataEntryBuilder().withKey(new PortOpDataEntryKey(intfName)).setPortId(intfName);
168                 List<Uuid> listSubnet = new ArrayList<>();
169                 listSubnet.add(subnetId);
170                 portOpBuilder.setSubnetIds(listSubnet);
171             } else {
172                 PortOpDataEntry portEntry = optionalPortOp.get();
173                 List<Uuid> listSubnet = new ArrayList<>();
174                 listSubnet = (portEntry.getSubnetIds() != null && !portEntry.getSubnetIds().isEmpty())
175                         ? new ArrayList<>(portEntry.getSubnetIds()) : listSubnet;
176                 portOpBuilder = new PortOpDataEntryBuilder(optionalPortOp.get());
177                 if (listSubnet == null) {
178                     listSubnet = new ArrayList<>();
179                 }
180                 if (!listSubnet.contains(subnetId)) {
181                     listSubnet.add(subnetId);
182                 }
183                 portOpBuilder.setSubnetIds(listSubnet);
184             }
185             if (dpnId != null && !dpnId.equals(Uint64.ZERO)) {
186                 portOpBuilder.setDpnId(dpnId);
187             }
188             portOpEntry = portOpBuilder.build();
189             SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier,
190                 portOpEntry, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
191             LOG.info("addPortOpDataEntry: Created PortOpData entry for port {} with DPNId {} subnetId {}",
192                      intfName, dpnId, subnetId.getValue());
193         } catch (TransactionCommitFailedException ex) {
194             LOG.error("addPortOpDataEntry: Addition of Interface {} for SubnetToDpn on subnet {} with DPN {} failed",
195                     intfName, subnetId.getValue(), dpnId, ex);
196         } catch (InterruptedException | ExecutionException e) {
197             LOG.error("addPortOpDataEntry: Failed to read from data store for interface {} subnet {} dpn {}",
198                     intfName, subnetId, dpnId);
199         }
200     }
201
202     public boolean removeInterfaceFromDpn(Uuid subnetId, Uint64 dpnId, String intfName) {
203         boolean dpnRemoved = false;
204         try {
205             InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
206                 InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
207                     new SubnetOpDataEntryKey(subnetId)).build();
208             InstanceIdentifier<SubnetToDpn> dpnOpId =
209                 subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
210             Optional<SubnetToDpn> optionalSubDpn = SingleTransactionDataBroker.syncReadOptional(broker,
211                     LogicalDatastoreType.OPERATIONAL, dpnOpId);
212             if (!optionalSubDpn.isPresent()) {
213                 LOG.debug("removeInterfaceFromDpn: Cannot delete, SubnetToDpn for intf {} subnet {} DPN {}"
214                         + " not available in datastore", intfName, subnetId.getValue(), dpnId);
215                 return false;
216             }
217
218             SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(optionalSubDpn.get());
219             Map<VpnInterfacesKey, VpnInterfaces> vpnInterfaceMap = new HashMap<>();
220
221             vpnInterfaceMap = (subDpnBuilder.getVpnInterfaces() != null && !subDpnBuilder.getVpnInterfaces().isEmpty())
222                     ? new HashMap<>(subDpnBuilder.getVpnInterfaces()) : vpnInterfaceMap;
223             VpnInterfaces vpnIntfs =
224                 new VpnInterfacesBuilder().withKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
225             vpnInterfaceMap.remove(vpnIntfs.key());
226             if (vpnInterfaceMap.isEmpty()) {
227                 // Remove the DPN as well
228                 removeDpnFromSubnet(subnetId, dpnId);
229                 dpnRemoved = true;
230             } else {
231                 subDpnBuilder.setVpnInterfaces(vpnInterfaceMap);
232                 SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId,
233                     subDpnBuilder.build(), VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
234             }
235             LOG.info("removeInterfaceFromDpn: Removed interface {} from sunbet {} dpn {}",
236                     intfName, subnetId.getValue(), dpnId);
237         } catch (TransactionCommitFailedException ex) {
238             LOG.error("removeInterfaceFromDpn: Deletion of Interface {} for SubnetToDpn on subnet {}"
239                     + " with DPN {} failed", intfName, subnetId.getValue(), dpnId, ex);
240         } catch (InterruptedException | ExecutionException e) {
241             LOG.error("removeInterfaceFromDpn: Failed to read data store for interface {} subnet {} dpn {}",
242                     intfName, subnetId, dpnId);
243         }
244         return dpnRemoved;
245     }
246
247     public PortOpDataEntry removePortOpDataEntry(String intfName, Uuid subnetId) {
248         // Remove PortOpData and return out
249         InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
250                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
251                         new PortOpDataEntryKey(intfName)).build();
252         PortOpDataEntry portOpEntry = null;
253         try {
254             Optional<PortOpDataEntry> optionalPortOp = SingleTransactionDataBroker.syncReadOptional(broker,
255                     LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
256             if (!optionalPortOp.isPresent()) {
257                 LOG.info("removePortOpDataEntry: Cannot delete, portOp for port {} is not available in datastore",
258                         intfName);
259             } else {
260                 portOpEntry = optionalPortOp.get();
261                 List<Uuid> listSubnet = new ArrayList<>();
262                 listSubnet = (portOpEntry.getSubnetIds() != null && !portOpEntry.getSubnetIds().isEmpty())
263                         ? new ArrayList<>(portOpEntry.getSubnetIds()) : listSubnet;
264                 if (listSubnet == null) {
265                     listSubnet = new ArrayList<>();
266                 }
267                 if (subnetId != null && listSubnet.contains(subnetId)) {
268                     listSubnet.remove(subnetId);
269                 }
270                 if (listSubnet.isEmpty() || subnetId == null) {
271                     SingleTransactionDataBroker.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier,
272                             VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
273                     LOG.info("removePortOpDataEntry: Deleted portOpData entry for port {}", intfName);
274                 } else {
275                     PortOpDataEntryBuilder portOpBuilder = null;
276                     portOpBuilder = new PortOpDataEntryBuilder(portOpEntry);
277                     portOpBuilder.setSubnetIds(listSubnet);
278                     SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
279                             portOpIdentifier, portOpEntry, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
280                     LOG.info("removePortOpDataEntry: Updated PortOpData entry for port {} with removing"
281                             + " subnetId {}", intfName, subnetId.getValue());
282                     portOpEntry = null;
283                 }
284             }
285         } catch (InterruptedException | ExecutionException e) {
286             LOG.error("removePortOpDataEntry: Failed to read data store for interface {} subnet {}", intfName,
287                     subnetId);
288         } catch (TransactionCommitFailedException e) {
289             LOG.error("removePortOpDataEntry: Failed to commit to data store for interface {} subnet {}", intfName,
290                     subnetId);
291         }
292         return portOpEntry;
293     }
294
295     public PortOpDataEntry getPortOpDataEntry(String intfName) {
296         PortOpDataEntry portOpDataEntry = null;
297         try {
298             // Remove PortOpData and return out
299             InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
300                     InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
301                             new PortOpDataEntryKey(intfName)).build();
302             Optional<PortOpDataEntry> optionalPortOp = SingleTransactionDataBroker.syncReadOptional(broker,
303                     LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
304             if (optionalPortOp.isPresent()) {
305                 portOpDataEntry = optionalPortOp.get();
306             }
307         } catch (InterruptedException | ExecutionException e) {
308             LOG.error("getPortOpDataEntry: Failed to read data store for interface {}", intfName);
309         }
310         return portOpDataEntry;
311     }
312 }