2 * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
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
9 package org.opendaylight.unimgr.mef.netvirt;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
14 import java.util.UUID;
16 import org.apache.commons.net.util.SubnetUtils;
17 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
23 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargetsBuilder;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4FamilyBuilder;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
30 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronVpnPortipPortData;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpnBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPortBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPortKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import com.google.common.base.Optional;
66 public class NetvirtVpnUtils {
67 private static final Logger logger = LoggerFactory.getLogger(NetvirtVpnUtils.class);
68 private final static String ELAN_PREFIX = "elan.";
69 private final static String TRUNK_SUFFIX = "-trunk";
70 private final static String VLAN_SEPARATOR = ".";
71 private final static String IP_ADDR_SUFFIX = "/32";
72 private final static String IP_MUSK_SEPARATOR = "/";
73 private final static int MaxRetries = 10;
75 public static void createVpnInstance(DataBroker dataBroker, String instanceName) {
76 VpnInstanceBuilder builder = new VpnInstanceBuilder();
77 builder.setVpnInstanceName(instanceName);
78 Ipv4FamilyBuilder ipv4FamilyBuilder = new Ipv4FamilyBuilder();
79 ipv4FamilyBuilder.setVpnTargets(new VpnTargetsBuilder().build());
80 // WA till netvirt will allow creation of VPN without RD
81 UUID vpnId = UUID.fromString(instanceName);
82 String rd = String.valueOf(Math.abs(vpnId.getLeastSignificantBits()));
83 ipv4FamilyBuilder.setRouteDistinguisher(rd);
84 builder.setIpv4Family(ipv4FamilyBuilder.build());
86 MdsalUtils.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
87 getVpnInstanceInstanceIdentifier(instanceName), builder.build());
90 public static void createUpdateVpnInterface(DataBroker dataBroker, String vpnName, String interfaceName,
91 IpPrefix ifPrefix, MacAddress macAddress, boolean primary, IpPrefix gwIpAddress) {
92 synchronized (interfaceName.intern()) {
93 String ipAddress = null;
94 String nextHopIp = null;
96 ipAddress = getPrefixFromSubnet(MefUtils.ipPrefixToString(ifPrefix));
98 ipAddress = MefUtils.ipPrefixToString(ifPrefix);
99 nextHopIp = getIpAddressFromPrefix(MefUtils.ipPrefixToString(gwIpAddress));
102 Adjacencies adjancencies = buildInterfaceAdjacency(ipAddress, macAddress, primary, nextHopIp);
103 VpnInterfaceBuilder einterfaceBuilder = createVpnInterface(vpnName, interfaceName, adjancencies);
105 MdsalUtils.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
106 getVpnInterfaceInstanceIdentifier(interfaceName), einterfaceBuilder.build());
110 private static Adjacencies buildInterfaceAdjacency(String ipAddress, MacAddress macAddress, boolean primary,
112 AdjacenciesBuilder builder = new AdjacenciesBuilder();
113 List<Adjacency> list = new ArrayList<Adjacency>();
115 AdjacencyBuilder aBuilder = new AdjacencyBuilder();
116 aBuilder.setIpAddress(ipAddress);
117 aBuilder.setMacAddress(macAddress.getValue());
118 aBuilder.setPrimaryAdjacency(primary);
119 if (nextHopIp != null) {
120 aBuilder.setNextHopIpList(Arrays.asList(nextHopIp));
122 list.add(aBuilder.build());
124 builder.setAdjacency(list);
125 return builder.build();
128 private static VpnInterfaceBuilder createVpnInterface(String instanceName, String interfaceName,
129 Adjacencies adjacencies) {
130 VpnInterfaceBuilder einterfaceBuilder = new VpnInterfaceBuilder();
131 einterfaceBuilder.setVpnInstanceName(instanceName);
132 einterfaceBuilder.setName(interfaceName);
133 einterfaceBuilder.addAugmentation(Adjacencies.class, adjacencies);
134 return einterfaceBuilder;
137 private static InstanceIdentifier<VpnInstance> getVpnInstanceInstanceIdentifier(String instanceName) {
138 return InstanceIdentifier.builder(VpnInstances.class).child(VpnInstance.class, new VpnInstanceKey(instanceName))
142 private static InstanceIdentifier<VpnInterface> getVpnInterfaceInstanceIdentifier(String interfaceName) {
143 return InstanceIdentifier.builder(VpnInterfaces.class)
144 .child(VpnInterface.class, new VpnInterfaceKey(interfaceName)).build();
147 public static void createVpnPortFixedIp(DataBroker dataBroker, String vpnName, String portName, IpPrefix ipAddress,
148 MacAddress macAddress) {
149 String fixedIpPrefix = MefUtils.ipPrefixToString(ipAddress);
150 String fixedIp = getIpAddressFromPrefix(fixedIpPrefix);
151 createVpnPortFixedIp(dataBroker, vpnName, portName, fixedIp, macAddress);
154 public static void createVpnPortFixedIp(DataBroker dataBroker, String vpnName, String portName, IpAddress ipAddress,
155 MacAddress macAddress) {
156 String fixedIp = MefUtils.ipAddressToString(ipAddress);
157 createVpnPortFixedIp(dataBroker, vpnName, portName, fixedIp, macAddress);
160 public static void createVpnPortFixedIp(DataBroker dataBroker, String vpnName, String portName, String fixedIp,
161 MacAddress macAddress) {
162 synchronized ((vpnName + fixedIp).intern()) {
163 InstanceIdentifier<VpnPortipToPort> id = buildVpnPortipToPortIdentifier(vpnName, fixedIp);
164 VpnPortipToPortBuilder builder = new VpnPortipToPortBuilder()
165 .setKey(new VpnPortipToPortKey(fixedIp, vpnName)).setVpnName(vpnName).setPortFixedip(fixedIp)
166 .setPortName(portName).setMacAddress(macAddress.getValue()).setSubnetIp(true).setConfig(true)
168 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
170 "Interface to fixedIp added: {}, vpn {}, interface {}, mac {} added to " + "VpnPortipToPort DS",
171 fixedIp, vpnName, portName, macAddress);
175 static InstanceIdentifier<NetworkMap> buildNetworkMapIdentifier(Uuid networkId) {
176 InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class)
177 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
181 private static void createSubnetToNetworkMapping(DataBroker dataBroker, Uuid subnetId, Uuid networkId) {
182 InstanceIdentifier<NetworkMap> networkMapIdentifier = buildNetworkMapIdentifier(networkId);
183 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
184 networkMapIdentifier);
185 NetworkMapBuilder nwMapBuilder = null;
186 if (optionalNetworkMap.isPresent()) {
187 nwMapBuilder = new NetworkMapBuilder(optionalNetworkMap.get());
189 nwMapBuilder = new NetworkMapBuilder().setKey(new NetworkMapKey(networkId)).setNetworkId(networkId);
190 logger.debug("Adding a new network node in NetworkMaps DS for network {}", networkId.getValue());
192 List<Uuid> subnetIdList = nwMapBuilder.getSubnetIdList();
193 if (subnetIdList == null) {
194 subnetIdList = new ArrayList<>();
196 subnetIdList.add(subnetId);
197 nwMapBuilder.setSubnetIdList(subnetIdList);
198 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, networkMapIdentifier, nwMapBuilder.build());
199 logger.debug("Created subnet-network mapping for subnet {} network {}", subnetId.getValue(),
200 networkId.getValue());
203 private static InstanceIdentifier<VpnPortipToPort> buildVpnPortipToPortIdentifier(String vpnName, String fixedIp) {
204 InstanceIdentifier<VpnPortipToPort> id = InstanceIdentifier.builder(NeutronVpnPortipPortData.class)
205 .child(VpnPortipToPort.class, new VpnPortipToPortKey(fixedIp, vpnName)).build();
209 public static void addDirectSubnetToVpn(DataBroker dataBroker,
210 final NotificationPublishService notificationPublishService, String vpnName, String subnetName,
211 IpPrefix subnetIpPrefix, String interfaceName) {
212 InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
213 .child(ElanInstance.class, new ElanInstanceKey(subnetName)).build();
214 Optional<ElanInstance> elanInstance = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
216 if (!elanInstance.isPresent()) {
217 logger.error("Trying to add invalid elan {} to vpn {}", subnetName, vpnName);
220 Long elanTag = elanInstance.get().getElanTag();
222 Uuid subnetId = new Uuid(subnetName);
223 logger.info("Adding subnet {} {} to elan map", subnetId);
224 createSubnetToNetworkMapping(dataBroker, subnetId, subnetId);
226 String subnetIp = getSubnetFromPrefix(MefUtils.ipPrefixToString(subnetIpPrefix));
227 logger.info("Adding subnet {} {} to vpn {}", subnetName, subnetIp, vpnName);
228 updateSubnetNode(dataBroker, new Uuid(vpnName), subnetId, subnetIp);
230 logger.info("Adding port {} to subnet {}", interfaceName, subnetName);
231 updateSubnetmapNodeWithPorts(dataBroker, subnetId, new Uuid(interfaceName));
233 logger.info("Publish subnet {}", subnetName);
234 publishSubnetAddNotification(notificationPublishService, subnetId, subnetIp, vpnName, elanTag);
238 protected static void updateSubnetNode(DataBroker dataBroker, Uuid vpnId, Uuid subnetId, String subnetIp) {
239 Subnetmap subnetmap = null;
240 SubnetmapBuilder builder = null;
241 InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
242 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
244 synchronized (subnetId.getValue().intern()) {
245 Optional<Subnetmap> sn = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
246 if (sn.isPresent()) {
247 builder = new SubnetmapBuilder(sn.get());
248 logger.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
250 builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
251 logger.debug("creating new subnetmap node for subnet ID {}", subnetId.getValue());
254 builder.setSubnetIp(subnetIp);
255 builder.setNetworkId(subnetId);
256 builder.setVpnId(vpnId);
258 subnetmap = builder.build();
259 logger.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
260 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
264 private static void updateSubnetmapNodeWithPorts(DataBroker dataBroker, Uuid subnetId, Uuid portId) {
265 Subnetmap subnetmap = null;
266 InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
267 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
268 synchronized (subnetId.getValue().intern()) {
269 Optional<Subnetmap> sn = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
270 if (sn.isPresent()) {
271 SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
272 if (null != portId) {
273 List<Uuid> portList = builder.getPortList();
274 if (null == portList) {
275 portList = new ArrayList<Uuid>();
277 portList.add(portId);
278 builder.setPortList(portList);
279 logger.debug("Updating subnetmap node {} with port {}", subnetId.getValue(), portId.getValue());
281 subnetmap = builder.build();
282 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
284 logger.error("Trying to update non-existing subnetmap node {} ", subnetId.getValue());
289 private static void publishSubnetAddNotification(final NotificationPublishService notificationPublishService,
290 Uuid subnetId, String subnetIp, String vpnName, Long elanTag) {
291 SubnetAddedToVpnBuilder builder = new SubnetAddedToVpnBuilder();
293 logger.info("publish notification called");
295 builder.setSubnetId(subnetId);
296 builder.setSubnetIp(subnetIp);
297 builder.setVpnName(vpnName);
298 builder.setExternalVpn(true);
299 builder.setElanTag(elanTag);
302 notificationPublishService.putNotification(builder.build());
303 } catch (InterruptedException e) {
304 logger.error("Fail to publish notification {}", builder, e);
305 throw new RuntimeException(e.getMessage());
309 private static String getIpAddressFromPrefix(String prefix) {
310 return prefix.split(IP_MUSK_SEPARATOR)[0];
313 private static String getMaskFromPrefix(String prefix) {
314 return prefix.split(IP_MUSK_SEPARATOR)[1];
317 private static String getSubnetFromPrefix(String prefix) {
318 SubnetInfo subnet = new SubnetUtils(prefix).getInfo();
319 return subnet.getNetworkAddress() + IP_MUSK_SEPARATOR + getMaskFromPrefix(prefix);
322 private static String getPrefixFromSubnet(String prefix) {
323 String myAddress = getIpAddressFromPrefix(prefix);
324 return myAddress + IP_ADDR_SUFFIX;
327 public static String getElanNameForVpnPort(String portName) {
328 return getUUidFromString(ELAN_PREFIX + portName);
331 public static String getInterfaceNameForVlan(String interfaceName, Integer vlan) {
332 final StringBuilder s = new StringBuilder();
333 s.append(interfaceName);
335 s.append(VLAN_SEPARATOR).append(vlan);
337 s.append(TRUNK_SUFFIX);
338 return getUUidFromString(s.toString());
341 public static String getUUidFromString(String key) {
342 return java.util.UUID.nameUUIDFromBytes(key.getBytes()).toString();
345 public static MacAddress resolveGwMac(DataBroker dataBroker, OdlArputilService arpUtilService, String vpnName,
346 IpPrefix srcIpPrefix, IpAddress dstIpAddress, String interf) {
348 String srcTpAddressStr = getIpAddressFromPrefix(MefUtils.ipPrefixToString(srcIpPrefix));
349 IpAddress srcIpAddress = new IpAddress(srcTpAddressStr.toCharArray());
351 if (srcIpAddress == null || dstIpAddress == null) {
352 logger.error("Can't send ARP to srcIp {} dstIp {}", srcIpAddress, dstIpAddress);
353 throw new RuntimeException("Can't send ARP for dstIp " + dstIpAddress);
356 MacAddress macAddress = null;
357 int retries = MaxRetries;
358 while (retries > 0 && macAddress == null) {
359 sendArpRequest(arpUtilService, srcIpAddress, dstIpAddress, interf);
360 macAddress = waitForArpReplyProcessing(dataBroker, vpnName, dstIpAddress, MaxRetries);
366 private static void sendArpRequest(OdlArputilService arpUtilService, IpAddress srcIpAddress, IpAddress dstIpAddress,
369 List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
371 .add(new InterfaceAddressBuilder().setInterface(interf).setIpAddress(srcIpAddress).build());
373 SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(dstIpAddress)
374 .setInterfaceAddress(interfaceAddresses).build();
375 arpUtilService.sendArpRequest(sendArpRequestInput);
376 } catch (Exception e) {
377 logger.error("Failed to send ARP request to IP {} from interfaces {}",
378 dstIpAddress.getIpv4Address().getValue(), interf, e);
379 throw new RuntimeException(e.getMessage());
383 public static MacAddress waitForArpReplyProcessing(DataBroker dataBroker, String vpnName, IpAddress dstIpAddress,
385 while (retries > 0) {
386 InstanceIdentifier<VpnPortipToPort> optionalPortIpId = buildVpnPortipToPortIdentifier(vpnName,
387 MefUtils.ipAddressToString(dstIpAddress));
388 Optional<VpnPortipToPort> optionalPortIp = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
391 if (optionalPortIp.isPresent()) {
392 return new MacAddress(optionalPortIp.get().getMacAddress());
400 private static void sleep() {
403 } catch (InterruptedException e) {