- Handled L2 Gw Connection CRUD related to Logical switch creation/Ucast/Mcast table updates in elanmanager module.
- Updated to use VXLAN provider segmentation id as the ELAN VNI for SR-IOV use cases.
Change-Id: If7bcc0a45a51773a75c7b7117a6a89e713e7eddc
Signed-off-by: Shashidhar R <shashidhar.raja@ericsson.com>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>neutronvpn-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.elanmanager.utils;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+
+public class ElanL2GwCacheUtils {
+ private static final ConcurrentHashMap<String, L2GatewayDevice> EMPTY_MAP = new ConcurrentHashMap<String, L2GatewayDevice>();
+ public static final String L2GATEWAY_CONN_CACHE_NAME = "L2GWCONN";
+
+ public static void createElanL2GwDeviceCache() {
+ if (CacheUtil.getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME) == null) {
+ CacheUtil.createCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ }
+ }
+
+ public static void addL2GatewayDeviceToCache(String elanName, L2GatewayDevice l2GwDevice) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
+ if (deviceMap == null) {
+ synchronized(ElanL2GwCacheUtils.class) {
+ deviceMap = cachedMap.get(elanName);
+ if (deviceMap == null) {
+ deviceMap = new ConcurrentHashMap<String, L2GatewayDevice>();
+ cachedMap.put(elanName, deviceMap);
+ }
+ }
+ }
+ deviceMap.put(l2GwDevice.getHwvtepNodeId(), l2GwDevice);
+ }
+
+ public static void removeL2GatewayDeviceFromAllElanCache(String deviceName) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ for (String elanName : cachedMap.keySet()) {
+ ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
+ if (deviceMap != null) {
+ deviceMap.remove(deviceName);
+ }
+ }
+ }
+
+
+ public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
+ if (deviceMap != null) {
+ L2GatewayDevice device = deviceMap.remove(deviceName);
+ return device;
+ } else {
+ return null;
+ }
+ }
+
+ public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
+ if (deviceMap != null) {
+ return deviceMap.get(deviceName);
+ } else {
+ return null;
+ }
+ }
+
+ public static ConcurrentMap<String, L2GatewayDevice> getAllElanL2GatewayDevicesFromCache(String elanName) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap = (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil
+ .getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ ConcurrentMap<String, L2GatewayDevice> result = cachedMap.get(elanName);
+ if (result == null) {
+ result = EMPTY_MAP;
+ }
+ return result;
+ }
+
+ public static List<L2GatewayDevice> getAllElanDevicesFromCache() {
+ List<String> l2GwsList = new ArrayList<>();
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ if (cachedMap == null || cachedMap.isEmpty()) {
+ return null;
+ }
+
+ List<L2GatewayDevice> l2GwDevices = new ArrayList<L2GatewayDevice>();
+ for (ConcurrentMap<String, L2GatewayDevice> l2gwDevices : cachedMap.values())
+ {
+ for (L2GatewayDevice l2gwDevice : l2gwDevices.values() ) {
+ l2GwDevices.add(l2gwDevice);
+ }
+ }
+
+ return l2GwDevices;
+ }
+
+}
import ietf-interfaces {
prefix if;
}
-
+ import ietf-inet-types {
+ prefix inet;
+ revision-date "2010-09-24";
+ }
import ietf-yang-types {
prefix yang;
}
description "elan module";
}
- /*
- * elan instance view.
- */
- container elan-instances {
- description
- "elan instances configuration parameters.
- elan instances support both the VLAN and VNI based elans.";
-
- list elan-instance {
- max-elements "unbounded";
- min-elements "0";
- key "elan-instance-name";
+ /*
+ * elan instance view.
+ */
+ container elan-instances {
description
- "Specifies the name of the elan instance. It is a string of 1 to 31
- case-sensitive characters.";
- leaf elan-instance-name {
- type string;
+ "elan instances configuration parameters. Elan instances support both the VLAN and VNI based elans.";
+
+ list elan-instance {
+ max-elements "unbounded";
+ min-elements "0";
+ key "elan-instance-name";
description
- "The name of the elan-instance.";
- }
- leaf elan-tag {
- type uint32;
- description "ELAN unique identifier which is unique across all the tenants. This will be created internally and if provided, the value will be discarded.";
- }
- leaf mac-timeout {
- type uint32 {
- range "0..65535";
+ "Specifies the name of the elan instance. It is a string of 1 to 31
+ case-sensitive characters.";
+ leaf elan-instance-name {
+ type string;
+ description "The name of the elan-instance.";
}
- description "MAC Table entry ageing time in seconds. A value of 0 will indicate that the MAC will never expire.";
- }
- leaf description {
- description
- "A textual description of elan instance, the elan instance description
- helps users memorize the elan instance.";
+ leaf elan-tag {
+ type uint32;
+ description "ELAN unique identifier which is unique across all the tenants.
+ This will be created internally and if provided, the value will be discarded.";
+ }
+ leaf vni {
+ type uint32;
+ description "Optional. Network identifier. It's mandatory when there are external devices
+ participating in the ELAN";
+ }
+ leaf mac-timeout {
+ type uint32 {
+ range "0..65535";
+ }
+ description "MAC Table entry ageing time in seconds.
+ A value of 0 will indicate that the MAC will never expire.";
+ }
+ leaf description {
+ description
+ "A textual description of elan instance, the elan instance description
+ helps users memorize the elan instance.";
- type string {
- length "1..254";
+ type string {
+ length "1..254";
+ }
}
}
}
- }
/*
* Binding Interfaces to a elan Instance.
<artifactId>elanmanager-impl</artifactId>
<version>${vpnservices.version}</version>
<packaging>bundle</packaging>
+
+ <properties>
+ <powermock.version>1.6.4</powermock.version>
+ <mockitoall.version>1.10.19</mockitoall.version>
+ </properties>
+
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>itm-api</artifactId>
<version>${vpnservices.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>neutronvpn-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>hwvtepsouthbound-api</artifactId>
+ <version>${vpns.ovsdb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.neutron</groupId>
+ <artifactId>model</artifactId>
+ <version>${neutron.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
<artifactId>interfacemgr-impl</artifactId>
<version>${vpnservices.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>dhcpservice-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+
+ <!-- Only for unit-test -->
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>${mockitoall.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
<capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28</capability>
<capability>urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&revision=2015-04-10</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:distributed-entity-ownership-service?module=distributed-entity-ownership-service&revision=2015-08-10</capability>
<capability>urn:opendaylight:vpnservice:itm?module=itm&revision=2015-07-01</capability>
<capability>urn:opendaylight:vpnservice:interfacemgr?module=odl-interface&revision=2015-03-31</capability>
</required-capabilities>
<type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
<name>binding-notification-adapter</name>
</notification-service>
+ <entity-ownership-service>
+ <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+ <name>entity-ownership-service</name>
+ </entity-ownership-service>
+ <binding-normalized-node-serializer>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-normalized-node-serializer>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.elan.cli.l2gw;
+
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Command(scope = "l2gw", name = "show-cache", description = "display l2gateways cache")
+public class L2GwUtilsCacheCli extends OsgiCommandSupport {
+ private static final Logger logger = LoggerFactory.getLogger(L2GwUtilsCacheCli.class);
+
+ private static final String DEMARCATION = "=================================";
+
+ @Option(name = "-cache", aliases = {"--cache"}, description = "cache name",
+ required = false, multiValued = false)
+ String cacheName = null;
+
+ @Option(name = "-elan", aliases = {"--elan"}, description = "elan name",
+ required = false, multiValued = false)
+ String elanName;
+
+ @Override
+ protected Object doExecute() {
+ try {
+ if (cacheName == null) {
+ System.out.println("Available caches");
+ System.out.println(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
+ System.out.println(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
+ return null;
+ }
+ switch (cacheName) {
+ case ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME:
+ dumpElanL2GwCache();
+ break;
+ case L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME:
+ dumpL2GwCache();
+ break;
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+ }
+
+ private void dumpL2GwCache() {
+ ConcurrentMap<String, L2GatewayDevice> devices = (ConcurrentMap<String, L2GatewayDevice>) CacheUtil
+ .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
+ if (devices == null) {
+ System.out.println("no devices are present in cache");
+ return;
+ }
+ for (String deviceName : devices.keySet()) {
+ System.out.println("device "+ devices.get(deviceName));
+ }
+ }
+
+ private void dumpElanL2GwCache() {
+ if (elanName == null) {
+ ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cache =
+ (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
+ cacheName);
+ if (cache == null) {
+ System.out.println("no devices are present in elan cache");
+ }
+ for (String elan : cache.keySet()) {
+ print(elan, cache.get(elan));
+ System.out.println(DEMARCATION);
+ System.out.println(DEMARCATION);
+ }
+ return;
+ }
+ ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+ print(elanName, elanDevices);
+ }
+
+ private void print(String elan,
+ ConcurrentMap<String, L2GatewayDevice> devices) {
+ System.out.println("Elan name : "+elan);
+ System.out.println("No of devices in elan "+devices.keySet().size());
+ for (String deviceName : devices.keySet()) {
+ System.out.println("device "+ devices.get(deviceName));
+ }
+ }
+}
public void deleteElanInterfaceForwardingEntries(ElanInstance elanInfo, InterfaceInfo interfaceInfo, MacEntry macEntry) {
InstanceIdentifier<MacEntry> macEntryId = ElanUtils.getMacEntryOperationalDataPath(elanInfo.getElanInstanceName(), macEntry.getMacAddress());
ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, macEntryId);
+ deleteElanInterfaceForwardingTablesList(interfaceInfo.getInterfaceName(), macEntry);
ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry);
}
}
+ /**
+ * Starts listening for changes in elan.yang:elan-instance container
+ */
public void registerListener() {
try {
elanInstanceListenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
}
@Override
- protected void remove(InstanceIdentifier<ElanInstance> identifier, ElanInstance del) {
- logger.trace("Remove ElanInstance - Key: {}, value: {}", identifier, del);
- String elanName = del.getElanInstanceName();
+ protected void remove(InstanceIdentifier<ElanInstance> identifier, ElanInstance deletedElan) {
+ logger.trace("Remove ElanInstance - Key: {}, value: {}", identifier, deletedElan);
+ String elanName = deletedElan.getElanInstanceName();
//check the elan Instance present in the Operational DataStore
Elan existingElan = ElanUtils.getElanByName(elanName);
- long elanTag = del.getElanTag();
+ long elanTag = deletedElan.getElanTag();
//Cleaning up the existing Elan Instance
if(existingElan != null) {
List<String> elanInterfaces = existingElan.getElanInterfaces();
if(elanInterfaces != null && !elanInterfaces.isEmpty()) {
for (String elanInterfaceName : elanInterfaces) {
InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName);
- elanInterfaceManager.removeElanInterface(del, elanInterfaceName);
+ elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName);
ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
}
}
return;
} else if (update.getElanTag() == null) {
// update the elan-Instance with new properties
- if(original.getMacTimeout().equals(update.getMacTimeout()) && original.getDescription().equalsIgnoreCase(update.getDescription())) {
- return;
- }
- ElanUtils.UpdateOperationalDataStore(broker, idManager, update);
+ ElanUtils.updateOperationalDataStore(broker, idManager, update);
return;
}
elanInterfaceManager.handleunprocessedElanInterfaces(update);
protected void add(InstanceIdentifier<ElanInstance> identifier, ElanInstance elanInstanceAdded) {
Elan elanInfo = ElanUtils.getElanByName(elanInstanceAdded.getElanInstanceName());
if(elanInfo == null) {
- ElanUtils.UpdateOperationalDataStore(broker, idManager, elanInstanceAdded);
+ ElanUtils.updateOperationalDataStore(broker, idManager, elanInstanceAdded);
}
}
*/
package org.opendaylight.vpnservice.elan.internal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
-
+import org.opendaylight.vpnservice.itm.api.IITMProvider;
+import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.vpnservice.mdsalutil.*;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+/**
+ * Class in charge of handling creations, modifications and removals of ElanInterfaces.
+ *
+ * @see org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface
+ *
+ */
public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterface> implements AutoCloseable {
private static ElanInterfaceManager elanInterfaceManager = new ElanInterfaceManager();
public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
String elanName = elanInfo.getElanInstanceName();
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+
if (interfaceInfo == null) {
+ // Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
}
- return;
+ } else {
+ removeElanInterface(elanInfo, interfaceInfo);
+ unbindService(elanInfo, interfaceName);
}
- removeElanInterface(elanInfo, interfaceInfo);
- unbindService(elanInfo, interfaceName);
}
private void removeElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
Optional<ElanInterfaceMac> existingElanInterface = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
if(existingElanInterface.isPresent()) {
- List<MacEntry> macEntries = existingElanInterface.get().getMacEntry();
- if(macEntries != null && !macEntries.isEmpty()) {
+ List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
+ List<MacEntry> existingMacEntries = existingElanInterface.get().getMacEntry();
+ List<MacEntry> macEntries = new ArrayList<>();
+ if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
+ macEntries.addAll(existingMacEntries);
+ }
+ if(!macEntries.isEmpty()) {
for (MacEntry macEntry : macEntries) {
logger.debug("removing the mac-entry:{} present on elanInterface:{}", macEntry.getMacAddress().getValue(), interfaceName);
elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(elanInfo, interfaceInfo, macEntry);
+ macAddresses.add(macEntry.getMacAddress());
+ }
+
+ // Removing all those MACs from External Devices belonging to this ELAN
+ if ( elanInfo.getVni() != null && elanInfo.getVni() != 0 ) {
+ ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
}
}
}
if(dpnInterfaces != null) {
List<String> interfaceLists = dpnInterfaces.getInterfaces();
interfaceLists.remove(interfaceName);
- updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
+
+ if (interfaceLists == null || interfaceLists.isEmpty()) {
+ deleteElanDpnInterface(elanName, dpId);
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName);
+ } else {
+ updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
+ }
}
}
String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
String interfaceName = elanInterfaceAdded.getName();
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+ if (interfaceInfo == null) {
+ logger.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
+ return;
+ }
ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
if (elanInstance == null) {
elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInterfaceAdded.getDescription()).build();
//Add the ElanInstance in the Configuration data-store
- ElanUtils.UpdateOperationalDataStore(broker, idManager, elanInstance);
+ ElanUtils.updateOperationalDataStore(broker, idManager, elanInstance);
elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
}
}
}
+ void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo){
+ ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanInstance.getElanInstanceName());
+ List<DpnInterfaces> dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
+ for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
+ if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
+ continue;
+ }
+ List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
+ for(String remoteIf : remoteElanInterfaces) {
+ ElanInterfaceMac elanIfMac = ElanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
+ InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
+ if(elanIfMac == null) {
+ continue;
+ }
+ List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
+ if(remoteMacEntries != null) {
+ for (MacEntry macEntry : remoteMacEntries) {
+ PhysAddress physAddress = macEntry.getMacAddress();
+ ElanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
+ remoteInterface.getInterfaceTag(),
+ elanInstance.getElanTag(),
+ physAddress.getValue(),
+ elanInstance.getElanInstanceName());
+ }
+ }
+ }
+ }
+ }
+
void addElanInterface(ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
+ Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
+ Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
+ Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
+
String interfaceName = elanInterface.getName();
String elanInstanceName = elanInterface.getElanInstanceName();
List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
+
Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
- BigInteger dpId = null;
if(elanInfo == null) {
- ElanUtils.UpdateOperationalDataStore(broker, idManager, elanInstance);
- }
- if(interfaceInfo != null) {
- dpId = interfaceInfo.getDpId();
+ ElanUtils.updateOperationalDataStore(broker, idManager, elanInstance);
}
+
+ // Specific actions to the DPN where the ElanInterface has been added, for example, programming the
+ // External tunnel table if needed or adding the ElanInterface to the DpnInterfaces in the operational DS.
+ BigInteger dpId = ( interfaceInfo != null ) ? dpId = interfaceInfo.getDpId() : null;
if(dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
if (!existingElanDpnInterfaces.isPresent()) {
+ // ELAN's 1st ElanInterface added to this DPN
createElanInterfacesList(elanInstanceName, interfaceName, dpId);
+ /*
+ * Install remote DMAC flow.
+ * This is required since this DPN is added later to the elan instance
+ * and remote DMACs of other interfaces in this elan instance are not present in the current dpn.
+ */
+ programRemoteDmacFlow(elanInstance, interfaceInfo);
+ // The 1st ElanInterface in a DPN must program the Ext Tunnel table, but only if Elan has VNI
+ if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
+ setExternalTunnelTable(dpId, elanInstance);
+ }
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
} else {
List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
elanInterfaces.add(interfaceName);
+ if (elanInterfaces.size() == 1) {//1st dpn interface
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+ }
updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
}
}
//Add interface to the ElanInterfaceForwardingEntires Container
createElanInterfaceTablesList(interfaceName);
createElanStateList(elanInstanceName, interfaceName);
- if(interfaceInfo != null) {
+ if (interfaceInfo != null) {
installFlowsAndGroups(elanInstance, interfaceInfo);
}
// add the static mac addresses
- if(staticMacAddresses != null) {
+ if (staticMacAddresses != null) {
+ boolean isInterfaceOperational = isOperational(interfaceInfo);
for (PhysAddress physAddress : staticMacAddresses) {
InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
} else {
elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress);
}
- if(interfaceInfo != null && isOperational(interfaceInfo)) {
- logger.debug("Installing Static Mac-Entry on the Elan Interface:{} with MacAddress:{}", interfaceInfo, physAddress.getValue());
+
+ if ( isInterfaceOperational ) {
+ // Setting SMAC, DMAC, UDMAC in this DPN and also in other DPNs
ElanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, physAddress.getValue());
}
}
- }
- }
- private Map<BigInteger, List<String>> readFePortsDbForElan(String elanName) {
- ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanName);
- HashMap<BigInteger, List<String>> fePortsDb = Maps.newHashMap();
- if (elanDpnInterfacesList == null) {
- return fePortsDb;
- }
- List<DpnInterfaces> dpnInterfaces = elanDpnInterfacesList.getDpnInterfaces();
- if (dpnInterfaces == null) {
- return fePortsDb;
- }
- for (DpnInterfaces dpnInterface : dpnInterfaces) {
- fePortsDb.put(dpnInterface.getDpId(), dpnInterface.getInterfaces());
+ if( isInterfaceOperational ) {
+ // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
+ ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, staticMacAddresses);
+ }
}
- return fePortsDb;
}
protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName, PhysAddress physAddress) {
Flow flowEntry = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
- getInstructionsDrop());
+ MDSALUtil.buildInstructionsDrop());
mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntry);
}
Flow flowEntity = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
- getInstructionsDrop());
+ MDSALUtil.buildInstructionsDrop());
mdsalManager.removeFlow(interfaceInfo.getDpId(), flowEntity);
}
for(DpnInterfaces dpnInterface : dpnInterfaceses) {
if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
try {
- List<Action> listAction = ElanUtils.getItmEgressAction(dpnId, dpnInterface.getDpId(), (int) elanTag);
+ List<Action> listAction = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
bucketId++;
} catch (Exception ex) {
}
}
}
+ List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
+ listBuckets.addAll(elanL2GwDevicesBuckets);
}
return listBuckets;
}
for(DpnInterfaces dpnInterface : dpnInterfaceses) {
if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
try {
- List<Action> listActionInfo = ElanUtils.getItmEgressAction(dpnId, dpnInterface.getDpId(), (int) elanTag);
+ List<Action> listActionInfo = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, 0, bucketId, 0xffffffffL, 0xffffffffL));
bucketId++;
} catch (Exception ex) {
}
}
}
+
+ List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
+ listBucketInfo.addAll(elanL2GwDevicesBuckets);
}
return listBucketInfo;
}
if (ElanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
&& otherFes.getInterfaces() != null && ! otherFes.getInterfaces().isEmpty()) {
try {
- List<Action> remoteListActionInfo = ElanUtils.getItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), (int) elanTag);
+ List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,MDSALUtil.WATCH_GROUP));
bucketId++;
} catch (Exception ex) {
}
}
}
- if(remoteListBucketInfo.size() == 0) {
+ List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
+ bucketId);
+ remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
+
+ if (remoteListBucketInfo.size() == 0) {
logger.debug( "No ITM is present on Dpn - {} " ,dpnInterface.getDpId());
continue;
}
InterfaceInfo interfaceInfo, BigInteger dstDpId) {
int elanTag = elanInfo.getElanTag().intValue();
long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
- DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), interfaceInfo.getDpId());
List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
if(elanDpns != null) {
for(DpnInterfaces dpnInterface : elanDpns) {
int bucketId = 0;
List<Bucket> remoteListBucket = new ArrayList<Bucket>();
if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
- for(String ifName : dpnInterfaces.getInterfaces()) {
- // In case if there is a InterfacePort in the cache which is not in
- // operational state, skip processing it
- InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
- if (!isOperational(ifInfo)) {
- continue;
- }
-
- remoteListBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
- bucketId++;
- }
try {
- List<Action> remoteListActionInfo = ElanUtils.getItmEgressAction(interfaceInfo.getDpId(), dstDpId, (int) elanTag);
+ List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(interfaceInfo.getDpId(), dstDpId, elanTag);
remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
bucketId++;
} catch (Exception ex) {
logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), dstDpId);
return;
}
+ List<Action> remoteListActionInfo = new ArrayList<Action>();
+ remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}).buildAction());
+ remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+
+ List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dstDpId, bucketId);
+ remoteListBucket.addAll(elanL2GwDevicesBuckets);
+
Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucket));
mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
break;
return mkMatches;
}
+
+ private List<MatchInfo> buildMatchesForVni(Long vni) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id,
+ new BigInteger[]{BigInteger.valueOf(vni)} );
+ mkMatches.add(match);
+ return mkMatches;
+ }
+
private List<Instruction> getInstructionsForOutGroup(
long groupId) {
List<Instruction> mkInstructions = new ArrayList<Instruction>();
List <Action> actions = new ArrayList <Action> ();
actions.add(new ActionInfo(ActionType.group, new String[]{Long.toString(groupId)}).buildAction());
- mkInstructions.add(ElanUtils.getWriteActionInstruction(actions));
+ mkInstructions.add(MDSALUtil.getWriteActionsInstruction(actions, 0));
+ return mkInstructions;
+ }
+
+ private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ // Matching metadata
+ mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet),
+ MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG}));
+ return mkMatches;
+ }
+
+
+
+
+ /**
+ * Builds the list of instructions to be installed in the External Tunnel table (38), which so far
+ * consists in writing the elanTag in metadata and send packet to the new DHCP table
+ *
+ * @param elanTag elanTag to be written in metadata when flow is selected
+ * @return the instructions ready to be installed in a flow
+ */
+ private List<InstructionInfo> getInstructionsExtTunnelTable(Long elanTag) {
+ List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
+ mkInstructions.add(new InstructionInfo(InstructionType.write_metadata,
+ new BigInteger[] {
+ ElanUtils.getElanMetadataLabel(elanTag),
+ ElanUtils.getElanMetadataMask()
+ } ) );
+ // TODO (eperefr) We should point to SMAC or DMAC depending on a configuration property to enable
+ // mac learning
+ mkInstructions.add(new InstructionInfo(InstructionType.goto_table,
+ new long[] { ElanConstants.ELAN_DMAC_TABLE }));
+
return mkInstructions;
}
}
public void installMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+
String interfaceName = interfaceInfo.getInterfaceName();
BigInteger currentDpn = interfaceInfo.getDpId();
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
for(MacEntry macEntry : macEntries) {
PhysAddress physAddress = macEntry.getMacAddress();
- ElanUtils.setupMacFlows(elanInfo, interfaceInfo, macEntry.isIsStaticAddress() ? ElanConstants.STATIC_MAC_TIMEOUT : elanInfo.getMacTimeout(), physAddress.getValue());
+ ElanUtils.setupMacFlows(elanInfo,
+ interfaceInfo,
+ macEntry.isIsStaticAddress()
+ ? ElanConstants.STATIC_MAC_TIMEOUT
+ : elanInfo.getMacTimeout(), physAddress.getValue());
}
//Programming the remoteDMACFlows
ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
if(remoteMacEntries != null) {
for (MacEntry macEntry : remoteMacEntries) {
PhysAddress physAddress = macEntry.getMacAddress();
- ElanUtils.setupRemoteDmacFlow(currentDpn, remoteInterface.getDpId(), remoteInterface.getInterfaceTag(), elanInfo.getElanTag(), physAddress.getValue(), elanInfo.getElanInstanceName());
+ ElanUtils.installDmacFlowsToInternalRemoteMac(currentDpn, remoteInterface.getDpId(),
+ remoteInterface.getInterfaceTag(),
+ elanInfo.getElanTag(),
+ physAddress.getValue(),
+ elanInfo.getElanInstanceName());
}
}
}
// In case if there is a InterfacePort in the cache which is not in
// operational state, skip processing it
InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
- if (ifInfo == null || !isOperational(ifInfo)) {
+ if (!isOperational(ifInfo)) {
continue;
}
Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
logger.trace("installing the localBroadCast Group:{}", group);
- // In the case of OVS disconnected we receive null object when we query Interface Operation datastore
- // so the size of the bucket will be zero
- if(listBucket.size() == 0) {
- mdsalManager.syncRemoveGroup(dpnId, group);
- } else {
- mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
- }
+ mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
}
public void setupLocalBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
// In case if there is a InterfacePort in the cache which is not in
// operational state, skip processing it
InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
- if (ifInfo == null || !isOperational(ifInfo)) {
+ if (!isOperational(ifInfo)) {
continue;
}
bucketId++;
}
-
Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
logger.trace("installing the localBroadCast Group:{}", group);
- // In the case of OVS disconnected we receive null object for the Interface Operation datastore
- // so the size of the bucket will be zero
- if(listBucket.size() == 0) {
- mdsalManager.syncRemoveGroup(dpnId, group);
- } else {
- mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
- }
+ mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
}
public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
mdsalManager.syncRemoveGroup(dpnId, group);
}
+ /**
+ * Installs a flow in the External Tunnel table consisting in translating
+ * the VNI retrieved from the packet that came over a tunnel with a TOR into
+ * elanTag that will be used later in the ELANs pipeline.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param elanInfo
+ * the elan info
+ */
+ public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
+ long elanTag = elanInfo.getElanTag();
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
+ NwConstants.EXTERNAL_TUNNEL_TABLE,
+ getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag),
+ 5, // prio
+ elanInfo.getElanInstanceName(), // flowName
+ 0, // idleTimeout
+ 0, // hardTimeout
+ ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
+ buildMatchesForVni(elanInfo.getVni()),
+ getInstructionsExtTunnelTable(elanTag) );
+
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ /**
+ * Removes, from External Tunnel table, the flow that translates from VNI to elanTag.
+ * Important: ensure this method is only called whenever there is no other ElanInterface in the specified DPN
+ *
+ * @param dpnId DPN whose Ext Tunnel table is going to be modified
+ * @param elanInfo holds the elanTag needed for selecting the flow to be removed
+ */
+ public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
+ // TODO (eperefr): Use DataStoreJobCoordinator in order to avoid that removing the last ElanInstance plus
+ // adding a new one does (almost at the same time) are executed in that exact order
+
+ String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
+ FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setFlowId(flowId);
+ mdsalManager.removeFlow(flowEntity);
+ }
+
public void setupTerminateServiceTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
long elanTag = elanInfo.getElanTag();
Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, elanTag),
public void setupUnknownDMacTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
long elanTag = elanInfo.getElanTag();
- Flow flowEntity = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag),
- 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag),
+ Flow flowEntity = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/false),
+ 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/false),
getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGID(elanTag)));
mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntity);
+
+ // only if vni is present in elanInfo, perform the following
+ if (elanInfo.getVni() != null && elanInfo.getVni() != 0) {
+ Flow flowEntity2 = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/true),
+ 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/true),
+ getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
+ mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntity2);
+ }
+
}
+
private void removeStaticELanFlows(final ElanInstance elanInfo, final InterfaceInfo interfaceInfo) {
BigInteger dpId = interfaceInfo.getDpId();
- long elanTag = elanInfo.getElanTag();
/*
* If there are not elan ports, remove the unknown smac and default dmac
* flows
*/
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpId);
- if(dpnInterfaces == null) {
- return;
- }
- List <String> elanInterfaces = dpnInterfaces.getInterfaces();
- if (elanInterfaces == null || elanInterfaces.isEmpty()) {
-
+ if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null || dpnInterfaces.getInterfaces().isEmpty()) {
+ // No more Elan Interfaces in this DPN
logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
removeDefaultTermFlow(dpId, elanInfo.getElanTag());
removeUnknownDmacFlow(dpId, elanInfo);
removeElanBroadcastGroup(elanInfo, interfaceInfo);
removeLocalBroadcastGroup(elanInfo, interfaceInfo);
+ if ( elanInfo.getVni() != null && elanInfo.getVni().longValue() != 0 ) {
+ unsetExternalTunnelTable(dpId, elanInfo);
+ }
removeFilterEqualsTable(elanInfo, interfaceInfo);
} else {
setupElanBroadcastGroups(elanInfo, interfaceInfo);
}
private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo) {
- Flow flow = getUnknownDmacFlowEntity(dpId, elanInfo);
+// Flow flow = getUnknownDmacFlowEntity(dpId, elanInfo);
+// mdsalManager.removeFlow(dpId, flow);
+ Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE,
+ elanInfo.getElanTag(), /*SH flag*/ false)))
+ .setTableId(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE)
+ .build();
mdsalManager.removeFlow(dpId, flow);
+
+ if ( elanInfo.getVni() != null && elanInfo.getVni() > 0 ) {
+ Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE,
+ elanInfo.getElanTag(), /*SH flag*/ true)))
+ .setTableId(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE)
+ .build();
+ mdsalManager.removeFlow(dpId, flow2);
+ }
+
+
}
private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
ElanUtils.DEFAULT_CALLBACK);
}
- private Flow getUnknownDmacFlowEntity(BigInteger dpId, ElanInstance elanInfo) {
- long elanTag = elanInfo.getElanTag();
- List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
- // Matching metadata
- mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
- ElanUtils.getElanMetadataLabel(elanTag),
- MetaDataUtil.METADATA_MASK_SERVICE }));
-
- List<Instruction> mkInstructions = new ArrayList<Instruction>();
- List <Action> actionsInfos = new ArrayList <Action> ();
- actionsInfos.add(new ActionInfo(ActionType.group, new String[]{Long.toString(ElanUtils.getElanRemoteBCGID(elanTag))}, 0).buildAction());
- mkInstructions.add(ElanUtils.getWriteActionInstruction(actionsInfos));
-
- Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag),
- 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
- mkMatches, mkInstructions);
- return flow;
- }
-
private String getFlowRef(long tableId, long elanTag) {
return new StringBuffer().append(tableId).append(elanTag).toString();
}
+ private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
+ return new StringBuffer().append(tableId).append(elanTag).append(shFlag).toString();
+ }
+
private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
List<Action> listAction = new ArrayList<Action>();
int actionKey = 0;
listAction.add((new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {BigInteger.valueOf(interfaceInfo.getInterfaceTag())}, actionKey)).buildAction());
actionKey++;
- listAction.add((new ActionInfo(ActionType.nx_resubmit, new String[] {Short.toString((short)55)}, actionKey)).buildAction());
+ listAction.add((new ActionInfo(ActionType.nx_resubmit,
+ new String[] {String.valueOf(ElanConstants.ELAN_FILTER_EQUALS_TABLE)}, actionKey)).buildAction());
return listAction;
}
dpnInterface);
}
+ /**
+ * Delete elan dpn interface from operational DS.
+ *
+ * @param elanInstanceName
+ * the elan instance name
+ * @param dpId
+ * the dp id
+ */
+ private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId) {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,
+ ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
+ }
+
private List<String> createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId) {
List<String> interfaceNames = new ArrayList<String>();
interfaceNames.add(interfaceName);
}
private boolean isOperational(InterfaceInfo interfaceInfo) {
+ if (interfaceInfo == null) {
+ return false;
+ }
return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
}
}
}
- public void handleInterfaceUpated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
+ public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
BigInteger dpId = interfaceInfo.getDpId();
String elanName = elanInstance.getElanInstanceName();
String ifName = interfaceInfo.getInterfaceName();
logger.trace("ElanInterface Service is removed for the interface:{}", ifName);
elanInterfaceManager.removeMacAddressTables(elanInstance, interfaceInfo);
elanInterfaceManager.removeFlowsAndGroups(elanInstance, interfaceInfo);
+
+ // Removing MACs from External Devices belonging to this ELAN
+ if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
+ List<PhysAddress> macAddresses = ElanUtils
+ .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
+ if (macAddresses != null && !macAddresses.isEmpty()) {
+ ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInstance, macAddresses);
+ }
+ }
}
}
mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
BigInteger.valueOf(LportTag)}));
return mkMatches;
+ }
+ public void updateElanBroadcastGroup(ElanInstance elanInfo) {
+ int bucketId = 0;
+ long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo
+ .getElanInstanceName());
+ if (dpns == null) {
+ return;
+ }
+ for (DpnInterfaces dpn : dpns) {
+ bucketId = 0;
+ List<Bucket> listBucket = new ArrayList<Bucket>();
+ bucketId = getLocalBcGroupBuckets(dpn, listBucket, bucketId);
+ getRemoteBCGroupBuckets(elanInfo, dpn.getDpId(), listBucket,
+ bucketId);
+ Group group = MDSALUtil.buildGroup(groupId,
+ elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+ MDSALUtil.buildBucketLists(listBucket));
+ logger.trace("installing the localBroadCast Group:{}", group);
+ mdsalManager.syncInstallGroup(dpn.getDpId(), group,
+ ElanConstants.DELAY_TIME_IN_MILLISECOND);
+ }
}
- private List<Instruction> getInstructionsDrop() {
- List<Instruction> mkInstructions = new ArrayList<Instruction>();
- List <Action> actionsInfos = new ArrayList <Action> ();
- actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[]{}).buildAction());
- mkInstructions.add(ElanUtils.getWriteActionInstruction(actionsInfos));
- return mkInstructions;
+ private int getLocalBcGroupBuckets(DpnInterfaces dpn,
+ List<Bucket> listBucket, int bucketId) {
+ for (String intf : dpn.getInterfaces()) {
+ InterfaceInfo ifInfo = interfaceManager.getInterfaceInfo(intf);
+ if (!isOperational(ifInfo)) {
+ continue;
+ }
+ listBucket.add(MDSALUtil.buildBucket(
+ getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT,
+ bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+ bucketId++;
+ }
+ return bucketId;
+ }
+
+ private void getRemoteBCGroupBuckets(ElanInstance elanInfo,
+ BigInteger dpnId, List<Bucket> listBucket, int bucketId) {
+ int elanTag = elanInfo.getElanTag().intValue();
+ ElanDpnInterfacesList elanDpns = ElanUtils
+ .getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+ if (elanDpns != null) {
+ List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
+ for (DpnInterfaces dpnInterface : dpnInterfaceses) {
+ if (ElanUtils.isDpnPresent(dpnInterface.getDpId())
+ && dpnInterface.getDpId() != dpnId
+ && dpnInterface.getInterfaces() != null
+ && !dpnInterface.getInterfaces().isEmpty()) {
+ try {
+ List<Action> listActionInfo = ElanUtils
+ .getInternalItmEgressAction(dpnId,
+ dpnInterface.getDpId(), elanTag);
+ listBucket.add(MDSALUtil.buildBucket(listActionInfo, 0,
+ bucketId, 0xffffffffL, 0xffffffffL));
+ bucketId++;
+ } catch (Exception ex) {
+ logger.error(
+ "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
+ dpnId, dpnInterface.getDpId());
+ }
+ }
+ }
+ }
+ List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
+ listBucket.addAll(elanL2GwDevicesBuckets);
+ }
+
+ public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
+ int bucketId) {
+ List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+ ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanInfo.getElanInstanceName());
+ for (L2GatewayDevice device : map.values()) {
+ String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
+ device.getHwvtepNodeId());
+ if (interfaceName == null) {
+ continue;
+ }
+ List<Action> listActionInfo = ElanUtils.buildItmEgressActions(interfaceName, elanInfo.getVni());
+ listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
+ MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+ bucketId++;
+ }
+ return listBucketInfo;
}
}
+
+
}
logger.trace("ElanService Interface Operational state has changes for Interface:{}", interfaceName);
- elanInterfaceManager.handleInterfaceUpated(interfaceInfo, elanInfo , isStateUp);
+ elanInterfaceManager.handleInterfaceUpdated(interfaceInfo, elanInfo , isStateUp);
}
@Override
return;
}
NodeConnectorId nodeConnectorId = new NodeConnectorId(delIf.getLowerLayerIf().get(0));
- BigInteger dpId = MDSALUtil.getDpnIdFromNodeName(nodeConnectorId.getValue());
+ BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
InterfaceInfo interfaceInfo = new InterfaceInfo(dpId, nodeConnectorId.getValue());
interfaceInfo.setInterfaceName(interfaceName);
interfaceInfo.setInterfaceType(InterfaceInfo.InterfaceType.VLAN_INTERFACE);
if (tunnelList.getInternalTunnel() != null) {
List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
for (InternalTunnel tunnel : internalTunnels) {
- if (internalTunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
+ if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
internalTunnel = tunnel;
break;
}
protected void add(InstanceIdentifier<Node> identifier, Node add) {
NodeId nodeId = add.getId();
String[] node = nodeId.getValue().split(":");
+ if(node.length < 2) {
+ logger.warn("Unexpected nodeId {}", nodeId.getValue());
+ return;
+ }
BigInteger dpId = new BigInteger(node[1]);
createTableMissEntry(dpId);
}
*/
package org.opendaylight.vpnservice.elan.internal;
+import java.math.BigInteger;
+
+import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
-//import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.NWUtil;
-import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.NoMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.interfacemgr.impl.rev150325.InterfacemgrImpl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+@SuppressWarnings("deprecation")
public class ElanPacketInHandler implements PacketProcessingListener {
private final DataBroker broker;
long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
- IfIndexInterface interfaceInfo = ElanUtils.getInterfaceInfoByInterfaceTag(portTag);
- if (interfaceInfo == null) {
+ Optional<IfIndexInterface> interfaceInfoOp = ElanUtils.getInterfaceInfoByInterfaceTag(portTag);
+ if (!interfaceInfoOp.isPresent()) {
logger.warn("There is no interface for given portTag {}", portTag);
return;
}
- String interfaceName = interfaceInfo.getInterfaceName();
+ String interfaceName = interfaceInfoOp.get().getInterfaceName();
ElanTagName elanTagName = ElanUtils.getElanInfoByElanTag(elanTag);
+ if (elanTagName == null) {
+ logger.warn("not able to find elanTagName in elan-tag-name-map for elan tag {}", elanTag);
+ return;
+ }
String elanName = elanTagName.getName();
- Elan elanInfo = ElanUtils.getElanByName(elanName);
MacEntry macEntry = ElanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
if(macEntry != null && macEntry.getInterface() == interfaceName) {
BigInteger macTimeStamp = macEntry.getControllerLearnedForwardingEntryTimestamp();
MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanName);
ElanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), elanInstance.getMacTimeout(), macAddress);
+
+ BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
+ ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, Arrays.asList(physAddress));
} catch (Exception e) {
logger.trace("Failed to decode packet: {}", e);
}
return;
}
ElanUtils.deleteMacFlows(elanInfo, oldInterfaceLport, macEntry);
+ ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, Arrays.asList(macEntry.getMacAddress()));
}
}
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
+
package org.opendaylight.vpnservice.elan.internal;
-import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Future;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.elanmanager.api.IElanService;
+import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
+import org.opendaylight.vpnservice.elan.l2gw.internal.ElanL2GatewayProvider;
import org.opendaylight.vpnservice.elan.statisitcs.ElanStatisticsImpl;
+import org.opendaylight.vpnservice.elan.statusanddiag.ElanStatusMonitor;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
import org.opendaylight.vpnservice.itm.api.IITMProvider;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Future;
+import com.google.common.base.Optional;
public class ElanServiceProvider implements BindingAwareProvider, IElanService, AutoCloseable {
private ElanNodeListener elanNodeListener;
private NotificationService notificationService;
private RpcProviderRegistry rpcProviderRegistry;
+ private IITMProvider itmManager;
+ private ItmRpcService itmRpcService;
+ private DataBroker broker;
+ private ElanL2GatewayProvider elanL2GatewayProvider;
+
+ private EntityOwnershipService entityOwnershipService;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+
+ private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
rpcProviderRegistry = rpcRegistry;
+ elanStatusMonitor.registerMbean();
}
- //private ElanInterfaceStateChangeListener elanInterfaceEventListener;
+ // private ElanInterfaceStateChangeListener elanInterfaceEventListener;
private ElanItmEventListener elanItmEventListener;
- public void setItmRpcService(ItmRpcService itmRpcService) {
- this.itmRpcService = itmRpcService;
- }
-
- public ItmRpcService getItmRpcService() {
- return itmRpcService;
- }
-
- private ItmRpcService itmRpcService;
- private DataBroker broker;
-
private static final Logger logger = LoggerFactory.getLogger(ElanServiceProvider.class);
@Override
public void onSessionInitiated(ProviderContext session) {
- createIdPool();
- broker = session.getSALService(DataBroker.class);
+ elanStatusMonitor.reportStatus("STARTING");
+ try {
+ createIdPool();
+ broker = session.getSALService(DataBroker.class);
+
+ ElanUtils.setDataBroker(broker);
+ ElanUtils.setIfaceMgrRpcService(interfaceManagerRpcService);
+ ElanUtils.setItmRpcService(itmRpcService);
+ ElanUtils.setMdsalManager(mdsalManager);
+
+ elanForwardingEntriesHandler = new ElanForwardingEntriesHandler(broker);
+
+ elanInterfaceManager = ElanInterfaceManager.getElanInterfaceManager();
+ elanInterfaceManager.setInterfaceManager(interfaceManager);
+ elanInterfaceManager.setIdManager(idManager);
+ elanInterfaceManager.setMdSalApiManager(mdsalManager);
+ elanInterfaceManager.setDataBroker(broker);
+ elanInterfaceManager.setInterfaceManagerRpcService(interfaceManagerRpcService);
+ elanInterfaceManager.setElanForwardingEntriesHandler(elanForwardingEntriesHandler);
+
+ elanInstanceManager = ElanInstanceManager.getElanInstanceManager();
+ elanInstanceManager.setDataBroker(broker);
+ elanInstanceManager.setIdManager(idManager);
+ elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
+
+
+ elanNodeListener = new ElanNodeListener(broker, mdsalManager);
+
+ elanPacketInHandler = new ElanPacketInHandler(broker);
+ elanPacketInHandler.setInterfaceManager(interfaceManager);
+
- elanForwardingEntriesHandler = new ElanForwardingEntriesHandler(broker);
+ elanSmacFlowEventListener = new ElanSmacFlowEventListener(broker);
+ elanSmacFlowEventListener.setMdSalApiManager(mdsalManager);
+ elanSmacFlowEventListener.setInterfaceManager(interfaceManager);
+ elanSmacFlowEventListener.setSalFlowService(session.getRpcService(SalFlowService.class));
- elanInterfaceManager = ElanInterfaceManager.getElanInterfaceManager();
- elanInterfaceManager.setInterfaceManager(interfaceManager);
- elanInterfaceManager.setIdManager(idManager);
- elanInterfaceManager.setMdSalApiManager(mdsalManager);
- elanInterfaceManager.setDataBroker(broker);
- elanInterfaceManager.registerListener();
- elanInterfaceManager.setInterfaceManagerRpcService(interfaceManagerRpcService);
- elanInterfaceManager.setElanForwardingEntriesHandler(elanForwardingEntriesHandler);
- elanInstanceManager = ElanInstanceManager.getElanInstanceManager();
- elanInstanceManager.setDataBroker(broker);
- elanInstanceManager.setIdManager(idManager);
- elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
- elanInstanceManager.registerListener();
+ // Initialize statistics rpc provider for elan
+ ElanStatisticsService interfaceStatsService = new ElanStatisticsImpl(broker, interfaceManager,
+ mdsalManager);
+ rpcProviderRegistry.addRpcImplementation(ElanStatisticsService.class, interfaceStatsService);
- elanNodeListener = new ElanNodeListener(broker, mdsalManager);
+ elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
+ elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
- elanPacketInHandler = new ElanPacketInHandler(broker);
- elanPacketInHandler.setInterfaceManager(interfaceManager);
- notificationService.registerNotificationListener(elanPacketInHandler);
- elanSmacFlowEventListener = new ElanSmacFlowEventListener(broker);
- elanSmacFlowEventListener.setMdSalApiManager(mdsalManager);
- elanSmacFlowEventListener.setInterfaceManager(interfaceManager);
- elanSmacFlowEventListener.setSalFlowService(session.getRpcService(SalFlowService.class));
- notificationService.registerNotificationListener(elanSmacFlowEventListener);
+ this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
- // Initialize statistics rpc provider for elan
- ElanStatisticsService interfaceStatsService = new ElanStatisticsImpl(broker, interfaceManager, mdsalManager);
- rpcProviderRegistry.addRpcImplementation(ElanStatisticsService.class, interfaceStatsService);
+ elanInterfaceManager.registerListener();
+ elanInstanceManager.registerListener();
+ notificationService.registerNotificationListener(elanSmacFlowEventListener);
+ notificationService.registerNotificationListener(elanPacketInHandler);
- elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
- elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
- ElanUtils.setElanServiceProvider(this);
+ elanStatusMonitor.reportStatus("OPERATIONAL");
+ } catch (Exception e) {
+ logger.error("Error initializing services", e);
+ elanStatusMonitor.reportStatus("ERROR");
+ }
}
public void setIdManager(IdManagerService idManager) {
this.interfaceManager = interfaceManager;
}
+ public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ }
+
+ public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ }
+
+ public IInterfaceManager getInterfaceManager() {
+ return this.interfaceManager;
+ }
+
public IMdsalApiManager getMdsalManager() {
return mdsalManager;
}
- public DataBroker getBroker() {
+ public IITMProvider getItmManager() {
+ return itmManager;
+ }
+
+ public DataBroker getBroker() {
return broker;
}
return interfaceManagerRpcService;
}
+ public void setItmManager(IITMProvider itmManager) {
+ this.itmManager = itmManager;
+ }
+
+ public void setItmRpcService(ItmRpcService itmRpcService) {
+ this.itmRpcService = itmRpcService;
+ }
+
+ public ItmRpcService getItmRpcService() {
+ return itmRpcService;
+ }
+
+ public ElanInstanceManager getElanInstanceManager() {
+ return elanInstanceManager;
+ }
+
+ public ElanInterfaceManager getElanInterfaceManager() {
+ return elanInterfaceManager;
+ }
+
+ public EntityOwnershipService getEntityOwnershipService() {
+ return entityOwnershipService;
+ }
+
+ public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() {
+ return bindingNormalizedNodeSerializer;
+ }
+
private void createIdPool() {
- CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
- .setPoolName(ElanConstants.ELAN_ID_POOL_NAME).setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE)
- .build();
+ CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
+ .setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
try {
- Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
- if ((result != null) && (result.get().isSuccessful())) {
- logger.debug("ELAN Id Pool is created successfully");
+ Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+ if ((result != null) && (result.get().isSuccessful())) {
+ logger.debug("ELAN Id Pool is created successfully");
}
} catch (Exception e) {
logger.error("Failed to create ELAN Id pool {}", e);
public boolean createElanInstance(String elanInstanceName, long macTimeout, String description) {
ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
boolean isSuccess = true;
- if(existingElanInstance != null) {
- if(compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
- logger.debug("Elan Instance is already present in the Operational DS {}", existingElanInstance);
- return true;
- } else {
- ElanInstance updateElanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(description).setMacTimeout(macTimeout).setKey(new ElanInstanceKey(elanInstanceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
- logger.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ", updateElanInstance, macTimeout, description);
- }
+ if (existingElanInstance != null) {
+ if (compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
+ logger.debug("Elan Instance is already present in the Operational DS {}", existingElanInstance);
+ return true;
+ } else {
+ ElanInstance updateElanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
+ .setDescription(description).setMacTimeout(macTimeout)
+ .setKey(new ElanInstanceKey(elanInstanceName)).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
+ logger.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ",
+ updateElanInstance, macTimeout, description);
+ }
} else {
- ElanInstance elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
+ ElanInstance elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
+ .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
+ .build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
logger.debug("Creating the new Elan Instance {}", elanInstance);
}
return isSuccess;
}
- public static boolean compareWithExistingElanInstance(ElanInstance existingElanInstance, long macTimeOut, String description) {
+ public static boolean compareWithExistingElanInstance(ElanInstance existingElanInstance, long macTimeOut,
+ String description) {
boolean isEqual = false;
- if(existingElanInstance.getMacTimeout() == macTimeOut && existingElanInstance.getDescription().equals(description)) {
+ if (existingElanInstance.getMacTimeout() == macTimeOut
+ && existingElanInstance.getDescription().equals(description)) {
isEqual = true;
}
return isEqual;
}
+
@Override
public void updateElanInstance(String elanInstanceName, long newMacTimout, String newDescription) {
createElanInstance(elanInstanceName, newMacTimout, newDescription);
public boolean deleteElanInstance(String elanInstanceName) {
boolean isSuccess = false;
ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
- if(existingElanInstance == null) {
- logger.debug("Elan Instance is not present {}" , existingElanInstance);
+ if (existingElanInstance == null) {
+ logger.debug("Elan Instance is not present {}", existingElanInstance);
return isSuccess;
}
logger.debug("Deletion of the existing Elan Instance {}", existingElanInstance);
- ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName));
+ ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName));
isSuccess = true;
return isSuccess;
}
@Override
- public void addElanInterface(String elanInstanceName, String interfaceName, List<String> staticMacAddresses, String description) {
- ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
- if(existingElanInstance != null) {
- ElanInterface elanInterface;
- if(staticMacAddresses == null) {
- elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName).setDescription(description).setName(interfaceName).setKey(new ElanInterfaceKey(interfaceName)).build();
- } else {
- elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName).setDescription(description).setName(interfaceName).setStaticMacEntries(getPhysAddress(staticMacAddresses)).setKey(new ElanInterfaceKey(interfaceName)).build();
- }
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
- logger.debug("Creating the new ELan Interface {}", elanInterface);
- }
+ public void addElanInterface(String elanInstanceName, String interfaceName, List<String> staticMacAddresses,
+ String description) {
+ ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
+ if (existingElanInstance != null) {
+ ElanInterface elanInterface;
+ if (staticMacAddresses == null) {
+ elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+ .setDescription(description).setName(interfaceName).setKey(new ElanInterfaceKey(interfaceName))
+ .build();
+ } else {
+ elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+ .setDescription(description).setName(interfaceName)
+ .setStaticMacEntries(getPhysAddress(staticMacAddresses))
+ .setKey(new ElanInterfaceKey(interfaceName)).build();
+ }
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
+ logger.debug("Creating the new ELan Interface {}", elanInterface);
+ }
}
@Override
- public void updateElanInterface(String elanInstanceName, String interfaceName, List<String> updatedStaticMacAddresses, String newDescription) {
+ public void updateElanInterface(String elanInstanceName, String interfaceName,
+ List<String> updatedStaticMacAddresses, String newDescription) {
ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
if (existingElanInterface == null) {
return;
List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
List<PhysAddress> updatedMacAddresses = getPhysAddress(updatedStaticMacAddresses);
List<PhysAddress> updatedPhysAddress = getUpdatedPhyAddress(existingMacAddress, updatedMacAddresses);
- if(updatedPhysAddress.size() > 0) {
+ if (updatedPhysAddress.size() > 0) {
logger.debug("updating the ElanInterface with new Mac Entries {}", updatedStaticMacAddresses);
- ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName).setName(interfaceName).setDescription(newDescription).setStaticMacEntries(updatedPhysAddress).setKey(new ElanInterfaceKey(interfaceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
+ ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+ .setName(interfaceName).setDescription(newDescription).setStaticMacEntries(updatedPhysAddress)
+ .setKey(new ElanInterfaceKey(interfaceName)).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
}
}
@Override
public void deleteElanInterface(String elanInstanceName, String interfaceName) {
ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
- if(existingElanInterface != null) {
- ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
+ if (existingElanInterface != null) {
+ ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
logger.debug("deleting the Elan Interface {}", existingElanInterface);
}
}
PhysAddress updateStaticMacAddress = new PhysAddress(macAddress);
if (existingElanInterface != null) {
List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
- if(existingMacAddress.contains(updateStaticMacAddress)) {
+ if (existingMacAddress.contains(updateStaticMacAddress)) {
return;
}
existingMacAddress.add(updateStaticMacAddress);
- ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName).setName(interfaceName).setStaticMacEntries(existingMacAddress).setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
+ ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+ .setName(interfaceName).setStaticMacEntries(existingMacAddress)
+ .setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName))
+ .build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
}
}
@Override
- public void deleteStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress) throws MacNotFoundException {
- ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
+ public void deleteStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress)
+ throws MacNotFoundException {
+ ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
PhysAddress physAddress = new PhysAddress(macAddress);
- if(existingElanInterface == null) {
+ if (existingElanInterface == null) {
return;
}
List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
- if(existingMacAddress.contains(physAddress)) {
+ if (existingMacAddress.contains(physAddress)) {
existingMacAddress.remove(physAddress);
- ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName).setName(interfaceName).setStaticMacEntries(existingMacAddress).setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
+ ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+ .setName(interfaceName).setStaticMacEntries(existingMacAddress)
+ .setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName))
+ .build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
} else {
throw new MacNotFoundException("Mac Not Found Exception");
}
public Collection<MacEntry> getElanMacTable(String elanInstanceName) {
Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
List<MacEntry> macAddress = new ArrayList<>();
- if(elanInfo == null) {
+ if (elanInfo == null) {
return macAddress;
}
- List<String> elanInterfaces = elanInfo.getElanInterfaces();
- if(elanInterfaces != null && elanInterfaces.size() > 0) {
- for(String elanInterface : elanInterfaces) {
+ List<String> elanInterfaces = elanInfo.getElanInterfaces();
+ if (elanInterfaces != null && elanInterfaces.size() > 0) {
+ for (String elanInterface : elanInterfaces) {
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
- if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null && elanInterfaceMac.getMacEntry().size() > 0){
+ if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null
+ && elanInterfaceMac.getMacEntry().size() > 0) {
macAddress.addAll(elanInterfaceMac.getMacEntry());
}
}
}
- return macAddress;
+ return macAddress;
}
@Override
public void flushMACTable(String elanInstanceName) {
Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
- if(elanInfo == null) {
+ if (elanInfo == null) {
return;
}
List<String> elanInterfaces = elanInfo.getElanInterfaces();
for (String elanInterface : elanInterfaces) {
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
if (elanInterfaceMac.getMacEntry() != null && elanInterfaceMac.getMacEntry().size() > 0) {
- List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
- for(MacEntry macEntry : macEntries) {
+ List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
+ for (MacEntry macEntry : macEntries) {
try {
deleteStaticMacAddress(elanInstanceName, elanInterface, macEntry.getMacAddress().getValue());
} catch (MacNotFoundException e) {
@Override
public void close() throws Exception {
- elanInstanceManager.close();
+ this.elanInstanceManager.close();
+ this.elanL2GatewayProvider.close();
}
public static List<PhysAddress> getPhysAddress(List<String> macAddress) {
List<PhysAddress> physAddresses = new ArrayList<>();
- for(String mac : macAddress) {
+ for (String mac : macAddress) {
physAddresses.add(new PhysAddress(mac));
}
return physAddresses;
}
-
- public List<PhysAddress> getUpdatedPhyAddress(List<PhysAddress> originalAddresses, List<PhysAddress> updatePhyAddresses) {
- if(updatePhyAddresses != null && !updatePhyAddresses.isEmpty()) {
+ public List<PhysAddress> getUpdatedPhyAddress(List<PhysAddress> originalAddresses,
+ List<PhysAddress> updatePhyAddresses) {
+ if (updatePhyAddresses != null && !updatePhyAddresses.isEmpty()) {
List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
if (originalAddresses != null && !originalAddresses.isEmpty()) {
existingClonedPhyAddress.addAll(0, originalAddresses);
@Override
public List<ElanInstance> getElanInstances() {
List<ElanInstance> elanList = new ArrayList<ElanInstance>();
- InstanceIdentifier<ElanInstances> elanInstancesIdentifier = InstanceIdentifier.builder(ElanInstances.class).build();
- Optional<ElanInstances> elansOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanInstancesIdentifier);
- if(elansOptional.isPresent()) {
+ InstanceIdentifier<ElanInstances> elanInstancesIdentifier = InstanceIdentifier.builder(ElanInstances.class)
+ .build();
+ Optional<ElanInstances> elansOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
+ elanInstancesIdentifier);
+ if (elansOptional.isPresent()) {
elanList.addAll(elansOptional.get().getElanInstance());
}
return elanList;
@Override
public List<String> getElanInterfaces(String elanInstanceName) {
List<String> elanInterfaces = new ArrayList<>();
- InstanceIdentifier<ElanInterfaces> elanInterfacesIdentifier = InstanceIdentifier.builder(ElanInterfaces.class).build();
- Optional<ElanInterfaces> elanInterfacesOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfacesIdentifier);
- if(!elanInterfacesOptional.isPresent()) {
- return elanInterfaces;
+ InstanceIdentifier<ElanInterfaces> elanInterfacesIdentifier = InstanceIdentifier.builder(ElanInterfaces.class)
+ .build();
+ Optional<ElanInterfaces> elanInterfacesOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
+ elanInterfacesIdentifier);
+ if (!elanInterfacesOptional.isPresent()) {
+ return elanInterfaces;
}
List<ElanInterface> elanInterfaceList = elanInterfacesOptional.get().getElanInterface();
- for(ElanInterface elanInterface : elanInterfaceList) {
- if(elanInterface.getElanInstanceName().equals(elanInstanceName)) {
+ for (ElanInterface elanInterface : elanInterfaceList) {
+ if (elanInterface.getElanInstanceName().equals(elanInstanceName)) {
elanInterfaces.add(elanInterface.getName());
}
}
*/
package org.opendaylight.vpnservice.elan.internal;
+import java.math.BigInteger;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
-import org.opendaylight.vpnservice.itm.api.IITMProvider;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331._if.indexes._interface.map.IfIndexInterface;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+@SuppressWarnings("deprecation")
public class ElanSmacFlowEventListener implements SalFlowListener {
private final DataBroker broker;
- private IMdsalApiManager mdsalManager;
private IInterfaceManager interfaceManager;
private static final Logger logger = LoggerFactory.getLogger(ElanSmacFlowEventListener.class);
public void setMdSalApiManager(IMdsalApiManager mdsalManager) {
- this.mdsalManager = mdsalManager;
}
@Override
public void onFlowAdded(FlowAdded arg0) {
if (elanTagInfo == null) {
return;
}
- String srcMacAddress = switchFlowRemoved.getMatch().getEthernetMatch()
+ final String srcMacAddress = switchFlowRemoved.getMatch().getEthernetMatch()
.getEthernetSource().getAddress().getValue().toUpperCase();
int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
if (portTag == 0) {
logger.debug(String.format("Flow removed event on SMAC flow entry. But having port Tag as 0 "));
return;
}
- IfIndexInterface existingInterfaceInfo = ElanUtils.getInterfaceInfoByInterfaceTag(portTag);
- String interfaceName = existingInterfaceInfo.getInterfaceName();
+ Optional<IfIndexInterface> existingInterfaceInfo = ElanUtils.getInterfaceInfoByInterfaceTag(portTag);
+ if (!existingInterfaceInfo.isPresent()) {
+ logger.debug("Interface is not available for port Tag {}", portTag);
+ return;
+ }
+ String interfaceName = existingInterfaceInfo.get().getInterfaceName();
PhysAddress physAddress = new PhysAddress(srcMacAddress);
if (interfaceName == null) {
logger.error(String.format("LPort record not found for tag %d", portTag));
if(macEntry != null && interfaceInfo != null) {
ElanUtils.deleteMacFlows(ElanUtils.getElanInstanceByName(elanTagInfo.getName()), interfaceInfo, macEntry);
}
- InstanceIdentifier<MacEntry> macEntryId = ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
- ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, macEntryId);
+ InstanceIdentifier<MacEntry> macEntryIdForElanInterface = ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
+ InstanceIdentifier<MacEntry> macEntryIdForElanInstance = ElanUtils.getMacEntryOperationalDataPath(elanTagInfo.getName(), physAddress);
+ WriteTransaction tx = broker.newWriteOnlyTransaction();
+ tx.delete(LogicalDatastoreType.OPERATIONAL, macEntryIdForElanInterface);
+ tx.delete(LogicalDatastoreType.OPERATIONAL, macEntryIdForElanInstance);
+ ListenableFuture<Void> writeResult = tx.submit();
+
+ //WRITE Callback
+ Futures.addCallback(writeResult, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ logger.debug("Successfully removed macEntry {} from Operational Datastore", srcMacAddress);
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.debug("Error {} while removing macEntry {} from Operational Datastore", error, srcMacAddress);
+ }
+ });
}
}
-
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.elan.l2gw.internal;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepNodeListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.L2GatewayConnectionListener;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Elan L2 Gateway provider class.
+ */
+public class ElanL2GatewayProvider implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayProvider.class);
+
+ private DataBroker broker;
+ private EntityOwnershipService entityOwnershipService;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+ private ItmRpcService itmRpcService;
+ private ElanInstanceManager elanInstanceManager;
+ private ElanInterfaceManager elanInterfaceManager;
+
+ private L2GatewayConnectionListener l2GwConnListener;
+ private HwvtepNodeListener hwvtepNodeListener;
+ private HwvtepLocalUcastMacListener torMacsListener;
+
+ /**
+ * Instantiates a new elan l2 gateway provider.
+ *
+ * @param elanServiceProvider
+ * the elan service provider
+ */
+ public ElanL2GatewayProvider(ElanServiceProvider elanServiceProvider) {
+ this.broker = elanServiceProvider.getBroker();
+ this.entityOwnershipService = elanServiceProvider.getEntityOwnershipService();
+ this.bindingNormalizedNodeSerializer = elanServiceProvider.getBindingNormalizedNodeSerializer();
+ this.itmRpcService = elanServiceProvider.getItmRpcService();
+ this.elanInstanceManager = elanServiceProvider.getElanInstanceManager();
+ this.elanInterfaceManager = elanServiceProvider.getElanInterfaceManager();
+
+ init();
+
+ LOG.info("ElanL2GatewayProvider Initialized");
+ }
+
+ /**
+ * Initialize Elan L2 Gateway.
+ */
+ private void init() {
+ ElanL2GwCacheUtils.createElanL2GwDeviceCache();
+ ElanL2GatewayUtils.setDataBroker(broker);
+ ElanL2GatewayUtils.setItmRpcService(itmRpcService);
+
+ ElanL2GatewayMulticastUtils.setBroker(broker);
+ ElanL2GatewayMulticastUtils.setElanInstanceManager(elanInstanceManager);
+ ElanL2GatewayMulticastUtils.setElanInterfaceManager(elanInterfaceManager);
+
+ this.torMacsListener = new HwvtepLocalUcastMacListener(broker, entityOwnershipService,
+ bindingNormalizedNodeSerializer);
+ this.l2GwConnListener = new L2GatewayConnectionListener(broker, entityOwnershipService,
+ bindingNormalizedNodeSerializer, elanInstanceManager);
+ this.hwvtepNodeListener = new HwvtepNodeListener(broker, entityOwnershipService,
+ bindingNormalizedNodeSerializer, elanInstanceManager, itmRpcService);
+ this.hwvtepNodeListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.AutoCloseable#close()
+ */
+ @Override
+ public void close() throws Exception {
+ this.torMacsListener.close();
+ this.l2GwConnListener.close();
+ this.hwvtepNodeListener.close();
+ LOG.info("ElanL2GatewayProvider Closed");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A listener for Ucast MAC entries that are added/removed to/from an External Device (e.g., TOR).
+ *
+ * When a Ucast MAC addr appears in the hwvtep's operational DS, that MAC must be populated in DMAC tables in all
+ * Elan participating DPNs. ELAN is selected according to field 'tunnel_key' of the Logical Switch to which the new
+ * MAC belongs.
+ *
+ */
+public class HwvtepLocalUcastMacListener extends
+ AsyncClusteredDataChangeListenerBase<LocalUcastMacs, HwvtepLocalUcastMacListener> implements AutoCloseable {
+
+ private DataBroker broker;
+ private EntityOwnershipService entityOwnershipService;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+ private ListenerRegistration<DataChangeListener> lstnerRegistration;
+
+ private static final Logger logger = LoggerFactory.getLogger(HwvtepLocalUcastMacListener.class);
+
+ public HwvtepLocalUcastMacListener(DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ super(LocalUcastMacs.class, HwvtepLocalUcastMacListener.class);
+
+ this.broker = broker;
+ this.entityOwnershipService = entityOwnershipService;
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ registerListener();
+ }
+
+ protected void registerListener() {
+ try {
+ lstnerRegistration = this.broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ HwvtepUtils.getWildCardPathForLocalUcastMacs(), this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ logger.error("Hwvtep LocalUcasMacs DataChange listener registration failed !", e);
+ throw new IllegalStateException("Hwvtep LocalUcasMacs DataChange listener registration failed .", e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (lstnerRegistration != null) {
+ try {
+ lstnerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ lstnerRegistration = null;
+ }
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs macRemoved) {
+ String hwvtepNodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ String macAddress = macRemoved.getMacEntryKey().getValue();
+
+ logger.trace("LocalUcastMacs {} removed from {}", macAddress, hwvtepNodeId);
+
+ ElanInstance elan = ElanL2GatewayUtils.getElanInstanceForUcastLocalMac(macRemoved);
+ if (elan == null) {
+ logger.warn("Could not find ELAN for mac {} being deleted", macAddress);
+ return;
+ }
+
+ String elanName = elan.getElanInstanceName();
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ if (elanL2GwDevice == null) {
+ logger.warn("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache", elanName, hwvtepNodeId);
+ return;
+ }
+
+ // Remove MAC from cache
+ elanL2GwDevice.removeUcastLocalMac(macRemoved);
+
+ ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
+ elanL2GwDevice, macRemoved); }
+
+ @Override
+ protected void update(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
+ LocalUcastMacs update) {
+ // TODO (eperefr) what can change here?
+
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs macAdded) {
+ String hwvtepNodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ String macAddress = macAdded.getMacEntryKey().getValue();
+
+ logger.trace("LocalUcastMacs {} added to {}", macAddress, hwvtepNodeId);
+
+ ElanInstance elan = ElanL2GatewayUtils.getElanInstanceForUcastLocalMac(macAdded);
+ if (elan == null) {
+ logger.warn("Could not find ELAN for mac {} being added", macAddress);
+ return;
+ }
+
+ String elanName = elan.getElanInstanceName();
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ if (elanL2GwDevice == null) {
+ logger.warn("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache", elanName, hwvtepNodeId);
+ return;
+ }
+
+ // Cache MAC for furthur processing later
+ elanL2GwDevice.addUcastLocalMac(macAdded);
+
+ ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
+ elanL2GwDevice, macAddress);
+ }
+
+ @Override
+ protected InstanceIdentifier<LocalUcastMacs> getWildCardPath() {
+ return InstanceIdentifier.create(LocalUcastMacs.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return HwvtepLocalUcastMacListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return DataChangeScope.BASE;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The listener class for listening to {@code LogicalSwitches}
+ * add/delete/update.
+ *
+ * @see LogicalSwitches
+ */
+public class HwvtepLogicalSwitchListener
+ extends AsyncDataChangeListenerBase<LogicalSwitches, HwvtepLogicalSwitchListener> {
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepLogicalSwitchListener.class);
+
+ /** The node id. */
+ private NodeId nodeId;
+
+ /** The logical switch name. */
+ private String logicalSwitchName;
+
+ /** The physical device. */
+ private Devices physicalDevice;
+
+ /** The l2 gateway device. */
+ private L2GatewayDevice l2GatewayDevice;
+
+ /** The default vlan id. */
+ private Integer defaultVlanId;
+
+ /**
+ * Instantiates a new hardware vtep logical switch listener.
+ *
+ * @param l2GatewayDevice
+ * the l2 gateway device
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param physicalDevice
+ * the physical device
+ * @param defaultVlanId
+ * the default vlan id
+ */
+ public HwvtepLogicalSwitchListener(L2GatewayDevice l2GatewayDevice, String logicalSwitchName,
+ Devices physicalDevice, Integer defaultVlanId) {
+ super(LogicalSwitches.class, HwvtepLogicalSwitchListener.class);
+ this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+ this.logicalSwitchName = logicalSwitchName;
+ this.physicalDevice = physicalDevice;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.defaultVlanId = defaultVlanId;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getWildCardPath()
+ */
+ @Override
+ public InstanceIdentifier<LogicalSwitches> getWildCardPath() {
+ return HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId,
+ new HwvtepNodeName(logicalSwitchName));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getDataChangeListener()
+ */
+ @Override
+ protected DataChangeListener getDataChangeListener() {
+ return HwvtepLogicalSwitchListener.this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getDataChangeScope()
+ */
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * remove(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void remove(InstanceIdentifier<LogicalSwitches> identifier, LogicalSwitches deletedLogicalSwitch) {
+ LOG.trace("Received Remove DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
+ deletedLogicalSwitch);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * update(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void update(InstanceIdentifier<LogicalSwitches> identifier, LogicalSwitches logicalSwitchOld,
+ LogicalSwitches logicalSwitchNew) {
+ LOG.trace("Received Update DataChange Notification for identifier: {}, LogicalSwitches old: {}, new: {}."
+ + "No Action Performed.", identifier, logicalSwitchOld, logicalSwitchNew);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * add(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void add(InstanceIdentifier<LogicalSwitches> identifier, LogicalSwitches logicalSwitchNew) {
+ LOG.debug("Received Add DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
+ logicalSwitchNew);
+ try {
+ L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice);
+ DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
+ LogicalSwitchAddedWorker logicalSwitchAddedWorker = new LogicalSwitchAddedWorker(nodeId, logicalSwitchNew);
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(),
+ logicalSwitchNew.getHwvtepNodeName().getValue());
+ jobCoordinator.enqueueJob(jobKey, logicalSwitchAddedWorker,
+ SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+
+ } catch (Exception e) {
+ LOG.error("Failed to handle HwVTEPLogicalSwitch - add: {}", e);
+ } finally {
+ try {
+ // This listener is specific to handle a specific logical
+ // switch, hence closing it.
+ LOG.trace("Closing LogicalSwitches listener for node: {}, logicalSwitch: {}", nodeId.getValue(),
+ logicalSwitchName);
+ close();
+ } catch (Exception e) {
+ LOG.warn("Failed to close HwVTEPLogicalSwitchListener: {}", e);
+ }
+ }
+ }
+
+ /**
+ * The Class LogicalSwitchAddedWorker.
+ */
+ private class LogicalSwitchAddedWorker implements Callable<List<ListenableFuture<Void>>> {
+ /** The logical switch new. */
+ LogicalSwitches logicalSwitchNew;
+
+ /**
+ * Instantiates a new logical switch added worker.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchNew
+ * the logical switch new
+ */
+ public LogicalSwitchAddedWorker(NodeId nodeId, LogicalSwitches logicalSwitchNew) {
+ this.logicalSwitchNew = logicalSwitchNew;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ try {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
+ final L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils
+ .getL2GatewayDeviceFromCache(elan, l2GatewayDevice.getHwvtepNodeId());
+ if (elanL2GwDevice == null) {
+ LOG.error("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache",
+ l2GatewayDevice.getHwvtepNodeId());
+ return null;
+ } else {
+ LOG.trace("got logical switch device {}", elanL2GwDevice);
+ futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+ new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
+ futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
+
+ HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+ logicalSwitchName, elanL2GwDevice,
+ new Callable<List<ListenableFuture<Void>>>() {
+
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
+ logicalSwitchName, elanL2GwDevice));
+ return futures;
+ }}
+ );
+ return futures;
+ }
+ } catch (Throwable e) {
+ LOG.error("failed to add ls ", e);
+ return null;
+ }
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class HwvtepNodeListener
+ extends AsyncClusteredDataChangeListenerBase<Node, HwvtepNodeListener> {
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepNodeListener.class);
+
+ private DataBroker dataBroker;
+ private EntityOwnershipService entityOwnershipService;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+ private ItmRpcService itmRpcService;
+ ElanInstanceManager elanInstanceManager;
+
+ public HwvtepNodeListener(final DataBroker dataBroker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+ ItmRpcService itmRpcService) {
+ super(Node.class, HwvtepNodeListener.class);
+ this.dataBroker = dataBroker;
+ this.entityOwnershipService = entityOwnershipService;
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ this.itmRpcService = itmRpcService;
+ this.elanInstanceManager = elanInstanceManager;
+ }
+
+ @Override
+ protected InstanceIdentifier<Node> getWildCardPath() {
+ return InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)).child(Node.class);
+ }
+
+ @Override
+ protected HwvtepNodeListener getDataChangeListener() {
+ return HwvtepNodeListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Node> key, Node nodeDeleted) {
+ LOG.debug("Received Node Remove Event: {}, {}", key, nodeDeleted.getNodeId().getValue());
+
+ PhysicalSwitchAugmentation psAugmentation = nodeDeleted.getAugmentation(PhysicalSwitchAugmentation.class);
+ if (psAugmentation != null) {
+ String psName = psAugmentation.getHwvtepNodeName().getValue();
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
+ if (l2GwDevice != null) {
+ if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+ L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
+ }
+ l2GwDevice.setConnected(false);
+ ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
+ } else {
+ LOG.error("Unable to find L2 Gateway details for {}", psName);
+ }
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Node> key, Node nodeBefore, Node nodeAfter) {
+ LOG.debug("Received Node Update Event: {}, {}, {}", key, nodeBefore, nodeAfter);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Node> key, Node nodeAdded) {
+ LOG.debug("Received Node Add Event: {}, {}", key, nodeAdded.getNodeId().getValue());
+
+ PhysicalSwitchAugmentation psAugmentation = nodeAdded.getAugmentation(PhysicalSwitchAugmentation.class);
+ if (psAugmentation != null) {
+ String psName = psAugmentation.getHwvtepNodeName().getValue();
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
+ if (l2GwDevice == null) {
+ l2GwDevice = new L2GatewayDevice();
+ l2GwDevice.setDeviceName(psName);
+ L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
+ }
+
+ String hwvtepNodeId = getManagedByNodeId(psAugmentation.getManagedBy());
+ l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
+ List<TunnelIps> tunnelIps = psAugmentation.getTunnelIps();
+ if (tunnelIps != null) {
+ for (TunnelIps tunnelIp : tunnelIps) {
+ IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
+ l2GwDevice.addTunnelIp(tunnelIpAddr);
+ if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+ // It's a pre-provision scenario
+ // Initiate ITM tunnel creation
+ ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
+
+ // Initiate Logical switch creation for associated L2
+ // Gateway Connections
+ List<L2gatewayConnection> l2GwConns = getAssociatedL2GwConnections(dataBroker,
+ l2GwDevice.getL2GatewayIds());
+ if (l2GwConns != null) {
+ for (L2gatewayConnection l2GwConn : l2GwConns) {
+ L2GatewayConnectionUtils.addL2GatewayConnection(dataBroker, entityOwnershipService,
+ bindingNormalizedNodeSerializer, elanInstanceManager, l2GwConn, psName);
+ }
+ }
+ //TODO handle deleted l2gw connections while the device is offline
+ }
+ }
+ }
+ }
+ }
+
+ private List<L2gatewayConnection> getAssociatedL2GwConnections(DataBroker broker, List<Uuid> l2GatewayIds) {
+ List<L2gatewayConnection> l2GwConnections = null;
+ List<L2gatewayConnection> allL2GwConns = getAllL2gatewayConnections(broker);
+ if (allL2GwConns != null) {
+ l2GwConnections = new ArrayList<L2gatewayConnection>();
+ for (Uuid l2GatewayId : l2GatewayIds) {
+ for (L2gatewayConnection l2GwConn : allL2GwConns) {
+ if (l2GwConn.getL2gatewayId().equals(l2GatewayId)) {
+ l2GwConnections.add(l2GwConn);
+ }
+ }
+ }
+ }
+ return l2GwConnections;
+ }
+
+ protected List<L2gatewayConnection> getAllL2gatewayConnections(DataBroker broker) {
+ InstanceIdentifier<L2gatewayConnections> inst = InstanceIdentifier.create(Neutron.class)
+ .child(L2gatewayConnections.class);
+ Optional<L2gatewayConnections> l2GwConns = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (l2GwConns.isPresent()) {
+ return l2GwConns.get().getL2gatewayConnection();
+ }
+ return null;
+ }
+
+ private String getManagedByNodeId(HwvtepGlobalRef globalRef) {
+ InstanceIdentifier<?> instId = globalRef.getValue();
+ return instId.firstKeyOf(Node.class, NodeKey.class).getNodeId().getValue();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The listener class for listening to {@code RemoteMcastMacs}
+ * add/delete/update.
+ *
+ * @see RemoteMcastMacs
+ */
+public class HwvtepRemoteMcastMacListener
+ extends AsyncDataChangeListenerBase<RemoteMcastMacs, HwvtepRemoteMcastMacListener> {
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepRemoteMcastMacListener.class);
+
+ /** The node id. */
+ private NodeId nodeId;
+
+ DataBroker broker;
+
+ String logicalSwitchName;
+
+ AtomicBoolean executeTask = new AtomicBoolean(true);
+
+ Callable<List<ListenableFuture<Void>>> taskToRun;
+ /**
+ * Instantiates a new remote mcast mac listener.
+ *
+ * @param broker
+ * the mdsal databroker reference
+ * @param logicalSwitchName
+ * @param l2GatewayDevice
+ * the l2 gateway device
+ * @param task
+ * the task to be run upon data presence
+ * @throws Exception
+ */
+ public HwvtepRemoteMcastMacListener(DataBroker broker, String logicalSwitchName, L2GatewayDevice l2GatewayDevice,
+ Callable<List<ListenableFuture<Void>>> task) throws Exception {
+ super(RemoteMcastMacs.class, HwvtepRemoteMcastMacListener.class);
+ this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+ this.broker = broker;
+ this.taskToRun = task;
+ this.logicalSwitchName = logicalSwitchName;
+ LOG.debug("registering the listener for mcast mac ");
+ registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+ if (isDataPresentInOpDs(getWildCardPath())) {
+ LOG.debug("mcast mac already present running the task ");
+ if (executeTask.compareAndSet(true, false)) {
+ runTask();
+ }
+ }
+ }
+
+ private boolean isDataPresentInOpDs(InstanceIdentifier<? extends DataObject> path) throws Exception {
+ Optional<? extends DataObject> mac = null;
+ try {
+ mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+ } catch (Throwable e) {
+ }
+ if (mac == null || !mac.isPresent()) {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getWildCardPath()
+ */
+ @Override
+ public InstanceIdentifier<RemoteMcastMacs> getWildCardPath() {
+ return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+ logicalSwitchName, new MacAddress(ElanConstants.UNKNOWN_DMAC));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getDataChangeListener()
+ */
+ @Override
+ protected DataChangeListener getDataChangeListener() {
+ return HwvtepRemoteMcastMacListener.this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * getDataChangeScope()
+ */
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * remove(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void remove(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs deleted) {
+ LOG.trace("Received Remove DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
+ deleted);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * update(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void update(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs old,
+ RemoteMcastMacs newdata) {
+ LOG.trace("Received Update DataChange Notification for identifier: {}, RemoteMcastMacs old: {}, new: {}."
+ + "No Action Performed.", identifier, old, newdata);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase#
+ * add(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
+ * org.opendaylight.yangtools.yang.binding.DataObject)
+ */
+ @Override
+ protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
+ LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
+ mcastMac);
+ if (executeTask.compareAndSet(true, false)) {
+ runTask();
+ }
+ }
+
+ void runTask() {
+ try {
+ DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), ElanConstants.UNKNOWN_DMAC);
+ jobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } catch (Exception e) {
+ LOG.error("Failed to handle remote mcast mac - add: {}", e);
+ } finally {
+ try {
+ close();
+ } catch (Exception e) {
+ LOG.warn("Failed to close McastMacSwitchListener: {}", e);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListenerBase<L2gatewayConnection,
+ L2GatewayConnectionListener> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionListener.class);
+
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+ private EntityOwnershipService entityOwnershipService;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+ private ElanInstanceManager elanInstanceManager;
+
+ public L2GatewayConnectionListener(final DataBroker db, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager) {
+ super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
+ broker = db;
+ this.entityOwnershipService = entityOwnershipService;
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ this.elanInstanceManager = elanInstanceManager;
+ registerListener(db);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.info("L2 Gateway Connection listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class)
+ .child(L2gatewayConnection.class),
+ L2GatewayConnectionListener.this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("Neutron Manager L2 Gateway Connection DataChange listener registration fail!", e);
+ throw new IllegalStateException(
+ "Neutron Manager L2 Gateway Connection DataChange listener registration failed.", e);
+ }
+ }
+
+ @Override
+ protected void add(final InstanceIdentifier<L2gatewayConnection> identifier, final L2gatewayConnection input) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Adding L2gatewayConnection : key: " + identifier + ", value=" + input);
+ }
+
+ // Get associated L2GwId from 'input'
+ // Create logical switch in each of the L2GwDevices part of L2Gw
+ // Logical switch name is network UUID
+ // Add L2GwDevices to ELAN
+ L2GatewayConnectionUtils.addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
+ elanInstanceManager, input);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection input) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Removing L2gatewayConnection : key: " + identifier + ", value=" + input);
+ }
+
+ L2GatewayConnectionUtils.deleteL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
+ elanInstanceManager, input);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection original,
+ L2gatewayConnection update) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Updating L2gatewayConnection : key: " + identifier + ", original value=" + original
+ + ", update value=" + update);
+ }
+ }
+
+ @Override
+ protected InstanceIdentifier<L2gatewayConnection> getWildCardPath() {
+ return InstanceIdentifier.create(L2gatewayConnection.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return L2GatewayConnectionListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return DataChangeScope.BASE;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.utils;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
+//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.DesignatedSwitchesForExternalTunnels;
+//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * The utility class to handle ELAN L2 Gateway related to multicast.
+ */
+public class ElanL2GatewayMulticastUtils {
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
+
+ /** The broker. */
+ private static DataBroker broker;
+
+ /** The elan instance manager. */
+ private static ElanInstanceManager elanInstanceManager;
+
+ /** The elan interface manager. */
+ private static ElanInterfaceManager elanInterfaceManager;
+
+ /**
+ * Sets the broker.
+ *
+ * @param broker
+ * the new broker
+ */
+ public static void setBroker(DataBroker broker) {
+ ElanL2GatewayMulticastUtils.broker = broker;
+ }
+
+ /**
+ * Sets the elan instance manager.
+ *
+ * @param elanMgr
+ * the new elan instance manager
+ */
+ public static void setElanInstanceManager(ElanInstanceManager elanMgr) {
+ ElanL2GatewayMulticastUtils.elanInstanceManager = elanMgr;
+ }
+
+ /**
+ * Sets the elan interface manager.
+ *
+ * @param interfaceMgr
+ * the new elan interface manager
+ */
+ public static void setElanInterfaceManager(ElanInterfaceManager interfaceMgr) {
+ elanInterfaceManager = interfaceMgr;
+ }
+
+ /**
+ * Handle mcast for elan l2 gw device add.
+ *
+ * @param elanName
+ * the elan name
+ * @param device
+ * the device
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
+ return updateMcastMacs(elanName, device, true/* updateThisDevice */);
+ }
+
+ /**
+ * Updates the remote mcast mac table for all the devices in this elan
+ * includes all the dpn tep ips and other devices tep ips in broadcast
+ * locator set.
+ *
+ * @param elanName
+ * the elan to be updated
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
+ SettableFuture<Void> future = SettableFuture.create();
+ future.set(null);
+ try {
+ ConcurrentMap<String, L2GatewayDevice> mapL2gwDevices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+ if (mapL2gwDevices == null || mapL2gwDevices.isEmpty()) {
+ LOG.trace("No L2GatewayDevices to configure RemoteMcastMac for elan {}", elanName);
+ return future;
+ }
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+
+ // TODO revisit
+ L2GatewayDevice firstDevice = mapL2gwDevices.values().iterator().next();
+ List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(firstDevice, dpns);
+ List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(mapL2gwDevices);
+
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ for (L2GatewayDevice device : mapL2gwDevices.values()) {
+ updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ }
+ return transaction.submit();
+ } catch (Throwable e) {
+ LOG.error("Failed to configure mcast mac on elan " + elanName, e);
+ }
+ return future;
+ }
+
+ /**
+ * Update mcast macs.
+ *
+ * @param elanName
+ * the elan name
+ * @param device
+ * the device
+ * @param updateThisDevice
+ * the update this device
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> updateMcastMacs(String elanName, L2GatewayDevice device,
+ boolean updateThisDevice) {
+
+ SettableFuture<Void> ft = SettableFuture.create();
+ ft.set(null);
+
+ ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
+ elanInterfaceManager.updateElanBroadcastGroup(elanInstance);
+
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+
+ ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+
+ List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
+ List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
+ // if (allTepIps.size() < 2) {
+ // LOG.debug("no other devices are found in the elan {}", elanName);
+ // return ft;
+ // }
+
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ if (updateThisDevice) {
+ updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ }
+
+ // TODO: Need to revisit below logic as logical switches might not be
+ // created to configure RemoteMcastMac entry
+ for (L2GatewayDevice otherDevice : devices.values()) {
+ if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
+ updateRemoteMcastMac(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
+ }
+ }
+ return transaction.submit();
+
+ }
+
+ /**
+ * Update remote mcast mac.
+ *
+ * @param transaction
+ * the transaction
+ * @param elanName
+ * the elan name
+ * @param device
+ * the device
+ * @param dpnsTepIps
+ * the dpns tep ips
+ * @param l2GwDevicesTepIps
+ * the l2 gw devices tep ips
+ * @return the write transaction
+ */
+ private static WriteTransaction updateRemoteMcastMac(WriteTransaction transaction, String elanName,
+ L2GatewayDevice device, List<IpAddress> dpnsTepIps, List<IpAddress> l2GwDevicesTepIps) {
+ NodeId nodeId = new NodeId(device.getHwvtepNodeId());
+ String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
+
+ ArrayList<IpAddress> otherTepIps = new ArrayList<>(l2GwDevicesTepIps);
+ otherTepIps.remove(device.getTunnelIp());
+
+ if (!dpnsTepIps.isEmpty()) {
+ otherTepIps.addAll(dpnsTepIps);
+ } else {
+ // If no dpns in elan, configure dhcp designated switch Tep Ip as a
+ // physical locator in l2 gw device
+ IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
+ if (dhcpDesignatedSwitchTepIp != null) {
+ otherTepIps.add(dhcpDesignatedSwitchTepIp);
+
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
+ HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
+
+ LOG.info(
+ "Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} as physical locator, elan {}",
+ device.getHwvtepNodeId(), String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
+ } else {
+ LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
+ device.getHwvtepNodeId(), elanName);
+ }
+ }
+
+ putRemoteMcastMac(transaction, nodeId, logicalSwitchName, otherTepIps);
+ LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
+ otherTepIps);
+ return transaction;
+ }
+
+ /**
+ * Put remote mcast mac in config DS.
+ *
+ * @param transaction
+ * the transaction
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param tepIps
+ * the tep ips
+ */
+ private static void putRemoteMcastMac(WriteTransaction transaction, NodeId nodeId, String logicalSwitchName,
+ ArrayList<IpAddress> tepIps) {
+ List<LocatorSet> locators = new ArrayList<>();
+ for (IpAddress tepIp : tepIps) {
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
+ HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+ HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
+ locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
+ }
+
+ HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
+ RemoteMcastMacs remoteUcastMac = new RemoteMcastMacsBuilder()
+ .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
+ .setLocatorSet(locators).build();
+ HwvtepUtils.putRemoteMcastMac(transaction, nodeId, remoteUcastMac);
+ }
+
+ /**
+ * Gets all the tep ips of dpns.
+ *
+ * @param device
+ * the device
+ * @param dpns
+ * the dpns
+ * @param devices
+ * the devices
+ * @return the all tep ips of dpns and devices
+ */
+ private static List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
+ List<IpAddress> tepIps = new ArrayList<>();
+ for (DpnInterfaces dpn : dpns) {
+ IpAddress internalTunnelIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpn.getDpId(),
+ new NodeId(l2GwDevice.getHwvtepNodeId()));
+ if (internalTunnelIp != null) {
+ tepIps.add(internalTunnelIp);
+ }
+ }
+ return tepIps;
+ }
+
+ /**
+ * Gets the all tep ips of l2 gw devices.
+ *
+ * @param devices
+ * the devices
+ * @return the all tep ips of l2 gw devices
+ */
+ private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
+ List<IpAddress> tepIps = new ArrayList<>();
+ for (L2GatewayDevice otherDevice : devices.values()) {
+ tepIps.add(otherDevice.getTunnelIp());
+ }
+ return tepIps;
+ }
+
+ /**
+ * Handle mcast for elan l2 gw device delete.
+ *
+ * @param elanInstance
+ * the elan instance
+ * @param l2GatewayDevice
+ * the l2 gateway device
+ * @return the listenable future
+ */
+ public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
+ L2GatewayDevice l2GatewayDevice) {
+ ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(),
+ l2GatewayDevice, false/* updateThisDevice */);
+ ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
+ new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
+ return Lists.newArrayList(updateMcastMacsFuture, deleteRemoteMcastMacFuture);
+ }
+
+ /**
+ * Delete remote mcast mac from Hwvtep node.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @return the listenable future
+ */
+ private static ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
+ RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
+ new MacAddress(ElanConstants.UNKNOWN_DMAC));
+
+ RemoteMcastMacs remoteMcast = HwvtepUtils.getRemoteMcastMac(broker, LogicalDatastoreType.OPERATIONAL, nodeId,
+ remoteMcastMacsKey);
+ if (remoteMcast != null) {
+ LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
+ logicalSwitchName);
+ return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
+ }
+
+ SettableFuture<Void> future = SettableFuture.create();
+ future.set(null);
+ return future;
+ }
+
+ /**
+ * Gets the tep ip of designated switch for external tunnel.
+ *
+ * @param l2GwDevice
+ * the l2 gw device
+ * @param elanInstanceName
+ * the elan instance name
+ * @return the tep ip of designated switch for external tunnel
+ */
+ public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
+ String elanInstanceName) {
+ IpAddress tepIp = null;
+ // TODO: Uncomment after DHCP changes are merged
+/* DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
+ elanInstanceName);
+ if (desgSwitch != null) {
+ tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
+ new NodeId(l2GwDevice.getHwvtepNodeId()));
+ }*/
+ return tepIp;
+ }
+
+ /**
+ * Gets the designated switch for external tunnel.
+ *
+ * @param tunnelIp
+ * the tunnel ip
+ * @param elanInstanceName
+ * the elan instance name
+ * @return the designated switch for external tunnel
+ */
+ // TODO: Uncomment after DHCP changes are merged
+/* public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
+ String elanInstanceName) {
+ InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
+ .builder(DesignatedSwitchesForExternalTunnels.class)
+ .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
+ .build();
+ Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
+ LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+ if (designatedSwitchForTunnelOptional.isPresent()) {
+ return designatedSwitchForTunnelOptional.get();
+ }
+ return null;
+ }*/
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.utils;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.AddL2GwDeviceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * It gathers a set of utility methods that handle ELAN configuration in external Devices (where external means
+ * "not-CSS". As of now: TORs).
+ *
+ * It makes use of HwvtepUtils class located under ovsdb/hwvtepsouthbound project for low-level mdsal operations
+ *
+ * @author eperefr
+ *
+ */
+public class ElanL2GatewayUtils {
+
+ private static DataBroker broker;
+ private static ItmRpcService itmRpcService;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
+
+ /**
+ * Sets the data broker.
+ *
+ * @param dataBroker
+ * the new data broker
+ */
+ public static void setDataBroker(DataBroker dataBroker) {
+ broker = dataBroker;
+ }
+
+ /**
+ * Sets the itm rpc service.
+ *
+ * @param itmRpc
+ * the new itm rpc service
+ */
+ public static void setItmRpcService(ItmRpcService itmRpc) {
+ itmRpcService = itmRpc;
+ }
+
+ /**
+ * Installs the given MAC as a remote mac in all external devices (as of
+ * now, TORs) that participate in the given Elan.
+ *
+ * @param elanInstance
+ * Elan to which the interface belongs to
+ * @param dpId
+ * Id of the DPN where the macs are located. Needed for selecting
+ * the right tunnel
+ * @param macAddresses
+ * the mac addresses
+ */
+ public static void installMacsInElanExternalDevices(ElanInstance elanInstance, BigInteger dpId,
+ List<PhysAddress> macAddresses) {
+ String logicalSwitchName = getElanFromLogicalSwitch(elanInstance.getElanInstanceName());
+ ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+ for (L2GatewayDevice externalDevice : elanDevices.values()) {
+ NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
+ IpAddress dpnTepIp = getSourceDpnTepIp(dpId, nodeId);
+ LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
+ if (dpnTepIp == null) {
+ LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
+ continue;
+ }
+ installMacsInExternalDeviceAsRemoteUcastMacs(externalDevice.getHwvtepNodeId(), macAddresses,
+ logicalSwitchName, dpnTepIp);
+ }
+ }
+
+ /**
+ * Installs a list of Mac Addresses as remote Ucast address in an external
+ * device using the hwvtep-southbound.
+ *
+ * @param deviceNodeId
+ * NodeId if the ExternalDevice where the macs must be installed
+ * in.
+ * @param macAddresses
+ * List of Mac addresses to be installed in the external device.
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param remoteVtepIp
+ * VTEP's IP in this CSS used for the tunnel with external
+ * device.
+ */
+ private static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String deviceNodeId,
+ List<PhysAddress> macAddresses, String logicalSwitchName, IpAddress remoteVtepIp) {
+ NodeId nodeId = new NodeId(deviceNodeId);
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
+ List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
+ for (PhysAddress mac : macAddresses) {
+ // TODO: Query ARP cache to get IP address corresponding to
+ // the MAC
+ IpAddress ipAddress = null;
+ macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
+ phyLocatorAug));
+ }
+ return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
+ }
+
+ /**
+ * Install macs in external device as remote ucast macs.
+ *
+ * @param elanName
+ * the elan name
+ * @param lstElanInterfaceNames
+ * the lst Elan interface names
+ * @param dpnId
+ * the dpn id
+ * @param externalNodeId
+ * the external node id
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String elanName,
+ Set<String> lstElanInterfaceNames, BigInteger dpnId, NodeId externalNodeId) {
+ SettableFuture<Void> future = SettableFuture.create();
+ future.set(null);
+ if (lstElanInterfaceNames == null || lstElanInterfaceNames.isEmpty()) {
+ return future;
+ }
+
+ IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, externalNodeId);
+ if (dpnTepIp == null) {
+ return future;
+ }
+
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepUtils.getPhysicalLocator(broker,
+ LogicalDatastoreType.CONFIGURATION, externalNodeId, dpnTepIp);
+ if (phyLocatorAug == null) {
+ phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
+ HwvtepUtils.putPhysicalLocator(transaction, externalNodeId, phyLocatorAug);
+ }
+
+ String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+ for (String interfaceName : lstElanInterfaceNames) {
+ ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
+ if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
+ for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
+ // TODO: Query ARP cache to get IP address corresponding to
+ // the MAC
+ IpAddress ipAddress = null;
+ RemoteUcastMacs mac = HwvtepSouthboundUtils.createRemoteUcastMac(externalNodeId,
+ macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, phyLocatorAug);
+ HwvtepUtils.putRemoteUcastMac(transaction, externalNodeId, mac);
+ }
+ }
+ }
+ LOG.debug("Installing macs in external device [{}] for dpn [{}], elan [{}], no of interfaces [{}]",
+ externalNodeId.getValue(), dpnId, elanName, lstElanInterfaceNames.size());
+ return transaction.submit();
+ }
+
+ /**
+ * Removes the given MAC Addresses from all the External Devices belonging
+ * to the specified ELAN.
+ *
+ * @param elanInstance
+ * the elan instance
+ * @param macAddresses
+ * the mac addresses
+ */
+ public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+ for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
+ removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
+ elanInstance.getElanInstanceName(), macAddresses);
+ }
+ }
+
+ /**
+ * Removes the given MAC Addresses from the specified External Device.
+ *
+ * @param deviceNodeId
+ * the device node id
+ * @param logicalSwitchName
+ * @param macAddresses
+ * the mac addresses
+ * @return the listenable future
+ */
+ private static ListenableFuture<Void> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
+ String logicalSwitchName, List<PhysAddress> macAddresses) {
+ NodeId nodeId = new NodeId(deviceNodeId);
+
+ // TODO (eperefr)
+ List<MacAddress> lstMac = Lists.transform(macAddresses, new Function<PhysAddress, MacAddress>() {
+ @Override
+ public MacAddress apply(PhysAddress physAddress) {
+ return (physAddress != null) ? new MacAddress(physAddress.getValue()) : null;
+ }
+ });
+ return HwvtepUtils.deleteRemoteUcastMacs(broker, nodeId, logicalSwitchName, lstMac);
+ }
+
+ public static ElanInstance getElanInstanceForUcastLocalMac(LocalUcastMacs localUcastMac) {
+ Optional<LogicalSwitches> lsOpc = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL,
+ (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
+ if (lsOpc.isPresent()) {
+ LogicalSwitches ls = lsOpc.get();
+ if (ls != null) {
+ // Logical switch name is Elan name
+ String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
+ return ElanUtils.getElanInstanceByName(elanName);
+ } else {
+ String macAddress = localUcastMac.getMacEntryKey().getValue();
+ LOG.error("Could not find logical_switch for {} being added/deleted", macAddress);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Install external device local macs in dpn.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param l2gwDeviceNodeId
+ * the l2gw device node id
+ * @param elan
+ * the elan
+ */
+ public static void installL2gwDeviceLocalMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
+ String elanName = elan.getElanInstanceName();
+ L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+ l2gwDeviceNodeId.getValue());
+ if (l2gwDevice == null) {
+ LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
+ return;
+ }
+
+ List<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
+ if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
+ for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
+ ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDeviceNodeId.getValue(), elan.getElanTag(),
+ elan.getVni(), localUcastMac.getMacEntryKey().getValue(), elanName);
+ }
+ }
+ LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
+ l2gwDeviceNodeId.getValue(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
+ }
+
+ public static void installL2GwUcastMacInElan(EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
+ L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
+ final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
+ final String elanInstanceName = elan.getElanInstanceName();
+
+ // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
+ // Looping through all DPNs in order to add/remove mac flows in their DMAC table
+ List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+ for (DpnInterfaces elanDpn : elanDpns) {
+ final BigInteger dpnId = elanDpn.getDpId();
+ final String nodeId = getNodeIdFromDpnId(dpnId);
+
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("Installing DMAC flows in {} connected to cluster node owner", dpnId.toString());
+
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ return ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId,
+ elan.getElanTag(), elan.getVni(), macToBeAdded, elanInstanceName);
+ }
+ }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("Install DMAC flows is not executed on the cluster node as this is not owner " +
+ "for the DPN {}", dpnId.toString());
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to install DMAC flows", error);
+ }
+ });
+ }
+
+ final IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
+ final List<PhysAddress> macList = new ArrayList<PhysAddress>();
+ macList.add(new PhysAddress(macToBeAdded));
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+ ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
+ final String hwvtepId = otherDevice.getHwvtepNodeId();
+ InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
+ bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId);
+
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
+ ListenableFuture<Void> installFuture = installMacsInExternalDeviceAsRemoteUcastMacs(
+ hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
+
+ Futures.addCallback(installFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Successful in initiating ucast_remote_macs addition" +
+ "related to {} in {}", logicalSwitchName, hwvtepId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error(String.format("Failed adding ucast_remote_macs related to " +
+ "%s in %s", logicalSwitchName, hwvtepId), error);
+ }
+ });
+
+ return Lists.newArrayList(installFuture);
+ }
+ }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("DMAC entry addition is not executed on the cluster node as this is not owner for " +
+ "the Hwvtep {}", hwvtepId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to install DMAC entry", error);
+ }
+ });
+ }
+ }
+ }
+
+ public static void unInstallL2GwUcastMacFromElan(EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
+ L2GatewayDevice extL2GwDevice, final LocalUcastMacs macToBeRemoved) {
+ final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
+ final String elanInstanceName = elan.getElanInstanceName();
+
+ // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
+ // Looping through all DPNs in order to add/remove mac flows in their DMAC table
+ List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+ for (DpnInterfaces elanDpn : elanDpns) {
+ final BigInteger dpnId = elanDpn.getDpId();
+ final String nodeId = getNodeIdFromDpnId(dpnId);
+
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("Uninstalling DMAC flows from {} connected to cluster node owner",
+ dpnId.toString());
+
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ return ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+ extDeviceNodeId, macToBeRemoved.getMacEntryKey().getValue());
+ }
+ }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("Uninstall DMAC flows is not executed on the cluster node as this is not owner " +
+ "for the DPN {}", dpnId.toString());
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to uninstall DMAC flows", error);
+ }
+ });
+ }
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+ ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
+ final String hwvtepId = otherDevice.getHwvtepNodeId();
+ final NodeId hwvtepNodeId = new NodeId(hwvtepId);
+ InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(hwvtepNodeId);
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
+ bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("Removing DMAC entry from {} connected to cluster node owner", hwvtepId);
+
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
+ ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMac(broker,
+ hwvtepNodeId, logicalSwitchName, macToBeRemoved.getMacEntryKey());
+
+ Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Successful in initiating ucast_remote_macs deletion " +
+ "related to {} in {}", logicalSwitchName, hwvtepId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error(String.format("Failed removing ucast_remote_macs related " +
+ "to %s in %s", logicalSwitchName, hwvtepId), error);
+ }
+ });
+
+ return Lists.newArrayList(uninstallFuture);
+ }
+ }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("DMAC entry removal is not executed on the cluster node as this is not owner for " +
+ "the Hwvtep {}", hwvtepId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to uninstall DMAC entry", error);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Delete elan macs from L2 gateway device.<br>
+ * This includes deleting ELAN mac table entries plus external device
+ * UcastLocalMacs which are part of the same ELAN.
+ *
+ * @param l2GatewayDevice
+ * the l2 gateway device
+ * @param elanName
+ * the elan name
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> deleteElanMacsFromL2GatewayDevice(L2GatewayDevice l2GatewayDevice,
+ String elanName) {
+ List<MacAddress> elanMacTableEntries = getElanMacTableEntries(elanName);
+ List<MacAddress> elanL2GatewayDevicesLocalMacs = getElanL2GatewayDevicesLocalMacs(l2GatewayDevice, elanName);
+
+ List<MacAddress> lstElanLocalMacs = new ArrayList<>(elanMacTableEntries);
+ lstElanLocalMacs.addAll(elanL2GatewayDevicesLocalMacs);
+
+ return HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(l2GatewayDevice.getHwvtepNodeId()),
+ elanName, lstElanLocalMacs);
+ }
+
+ /**
+ * Gets the elan mac table entries.
+ *
+ * @param elanName
+ * the elan name
+ * @return the elan mac table entries as list
+ */
+ public static List<MacAddress> getElanMacTableEntries(String elanName) {
+ MacTable macTable = ElanUtils.getElanMacTable(elanName);
+ if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
+ LOG.trace("MacTable is empty for elan: {}", elanName);
+ return Collections.emptyList();
+ }
+ List<MacAddress> lstMacs = Lists.transform(macTable.getMacEntry(), new Function<MacEntry, MacAddress>() {
+ @Override
+ public MacAddress apply(MacEntry macEntry) {
+ return (macEntry != null) ? new MacAddress(macEntry.getMacAddress().getValue()) : null;
+ }
+ });
+ return lstMacs;
+ }
+
+ /**
+ * Gets the elan l2 gateway devices local macs.
+ *
+ * @param l2GwDeviceToBeExcluded
+ * the l2 gw device to be excluded
+ * @param elanName
+ * the elan name
+ * @return the elan l2 gateway devices local macs
+ */
+ public static List<MacAddress> getElanL2GatewayDevicesLocalMacs(L2GatewayDevice l2GwDeviceToBeExcluded,
+ String elanName) {
+ List<MacAddress> lstL2GatewayDeviceMacs = new ArrayList<>();
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+ if (elanL2GwDevicesFromCache != null) {
+ for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) {
+ List<LocalUcastMacs> lstUcastLocalMacs = otherDevice.getUcastLocalMacs();
+ if (lstUcastLocalMacs != null) {
+ List<MacAddress> l2GwDeviceMacs = Lists.transform(lstUcastLocalMacs,
+ new Function<LocalUcastMacs, MacAddress>() {
+ @Override
+ public MacAddress apply(LocalUcastMacs localUcastMac) {
+ return (localUcastMac != null) ? localUcastMac.getMacEntryKey() : null;
+ }
+ });
+ lstL2GatewayDeviceMacs.addAll(l2GwDeviceMacs);
+ }
+ }
+ }
+ }
+ return lstL2GatewayDeviceMacs;
+ }
+
+ /**
+ * Install ELAN macs in L2 Gateway device.<br>
+ * This includes installing ELAN mac table entries plus external device
+ * UcastLocalMacs which are part of the same ELAN.
+ *
+ * @param elanName
+ * the elan name
+ * @param l2GatewayDevice
+ * the l2 gateway device which has to be configured
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> installElanMacsInL2GatewayDevice(String elanName,
+ L2GatewayDevice l2GatewayDevice) {
+ String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+ NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+
+ List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName,
+ l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
+ List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName,
+ l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
+
+ List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
+ lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
+
+ ListenableFuture<Void> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId, lstRemoteUcastMacs);
+
+ LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
+ lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
+ return future;
+ }
+
+ /**
+ * Gets the l2 gateway devices ucast local macs as remote ucast macs.
+ *
+ * @param elanName
+ * the elan name
+ * @param l2GatewayDeviceToBeConfigured
+ * the l2 gateway device to be configured
+ * @param hwVtepNodeId
+ * the hw vtep node Id to be configured
+ * @param logicalSwitchName
+ * the logical switch name
+ * @return the l2 gateway devices macs as remote ucast macs
+ */
+ public static List<RemoteUcastMacs> getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+ List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+
+ if (elanL2GwDevicesFromCache != null) {
+ for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
+ if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
+ continue;
+ }
+ if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
+ List<LocalUcastMacs> lstUcastLocalMacs = otherDevice.getUcastLocalMacs();
+ if (lstUcastLocalMacs != null) {
+ for (LocalUcastMacs localUcastMac : lstUcastLocalMacs) {
+ HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(
+ String.valueOf(otherDevice.getTunnelIp().getValue()));
+ RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
+ localUcastMac.getMacEntryKey().getValue(), localUcastMac.getIpaddr(),
+ logicalSwitchName, physLocatorAug);
+ lstRemoteUcastMacs.add(remoteUcastMac);
+ }
+ }
+ }
+ }
+ }
+ return lstRemoteUcastMacs;
+ }
+
+ /**
+ * Are MLAG devices.
+ *
+ * @param l2GatewayDevice
+ * the l2 gateway device
+ * @param otherL2GatewayDevice
+ * the other l2 gateway device
+ * @return true, if both the specified l2 gateway devices are part of same
+ * MLAG
+ */
+ public static boolean areMLAGDevices(L2GatewayDevice l2GatewayDevice, L2GatewayDevice otherL2GatewayDevice) {
+ // If tunnel IPs are same, then it is considered to be part of same MLAG
+ return Objects.equals(l2GatewayDevice.getTunnelIp(), otherL2GatewayDevice.getTunnelIp());
+ }
+
+ /**
+ * Gets the elan mac table entries as remote ucast macs. <br>
+ * Note: ELAN MAC table only contains internal switches MAC's. It doesn't
+ * contain external device MAC's.
+ *
+ * @param elanName
+ * the elan name
+ * @param l2GatewayDeviceToBeConfigured
+ * the l2 gateway device to be configured
+ * @param hwVtepNodeId
+ * the hw vtep node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @return the elan mac table entries as remote ucast macs
+ */
+ public static List<RemoteUcastMacs> getElanMacTableEntriesAsRemoteUcastMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+ List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
+
+ MacTable macTable = ElanUtils.getElanMacTable(elanName);
+ if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
+ LOG.trace("MacTable is empty for elan: {}", elanName);
+ return lstRemoteUcastMacs;
+ }
+
+ for (MacEntry macEntry : macTable.getMacEntry()) {
+ BigInteger dpnId = ElanUtils.getDpidFromInterface(macEntry.getInterface());
+ if (dpnId == null) {
+ LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
+ continue;
+ }
+
+ IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, hwVtepNodeId);
+ LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpnId, hwVtepNodeId.getValue());
+ if (dpnTepIp == null) {
+ LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpnId, hwVtepNodeId.getValue());
+ continue;
+ }
+ HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
+ // TODO: Query ARP cache to get IP address corresponding to the
+ // MAC
+ IpAddress ipAddress = null;
+ RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
+ macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, physLocatorAug);
+ lstRemoteUcastMacs.add(remoteUcastMac);
+ }
+ return lstRemoteUcastMacs;
+ }
+
+ /**
+ * Gets the external tunnel interface name.
+ *
+ * @param sourceNode
+ * the source node
+ * @param dstNode
+ * the dst node
+ * @return the external tunnel interface name
+ */
+ public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+ String tunnelInterfaceName = null;
+ try {
+ Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
+ .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
+ .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+
+ RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
+ if (rpcResult.isSuccessful()) {
+ tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
+ LOG.debug("Tunnel interface name: {} for sourceNode: {} and dstNode: {}", tunnelInterfaceName,
+ sourceNode, dstNode);
+ } else {
+ LOG.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}",
+ rpcResult.getErrors());
+ }
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ LOG.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}: {} ",
+ sourceNode, dstNode, e);
+ }
+ return tunnelInterfaceName;
+ }
+
+ /**
+ * Gets the source dpn tep ip.
+ *
+ * @param srcDpnId
+ * the src dpn id
+ * @param dstHwVtepNodeId
+ * the dst hw vtep node id
+ * @return the dpn tep ip
+ */
+ public static IpAddress getSourceDpnTepIp(BigInteger srcDpnId, NodeId dstHwVtepNodeId) {
+ IpAddress dpnTepIp = null;
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(srcDpnId),
+ dstHwVtepNodeId.getValue());
+ if (tunnelInterfaceName != null) {
+ Interface tunnelInterface = getInterfaceFromConfigDS(new InterfaceKey(tunnelInterfaceName), broker);
+ if (tunnelInterface != null) {
+ dpnTepIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+ } else {
+ LOG.warn("Tunnel interface not found for tunnelInterfaceName {}", tunnelInterfaceName);
+ }
+ } else {
+ LOG.warn("Tunnel interface name not found for srcDpnId {} and dstHwVtepNodeId {}", srcDpnId,
+ dstHwVtepNodeId);
+ }
+ return dpnTepIp;
+ }
+
+ /**
+ * Update vlan bindings in l2 gateway device.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param hwVtepDevice
+ * the hardware device
+ * @param defaultVlanId
+ * the default vlan id
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
+ Devices hwVtepDevice, Integer defaultVlanId) {
+ if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
+ String errMsg = "HwVtepDevice is null or interfaces are empty.";
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice
+ .getInterfaces()) {
+ List<VlanBindings> vlanBindings = new ArrayList<>();
+ if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
+ for (Integer vlanId : deviceInterface.getSegmentationIds()) {
+ vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
+ }
+ } else {
+ // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
+ // ID not specified at interface level.
+ vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
+ }
+ HwvtepUtils.mergeVlanBindings(transaction, nodeId, hwVtepDevice.getDeviceName(),
+ deviceInterface.getInterfaceName(), vlanBindings);
+ }
+ ListenableFuture<Void> future = transaction.submit();
+ LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
+ logicalSwitchName);
+ return future;
+ }
+
+ /**
+ * Delete vlan bindings from l2 gateway device.
+ *
+ * @param nodeId
+ * the node id
+ * @param hwVtepDevice
+ * the hw vtep device
+ * @param defaultVlanId
+ * the default vlan id
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
+ Integer defaultVlanId) {
+ if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
+ String errMsg = "HwVtepDevice is null or interfaces are empty.";
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
+
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice
+ .getInterfaces()) {
+ String phyPortName = deviceInterface.getInterfaceName();
+ if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
+ for (Integer vlanId : deviceInterface.getSegmentationIds()) {
+ HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, vlanId);
+ }
+ } else {
+ // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
+ // ID not specified at interface level.
+ HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, defaultVlanId);
+ }
+ }
+ ListenableFuture<Void> future = transaction.submit();
+
+ LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
+ nodeId.getValue(), hwVtepDevice, defaultVlanId);
+ return future;
+ }
+
+ /**
+ * Gets the elan name from logical switch name.
+ *
+ * @param logicalSwitchName
+ * the logical switch name
+ * @return the elan name from logical switch name
+ */
+ public static String getElanFromLogicalSwitch(String logicalSwitchName) {
+ // Assuming elan name is same as logical switch name
+ String elanName = logicalSwitchName;
+ return elanName;
+ }
+
+ /**
+ * Gets the logical switch name from elan name.
+ *
+ * @param elanName
+ * the elan name
+ * @return the logical switch from elan name
+ */
+ public static String getLogicalSwitchFromElan(String elanName) {
+ // Assuming logical switch name is same as elan name
+ String logicalSwitchName = elanName;
+ return logicalSwitchName;
+ }
+
+ /**
+ * Gets the l2 gateway connection job key.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @return the l2 gateway connection job key
+ */
+ public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
+ return new StringBuilder(nodeId).append(logicalSwitchName).toString();
+ }
+
+ public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
+ InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder =
+ InstanceIdentifier.builder(Interfaces.class).child(Interface.class, interfaceKey);
+ return interfaceInstanceIdentifierBuilder.build();
+ }
+
+ public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
+ InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
+ Optional<Interface> interfaceOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
+ if (!interfaceOptional.isPresent()) {
+ return null;
+ }
+
+ return interfaceOptional.get();
+ }
+
+ /**
+ * Delete l2 gateway device ucast local macs from elan.<br>
+ * Deletes macs from internal ELAN nodes and also on rest of external l2
+ * gateway devices which are part of the ELAN.
+ *
+ * @param l2GatewayDevice
+ * the l2 gateway device whose ucast local macs to be deleted
+ * from elan
+ * @param elanName
+ * the elan name
+ * @return the listenable future
+ */
+ public static List<ListenableFuture<Void>> deleteL2GatewayDeviceUcastLocalMacsFromElan(
+ L2GatewayDevice l2GatewayDevice, String elanName) {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+ ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
+ if (elan == null) {
+ LOG.error("Could not find Elan by name: {}", elanName);
+ return futures;
+ }
+
+ List<LocalUcastMacs> lstLocalUcastMacs = l2GatewayDevice.getUcastLocalMacs();
+ if (lstLocalUcastMacs != null) {
+ for (LocalUcastMacs localUcastMac : lstLocalUcastMacs) {
+ List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+ if (dpnInterfaces != null) {
+ // TODO: Need to check if it can be optimized
+ for (DpnInterfaces elanDpn : dpnInterfaces) {
+ ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), elanDpn.getDpId(),
+ l2GatewayDevice.getHwvtepNodeId(), localUcastMac.getMacEntryKey().getValue());
+ }
+ }
+ }
+
+ List<MacAddress> lstMac = Lists.transform(lstLocalUcastMacs, new Function<LocalUcastMacs, MacAddress>() {
+ @Override
+ public MacAddress apply(LocalUcastMacs mac) {
+ return (mac != null) ? mac.getMacEntryKey() : null;
+ }
+ });
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+ .getAllElanL2GatewayDevicesFromCache(elanName);
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(l2GatewayDevice.getHwvtepNodeId())) {
+ futures.add(HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(otherDevice.getHwvtepNodeId()),
+ elanName, lstMac));
+ }
+ }
+ }
+ return futures;
+ }
+
+ public static void createItmTunnels(ItmRpcService itmRpcService, String hwvtepId, String psName,
+ IpAddress tunnelIp) {
+ AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
+ builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
+ builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
+ builder.setIpAddress(tunnelIp);
+ try {
+ Future<RpcResult<Void>> result = itmRpcService.addL2GwDevice(builder.build());
+ RpcResult<Void> rpcResult = result.get();
+ if (rpcResult.isSuccessful()) {
+ LOG.info("Created ITM tunnels for {}", hwvtepId);
+ } else {
+ LOG.error("Failed to create ITM Tunnels: ", rpcResult.getErrors());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("RPC to create ITM tunnels failed", e);
+ }
+ }
+
+ public static String getNodeIdFromDpnId(BigInteger dpnId) {
+ return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.elan.l2gw.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.L2gateways;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class L2GatewayConnectionUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionUtils.class);
+
+ public static boolean isGatewayAssociatedToL2Device(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice.getL2GatewayIds().size() > 0);
+ }
+
+ public static L2gateway getNeutronL2gateway(DataBroker broker, Uuid l2GatewayId) {
+ LOG.debug("getNeutronL2gateway for {}", l2GatewayId.getValue());
+ InstanceIdentifier<L2gateway> inst = InstanceIdentifier.create(Neutron.class).child(L2gateways.class)
+ .child(L2gateway.class, new L2gatewayKey(l2GatewayId));
+ Optional<L2gateway> l2Gateway = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (l2Gateway.isPresent()) {
+ return l2Gateway.get();
+ }
+ return null;
+ }
+
+ public static List<L2gateway> getL2gatewayList(DataBroker broker) {
+ InstanceIdentifier<L2gateways> inst = InstanceIdentifier.create(Neutron.class).child(L2gateways.class);
+ Optional<L2gateways> l2gateways = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+
+ if (l2gateways.isPresent()) {
+ return l2gateways.get().getL2gateway();
+ }
+ return null;
+ }
+
+ public static List<L2gatewayConnection> getAllL2gatewayConnections(DataBroker broker) {
+ InstanceIdentifier<L2gatewayConnections> inst = InstanceIdentifier.create(Neutron.class)
+ .child(L2gatewayConnections.class);
+ Optional<L2gatewayConnections> l2GwConns = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (l2GwConns.isPresent()) {
+ return l2GwConns.get().getL2gatewayConnection();
+ }
+ return null;
+ }
+
+ public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+ L2gatewayConnection input) {
+ addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstanceManager,
+ input, null);
+ }
+
+ public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+ L2gatewayConnection input, String l2GwDeviceName) {
+ Uuid networkUuid = input.getNetworkId();
+ ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
+ if (elanInstance == null || elanInstance.getVni() == null) {
+ LOG.error("Neutron network with id {} is not present", networkUuid.getValue());
+ } else {
+ Uuid l2GatewayId = input.getL2gatewayId();
+ L2gateway l2Gateway = getNeutronL2gateway(broker, l2GatewayId);
+ if (l2Gateway == null) {
+ LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
+ } else {
+ associateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
+ l2Gateway, input.getSegmentId(), l2GwDeviceName);
+ }
+ }
+ }
+
+ public static void deleteL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+ L2gatewayConnection input) {
+ Uuid networkUuid = input.getNetworkId();
+ ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
+ if (elanInstance == null) {
+ LOG.error("Neutron network with id {} is not present", networkUuid.getValue());
+ } else {
+ Uuid l2GatewayId = input.getL2gatewayId();
+ L2gateway l2Gateway = L2GatewayConnectionUtils.getNeutronL2gateway(broker, l2GatewayId);
+ if (l2Gateway == null) {
+ LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
+ } else {
+ disAssociateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
+ l2Gateway, input.getSegmentId());
+ }
+ }
+ }
+
+ private static void disAssociateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
+ L2gateway l2Gateway, final Integer defaultVlan) {
+ final String elanName = elanInstance.getElanInstanceName();
+ List<Devices> l2Devices = l2Gateway.getDevices();
+ for (final Devices l2Device : l2Devices) {
+ final String l2DeviceName = l2Device.getDeviceName();
+ final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ if (isL2GwDeviceConnected(l2GatewayDevice)) {//TODO handle delete while device is offline
+ // Delete L2 Gateway device from 'ElanL2GwDevice' cache
+ ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, l2GatewayDevice.getHwvtepNodeId());
+
+ final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
+ InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
+ bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("L2 Gateway device delete is triggered for {} connected to cluster owner node",
+ l2DeviceName);
+
+ // Create DataStoreJobCoordinator jobs to create Logical
+ // switches on all physical switches
+ // which are part of L2 Gateway
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ DisAssociateHwvtepFromElan disAssociateHwvtepToElan = new DisAssociateHwvtepFromElan(broker,
+ l2GatewayDevice, elanInstance, l2Device, defaultVlan);
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
+ dataStoreCoordinator.enqueueJob(jobKey, disAssociateHwvtepToElan,
+ SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("L2 Gateway device delete is not triggered on the cluster node as this is not " +
+ "owner for {}", l2DeviceName);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to trigger L2 Gateway device delete action", error);
+ }
+ });
+ } else {
+ LOG.error("could not handle connection delete L2 Gateway device with id {} is not present",
+ l2DeviceName);
+ }
+ }
+ }
+
+ private static void associateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
+ L2gateway l2Gateway, final Integer defaultVlan, String l2GwDeviceName) {
+ final String elanName = elanInstance.getElanInstanceName();
+ List<Devices> l2Devices = l2Gateway.getDevices();
+ for (final Devices l2Device : l2Devices) {
+ final String l2DeviceName = l2Device.getDeviceName();
+ // L2gateway can have more than one L2 Gw devices. Configure Logical Switch, VLAN mappings,...
+ // only on the switch which has come up just now and exclude all other devices from
+ // preprovisioning/re-provisioning
+ if (l2GwDeviceName != null && !l2GwDeviceName.equals(l2DeviceName)) {
+ continue;
+ }
+ final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ if (isL2GwDeviceConnected(l2GatewayDevice)) {
+ // Add L2 Gateway device to 'ElanL2GwDevice' cache
+ final boolean createLogicalSwitch;
+ LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
+ new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
+ if (logicalSwitch == null) {
+ final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+ l2GatewayDevice, elanName, l2Device, defaultVlan);
+ hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+ createLogicalSwitch = true;
+ } else {
+ addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice);
+ createLogicalSwitch = false;
+ }
+ final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
+ InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
+ bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ LOG.info("Creating Logical switch on {} connected to cluster owner node", l2DeviceName);
+
+ // Create DataStoreJobCoordinator jobs to create Logical
+ // switches on all physical switches
+ // which are part of L2 Gateway
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ AssociateHwvtepToElan associateHwvtepToElan = new AssociateHwvtepToElan(broker,
+ l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
+ dataStoreCoordinator.enqueueJob(jobKey, associateHwvtepToElan,
+ SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ LOG.info("Logical switch creation is not triggered on the cluster node as this is not " +
+ "owner for {}", l2DeviceName);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed to trigger Logical switch creation action", error);
+ }
+ });
+ } else {
+ LOG.error("L2 Gateway device with id {} is not present", l2DeviceName);
+ }
+ }
+ }
+
+ public static void addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice) {
+ L2GatewayDevice elanL2GwDevice = new L2GatewayDevice();
+ elanL2GwDevice.setHwvtepNodeId(l2GatewayDevice.getHwvtepNodeId());
+ elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
+ elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
+ ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
+ }
+
+ private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
+ }
+
+ private static class AssociateHwvtepToElan implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+ boolean createLogicalSwitch;
+
+ public AssociateHwvtepToElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
+ this.broker = broker;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanInstance = elanInstance;
+ this.l2Device = l2Device;
+ this.defaultVlan = defaultVlan;
+ this.createLogicalSwitch = createLogicalSwitch;
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+ final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+
+ // Create Logical Switch if it's not created already in
+ // the device
+ if (createLogicalSwitch) {
+ ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance, l2Device);
+ futures.add(lsCreateFuture);
+ } else {
+ // Logical switch is already created; do the rest of
+ // configuration
+ futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+ new NodeId(l2GatewayDevice.getHwvtepNodeId()), logicalSwitchName, l2Device, defaultVlan));
+ futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, l2GatewayDevice));
+ HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+ logicalSwitchName, l2GatewayDevice,
+ new Callable<List<ListenableFuture<Void>>>() {
+
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
+ logicalSwitchName, l2GatewayDevice));
+ return futures;
+ }}
+ );
+ }
+
+ return futures;
+ }
+
+ private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device) {
+ final String logicalSwitchName = ElanL2GatewayUtils
+ .getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+ String segmentationId = elanInstance.getVni().toString();
+
+ // Register for Logical switch update in opearational DS
+ final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+ l2GatewayDevice, logicalSwitchName, l2Device, defaultVlan);
+ hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+
+ NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+ InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
+ LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
+ elanInstance.getDescription(), segmentationId);
+
+ ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
+ Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ // Listener will be closed after all configuration completed
+ // on hwvtep by
+ // listener itself
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
+ try {
+ hwVTEPLogicalSwitchListener.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DataChangeListener.", e);
+ }
+ }
+ });
+ return lsCreateFuture;
+ }
+ }
+
+ private static class DisAssociateHwvtepFromElan implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+
+ public DisAssociateHwvtepFromElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device, Integer defaultVlan) {
+ this.broker = broker;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanInstance = elanInstance;
+ this.l2Device = l2Device;
+ this.defaultVlan = defaultVlan;
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+ // Remove remote MACs and vlan mappings from physical port
+ // Once all above configurations are deleted, delete logical
+ // switch
+ NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+ String elanName = elanInstance.getElanInstanceName();
+ futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
+ futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
+ l2GatewayDevice));
+ futures.addAll(ElanL2GatewayUtils.deleteL2GatewayDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+ futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
+ Thread.sleep(30000);
+ futures.add(HwvtepUtils.deleteLogicalSwitch(this.broker, hwvtepNodeId, elanName));
+
+ return futures;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.statusanddiag;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElanStatusMonitor implements ElanStatusMonitorMBean{
+
+ private String serviceStatus;
+ private static ElanStatusMonitor elanStatusMonitor = new ElanStatusMonitor();
+ private static final String JMX_ELAN_OBJ_NAME = "com.ericsson.sdncp.services.status:type=SvcElanService";
+ private static final Logger log = LoggerFactory.getLogger(ElanStatusMonitor.class);
+
+ private ElanStatusMonitor () {
+ }
+
+ public void registerMbean() {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ try {
+ ObjectName objName = new ObjectName(JMX_ELAN_OBJ_NAME);
+ mbs.registerMBean(elanStatusMonitor, objName);
+ log.info("MXBean registration SUCCESSFUL!!! {}", JMX_ELAN_OBJ_NAME);
+ } catch (InstanceAlreadyExistsException iaeEx) {
+ log.error("MXBean registration FAILED with InstanceAlreadyExistsException", iaeEx);
+ } catch (MBeanRegistrationException mbrEx) {
+ log.error("MXBean registration FAILED with MBeanRegistrationException", mbrEx);
+ } catch (NotCompliantMBeanException ncmbEx) {
+ log.error("MXBean registration FAILED with NotCompliantMBeanException", ncmbEx);
+ } catch (MalformedObjectNameException monEx) {
+ log.error("MXBean registration failed with MalformedObjectNameException", monEx);
+ }
+ }
+
+ public static ElanStatusMonitor getInstance() {
+ return elanStatusMonitor;
+ }
+
+ @Override
+ public String acquireServiceStatus() {
+ return serviceStatus;
+ }
+
+ public void reportStatus (String serviceStatus) {
+ this.serviceStatus = serviceStatus;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.statusanddiag;
+
+public interface ElanStatusMonitorMBean {
+
+ public String acquireServiceStatus();
+
+}
public static final short ELAN_FILTER_EQUALS_TABLE = 55;
public static final BigInteger COOKIE_ELAN_FILTER_EQUALS = new BigInteger("8800000", 16);
-
+ public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
+ public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
}
/*
- * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
*/
package org.opendaylight.vpnservice.elan.utils;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
-import com.google.common.util.concurrent.CheckedFuture;
-import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceServiceUtil;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.vpnservice.mdsalutil.*;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil.MdsalOp;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.actions._case.WriteActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceTypeFlowBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaceForwardingEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanTagNameMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceTypeFlowBased;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesKey;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+public class ElanUtils {
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
+ private static final ArrayList EMPTY_LIST = new ArrayList();
-public class ElanUtils {
+ private static OdlInterfaceRpcService interfaceMgrRpcService;
- private static ElanServiceProvider elanServiceProvider;
- private static final Logger logger = LoggerFactory.getLogger(ElanUtils.class);
+ private static ItmRpcService itmRpcService;
- public static final FutureCallback<Void> DEFAULT_CALLBACK =
- new FutureCallback<Void>() {
- public void onSuccess(Void result) {
- logger.debug("Success in Datastore operation");
- }
+ private static IMdsalApiManager mdsalMgr;
+
+ private static DataBroker dataBroker;
- public void onFailure(Throwable error) {
- logger.error("Error in Datastore operation", error);
- };
- };
+ private static final Logger logger = LoggerFactory.getLogger(ElanUtils.class);
+
+ public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ logger.debug("Success in Datastore operation");
+ }
- public static Integer getUniqueId(IdManagerService idManager, String poolName, String idKey) {
- AllocateIdInput getIdInput = new AllocateIdInputBuilder()
- .setPoolName(poolName)
- .setIdKey(idKey).build();
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Error in Datastore operation", error);
+ }
+ };
+
+ /**
+ * Uses the IdManager to retrieve a brand new ElanTag.
+ *
+ * @param idManager
+ * the id manager
+ * @param idKey
+ * the id key
+ * @return the integer
+ */
+ public static Integer retrieveNewElanTag(IdManagerService idManager, String idKey) {
+
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
+ .setIdKey(idKey).build();
try {
Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
RpcResult<AllocateIdOutput> rpcResult = result.get();
- if(rpcResult.isSuccessful()) {
+ if (rpcResult.isSuccessful()) {
return rpcResult.getResult().getIdValue().intValue();
} else {
logger.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
return 0;
}
- public static void setElanServiceProvider(ElanServiceProvider elanService) {
- elanServiceProvider = elanService;
+ public static DataBroker getDataBroker() {
+ return dataBroker;
+ }
+
+ public final static void setIfaceMgrRpcService(OdlInterfaceRpcService rpcService) {
+ interfaceMgrRpcService = rpcService;
+ }
+
+ public final static void setItmRpcService(ItmRpcService itmService) {
+ itmRpcService = itmService;
+ }
+
+ public final static void setDataBroker(DataBroker broker) {
+ dataBroker = broker;
+ }
+
+ public final static void setMdsalManager(IMdsalApiManager mdsalApiManager) {
+ mdsalMgr = mdsalApiManager;
}
+
public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
InstanceIdentifier<T> path) {
-
- ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
-
+ ReadOnlyTransaction tx = (broker != null ) ? broker.newReadOnlyTransaction() : dataBroker.newReadOnlyTransaction();
Optional<T> result = Optional.absent();
try {
- result = tx.read(datastoreType, path).get();
+ CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
+ result = checkedFuture.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
}
+
public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
}
//elan-instances config container
public static ElanInstance getElanInstanceByName(String elanInstanceName) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
- Optional<ElanInstance> elanInstance = read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+ Optional<ElanInstance> elanInstance = read(dataBroker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
if(elanInstance.isPresent()) {
return elanInstance.get();
}
//elan-interfaces Config Container
public static ElanInterface getElanInterfaceByElanInterfaceName(String elanInterfaceName) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
- Optional<ElanInterface> existingElanInterface = read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
+ Optional<ElanInterface> existingElanInterface = read(dataBroker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
if(existingElanInterface.isPresent()) {
return existingElanInterface.get();
}
//elan-state Operational container
public static Elan getElanByName(String elanInstanceName) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
- Optional<Elan> elanInstance = read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier);
+ Optional<Elan> elanInstance = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanIdentifier);
if(elanInstance.isPresent()) {
return elanInstance.get();
}
// grouping of forwarding-entries
public static MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
- Optional<MacEntry> existingInterfaceMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId);
+ Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId);
if(existingInterfaceMacEntry.isPresent()) {
return existingInterfaceMacEntry.get();
}
}
public static MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
- DataBroker broker = elanServiceProvider.getBroker();
- Optional<MacEntry> existingInterfaceMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+ Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
if(existingInterfaceMacEntry.isPresent()) {
return existingInterfaceMacEntry.get();
}
//elan-forwarding-tables Operational container
public static MacEntry getMacTableByElanName(String elanName, PhysAddress physAddress) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
- Optional<MacEntry> existingElanMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, macId);
+ Optional<MacEntry> existingElanMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, macId);
if(existingElanMacEntry.isPresent()) {
return existingElanMacEntry.get();
}
public static MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
- DataBroker broker = elanServiceProvider.getBroker();
- Optional<MacEntry> existingInterfaceMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+ Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
if(existingInterfaceMacEntry.isPresent()) {
return existingInterfaceMacEntry.get();
}
//elan-interface-forwarding-entries Operational container
public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
- Optional<ElanInterfaceMac> existingElanInterface = read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
+ Optional<ElanInterfaceMac> existingElanInterface = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
if(existingElanInterface.isPresent()) {
return existingElanInterface.get();
}
return null;
}
+ /**
+ * Gets the elan interface mac addresses.
+ *
+ * @param interfaceName
+ * the interface name
+ * @return the elan interface mac addresses
+ */
+ public static List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
+ List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
+ ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
+ if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
+ List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
+ for (MacEntry macEntry : macEntries) {
+ macAddresses.add(macEntry.getMacAddress());
+ }
+ }
+ return macAddresses;
+ }
+
public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(String interfaceName) {
return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class).child(ElanInterfaceMac.class,
new ElanInterfaceMacKey(interfaceName)).build();
}
- //elan-dpn-interfaces Operational Container
+ /**
+ * Returns the list of Interfaces that belong to an Elan on an specific DPN.
+ * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
+ *
+ * @param elanInstanceName
+ * name of the Elan to which the interfaces must belong to
+ * @param dpId
+ * Id of the DPN where the interfaces are located
+ * @return
+ */
public static DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
- DataBroker broker = elanServiceProvider.getBroker();
- InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
- Optional<DpnInterfaces> elanDpnInterfaces = read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId);
- if(elanDpnInterfaces.isPresent()) {
+ InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId =
+ getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
+ Optional<DpnInterfaces> elanDpnInterfaces = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId);
+ if ( elanDpnInterfaces.isPresent() ) {
return elanDpnInterfaces.get();
}
return null;
}
- public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName, BigInteger dpId) {
- return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class,
- new ElanDpnInterfacesListKey(elanInstanceName)).child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
+ /**
+ * Returns the InstanceIdentifier that points to the Interfaces of an Elan in a
+ * given DPN in the Operational DS.
+ * Data retrieved from Elans's operational DS: dpn-interfaces list
+ *
+ * @param elanInstanceName
+ * name of the Elan to which the interfaces must belong to
+ * @param dpId
+ * Id of the DPN where the interfaces are located
+ * @return
+ */
+ public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
+ BigInteger dpId) {
+ return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+ .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
+ .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
}
//elan-tag-name-map Operational Container
public static ElanTagName getElanInfoByElanTag(long elanTag) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
- Optional<ElanTagName> existingElanInfo = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanId);
+ Optional<ElanTagName> existingElanInfo = ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanId);
if(existingElanInfo.isPresent()) {
return existingElanInfo.get();
}
}
// interface-index-tag operational container
- public static IfIndexInterface getInterfaceInfoByInterfaceTag(long interfaceTag) {
- DataBroker broker = elanServiceProvider.getBroker();
+ public static Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
- Optional<IfIndexInterface> existingInterfaceInfo = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
- if(existingInterfaceInfo.isPresent()) {
- return existingInterfaceInfo.get();
- }
- return null;
+ return ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, interfaceId);
}
public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
- return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+ return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class,
+ new ElanDpnInterfacesListKey(elanInstanceName)).build();
}
public static ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
- DataBroker broker = elanServiceProvider.getBroker();
InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
- Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+ Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
if(existingElanDpnInterfaces.isPresent()) {
return existingElanDpnInterfaces.get();
}
return null;
}
- public static ElanDpnInterfaces getElanDpnInterfacesList() {
- DataBroker broker = elanServiceProvider.getBroker();
- InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class).build();
- Optional<ElanDpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+ /**
+ * This method is useful get all ELAN participating CSS dpIds to install
+ * program remote dmac entries and updating remote bc groups for tor
+ * integration.
+ *
+ * @param elanInstanceName
+ * the elan instance name
+ * @return list of dpIds
+ */
+ public static List<BigInteger> getParticipatingDPNsInElanInstance(String elanInstanceName) {
+ List<BigInteger> dpIds = new ArrayList<BigInteger>();
+ InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
+ Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+ if (!existingElanDpnInterfaces.isPresent()) {
+ return dpIds;
+ }
+ List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
+ for (DpnInterfaces dpnInterface: dpnInterfaces) {
+ dpIds.add(dpnInterface.getDpId());
+ }
+ return dpIds;
+ }
+
+ /**
+ * To check given dpId is already present in Elan instance. This can be used
+ * to program flow entry in external tunnel table when a new access port
+ * added for first time into the ELAN instance
+ *
+ * @param dpId
+ * the dp id
+ * @param elanInstanceName
+ * the elan instance name
+ * @return true if dpId is already present, otherwise return false
+ */
+ public static boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
+ boolean isDpIdPresent = false;
+ InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
+ Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+ if (!existingElanDpnInterfaces.isPresent()) {
+ return isDpIdPresent;
+ }
+ List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
+ for (DpnInterfaces dpnInterface: dpnInterfaces) {
+ if (dpnInterface.getDpId().equals(dpId)) {
+ isDpIdPresent = true;
+ break;
+ }
+ }
+ return isDpIdPresent;
+ }
+
+ public static ElanDpnInterfaces getElanDpnInterfacesList() {
+ InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId =
+ InstanceIdentifier.builder(ElanDpnInterfaces.class).build();
+ Optional<ElanDpnInterfaces> existingElanDpnInterfaces =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
if(existingElanDpnInterfaces.isPresent()) {
return existingElanDpnInterfaces.get();
}
}
public static ElanForwardingTables getElanForwardingList() {
- DataBroker broker = elanServiceProvider.getBroker();
- InstanceIdentifier<ElanForwardingTables> elanForwardingTableId = InstanceIdentifier.builder(ElanForwardingTables.class).build();
- Optional<ElanForwardingTables> existingElanForwardingList = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId);
+ InstanceIdentifier<ElanForwardingTables> elanForwardingTableId =
+ InstanceIdentifier.builder(ElanForwardingTables.class).build();
+ Optional<ElanForwardingTables> existingElanForwardingList =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId);
if(existingElanForwardingList.isPresent()) {
return existingElanForwardingList.get();
}
return null;
}
+ /**
+ * Gets the elan mac table.
+ *
+ * @param elanName
+ * the elan name
+ * @return the elan mac table
+ */
+ public static MacTable getElanMacTable(String elanName) {
+ InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
+ Optional<MacTable> existingElanMacTable =
+ ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId);
+ if (existingElanMacTable.isPresent()) {
+ return existingElanMacTable.get();
+ }
+ return null;
+ }
public static long getElanLocalBCGID(long elanTag) {
return ElanConstants.ELAN_GID_MIN + (((elanTag % ElanConstants.ELAN_GID_MIN) *2) - 1);
return (BigInteger.valueOf(elanTag)).shiftLeft(24);
}
+ public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet ) {
+ int shBit = (isSHFlagSet) ? 1 : 0;
+ return (BigInteger.valueOf(elanTag)).shiftLeft(24).or(BigInteger.valueOf(shBit));
+ }
+
public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
}
return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
}
+ /**
+ * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and also in
+ * other DPNs.
+ *
+ * @param elanInfo
+ * the elan info
+ * @param interfaceInfo
+ * the interface info
+ * @param macTimeout
+ * the mac timeout
+ * @param macAddress
+ * the mac address
+ */
public static void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
- String macAddress) {
- IMdsalApiManager mdsalApiManager = elanServiceProvider.getMdsalManager();
- DataBroker broker = elanServiceProvider.getBroker();
- ItmRpcService itmRpcService = elanServiceProvider.getItmRpcService();
+ String macAddress) {
synchronized (macAddress) {
- logger.info("Acquired lock for mac : " + macAddress + "Proceeding with install operation.");
- setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalApiManager);
- setupTermDmacFlows(interfaceInfo, mdsalApiManager);
- setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalApiManager, broker);
+ logger.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
+ setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalMgr);
+ setupTermDmacFlows(interfaceInfo, mdsalMgr);
+ setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalMgr, dataBroker);
}
}
public static void setupDMacFlowonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
- String macAddress) {
+ String macAddress) {
synchronized (macAddress) {
logger.info("Acquired lock for mac : " + macAddress + "Proceeding with install operation.");
setupOrigDmacFlowsonRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress);
}
+ /**
+ * Inserts a Flow in SMAC table to state that the MAC has already been learnt.
+ *
+ * @param elanInfo
+ * @param interfaceInfo
+ * @param macTimeout
+ * @param macAddress
+ * @param mdsalApiManager
+ */
private static void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
- String macAddress, IMdsalApiManager mdsalApiManager) {
- FlowEntity flowEntity = getKnownSmacFlowEntity(elanInfo, interfaceInfo, macTimeout, macAddress);
+ String macAddress, IMdsalApiManager mdsalApiManager) {
+ FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
mdsalApiManager.installFlow(flowEntity);
if (logger.isDebugEnabled()) {
- logger.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}", elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
+ logger.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
+ elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
}
}
- private static FlowEntity getKnownSmacFlowEntity(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, String macAddress) {
+ public static FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, String macAddress) {
BigInteger dpId = interfaceInfo.getDpId();
int lportTag = interfaceInfo.getInterfaceTag();
long elanTag = elanInfo.getElanTag();
return flowEntity;
}
+ /**
+ * Installs a Flow in INTERNAL_TUNNEL_TABLE of the affected DPN that sends the packet through the specified
+ * interface if the tunnel_id matches the interface's lportTag
+ *
+ * @param interfaceInfo
+ * @param mdsalApiManager
+ */
private static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
BigInteger dpId = interfaceInfo.getDpId();
int lportTag = interfaceInfo.getInterfaceTag();
- Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,lportTag), 5, String.format("%s:%d","ITM Flow Entry ",lportTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)), getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
+ Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
+ String.format("%s:%d","ITM Flow Entry ",lportTag), 0, 0,
+ ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
+ getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
mdsalApiManager.installFlow(dpId, flow);
if (logger.isDebugEnabled()) {
- logger.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId, interfaceInfo.getPortName());
+ logger.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}",
+ dpId, interfaceInfo.getPortName());
}
}
- private static String getFlowRef(short tableId, int elanTag) {
+ /**
+ * Constructs the FlowName for flows installed in the Internal Tunnel Table,
+ * consisting in tableId + elanTag.
+ *
+ * @param tableId
+ * @param elanTag
+ * @return
+ */
+ public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
return new StringBuffer().append(tableId).append(elanTag).toString();
}
- private static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int LportTag) {
+ /**
+ * Constructs the Matches that checks that the tunnel_id field contains a
+ * specific lportTag
+ *
+ * @param lportTag
+ * lportTag that must be checked against the tunnel_id field
+ * @return
+ */
+ public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
// Matching metadata
mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
- BigInteger.valueOf(LportTag)}));
+ BigInteger.valueOf(lportTag)}));
return mkMatches;
-
-
}
- public static List<Instruction> getInstructionsInPortForOutGroup(
- String ifName) {
+ /**
+ * Constructs the Instructions that take the packet over a given interface
+ *
+ * @param ifName
+ * Name of the interface where the packet must be sent over. It can
+ * be a local interface or a tunnel interface (internal or external)
+ * @return
+ */
+ public static List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
List<Instruction> mkInstructions = new ArrayList<Instruction>();
- List <Action> actionsInfos = new ArrayList <Action> ();
- actionsInfos.addAll(ElanUtils.getEgressActionsForInterface(ifName));
- mkInstructions.add(new InstructionBuilder().setInstruction(new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(actionsInfos).build()).build())
- .setKey(new InstructionKey(0)).build());
- return mkInstructions;
- }
-
- public static Instruction getWriteActionInstruction(List<Action> actions) {
- return new InstructionBuilder().setInstruction(new WriteActionsCaseBuilder().setWriteActions(new WriteActionsBuilder().setAction(actions).build()).build()).setKey(new InstructionKey(0)).build();
- }
-
- public static Instruction getApplyActionInstruction(List<Action> actions) {
- return new InstructionBuilder().setInstruction(new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(actions).build()).build()).setKey(new InstructionKey(0)).build();
- }
-
-
- public static List<Action> getEgressActionsForInterface(String ifName) {
+ List<Action> actions = ElanUtils.getEgressActionsForInterface(ifName, /*tunnelKey*/ null );
+
+ mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
+ return mkInstructions;
+ }
+
+
+ /**
+ * Returns the list of Actions to be taken when sending the packet through
+ * an Elan interface. Note that this interface can refer to an ElanInterface
+ * where the Elan VM is attached to a DPN or an ITM tunnel interface where
+ * Elan traffic can be sent through. In this latter case, the tunnelKey is
+ * mandatory and it can hold serviceId for internal tunnels or the VNI for
+ * external tunnels.
+ *
+ * @param ifName
+ * the if name
+ * @param tunnelKey
+ * the tunnel key
+ * @return the egress actions for interface
+ */
+ public static List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
List<Action> listAction = new ArrayList<Action>();
try {
+ GetEgressActionsForInterfaceInput getEgressActionInput =
+ new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(tunnelKey).build();
Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
- elanServiceProvider.getInterfaceManagerRpcService().getEgressActionsForInterface(
- new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
+ interfaceMgrRpcService.getEgressActionsForInterface(getEgressActionInput);
RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
- if(!rpcResult.isSuccessful()) {
- logger.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
+ if (!rpcResult.isSuccessful()) {
+ logger.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
+ ifName, rpcResult.getErrors());
} else {
List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
rpcResult.getResult().getAction();
}
private static void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
- IMdsalApiManager mdsalApiManager, DataBroker broker) {
+ IMdsalApiManager mdsalApiManager, DataBroker broker) {
BigInteger dpId = interfaceInfo.getDpId();
String ifName = interfaceInfo.getInterfaceName();
long ifTag = interfaceInfo.getInterfaceTag();
- long groupId = interfaceInfo.getGroupId();
String elanInstanceName = elanInfo.getElanInstanceName();
- List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
- if(remoteFEs != null) {
- for (DpnInterfaces remoteFE : remoteFEs) {
- Long elanTag = elanInfo.getElanTag();
- if (remoteFE.getDpId().equals(dpId)) {
- // On the local FE set up a direct output flow
+ List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
+ if (elanDpns != null) {
+ Long elanTag = elanInfo.getElanTag();
+ for (DpnInterfaces elanDpn : elanDpns) {
+ if (elanDpn.getDpId().equals(dpId)) {
+ // On the local DPN set up a direct output flow
setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInstanceName, mdsalApiManager, ifTag);
- if (logger.isDebugEnabled()) {
- logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
- }
+ logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
+ elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
} else {
- if (isDpnPresent(remoteFE.getDpId())) {
- // Check for the Remote DPN present in Inventory Manager
- setupRemoteDmacFlow(remoteFE.getDpId(), dpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress, elanInstanceName);
- if (logger.isDebugEnabled()) {
- logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, remoteFE.getDpId());
- }
+ // Check for the Remote DPN present in Inventory Manager
+ if (isDpnPresent(elanDpn.getDpId())) {
+ // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC
+ // need to be forwarded through the appropiated ITM tunnel
+ setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the remote DPN in this case)
+ dpId, // dstDpn (the local DPN)
+ interfaceInfo.getInterfaceTag(), // lportTag of the local interface
+ elanTag, // identifier of the Elan
+ macAddress, // MAC to be programmed in remote DPN
+ elanInstanceName);
+ logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
+ elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId());
}
}
}
+
+ // TODO (eperefr): Make sure that the same is performed against the ElanDevices.
}
}
@SuppressWarnings("unchecked")
public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
+ if (dpns == null) {
+ return EMPTY_LIST;
+ }
return dpns;
}
private static void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
String displayName, IMdsalApiManager mdsalApiManager, long ifTag) {
- Flow flowEntity = getLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, displayName, ifTag);
+ Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, displayName, ifTag);
mdsalApiManager.installFlow(dpId, flowEntity);
}
return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(remoteDpId).append(macAddress).toString();
}
- public static Flow getLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
- String displayName, long ifTag) {
+ private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
+ String dstMacAddress, long elanTag, boolean shFlag) {
+ return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId)
+ .append(extDeviceNodeId).append(dstMacAddress).append(shFlag)
+ .toString();
+ }
+
+ /**
+ * Builds the flow to be programmed in the DMAC table of the local DPN (that is, where the MAC is attached to).
+ * This flow consists in:
+ *
+ * Match:
+ * + elanTag in metadata
+ * + packet goes to a MAC locally attached
+ * Actions:
+ * + optionally, pop-vlan + set-vlan-id
+ * + output to ifName's portNumber
+ *
+ * @param elanTag the elan tag
+ * @param dpId the dp id
+ * @param ifName the if name
+ * @param macAddress the mac address
+ * @param displayName the display name
+ * @param ifTag the if tag
+ * @return the flow
+ */
+ public static Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
+ String displayName, long ifTag) {
List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
- mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
- ElanUtils.getElanMetadataLabel(elanTag),
- MetaDataUtil.METADATA_MASK_SERVICE }));
+ mkMatches.add(new MatchInfo(MatchFieldType.metadata,
+ new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE }));
mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
List<Instruction> mkInstructions = new ArrayList<Instruction>();
- List <Action> actionsInfos = new ArrayList <Action> ();
- actionsInfos.addAll(getEgressActionsForInterface(ifName));
- mkInstructions.add(new InstructionBuilder().setInstruction(new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(actionsInfos).build()).build())
- .setKey(new InstructionKey(0)).build());
- Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag),
- 20, displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+ List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
+ mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
+ Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
+ displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches,
+ mkInstructions);
return flow;
}
public static void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String macAddress,
String displayName) {
- IMdsalApiManager mdsalApiManager = elanServiceProvider.getMdsalManager();
- Flow flowEntity = getRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName);
- mdsalApiManager.installFlow(srcDpId, flowEntity);
- }
-
- public static Flow getRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
- String macAddress, String displayName) {
- ItmRpcService itmRpcService = elanServiceProvider.getItmRpcService();
+ Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName);
+ mdsalMgr.installFlow(srcDpId, flowEntity);
+ }
+
+ /**
+ * Builds a Flow to be programmed in a remote DPN's DMAC table.
+ * This flow consists in:
+ * Match:
+ * + elanTag in packet's metadata
+ * + packet going to a MAC known to be located in another DPN
+ * Actions:
+ * + set_tunnel_id(lportTag)
+ * + output ITM internal tunnel interface with the other DPN
+ *
+ * @param srcDpId
+ * @param destDpId
+ * @param lportTag
+ * @param elanTag
+ * @param macAddress
+ * @param displayName
+ * @return
+ */
+ public static Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
+ String macAddress, String displayName) {
List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
- mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[]{
- ElanUtils.getElanMetadataLabel(elanTag),
- MetaDataUtil.METADATA_MASK_SERVICE }));
+ mkMatches.add(new MatchInfo(MatchFieldType.metadata,
+ new BigInteger[]{ ElanUtils.getElanMetadataLabel(elanTag),
+ MetaDataUtil.METADATA_MASK_SERVICE }));
mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
List<Instruction> mkInstructions = new ArrayList<Instruction>();
- //List of ActionInfo for the provided Source and Destination DPIDs
+ //List of Action for the provided Source and Destination DPIDs
try {
- List<Action> actionsInfos = getItmEgressAction(srcDpId, destDpId, lportTag);
- Instruction instruction = new InstructionBuilder().setInstruction(new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(actionsInfos).build()).build())
- .setKey(new InstructionKey(0)).build();
- mkInstructions.add(instruction);
+ List<Action> actions = getInternalItmEgressAction(srcDpId, destDpId, lportTag);
+ mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
} catch (Exception e) {
logger.error("Interface Not Found exception");
}
- Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag), 20
- , displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+ Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
+ 20, /* prio */
+ displayName, 0, /* idleTimeout */
+ 0, /* hardTimeout */
+ ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
return flow;
String macAddress = macEntry.getMacAddress().getValue();
synchronized (macAddress) {
logger.info("Acquired lock for mac : " + macAddress + "Proceeding with remove operation.");
- deleteMacFlows(elanInfo, interfaceInfo, macAddress, true);
+ deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true);
}
}
public static void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac) {
String elanInstanceName = elanInfo.getElanInstanceName();
- String ifName = interfaceInfo.getInterfaceName();
long ifTag = interfaceInfo.getInterfaceTag();
List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
- IMdsalApiManager mdsalApiManager = elanServiceProvider.getMdsalManager();
- ItmRpcService itmRpcService = elanServiceProvider.getItmRpcService();
BigInteger srcdpId = interfaceInfo.getDpId();
- String displayName = elanInstanceName;
- long groupId = interfaceInfo.getGroupId();
for (DpnInterfaces dpnInterface: remoteFEs) {
Long elanTag = elanInfo.getElanTag();
- if (dpnInterface.getDpId().equals(srcdpId)) {
+ BigInteger dstDpId = dpnInterface.getDpId();
+ if (dstDpId.equals(srcdpId)) {
if(deleteSmac) {
- mdsalApiManager.removeFlow(getKnownSmacFlowEntity(elanInfo, interfaceInfo, 0, macAddress));
+ mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_SMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
}
- mdsalApiManager.removeFlow(dpnInterface.getDpId(), getLocalDmacFlowEntry(elanTag, dpnInterface.getDpId(), ifName, macAddress, displayName, ifTag));
- RemoveTerminatingServiceActionsInput removeTerminatingServiceActionsInput = new RemoveTerminatingServiceActionsInputBuilder().setServiceId(interfaceInfo.getInterfaceTag()).setDpnId(dpnInterface.getDpId()).build();
+ mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
+ RemoveTerminatingServiceActionsInput removeTerminatingServiceActionsInput = new RemoveTerminatingServiceActionsInputBuilder().setServiceId(interfaceInfo.getInterfaceTag()).setDpnId(srcdpId).build();
itmRpcService.removeTerminatingServiceActions(removeTerminatingServiceActionsInput);
- if (logger.isDebugEnabled()) {
- logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpnInterface.getDpId());
+ if (logger.isDebugEnabled()) {
+ logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
}
- } else if (isDpnPresent(dpnInterface.getDpId())) {
- mdsalApiManager.removeFlow(dpnInterface.getDpId(),
- getRemoteDmacFlowEntry(dpnInterface.getDpId(), srcdpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress,
- displayName));
+ } else if (isDpnPresent(dstDpId)) {
+ mdsalMgr.removeFlow(dstDpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)));
if (logger.isDebugEnabled()) {
- logger.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpnInterface.getDpId());
+ logger.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
}
}
}
}
- public static void UpdateOperationalDataStore(DataBroker broker, IdManagerService idManager, ElanInstance elanInstanceAdded) {
+ /**
+ * Updates the Elan information in the Operational DS. It also updates the
+ * ElanInstance in the Config DS by setting the adquired elanTag.
+ *
+ * @param broker
+ * the broker
+ * @param idManager
+ * the id manager
+ * @param elanInstanceAdded
+ * the elan instance added
+ */
+ public static void updateOperationalDataStore(DataBroker broker, IdManagerService idManager,
+ ElanInstance elanInstanceAdded) {
String elanInstanceName = elanInstanceAdded.getElanInstanceName();
- long elanTag = ElanUtils.getUniqueId(idManager, ElanConstants.ELAN_ID_POOL_NAME, elanInstanceName);
+ long elanTag = ElanUtils.retrieveNewElanTag(idManager, elanInstanceName);
Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setKey(new ElanKey(elanInstanceName)).build();
+
//Add the ElanState in the elan-state operational data-store
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanInfo);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
+ ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanInfo);
+
//Add the ElanMacTable in the elan-mac-table operational data-store
MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable);
- ElanTagName elanTagName = new ElanTagNameBuilder().setElanTag(elanTag).setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
+ ElanUtils.getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable);
+
+ ElanTagName elanTagName = new ElanTagNameBuilder().setElanTag(elanTag).setKey(new ElanTagNameKey(elanTag))
+ .setName(elanInstanceName).build();
+
//Add the ElanTag to ElanName in the elan-tag-name Operational data-store
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
- ElanInstance elanInstanceWithTag = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInstanceAdded.getDescription()).setMacTimeout(elanInstanceAdded
- .getMacTimeout() == null ? ElanConstants.DEFAULT_MAC_TIME_OUT : elanInstanceAdded.getMacTimeout()).setKey(elanInstanceAdded.getKey()).setElanTag(elanTag).build();
- MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
+ ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
+
+ // Updates the ElanInstance Config DS by setting the just adquired elanTag
+ ElanInstance elanInstanceWithTag = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
+ .setDescription(elanInstanceAdded.getDescription())
+ .setMacTimeout(elanInstanceAdded.getMacTimeout() == null ? ElanConstants.DEFAULT_MAC_TIME_OUT
+ : elanInstanceAdded.getMacTimeout())
+ .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag).build();
+ MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
+ getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag);
}
public static boolean isDpnPresent(BigInteger dpnId) {
- DataBroker broker = elanServiceProvider.getBroker();
- boolean isPresent = false;
String dpn = String.format("%s:%s", "openflow",dpnId);
NodeId nodeId = new NodeId(dpn);
- InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId)).build();
- Optional<Node> nodePresent = read(broker, LogicalDatastoreType.OPERATIONAL, node);
- if(nodePresent.isPresent()) {
- isPresent = true;
- }
- return isPresent;
+
+ InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId))
+ .build();
+ Optional<Node> nodePresent = read(dataBroker, LogicalDatastoreType.OPERATIONAL, node);
+ return (nodePresent.isPresent());
}
public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) {
}
public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
- InstanceIdentifier<T> path, FutureCallback<Void> callback) {
+ InstanceIdentifier<T> path, FutureCallback<Void> callback) {
WriteTransaction tx = broker.newWriteOnlyTransaction();
tx.delete(datastoreType, path);
Futures.addCallback(tx.submit(), callback);
}
public static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
- InstanceIdentifier<T> path, T data) {
+ InstanceIdentifier<T> path, T data) {
WriteTransaction tx = broker.newWriteOnlyTransaction();
tx.put(datastoreType, path, data, true);
CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
- BigInteger cookie, List<Instruction> instructions) {
+ BigInteger cookie, List<Instruction> instructions) {
StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
.setServiceName(serviceName).setServicePriority(servicePriority)
.child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
}
+ /**
+ * Builds the list of actions to be taken when sending the packet over a
+ * VxLan Tunnel Interface, such as setting the tunnel_id field, the vlanId
+ * if proceeds and output the packet over the right port.
+ *
+ * @param tunnelIfaceName
+ * the tunnel iface name
+ * @param tunnelKey
+ * the tunnel key
+ * @return the list
+ */
+ public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
+ List<Action> result = EMPTY_LIST;
+ if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
+ GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
+ .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
+
+ Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture =
+ interfaceMgrRpcService.getEgressActionsForInterface(getEgressActInput);
+ try {
+ if (egressActionsOutputFuture.get().isSuccessful()) {
+ GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
+ result = egressActionsOutput.getAction();
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ logger.error("Error in RPC call getEgressActionsForInterface {}", e);
+ }
+ }
+
+ if ( result == null || result.size() == 0 ) {
+ logger.warn("Could not build Egress actions for interface {} and tunnelId {}", tunnelIfaceName, tunnelKey);
+ }
+ return result;
+ }
- public static List<Action> getItmEgressAction(BigInteger sourceDpnId,
- BigInteger destinationDpnId, int serviceTag) {
- ItmRpcService itmManager = elanServiceProvider.getItmRpcService();
- OdlInterfaceRpcService interfaceManagerRpcService = elanServiceProvider.getInterfaceManagerRpcService();
- logger.debug("In getItmIngress Action source {}, destination {}, elanTag {}", sourceDpnId, destinationDpnId, serviceTag);
- List<Action> actions = new ArrayList<>();
- String tunnelInterfaceName;
- GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder().setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
- Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmManager.getTunnelInterfaceName(input);
+ /**
+ * Builds the list of actions to be taken when sending the packet over an
+ * external VxLan tunnel interface, such as stamping the VNI on the VxLAN
+ * header, setting the vlanId if it proceeds and output the packet over the
+ * right port.
+ *
+ * @param srcDpnId
+ * Dpn where the tunnelInterface is located
+ * @param torNode
+ * NodeId of the ExternalDevice where the packet must be sent to.
+ * @param vni
+ * Vni to be stamped on the VxLAN Header.
+ * @return the external itm egress action
+ */
+ public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
+ List<Action> result = EMPTY_LIST;
+
+ GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
+ .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).build();
+ Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
+ itmRpcService.getExternalTunnelInterfaceName(input);
try {
- GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
- tunnelInterfaceName = tunnelInterfaceNameOutput.getInterfaceName();
- logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelInterfaceName);
+ if (output.get().isSuccessful()) {
+ GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
+ String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
+ if ( logger.isDebugEnabled() )
+ logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
+
+ result = buildItmEgressActions(tunnelIfaceName, vni);
+ }
+
} catch (InterruptedException | ExecutionException e) {
logger.error("Error in RPC call getTunnelInterfaceName {}", e);
- return actions;
- }
- if (tunnelInterfaceName != null && !tunnelInterfaceName.isEmpty()) {
- try{
- GetEgressActionsForInterfaceInput getEgressActionInput =
- new GetEgressActionsForInterfaceInputBuilder().setIntfName(tunnelInterfaceName).setTunnelKey(null).build();
- Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
- interfaceManagerRpcService.getEgressActionsForInterface(getEgressActionInput);
- RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
- if (!rpcResult.isSuccessful()) {
- logger.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
- tunnelInterfaceName, rpcResult.getErrors());
- } else {
- actions = rpcResult.getResult().getAction();
- }
- } catch (InterruptedException | ExecutionException e) {
- logger.error("Error in RPC call getEgressActionsForInterface {}", e);
- return actions;
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds the list of actions to be taken when sending the packet over an
+ * internal VxLan tunnel interface, such as setting the serviceTag on the
+ * VNI field of the VxLAN header, setting the vlanId if it proceeds and
+ * output the packet over the right port.
+ *
+ * @param sourceDpnId
+ * Dpn where the tunnelInterface is located
+ * @param destinationDpnId
+ * Dpn where the packet must be sent to. It is used here in order
+ * to select the right tunnel interface.
+ * @param serviceTag
+ * serviceId to be sent on the VxLAN header.
+ * @return the internal itm egress action
+ */
+ public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
+ long serviceTag) {
+ List<Action> result = EMPTY_LIST;
+
+ logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
+ sourceDpnId, destinationDpnId, serviceTag);
+
+ GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
+ .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
+ Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
+ try {
+ if (output.get().isSuccessful()) {
+ GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
+ String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
+ logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
+
+ result = buildItmEgressActions(tunnelIfaceName, serviceTag);
}
+ } catch (InterruptedException | ExecutionException e) {
+ logger.error("Error in RPC call getTunnelInterfaceName {}", e);
}
- return actions;
+
+ return result;
}
public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
// Matching metadata
- mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[]{
- BigInteger.valueOf(elanTag)}));
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[]{BigInteger.valueOf(elanTag)}));
return mkMatches;
}
public static void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
- ItmRpcService itmRpcService = elanServiceProvider.getItmRpcService();
RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder().setDpnId(destDpId).setServiceId(serviceId).build();
Future<RpcResult<Void>> futureObject = itmRpcService.removeTerminatingServiceActions(input);
try {
}
public static void createTerminatingServiceActions(BigInteger destDpId, int serviceId, List<Action> actions) {
- ItmRpcService itmRpcService = elanServiceProvider.getItmRpcService();
List<Instruction> mkInstructions = new ArrayList<Instruction>();
- mkInstructions.add(getApplyActionInstruction(actions));
+ mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
CreateTerminatingServiceActionsInput input = new CreateTerminatingServiceActionsInputBuilder().setDpnId(destDpId).setServiceId(serviceId).setInstruction(mkInstructions).build();
itmRpcService.createTerminatingServiceActions(input);
}
- public static TunnelList buildInternalTunnel(DataBroker dataBroker) {
+ public static TunnelList buildInternalTunnel(DataBroker broker) {
InstanceIdentifier<TunnelList> tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class).build();
- Optional<TunnelList> tunnelList = read(dataBroker, LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier);
- if(tunnelList.isPresent()) {
+ Optional<TunnelList> tunnelList = read(broker, LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier);
+ if (tunnelList.isPresent()) {
return tunnelList.get();
}
return null;
}
+
+ /**
+ * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
+ * connected remotely in another CSS and accessible through an internal
+ * tunnel. It also installs the flow for dropping the packet if it came over
+ * an ITM tunnel (that is, if the Split-Horizon flag is set)
+ *
+ * @param localDpId
+ * Id of the DPN where the MAC Addr is accessible locally
+ * @param remoteDpId
+ * Id of the DPN where the flow must be installed
+ * @param lportTag
+ * lportTag of the interface where the mac is connected to.
+ * @param elanTag
+ * Identifier of the ELAN
+ * @param macAddress
+ * MAC to be installed in remoteDpId's DMAC table
+ * @param displayName
+ * the display name
+ */
+ public static void installDmacFlowsToInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
+ long elanTag, String macAddress, String displayName) {
+ Flow flow = buildDmacFlowForInternalRemoteMac(localDpId, remoteDpId, lportTag, elanTag, macAddress, displayName);
+ mdsalMgr.installFlow(remoteDpId, flow);
+ }
+
+ /**
+ * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC
+ * that is connected remotely in an External Device (TOR) and that is
+ * accessible through an external tunnel. It also installs the flow for
+ * dropping the packet if it came over an ITM tunnel (that is, if the
+ * Split-Horizon flag is set)
+ *
+ * @param dpnId
+ * Id of the DPN where the flow must be installed
+ * @param extDeviceNodeId
+ * the ext device node id
+ * @param elanTag
+ * the elan tag
+ * @param vni
+ * the vni
+ * @param macAddress
+ * the mac address
+ * @param displayName
+ * the display name
+ */
+ public static List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMac(BigInteger dpnId,
+ String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName) {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ synchronized (macAddress) {
+ Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName);
+ futures.add(mdsalMgr.installFlow(dpnId, flow));
+
+ Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
+ futures.add(mdsalMgr.installFlow(dpnId, dropFlow));
+ }
+ return futures;
+ }
+
+ public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ ElanUtils.getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG }));
+ mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddr }));
+
+ return mkMatches;
+ }
+
+ /**
+ * Builds a Flow to be programmed in a DPN's DMAC table. This method must be used when the MAC is located in an
+ * External Device (TOR).
+ * The flow matches on the specified MAC and
+ * 1) sends the packet over the CSS-TOR tunnel if SHFlag is not set, or
+ * 2) drops it if SHFlag is set (what means the packet came from an external tunnel)
+ *
+ * @param dpId DPN whose DMAC table is going to be modified
+ * @param extDeviceNodeId Hwvtep node where the mac is attached to
+ * @param elanTag ElanId to which the MAC is being added to
+ * @param vni the vni
+ * @param dstMacAddress The mac address to be programmed
+ * @param displayName the display name
+ * @return the flow
+ */
+ public static Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
+ Long vni, String dstMacAddress, String displayName ) {
+ List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ false, dstMacAddress);
+ List<Instruction> mkInstructions = new ArrayList<Instruction>();
+ try {
+ List<Action> actions = getExternalItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
+ mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
+ } catch (Exception e) {
+ logger.error("Could not get Egress Actions for DpId={} externalNode={}", dpId, extDeviceNodeId );
+ }
+
+ Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag,
+ false),
+ 20, /* prio */
+ displayName, 0, /* idleTimeout */
+ 0, /* hardTimeout */
+ ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+
+ return flow;
+ }
+
+ /**
+ * Builds the flow that drops the packet if it came through an external tunnel, that is, if the Split-Horizon
+ * flag is set.
+ *
+ * @param dpnId DPN whose DMAC table is going to be modified
+ * @param extDeviceNodeId Hwvtep node where the mac is attached to
+ * @param elanTag ElanId to which the MAC is being added to
+ * @param dstMacAddress The mac address to be programmed
+ * @param displayName
+ * @return
+ */
+ private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
+ Long elanTag, String dstMacAddress) {
+ List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ true, dstMacAddress);
+ List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
+ String flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
+ elanTag, true);
+ Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
+ "Drop", 0, /* idleTimeout */
+ 0, /* hardTimeout */
+ ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+
+ return flow;
+ }
+
+ private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) {
+ return new StringBuilder(ElanConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop")
+ .toString();
+ }
+
+ /**
+ * Builds a Flow to be programmed in a remote DPN's DMAC table. This method must be used when the MAC is located
+ * in another CSS.
+ *
+ * This flow consists in:
+ * Match:
+ * + elanTag in packet's metadata
+ * + packet going to a MAC known to be located in another DPN
+ * Actions:
+ * + set_tunnel_id(lportTag)
+ * + output on ITM internal tunnel interface with the other DPN
+ *
+ * @param localDpId the local dp id
+ * @param remoteDpId the remote dp id
+ * @param lportTag the lport tag
+ * @param elanTag the elan tag
+ * @param macAddress the mac address
+ * @param displayName the display name
+ * @return the flow
+ */
+ public static Flow buildDmacFlowForInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
+ long elanTag, String macAddress, String displayName) {
+ List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ false, macAddress);
+
+ List<Instruction> mkInstructions = new ArrayList<Instruction>();
+
+ try {
+ //List of Action for the provided Source and Destination DPIDs
+ List<Action> actions = getInternalItmEgressAction(localDpId, remoteDpId, lportTag);
+ mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
+ } catch (Exception e) {
+ logger.error("Could not get Egress Actions for localDpId={} remoteDpId={} lportTag={}",
+ localDpId, remoteDpId, lportTag);
+ }
+
+ Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
+ getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, localDpId, remoteDpId, macAddress, elanTag),
+ 20, /* prio */
+ displayName, 0, /* idleTimeout */
+ 0, /* hardTimeout */
+ ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+
+ return flow;
+
+ }
+
+ /**
+ * Installs or removes flows in DMAC table for MACs that are/were located in
+ * an external Elan Device.
+ *
+ * @param dpId
+ * Id of the DPN where the DMAC table is going to be modified
+ * @param extNodeId
+ * Id of the External Device where the MAC is located
+ * @param elanTag
+ * Id of the ELAN
+ * @param vni
+ * VNI of the LogicalSwitch to which the MAC belongs to, and that
+ * is associated with the ELAN
+ * @param macAddress
+ * the mac address
+ * @param elanInstanceName
+ * the elan instance name
+ * @param addOrRemove
+ * Indicates if flows must be installed or removed.
+ * @see org.opendaylight.vpnservice.mdsalutil.MDSALUtil.MdsalOp
+ */
+ public static void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni,
+ String macAddress, String elanInstanceName, MdsalOp addOrRemove) {
+ if ( addOrRemove == MdsalOp.CREATION_OP ) {
+ ElanUtils.installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName);
+ } else if ( addOrRemove == MdsalOp.REMOVAL_OP ) {
+ ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress );
+ }
+ }
+
+ /**
+ * Delete dmac flows to external mac.
+ *
+ * @param elanTag
+ * the elan tag
+ * @param dpId
+ * the dp id
+ * @param extDeviceNodeId
+ * the ext device node id
+ * @param macToRemove
+ * the mac to remove
+ */
+ public static List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
+ String extDeviceNodeId, String macToRemove ) {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ synchronized (macToRemove) {
+ // Removing the flows that sends the packet on an external tunnel
+ String flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId,
+ macToRemove, elanTag, false);
+ Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(ElanConstants.ELAN_DMAC_TABLE)
+ .build();
+ futures.add(mdsalMgr.removeFlow(dpId, flowToRemove));
+
+ // And now removing the drop flow
+ flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
+ elanTag, true);
+ flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(ElanConstants.ELAN_DMAC_TABLE)
+ .build();
+ futures.add(mdsalMgr.removeFlow(dpId, flowToRemove));
+ }
+ return futures;
+ }
+
+ /**
+ * Gets the dpid from interface.
+ *
+ * @param interfaceName
+ * the interface name
+ * @return the dpid from interface
+ */
+ public static BigInteger getDpidFromInterface(String interfaceName) {
+ BigInteger dpId = null;
+ Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceMgrRpcService
+ .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
+ try {
+ RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
+ if (rpcResult.isSuccessful()) {
+ dpId = rpcResult.getResult().getDpid();
+ }
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ logger.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e);
+ }
+ return dpId;
+ }
+
}
+
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.elanservice.impl.rev150216;
import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
provider.setInterfaceManager(getOdlinterfaceDependency());
provider.setInterfaceManagerRpcService(rpcregistryDependency.getRpcService(OdlInterfaceRpcService.class));
provider.setItmRpcService(rpcregistryDependency.getRpcService(ItmRpcService.class));
+ provider.setItmManager(getItmmanagerDependency());
provider.setIdManager(idManager);
+ provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
+ provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
/*
-* Generated file
-*
-* Generated from: yang module name: elanservice-impl yang module local name: elanservice-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Dec 04 18:32:00 IST 2015
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.elanservice.impl.rev150216;
public class ElanServiceImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.elanservice.impl.rev150216.AbstractElanServiceImplModuleFactory {
<property name="interfaceManager" ref="interfaceManagerRef" />
</action>
</command>
+ <command>
+ <action class="org.opendaylight.vpnservice.elan.cli.l2gw.L2GwUtilsCacheCli">
+ </action>
+ </command>
</command-bundle>
</blueprint>
\ No newline at end of file
import config { prefix config; revision-date 2013-04-05; }
import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
import opendaylight-sal-binding-broker-impl { prefix md-sal-binding-impl; revision-date 2013-10-28;}
+ import opendaylight-entity-ownership-service { prefix eos; revision-date 2015-08-10;}
import elanmanager-api { prefix elanmgr-api; revision-date 2015-07-07;}
import odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
import odl-interface {prefix odlif; revision-date 2015-03-31;}
}
}
}
+ container entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
+ }
+ }
+ container binding-normalized-node-serializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-normalized-node-serializer;
+ }
+ }
+ }
}
}
}
\ No newline at end of file
public static InstanceIdentifier<RemoteUcastMacs> createRemoteUcastMacsInstanceIdentifier(NodeId nodeId,
String logicalSwitchName,
MacAddress mac) {
- InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
new HwvtepNodeName(logicalSwitchName));
return createInstanceIdentifier(nodeId).augmentation(HwvtepGlobalAugmentation.class)
.child(RemoteUcastMacs.class, new RemoteUcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch), mac));
}
-
+
/**
* Creates the local ucast macs instance identifier.
*
public static InstanceIdentifier<LocalUcastMacs> createLocalUcastMacsInstanceIdentifier(NodeId nodeId,
String logicalSwitchName,
MacAddress mac) {
- InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
new HwvtepNodeName(logicalSwitchName));
return createInstanceIdentifier(nodeId).augmentation(HwvtepGlobalAugmentation.class).child(LocalUcastMacs.class,
new LocalUcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch), mac));
}
+ /**
+ * Creates the remote mcast macs instance identifier.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param mac
+ * the mac
+ * @return the instance identifier
+ */
public static InstanceIdentifier<RemoteMcastMacs> createRemoteMcastMacsInstanceIdentifier(NodeId nodeId,
- String logicalSwitchName,
- MacAddress mac) {
- InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
+ String logicalSwitchName, MacAddress mac) {
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = createLogicalSwitchesInstanceIdentifier(nodeId,
new HwvtepNodeName(logicalSwitchName));
- return createInstanceIdentifier(nodeId).augmentation(HwvtepGlobalAugmentation.class).child(RemoteMcastMacs.class,
- new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch), mac));
+ return createInstanceIdentifier(nodeId).augmentation(HwvtepGlobalAugmentation.class)
+ .child(RemoteMcastMacs.class, new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch), mac));
}
/**
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
transaction.put(LogicalDatastoreType.CONFIGURATION, iid, terminationPoint, true);
}
+ /**
+ * Gets the physical locator.
+ *
+ * @param broker
+ * the broker
+ * @param datastoreType
+ * the datastore type
+ * @param nodeId
+ * the node id
+ * @param phyLocatorIp
+ * the phy locator ip
+ * @return the physical locator
+ */
+ public static HwvtepPhysicalLocatorAugmentation getPhysicalLocator(DataBroker broker,
+ LogicalDatastoreType datastoreType, NodeId nodeId, final IpAddress phyLocatorIp) {
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(phyLocatorIp.getValue()));
+ InstanceIdentifier<HwvtepPhysicalLocatorAugmentation> iid = HwvtepSouthboundUtils
+ .createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug)
+ .augmentation(HwvtepPhysicalLocatorAugmentation.class);
+ Optional<HwvtepPhysicalLocatorAugmentation> optPhyLocator = MDSALUtil.read(broker, datastoreType, iid);
+ if (optPhyLocator.isPresent()) {
+ return optPhyLocator.get();
+ }
+ return null;
+ }
+
/**
* Adds the remote ucast macs into config DS.
*
*/
public static void putRemoteUcastMac(final WriteTransaction transaction, final NodeId nodeId,
RemoteUcastMacs remoteUcastMac) {
- InstanceIdentifier<RemoteUcastMacs> iid = HwvtepSouthboundUtils.createInstanceIdentifier(nodeId).augmentation(HwvtepGlobalAugmentation.class)
- .child(RemoteUcastMacs.class, new RemoteUcastMacsKey(remoteUcastMac.getLogicalSwitchRef(), remoteUcastMac.getMacEntryKey()));
+ InstanceIdentifier<RemoteUcastMacs> iid = HwvtepSouthboundUtils.createInstanceIdentifier(nodeId)
+ .augmentation(HwvtepGlobalAugmentation.class).child(RemoteUcastMacs.class,
+ new RemoteUcastMacsKey(remoteUcastMac.getLogicalSwitchRef(), remoteUcastMac.getMacEntryKey()));
transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteUcastMac, true);
}
* the mac
*/
public static void deleteRemoteUcastMac(final WriteTransaction transaction, final NodeId nodeId,
- String logialSwitchName,
- final MacAddress mac) {
+ String logialSwitchName, final MacAddress mac) {
transaction.delete(LogicalDatastoreType.CONFIGURATION,
HwvtepSouthboundUtils.createRemoteUcastMacsInstanceIdentifier(nodeId, logialSwitchName, mac));
}
transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true);
}
+ /**
+ * Gets the remote mcast mac.
+ *
+ * @param broker
+ * the broker
+ * @param datastoreType
+ * the datastore type
+ * @param nodeId
+ * the node id
+ * @param remoteMcastMacsKey
+ * the remote mcast macs key
+ * @return the remote mcast mac
+ */
+ public static RemoteMcastMacs getRemoteMcastMac(DataBroker broker, LogicalDatastoreType datastoreType,
+ NodeId nodeId, RemoteMcastMacsKey remoteMcastMacsKey) {
+ final InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils
+ .createRemoteMcastMacsInstanceIdentifier(nodeId, remoteMcastMacsKey);
+ Optional<RemoteMcastMacs> optRemoteMcastMac = MDSALUtil.read(broker, datastoreType, iid);
+ if (optRemoteMcastMac.isPresent()) {
+ return optRemoteMcastMac.get();
+ }
+ return null;
+ }
+
/**
* Delete remote mcast mac from config DS.
*
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
/** The ucast local macs. */
List<LocalUcastMacs> ucastLocalMacs = Collections.synchronizedList(new ArrayList<LocalUcastMacs>());
+ /** the status of this device connectin */
+ AtomicBoolean connected = new AtomicBoolean(true);
+
/**
* VTEP device name mentioned with L2 Gateway.
*
ucastLocalMacs.remove(localUcastMacs);
}
+ public boolean isConnected() {
+ return connected.get();
+ }
+
+ public void setConnected(boolean connected) {
+ this.connected.set(connected);
+ }
+
/*
* (non-Javadoc)
*
String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(input);
ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
if (segmentationId != null) {
- //TODO: Uncomment below line while ELAN changes are ported
- //elanInstanceBuilder.setVni(Long.valueOf(segmentationId));
+ elanInstanceBuilder.setVni(Long.valueOf(segmentationId));
}
elanInstanceBuilder.setKey(new ElanInstanceKey(elanInstanceName));
ElanInstance elanInstance = elanInstanceBuilder.build();
}
private void handleNeutronPortCreated(Port port) {
+ if (!NeutronvpnUtils.isPortVnicTypeNormal(port)) {
+ LOG.info("Port {} is not a NORMAL VNIC Type port; OF Port interfaces are not created",
+ port.getUuid().getValue());
+ return;
+ }
LOG.info("Of-port-interface creation");
// Create of-port interface for this neutron port
String portInterfaceName = createOfPortInterface(port);
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
public class NeutronvpnUtils {
private static final Logger logger = LoggerFactory.getLogger(NeutronvpnUtils.class);
+ public static final String VNIC_TYPE_NORMAL = "normal";
protected static Subnetmap getSubnetmap(DataBroker broker, Uuid subnetId) {
InstanceIdentifier id = buildSubnetMapIdentifier(subnetId);
NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
if (providerExtension != null) {
segmentationId = providerExtension.getSegmentationId();
+ if (segmentationId == null) {
+ List<Segments> providerSegments = providerExtension.getSegments();
+ if (providerSegments != null && providerSegments.size() > 0) {
+ for (Segments providerSegment: providerSegments) {
+ if (isNetworkSegmentTypeVxlan(providerSegment)) {
+ segmentationId = providerSegment.getSegmentationId();
+ break;
+ }
+ }
+ }
+ }
}
return segmentationId;
}
return new StringBuilder().append("tap").append(tapId).toString();
}
+ protected static boolean isPortVnicTypeNormal(Port port) {
+ PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
+ if(portBinding == null || portBinding.getVnicType() == null) {
+ // By default, VNIC_TYPE is NORMAL
+ return true;
+ }
+ String vnicType = portBinding.getVnicType().trim().toLowerCase();
+ return vnicType.equals(VNIC_TYPE_NORMAL);
+ }
+
protected static boolean lock(LockManagerService lockManager, String lockName) {
TryLockInput input = new TryLockInputBuilder().setLockName(lockName).setTime(5L).setTimeUnit
(TimeUnits.Milliseconds).build();
return result;
}
+ static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
+ Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
+ return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
+ }
}