Support for LearntVpnVipToPort in netvirt
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / NetvirtVpnUtils.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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
9 package org.opendaylight.unimgr.mef.netvirt;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.UUID;
16
17 import org.apache.commons.net.util.SubnetUtils;
18 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargetsBuilder;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
30 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4FamilyBuilder;
32 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronVpnPortipPortData;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpnBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpnBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPortBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPortKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
82
83 import com.google.common.base.Optional;
84
85 public class NetvirtVpnUtils {
86     private static final Logger logger = LoggerFactory.getLogger(NetvirtVpnUtils.class);
87     private final static String ELAN_PREFIX = "elan.";
88     private final static String IP_ADDR_SUFFIX = "/32";
89     private final static String IP_MUSK_SEPARATOR = "/";
90
91     public static void createVpnInstance(DataBroker dataBroker, String instanceName) {
92         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
93         createVpnInstance(instanceName, tx);
94         MdsalUtils.commitTransaction(tx);
95     }
96
97     public static void createVpnInstance(String instanceName, WriteTransaction tx) {
98         VpnInstanceBuilder builder = new VpnInstanceBuilder();
99         builder.setVpnInstanceName(instanceName);
100         Ipv4FamilyBuilder ipv4FamilyBuilder = new Ipv4FamilyBuilder();
101         VpnTargetsBuilder vpnTargetsB = new VpnTargetsBuilder();
102         vpnTargetsB.setVpnTarget(new ArrayList<VpnTarget>());
103         ipv4FamilyBuilder.setVpnTargets(vpnTargetsB.build());
104
105         // WA till netvirt will allow creation of VPN without RD
106         UUID vpnId = UUID.fromString(instanceName);
107         String rd = String.valueOf(Math.abs(vpnId.getLeastSignificantBits()));
108         ipv4FamilyBuilder.setRouteDistinguisher(rd);
109         builder.setIpv4Family(ipv4FamilyBuilder.build());
110
111         tx.put(LogicalDatastoreType.CONFIGURATION, getVpnInstanceInstanceIdentifier(instanceName), builder.build());
112     }
113
114     public static void removeVpnInstance(String instanceName, WriteTransaction tx) {
115         tx.delete(LogicalDatastoreType.CONFIGURATION, getVpnInstanceInstanceIdentifier(instanceName));
116     }
117
118     private static InstanceIdentifier<VpnInstance> getVpnInstanceInstanceIdentifier(String instanceName) {
119         return InstanceIdentifier.builder(VpnInstances.class).child(VpnInstance.class, new VpnInstanceKey(instanceName))
120                 .build();
121     }
122
123     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(
124             String vpnName) {
125         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
126                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
127                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(
128                                 vpnName))
129                 .build();
130     }
131
132     public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
133         return InstanceIdentifier.builder(VpnInstanceOpData.class)
134                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
135     }
136
137     public static void createUpdateVpnInterface(DataBroker dataBroker, String vpnName, String interfaceName,
138             String ifAddr, String macAddress, boolean primary, String gwIpAddress, String directSubnetId) {
139         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
140         createUpdateVpnInterface(vpnName, interfaceName, ifAddr, macAddress, primary, gwIpAddress, directSubnetId, tx);
141         MdsalUtils.commitTransaction(tx);
142     }
143
144     public static void createUpdateVpnInterface(String vpnName, String interfaceName, IpPrefix ifPrefix,
145             String macAddress, boolean primary, IpPrefix gwIpAddress, String directSubnetId, WriteTransaction tx) {
146         synchronized (interfaceName.intern()) {
147             String ipAddress = null;
148             String nextHopIp = null;
149             if (primary) {
150                 ipAddress = getAddressFromSubnet(ipPrefixToString(ifPrefix));
151             } else {
152                 ipAddress = ipPrefixToString(ifPrefix);
153                 nextHopIp = getIpAddressFromPrefix(ipPrefixToString(gwIpAddress));
154             }
155             createUpdateVpnInterface(vpnName, interfaceName, ipAddress, macAddress, primary, nextHopIp, directSubnetId,
156                     tx);
157         }
158     }
159
160     public static void createUpdateVpnInterface(String vpnName, String interfaceName, String ipAddress,
161             String macAddress, boolean primary, String nextHopIp, String subnetId, WriteTransaction tx) {
162         synchronized (interfaceName.intern()) {
163             Adjacencies adjancencies = buildInterfaceAdjacency(ipAddress, macAddress, primary, nextHopIp, subnetId);
164             VpnInterfaceBuilder einterfaceBuilder = createVpnInterface(vpnName, interfaceName, adjancencies);
165
166             tx.merge(LogicalDatastoreType.CONFIGURATION, getVpnInterfaceInstanceIdentifier(interfaceName),
167                     einterfaceBuilder.build());
168         }
169     }
170
171     private static VpnInterfaceBuilder createVpnInterface(String instanceName, String interfaceName,
172             Adjacencies adjacencies) {
173         VpnInterfaceBuilder einterfaceBuilder = new VpnInterfaceBuilder();
174         einterfaceBuilder.setVpnInstanceName(instanceName);
175         einterfaceBuilder.setName(interfaceName);
176         einterfaceBuilder.addAugmentation(Adjacencies.class, adjacencies);
177         return einterfaceBuilder;
178     }
179
180     private static Adjacencies buildInterfaceAdjacency(String ipAddress, String macAddress, boolean primary,
181             String nextHopIp, String subnetId) {
182         AdjacenciesBuilder builder = new AdjacenciesBuilder();
183         List<Adjacency> list = new ArrayList<>();
184
185         AdjacencyBuilder aBuilder = new AdjacencyBuilder();
186         aBuilder.setIpAddress(ipAddress);
187         if (macAddress != null) {
188             aBuilder.setMacAddress(macAddress);
189         }
190         aBuilder.setPrimaryAdjacency(primary);
191         if (subnetId != null) {
192             aBuilder.setSubnetId(new Uuid(subnetId));
193         }
194         if (nextHopIp != null) {
195             aBuilder.setNextHopIpList(Arrays.asList(nextHopIp));
196         }
197         list.add(aBuilder.build());
198
199         builder.setAdjacency(list);
200         return builder.build();
201     }
202
203     public static void removeVpnInterface(String interfaceName, WriteTransaction tx) {
204         synchronized (interfaceName.intern()) {
205             tx.delete(LogicalDatastoreType.CONFIGURATION, getVpnInterfaceInstanceIdentifier(interfaceName));
206         }
207     }
208
209     public static void removeVpnInterfaceAdjacencies(DataBroker dataBroker, String vpnName, String interfaceName) {
210
211         InstanceIdentifier<VpnInterface> identifier = getVpnInterfaceInstanceIdentifier(interfaceName);
212         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
213
214         Optional<Adjacencies> adjacencies = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
215         List<Adjacency> adjacenciesList = adjacencies.isPresent() && adjacencies.get().getAdjacency() != null
216                 ? adjacencies.get().getAdjacency() : Collections.emptyList();
217         adjacenciesList.forEach(a -> {
218             String ipStr = getIpAddressFromPrefix(a.getIpAddress());
219             InstanceIdentifier<LearntVpnVipToPort> id = getLearntVpnVipToPortIdentifier(vpnName, ipStr);
220             MdsalUtils.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
221         });
222         int waitCount = (adjacenciesList.isEmpty()) ? 2 : 2 * adjacenciesList.size();
223
224         AdjacenciesBuilder builder = new AdjacenciesBuilder();
225         List<Adjacency> list = new ArrayList<>();
226         builder.setAdjacency(list);
227         VpnInterfaceBuilder einterfaceBuilder = createVpnInterface(vpnName, interfaceName, builder.build());
228         MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, identifier, einterfaceBuilder.build());
229
230         final DataWaitGetter<Adjacencies> getData = vpnint -> {
231             if (vpnint.getAdjacency() == null)
232                 return null;
233             return vpnint.getAdjacency().stream().filter(a -> !a.isPrimaryAdjacency());
234         };
235
236         @SuppressWarnings("resource") // AutoCloseable
237         DataWaitListener<Adjacencies> vpnIntWaiter = new DataWaitListener<Adjacencies>(dataBroker, path, waitCount,
238                 LogicalDatastoreType.OPERATIONAL, getData);
239         if (!vpnIntWaiter.waitForClean()) {
240             logger.error("Fail to wait for VPN interface clean-up {} {}", vpnName, interfaceName);
241             return;
242         }
243     }
244
245     public static void removeVpnInterfaceAdjacency(DataBroker dataBroker, String interfaceName, IpPrefix ifPrefix) {
246         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
247         String ipAddress = ipPrefixToString(ifPrefix);
248         removeVpnInterfaceAdjacency(interfaceName, ipAddress, tx);
249         MdsalUtils.commitTransaction(tx);
250     }
251
252     public static void removeVpnInterfaceAdjacency(DataBroker dataBroker, String interfaceName, IpAddress ifAddress) {
253         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
254         String ifAddressStr = getAddressFromSubnet(ipAddressToString(ifAddress));
255         removeVpnInterfaceAdjacency(interfaceName, ifAddressStr, tx);
256         MdsalUtils.commitTransaction(tx);
257     }
258
259     private static void removeVpnInterfaceAdjacency(String interfaceName, String ipAddress, WriteTransaction tx) {
260         synchronized (interfaceName.intern()) {
261
262             InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class)
263                     .child(VpnInterface.class, new VpnInterfaceKey(interfaceName)).augmentation(Adjacencies.class)
264                     .child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
265
266             tx.delete(LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
267         }
268     }
269
270     private static InstanceIdentifier<VpnInterface> getVpnInterfaceInstanceIdentifier(String interfaceName) {
271         return InstanceIdentifier.builder(VpnInterfaces.class)
272                 .child(VpnInterface.class, new VpnInterfaceKey(interfaceName)).build();
273     }
274
275     public static void createVpnPortFixedIp(DataBroker dataBroker, String vpnName, String portName, IpPrefix ipAddress,
276             MacAddress macAddress) {
277         String fixedIpPrefix = ipPrefixToString(ipAddress);
278         String fixedIp = getIpAddressFromPrefix(fixedIpPrefix);
279
280         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
281         createVpnPortFixedIp(vpnName, portName, fixedIp, macAddress, tx);
282         MdsalUtils.commitTransaction(tx);
283     }
284
285     private static void createVpnPortFixedIp(String vpnName, String portName, String fixedIp, MacAddress macAddress,
286             WriteTransaction tx) {
287         synchronized ((vpnName + fixedIp).intern()) {
288             InstanceIdentifier<VpnPortipToPort> id = getVpnPortipToPortIdentifier(vpnName, fixedIp);
289             VpnPortipToPortBuilder builder = new VpnPortipToPortBuilder()
290                     .setKey(new VpnPortipToPortKey(fixedIp, vpnName)).setVpnName(vpnName).setPortFixedip(fixedIp)
291                     .setPortName(portName).setMacAddress(macAddress.getValue()).setSubnetIp(true);
292             tx.put(LogicalDatastoreType.CONFIGURATION, id, builder.build());
293             logger.debug(
294                     "Interface to fixedIp added: {}, vpn {}, interface {}, mac {} added to " + "VpnPortipToPort DS",
295                     fixedIp, vpnName, portName, macAddress);
296         }
297     }
298
299     public static VpnPortipToPort getVpnPortFixedIp(DataBroker dataBroker, String vpnName, String fixedIp) {
300         InstanceIdentifier<VpnPortipToPort> id = getVpnPortipToPortIdentifier(vpnName, fixedIp);
301         Optional<VpnPortipToPort> opt = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
302         return opt != null && opt.isPresent() ? opt.get() : null;
303     }
304
305     public static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker dataBroker, String vpnName, String fixedIp) {
306         InstanceIdentifier<LearntVpnVipToPort> id = getLearntVpnVipToPortIdentifier(vpnName, fixedIp);
307         Optional<LearntVpnVipToPort> opt = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
308         return opt != null && opt.isPresent() ? opt.get() : null;
309     }
310
311     public static void removeVpnPortFixedIp(String vpnName, IpPrefix ipAddress, WriteTransaction tx) {
312         String fixedIpPrefix = ipPrefixToString(ipAddress);
313         String fixedIp = getIpAddressFromPrefix(fixedIpPrefix);
314         InstanceIdentifier<VpnPortipToPort> id = getVpnPortipToPortIdentifier(vpnName, fixedIp);
315         tx.delete(LogicalDatastoreType.CONFIGURATION, id);
316     }
317
318     public static void registerDirectSubnetForVpn(DataBroker dataBroker, Uuid subnetName, IpAddress gwIpAddress) {
319         final SubnetKey subnetkey = new SubnetKey(subnetName);
320
321         final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
322                 .child(Subnets.class).child(Subnet.class, subnetkey);
323
324         SubnetBuilder subnetBuilder = new SubnetBuilder();
325         subnetBuilder.setIpVersion(IpVersionV4.class);
326         subnetBuilder.setGatewayIp(gwIpAddress);
327         subnetBuilder.setKey(subnetkey);
328         MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetidentifier, subnetBuilder.build());
329     }
330
331     public static void unregisterDirectSubnetForVpn(DataBroker dataBroker, Uuid subnetName) {
332         final SubnetKey subnetkey = new SubnetKey(subnetName);
333         final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
334                 .child(Subnets.class).child(Subnet.class, subnetkey);
335
336         MdsalUtils.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
337     }
338
339     public static void addDirectSubnetToVpn(DataBroker dataBroker,
340             final NotificationPublishService notificationPublishService, String vpnName, String subnetName,
341             IpPrefix subnetIpPrefix, String interfaceName, String intfMac, int waitForElan) {
342         InstanceIdentifier<ElanInstance> elanIdentifierId = NetvirtUtils.getElanInstanceInstanceIdentifier(subnetName);
343
344         @SuppressWarnings("resource") // AutoCloseable
345         DataWaitListener<ElanInstance> elanTagWaiter = new DataWaitListener<>(dataBroker, elanIdentifierId,
346                 10, LogicalDatastoreType.CONFIGURATION, el -> el.getElanTag());
347         if (!elanTagWaiter.waitForData()) {
348             logger.error("Trying to add invalid elan {} to vpn {}", subnetName, vpnName);
349             return;
350         }
351
352         Uuid subnetId = new Uuid(subnetName);
353         logger.info("Adding subnet {} {} to elan map", subnetId, subnetId);
354         createSubnetToNetworkMapping(dataBroker, subnetId, subnetId);
355
356         String subnetIp = getSubnetFromPrefix(ipPrefixToString(subnetIpPrefix));
357         logger.info("Adding subnet {} {} to vpn {}", subnetName, subnetIp, vpnName);
358         updateSubnetNode(dataBroker, new Uuid(vpnName), subnetId, subnetIp, intfMac);
359
360         logger.info("Adding port {} to subnet {}", interfaceName, subnetName);
361         updateSubnetmapNodeWithPorts(dataBroker, subnetId, new Uuid(interfaceName), null, vpnName);
362
363         Optional<ElanInstance> elanInstance = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
364                 elanIdentifierId);
365         Long elanTag = elanInstance.get().getElanTag();
366
367         logger.info("Publish subnet {}", subnetName);
368         publishSubnetAddNotification(notificationPublishService, subnetId, subnetIp, vpnName, elanTag);
369         logger.info("Finished Working on subnet {}", subnetName);
370     }
371
372     public static void removeDirectSubnetFromVpn(DataBroker dataBroker,
373             final NotificationPublishService notificationPublishService, String vpnName, String subnetName,
374             String interfaceName) {
375         InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
376                 .child(ElanInstance.class, new ElanInstanceKey(subnetName)).build();
377         Optional<ElanInstance> elanInstance = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
378                 elanIdentifierId);
379         if (!elanInstance.isPresent()) {
380             logger.error("Trying to add invalid elan {} to vpn {}", subnetName, vpnName);
381             return;
382         }
383         Long elanTag = elanInstance.get().getElanTag() != null ? elanInstance.get().getElanTag()
384                 : elanInstance.get().getSegmentationId();
385         Uuid subnetId = new Uuid(subnetName);
386
387         logger.info("Publish subnet remove {}", subnetName);
388         publishSubnetRemoveNotification(notificationPublishService, subnetId, vpnName, elanTag);
389
390         logger.info("Removing port {} from subnet {}", interfaceName, subnetName);
391         updateSubnetmapNodeWithPorts(dataBroker, subnetId, null, new Uuid(interfaceName), vpnName);
392
393         logger.info("Removing subnet {} from vpn {}", subnetName, vpnName);
394         removeSubnetNode(dataBroker, new Uuid(vpnName));
395
396         logger.info("Removing subnet {} to elan map", subnetId);
397         removeSubnetToNetworkMapping(dataBroker, subnetId);
398
399         logger.info("Finished Working on subnet {}", subnetName);
400     }
401
402     private static void createSubnetToNetworkMapping(DataBroker dataBroker, Uuid subnetId, Uuid networkId) {
403         InstanceIdentifier<NetworkMap> networkMapIdentifier = getNetworkMapIdentifier(networkId);
404         Optional<NetworkMap> optionalNetworkMap = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
405                 networkMapIdentifier);
406         NetworkMapBuilder nwMapBuilder = null;
407         if (optionalNetworkMap.isPresent()) {
408             nwMapBuilder = new NetworkMapBuilder(optionalNetworkMap.get());
409         } else {
410             nwMapBuilder = new NetworkMapBuilder().setKey(new NetworkMapKey(networkId)).setNetworkId(networkId);
411             logger.debug("Adding a new network node in NetworkMaps DS for network {}", networkId.getValue());
412         }
413         List<Uuid> subnetIdList = nwMapBuilder.getSubnetIdList();
414         if (subnetIdList == null) {
415             subnetIdList = new ArrayList<>();
416         }
417         subnetIdList.add(subnetId);
418         nwMapBuilder.setSubnetIdList(subnetIdList);
419         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier, nwMapBuilder.build());
420         logger.debug("Created subnet-network mapping for subnet {} network {}", subnetId.getValue(),
421                 networkId.getValue());
422     }
423
424     private static void removeSubnetToNetworkMapping(DataBroker dataBroker, Uuid networkId) {
425         InstanceIdentifier<NetworkMap> networkMapIdentifier = getNetworkMapIdentifier(networkId);
426         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier);
427         logger.debug("Deleted subnet-network mapping for  network {}", networkId.getValue());
428     }
429
430     protected static void updateSubnetNode(DataBroker dataBroker, Uuid vpnId, Uuid subnetId, String subnetIp,
431             String intfMac) {
432         Subnetmap subnetmap = null;
433         SubnetmapBuilder builder = null;
434         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
435                 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
436
437         synchronized (subnetId.getValue().intern()) {
438             Optional<Subnetmap> sn = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
439             if (sn.isPresent()) {
440                 builder = new SubnetmapBuilder(sn.get());
441                 logger.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
442             } else {
443                 builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
444                 logger.debug("creating new subnetmap node for subnet ID {}", subnetId.getValue());
445             }
446
447             builder.setSubnetIp(subnetIp);
448             builder.setNetworkId(subnetId);
449             builder.setVpnId(vpnId);
450             builder.setRouterIntfMacAddress(intfMac);
451
452             subnetmap = builder.build();
453             logger.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
454             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
455         }
456     }
457
458     protected static void removeSubnetNode(DataBroker dataBroker, Uuid subnetId) {
459         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
460                 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
461
462         synchronized (subnetId.getValue().intern()) {
463             logger.debug("Deleting subnetMap node: {} ", subnetId.getValue());
464             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
465         }
466     }
467
468     private static void updateSubnetmapNodeWithPorts(DataBroker dataBroker, Uuid subnetId, Uuid portIdToAdd,
469             Uuid portIdToRemove, String vpnName) {
470         Subnetmap subnetmap = null;
471         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
472                 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
473         synchronized (subnetId.getValue().intern()) {
474             Optional<Subnetmap> sn = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
475             if (sn.isPresent()) {
476                 SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
477                 if (null != portIdToAdd) {
478                     List<Uuid> portList = builder.getPortList();
479                     if (null == portList) {
480                         portList = new ArrayList<>();
481                     }
482                     if (portIdToAdd != null) {
483                         portList.add(portIdToAdd);
484                         logger.debug("Updating subnetmap node {} with port {}", subnetId.getValue(),
485                                 portIdToAdd.getValue());
486
487                     }
488                     if (portIdToRemove != null) {
489                         portList.remove(portIdToRemove);
490                         logger.debug("Updating subnetmap node {} removing port {}", subnetId.getValue(),
491                                 portIdToRemove.getValue());
492
493                     }
494                     builder.setRouterId(new Uuid(vpnName));
495                     builder.setPortList(portList);
496                 }
497                 subnetmap = builder.build();
498                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
499             } else {
500                 logger.error("Trying to update non-existing subnetmap node {} ", subnetId.getValue());
501             }
502         }
503     }
504
505     private static InstanceIdentifier<NetworkMap> getNetworkMapIdentifier(Uuid networkId) {
506         InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class)
507                 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
508         return id;
509     }
510
511     private static InstanceIdentifier<VpnPortipToPort> getVpnPortipToPortIdentifier(String vpnName, String fixedIp) {
512         InstanceIdentifier<VpnPortipToPort> id = InstanceIdentifier.builder(NeutronVpnPortipPortData.class)
513                 .child(VpnPortipToPort.class, new VpnPortipToPortKey(fixedIp, vpnName)).build();
514         return id;
515     }
516
517     private static InstanceIdentifier<LearntVpnVipToPort> getLearntVpnVipToPortIdentifier(String vpnName,
518             String fixedIp) {
519         InstanceIdentifier<LearntVpnVipToPort> id = InstanceIdentifier.builder(LearntVpnVipToPortData.class)
520                 .child(LearntVpnVipToPort.class, new LearntVpnVipToPortKey(fixedIp, vpnName)).build();
521         return id;
522     }
523
524     public static InstanceIdentifier<VpnPortipToPort> getVpnPortipToPortIdentifier() {
525         return InstanceIdentifier.builder(NeutronVpnPortipPortData.class).child(VpnPortipToPort.class).build();
526     }
527
528     public static InstanceIdentifier<LearntVpnVipToPort> getLearntVpnVipToPortIdentifier() {
529         return InstanceIdentifier.builder(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class).build();
530     }
531
532     private static void publishSubnetAddNotification(final NotificationPublishService notificationPublishService,
533             Uuid subnetId, String subnetIp, String vpnName, Long elanTag) {
534         SubnetAddedToVpnBuilder builder = new SubnetAddedToVpnBuilder();
535
536         logger.info("publish notification called for network creation");
537
538         builder.setSubnetId(subnetId);
539         builder.setSubnetIp(subnetIp);
540         builder.setVpnName(vpnName);
541         builder.setExternalVpn(true);
542         builder.setElanTag(elanTag);
543
544         try {
545             notificationPublishService.putNotification(builder.build());
546         } catch (InterruptedException e) {
547             logger.error("Fail to publish notification {}", builder, e);
548             throw new RuntimeException(e.getMessage());
549         }
550     }
551
552     private static void publishSubnetRemoveNotification(final NotificationPublishService notificationPublishService,
553             Uuid subnetId, String vpnName, Long elanTag) {
554         SubnetDeletedFromVpnBuilder builder = new SubnetDeletedFromVpnBuilder();
555
556         logger.info("publish notification called for network deletion");
557
558         builder.setSubnetId(subnetId);
559         builder.setVpnName(vpnName);
560         builder.setExternalVpn(true);
561         builder.setElanTag(elanTag);
562
563         try {
564             notificationPublishService.putNotification(builder.build());
565         } catch (InterruptedException e) {
566             logger.error("Fail to publish notification {}", builder, e);
567             throw new RuntimeException(e.getMessage());
568         }
569     }
570
571     public static void sendArpRequest(OdlArputilService arpUtilService, IpAddress srcIpAddress, IpAddress dstIpAddress,
572             String interf) {
573         try {
574             List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
575             interfaceAddresses
576                     .add(new InterfaceAddressBuilder().setInterface(interf).setIpAddress(srcIpAddress).build());
577
578             SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(dstIpAddress)
579                     .setInterfaceAddress(interfaceAddresses).build();
580             arpUtilService.sendArpRequest(sendArpRequestInput);
581         } catch (Exception e) {
582             logger.error("Failed to send ARP request to IP {} from interfaces {}",
583                     dstIpAddress.getIpv4Address().getValue(), interf, e);
584             throw new RuntimeException(e.getMessage());
585         }
586     }
587
588     public static String getElanNameForVpnPort(String uniId, String ipUniId) {
589         return getUUidFromString(ELAN_PREFIX + uniId + ipUniId);
590     }
591
592     public static String getIpAddressFromPrefix(String prefix) {
593         return prefix.split(IP_MUSK_SEPARATOR)[0];
594     }
595
596     private static String getMaskFromPrefix(String prefix) {
597         return prefix.split(IP_MUSK_SEPARATOR)[1];
598     }
599
600     public static String getSubnetFromPrefix(String prefix) {
601         SubnetInfo subnet = new SubnetUtils(prefix).getInfo();
602         return subnet.getNetworkAddress() + IP_MUSK_SEPARATOR + getMaskFromPrefix(prefix);
603     }
604
605     public static String getSubnetFromPrefix(IpPrefix prefix) {
606         String prefixStr = ipPrefixToString(prefix);
607         return getSubnetFromPrefix(prefixStr);
608     }
609
610     private static String getAddressFromSubnet(String prefix) {
611         String myAddress = getIpAddressFromPrefix(prefix);
612         return myAddress + IP_ADDR_SUFFIX;
613     }
614
615     public static String getUUidFromString(String key) {
616         return java.util.UUID.nameUUIDFromBytes(key.getBytes()).toString();
617     }
618
619     public static String ipPrefixToString(IpPrefix ipAddress) {
620         if (ipAddress.getIpv4Prefix() != null) {
621             return ipAddress.getIpv4Prefix().getValue();
622         }
623
624         return ipAddress.getIpv6Prefix().getValue();
625     }
626
627     public static String ipAddressToString(IpAddress ipAddress) {
628         if (ipAddress.getIpv4Address() != null) {
629             return ipAddress.getIpv4Address().getValue();
630         }
631
632         return ipAddress.getIpv6Address().getValue();
633     }
634 }