}
}
+ rpc monitor-profile-get {
+ input {
+ container profile {
+ uses monitor-profile-params;
+ }
+ }
+ output {
+ leaf profile-id { type uint32; }
+ }
+ }
+
rpc monitor-start {
input {
container config {
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.InterfacesState;
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.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetNodeconnectorIdFromInterfaceInputBuilder;
return new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
}
- protected byte[] getMacAddress(String interfaceName) {
- InstanceIdentifier<NodeConnector> ncId = getNodeConnectorId(interfaceName);
- if(ncId != null) {
- String macAddress = inventoryReader.getMacAddress(ncId);
- if(!Strings.isNullOrEmpty(macAddress)) {
- return AlivenessMonitorUtil.parseMacAddress(macAddress);
- }
+ protected org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperDS(String interfaceName){
+ InstanceIdentifier.InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
+ InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceStateOptional = read(LogicalDatastoreType.OPERATIONAL, id);
+ if(interfaceStateOptional.isPresent()) {
+ return interfaceStateOptional.get();
+ }
+ return null;
+ }
+
+ protected byte[] getMacAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState, String interfaceName) {
+ String macAddress = interfaceState.getPhysAddress().getValue();
+ if(!Strings.isNullOrEmpty(macAddress)) {
+ return AlivenessMonitorUtil.parseMacAddress(macAddress);
}
return null;
}
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStopInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorUnpauseInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitoringMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileGetOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629._interface.monitor.map.InterfaceMonitorEntryKey;
WriteTransaction tx = broker.newWriteOnlyTransaction();
tx.put(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId), monitoringInfo, CREATE_MISSING_PARENT);
+ LOG.debug("adding oper monitoring info {}", monitoringInfo);
tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitoringKey), monitoringState, CREATE_MISSING_PARENT);
+ LOG.debug("adding oper monitoring state {}", monitoringState);
tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorMapId(monitorId), mapEntry, CREATE_MISSING_PARENT);
+ LOG.debug("adding oper map entry {}", mapEntry);
Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
@Override
return result;
}
+
+ @Override
+ public Future<RpcResult<MonitorProfileGetOutput>> monitorProfileGet(MonitorProfileGetInput input){
+ LOG.debug("Monitor Profile Get operation for input profile- {}", input.getProfile());
+ RpcResultBuilder<MonitorProfileGetOutput> rpcResultBuilder;
+ try{
+ final Long profileId = getExistingProfileId(input);
+
+ MonitorProfileGetOutputBuilder output = new MonitorProfileGetOutputBuilder().setProfileId(profileId);
+ rpcResultBuilder = RpcResultBuilder.success();
+ rpcResultBuilder.withResult(output.build());
+ }catch(Exception e){
+ LOG.error("Retrieval of monitor profile ID for input {} failed due to {}" , input, e);
+ rpcResultBuilder = RpcResultBuilder.failed();
+ }
+ return Futures.immediateFuture(rpcResultBuilder.build());
+ }
+
+ private Long getExistingProfileId(MonitorProfileGetInput input){
+ org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.Profile profile = input.getProfile();
+ final Long failureThreshold = profile.getFailureThreshold();
+ final Long monitorInterval = profile.getMonitorInterval();
+ final Long monitorWindow = profile.getMonitorWindow();
+ final EtherTypes ethType = profile.getProtocolType();
+ LOG.debug("getExistingProfileId for profile : {}", input.getProfile());
+ String idKey = getUniqueProfileKey(failureThreshold, monitorInterval, monitorWindow, ethType);
+ LOG.debug("Obtained existing profile ID for profile : {}", input.getProfile());
+ return (Long.valueOf(getUniqueId(idKey)));
+ }
+
private String getUniqueProfileKey(Long failureThreshold,Long monitorInterval,Long monitorWindow,EtherTypes ethType) {
return new StringBuilder().append(failureThreshold).append(AlivenessMonitorConstants.SEPERATOR)
.append(monitorInterval).append(AlivenessMonitorConstants.SEPERATOR)
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
import org.opendaylight.controller.liblldp.LLDPTLV.TLVType;
import org.opendaylight.controller.liblldp.Packet;
import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.vpnservice.interfacemgr.globals.IfmConstants;
import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
import org.opendaylight.vpnservice.mdsalutil.ActionType;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
}
//Get Mac Address for the source interface
- byte[] sourceMac = getMacAddress(sourceInterface);
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = getInterfaceFromOperDS(sourceInterface);
+ byte[] sourceMac = getMacAddress(interfaceState, sourceInterface);
if(sourceMac == null) {
LOG.error("Could not read mac address for the source interface {} from the Inventory. "
+ "LLDP packet cannot be send.", sourceInterface);
long nodeId = -1, portNum = -1;
try {
- GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(sourceInterface).build();
- Future<RpcResult<GetPortFromInterfaceOutput>> portOutput = interfaceService.getPortFromInterface(input);
- RpcResult<GetPortFromInterfaceOutput> result = portOutput.get();
- if(result.isSuccessful()) {
- GetPortFromInterfaceOutput output = result.getResult();
- nodeId = output.getDpid().longValue();
- portNum = output.getPortno();
- } else {
- LOG.error("Could not retrieve port details for interface {}", sourceInterface);
- return;
- }
- }catch(InterruptedException | ExecutionException e) {
- LOG.error("Failed to retrieve interface service RPC Result ", e);
+ String lowerLayerIf = interfaceState.getLowerLayerIf().get(0);
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
+ nodeId = Long.valueOf(getDpnFromNodeConnectorId(nodeConnectorId));
+ portNum = Long.valueOf(getPortNoFromNodeConnectorId(nodeConnectorId));
+ }catch(Exception e) {
+ LOG.error("Failed to retrieve node id and port number ", e);
return;
}
Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface);
try {
- List<ActionInfo> actions = getInterfaceActions(sourceInterface, portNum);
+ List<ActionInfo> actions = getInterfaceActions(interfaceState, portNum);
if(actions.isEmpty()) {
LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
return;
}
}
- private List<ActionInfo> getInterfaceActions(String interfaceName, long portNum) throws InterruptedException, ExecutionException {
+ public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
+ /*
+ * NodeConnectorId is of form 'openflow:dpnid:portnum'
+ */
+ String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
+ return split[1];
+ }
+
+ public static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
+ /*
+ * NodeConnectorId is of form 'openflow:dpnid:portnum'
+ */
+ String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
+ return split[2];
+ }
+ private List<ActionInfo> getInterfaceActions(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState,long portNum) throws InterruptedException, ExecutionException {
Class<? extends InterfaceType> intfType;
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface interfaceInfo =
- getInterfaceFromConfigDS(interfaceName);
- if(interfaceInfo != null) {
- intfType = interfaceInfo.getType();
+ if(interfaceState != null) {
+ intfType = interfaceState.getType();
} else {
- LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceName);
+ LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceState.getName());
return Collections.emptyList();
}
return result;
}
+ public static String byteArrayToString(byte[] bytes) {
+ StringBuilder str = new StringBuilder();
+ for (byte b : bytes) {
+ str.append(Integer.toHexString((b >>> 4) & 0x0F));
+ str.append(Integer.toHexString(b & 0x0F));
+ str.append(":");
+ }
+ str.deleteCharAt(str.lastIndexOf(":"));
+ return str.toString();
+ }
}
--- /dev/null
+module vpnservice-dhcp {
+ namespace "urn:opendaylight:vpnservice:dhcp";
+ prefix "dhcp";
+
+ import ietf-inet-types {
+ prefix inet;
+ revision-date "2010-09-24";
+ }
+
+ revision "2016-04-28" {
+ description "It provides required datastore containers to handle DHCP requests
+ coming from access or external tunnel ports";
+ }
+
+ container designated-switches-for-external-tunnels {
+ config true;
+ description "contains designated dataplane-node-identifier which handles DHCP requests for each external tunnel";
+ list designated-switch-for-tunnel {
+ key "tunnel-remote-ip-address elan-instance-name";
+ leaf tunnel-remote-ip-address {
+ description "remote end point ip address of external tunnel";
+ type inet:ip-address;
+ }
+ leaf elan-instance-name {
+ description "elan name indicates l2 network domain";
+ type string;
+ }
+ leaf dpId {
+ description "contains dataplane-node-identifier";
+ type int64;
+ }
+ }
+ }
+}
\ No newline at end of file
<artifactId>interfacemgr-api</artifactId>
<version>${vpnservices.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>elanmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>itm-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>hwvtepsouthbound-api</artifactId>
+ <version>${vpns.ovsdb.version}</version>
+ </dependency>
</dependencies>
</project>
<capability>urn:opendaylight:params:xml:ns:yang:dhcpservice:impl?module=dhcpservice-impl&revision=2015-07-10</capability>
<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: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:params:xml:ns:yang:neutronvpn:api?module=neutronvpn-api&revision=2015-08-12</capability>
</required-capabilities>
<configuration>
<type xmlns:neutronvpn="urn:opendaylight:params:xml:ns:yang:neutronvpn:api">neutronvpn:neutronvpn-api</type>
<name>neutronvpn</name>
</neutronvpn>
+ <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>
</module>
</modules>
</data>
package org.opendaylight.vpnservice.dhcpservice;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
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.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
--- /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.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerBase<DesignatedSwitchForTunnel, DhcpDesignatedDpnListener> implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DhcpDesignatedDpnListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private DataBroker broker;
+
+ public DhcpDesignatedDpnListener(final DhcpExternalTunnelManager dhcpExternalTunnelManager, final DataBroker broker) {
+ super(DesignatedSwitchForTunnel.class, DhcpDesignatedDpnListener.class);
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+ this.broker = broker;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DhcpDesignatedDpnListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.debug("DhcpDesignatedDpnListener Listener Closed");
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel del) {
+ dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(del.getDpId()), del.getTunnelRemoteIpAddress(), del.getElanInstanceName());
+ dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(del.getElanInstanceName(), del.getTunnelRemoteIpAddress(), DhcpServiceUtils.getListOfDpns(broker));
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel original,
+ DesignatedSwitchForTunnel update) {
+ BigInteger designatedDpnId = BigInteger.valueOf(update.getDpId());
+ IpAddress tunnelRemoteIpAddress = update.getTunnelRemoteIpAddress();
+ String elanInstanceName = update.getElanInstanceName();
+ dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
+ dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+ if (elanDpns == null || elanDpns.isEmpty()) {
+ dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel add) {
+ BigInteger designatedDpnId = BigInteger.valueOf(add.getDpId());
+ IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress();
+ String elanInstanceName = add.getElanInstanceName();
+ dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+ if (elanDpns == null || elanDpns.isEmpty()) {
+ dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ }
+ }
+
+ @Override
+ protected InstanceIdentifier<DesignatedSwitchForTunnel> getWildCardPath() {
+ return InstanceIdentifier.create(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return DhcpDesignatedDpnListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.SUBTREE;
+ }
+}
--- /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.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+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.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+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.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+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.Uuid;
+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.rev150712.Neutron;
+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.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.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.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+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.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class DhcpExternalTunnelManager {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpExternalTunnelManager.class);
+ public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+ private static final FutureCallback<Void> DEFAULT_CALLBACK =
+ new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ logger.debug("Success in Datastore write operation");
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Error in Datastore write operation", error);
+ };
+ };
+ private final DataBroker broker;
+ private IMdsalApiManager mdsalUtil;
+
+ private ConcurrentMap<BigInteger, List<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache = new ConcurrentHashMap<BigInteger, List<Pair<IpAddress, String>>>();
+ private ConcurrentMap<Pair<IpAddress, String>, Set<String>> tunnelIpElanNameToVmMacCache = new ConcurrentHashMap<Pair<IpAddress, String>, Set<String>>();
+ private ConcurrentMap<Pair<BigInteger, String>, Port> vniMacAddressToPortCache = new ConcurrentHashMap<Pair<BigInteger, String>, Port>();
+ private ItmRpcService itmRpcService;
+ private EntityOwnershipService entityOwnershipService;
+
+ public DhcpExternalTunnelManager(DataBroker broker, IMdsalApiManager mdsalUtil, ItmRpcService itmRpcService, EntityOwnershipService entityOwnershipService) {
+ this.broker = broker;
+ this.mdsalUtil = mdsalUtil;
+ this.itmRpcService = itmRpcService;
+ this.entityOwnershipService = entityOwnershipService;
+ initilizeCaches();
+ }
+
+ private void initilizeCaches() {
+ logger.trace("Loading designatedDpnsToTunnelIpElanNameCache");
+ InstanceIdentifier<DesignatedSwitchesForExternalTunnels> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).build();
+ Optional<DesignatedSwitchesForExternalTunnels> designatedSwitchForTunnelOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+ if (designatedSwitchForTunnelOptional.isPresent()) {
+ List<DesignatedSwitchForTunnel> list = designatedSwitchForTunnelOptional.get().getDesignatedSwitchForTunnel();
+ for (DesignatedSwitchForTunnel designatedSwitchForTunnel : list) {
+ List<Pair<IpAddress, String>> listOfTunnelIpElanNamePair = designatedDpnsToTunnelIpElanNameCache.get(designatedSwitchForTunnel.getDpId());
+ if (listOfTunnelIpElanNamePair == null) {
+ listOfTunnelIpElanNamePair = new LinkedList<Pair<IpAddress, String>>();
+ }
+ Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(designatedSwitchForTunnel.getTunnelRemoteIpAddress(), designatedSwitchForTunnel.getElanInstanceName());
+ listOfTunnelIpElanNamePair.add(tunnelIpElanNamePair);
+ designatedDpnsToTunnelIpElanNameCache.put(BigInteger.valueOf(designatedSwitchForTunnel.getDpId()), listOfTunnelIpElanNamePair);
+ }
+ }
+ logger.trace("Loading vniMacAddressToPortCache");
+ InstanceIdentifier<Ports> inst = InstanceIdentifier.builder(Neutron.class).child(Ports.class).build();
+ Optional<Ports> optionalPorts = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (optionalPorts.isPresent()) {
+ List<Port> list = optionalPorts.get().getPort();
+ for (Port port : list) {
+ if(NeutronUtils.isPortVnicTypeNormal(port)) {
+ continue;
+ }
+ String macAddress = port.getMacAddress();
+ Uuid networkId = port.getNetworkId();
+ String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+ if (segmentationId == null) {
+ return;
+ }
+ updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
+ }
+ }
+
+ }
+
+
+ public BigInteger designateDpnId(IpAddress tunnelIp,
+ String elanInstanceName, List<BigInteger> dpns) {
+ BigInteger designatedDpnId = readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+ if (designatedDpnId != null && !designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ logger.trace("Dpn {} already designated for tunnelIp - elan : {} - {}", designatedDpnId, tunnelIp, elanInstanceName);
+ return designatedDpnId;
+ }
+ return chooseDpn(tunnelIp, elanInstanceName, dpns);
+ }
+
+ public void installDhcpFlowsForVms(IpAddress tunnelIp, String elanInstanceName, List<BigInteger> dpns,
+ BigInteger designatedDpnId, String vmMacAddress) {
+ installDhcpEntries(designatedDpnId, vmMacAddress, entityOwnershipService);
+ dpns.remove(designatedDpnId);
+ for (BigInteger dpn : dpns) {
+ installDhcpDropAction(dpn, vmMacAddress, entityOwnershipService);
+ }
+ updateLocalCache(tunnelIp, elanInstanceName, vmMacAddress);
+ }
+
+ public void installDhcpFlowsForVms(IpAddress tunnelIp,
+ String elanInstanceName, BigInteger designatedDpnId, Set<String> listVmMacAddress) {
+ for (String vmMacAddress : listVmMacAddress) {
+ installDhcpEntries(designatedDpnId, vmMacAddress);
+ }
+ }
+
+ public void unInstallDhcpFlowsForVms(String elanInstanceName, List<BigInteger> dpns, String vmMacAddress) {
+ for (BigInteger dpn : dpns) {
+ unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+ }
+ removeFromLocalCache(elanInstanceName, vmMacAddress);
+ }
+
+ public BigInteger readDesignatedSwitchesForExternalTunnel(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 BigInteger.valueOf(designatedSwitchForTunnelOptional.get().getDpId());
+ }
+ return null;
+ }
+
+ public void writeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+ DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+ InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+ DesignatedSwitchForTunnel designatedSwitchForTunnel = new DesignatedSwitchForTunnelBuilder().setDpId(dpnId.longValue()).setElanInstanceName(elanInstanceName).setTunnelRemoteIpAddress(tunnelIp).setKey(designatedSwitchForTunnelKey).build();
+ logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+ MDSALDataStoreUtils.asyncUpdate(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, designatedSwitchForTunnel, DEFAULT_CALLBACK);
+ }
+
+ public void removeDesignatedSwitchForExternalTunnel(BigInteger dpnId, IpAddress tunnelIp, String elanInstanceName) {
+ DesignatedSwitchForTunnelKey designatedSwitchForTunnelKey = new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp);
+ InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier.builder(DesignatedSwitchesForExternalTunnels.class).child(DesignatedSwitchForTunnel.class, designatedSwitchForTunnelKey).build();
+ logger.trace("Writing into CONFIG DS tunnelIp {}, elanInstanceName {}, dpnId {}", tunnelIp, elanInstanceName, dpnId);
+ MDSALDataStoreUtils.asyncRemove(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier, DEFAULT_CALLBACK);
+ }
+
+ public void installDhcpDropActionOnDpn(BigInteger dpId) {
+ List<String> vmMacs = getAllVmMacs();
+ logger.trace("Installing drop actions to this new DPN {} VMs {}", dpId, vmMacs);
+ for (String vmMacAddress : vmMacs) {
+ installDhcpDropAction(dpId, vmMacAddress);
+ }
+ }
+
+ private List<String> getAllVmMacs() {
+ List<String> vmMacs = new LinkedList<String>();
+ Collection<Set<String>> listOfVmMacs = tunnelIpElanNameToVmMacCache.values();
+ for (Set<String> list : listOfVmMacs) {
+ vmMacs.addAll(list);
+ }
+ return vmMacs;
+ }
+
+ public void updateLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+ Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+ List<Pair<IpAddress, String>> tunnelIpElanNameList;
+ tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+ if (tunnelIpElanNameList == null) {
+ tunnelIpElanNameList = new LinkedList<Pair<IpAddress, String>>();
+ }
+ tunnelIpElanNameList.add(tunnelIpElanName);
+ designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+ }
+
+ private void updateLocalCache(IpAddress tunnelIp, String elanInstanceName, String vmMacAddress) {
+ Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+ Set<String> listExistingVmMacAddress;
+ listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanName);
+ if (listExistingVmMacAddress == null) {
+ listExistingVmMacAddress = new HashSet<String>();
+ }
+ listExistingVmMacAddress.add(vmMacAddress);
+ tunnelIpElanNameToVmMacCache.put(tunnelIpElanName, listExistingVmMacAddress);
+ }
+
+ public void handleDesignatedDpnDown(BigInteger dpnId, List<BigInteger> listOfDpns) {
+ logger.trace("In handleDesignatedDpnDown dpnId {}, listOfDpns {}", dpnId, listOfDpns);
+ try {
+ List<Pair<IpAddress, String>> listOfTunnelIpElanNamePairs = designatedDpnsToTunnelIpElanNameCache.get(dpnId);
+ if (!dpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ List<String> listOfVms = getAllVmMacs();
+ for (String vmMacAddress : listOfVms) {
+ unInstallDhcpEntries(dpnId, vmMacAddress);
+ }
+ }
+ if (listOfTunnelIpElanNamePairs == null || listOfTunnelIpElanNamePairs.isEmpty()) {
+ logger.trace("No tunnelIpElanName to handle for dpn {}. Returning", dpnId);
+ return;
+ }
+ for (Pair<IpAddress, String> pair : listOfTunnelIpElanNamePairs) {
+ updateCacheAndInstallNewFlows(dpnId, listOfDpns, pair);
+ }
+ } catch (Exception e) {
+ logger.error("Error in handleDesignatedDpnDown {}", e);
+ }
+ }
+
+ public void updateCacheAndInstallNewFlows(BigInteger dpnId,
+ List<BigInteger> listOfDpns, Pair<IpAddress, String> pair)
+ throws ExecutionException {
+ BigInteger newDesignatedDpn = chooseDpn(pair.getLeft(), pair.getRight(), listOfDpns);
+ if (newDesignatedDpn.equals(DHCPMConstants.INVALID_DPID)) {
+ return;
+ }
+ Set<String> listVmMacs = tunnelIpElanNameToVmMacCache.get(pair);
+ if (listVmMacs != null && !listVmMacs.isEmpty()) {
+ installDhcpFlowsForVms(pair.getLeft(), pair.getRight(), newDesignatedDpn, listVmMacs);
+ }
+ }
+
+ private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId) {
+ try {
+ Set<String> listVmMacAddress = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+ if (listVmMacAddress == null || listVmMacAddress.isEmpty()) {
+ return;
+ }
+ for (String vmMacAddress : listVmMacAddress) {
+ installDhcpDropAction(dpnId, vmMacAddress);
+ }
+ } catch (Exception e) {
+ logger.error("Error in uninstallExistingFlows {}", e);
+ }
+ }
+
+ /**
+ * Choose a dpn among the list of elanDpns such that it has lowest count of being the designated dpn.
+ * @param tunnelIp
+ * @param elanInstanceName
+ * @param dpns
+ * @return
+ */
+ private BigInteger chooseDpn(IpAddress tunnelIp, String elanInstanceName,
+ List<BigInteger> dpns) {
+ BigInteger designatedDpnId = DHCPMConstants.INVALID_DPID;
+ if (dpns != null && dpns.size() != 0) {
+ List<BigInteger> candidateDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+ candidateDpns.retainAll(dpns);
+ logger.trace("Choosing new dpn for tunnelIp {}, elanInstanceName {}, among elanDpns {}", tunnelIp, elanInstanceName, candidateDpns);
+ boolean elanDpnAvailableFlag = true;
+ if (candidateDpns == null || candidateDpns.isEmpty()) {
+ candidateDpns = dpns;
+ elanDpnAvailableFlag = false;
+ }
+ int size = 0;
+ L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+ if (device == null) {
+ logger.trace("Could not find any device for elanInstanceName {} and tunnelIp {}", elanInstanceName, tunnelIp);
+ handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+ return designatedDpnId;
+ }
+ for (BigInteger dpn : candidateDpns) {
+ String hwvtepNodeId = device.getHwvtepNodeId();
+ if (!elanDpnAvailableFlag) {
+ if (!isTunnelConfigured(dpn, hwvtepNodeId)) {
+ logger.trace("Tunnel is not configured on dpn {} to TOR {}", dpn, hwvtepNodeId);
+ continue;
+ }
+ } else if (!isTunnelUp(hwvtepNodeId, dpn)) {
+ logger.trace("Tunnel is not up between dpn {} and TOR {}", dpn, hwvtepNodeId);
+ continue;
+ }
+ List<Pair<IpAddress, String>> tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(dpn);
+ if (tunnelIpElanNameList == null) {
+ designatedDpnId = dpn;
+ break;
+ }
+ if (size == 0 || tunnelIpElanNameList.size() < size) {
+ size = tunnelIpElanNameList.size();
+ designatedDpnId = dpn;
+ }
+ }
+ writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+ return designatedDpnId;
+ }
+ handleUnableToDesignateDpn(tunnelIp, elanInstanceName);
+ return designatedDpnId;
+ }
+
+ private void handleUnableToDesignateDpn(IpAddress tunnelIp, String elanInstanceName) {
+ writeDesignatedSwitchForExternalTunnel(DHCPMConstants.INVALID_DPID, tunnelIp, elanInstanceName);
+ }
+
+ public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+ DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+ }
+
+ public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+ final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ installDhcpEntries(dpnId, vmMacAddress);
+ } else {
+ logger.trace("Exiting installDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Error while fetching checkNodeEntityOwner", error);
+ }
+ });
+ }
+
+ public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress) {
+ DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
+ }
+
+ public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+ final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ unInstallDhcpEntries(dpnId, vmMacAddress);
+ } else {
+ logger.trace("Exiting unInstallDhcpEntries since this cluster node is not the owner for dpn {}", nodeId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Error while fetching checkNodeEntityOwner", error);
+ }
+ });
+ }
+
+ public void installDhcpDropAction(BigInteger dpn, String vmMacAddress) {
+ DhcpServiceUtils.setupDhcpDropAction(dpn, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
+ }
+
+ public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
+ final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ installDhcpDropAction(dpnId, vmMacAddress);
+ } else {
+ logger.trace("Exiting installDhcpDropAction since this cluster node is not the owner for dpn {}", nodeId);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Error while fetching checkNodeEntityOwner", error);
+ }
+ });
+ }
+
+ public void handleTunnelStateDown(IpAddress tunnelIp, BigInteger interfaceDpn) {
+ logger.trace("In handleTunnelStateDown tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+ if (interfaceDpn == null) {
+ return;
+ }
+ try {
+ List<Pair<IpAddress, String>> tunnelElanPairList = designatedDpnsToTunnelIpElanNameCache.get(interfaceDpn);
+ if (tunnelElanPairList == null || tunnelElanPairList.isEmpty()) {
+ return;
+ }
+ for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairList) {
+ IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
+ if (tunnelIpInDpn.equals(tunnelIp)) {
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+ dpns.remove(interfaceDpn);
+ changeExistingFlowToDrop(tunnelElanPair, interfaceDpn);
+ updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Error in handleTunnelStateDown {}", e.getMessage());
+ logger.trace("Exception details {}", e);
+ }
+ }
+
+ private void removeFromLocalCache(String elanInstanceName, String vmMacAddress) {
+ Set<Pair<IpAddress, String>> tunnelIpElanNameKeySet = tunnelIpElanNameToVmMacCache.keySet();
+ for (Pair<IpAddress, String> pair : tunnelIpElanNameKeySet) {
+ if (pair.getRight().trim().equalsIgnoreCase(elanInstanceName.trim())) {
+ Set<String> listExistingVmMacAddress;
+ listExistingVmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
+ if (listExistingVmMacAddress == null || listExistingVmMacAddress.isEmpty()) {
+ continue;
+ }
+ listExistingVmMacAddress.remove(vmMacAddress);
+ if (listExistingVmMacAddress.size() > 0) {
+ tunnelIpElanNameToVmMacCache.put(pair, listExistingVmMacAddress);
+ return;
+ }
+ tunnelIpElanNameToVmMacCache.remove(pair);
+ }
+ }
+ }
+
+ public void removeFromLocalCache(BigInteger designatedDpnId, IpAddress tunnelIp, String elanInstanceName) {
+ Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+ List<Pair<IpAddress, String>> tunnelIpElanNameList;
+ tunnelIpElanNameList = designatedDpnsToTunnelIpElanNameCache.get(designatedDpnId);
+ if (tunnelIpElanNameList != null) {
+ tunnelIpElanNameList.remove(tunnelIpElanName);
+ if (tunnelIpElanNameList.size() != 0) {
+ designatedDpnsToTunnelIpElanNameCache.put(designatedDpnId, tunnelIpElanNameList);
+ } else {
+ designatedDpnsToTunnelIpElanNameCache.remove(designatedDpnId);
+ }
+ }
+ }
+
+ public void updateVniMacToPortCache(BigInteger vni, String macAddress, Port port) {
+ if (macAddress == null) {
+ return;
+ }
+ Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+ logger.trace("Updating vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, port);
+ vniMacAddressToPortCache.put(vniMacAddressPair, port);
+ }
+
+ public void removeVniMacToPortCache(BigInteger vni, String macAddress) {
+ if (macAddress == null) {
+ return;
+ }
+ Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+ vniMacAddressToPortCache.remove(vniMacAddressPair);
+ }
+
+ public Port readVniMacToPortCache(BigInteger vni, String macAddress) {
+ if (macAddress == null) {
+ return null;
+ }
+ Pair<BigInteger, String> vniMacAddressPair = new ImmutablePair<BigInteger, String>(vni, macAddress.toUpperCase());
+ logger.trace("Reading vniMacAddressToPortCache with vni {} , mac {} , pair {} and port {}", vni, macAddress.toUpperCase(), vniMacAddressPair, vniMacAddressToPortCache.get(vniMacAddressPair));
+ return vniMacAddressToPortCache.get(vniMacAddressPair);
+ }
+
+ public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+ String tunnelInterfaceName = null;
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+ try {
+ Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
+ .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
+ .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
+
+ RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
+ if (rpcResult.isSuccessful()) {
+ tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
+ logger.debug("Tunnel interface name: {}", tunnelInterfaceName);
+ } else {
+ logger.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}",
+ rpcResult.getErrors());
+ }
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ logger.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}: {} ",
+ sourceNode, dstNode, e);
+ }
+ return tunnelInterfaceName;
+ }
+
+ public static Optional<Node> getNode(DataBroker dataBroker, String physicalSwitchNodeId) {
+ InstanceIdentifier<Node> psNodeId = HwvtepSouthboundUtils
+ .createInstanceIdentifier(new NodeId(physicalSwitchNodeId));
+ Optional<Node> physicalSwitchOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, psNodeId, dataBroker);
+ return physicalSwitchOptional;
+ }
+
+ public RemoteMcastMacs createRemoteMcastMac(Node dstDevice, String logicalSwitchName, IpAddress internalTunnelIp) {
+ List<LocatorSet> locators = new ArrayList<>();
+ for (TerminationPoint tp : dstDevice.getTerminationPoint()) {
+ HwvtepPhysicalLocatorAugmentation aug = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
+ if (internalTunnelIp.getIpv4Address().equals(aug.getDstIp().getIpv4Address())) {
+ HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+ HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(dstDevice.getNodeId(), aug));
+ locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
+ }
+ }
+ HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(dstDevice.getNodeId(), new HwvtepNodeName(logicalSwitchName)));
+
+ RemoteMcastMacs remoteUcastMacs = new RemoteMcastMacsBuilder()
+ .setMacEntryKey(new MacAddress(UNKNOWN_DMAC))
+ .setLogicalSwitchRef(lsRef).setLocatorSet(locators).build();
+ return remoteUcastMacs;
+ }
+
+ private WriteTransaction putRemoteMcastMac(WriteTransaction transaction, String elanName, L2GatewayDevice device, IpAddress internalTunnelIp) {
+ Optional<Node> optionalNode = getNode(broker, device.getHwvtepNodeId());
+ Node dstNode = optionalNode.get();
+ if (dstNode == null) {
+ logger.debug("could not get device node {} ", device.getHwvtepNodeId());
+ return null;
+ }
+ RemoteMcastMacs macs = createRemoteMcastMac(dstNode, elanName, internalTunnelIp);
+ HwvtepUtils.putRemoteMcastMac(transaction, dstNode.getNodeId(), macs);
+ return transaction;
+ }
+
+ public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp, final String elanInstanceName) {
+ if (designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ return;
+ }
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ logger.info("Installing remote McastMac");
+ L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
+ IpAddress internalTunnelIp = null;
+ if (tunnelInterfaceName != null) {
+ Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+ if (tunnelInterface == null) {
+ logger.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
+ return;
+ }
+ internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
+ if (transaction != null) {
+ transaction.submit();
+ }
+ }
+ } else {
+ logger.info("Installing remote McastMac is not executed for this node.");
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to install remote McastMac", error);
+ }
+ });
+ }
+
+ private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
+ ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+ for (L2GatewayDevice device : devices.values()) {
+ if (device.getTunnelIp().equals(tunnelIp)) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ private boolean isTunnelUp(String nodeName, BigInteger dpn) {
+ boolean isTunnelUp = false;
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), nodeName);
+ if (tunnelInterfaceName == null) {
+ logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+ return isTunnelUp;
+ }
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromOperationalDS(tunnelInterfaceName, broker);
+ if (tunnelInterface == null) {
+ logger.debug("Interface {} is not present in interface state", tunnelInterfaceName);
+ return isTunnelUp;
+ }
+ isTunnelUp = (tunnelInterface.getOperStatus() == OperStatus.Up) ? true :false;
+ return isTunnelUp;
+ }
+
+ public void handleTunnelStateUp(IpAddress tunnelIp, BigInteger interfaceDpn) {
+ logger.trace("In handleTunnelStateUp tunnelIp {}, interfaceDpn {}", tunnelIp, interfaceDpn);
+ try {
+ List<Pair<IpAddress, String>> tunnelIpElanPair = designatedDpnsToTunnelIpElanNameCache.get(DHCPMConstants.INVALID_DPID);
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
+ if (tunnelIpElanPair == null || tunnelIpElanPair.isEmpty()) {
+ return;
+ }
+ for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
+ if (tunnelIp.equals(pair.getLeft())) {
+ designateDpnId(tunnelIp, pair.getRight(), dpns);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Error in handleTunnelStateUp {}", e.getMessage());
+ logger.trace("Exception details {}", e);
+ }
+ }
+
+ private boolean isTunnelConfigured(BigInteger dpn, String hwVtepNodeId) {
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpn), hwVtepNodeId);
+ if (tunnelInterfaceName == null) {
+ return false;
+ }
+ Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+ if (tunnelInterface == null) {
+ logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
+ return false;
+ }
+ return true;
+ }
+
+ public void unInstallDhcpFlowsForVms(String elanInstanceName, IpAddress tunnelIp, List<BigInteger> dpns) {
+ Pair<IpAddress, String> tunnelIpElanNamePair = new ImmutablePair<IpAddress, String>(tunnelIp, elanInstanceName);
+ Set<String> vmMacs = tunnelIpElanNameToVmMacCache.get(tunnelIpElanNamePair);
+ logger.trace("In unInstallFlowsForVms elanInstanceName {}, tunnelIp {}, dpns {}, vmMacs {}", elanInstanceName, tunnelIp, dpns, vmMacs);
+ if (vmMacs == null) {
+ return;
+ }
+ for (String vmMacAddress : vmMacs) {
+ for (BigInteger dpn : dpns) {
+ unInstallDhcpEntries(dpn, vmMacAddress, entityOwnershipService);
+ }
+ }
+ tunnelIpElanNameToVmMacCache.remove(tunnelIpElanNamePair);
+ }
+}
--- /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.dhcpservice;
+
+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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpInterfaceConfigListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceConfigListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private DataBroker dataBroker;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+ public DhcpInterfaceConfigListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+ super(Interface.class);
+ this.dataBroker = dataBroker;
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+ registerListener();
+ }
+
+ private void registerListener() {
+ try {
+ listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), DhcpInterfaceConfigListener.this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
+ throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ logger.info("DhcpInterfaceConfigListener Closed");
+ }
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+ IfTunnel tunnelInterface = del.getAugmentation(IfTunnel.class);
+ if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+ IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+ ParentRefs interfce = del.getAugmentation(ParentRefs.class);
+ if (interfce != null) {
+ dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, interfce.getDatapathNodeIdentifier());
+ }
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+ // Handled in update () DhcpInterfaceEventListener
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
+ // Handled in add() DhcpInterfaceEventListener
+ }
+}
\ No newline at end of file
import java.math.BigInteger;
import java.util.List;
+import org.apache.commons.lang3.tuple.ImmutablePair;
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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+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.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
private ListenerRegistration<DataChangeListener> listenerRegistration;
private DataBroker dataBroker;
private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
+ @Override
public void onSuccess(Void result) {
logger.debug("Success in Datastore write operation");
}
+ @Override
public void onFailure(Throwable error) {
logger.error("Error in Datastore write operation", error);
}
};
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
- public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker) {
+ public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
super(Interface.class);
this.dhcpManager = dhcpManager;
this.dataBroker = dataBroker;
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
registerListener();
}
private void registerListener() {
try {
listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
- getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
+ getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE);
} catch (final Exception e) {
logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e);
throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e);
@Override
- protected void remove(InstanceIdentifier<Interface> identifier,
- Interface del) {
- String interfaceName = del.getName();
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
List<String> ofportIds = del.getLowerLayerIf();
+ if (ofportIds == null || ofportIds.isEmpty()) {
+ return;
+ }
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ DhcpServiceUtils.getInterfaceFromConfigDS(del.getName(), dataBroker);
+ if (iface != null) {
+ IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+ if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+ IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+ if (dpns.contains(dpId)) {
+ dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+ }
+ return;
+ }
+ }
+ String interfaceName = del.getName();
logger.trace("Received remove DCN for interface {} dpId {}", interfaceName, dpId);
unInstallDhcpEntries(interfaceName, dpId);
+ dhcpManager.removeInterfaceCache(interfaceName);
}
@Override
protected void update(InstanceIdentifier<Interface> identifier,
Interface original, Interface update) {
+ List<String> ofportIds = update.getLowerLayerIf();
+ if (ofportIds == null || ofportIds.isEmpty()) {
+ return;
+ }
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
+ BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+ String interfaceName = update.getName();
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ DhcpServiceUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
+ if (iface == null) {
+ logger.trace("Interface {} is not present in the config DS", interfaceName);
+ return;
+ }
+ if (update.getType() == null) {
+ logger.trace("Interface type for interface {} is null", interfaceName);
+ return;
+ }
+ if ((original.getOperStatus().getIntValue() ^ update.getOperStatus().getIntValue()) == 0) {
+ logger.trace("Interface operstatus {} is same", update.getOperStatus());
+ return;
+ }
+ if (Tunnel.class.equals(update.getType())) {
+ IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+ if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+ IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+ if (dpns.contains(dpId)) {
+ if (update.getOperStatus() == OperStatus.Down) {
+ dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId);
+ } else if (update.getOperStatus() == OperStatus.Up) {
+ dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+ }
+ }
+ }
+ return;
+ }
}
@Override
protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
String interfaceName = add.getName();
List<String> ofportIds = add.getLowerLayerIf();
+ if (ofportIds == null || ofportIds.isEmpty()) {
+ return;
+ }
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
logger.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpId);
- installDhcpEntries(interfaceName, dpId);
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ DhcpServiceUtils.getInterfaceFromConfigDS(add.getName(), dataBroker);
+ if (iface != null) {
+ IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class);
+ if (tunnelInterface != null && !tunnelInterface.isInternal()) {
+ IpAddress tunnelIp = tunnelInterface.getTunnelDestination();
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+ if (dpns.contains(dpId)) {
+ dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId);
+ }
+ return;
+ }
+ }
+ if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
+ installDhcpEntries(interfaceName, dpId);
+ dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, add.getPhysAddress().getValue()));
+ }
}
private String getNeutronMacAddress(String interfaceName) {
logger.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port);
return port.getMacAddress();
}
- logger.trace("Port not found in neutron. Interface Name {}", interfaceName);
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.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+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.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.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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeListenerBase<L2gatewayConnection,DhcpL2GatewayConnectionListener> implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceEventListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private final DataBroker dataBroker;
+
+ public DhcpL2GatewayConnectionListener(DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+ super(L2gatewayConnection.class, DhcpL2GatewayConnectionListener.class);
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+ this.dataBroker = dataBroker;
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<L2gatewayConnection> identifier,
+ L2gatewayConnection del) {
+ Uuid gatewayId = del.getL2gatewayId();
+ InstanceIdentifier<L2gateway> inst = InstanceIdentifier.create(Neutron.class).child(L2gateways.class)
+ .child(L2gateway.class, new L2gatewayKey(gatewayId));
+ Optional<L2gateway> l2Gateway = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (!l2Gateway.isPresent()) {
+ logger.trace("L2Gw not present id {}", gatewayId);
+ return;
+ }
+ Uuid networkUuid = del.getNetworkId();
+ boolean isLastConnection = isLastGatewayConnection(networkUuid);
+ if (!isLastConnection) {
+ logger.trace("Not the last L2GatewayConnection. Not removing flows.");
+ return;
+ }
+ List<Devices> l2Devices = l2Gateway.get().getDevices();
+ for (Devices l2Device : l2Devices) {
+ String l2DeviceName = l2Device.getDeviceName();
+ L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ IpAddress tunnelIp = l2GatewayDevice.getTunnelIp();
+ BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, del.getNetworkId().getValue());
+ if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ logger.error("Could not find desiganted DPN ID");
+ return;
+ }
+ dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, del.getNetworkId().getValue());
+ }
+ }
+
+ private boolean isLastGatewayConnection(Uuid networkUuid) {
+ boolean isLastConnection = true;
+ InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
+ Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
+ List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
+ for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
+ if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
+ isLastConnection = false;
+ break;
+ }
+ }
+ return isLastConnection;
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<L2gatewayConnection> identifier,
+ L2gatewayConnection original, L2gatewayConnection update) {
+
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<L2gatewayConnection> identifier,
+ L2gatewayConnection add) {
+
+ }
+
+ @Override
+ protected InstanceIdentifier<L2gatewayConnection> getWildCardPath() {
+ return InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class)
+ .child(L2gatewayConnection.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return DhcpL2GatewayConnectionListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.SUBTREE;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ logger.info("DhcpL2GatewayConnection listener 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.dhcpservice;
+
+import java.math.BigInteger;
+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.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+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.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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpLogicalSwitchListener extends AbstractDataChangeListener<LogicalSwitches> implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpLogicalSwitchListener.class);
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private DataBroker dataBroker;
+
+ public DhcpLogicalSwitchListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+ super(LogicalSwitches.class);
+ this.dhcpExternalTunnelManager = dhcpManager;
+ this.dataBroker = dataBroker;
+ registerListener();
+ }
+
+ private void registerListener() {
+ try {
+ listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), DhcpLogicalSwitchListener.this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ logger.error("DhcpLogicalSwitchListener DataChange listener registration fail!", e);
+ throw new IllegalStateException("DhcpLogicalSwitchListener registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<LogicalSwitches> getWildCardPath() {
+ return InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+ .child(Node.class).augmentation(HwvtepGlobalAugmentation.class)
+ .child(LogicalSwitches.class);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ logger.info("DhcpLogicalSwitchListener Closed");
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<LogicalSwitches> identifier,
+ LogicalSwitches del) {
+ logger.trace("Received LogicalSwitch remove DCN");
+ String elanInstanceName = del.getLogicalSwitchUuid().toString();
+ ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+ String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ L2GatewayDevice targetDevice = null;
+ for (L2GatewayDevice device : devices.values()) {
+ if (nodeId.equals(device.getHwvtepNodeId())) {
+ targetDevice = device;
+ break;
+ }
+ }
+ if (targetDevice == null) {
+ logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+ return;
+ }
+ IpAddress tunnelIp = targetDevice.getTunnelIp();
+ handleLogicalSwitchRemove(elanInstanceName, tunnelIp);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<LogicalSwitches> identifier,
+ LogicalSwitches original, LogicalSwitches update) {
+ logger.trace("Received LogicalSwitch update DCN");
+
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<LogicalSwitches> identifier,
+ LogicalSwitches add) {
+ logger.trace("Received LogicalSwitch add DCN");
+ String elanInstanceName = add.getHwvtepNodeName().getValue();
+ ConcurrentMap<String, L2GatewayDevice> devices = L2GatewayCacheUtils.getCache();
+ String nodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ L2GatewayDevice targetDevice = null;
+ for (L2GatewayDevice device : devices.values()) {
+ if (nodeId.equals(device.getHwvtepNodeId())) {
+ targetDevice = device;
+ break;
+ }
+ }
+ if (targetDevice == null) {
+ logger.error("Logical Switch Device with name {} is not present in L2GW cache", elanInstanceName);
+ return;
+ }
+ IpAddress tunnelIp = targetDevice.getTunnelIp();
+ handleLogicalSwitchAdd(elanInstanceName, tunnelIp);
+
+ }
+
+ private void handleLogicalSwitchRemove(String elanInstanceName, IpAddress tunnelIp) {
+ BigInteger designatedDpnId;
+ designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+ if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ logger.info("Could not find designated DPN ID");
+ return;
+ }
+ dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
+ }
+
+ private void handleLogicalSwitchAdd(String elanInstanceName, IpAddress tunnelIp) {
+ List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(dataBroker);
+ BigInteger designatedDpnId;
+ designatedDpnId = dhcpExternalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
+ if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ logger.info("Unable to designate a DPN");
+ return;
+ }
+ }
+}
\ No newline at end of file
*/
package org.opendaylight.vpnservice.dhcpservice;
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
-
-import com.google.common.base.Optional;
-
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-import com.google.common.util.concurrent.FutureCallback;
-
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
-import org.opendaylight.vpnservice.mdsalutil.ActionType;
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.MatchFieldType;
import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
import org.slf4j.Logger;
private int dhcpOptRebindingTime = 0;
private String dhcpOptDefDomainName;
private INeutronVpnManager neutronVpnService;
-
- private static final FutureCallback<Void> DEFAULT_CALLBACK =
- new FutureCallback<Void>() {
- public void onSuccess(Void result) {
- logger.debug("Success in Datastore write operation");
- }
- public void onFailure(Throwable error) {
- logger.error("Error in Datastore write operation", error);
- };
- };
+ // cache used to maintain DpnId and physical address for each interface.
+ private static HashMap<String, ImmutablePair<BigInteger, String>> interfaceToDpnIdMacAddress = new HashMap<String, ImmutablePair<BigInteger, String>>();
/**
* @param db - dataBroker reference
logger.info("DHCP Manager Closed");
}
- public void installDhcpEntries(BigInteger dpnId) {
- logger.debug("Installing Default DHCP Flow tp DPN: {}", dpnId);
- setupDefaultDhcpFlow(dpnId, NwConstants.DHCP_TABLE, NwConstants.ADD_FLOW);
- }
-
- private void setupDefaultDhcpFlow(BigInteger dpId, short tableId, int addOrRemove) {
-
- List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
- matches.add(new MatchInfo(MatchFieldType.eth_type,
- new long[] { NwConstants.ETHTYPE_IPV4 }));
- matches.add(new MatchInfo(MatchFieldType.ip_proto,
- new long[] { IPProtocols.UDP.intValue() }));
- matches.add(new MatchInfo(MatchFieldType.udp_src,
- new long[] { DHCPMConstants.dhcpClientPort }));
- matches.add(new MatchInfo(MatchFieldType.udp_dst,
- new long[] { DHCPMConstants.dhcpServerPort }));
-
- List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
- List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
- // Punt to controller
- actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
- new String[] {}));
- instructions.add(new InstructionInfo(InstructionType.write_actions,
- actionsInfos));
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
- getDefaultDhcpFlowRef(dpId, tableId),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
- DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
- mdsalUtil.installFlow(flowEntity);
- }
-
- private String getDefaultDhcpFlowRef(BigInteger dpId, long tableId) {
- return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX).append(dpId)
- .append(NwConstants.FLOWID_SEPARATOR).append(tableId).toString();
- }
-
public int setLeaseDuration(int leaseDuration) {
configureLeaseDuration(leaseDuration);
return getDhcpLeaseTime();
public Port getNeutronPort(String name) {
try {
return neutronVpnService.getNeutronPort(name);
+ } catch (IllegalArgumentException e) {
+ return null;
} catch (Exception ex) {
logger.trace("In getNeutronPort interface name passed {} exception message {}.", name, ex.getMessage());
return null;
}
public void installDhcpEntries(BigInteger dpnId, String vmMacAddress) {
- setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW);
- }
-
- private void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove) {
- if (dpId == null || dpId == DHCPMConstants.INVALID_DPID || vmMacAddress == null) {
- return;
- }
- List<MatchInfo> matches = new ArrayList<MatchInfo>();
-
- matches.add(new MatchInfo(MatchFieldType.eth_type,
- new long[] { NwConstants.ETHTYPE_IPV4 }));
- matches.add(new MatchInfo(MatchFieldType.ip_proto,
- new long[] { IPProtocols.UDP.intValue() }));
- matches.add(new MatchInfo(MatchFieldType.udp_src,
- new long[] { DHCPMConstants.dhcpClientPort }));
- matches.add(new MatchInfo(MatchFieldType.udp_dst,
- new long[] { DHCPMConstants.dhcpServerPort }));
- matches.add(new MatchInfo(MatchFieldType.eth_src,
- new String[] { vmMacAddress }));
-
- List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
- List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-
- // Punt to controller
- actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
- new String[] {}));
- instructions.add(new InstructionInfo(InstructionType.write_actions,
- actionsInfos));
- if (addOrRemove == NwConstants.DEL_FLOW) {
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
- getDhcpFlowRef(dpId, tableId, vmMacAddress),
- DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
- DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
- logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
- mdsalUtil.removeFlow(flowEntity);
- } else {
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
- getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
- DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
- logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
- mdsalUtil.installFlow(flowEntity);
- }
- }
-
- private String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
- return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
- .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
- .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
- .append(vmMacAddress).toString();
+ DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil);
}
public void unInstallDhcpEntries(BigInteger dpId, String vmMacAddress) {
- setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW);
+ DhcpServiceUtils.setupDhcpFlowEntry(dpId, NwConstants.DHCP_TABLE, vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil);
}
public void setupTableMissForDhcpTable(BigInteger dpId) {
0, "DHCP Table Miss Flow", 0, 0,
DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
mdsalUtil.installFlow(flowEntity);
+ setupTableMissForHandlingExternalTunnel(dpId);
+ }
+
+ private void setupTableMissForHandlingExternalTunnel(BigInteger dpId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.EXTERNAL_TUNNEL_TABLE }));
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL, "DHCPTableMissFlowForExternalTunnel",
+ 0, "DHCP Table Miss Flow For External Tunnel", 0, 0,
+ DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+ mdsalUtil.installFlow(flowEntity);
+ }
+
+ public void updateInterfaceCache(String interfaceName, ImmutablePair<BigInteger, String> pair) {
+ interfaceToDpnIdMacAddress.put(interfaceName, pair);
+ }
+
+ public ImmutablePair<BigInteger, String> getInterfaceCache(String interfaceName) {
+ return interfaceToDpnIdMacAddress.get(interfaceName);
+ }
+
+ public void removeInterfaceCache(String interfaceName) {
+ interfaceToDpnIdMacAddress.remove(interfaceName);
}
}
--- /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.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+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.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.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DhcpNeutronPortListener extends AsyncClusteredDataChangeListenerBase<Port, DhcpNeutronPortListener> implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DhcpNeutronPortListener.class);
+
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private DataBroker broker;
+
+ public DhcpNeutronPortListener(final DataBroker db, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+ super(Port.class, DhcpNeutronPortListener.class);
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+ this.broker = db;
+ }
+
+ @Override
+ protected InstanceIdentifier<Port> getWildCardPath() {
+ return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DhcpNeutronPortListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.debug("DhcpNeutronPortListener Listener Closed");
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Port> identifier, Port del) {
+ LOG.trace("Port removed: {}", del);
+ if(NeutronUtils.isPortVnicTypeNormal(del)) {
+ return;
+ }
+ String macAddress = del.getMacAddress();
+ Uuid networkId = del.getNetworkId();
+ String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+ if (segmentationId == null) {
+ return;
+ }
+ List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+ dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(networkId.getValue(), listOfDpns, macAddress);
+ dhcpExternalTunnelManager.removeVniMacToPortCache(new BigInteger(segmentationId), macAddress);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
+ LOG.trace("Port changed to {}", update);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Port> identifier, Port add) {
+ LOG.trace("Port added {}", add);
+ if(NeutronUtils.isPortVnicTypeNormal(add)) {
+ LOG.trace("Port is normal {}", add);
+ return;
+ }
+ String macAddress = add.getMacAddress();
+ Uuid networkId = add.getNetworkId();
+ String segmentationId = DhcpServiceUtils.getSegmentationId(networkId, broker);
+ if (segmentationId == null) {
+ LOG.trace("segmentation id is null");
+ return;
+ }
+ dhcpExternalTunnelManager.updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, add);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return DhcpNeutronPortListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.SUBTREE;
+ }
+}
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
private final DataBroker dataBroker;
private final DhcpManager dhcpMgr;
private OdlInterfaceRpcService interfaceManagerRpc;
- private static HashMap<String, ImmutablePair<BigInteger, String>> localCache = new HashMap<String, ImmutablePair<BigInteger, String>>();
private boolean computeUdpChecksum = true;
private PacketProcessingService pktService;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
- public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) {
+ public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.dataBroker = broker;
dhcpMgr = dhcpManager;
}
//TODO: Handle this in a separate thread
@Override
public void onPacketReceived(PacketReceived packet) {
- LOG.trace("Pkt received: {}", packet);
Class<? extends PacketInReason> pktInReason = packet.getPacketInReason();
- short tableId = packet.getTableId().getValue();
if (isPktInReasonSendtoCtrl(pktInReason)) {
byte[] inPayload = packet.getPayload();
Ethernet ethPkt = new Ethernet();
try {
ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
} catch (Exception e) {
- LOG.warn("Failed to decode DHCP Packet", e);
+ LOG.warn("Failed to decode DHCP Packet {}", e);
+ LOG.trace("Received packet {}", packet);
return;
}
try {
pktIn = getDhcpPktIn(ethPkt);
if (pktIn != null) {
LOG.trace("DHCPPkt received: {}", pktIn);
+ LOG.trace("Received Packet: {}", packet);
BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+ String macAddress = DHCPUtils.byteArrayToString(ethPkt.getSourceMACAddress());
+ BigInteger tunnelId = packet.getMatch().getTunnel() == null ? null : packet.getMatch().getTunnel().getTunnelId();
String interfaceName = getInterfaceNameFromTag(portTag);
ImmutablePair<BigInteger, String> pair = getDpnIdPhysicalAddressFromInterfaceName(interfaceName);
- DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName);
+ DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId);
byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, pair.getRight());
- sendPacketOut(pktOut, pair.getLeft(), interfaceName);
+ sendPacketOut(pktOut, pair.getLeft(), interfaceName, tunnelId);
}
} catch (Exception e) {
- LOG.warn("Failed to get DHCP Reply {}", e);
+ LOG.warn("Failed to get DHCP Reply");
+ LOG.trace("Reason for failure {}", e);
}
}
}
- private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName) {
+ private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName, BigInteger tunnelId) {
LOG.trace("Sending packet out DpId {}, portId {}, vlanId {}, interfaceName {}", dpnId, interfaceName);
- List<Action> action = getEgressAction(interfaceName);
+ List<Action> action = getEgressAction(interfaceName, tunnelId);
TransmitPacketInput output = MDSALUtil.getPacketOut(action, pktOut, dpnId);
LOG.trace("Transmitting packet: {}",output);
this.pktService.transmitPacket(output);
}
- private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName) {
+ private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId) {
LOG.debug("DHCP pkt rcvd {}", dhcpPkt);
byte msgType = dhcpPkt.getMsgType();
if (msgType == DHCPConstants.MSG_DECLINE) {
LOG.debug("DHCPRELEASE received");
return null;
}
-
- Port nPort = getNeutronPort(interfaceName);
+ Port nPort;
+ if (tunnelId != null) {
+ nPort = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
+ } else {
+ nPort = getNeutronPort(interfaceName);
+ }
Subnet nSubnet = getNeutronSubnet(nPort);
DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet);
LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo);
dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
.setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes())
.setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
- } else {
- //FIXME: Delete this test code
- LOG.error("TestOnly Code");
- dhcpInfo = new DhcpInfo();
- dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1")
- .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1");
- LOG.warn("Failed to get Subnet info for DHCP reply");
}
return dhcpInfo;
}
private DHCP getDhcpPktIn(Ethernet actualEthernetPacket) {
Ethernet ethPkt = actualEthernetPacket;
- LOG.trace("Inside getDhcpPktIn ethPkt {} \n getPayload {}", ethPkt, ethPkt.getPayload());
if (ethPkt.getEtherType() == (short)NwConstants.ETHTYPE_802_1Q) {
ethPkt = (Ethernet)ethPkt.getPayload();
}
try {
reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length);
} catch (PacketException e) {
- LOG.warn("Failed to deserialize DHCP pkt {}", e);
+ LOG.warn("Failed to deserialize DHCP pkt");
+ LOG.trace("Reason for failure {}", e);
return null;
}
return reply;
ether.setEtherType(EtherTypes.IPv4.shortValue());
ether.setPayload(ip4Reply);
}
- //TODO:
ether.setSourceMACAddress(getServerMacAddress(phyAddrees));
ether.setDestinationMACAddress(etherPkt.getSourceMACAddress());
return id;
}
- private List<Action> getEgressAction(String interfaceName) {
+ private List<Action> getEgressAction(String interfaceName, BigInteger tunnelId) {
List<Action> actions = null;
try {
+ GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
+ if (tunnelId != null) {
+ egressAction.setTunnelKey(tunnelId.longValue());
+ }
Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
- interfaceManagerRpc.getEgressActionsForInterface(
- new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName).build());
+ interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
if(!rpcResult.isSuccessful()) {
LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName, rpcResult.getErrors());
}
private ImmutablePair<BigInteger, String> getDpnIdPhysicalAddressFromInterfaceName(String interfaceName) {
- ImmutablePair<BigInteger, String> pair = localCache.get(interfaceName);
+ ImmutablePair<BigInteger, String> pair = dhcpMgr.getInterfaceCache(interfaceName);
if (pair!=null && pair.getLeft() != null && pair.getRight() != null) {
return pair;
}
BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
String phyAddress = interfaceState==null ? "":interfaceState.getPhysAddress().getValue();
pair = new ImmutablePair<BigInteger, String>(dpId, phyAddress);
- localCache.put(interfaceName, pair);
- return null;
+ dhcpMgr.updateInterfaceCache(interfaceName, pair);
+ return pair;
}
}
*/
package org.opendaylight.vpnservice.dhcpservice;
-import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
-import org.opendaylight.yangtools.concepts.Registration;
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.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+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.yangtools.concepts.Registration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private DhcpConfigListener dhcpConfigListener;
private OdlInterfaceRpcService interfaceManagerRpc;
private DhcpInterfaceEventListener dhcpInterfaceEventListener;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private DhcpNeutronPortListener dhcpNeutronPortListener;
+ private DhcpLogicalSwitchListener dhcpLogicalSwitchListener;
+ private DhcpUCastMacListener dhcpUCastMacListener;
+ private ItmRpcService itmRpcService;
+ private DhcpInterfaceConfigListener dhcpInterfaceConfigListener;
+ private EntityOwnershipService entityOwnershipService;
+ private DhcpDesignatedDpnListener dhcpDesignatedDpnListener;
+ private DhcpL2GatewayConnectionListener dhcpL2GatewayConnectionListener;
@Override
public void onSessionInitiated(ProviderContext session) {
dhcpManager = new DhcpManager(dataBroker);
dhcpManager.setMdsalManager(mdsalManager);
dhcpManager.setNeutronVpnService(neutronVpnManager);
- dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager);
+ dhcpExternalTunnelManager = new DhcpExternalTunnelManager(dataBroker, mdsalManager, itmRpcService, entityOwnershipService);
+ dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager, dhcpExternalTunnelManager);
dhcpPktHandler.setPacketProcessingService(pktProcessingService);
dhcpPktHandler.setInterfaceManagerRpc(interfaceManagerRpc);
packetListener = notificationService.registerNotificationListener(dhcpPktHandler);
- dhcpNodeListener = new NodeListener(dataBroker, dhcpManager);
+ dhcpNodeListener = new NodeListener(dataBroker, dhcpManager, dhcpExternalTunnelManager);
dhcpConfigListener = new DhcpConfigListener(dataBroker, dhcpManager);
- dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker);
+ dhcpInterfaceEventListener = new DhcpInterfaceEventListener(dhcpManager, dataBroker, dhcpExternalTunnelManager);
+ dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(dataBroker, dhcpExternalTunnelManager);
+ dhcpLogicalSwitchListener = new DhcpLogicalSwitchListener(dhcpExternalTunnelManager, dataBroker);
+ dhcpUCastMacListener = new DhcpUCastMacListener(dhcpExternalTunnelManager, dataBroker);
+ dhcpUCastMacListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+ dhcpNeutronPortListener = new DhcpNeutronPortListener(dataBroker, dhcpExternalTunnelManager);
+ dhcpNeutronPortListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+ dhcpDesignatedDpnListener = new DhcpDesignatedDpnListener(dhcpExternalTunnelManager, dataBroker);
+ dhcpDesignatedDpnListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+ dhcpL2GatewayConnectionListener = new DhcpL2GatewayConnectionListener(dataBroker, dhcpExternalTunnelManager);
+ dhcpL2GatewayConnectionListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
} catch (Exception e) {
LOG.error("Error initializing services {}", e);
}
}
-
public void setMdsalManager(IMdsalApiManager mdsalManager) {
this.mdsalManager = mdsalManager;
}
public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
this.interfaceManagerRpc = interfaceManagerRpc;
}
+
+ public void setItmRpcService(ItmRpcService itmRpcService) {
+ this.itmRpcService = itmRpcService;
+ }
+
+ public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ }
}
--- /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.dhcpservice;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+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.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+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.InterfacesState;
+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.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.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.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.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+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.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpServiceUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpServiceUtils.class);
+
+ public static Interface getInterfaceFromConfigDS(String interfaceName, DataBroker dataBroker) {
+ InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+ InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
+ Optional<Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
+ if (!interfaceOptional.isPresent()) {
+ return null;
+ }
+ return interfaceOptional.get();
+ }
+
+ private static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
+ InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder =
+ InstanceIdentifier.builder(Interfaces.class).child(Interface.class, interfaceKey);
+ return interfaceInstanceIdentifierBuilder.build();
+ }
+
+ public static void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+ if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+ return;
+ }
+ List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+
+ // Punt to controller
+ actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
+ new String[] {}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions,
+ actionsInfos));
+ if (addOrRemove == NwConstants.DEL_FLOW) {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+ getDhcpFlowRef(dpId, tableId, vmMacAddress),
+ DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+ DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+ logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ mdsalUtil.removeFlow(flowEntity);
+ } else {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+ getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+ DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+ logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ mdsalUtil.installFlow(flowEntity);
+ }
+ }
+
+ private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
+ return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
+ .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(vmMacAddress).toString();
+ }
+
+ public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil) {
+ if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
+ return;
+ }
+ List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+ // Drop Action
+ actionsInfos.add(new ActionInfo(ActionType.drop_action,
+ new String[] {}));
+ if (addOrRemove == NwConstants.DEL_FLOW) {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+ getDhcpFlowRef(dpId, tableId, vmMacAddress),
+ DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+ DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
+ logger.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ mdsalUtil.removeFlow(flowEntity);
+ } else {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+ getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
+ DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
+ logger.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ mdsalUtil.installFlow(flowEntity);
+ }
+ }
+
+ private static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { NwConstants.ETHTYPE_IPV4 }));
+ matches.add(new MatchInfo(MatchFieldType.ip_proto,
+ new long[] { IPProtocols.UDP.intValue() }));
+ matches.add(new MatchInfo(MatchFieldType.udp_src,
+ new long[] { DHCPMConstants.dhcpClientPort }));
+ matches.add(new MatchInfo(MatchFieldType.udp_dst,
+ new long[] { DHCPMConstants.dhcpServerPort }));
+ matches.add(new MatchInfo(MatchFieldType.eth_src,
+ new String[] { vmMacAddress }));
+ return matches;
+ }
+
+ public static List<BigInteger> getListOfDpns(DataBroker broker) {
+ List<BigInteger> dpnsList = new LinkedList<BigInteger>();
+ InstanceIdentifier<Nodes> nodesInstanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
+ Optional<Nodes> nodesOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, nodesInstanceIdentifier);
+ if (!nodesOptional.isPresent()) {
+ return dpnsList;
+ }
+ Nodes nodes = nodesOptional.get();
+ List<Node> nodeList = nodes.getNode();
+ for (Node node : nodeList) {
+ NodeId nodeId = node.getId();
+ if (nodeId == null) {
+ continue;
+ }
+ BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+ dpnsList.add(dpnId);
+ }
+ return dpnsList;
+ }
+
+ public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
+ List<BigInteger> elanDpns = new LinkedList<BigInteger>();
+ InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier = InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+ Optional<ElanDpnInterfacesList> elanDpnOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
+ if (elanDpnOptional.isPresent()) {
+ List<DpnInterfaces> dpns = elanDpnOptional.get().getDpnInterfaces();
+ for (DpnInterfaces dpnInterfaces : dpns) {
+ elanDpns.add(dpnInterfaces.getDpId());
+ }
+ }
+ return elanDpns;
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey interfaceKey = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName);
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class, interfaceKey).build();
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker);
+ if (!interfaceOptional.isPresent()) {
+ return null;
+ }
+ return interfaceOptional.get();
+ }
+
+
+ public static String getSegmentationId(Uuid networkId, DataBroker broker) {
+ InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class).child(Networks.class).child
+ (Network.class, new NetworkKey(networkId));
+ Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (!optionalNetwork.isPresent()) {
+ return null;
+ }
+ Network network = optionalNetwork.get();
+ String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network);
+ return segmentationId;
+ }
+
+ public static String getNodeIdFromDpnId(BigInteger dpnId) {
+ return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
+ }
+
+ public static String getTrunkPortMacAddress(String parentRefName,
+ DataBroker broker) {
+ InstanceIdentifier<Port> portInstanceIdentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
+ Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
+ if (!trunkPort.isPresent()) {
+ logger.warn("Trunk port {} not available for sub-port", parentRefName);
+ return null;
+ }
+ return trunkPort.get().getMacAddress();
+ }
+}
\ 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.dhcpservice;
+
+import java.math.BigInteger;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+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.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.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+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;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DhcpUCastMacListener extends AsyncClusteredDataChangeListenerBase<LocalUcastMacs, DhcpUCastMacListener> implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(DhcpUCastMacListener.class);
+ private DataBroker broker;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
+
+ public DhcpUCastMacListener(DhcpExternalTunnelManager dhcpManager, DataBroker dataBroker) {
+ super(LocalUcastMacs.class, DhcpUCastMacListener.class);
+ this.broker = dataBroker;
+ this.dhcpExternalTunnelManager = dhcpManager;
+ }
+
+ @Override
+ protected InstanceIdentifier<LocalUcastMacs> getWildCardPath() {
+ return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
+ .augmentation(HwvtepGlobalAugmentation.class).child(LocalUcastMacs.class);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ logger.info("DhcpUCastMacListener Closed");
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<LocalUcastMacs> identifier,
+ LocalUcastMacs del) {
+ // Flow removal for table 18 is handled in Neutron Port delete.
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<LocalUcastMacs> identifier,
+ LocalUcastMacs original, LocalUcastMacs update) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<LocalUcastMacs> identifier,
+ LocalUcastMacs add) {
+ NodeId torNodeId = identifier.firstKeyOf(Node.class).getNodeId();
+ InstanceIdentifier<LogicalSwitches> logicalSwitchRef = (InstanceIdentifier<LogicalSwitches>) add.getLogicalSwitchRef().getValue();
+ Optional<LogicalSwitches> logicalSwitchOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, logicalSwitchRef);
+ if ( !logicalSwitchOptional.isPresent() ) {
+ logger.error("Logical Switch ref doesn't have data {}", logicalSwitchRef);
+ return;
+ }
+ LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
+ String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
+ String macAddress = add.getMacEntryKey().getValue();
+ BigInteger vni = new BigInteger(logicalSwitch.getTunnelKey());
+ Port port = dhcpExternalTunnelManager.readVniMacToPortCache(vni, macAddress);
+ if (port == null) {
+ logger.trace("No neutron port created for macAddress {}, tunnelKey {}", macAddress, vni);
+ return;
+ }
+ L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
+ if (device == null) {
+ logger.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
+ return;
+ }
+ IpAddress tunnelIp = device.getTunnelIp();
+ BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
+ dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, macAddress);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return DhcpUCastMacListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return DataChangeScope.SUBTREE;
+ }
+}
\ No newline at end of file
*/
package org.opendaylight.vpnservice.dhcpservice;
+import java.math.BigInteger;
+import java.util.List;
+
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.dhcpservice.api.DHCPMConstants;
-import org.opendaylight.vpnservice.mdsalutil.*;
-import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-
public class NodeListener extends AbstractDataChangeListener<Node> implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(NodeListener.class);
- private IMdsalApiManager mdsalManager;
private ListenerRegistration<DataChangeListener> listenerRegistration;
private final DataBroker broker;
private DhcpManager dhcpManager;
+ private DhcpExternalTunnelManager dhcpExternalTunnelManager;
- public NodeListener(final DataBroker db, final DhcpManager dhcpMgr) {
+ public NodeListener(final DataBroker db, final DhcpManager dhcpMgr, final DhcpExternalTunnelManager dhcpExternalTunnelManager) {
super(Node.class);
broker = db;
dhcpManager = dhcpMgr;
+ this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
registerListener(db);
}
private void registerListener(final DataBroker db) {
try {
listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
- getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
} catch (final Exception e) {
LOG.error("NodeListener: DataChange listener registration fail!", e);
throw new IllegalStateException("NodeListener: registration Listener failed.", e);
return InstanceIdentifier.create(Nodes.class).child(Node.class);
}
-
@Override
protected void remove(InstanceIdentifier<Node> identifier, Node del) {
-
+ NodeId nodeId = del.getId();
+ BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
+ List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+ dhcpExternalTunnelManager.handleDesignatedDpnDown(dpnId, listOfDpns);
}
@Override
protected void add(InstanceIdentifier<Node> identifier, Node add) {
NodeId nodeId = add.getId();
String[] node = nodeId.getValue().split(":");
+ if(node.length < 2) {
+ LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+ return;
+ }
BigInteger dpId = new BigInteger(node[1]);
dhcpManager.setupTableMissForDhcpTable(dpId);
+ dhcpExternalTunnelManager.installDhcpDropActionOnDpn(dpId);
+ List<BigInteger> listOfDpns = DhcpServiceUtils.getListOfDpns(broker);
+ dhcpExternalTunnelManager.handleDesignatedDpnDown(DHCPMConstants.INVALID_DPID, listOfDpns);
}
@Override
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.vpnservice.dhcpservice.DhcpProvider;
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;
public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.impl.rev150710.AbstractDhcpServiceImplModule {
public DhcpServiceImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
dhcpProvider.setMdsalManager(getMdsalutilDependency());
dhcpProvider.setNeutronVpnManager(getNeutronvpnDependency());
dhcpProvider.setInterfaceManagerRpc(rpcregistryDependency.getRpcService(OdlInterfaceRpcService.class));
+ dhcpProvider.setItmRpcService(rpcregistryDependency.getRpcService(ItmRpcService.class));
+ dhcpProvider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
getBrokerDependency().registerProvider(dhcpProvider);
return dhcpProvider;
}
import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
import odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
import neutronvpn-api { prefix nvpn; revision-date 2015-08-12;}
+ import opendaylight-entity-ownership-service { prefix eos; revision-date 2015-08-10;}
description
"Service definition for dhcpservice project";
}
}
}
+
+ container entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
+ }
+ }
}
}
}
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 java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.utils.cache.CacheUtil;
}
- public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
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);
+ L2GatewayDevice device = deviceMap.remove(l2gwDeviceNodeId);
return device;
} else {
return null;
}
}
- public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
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);
+ return deviceMap.get(l2gwDeviceNodeId);
} else {
return null;
}
}
- public static ConcurrentMap<String, L2GatewayDevice> getAllElanL2GatewayDevicesFromCache(String elanName) {
+ public static ConcurrentMap<String, L2GatewayDevice> getInvolvedL2GwDevices(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);
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>${mdsal.version}</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
-
</project>
<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">
return;
}
ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
print(elanName, elanDevices);
}
--- /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.internal;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+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.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanDpnInterfaceClusteredListener
+ extends AsyncClusteredDataChangeListenerBase<DpnInterfaces, ElanDpnInterfaceClusteredListener>
+ implements AutoCloseable {
+ private DataBroker broker;
+ private ElanInterfaceManager elanInterfaceManager;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ElanDpnInterfaceClusteredListener.class);
+
+ public ElanDpnInterfaceClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+ super(DpnInterfaces.class, ElanDpnInterfaceClusteredListener.class);
+ broker = db;
+ elanInterfaceManager = ifManager;
+ registerListener(db);
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), ElanDpnInterfaceClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+ } catch (final Exception e) {
+ LOG.error("DpnInterfaces DataChange listener registration fail!", e);
+ }
+ }
+
+ @Override
+ public InstanceIdentifier<DpnInterfaces> getWildCardPath() {
+ return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class)
+ .child(DpnInterfaces.class).build();
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return ElanDpnInterfaceClusteredListener.this;
+ }
+
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ void handleUpdate(InstanceIdentifier<DpnInterfaces> id, DpnInterfaces dpnInterfaces) {
+ final String elanName = getElanName(id);
+ if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+ LOG.debug("dpnInterface updation, no external l2 devices to update for elan {} with Dp Id:", elanName,
+ dpnInterfaces.getDpId());
+ return;
+ }
+ ElanClusterUtils.runOnlyInLeaderNode(elanName, "updating mcast mac upon tunnel event",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+ }
+ });
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+ // this is the last dpn interface on this elan
+ final String elanName = getElanName(identifier);
+ LOG.debug("Received ElanDpnInterface removed for for elan {} with Dp Id ", elanName,
+ dpnInterfaces.getDpId());
+
+ if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+ LOG.debug("dpnInterface removed, no external l2 devices to update for elan {} with Dp Id:", elanName,
+ dpnInterfaces.getDpId());
+ return;
+ }
+ ElanClusterUtils.runOnlyInLeaderNode(elanName, "handling ElanDpnInterface removed",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ // deleting Elan L2Gw Devices UcastLocalMacs From Dpn
+ ElanL2GatewayUtils.deleteElanL2GwDevicesUcastLocalMacsFromDpn(elanName,
+ dpnInterfaces.getDpId());
+ // updating remote mcast mac on l2gw devices
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+ }
+ });
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<DpnInterfaces> identifier, DpnInterfaces original,
+ final DpnInterfaces dpnInterfaces) {
+ LOG.debug("dpninterfaces update fired new size {}", dpnInterfaces.getInterfaces().size());
+ if (dpnInterfaces.getInterfaces().size() == 0) {
+ LOG.debug("dpninterfaces last dpn interface on this elan {} ", dpnInterfaces.getKey());
+ // this is the last dpn interface on this elan
+ handleUpdate(identifier, dpnInterfaces);
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+ if (dpnInterfaces.getInterfaces().size() == 1) {
+ LOG.debug("dpninterfaces first dpn interface on this elan {} {} ", dpnInterfaces.getKey(),
+ dpnInterfaces.getInterfaces().get(0));
+ // this is the first dpn interface on this elan
+ handleUpdate(identifier, dpnInterfaces);
+ }
+ }
+
+ /**
+ * @param identifier
+ * @return
+ */
+ private String getElanName(InstanceIdentifier<DpnInterfaces> identifier) {
+ return identifier.firstKeyOf(ElanDpnInterfacesList.class).getElanInstanceName();
+ }
+}
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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
private ListenerRegistration<DataChangeListener> elanInstanceListenerRegistration;
private IdManagerService idManager;
private ElanInterfaceManager elanInterfaceManager;
+ private IInterfaceManager interfaceManager;
private static final Logger logger = LoggerFactory.getLogger(ElanInstanceManager.class);
this.elanInterfaceManager = elanInterfaceManager;
}
+ public void setInterfaceManager(IInterfaceManager interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
/**
* Starts listening for changes in elan.yang:elan-instance container
if(elanInterfaces != null && !elanInterfaces.isEmpty()) {
for (String elanInterfaceName : elanInterfaces) {
InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName);
- elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName);
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
+ elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo);
ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
}
}
--- /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.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+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.interfaces.ElanInterface;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceAddWorker implements Callable<List<ListenableFuture<Void>>> {
+ private String key;
+ private ElanInterface elanInterface;
+ private ElanInstance elanInstance;
+ private InterfaceInfo interfaceInfo;
+ private ElanInterfaceManager dataChangeListener;
+
+ public ElanInterfaceAddWorker(String key, ElanInterface elanInterface, InterfaceInfo interfaceInfo,
+ ElanInstance elanInstance, ElanInterfaceManager dataChangeListener) {
+ super();
+ this.key = key;
+ this.elanInterface = elanInterface;
+ this.interfaceInfo = interfaceInfo;
+ this.elanInstance = elanInstance;
+ this.dataChangeListener = dataChangeListener;
+ }
+
+ @Override
+ public String toString() {
+ return "ElanInterfaceAddWorker [key=" + key + ", elanInterface=" + elanInterface + ", elanInstance="
+ + elanInstance + ", interfaceInfo=" + interfaceInfo + "]";
+ }
+
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ dataChangeListener.addElanInterface(elanInterface, interfaceInfo, elanInstance);
+ return futures;
+ }
+
+
+
+}
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-
+import org.apache.commons.lang3.StringUtils;
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.elanmanager.utils.ElanL2GwCacheUtils;
+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.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.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.interfaces.rev140508.interfaces.state.Interface;
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.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.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.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.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.forwarding.entries.MacEntryKey;
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.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
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.
protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
String interfaceName = del.getName();
ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
- removeElanInterface(elanInfo, interfaceName);
- }
-
- public void removeElanService(ElanInterface del, InterfaceInfo interfaceInfo) {
- ElanInstance elanInstance = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
- String interfaceName = del.getName();
- removeElanInterface(elanInstance, interfaceInfo);
- unbindService(elanInstance, interfaceName);
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+ String elanInstanceName = elanInfo.getElanInstanceName();
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceRemoveWorker configWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInfo, interfaceName, interfaceInfo, this);
+ coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
}
- public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
+ public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) {
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);
BigInteger dpId = interfaceInfo.getDpId();
String elanName = elanInfo.getElanInstanceName();
+ long elanTag = elanInfo.getElanTag();
String interfaceName = interfaceInfo.getInterfaceName();
Elan elanState = ElanUtils.getElanByName(elanName);
logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
if (dpnIfLists.getInterfaces().contains(interfaceName)) {
logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
- removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+ removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
break;
}
}
}
} else {
- removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+ removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
}
removeStaticELanFlows(elanInfo, interfaceInfo);
}
}
- private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName) {
+ private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName, long elanTag) {
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
if(dpnInterfaces != null) {
List<String> interfaceLists = dpnInterfaces.getInterfaces();
interfaceLists.remove(interfaceName);
if (interfaceLists == null || interfaceLists.isEmpty()) {
+ deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
deleteElanDpnInterface(elanName, dpId);
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName);
} else {
updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
}
}
}
+ private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
+ List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+ for (DpnInterfaces dpnInterface : dpnInterfaces) {
+ BigInteger currentDpId = dpnInterface.getDpId();
+ if (!currentDpId.equals(dpId)) {
+ for (String elanInterface : dpnInterface.getInterfaces()) {
+ ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+ if (macs == null) {
+ continue;
+ }
+ for (MacEntry mac : macs.getMacEntry())
+ mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+ ElanUtils.getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
+ }
+ }
+ }
+ }
+
@Override
protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
// updating the static-Mac Entries for the existing elanInterface
unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
return;
}
- addElanInterface(elanInterfaceAdded, interfaceInfo, elanInstance);
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceAddWorker addWorker = new ElanInterfaceAddWorker(elanInstanceName, elanInterfaceAdded,
+ interfaceInfo, elanInstance, this);
+ coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
}
void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
setExternalTunnelTable(dpId, elanInstance);
}
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+ ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
} else {
List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
elanInterfaces.add(interfaceName);
if (elanInterfaces.size() == 1) {//1st dpn interface
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+ ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
}
updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
}
if( isInterfaceOperational ) {
// Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
- ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, staticMacAddresses);
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
}
}
}
if (isOperational(interfaceInfo)) {
// LocalBroadcast Group creation with elan-Interfaces
- setupElanBroadcastGroups(elanInfo, interfaceInfo);
+ setupElanBroadcastGroups(elanInfo, interfaceInfo.getDpId());
setupLocalBroadcastGroups(elanInfo, interfaceInfo);
//Terminating Service , UnknownDMAC Table.
setupTerminateServiceTable(elanInfo, interfaceInfo);
+ ElanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager);
setupUnknownDMacTable(elanInfo, interfaceInfo);
setupFilterEqualsTable(elanInfo, interfaceInfo);
// bind the Elan service to the Interface
return listBuckets;
}
- private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo,
- InterfaceInfo interfaceInfo, int bucketId) {
- BigInteger dpnId = interfaceInfo.getDpId();
+ private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
int elanTag = elanInfo.getElanTag().intValue();
List<Bucket> listBucketInfo = new ArrayList<Bucket>();
ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
}
}
- private void updateRemoteBCGrouponDpnTunnelEvent(ElanInstance elanInfo,
- InterfaceInfo interfaceInfo, BigInteger dstDpId) {
- int elanTag = elanInfo.getElanTag().intValue();
- long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
- 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()) {
- try {
- 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;
- }
- }
- }
- }
-
-
/**
* Returns the bucket info with the given interface as the only bucket.
*/
}
}
- public void setupElanBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+ public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
List<Bucket> listBucket = new ArrayList<Bucket>();
int bucketId = 0;
- BigInteger dpnId = interfaceInfo.getDpId();
long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
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());
+ // FIXME: interfaceType to be obtained dynamically. It doesn't
+ // affect the functionality here as it is nowhere used.
+ InterfaceType interfaceType = InterfaceInfo.InterfaceType.VLAN_INTERFACE;
+ InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceType);
if (!isOperational(ifInfo)) {
continue;
}
listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
bucketId++;
}
- List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, interfaceInfo, bucketId);
+ List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
listBucket.addAll(listBucketInfoRemote);
Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
- logger.trace("installing the localBroadCast Group:{}", group);
+ logger.trace("installing the remote BroadCast Group:{}", group);
mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
}
String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
flowEntity.setFlowId(flowId);
mdsalManager.removeFlow(flowEntity);
}
// No more Elan Interfaces in this DPN
logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+ removeDefaultTermFlow(dpId, interfaceInfo.getInterfaceTag());
removeUnknownDmacFlow(dpId, elanInfo);
removeElanBroadcastGroup(elanInfo, interfaceInfo);
removeLocalBroadcastGroup(elanInfo, interfaceInfo);
}
removeFilterEqualsTable(elanInfo, interfaceInfo);
} else {
- setupElanBroadcastGroups(elanInfo, interfaceInfo);
+ setupElanBroadcastGroups(elanInfo, dpId);
setupLocalBroadcastGroups(elanInfo, interfaceInfo);
removeFilterEqualsTable(elanInfo, interfaceInfo);
}
if (interfaceInfo == null) {
return false;
}
- return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
+ return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
}
protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
}
}
- public void handleTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
+ public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
- Set<String> elanInstancesMap = new HashSet<>();
if(dpnInterfaceLists == null) {
return;
}
}
if(cnt == 2) {
logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
+ ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+ // update Remote BC Group
+ setupElanBroadcastGroups(elanInfo, srcDpId);
+
DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
Set<String> interfaceLists = new HashSet<>();
- ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
interfaceLists.addAll(dpnInterface.getInterfaces());
for(String ifName : interfaceLists) {
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
if (isOperational(interfaceInfo)) {
- if (interfaceInfo.getDpId().equals(srcDpId) && !elanInstancesMap.contains(elanDpns.getElanInstanceName())) {
- elanInstancesMap.add(elanDpns.getElanInstanceName());
- elanInterfaceManager.updateRemoteBCGrouponDpnTunnelEvent(elanInfo, interfaceInfo, dstDpId);
- }
elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
}
}
}
}
+ /**
+ * Handle external tunnel state event.
+ *
+ * @param externalTunnel
+ * the external tunnel
+ * @param intrf
+ * the interface
+ */
+ public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+ if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
+ return;
+ }
+ // dpId/externalNodeId will be available either in source or destination
+ // based on the tunnel end point
+ BigInteger dpId = null;
+ NodeId externalNodeId = null;
+ if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
+ dpId = new BigInteger(externalTunnel.getSourceDevice());
+ externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
+ } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
+ dpId = new BigInteger(externalTunnel.getDestinationDevice());
+ externalNodeId = new NodeId(externalTunnel.getSourceDevice());
+ }
+ if (dpId == null || externalNodeId == null) {
+ logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
+ return;
+ }
+
+ ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
+ if (dpnInterfaceLists == null) {
+ return;
+ }
+ List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+ for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
+ String elanName = elanDpns.getElanInstanceName();
+ ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+
+ DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+ if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+ || dpnInterfaces.getInterfaces().isEmpty()) {
+ continue;
+ }
+ logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
+
+ setupElanBroadcastGroups(elanInfo, dpId);
+ // install L2gwDevices local macs in dpn.
+ ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
+ // Install dpn macs on external device
+ ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+ externalNodeId);
+ }
+ logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
+ }
+
+ /**
+ * Validate external tunnel state event.
+ *
+ * @param externalTunnel
+ * the external tunnel
+ * @param intrf
+ * the intrf
+ * @return true, if successful
+ */
+ private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+ if (intrf.getOperStatus() == Interface.OperStatus.Up) {
+ String srcDevice = externalTunnel.getDestinationDevice();
+ String destDevice = externalTunnel.getSourceDevice();
+ ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
+ LogicalDatastoreType.CONFIGURATION);
+ if (logger.isTraceEnabled()) {
+ logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
+ otherEndPointExtTunnel);
+ }
+ if (otherEndPointExtTunnel != null) {
+ boolean otherEndPointInterfaceOperational = ElanUtils
+ .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
+ if (otherEndPointInterfaceOperational) {
+ return true;
+ } else {
+ logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
+ otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
+ }
+ }
+ }
+ return false;
+ }
+
public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
BigInteger dpId = interfaceInfo.getDpId();
String elanName = elanInstance.getElanInstanceName();
logger.trace("ElanInterface Service is installed for interface:{}", ifName);
elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
+
+ if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
+ List<PhysAddress> macAddresses = ElanUtils
+ .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
+ if (macAddresses != null && !macAddresses.isEmpty()) {
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(),
+ dpId, macAddresses);
+ }
+ }
} else {
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
return mkMatches;
}
- public void updateElanBroadcastGroup(ElanInstance elanInfo) {
- int bucketId = 0;
- long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
-
- List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo
- .getElanInstanceName());
+ public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
+ 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 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());
- }
- }
- }
+ setupElanBroadcastGroups(elanInfo, dpn.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());
+ .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
for (L2GatewayDevice device : map.values()) {
String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
device.getHwvtepNodeId());
--- /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.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+ private String key;
+ private ElanInstance elanInfo;
+ private String interfaceName;
+ private InterfaceInfo interfaceInfo;
+ private ElanInterfaceManager dataChangeListener;
+
+ public ElanInterfaceRemoveWorker(String key, ElanInstance elanInfo, String interfaceName,
+ InterfaceInfo interfaceInfo, ElanInterfaceManager dataChangeListener) {
+ super();
+ this.key = key;
+ this.elanInfo = elanInfo;
+ this.interfaceName = interfaceName;
+ this.interfaceInfo = interfaceInfo;
+ this.dataChangeListener = dataChangeListener;
+ }
+
+ @Override
+ public String toString() {
+ return "ElanInterfaceRemoveWorker [key=" + key + ", elanInfo=" + elanInfo +
+ ", interfaceName=" + interfaceName
+ + ", interfaceInfo=" + interfaceInfo + "]";
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ dataChangeListener.removeElanInterface(elanInfo, interfaceName, interfaceInfo);
+ return futures;
+ }
+
+}
package org.opendaylight.vpnservice.elan.internal;
-import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.List;
+
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.DataStoreJobCoordinator;
+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.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
-import java.util.List;
-
public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
private DataBroker broker;
private IInterfaceManager interfaceManager;
this.interfaceManager = interfaceManager;
}
- private void handleVlanInterfaceOperationalStateChange(String interfaceName, boolean isStateUp) {
- //fetching the elanInstanceName from elan-interface config data-store
- ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
- if (elanInterface == null) {
- return;
- }
- ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
- InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName,
- InterfaceInfo.InterfaceType.VLAN_INTERFACE);
- if (interfaceInfo == null) {
- logger.warn("Interface {} doesn't exist in operational datastore", interfaceName);
- return;
- }
-
- logger.trace("ElanService Interface Operational state has changes for Interface:{}", interfaceName);
- elanInterfaceManager.handleInterfaceUpdated(interfaceInfo, elanInfo , isStateUp);
- }
-
@Override
protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
logger.trace("Received interface {} Down event", delIf);
interfaceInfo.setInterfaceName(interfaceName);
interfaceInfo.setInterfaceType(InterfaceInfo.InterfaceType.VLAN_INTERFACE);
interfaceInfo.setInterfaceTag(delIf.getIfIndex());
- elanInterfaceManager.removeElanService(elanInterface, interfaceInfo);
+ String elanInstanceName = elanInterface.getElanInstanceName();
+ ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceRemoveWorker removeWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInstance,
+ interfaceName, interfaceInfo, elanInterfaceManager);
+ coordinator.enqueueJob(elanInstanceName, removeWorker, ElanConstants.JOB_MAX_RETRIES);
}
@Override
protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
logger.trace("Operation Interface update event - Old: {}, New: {}", original, update);
String interfaceName = update.getName();
+ if (update.getType() == null) {
+ logger.trace("Interface type for interface {} is null", interfaceName);
+ return;
+ }
if(update.getType().equals(Tunnel.class)) {
if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
InternalTunnel internalTunnel = getTunnelState(interfaceName);
if (internalTunnel != null) {
- elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+ elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
}
}
- } else if(update.getType().equals(L2vlan.class)) {
- ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
- if(elanInterface == null) {
- logger.debug("No Elan Interface is created for the interface:{} ", interfaceName);
- return;
- }
- if (update.getOperStatus().equals(Interface.OperStatus.Up) && update.getAdminStatus() == Interface.AdminStatus.Up) {
- logger.trace("Operation Status for Interface:{} event state UP ", interfaceName);
- handleVlanInterfaceOperationalStateChange(interfaceName, true);
- } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
- logger.trace("Operation Status for Interface:{} event state DOWN ", interfaceName);
- handleVlanInterfaceOperationalStateChange(interfaceName, false);
- }
-
}
}
if(intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
InternalTunnel internalTunnel = getTunnelState(interfaceName);
if (internalTunnel != null) {
- elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+ elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(),
+ internalTunnel.getDestinationDPN());
}
}
}
public InternalTunnel getTunnelState(String interfaceName) {
InternalTunnel internalTunnel = null;
TunnelList tunnelList = ElanUtils.buildInternalTunnel(broker);
- if (tunnelList.getInternalTunnel() != null) {
+ if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
for (InternalTunnel tunnel : internalTunnels) {
if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
--- /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.internal;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElanInterfaceStateClusteredListener extends
+ AsyncClusteredDataChangeListenerBase<Interface, ElanInterfaceStateClusteredListener> implements AutoCloseable {
+ private DataBroker broker;
+ private ElanInterfaceManager elanInterfaceManager;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceStateClusteredListener.class);
+
+ public ElanInterfaceStateClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+ super(Interface.class, ElanInterfaceStateClusteredListener.class);
+ broker = db;
+ elanInterfaceManager = ifManager;
+ registerListener(db);
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), ElanInterfaceStateClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+ } catch (final Exception e) {
+ logger.error("Elan Interfaces DataChange listener registration fail!", e);
+ throw new IllegalStateException("ElanInterface registration Listener failed.", e);
+ }
+ }
+
+ @Override
+ public InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return ElanInterfaceStateClusteredListener.this;
+ }
+
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier, Interface original, final Interface update) {
+ add(identifier, update);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, final Interface intrf) {
+ if (intrf.getType() != null && intrf.getType().equals(Tunnel.class)) {
+ if (intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
+ final String interfaceName = intrf.getName();
+
+ ElanClusterUtils.runOnlyInLeaderNode(new Runnable() {
+ @Override
+ public void run() {
+ logger.debug("running external tunnel update job for interface {} added", interfaceName);
+ handleExternalTunnelUpdate(interfaceName, intrf);
+ }
+ });
+ }
+ }
+ }
+
+ private void handleExternalTunnelUpdate(String interfaceName, Interface update) {
+ ExternalTunnel externalTunnel = ElanUtils.getExternalTunnel(interfaceName, LogicalDatastoreType.CONFIGURATION);
+ if (externalTunnel != null) {
+ logger.debug("handling external tunnel update event for ext device dst {} src {} ",
+ externalTunnel.getDestinationDevice(), externalTunnel.getSourceDevice());
+ elanInterfaceManager.handleExternalTunnelStateEvent(externalTunnel, update);
+ } else {
+ logger.trace("External tunnel not found with interfaceName: {}", interfaceName);
+ }
+ }
+}
import org.opendaylight.vpnservice.mdsalutil.NWUtil;
import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
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.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.MacEntryBuilder;
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 {
ElanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), elanInstance.getMacTimeout(), macAddress);
BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
- ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, Arrays.asList(physAddress));
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+ Arrays.asList(physAddress));
} catch (Exception e) {
logger.trace("Failed to decode packet: {}", e);
}
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.elanmanager.api.IElanService;
import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
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.ElanClusterUtils;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
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.slf4j.Logger;
private ElanPacketInHandler elanPacketInHandler;
private ElanSmacFlowEventListener elanSmacFlowEventListener;
private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener;
+ private ElanInterfaceStateClusteredListener infStateChangeClusteredListener;
+ private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener;
private ElanNodeListener elanNodeListener;
private NotificationService notificationService;
private RpcProviderRegistry rpcProviderRegistry;
private ElanL2GatewayProvider elanL2GatewayProvider;
private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+ if (dataStoreJobCoordinator == null) {
+ dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+ }
+ return dataStoreJobCoordinator;
+ }
+
public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
rpcProviderRegistry = rpcRegistry;
elanStatusMonitor.reportStatus("STARTING");
try {
createIdPool();
+ getDataStoreJobCoordinator();
broker = session.getSALService(DataBroker.class);
ElanUtils.setDataBroker(broker);
elanInstanceManager.setDataBroker(broker);
elanInstanceManager.setIdManager(idManager);
elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
+ elanInstanceManager.setInterfaceManager(interfaceManager);
elanNodeListener = new ElanNodeListener(broker, mdsalManager);
elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
+ infStateChangeClusteredListener = new ElanInterfaceStateClusteredListener(broker, elanInterfaceManager);
+ elanDpnInterfaceClusteredListener = new ElanDpnInterfaceClusteredListener(broker, elanInterfaceManager);
+ ElanClusterUtils.setEntityOwnershipService(entityOwnershipService);
+ ElanClusterUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
elanInterfaceManager.registerListener();
this.entityOwnershipService = entityOwnershipService;
}
- public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
- }
-
public IInterfaceManager getInterfaceManager() {
return this.interfaceManager;
}
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();
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.CandidateAlreadyRegisteredException;
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.internal.ElanInterfaceManager;
import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepNodeListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
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.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.utils.clustering.EntityOwnerUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
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;
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;
+ private HwvtepPhysicalLocatorListener physicalLocatorListener;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
/**
* Instantiates a new elan l2 gateway 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();
-
+ dataStoreJobCoordinator = elanServiceProvider.getDataStoreJobCoordinator();
init();
LOG.info("ElanL2GatewayProvider Initialized");
ElanL2GwCacheUtils.createElanL2GwDeviceCache();
ElanL2GatewayUtils.setDataBroker(broker);
ElanL2GatewayUtils.setItmRpcService(itmRpcService);
+ ElanL2GatewayUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
ElanL2GatewayMulticastUtils.setBroker(broker);
ElanL2GatewayMulticastUtils.setElanInstanceManager(elanInstanceManager);
ElanL2GatewayMulticastUtils.setElanInterfaceManager(elanInterfaceManager);
+ ElanL2GatewayMulticastUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+ L2GatewayConnectionUtils.setElanInstanceManager(elanInstanceManager);
+ L2GatewayConnectionUtils.setBroker(broker);
+ L2GatewayConnectionUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
- this.torMacsListener = new HwvtepLocalUcastMacListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer);
- this.l2GwConnListener = new L2GatewayConnectionListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager);
- this.hwvtepNodeListener = new HwvtepNodeListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager, itmRpcService);
+ HwvtepRemoteMcastMacListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+ HwvtepLogicalSwitchListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+ this.torMacsListener = new HwvtepLocalUcastMacListener(broker);
+ this.l2GwConnListener = new L2GatewayConnectionListener(broker, elanInstanceManager);
+ this.hwvtepNodeListener = new HwvtepNodeListener(broker, elanInstanceManager, itmRpcService);
this.hwvtepNodeListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+
+ physicalLocatorListener = new HwvtepPhysicalLocatorListener(broker);
+ try {
+ EntityOwnerUtils.registerEntityCandidateForOwnerShip(entityOwnershipService,
+ HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ null/*listener*/);
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.error("failed to register the entity");
+ }
}
/*
--- /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.jobs;
+
+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.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+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.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.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.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class AssociateHwvtepToElanJob implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+ boolean createLogicalSwitch;
+ private static final Logger LOG = LoggerFactory.getLogger(AssociateHwvtepToElanJob.class);
+
+ public AssociateHwvtepToElanJob(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;
+ LOG.debug("created assosiate l2gw connection job for {} {} ", elanInstance.getElanInstanceName(),
+ l2GatewayDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return elanInstance.getElanInstanceName();
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ String elanInstanceName = elanInstance.getElanInstanceName();
+ LOG.debug("running assosiate l2gw connection job for {} {} ", elanInstanceName, hwvtepNodeId);
+
+ // Create Logical Switch if it's not created already in the device
+ if (createLogicalSwitch) {
+ LOG.info("creating logical switch {} for {} ", elanInstanceName, hwvtepNodeId);
+
+ ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance);
+ futures.add(lsCreateFuture);
+ } else {
+ String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstanceName);
+ LOG.info("{} is already created in {}; adding remaining configurations", logicalSwitchName, hwvtepNodeId);
+
+ LogicalSwitchAddedJob logicalSwitchAddedJob = new LogicalSwitchAddedJob(logicalSwitchName, l2Device,
+ l2GatewayDevice, defaultVlan);
+ return logicalSwitchAddedJob.call();
+ }
+
+ return futures;
+ }
+
+ private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance) {
+ final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(
+ elanInstance.getElanInstanceName());
+ String segmentationId = elanInstance.getVni().toString();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("logical switch {} is created on {} with VNI {}", logicalSwitchName,
+ l2GatewayDevice.getHwvtepNodeId(), segmentationId);
+ }
+ 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);
+ }
+ });
+ return lsCreateFuture;
+ }
+}
--- /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.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+
+/**
+ * The Job class to delete L2 gateway device local ucast macs from other Elan L2
+ * gateway devices.
+ */
+public class DeleteL2GwDeviceMacsFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+
+ /** The Constant JOB_KEY_PREFIX. */
+ private static final String JOB_KEY_PREFIX = "hwvtep:";
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(DeleteL2GwDeviceMacsFromElanJob.class);
+
+ /** The broker. */
+ private final DataBroker broker;
+
+ /** The elan name. */
+ private final String elanName;
+
+ /** The l2 gw device. */
+ private final L2GatewayDevice l2GwDevice;
+
+ /** The mac addresses. */
+ private final List<MacAddress> macAddresses;
+
+ /**
+ * Instantiates a new delete l2 gw device macs from elan job.
+ *
+ * @param broker
+ * the broker
+ * @param elanName
+ * the elan name
+ * @param l2GwDevice
+ * the l2 gw device
+ * @param macAddresses
+ * the mac addresses
+ */
+ public DeleteL2GwDeviceMacsFromElanJob(DataBroker broker, String elanName, L2GatewayDevice l2GwDevice,
+ List<MacAddress> macAddresses) {
+ this.broker = broker;
+ this.elanName = elanName;
+ this.l2GwDevice = l2GwDevice;
+ this.macAddresses = macAddresses;
+ }
+
+ public String getJobKey() {
+ return JOB_KEY_PREFIX + this.elanName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ LOG.debug("Deleting l2gw device [{}] macs from other l2gw devices for elan [{}]",
+ this.l2GwDevice.getHwvtepNodeId(), this.elanName);
+ final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(this.elanName);
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(this.elanName);
+ List<ListenableFuture<Void>> futures = Lists.newArrayList();
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(this.l2GwDevice.getHwvtepNodeId())
+ && !ElanL2GatewayUtils.areMLAGDevices(this.l2GwDevice, otherDevice)) {
+ final String hwvtepId = otherDevice.getHwvtepNodeId();
+ // never batch deletes
+ ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMacs(this.broker,
+ new NodeId(hwvtepId), logicalSwitchName, this.macAddresses);
+ Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ 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);
+ }
+ });
+ // TODO: why to create a new arraylist for uninstallFuture?
+ futures.addAll(Lists.newArrayList(uninstallFuture));
+ }
+ }
+ 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.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class DisAssociateHwvtepFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+ boolean isLastL2GwConnDeleted;
+
+ private static final Logger LOG = LoggerFactory.getLogger(DisAssociateHwvtepFromElanJob.class);
+
+ public DisAssociateHwvtepFromElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device, Integer defaultVlan, boolean isLastL2GwConnDeleted) {
+ this.broker = broker;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanInstance = elanInstance;
+ this.l2Device = l2Device;
+ this.defaultVlan = defaultVlan;
+ this.isLastL2GwConnDeleted = isLastL2GwConnDeleted;
+ LOG.info("created disassosiate l2gw connection job for {} {}", elanInstance.getElanInstanceName(),
+ l2GatewayDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return elanInstance.getElanInstanceName();
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ String elanName = elanInstance.getElanInstanceName();
+ String strHwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ NodeId hwvtepNodeId = new NodeId(strHwvtepNodeId);
+ LOG.info("running disassosiate l2gw connection job for {} {}", elanName, strHwvtepNodeId);
+
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+ // Remove remote MACs and vlan mappings from physical port
+ // Once all above configurations are deleted, delete logical
+ // switch
+ LOG.info("delete vlan bindings for {} {}", elanName, strHwvtepNodeId);
+ futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
+
+ if (isLastL2GwConnDeleted) {
+ LOG.info("delete remote ucast macs {} {}", elanName, strHwvtepNodeId);
+ futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
+
+ LOG.info("delete mcast mac for {} {}", elanName, strHwvtepNodeId);
+ futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
+ l2GatewayDevice));
+
+ LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
+ futures.addAll(ElanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+
+ LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
+ ElanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
+ ElanL2GatewayUtils.getLogicalSwitchFromElan(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.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepDeviceMcastMacUpdateJob implements Callable<List<ListenableFuture<Void>>> {
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceMcastMacUpdateJob.class);
+
+ String elanName;
+ L2GatewayDevice l2GatewayDevice;
+
+ public HwvtepDeviceMcastMacUpdateJob(String elanName, L2GatewayDevice l2GatewayDevice) {
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanName = elanName;
+ }
+
+ public String getJobKey() {
+ return elanName;
+ }
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ LOG.info("running update mcast mac entry job for {} {}",
+ elanName, l2GatewayDevice.getHwvtepNodeId());
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevice(elanName, l2GatewayDevice));
+ }
+
+}
--- /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.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Class LogicalSwitchAddedWorker.
+ */
+public class LogicalSwitchAddedJob implements Callable<List<ListenableFuture<Void>>> {
+ /** The logical switch name. */
+ private String logicalSwitchName;
+
+ /** The physical device. */
+ private Devices physicalDevice;
+
+ /** The l2 gateway device. */
+ private L2GatewayDevice elanL2GwDevice;
+
+ /** The default vlan id. */
+ private Integer defaultVlanId;
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchAddedJob.class);
+
+ public LogicalSwitchAddedJob(String logicalSwitchName, Devices physicalDevice, L2GatewayDevice l2GatewayDevice,
+ Integer defaultVlanId) {
+ this.logicalSwitchName = logicalSwitchName;
+ this.physicalDevice = physicalDevice;
+ this.elanL2GwDevice = l2GatewayDevice;
+ this.defaultVlanId = defaultVlanId;
+ LOG.debug("created logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return logicalSwitchName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ try {
+ LOG.debug("running logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
+
+ LOG.info("creating vlan bindings for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+ new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
+ LOG.info("creating mast mac entries for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
+
+ List<IpAddress> expectedPhyLocatorIps = Lists.newArrayList();
+ HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+ logicalSwitchName, elanL2GwDevice, expectedPhyLocatorIps,
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ LOG.info("adding remote ucast macs for {} {}", logicalSwitchName,
+ elanL2GwDevice.getHwvtepNodeId());
+ 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;
+ }
+ }
+
+}
--- /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.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * The Class LogicalSwitchDeletedJob.
+ */
+public class LogicalSwitchDeletedJob implements Callable<List<ListenableFuture<Void>>> {
+ private DataBroker broker;
+
+ /** The logical switch name. */
+ private String logicalSwitchName;
+
+ /** The physical device. */
+ private NodeId hwvtepNodeId;
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchDeletedJob.class);
+
+ public LogicalSwitchDeletedJob(DataBroker broker, NodeId hwvtepNodeId, String logicalSwitchName) {
+ this.broker = broker;
+ this.hwvtepNodeId = hwvtepNodeId;
+ this.logicalSwitchName = logicalSwitchName;
+ LOG.debug("created logical switch deleted job for {} on {}", logicalSwitchName, hwvtepNodeId);
+ }
+
+ public String getJobKey() {
+ return logicalSwitchName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ try {
+ LOG.debug("running logical switch deleted job for {} in {}", logicalSwitchName, hwvtepNodeId);
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
+ return futures;
+ } catch (Throwable e) {
+ LOG.error("failed to delete ls ", e);
+ return null;
+ }
+ }
+}
*/
package org.opendaylight.vpnservice.elan.l2gw.listeners;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
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.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
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;
+import com.google.common.collect.Lists;
+
/**
* A listener for Ucast MAC entries that are added/removed to/from an External Device (e.g., TOR).
*
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) {
+ public HwvtepLocalUcastMacListener(DataBroker broker) {
super(LocalUcastMacs.class, HwvtepLocalUcastMacListener.class);
this.broker = broker;
- this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
registerListener();
}
// Remove MAC from cache
elanL2GwDevice.removeUcastLocalMac(macRemoved);
- ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
- elanL2GwDevice, macRemoved); }
+ ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+ Lists.newArrayList(macRemoved.getMacEntryKey()));
+ }
@Override
protected void update(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
// Cache MAC for furthur processing later
elanL2GwDevice.addUcastLocalMac(macAdded);
- ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
- elanL2GwDevice, macAddress);
+ ElanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress);
}
@Override
*/
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.jobs.LogicalSwitchAddedJob;
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.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.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.util.concurrent.ListenableFuture;
-
/**
* The listener class for listening to {@code LogicalSwitches}
* add/delete/update.
/** The default vlan id. */
private Integer defaultVlanId;
+ /** Id of L2 Gateway connection responsible for this logical switch creation */
+ private Uuid l2GwConnId;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Instantiates a new hardware vtep logical switch listener.
*
* the physical device
* @param defaultVlanId
* the default vlan id
+ * @param l2GwConnId
+ * the l2 gateway connection id
*/
public HwvtepLogicalSwitchListener(L2GatewayDevice l2GatewayDevice, String logicalSwitchName,
- Devices physicalDevice, Integer defaultVlanId) {
+ Devices physicalDevice, Integer defaultVlanId, Uuid l2GwConnId) {
super(LogicalSwitches.class, HwvtepLogicalSwitchListener.class);
this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
this.logicalSwitchName = logicalSwitchName;
this.physicalDevice = physicalDevice;
this.l2GatewayDevice = l2GatewayDevice;
this.defaultVlanId = defaultVlanId;
+ this.l2GwConnId = l2GwConnId;
}
/*
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,
+ L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(
+ logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice, l2GwConnId);
+
+ LogicalSwitchAddedJob logicalSwitchAddedWorker = new LogicalSwitchAddedJob(
+ logicalSwitchName, physicalDevice, elanDevice, defaultVlanId);
+ dataStoreJobCoordinator.enqueueJob(logicalSwitchAddedWorker.getJobKey(), logicalSwitchAddedWorker,
SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
} catch (Exception 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
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.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;
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,
+ public HwvtepNodeListener(final DataBroker dataBroker, 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 void remove(InstanceIdentifier<Node> key, Node nodeDeleted) {
- LOG.debug("Received Node Remove Event: {}, {}", key, nodeDeleted.getNodeId().getValue());
+ String nodeId = nodeDeleted.getNodeId().getValue();
+ LOG.debug("Received Node Remove Event for {}", nodeId);
PhysicalSwitchAugmentation psAugmentation = nodeDeleted.getAugmentation(PhysicalSwitchAugmentation.class);
if (psAugmentation != null) {
String psName = psAugmentation.getHwvtepNodeName().getValue();
+ LOG.info("Physical switch {} removed from node {} event received", psName, nodeId);
+
L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
if (l2GwDevice != null) {
if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
+ LOG.debug("{} details removed from L2Gateway Cache", psName);
+ } else {
+ LOG.debug("{} details are not removed from L2Gateway Cache as it has L2Gateway refrence", psName);
}
+
l2GwDevice.setConnected(false);
ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
} else {
LOG.error("Unable to find L2 Gateway details for {}", psName);
}
+ } else {
+ LOG.trace("Received Node Remove Event for {} is not related to Physical switch; it's not processed",
+ nodeId);
}
}
@Override
protected void update(InstanceIdentifier<Node> key, Node nodeBefore, Node nodeAfter) {
- LOG.debug("Received Node Update Event: {}, {}, {}", key, nodeBefore, nodeAfter);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Received Node Update Event: Node Before: {}, Node After: {}", nodeBefore, nodeAfter);
+ }
}
@Override
protected void add(InstanceIdentifier<Node> key, Node nodeAdded) {
- LOG.debug("Received Node Add Event: {}, {}", key, nodeAdded.getNodeId().getValue());
+ String nodeId = nodeAdded.getNodeId().getValue();
+ LOG.debug("Received Node Add Event for {}", nodeId);
PhysicalSwitchAugmentation psAugmentation = nodeAdded.getAugmentation(PhysicalSwitchAugmentation.class);
if (psAugmentation != null) {
String psName = psAugmentation.getHwvtepNodeName().getValue();
+ LOG.info("Physical switch {} added to node {} event received", psName, nodeId);
+
L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
if (l2GwDevice == null) {
+ LOG.debug("{} details are not present in L2Gateway Cache; added now!", psName);
+
l2GwDevice = new L2GatewayDevice();
l2GwDevice.setDeviceName(psName);
L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
+ } else {
+ LOG.debug("{} details are present in L2Gateway Cache and same reference used for updates", psName);
}
+ l2GwDevice.setConnected(true);
String hwvtepNodeId = getManagedByNodeId(psAugmentation.getManagedBy());
l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
List<TunnelIps> tunnelIps = psAugmentation.getTunnelIps();
IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
l2GwDevice.addTunnelIp(tunnelIpAddr);
if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("L2Gateway {} associated for {} physical switch; creating ITM tunnels for {}",
+ l2GwDevice.getL2GatewayIds(), psName, tunnelIpAddr);
+ }
+
// It's a pre-provision scenario
// Initiate ITM tunnel creation
ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
List<L2gatewayConnection> l2GwConns = getAssociatedL2GwConnections(dataBroker,
l2GwDevice.getL2GatewayIds());
if (l2GwConns != null) {
+ LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
+
for (L2gatewayConnection l2GwConn : l2GwConns) {
- L2GatewayConnectionUtils.addL2GatewayConnection(dataBroker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager, l2GwConn, psName);
+ LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
+ l2GwConn.getL2gatewayId(), psName);
+
+ L2GatewayConnectionUtils.addL2GatewayConnection(l2GwConn, psName);
}
}
//TODO handle deleted l2gw connections while the device is offline
}
}
}
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("L2Gateway cache updated with below details: {}", l2GwDevice);
+ }
+ } else {
+ LOG.trace("Received Node Add Event for {} is not related to Physical switch; it's not processed", nodeId);
}
}
--- /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 com.google.common.collect.Lists;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+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.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Listener for physical locator presence in operational datastore
+ *
+ *
+ *
+ */
+public class HwvtepPhysicalLocatorListener extends
+ AsyncClusteredDataChangeListenerBase<TerminationPoint, HwvtepPhysicalLocatorListener> implements AutoCloseable {
+
+ private DataBroker broker;
+ private ListenerRegistration<DataChangeListener> lstnerRegistration;
+
+ private static final Logger logger = LoggerFactory.getLogger(HwvtepPhysicalLocatorListener.class);
+
+ public HwvtepPhysicalLocatorListener(DataBroker broker) {
+ super(TerminationPoint.class, HwvtepPhysicalLocatorListener.class);
+
+ this.broker = broker;
+ registerListener();
+ logger.debug("created HwvtepPhysicalLocatorListener");
+ }
+
+ static Map<InstanceIdentifier<TerminationPoint>, List<Runnable>> waitingJobsList = new ConcurrentHashMap<>();
+ static Map<InstanceIdentifier<TerminationPoint>, Boolean> teps = new ConcurrentHashMap<>();
+
+ public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier<TerminationPoint> key, Runnable runnable) {
+ if (teps.get(key) != null) {
+ logger.debug("physical locator already available {} running job ", key);
+ runnable.run();
+ return;
+ }
+ synchronized (HwvtepPhysicalLocatorListener.class) {
+ List<Runnable> list = waitingJobsList.get(key);
+ if (list == null) {
+ waitingJobsList.put(key, Lists.newArrayList(runnable));
+ } else {
+ list.add(runnable);
+ }
+ logger.debug("added the job to wait list of physical locator {}", key);
+ }
+ }
+
+ protected void registerListener() {
+ try {
+ lstnerRegistration = this.broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+ child(TerminationPoint.class), this, DataChangeScope.BASE);
+ } 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<TerminationPoint> identifier, TerminationPoint del) {
+ logger.trace("physical locator removed {}", identifier);
+ teps.remove(identifier);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint original, TerminationPoint update) {
+ logger.trace("physical locator available {}", identifier);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint add) {
+ logger.trace("physical locator available {}", identifier);
+ teps.put(identifier, true);
+ List<Runnable> runnableList = null;
+ synchronized (HwvtepPhysicalLocatorListener.class) {
+ runnableList = waitingJobsList.get(identifier);
+ waitingJobsList.remove(identifier);
+ }
+ if (runnableList != null) {
+ logger.debug("physical locator available {} running jobs ", identifier);
+ for (Runnable r : runnableList) {
+ r.run();
+ }
+ } else {
+ logger.debug("no jobs are waiting for physical locator {}", identifier);
+ }
+ }
+
+ @Override
+ protected InstanceIdentifier<TerminationPoint> getWildCardPath() {
+ return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+ child(TerminationPoint.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return HwvtepPhysicalLocatorListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return DataChangeScope.BASE;
+ }
+}
*/
package org.opendaylight.vpnservice.elan.l2gw.listeners;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
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.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.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.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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
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;
/** The node id. */
private NodeId nodeId;
+ private List<IpAddress> expectedPhyLocatorIps;
+
DataBroker broker;
String logicalSwitchName;
AtomicBoolean executeTask = new AtomicBoolean(true);
Callable<List<ListenableFuture<Void>>> taskToRun;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Instantiates a new remote mcast mac listener.
*
* @param broker
* the mdsal databroker reference
* @param logicalSwitchName
+ * the logical switch name
* @param l2GatewayDevice
* the l2 gateway device
+ * @param expectedPhyLocatorIps
+ * the expected phy locator ips
* @param task
* the task to be run upon data presence
* @throws Exception
+ * the exception
*/
public HwvtepRemoteMcastMacListener(DataBroker broker, String logicalSwitchName, L2GatewayDevice l2GatewayDevice,
- Callable<List<ListenableFuture<Void>>> task) throws Exception {
+ List<IpAddress> expectedPhyLocatorIps, 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 ");
+ this.expectedPhyLocatorIps = expectedPhyLocatorIps;
+ LOG.info("registering the listener for mcast mac ");
registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+ LOG.info("registered the listener for mcast mac ");
if (isDataPresentInOpDs(getWildCardPath())) {
- LOG.debug("mcast mac already present running the task ");
+ LOG.info("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;
+ private boolean isDataPresentInOpDs(InstanceIdentifier<RemoteMcastMacs> path) throws Exception {
+ Optional<RemoteMcastMacs> mac = null;
try {
mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
} catch (Throwable e) {
if (mac == null || !mac.isPresent()) {
return false;
}
+ if (this.expectedPhyLocatorIps != null && !this.expectedPhyLocatorIps.isEmpty()) {
+ RemoteMcastMacs remoteMcastMac = mac.get();
+ if (remoteMcastMac.getLocatorSet() == null || remoteMcastMac.getLocatorSet().isEmpty()) {
+ return false;
+ }
+ for (IpAddress ip : this.expectedPhyLocatorIps) {
+ boolean ipExists = ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(this.nodeId,
+ remoteMcastMac, ip);
+ if (!ipExists) {
+ LOG.trace("IP [{}] not found in RemoteMcastMacs for node [{}]", String.valueOf(ip.getValue()),
+ this.nodeId.getValue());
+ return false;
+ }
+ }
+ }
return true;
}
*/
@Override
protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
- LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
- mcastMac);
+ LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier, mcastMac);
+ // No isDataPresentInOpDs check is done as assuming all the expected phy
+ // locator ips will be available during add
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());
+
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), nodeId.getValue());
+ dataStoreJobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
} catch (Exception e) {
LOG.error("Failed to handle remote mcast mac - add: {}", e);
} finally {
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.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;
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) {
+ public L2GatewayConnectionListener(final DataBroker db, ElanInstanceManager elanInstanceManager) {
super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
broker = db;
- this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
this.elanInstanceManager = elanInstanceManager;
registerListener(db);
}
@Override
protected void add(final InstanceIdentifier<L2gatewayConnection> identifier, final L2gatewayConnection input) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Adding L2gatewayConnection : key: " + identifier + ", value=" + input);
+ LOG.trace("Adding L2gatewayConnection: {}", 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);
+ L2GatewayConnectionUtils.addL2GatewayConnection(input);
}
@Override
protected void remove(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection input) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Removing L2gatewayConnection : key: " + identifier + ", value=" + input);
+ LOG.trace("Removing L2gatewayConnection: {}", input);
}
- L2GatewayConnectionUtils.deleteL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
- elanInstanceManager, input);
+ L2GatewayConnectionUtils.deleteL2GatewayConnection(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);
+ LOG.trace("Updating L2gatewayConnection : original value={}, updated value={}", original, update);
}
}
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.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
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.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.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;
/** The elan interface manager. */
private static ElanInterfaceManager elanInterfaceManager;
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Sets the broker.
*
* @return the listenable future
*/
public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
- return updateMcastMacs(elanName, device, true/* updateThisDevice */);
+ return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
}
/**
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);
+ for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
+ prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
}
return transaction.submit();
} catch (Throwable e) {
return future;
}
+ public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
+ HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
+ dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
+ }
+
/**
- * Update mcast macs.
+ * Update remote mcast mac on elan l2 gw device.
+ *
+ * @param elanName
+ * the elan name
+ * @param device
+ * the device
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
+ return transaction.submit();
+ }
+
+ public static void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
+ L2GatewayDevice device) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elanName);
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+ List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
+ List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
+ preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ }
+
+ /**
+ * Update mcast macs for this elan.
+ * for all dpns in this elan recompute and update broadcast group
+ * for all l2gw devices in this elan recompute and update remote mcast mac entry
*
* @param elanName
* the elan name
* the update this device
* @return the listenable future
*/
- public static ListenableFuture<Void> updateMcastMacs(String elanName, L2GatewayDevice device,
- boolean updateThisDevice) {
+ public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
+ boolean updateThisDevice) {
SettableFuture<Void> ft = SettableFuture.create();
ft.set(null);
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
- elanInterfaceManager.updateElanBroadcastGroup(elanInstance);
+ elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
WriteTransaction transaction = broker.newWriteOnlyTransaction();
if (updateThisDevice) {
- updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
}
// TODO: Need to revisit below logic as logical switches might not be
- // created to configure RemoteMcastMac entry
+ // present to configure RemoteMcastMac entry
for (L2GatewayDevice otherDevice : devices.values()) {
if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
- updateRemoteMcastMac(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
+ preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
}
}
return transaction.submit();
* 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) {
+ private static void preapareRemoteMcastMacEntry(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 {
+ ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
+ remoteTepIps.remove(device.getTunnelIp());
+ remoteTepIps.addAll(dpnsTepIps);
+ if (dpnsTepIps.isEmpty()) {
// 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);
+ remoteTepIps.add(dhcpDesignatedSwitchTepIp);
HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
.createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
}
}
- putRemoteMcastMac(transaction, nodeId, logicalSwitchName, otherTepIps);
+ putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
- otherTepIps);
- return transaction;
+ remoteTepIps);
}
/**
/**
* Gets all the tep ips of dpns.
*
- * @param device
+ * @param l2GwDevice
* 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) {
*/
public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
L2GatewayDevice l2GatewayDevice) {
- ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(),
+ ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
l2GatewayDevice, false/* updateThisDevice */);
ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
String elanInstanceName) {
IpAddress tepIp = null;
- // TODO: Uncomment after DHCP changes are merged
-/* DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
+ DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
elanInstanceName);
if (desgSwitch != null) {
tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
new NodeId(l2GwDevice.getHwvtepNodeId()));
- }*/
+ }
return tepIp;
}
* the elan instance name
* @return the designated switch for external tunnel
*/
- // TODO: Uncomment after DHCP changes are merged
-/* public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
+ public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
String elanInstanceName) {
InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
.builder(DesignatedSwitchesForExternalTunnels.class)
return designatedSwitchForTunnelOptional.get();
}
return null;
- }*/
+ }
}
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
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.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchDeletedJob;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
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.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.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.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.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.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.locator.set.attributes.LocatorSet;
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.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.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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
*
*/
public class ElanL2GatewayUtils {
-
- private static DataBroker broker;
- private static ItmRpcService itmRpcService;
+ private static DataBroker broker;
+ private static ItmRpcService itmRpcService;
+ private static DataStoreJobCoordinator dataStoreJobCoordinator;
+ private static Timer LogicalSwitchDeleteJobTimer = new Timer();
+ private static final int LOGICAL_SWITCH_DELETE_DELAY = 120000;
+ private static ConcurrentMap<Pair<NodeId, String>, TimerTask> LogicalSwitchDeletedTasks =
+ new ConcurrentHashMap<Pair<NodeId, String>, TimerTask>();
private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
}
/**
- * Installs the given MAC as a remote mac in all external devices (as of
- * now, TORs) that participate in the given Elan.
+ * Sets DataStoreJobCoordinator
*
- * @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
+ * @param dsJobCoordinator
+ * the new dataStoreJobCoordinator
*/
- 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);
- }
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator dsJobCoordinator) {
+ dataStoreJobCoordinator = dsJobCoordinator;
}
/**
- * 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.
- *
+ * Installs dpn macs in external device.
+ * first it checks if the physical locator towards this dpn tep is present or not
+ * if the physical locator is present go ahead and add the ucast macs
+ * otherwise update the mcast mac entry to include this dpn tep ip
+ * and schedule the job to put ucast macs once the physical locator is programmed in device
* @param elanName
* the elan name
* @param lstElanInterfaceNames
* 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;
+ public static void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames,
+ BigInteger dpnId, NodeId externalNodeId) {
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+ externalNodeId.getValue());
+ if (elanL2GwDevice == null) {
+ LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
+ return;
}
-
IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, externalNodeId);
if (dpnTepIp == null) {
- return future;
+ LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}",
+ dpnId, externalNodeId);
+ return;
}
- 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);
+ RemoteMcastMacs remoteMcastMac = readRemoteMcastMac(externalNodeId, logicalSwitchName,
+ LogicalDatastoreType.OPERATIONAL);
+ boolean phyLocAlreadyExists = checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
+ dpnTepIp);
+ LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
+ phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
+ List<PhysAddress> staticMacs = null;
+ staticMacs = getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
+
+ if (phyLocAlreadyExists) {
+ scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+ return;
}
+ ElanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
+ scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+ }
- String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+ /**
+ * gets the macs addresses for elan interfaces
+ *
+ * @param lstElanInterfaceNames
+ * the lst elan interface names
+ * @return the list
+ */
+ private static List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
+ List<PhysAddress> result = new ArrayList<>();
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);
+ result.add(macEntry.getMacAddress());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check if phy locator already exists in remote mcast entry.
+ *
+ * @param nodeId
+ * the node id
+ * @param remoteMcastMac
+ * the remote mcast mac
+ * @param expectedPhyLocatorIp
+ * the expected phy locator ip
+ * @return true, if successful
+ */
+ public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
+ RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
+ if (remoteMcastMac != null) {
+ HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
+ HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
+ HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
+ if (remoteMcastMac.getLocatorSet() != null) {
+ for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
+ if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
+ LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
+ return true;
+ }
}
}
}
- LOG.debug("Installing macs in external device [{}] for dpn [{}], elan [{}], no of interfaces [{}]",
- externalNodeId.getValue(), dpnId, elanName, lstElanInterfaceNames.size());
- return transaction.submit();
+ return false;
+ }
+
+ /**
+ * Gets the remote mcast mac.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param datastoreType
+ * the datastore type
+ * @return the remote mcast mac
+ */
+ public static RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
+ LogicalDatastoreType datastoreType) {
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
+ RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
+ new MacAddress(ElanConstants.UNKNOWN_DMAC));
+ RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
+ remoteMcastMacsKey);
+ return remoteMcastMac;
}
/**
*/
public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+ .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
elanInstance.getElanInstanceName(), macAddresses);
* @param elan
* the elan
*/
- public static void installL2gwDeviceLocalMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
- String elanName = elan.getElanInstanceName();
- L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+ public static void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
+ L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
l2gwDeviceNodeId.getValue());
if (l2gwDevice == null) {
LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
return;
}
+ installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+ }
+
+ /**
+ * Install dmac flows on dpn.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param l2gwDevice
+ * the l2gw device
+ * @param elan
+ * the elan
+ */
+ public static void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan) {
+ String elanName = elan.getElanInstanceName();
+
List<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
- ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDeviceNodeId.getValue(), elan.getElanTag(),
+ //TODO batch these ops
+ ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDevice.getHwvtepNodeId(), elan.getElanTag(),
elan.getVni(), localUcastMac.getMacEntryKey().getValue(), elanName);
}
+ LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
+ l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, 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) {
+ /**
+ * Install elan l2gw devices local macs in dpn.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param elan
+ * the elan
+ */
+ public static void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elan.getElanInstanceName());
+ if (elanL2GwDevicesFromCache != null) {
+ for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
+ installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+ }
+ } else {
+ LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
+ }
+ }
+
+ public static void installL2GwUcastMacInElan(final ElanInstance elan,
+ final 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);
+ final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+ if (elanDpns != null && elanDpns.size() > 0) {
+ String jobKey = elan.getElanInstanceName() + ":" + macToBeAdded;
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+ "install l2gw mcas in dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ for (DpnInterfaces elanDpn : elanDpns) {
+ //TODO batch the below call
+ fts.addAll(ElanUtils.installDmacFlowsToExternalRemoteMac(elanDpn.getDpId(),
+ 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);
- }
- });
+ return fts;
+ }
+ });
}
-
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>() {
+ String jobKey = "hwvtep:"+elan.getElanInstanceName() + ":" + macToBeAdded;
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+ "install remote ucast macs in l2gw device",
+ new Callable<List<ListenableFuture<Void>>>() {
@Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId);
+ public List<ListenableFuture<Void>> call() throws Exception {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+ ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
+
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ 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));
+ final String logicalSwitchName = elanInstanceName;
+
+ ListenableFuture<Void> ft = HwvtepUtils.installUcastMacs(
+ broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
+ //TODO batch the above call
+ Futures.addCallback(ft, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ LOG.trace("Successful in initiating ucast_remote_macs addition" +
+ "related to {} in {}", logicalSwitchName, 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(String.format("Failed adding ucast_remote_macs related to " +
+ "%s in %s", logicalSwitchName, hwvtepId), error);
+ };
+ });
+ fts.add(ft);
+ }
}
- }
+ return fts;
+ }});
+ }
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to install DMAC entry", error);
- }
- });
+ /**
+ * Un install l2 gw ucast mac from elan.
+ *
+ * @param elan
+ * the elan
+ * @param l2GwDevice
+ * the l2 gw device
+ * @param macAddresses
+ * the mac addresses
+ */
+ public static void unInstallL2GwUcastMacFromElan(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+ final List<MacAddress> macAddresses) {
+ if (macAddresses == null || macAddresses.isEmpty()) {
+ return;
+ }
+ final String elanName = 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
+ for (final MacAddress mac : macAddresses) {
+ final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+ if (elanDpns != null && !elanDpns.isEmpty()) {
+ String jobKey = elanName + ":" + mac.getValue();
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ for (DpnInterfaces elanDpn : elanDpns) {
+ BigInteger dpnId = elanDpn.getDpId();
+ // never batch deletes
+ fts.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+ l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+ }
+ return fts;
+ }
+ });
}
}
- }
- 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();
+ DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(broker, elanName, l2GwDevice,
+ macAddresses);
+ ElanClusterUtils.runOnlyInLeaderNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+ }
- // 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());
+ /**
+ * Delete elan l2 gateway devices ucast local macs from dpn.
+ *
+ * @param elanName
+ * the elan name
+ * @param dpnId
+ * the dpn id
+ */
+ public static void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+ if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
+ LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
+ return;
+ }
+ final ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
+ if (elan == null) {
+ LOG.error("Could not find Elan by name: {}", elanName);
+ return;
+ }
+ LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
+
+ final Long elanTag = elan.getElanTag();
+ for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
+ List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GwDevice);
+ if (localMacs != null && !localMacs.isEmpty()) {
+ for (final MacAddress mac : localMacs) {
+ String jobKey = elanName + ":" + mac.getValue();
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> futures = Lists.newArrayList();
- 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());
- }
+ futures.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
+ l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+ return futures;
+ }
+ });
}
+ }
+ }
+ }
+ /**
+ * Gets the l2 gw device local macs.
+ *
+ * @param l2gwDevice
+ * the l2gw device
+ * @return the l2 gw device local macs
+ */
+ public static List<MacAddress> getL2GwDeviceLocalMacs(L2GatewayDevice l2gwDevice) {
+ List<MacAddress> macs = new ArrayList<>();
+ if (l2gwDevice == null) {
+ return macs;
+ }
+ List<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+ if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
+ macs = Lists.transform(lstUcastLocalMacs, new Function<LocalUcastMacs, MacAddress>() {
@Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to uninstall DMAC flows", error);
+ public MacAddress apply(LocalUcastMacs localUcastMac) {
+ return (localUcastMac != null) ? localUcastMac.getMacEntryKey() : null;
}
});
}
-
- 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);
- }
- });
- }
- }
+ return macs;
}
/**
List<MacAddress> lstL2GatewayDeviceMacs = new ArrayList<>();
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
if (elanL2GwDevicesFromCache != null) {
for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) {
String logicalSwitchName = getLogicalSwitchFromElan(elanName);
NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
- List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName,
+ List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName,
l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
- List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName,
+ List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
* 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) {
+ public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured,
+ NodeId hwVtepNodeId, String logicalSwitchName) {
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
if (elanL2GwDevicesFromCache != null) {
for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
* 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) {
+ public static List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured,
+ NodeId hwVtepNodeId, String logicalSwitchName) {
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
MacTable macTable = ElanUtils.getElanMacTable(elanName);
* @return the external tunnel interface name
*/
public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
String tunnelInterfaceName = null;
try {
Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
.getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
- .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+ .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
if (rpcResult.isSuccessful()) {
* @return the l2 gateway connection job key
*/
public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
- return new StringBuilder(nodeId).append(logicalSwitchName).toString();
+ return logicalSwitchName;
}
public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
* the elan name
* @return the listenable future
*/
- public static List<ListenableFuture<Void>> deleteL2GatewayDeviceUcastLocalMacsFromElan(
- L2GatewayDevice l2GatewayDevice, String elanName) {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
+ public static List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+ String elanName) {
+ LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(), 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));
- }
- }
- }
+ List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GatewayDevice);
+ unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs);
return futures;
}
return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
}
+ public static void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
+ List<PhysAddress> staticMacAddresses) {
+ ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elanName);
+ for (final L2GatewayDevice externalDevice : elanDevices.values()) {
+ scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
+ }
+ }
+
+ public static void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
+ final List<PhysAddress> staticMacAddresses,
+ final L2GatewayDevice externalDevice) {
+ NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
+ final IpAddress dpnTepIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpId, nodeId);
+ LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
+ if (dpnTepIp == null) {
+ LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
+ return;
+ }
+ TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(
+ dpnTepIp.getIpv4Address().getValue());
+ InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId
+ (nodeId, tpKey);
+
+ HwvtepPhysicalLocatorListener.runJobAfterPhysicalLocatorIsAvialable(tpPath, new Runnable() {
+ @Override
+ public void run() {
+ HwvtepUtils.installUcastMacs(broker,
+ externalDevice.getHwvtepNodeId(), staticMacAddresses,
+ elanName, dpnTepIp);
+ }
+ });
+ }
+
+ public static void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+ TimerTask logicalSwitchDeleteTask = new TimerTask() {
+ @Override
+ public void run() {
+ LogicalSwitchDeletedJob logicalSwitchDeletedJob = new LogicalSwitchDeletedJob(broker, hwvtepNodeId,
+ lsName);
+ ElanL2GatewayUtils.dataStoreJobCoordinator.enqueueJob(logicalSwitchDeletedJob.getJobKey(),
+ logicalSwitchDeletedJob, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ }
+ };
+ Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+ LogicalSwitchDeletedTasks.putIfAbsent(nodeIdLogicalSwitchNamePair, logicalSwitchDeleteTask);
+ LogicalSwitchDeleteJobTimer.schedule(logicalSwitchDeleteTask, LOGICAL_SWITCH_DELETE_DELAY);
+ }
+
+ public static void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+ Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+ TimerTask logicalSwitchDeleteTask = LogicalSwitchDeletedTasks.get(nodeIdLogicalSwitchNamePair);
+ if (logicalSwitchDeleteTask != null) {
+ LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
+ logicalSwitchDeleteTask.cancel();
+ LogicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
+ }
+ }
}
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.jobs.AssociateHwvtepToElanJob;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
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.elan.utils.ElanClusterUtils;
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.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);
+ private static DataBroker broker;
+ private static ElanInstanceManager elanInstanceManager;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static void setBroker(DataBroker broker) {
+ L2GatewayConnectionUtils.broker = broker;
+ }
+
+ public static void setElanInstanceManager(ElanInstanceManager elanInstanceManager) {
+ L2GatewayConnectionUtils.elanInstanceManager = elanInstanceManager;
+ }
+
public static boolean isGatewayAssociatedToL2Device(L2GatewayDevice l2GwDevice) {
return (l2GwDevice.getL2GatewayIds().size() > 0);
}
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(L2gatewayConnection input) {
+ addL2GatewayConnection(input, null/*deviceName*/);
}
- public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
- L2gatewayConnection input, String l2GwDeviceName) {
+ public static void addL2GatewayConnection(L2gatewayConnection input, String l2GwDeviceName) {
+ LOG.info("Adding L2gateway Connection with ID: {}", input.getKey().getUuid());
+
Uuid networkUuid = input.getNetworkId();
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
if (elanInstance == null || elanInstance.getVni() == null) {
if (l2Gateway == null) {
LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
} else {
- associateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
- l2Gateway, input.getSegmentId(), l2GwDeviceName);
+ associateHwvtepsToElan(elanInstance, l2Gateway, input, l2GwDeviceName);
}
}
}
- public static void deleteL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
- L2gatewayConnection input) {
+ public static void deleteL2GatewayConnection(L2gatewayConnection input) {
+ LOG.info("Deleting L2gateway Connection with ID: {}", input.getKey().getUuid());
+
Uuid networkUuid = input.getNetworkId();
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
if (elanInstance == null) {
if (l2Gateway == null) {
LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
} else {
- disAssociateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
- l2Gateway, input.getSegmentId());
+ disAssociateHwvtepsFromElan(elanInstance, l2Gateway, input);
}
}
}
- private static void disAssociateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
- L2gateway l2Gateway, final Integer defaultVlan) {
- final String elanName = elanInstance.getElanInstanceName();
+ private static void disAssociateHwvtepsFromElan(ElanInstance elanInstance, L2gateway l2Gateway,
+ L2gatewayConnection input) {
+ String elanName = elanInstance.getElanInstanceName();
+ Integer defaultVlan = input.getSegmentId();
List<Devices> l2Devices = l2Gateway.getDevices();
- for (final Devices l2Device : l2Devices) {
- final String l2DeviceName = l2Device.getDeviceName();
- final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ for (Devices l2Device : l2Devices) {
+ String l2DeviceName = l2Device.getDeviceName();
+ 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);
- }
- });
+ String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ boolean isLastL2GwConnDeleted = false;
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ if (isLastL2GwConnBeingDeleted(elanL2GwDevice)) {
+ LOG.debug("Elan L2Gw Conn cache removed for id {}", hwvtepNodeId);
+ ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ isLastL2GwConnDeleted = true;
+ } else {
+ Uuid l2GwConnId = input.getKey().getUuid();
+ LOG.debug("Elan L2Gw Conn cache with id {} is being referred by other L2Gw Conns; so only " +
+ "L2 Gw Conn {} reference is removed", hwvtepNodeId, l2GwConnId);
+ elanL2GwDevice.removeL2GatewayId(l2GwConnId);
+ }
+
+ DisAssociateHwvtepFromElanJob disAssociateHwvtepToElanJob = new DisAssociateHwvtepFromElanJob(broker,
+ elanL2GwDevice, elanInstance, l2Device, defaultVlan, isLastL2GwConnDeleted);
+ ElanClusterUtils.runOnlyInLeaderNode(disAssociateHwvtepToElanJob.getJobKey(),
+ "remove l2gw connection job ",
+ disAssociateHwvtepToElanJob);
} else {
- LOG.error("could not handle connection delete L2 Gateway device with id {} is not present",
- l2DeviceName);
+ LOG.info("L2GwConn delete is not handled for device with id {} as it's not connected", 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();
+ private static void associateHwvtepsToElan(ElanInstance elanInstance,
+ L2gateway l2Gateway, L2gatewayConnection input, String l2GwDeviceName) {
+ String elanName = elanInstance.getElanInstanceName();
+ Integer defaultVlan = input.getSegmentId();
+ Uuid l2GwConnId = input.getKey().getUuid();
List<Devices> l2Devices = l2Gateway.getDevices();
- for (final Devices l2Device : l2Devices) {
- final String l2DeviceName = l2Device.getDeviceName();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Associating ELAN {} with L2Gw Conn Id {} having below L2Gw devices {}", elanName, l2GwConnId,
+ l2Devices);
+ }
+
+ for (Devices l2Device : l2Devices) {
+ 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)) {
+ LOG.debug("Associating Hwvtep to ELAN is not been processed for {}; as only {} got connected now!",
+ l2DeviceName, l2GwDeviceName);
continue;
}
- final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
if (isL2GwDeviceConnected(l2GatewayDevice)) {
+ NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+
+ // Delete pending delete logical switch task if scheduled
+ ElanL2GatewayUtils.cancelDeleteLogicalSwitch(hwvtepNodeId,
+ ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+
// Add L2 Gateway device to 'ElanL2GwDevice' cache
- final boolean createLogicalSwitch;
+ boolean createLogicalSwitch;
LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
- new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
+ hwvtepNodeId, elanName);
if (logicalSwitch == null) {
- final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
- l2GatewayDevice, elanName, l2Device, defaultVlan);
+ HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+ l2GatewayDevice, elanName, l2Device, defaultVlan, l2GwConnId);
hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
createLogicalSwitch = true;
} else {
- addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice);
+ addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice, l2GwConnId);
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<>();
+ AssociateHwvtepToElanJob associateHwvtepToElanJob = new AssociateHwvtepToElanJob(broker,
+ l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
- final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+ ElanClusterUtils.runOnlyInLeaderNode( associateHwvtepToElanJob.getJobKey() ,
+ "create logical switch in hwvtep topo",
+ associateHwvtepToElanJob);
- // 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;
- }}
- );
+ LOG.info("L2GwConn create is not handled for device with id {} as it's not connected", l2DeviceName);
}
-
- 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);
- }
- }
+ public static L2GatewayDevice addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice,
+ Uuid l2GwConnId) {
+ String l2gwDeviceNodeId = l2GatewayDevice.getHwvtepNodeId();
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, l2gwDeviceNodeId);
+ if (elanL2GwDevice == null) {
+ elanL2GwDevice = new L2GatewayDevice();
+ elanL2GwDevice.setHwvtepNodeId(l2gwDeviceNodeId);
+ elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
+ elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
+ ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
+ LOG.debug("Elan L2GwConn cache created for hwvtep id {}", l2gwDeviceNodeId);
+ } else {
+ LOG.debug("Elan L2GwConn cache already exists for hwvtep id {}; updating L2GwConn id {} to it",
+ l2gwDeviceNodeId, l2GwConnId);
+ }
+ elanL2GwDevice.addL2GatewayId(l2GwConnId);
- @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;
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Elan L2GwConn cache updated with below details: {}", elanL2GwDevice);
}
+ return elanL2GwDevice;
}
- 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;
- }
+ private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
+ }
- @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;
- }
+ protected static boolean isLastL2GwConnBeingDeleted(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice.getL2GatewayIds().size() == 1);
}
}
--- /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.utils;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ElanClusterUtils {
+ private static final Logger logger = LoggerFactory.getLogger(ElanClusterUtils.class);
+
+ private static EntityOwnershipService eos;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+ eos = entityOwnershipService;
+ }
+
+ public static void runOnlyInLeaderNode(Runnable job) {
+ runOnlyInLeaderNode(job, "");
+ }
+
+ public static void runOnlyInLeaderNode(final Runnable job, final String jobDescription) {
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ job.run();
+ } else {
+ logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+ }
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to identity cluster owner ", error);
+ }
+ });
+ }
+
+ public static void runOnlyInLeaderNode(String jobKey, Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+ runOnlyInLeaderNode(jobKey, "", dataStoreJob);
+ }
+
+ public static void runOnlyInLeaderNode(final String jobKey, final String jobDescription,
+ final Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ logger.trace("scheduling job {} ", jobDescription);
+ dataStoreJobCoordinator.enqueueJob(jobKey, dataStoreJob,
+ SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+ }
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to identity cluster owner for job "+jobDescription, error);
+ }
+ });
+ }
+}
public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+ public static final int JOB_MAX_RETRIES = 3;
}
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import org.apache.commons.lang3.StringUtils;
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.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.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
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.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
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.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
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.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
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.RemoveTerminatingServiceActionsInputBuilder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ElanUtils {
- private static final ArrayList EMPTY_LIST = new ArrayList();
-
private static OdlInterfaceRpcService interfaceMgrRpcService;
private static ItmRpcService itmRpcService;
synchronized (macAddress) {
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);
}
}
* @param interfaceInfo
* @param mdsalApiManager
*/
- private static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
+ public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
BigInteger dpId = interfaceInfo.getDpId();
int lportTag = interfaceInfo.getInterfaceTag();
Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
if (dpns == null) {
- return EMPTY_LIST;
+ return Collections.emptyList();
}
return dpns;
}
}
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, srcdpId);
}
* @return the list
*/
public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
.setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
* @return the external itm egress action
*/
public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
- .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).build();
+ .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).setTunnelType(TunnelTypeVxlan.class).build();
Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
itmRpcService.getExternalTunnelInterfaceName(input);
try {
*/
public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
long serviceTag) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
sourceDpnId, destinationDpnId, serviceTag);
-
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
- .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
+ .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
try {
if (output.get().isSuccessful()) {
return null;
}
+ /**
+ * Gets the external tunnel.
+ *
+ * @param sourceDevice
+ * the source device
+ * @param destinationDevice
+ * the destination device
+ * @param datastoreType
+ * the datastore type
+ * @return the external tunnel
+ */
+ public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
+ LogicalDatastoreType datastoreType) {
+ ExternalTunnel externalTunnel = null;
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class ;
+ InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
+ .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
+ Optional<ExternalTunnel> tunnelList = read(dataBroker, datastoreType, iid);
+ if (tunnelList.isPresent()) {
+ externalTunnel = tunnelList.get();
+ }
+ return externalTunnel;
+ }
+
+ /**
+ * Gets the external tunnel.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param datastoreType
+ * the datastore type
+ * @return the external tunnel
+ */
+ public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
+ ExternalTunnel externalTunnel = null;
+ List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
+ for (ExternalTunnel tunnel : externalTunnels) {
+ if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+ externalTunnel = tunnel;
+ break;
+ }
+ }
+ return externalTunnel;
+ }
+
+ /**
+ * Gets the all external tunnels.
+ *
+ * @return the all external tunnels
+ */
+ public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
+ List<ExternalTunnel> result = null;
+ InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+ Optional<ExternalTunnelList> tunnelList = read(dataBroker, datastoreType, iid);
+ if (tunnelList.isPresent()) {
+ result = tunnelList.get().getExternalTunnel();
+ }
+ if (result == null) {
+ result = Collections.emptyList();
+ }
+ return result;
+ }
+
/**
* 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
return dpId;
}
+ /**
+ * Checks if is interface operational.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param dataBroker
+ * the data broker
+ * @return true, if is interface operational
+ */
+ public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
+ if (StringUtils.isBlank(interfaceName)) {
+ return false;
+ }
+ Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
+ if (ifState == null) {
+ return false;
+ }
+ return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
+ }
+
+ /**
+ * Gets the interface state from operational ds.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param dataBroker
+ * the data broker
+ * @return the interface state from oper ds
+ */
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
+ String interfaceName, DataBroker dataBroker) {
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
+ interfaceName);
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
+ .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+ if (ifStateOptional.isPresent()) {
+ return ifStateOptional.get();
+ }
+ return null;
+ }
+
+ /**
+ * Creates the interface state instance identifier.
+ *
+ * @param interfaceName
+ * the interface name
+ * @return the instance identifier
+ */
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
+ String interfaceName) {
+ InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
+ .builder(InterfacesState.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+ interfaceName));
+ return idBuilder.build();
+ }
+
}
provider.setItmManager(getItmmanagerDependency());
provider.setIdManager(idManager);
provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
- provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
}
}
}
- 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
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../../commons/config-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>alarmmanager</artifactId>
+ <version>${vpnservices.version}</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+ <osgi.version>5.0.0</osgi.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>fcaps-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${maven-bundle-plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.alarmmanager.Activator</Bundle-Activator>
+ <Export-Package>org.opendaylight.vpnservice.fcapsmanager.alarmmanager*;version=${project.version}</Export-Package>
+ <Import-Package>*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ 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.fcapsmanager.alarmmanager;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+ static Logger s_logger = LoggerFactory.getLogger(Activator.class);
+ private Runnable listener;
+ private Thread listenerThread;
+
+ public void start(BundleContext context) {
+ s_logger.info("Starting alarmmanager bundle");
+ AlarmNotificationListeners notificationListeners = new AlarmNotificationListeners(context);
+ try {
+ listener = notificationListeners;
+ listenerThread = new Thread(listener);
+ listenerThread.start();
+ } catch (Exception e) {
+ s_logger.error("Exception in alarm thread {}", e);
+ }
+ }
+
+ public void stop(BundleContext context) {
+ s_logger.info("Stopping alarmmanager bundle");
+ }
+}
\ 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.fcapsmanager.alarmmanager;
+
+import javax.management.*;
+import java.lang.management.ManagementFactory;
+import java.util.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.vpnservice.fcapsmanager.AlarmServiceFacade;
+
+public class AlarmNotificationListeners implements Runnable {
+ static Logger s_logger = LoggerFactory.getLogger(AlarmNotificationListeners.class);
+ private MBeanServer mbs = null;
+ private static String DOMAIN = "SDNC.FM";
+
+ private final DelegateListener delegateListener = new DelegateListener();
+ private BundleContext context = null;
+
+ public AlarmNotificationListeners(BundleContext context) {
+ this.context=context;
+ }
+
+ /**
+ * Platform dependent bundle injects its handle and it is retrieved in the method
+ */
+ private AlarmServiceFacade getAlarmServiceSPI (){
+ AlarmServiceFacade service =null;
+ if(context != null) {
+ try {
+ ServiceReference<?> serviceReference = context.
+ getServiceReference(AlarmServiceFacade.class.getName());
+ service = (AlarmServiceFacade) context.
+ getService(serviceReference);
+ }catch (NullPointerException ex){
+ service = null;
+ }catch (Exception e){
+ s_logger.error("Exception {} occurred in getting AlarmServiceSPI",e);
+ }
+ }
+ return service;
+ }
+
+ /**
+ * Gets register notification when a mbean is registered in platform Mbeanserver and checks if it is alarm mbean and add attribute notification listener to it.
+ * Gets attribute notification when alarm mbean is updated by the application.
+ */
+ public class DelegateListener implements NotificationListener {
+ public void handleNotification(Notification notification, Object obj) {
+ if (notification instanceof MBeanServerNotification) {
+ MBeanServerNotification msnotification =
+ (MBeanServerNotification) notification;
+ String nType = msnotification.getType();
+ ObjectName mbn = msnotification.getMBeanName();
+
+ if (nType.equals("JMX.mbean.registered")) {
+ if (mbn.toString().contains(DOMAIN)) {
+ s_logger.debug("Received registeration of Mbean "+mbn);
+ try {
+ mbs.addNotificationListener(mbn,delegateListener, null, null);
+ s_logger.debug("Added attribute notification listener for Mbean "+ mbn);
+ } catch (InstanceNotFoundException e) {
+ s_logger.error("Exception while adding attribute notification of mbean {}", e);
+ }
+ }
+ }
+
+ if (nType.equals("JMX.mbean.unregistered")) {
+ if (mbn.toString().contains(DOMAIN)) {
+ s_logger.debug("Time: " + msnotification.getTimeStamp() + "MBean " + msnotification.getMBeanName()+" unregistered successfully");
+ }
+ }
+ }
+ else if (notification instanceof AttributeChangeNotification) {
+ AttributeChangeNotification acn =
+ (AttributeChangeNotification) notification;
+
+ s_logger.debug("Received attribute notification of Mbean: "
+ + notification.getSource()
+ + " for attribute:" + acn.getAttributeName() );
+
+ if(acn.getAttributeName().toString().equals("raiseAlarmObject")){
+
+ String value=acn.getNewValue().toString();
+ value = value.replace(value.charAt(0), ' ');
+ value = value.replace(value.charAt(value.lastIndexOf("]")), ' ');
+
+ String[] args =value.split(",");
+ s_logger.debug("Receive attribute value :"+args[0].trim()+args[1].trim()+args[2].trim());
+ if(getAlarmServiceSPI() != null ) {
+ getAlarmServiceSPI().raiseAlarm(args[0].trim(),args[1].trim(),args[2].trim());
+ } else {
+ s_logger.debug("Alarm service not available");
+ }
+
+ } else if(acn.getAttributeName().toString().equals("clearAlarmObject")){
+
+ String value=acn.getNewValue().toString();
+ value = value.replace(value.charAt(0), ' ');
+ value = value.replace(value.charAt(value.lastIndexOf("]")), ' ');
+
+ String[] args =value.split(",");
+ s_logger.debug("Receive attribute value :"+args[0].trim()+args[1].trim()+args[2].trim());
+ if(getAlarmServiceSPI() != null )
+ getAlarmServiceSPI().clearAlarm(args[0].trim(), args[1].trim(), args[2].trim());
+ else
+ s_logger.debug("Alarm service not available");
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the platform MBeanServer instance and registers to get notification whenever alarm mbean is registered in the mbeanserver
+ */
+ @Override
+ public void run() {
+ mbs = ManagementFactory.getPlatformMBeanServer();
+
+ queryMbeans();
+
+ ObjectName delegate = null;
+ try {
+ delegate = new ObjectName("JMImplementation:type=MBeanServerDelegate");
+ } catch (MalformedObjectNameException e) {
+ e.printStackTrace();
+ }
+ NotificationFilterSupport filter = new NotificationFilterSupport();
+ filter.enableType("JMX.mbean.registered");
+ filter.enableType("JMX.mbean.unregistered");
+
+ try {
+ mbs.addNotificationListener(delegate, delegateListener, filter, null);
+ s_logger.debug("Added registeration listener for Mbean {}",delegate);
+ } catch (InstanceNotFoundException e) {
+ s_logger.error("Failed to add registeration listener {}", e);
+ }
+
+ waitForNotification();
+ }
+
+ /**
+ * Pre-provisioning case to handle all alarm mbeans which are registered before installation of framework bundle
+ * Queries the platform Mbeanserver to retrieve registered alarm mbean and add attribute notification listener to it
+ */
+ public void queryMbeans() {
+
+ Set<ObjectName> names =
+ new TreeSet<ObjectName>(mbs.queryNames(null, null));
+ s_logger.debug("Queried MBeanServer for MBeans:");
+ for (ObjectName beanName : names) {
+ if(beanName.toString().contains(DOMAIN)){
+ try {
+ mbs.addNotificationListener(beanName,delegateListener, null, null);
+ s_logger.debug("Added attribute notification listener for Mbean "+ beanName);
+ } catch (InstanceNotFoundException e) {
+ s_logger.error("Failed to add attribute notification for Mbean {}", e);
+ }
+ }
+ }
+ }
+ public void waitForNotification() {
+ while(true){
+ try {
+ Thread.sleep(50);
+ }
+ catch(Exception ex){
+ ex.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../../commons/config-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>countermanager</artifactId>
+ <version>${vpnservices.version}</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+ <osgi.version>5.0.0</osgi.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>fcaps-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${maven-bundle-plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.countermanager.Activator</Bundle-Activator>
+ <Export-Package>org.opendaylight.vpnservice.fcapsmanager.countermanager*;version=${project.version}</Export-Package>
+ <Import-Package>*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ 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.fcapsmanager.countermanager;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ReflectionException;
+import java.io.IOException;
+
+public class Activator implements BundleActivator {
+ private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Activator.class);
+ private Runnable listener;
+ private Thread listenerThread;
+
+ public void start(BundleContext context) throws InstanceNotFoundException, MalformedObjectNameException, MBeanException, ReflectionException, IOException {
+ LOG.info("Starting countermanager bundle ");
+ PMRegistrationListener notificationListeners = new PMRegistrationListener(context);
+ try {
+ listener = notificationListeners;
+ listenerThread = new Thread(listener);
+ listenerThread.start();
+ } catch (Exception e) {
+ LOG.error("Exception in counter thread {}", e);
+ }
+ }
+
+ public void stop(BundleContext context) {
+ LOG.info("Stopping countermanager bundle ");
+ }
+}
\ 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.fcapsmanager.countermanager;
+
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationFilterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.osgi.framework.BundleContext;
+import org.slf4j.LoggerFactory;
+
+public class PMRegistrationListener implements Runnable {
+ private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(PMRegistrationListener.class);
+ static MBeanServer mbs = null;
+
+ private static String DOMAIN = "SDNC.PM";
+ public static HashSet<ObjectName> beanNames = new HashSet<ObjectName>();
+ private BundleContext context = null;
+
+ public PMRegistrationListener(BundleContext context){
+ this.context=context;
+ }
+
+ /**
+ * Gets register notification when a mbean is registered in platform Mbeanserver and checks if it is counter mbean and add it to the map.
+ */
+ public static class DelegateListener implements NotificationListener {
+ public void handleNotification(Notification notification, Object obj) {
+ if (notification instanceof MBeanServerNotification) {
+ MBeanServerNotification msnotification =
+ (MBeanServerNotification) notification;
+ String nType = msnotification.getType();
+ ObjectName mbn = msnotification.getMBeanName();
+ if (nType.equals("JMX.mbean.registered")) {
+ String mbean = mbn.toString();
+ if(mbean.contains(DOMAIN)) {
+ beanNames.add(mbn);
+ LOG.debug("Beans are " +beanNames);
+ }
+ }
+ if (nType.equals("JMX.mbean.unregistered")) {
+ if(mbn.toString().contains(DOMAIN)) {
+ beanNames.remove(mbn);
+ LOG.debug(mbn +" MBean has been unregistered");
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void run(){
+ mbs = ManagementFactory.getPlatformMBeanServer();
+ queryMbeans();
+ DelegateListener delegateListener = new DelegateListener();
+ ObjectName delegate = null;
+ try {
+ delegate = new ObjectName("JMImplementation:type=MBeanServerDelegate");
+ } catch (MalformedObjectNameException e) {
+ e.printStackTrace();
+ }
+ NotificationFilterSupport filter = new NotificationFilterSupport();
+
+ filter.enableType("JMX.mbean.registered");
+ filter.enableType("JMX.mbean.unregistered");
+
+ LOG.debug("Add PM Registeration Notification Listener");
+ try {
+ mbs.addNotificationListener(delegate, delegateListener, filter,null);
+ }catch (InstanceNotFoundException e) {
+ e.printStackTrace();
+ }
+ Poller poller = new Poller(this.context);
+ poller.polling();
+ waitforNotification();
+ }
+
+ /**
+ * Prepovising case to handle all counter mbeans which are registered before the installation of framework bundle
+ * Queries the platform Mbeanserver to retrieve registered counter mbean and add it to the map
+ */
+ public void queryMbeans() {
+ Set<ObjectName> names =
+ new TreeSet<ObjectName>(mbs.queryNames(null, null));
+ LOG.debug("\nQueried MBeanServer for MBeans:");
+ for (ObjectName name : names) {
+ if(name.toString().contains(DOMAIN)){
+ beanNames.add(name);
+ }
+ }
+ }
+
+ private void waitforNotification() {
+ while(true){
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ 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.fcapsmanager.countermanager;
+
+import java.lang.management.ManagementFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import org.opendaylight.vpnservice.fcapsmanager.PMServiceFacade;
+
+public class Poller {
+ private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Poller.class);
+ private static BundleContext context = null;
+ public Poller(){
+ }
+ public Poller(BundleContext bundleContext) {
+ context = bundleContext;
+ }
+ //This method do the Polling every 5 second and retrieves the the counter details
+ //@Override
+ public void polling() {
+ LOG.debug("Poller Polling Mbean List and the content is " + PMRegistrationListener.beanNames);
+ ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
+ service.scheduleAtFixedRate(new Pollerthread(), 0, 5, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Platform dependent bundle injects its handle and it is retrieved in the method
+ */
+ protected PMServiceFacade getPMServiceSPI (){
+ PMServiceFacade service =null;
+ if(context != null) {
+ try {
+ ServiceReference<?> serviceReference = context.
+ getServiceReference(PMServiceFacade.class.getName());
+ service = (PMServiceFacade) context.
+ getService(serviceReference);
+ }catch(NullPointerException ex){
+ service = null;
+ }catch (Exception e){
+ LOG.error("Exception {} occurred in getting PMServiceSPI",e);
+ }
+ }
+ return service;
+ }
+}
+
+class Pollerthread implements Runnable {
+ private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(Pollerthread.class);
+ MBeanServer mbs = null;
+ Map<String,String> getCounter = new HashMap<String,String>();
+ Poller poller = new Poller();
+
+ /**
+ * Retrieve countermap from each counter mbean and send to platform
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void run() {
+ try {
+ mbs = ManagementFactory.getPlatformMBeanServer();
+ for (ObjectName objectName : PMRegistrationListener.beanNames) {
+ getCounter=(Map<String, String>) mbs.invoke(objectName, "retrieveCounterMap",null,null);
+ if(poller.getPMServiceSPI() != null)
+ poller.getPMServiceSPI().connectToPMFactory(getCounter);
+ else
+ LOG.debug("PM service not available");
+ }
+ } catch (Exception e) {
+ LOG.error("Exception caught {} ", e);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+Copyright (c) 2015 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../../commons/config-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>fcaps-api</artifactId>
+ <version>${vpnservices.version}</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <maven-bundle-plugin.version>2.5.3</maven-bundle-plugin.version>
+ <osgi.version>5.0.0</osgi.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${maven-bundle-plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Bundle-Activator>org.opendaylight.vpnservice.fcapsmanager.Activator</Bundle-Activator>
+ <Export-Package>org.opendaylight.vpnservice.fcapsmanager*;version=${project.version}</Export-Package>
+ <Import-Package>*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ 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.fcapsmanager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+ static Logger s_logger = LoggerFactory.getLogger(Activator.class);
+ public void start(BundleContext context) {
+ s_logger.info("Starting fcapsSPI bundle");
+ }
+
+ public void stop(BundleContext context) {
+ s_logger.info("Stopping fcapsSPI bundle");
+ }
+
+}
\ 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.fcapsmanager;
+
+public interface AlarmServiceFacade {
+ /**
+ * Raises the given alarm in platform environment
+ *
+ * @param alarmName
+ * Alarm to be raised
+ * @param additionalText
+ * Additional details describing about the alarm
+ * @param source
+ * Source of the alarm ex: dpnId=openflow:1
+ * the source node that caused this alarm
+ */
+ public void raiseAlarm(String alarmName, String additionalText, String source);
+
+ /**
+ * Clears the given alarm in platform environment
+ *
+ * @param alarmName
+ * Alarm to be cleared
+ * @param additionalText
+ * Additional details describing about the alarm
+ * @param source
+ * Source of the alarm ex: dpnId=openflow:1
+ * the source node that caused this alarm
+ */
+ public void clearAlarm(String alarmName, String additionalText, String source);
+}
\ 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.fcapsmanager;
+
+import java.util.Map;
+
+public interface PMServiceFacade {
+ public void connectToPMFactory(Map map);
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2015 - 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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>fcapsmanager</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <name>fcapsmanager</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <modules>
+ <module>fcaps-api</module>
+ <module>alarmmanager</module>
+ <module>countermanager</module>
+ </modules>
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
<idmanager.version>${vpnservices.version}</idmanager.version>
<itm.version>${vpnservices.version}</itm.version>
<neutronvpn.version>${vpnservices.version}</neutronvpn.version>
+ <fcaps.manager.version>${vpnservices.version}</fcaps.manager.version>
+
</properties>
<dependencyManagement>
<dependencies>
<artifactId>dhcpservice-api</artifactId>
<version>${vpnservices.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>natservice-impl</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>natservice-impl</artifactId>
+ <version>${vpnservices.version}</version>
+ <classifier>config</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>natservice-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>neutronvpn-api</artifactId>
<classifier>config</classifier>
<type>xml</type>
</dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>alarmmanager</artifactId>
+ <version>${fcaps.manager.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>countermanager</artifactId>
+ <version>${fcaps.manager.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>fcaps-api</artifactId>
+ <version>${fcaps.manager.version}</version>
+ </dependency>
</dependencies>
</project>
<bundle>mvn:org.opendaylight.vpnservice/itm-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.vpnservice/neutronvpn-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.vpnservice/dhcpservice-api/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.vpnservice/natservice-api/{{VERSION}}</bundle>
</feature>
<feature name='odl-vpnservice-impl' version='${project.version}' description='OpenDaylight :: vpnservice :: impl '>
<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
<bundle>mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.vpnservice/elanmanager-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}</bundle>
<!--<bundle>mvn:org.opendaylight.vpnservice.third-party/org.apache.thriftlib/1.1.0-SNAPSHOT</bundle>-->
<bundle>wrap:mvn:org.apache.thrift/libthrift/0.9.1$overwrite=merge&Bundle-Version=0.9.1&Export-Package=*;-noimport:=true;version="0.9.1"</bundle>
<configfile finalname="neutronvpn-impl-default-config.xml">mvn:org.opendaylight.vpnservice/neutronvpn-impl/{{VERSION}}/xml/config</configfile>
<configfile finalname="dhcpservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/dhcpservice-impl/{{VERSION}}/xml/config</configfile>
<configfile finalname="elanmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/elanmanager-impl/{{VERSION}}/xml/config</configfile>
+ <configfile finalname="natservice-impl-default-config.xml">mvn:org.opendaylight.vpnservice/natservice-impl/{{VERSION}}/xml/config</configfile>
</feature>
<feature name='odl-vpnservice-impl-rest' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: REST '>
<bundle>mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}</bundle>
<configfile finalname="vpnintent-impl-default-config.xml">mvn:org.opendaylight.vpnservice/vpnintent-impl/{{VERSION}}/xml/config</configfile>
</feature>
- </features>
+
+ <feature name='odl-fcaps-framework' version='${project.version}' description='OpenDaylight :: fcapsframework'>
+ <bundle>mvn:org.opendaylight.vpnservice/fcaps-api/${fcaps.manager.version}</bundle>
+ <bundle>mvn:org.opendaylight.vpnservice/alarmmanager/${fcaps.manager.version}</bundle>
+ <bundle>mvn:org.opendaylight.vpnservice/countermanager/${fcaps.manager.version}</bundle>
+ </feature>
+</features>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-base</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+module fib-rpc {\r
+ namespace "urn:opendaylight:vpnservice:fib:rpc";\r
+ prefix "fib-rpc";\r
+\r
+ import ietf-inet-types {\r
+ prefix inet;\r
+ revision-date "2010-09-24";\r
+ }\r
+\r
+ import opendaylight-flow-types {\r
+ prefix offlow;\r
+ revision-date "2013-10-26";\r
+ }\r
+\r
+ revision "2016-01-21" {\r
+ description "FIB Servicer RPC Module";\r
+ }\r
+\r
+ /* RPCs */\r
+\r
+ rpc create-fib-entry {\r
+ description "to install FIB/LFIB/TST routes on specified dpn with given instructions";\r
+ input {\r
+ leaf source-dpid {\r
+ type uint64;\r
+ }\r
+ leaf vpn-name {\r
+ type string;\r
+ }\r
+ leaf service-id {\r
+ type uint32;\r
+ }\r
+ leaf ip-address {\r
+ type string;\r
+ }\r
+ uses offlow:instruction-list;\r
+ }\r
+ }\r
+\r
+ rpc remove-fib-entry {\r
+ description "to remove FIB/LFIB/TST routes from specified dpn";\r
+ input {\r
+ leaf source-dpid {\r
+ type uint64;\r
+ }\r
+ leaf vpn-name {\r
+ type string;\r
+ }\r
+ leaf service-id {\r
+ type uint32;\r
+ }\r
+ leaf ip-address {\r
+ type string;\r
+ }\r
+ }\r
+ }\r
+}
\ 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.fibmanager;
+
+import java.math.BigInteger;
+
+public class FibConstants {
+ static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
+ static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
+ static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+ static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
+ static final String FLOWID_PREFIX = "L3.";
+ static final String VPN_IDPOOL_NAME = "vpnservices";
+ static final String SEPARATOR = ".";
+}
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
private NexthopManager nextHopManager;
private ItmRpcService itmManager;
private OdlInterfaceRpcService interfaceManager;
+ private IdManagerService idManager;
private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
this.interfaceManager = ifManager;
}
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
private void registerListener(final DataBroker db) {
try {
listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
@Override
protected void add(final InstanceIdentifier<VrfEntry> identifier,
final VrfEntry vrfEntry) {
- LOG.trace("key: " + identifier + ", value=" + vrfEntry );
+ LOG.trace("Add key: " + identifier + ", value=" + vrfEntry );
createFibEntries(identifier, vrfEntry);
}
@Override
protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
- LOG.trace("key: " + identifier + ", value=" + vrfEntry);
+ LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry);
deleteFibEntries(identifier, vrfEntry);
}
@Override
protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
- LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
+ LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update );
createFibEntries(identifier, update);
}
Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
- Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
- Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
+ Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
+ Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
Long vpnId = vpnInstance.getVpnId();
- RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
+ String rd = vrfTableKey.getRouteDistinguisher();
+ RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
vrfEntry.getDestPrefix());
if (rdToElanOpEntry!=null) {
if (vpnToDpnList!=null) {
return;
}
BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
- vrfTableKey.getRouteDistinguisher(), vrfEntry);
+ rd, vrfEntry);
if (vpnToDpnList != null) {
- for (VpnToDpnList curDpn : vpnToDpnList) {
- if (!curDpn.getDpnId().equals(localDpnId)) {
- createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
- vrfTableKey, vrfEntry);
+ for (VpnToDpnList curDpn : vpnToDpnList) {
+ if (!curDpn.getDpnId().equals(localDpnId)) {
+ createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
+ vrfTableKey, vrfEntry);
+ }
}
- }
}
}
private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
long vpnId, VrfEntry vrfEntry){
- makeSubnetRouteFlow(dpnId);
List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
- List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
Long elanTag = rdToElanOpEntry.getElanTag();
+
instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
instructions,NwConstants.ADD_FLOW);
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ // reinitialize instructions list for LFIB Table
+ instructions = new ArrayList<InstructionInfo>();
+
+ actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+
makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
// TODO makeTunnelTableEntry();
return result;
}
- private void makeSubnetRouteFlow(BigInteger dpnId) {
- //Ask Vivek cookie
+ private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
- instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
List<MatchInfo> matches = new ArrayList<MatchInfo>();
String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
- LOG.debug("Invoking MDSAL to install Table Miss Entries");
- mdsalManager.syncInstallFlow(flowEntity,1);
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ LOG.debug("Invoking MDSAL to install SubnetRoute Table Miss Entries for DPN" + dpnId);
+ mdsalManager.installFlow(flowEntity);
+ } else {
+ LOG.debug("Invoking MDSAL to remove SubnetRoute Table Miss Entries for DPN " + dpnId);
+ mdsalManager.removeFlow(flowEntity);
+ }
}
private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
FibUtil.getVpnInterfaceIdentifier(ifName));
- }
+ }
+
+ FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+ FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
+
}
private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
+ String rd = vrfTableKey.getRouteDistinguisher();
VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
- Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
+ if (vpnInstance == null) {
+ LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
+ return;
+ }
Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
vrfEntry.getDestPrefix());
InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
vrfEntry.getDestPrefix());
MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
+ FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
+ FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
return;
}
BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
- vrfTableKey.getRouteDistinguisher(), vrfEntry);
+ vrfTableKey.getRouteDistinguisher(), vrfEntry);
if (vpnToDpnList != null) {
- for (VpnToDpnList curDpn : vpnToDpnList) {
- if (!curDpn.getDpnId().equals(localDpnId)) {
- deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
+ for (VpnToDpnList curDpn : vpnToDpnList) {
+ if (!curDpn.getDpnId().equals(localDpnId)) {
+ deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
+ }
}
- }
}
//The flow/group entry has been deleted from config DS; need to clean up associated operational
//DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
if (vrfTable.isPresent()) {
for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+ /* Handle subnet routes here */
+ RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
+ vrfEntry.getDestPrefix());
+ if (rdToElanOpEntry != null) {
+ LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
+ dpnId, rd);
+ makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
+ makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
+ vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
+ continue;
+ }
// Passing null as we don't know the dpn
// to which prefix is attached at this point
deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
+ makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
}
private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.fibmanager.api.IFibManager;
import org.opendaylight.vpnmanager.api.IVpnManager;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
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;
private ItmRpcService itmManager;
private OdlInterfaceRpcService interfaceManager;
private FibNodeCapableListener fibNcListener;
+ private RpcProviderRegistry rpcProviderRegistry;
+ private RpcRegistration<FibRpcService> rpcRegistration;
@Override
public void onSessionInitiated(ProviderContext session) {
fibManager.setNextHopManager(nexthopManager);
fibManager.setITMRpcService(itmManager);
fibManager.setInterfaceManager(interfaceManager);
+ fibManager.setIdManager(idManager);
fibNcListener = new FibNodeCapableListener(dataBroker, fibManager);
+ FibRpcService fibRpcService = new FibRpcServiceImpl(dataBroker, mdsalManager, this);
+ rpcRegistration = getRpcProviderRegistry().addRpcImplementation(FibRpcService.class, fibRpcService);
} catch (Exception e) {
LOG.error("Error initializing services", e);
}
public void deleteStaticRoute(String prefix, String rd) {
this.vpnmanager.delExtraRoute(prefix, rd, null);
}
+
+ public void setRpcProviderRegistry(RpcProviderRegistry rpcProviderRegistry) {
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ }
+
+ private RpcProviderRegistry getRpcProviderRegistry() {
+ return rpcProviderRegistry;
+ }
+
}
--- /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.fibmanager;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+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.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.fibmanager.api.IFibManager;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+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.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
+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.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+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 static org.opendaylight.vpnservice.fibmanager.FibConstants.*;
+
+public class FibRpcServiceImpl implements FibRpcService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FibRpcServiceImpl.class);
+ private IMdsalApiManager mdsalManager;
+ private DataBroker broker;
+ private IFibManager fibManager;
+
+ public FibRpcServiceImpl(DataBroker broker, IMdsalApiManager mdsalManager, IFibManager fibManager) {
+ this.broker = broker;
+ this.mdsalManager = mdsalManager;
+ this.fibManager = fibManager;
+ }
+
+
+ /**
+ * to install FIB routes on specified dpn with given instructions
+ *
+ */
+ public Future<RpcResult<Void>> createFibEntry(CreateFibEntryInput input) {
+
+ BigInteger dpnId = input.getSourceDpid();
+ String vpnName = input.getVpnName();
+ long vpnId = getVpnId(broker, vpnName);
+ String ipAddress = input.getIpAddress();
+ LOG.info("Create custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
+ List<Instruction> instructions = input.getInstruction();
+
+ makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions);
+ updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+
+ return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+ }
+
+ /**
+ * to remove FIB/LFIB/TST routes from specified dpn
+ *
+ */
+ public Future<RpcResult<Void>> removeFibEntry(RemoveFibEntryInput input) {
+
+ BigInteger dpnId = input.getSourceDpid();
+ String vpnName = input.getVpnName();
+ long vpnId = getVpnId(broker, vpnName);
+ long serviceId = input.getServiceId();
+ String ipAddress = input.getIpAddress();
+
+ LOG.info("Delete custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
+
+ removeLocalFibEntry(dpnId, vpnId, ipAddress);
+ //removeLFibTableEntry(dpnId, serviceId);
+ //removeTunnelTableEntry(dpnId, serviceId);
+ removeFromVpnDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+
+ return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+ }
+
+ private void removeLocalFibEntry(BigInteger dpnId, long vpnId, String ipPrefix) {
+ String values[] = ipPrefix.split("/");
+ String ipAddress = values[0];
+ int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
+ LOG.debug("Removing route from DPN. ip {} masklen {}", ipAddress, prefixLength);
+ InetAddress destPrefix = null;
+ try {
+ destPrefix = InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException in removeRoute. Failed to remove Route for ipPrefix {}", ipAddress);
+ return;
+ }
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ if(prefixLength != 0) {
+ matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+ destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
+ }
+
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress);
+
+
+ int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
+ priority, flowRef, 0, 0,
+ COOKIE_VM_FIB_TABLE, matches, null);
+
+ mdsalManager.removeFlow(dpnId, flowEntity);
+
+ LOG.debug("FIB entry for route {} on dpn {} removed successfully", ipAddress, dpnId);
+ }
+
+ private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x8847L }));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ LOG.debug("removing LFib entry with flow ref {}", flowRef);
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, null);
+
+ mdsalManager.removeFlow(dpnId, flowEntity);
+
+ LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+ private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+ LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ // Matching metadata
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+ 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+ COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+ mdsalManager.removeFlow(dpnId, flowEntity);
+ LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+ private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+ LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+ Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
+ 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+
+ mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+ }
+
+ private long getIpAddress(byte[] rawIpAddress) {
+ return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
+ + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
+ }
+
+ private void makeLocalFibEntry(long vpnId, BigInteger dpnId, String ipPrefix, List<Instruction> customInstructions) {
+ String values[] = ipPrefix.split("/");
+ String ipAddress = values[0];
+ int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
+ LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
+ InetAddress destPrefix = null;
+ try {
+ destPrefix = InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", ipAddress);
+ return;
+ }
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ if(prefixLength != 0) {
+ matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+ destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
+ }
+
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress);
+
+
+ int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
+ priority, flowRef, 0, 0,
+ COOKIE_VM_FIB_TABLE, matches, customInstructions);
+
+ mdsalManager.installFlow(dpnId, flowEntity);
+
+ LOG.debug("FIB entry for route {} on dpn {} installed successfully", ipAddress, dpnId);
+ }
+
+ private void makeLFibTableEntry(BigInteger dpId, long serviceId, List<Instruction> customInstructions) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x8847L }));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ List<Instruction> instructions = new ArrayList<Instruction>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+ Instruction writeInstruction = new InstructionInfo(InstructionType.write_actions, actionsInfos).buildInstruction(0);
+ instructions.add(writeInstruction);
+ instructions.addAll(customInstructions);
+
+ // Install the flow entry in L3_LFIB_TABLE
+ String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+ mdsalManager.installFlow(dpId, flowEntity);
+
+ LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+ }
+
+ private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+ return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+ }
+
+ private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+ LOG.debug("Updating VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
+ dpnId, vpnName, ipAddr);
+ String routeDistinguisher = getVpnRd(broker, vpnName);
+ String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+ InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+ Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
+ ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
+
+ if (dpnInVpn.isPresent()) {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance
+ .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+ new IpAddressesKey(ipAddr)), ipAddress);
+ } else {
+ MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+ getVpnInstanceOpDataIdentifier(rd),
+ getVpnInstanceOpData(rd, vpnId));
+ VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+ .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = new ArrayList<>();
+ ipAddresses.add(ipAddress);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
+ vpnToDpnList.setIpAddresses(ipAddresses).build());
+ LOG.debug("populate FIB on new dpn {} for VPN {}", dpnId, vpnName);
+ fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
+ }
+ }
+
+ private synchronized void removeFromVpnDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+ LOG.debug("Removing association of VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
+ dpnId, vpnName, ipAddr);
+ String routeDistinguisher = getVpnRd(broker, vpnName);
+ String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+ InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+ Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (dpnInVpn.isPresent()) {
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+ .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
+ ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
+
+ if (ipAddresses != null && ipAddresses.remove(ipAddress)) {
+ if (ipAddresses.isEmpty()) {
+ List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+ if(vpnInterfaces ==null || vpnInterfaces.isEmpty()) {
+ //Clean up the dpn
+ LOG.debug("Cleaning up dpn {} from VPN {}", dpnId, vpnName);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+ fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
+ }
+ } else {
+ delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+ .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+ new IpAddressesKey(ipAddr)));
+ }
+ }
+ }
+ }
+
+ //TODO: Below Util methods to be removed once VpnUtil methods are exposed in api bundle
+ public static String getVpnRd(DataBroker broker, String vpnName) {
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+ = getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ String rd = null;
+ if(vpnInstance.isPresent()) {
+ rd = vpnInstance.get().getVrfId();
+ }
+ return rd;
+ }
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+ getVpnInstanceToVpnIdIdentifier(String vpnName) {
+ return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
+ }
+
+
+ static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
+ return InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
+ .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
+ }
+
+ static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
+ return InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
+ }
+
+ static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId) {
+ return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).build();
+ }
+
+ static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
+ InstanceIdentifier<T> path) {
+ WriteTransaction tx = broker.newWriteOnlyTransaction();
+ tx.delete(datastoreType, path);
+ tx.submit();
+ }
+
+ static long getVpnId(DataBroker broker, String vpnName) {
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+ = getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ long vpnId = -1;
+ if(vpnInstance.isPresent()) {
+ vpnId = vpnInstance.get().getVpnId();
+ }
+ return vpnId;
+ }
+
+}
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+
+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.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
public class FibUtil {
private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build();
}
+ static String getNextHopLabelKey(String rd, String prefix){
+ String key = rd + FibConstants.SEPARATOR + prefix;
+ return key;
+ }
+
+ static void releaseId(IdManagerService idManager, String poolName, String idKey) {
+ ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
+ try {
+ Future<RpcResult<Void>> result = idManager.releaseId(idInput);
+ RpcResult<Void> rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
+ }
+ }
+
static final FutureCallback<Void> DEFAULT_CALLBACK =
new FutureCallback<Void>() {
public void onSuccess(Void result) {
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
return null;
}
+ @Override
+ public List<IpAddresses> getIpAddresses() { return null; }
+
@Override
public VpnToDpnListKey getKey() {
return new VpnToDpnListKey(Dpn);
hwVTEPTunnelsStateListener = new HwVTEPTunnelsStateListener(dataBroker);
hwVTEPTunnelsStateListener.registerListener(LogicalDatastoreType.OPERATIONAL,dataBroker);
- //terminationPointStateListener = new TerminationPointStateListener(dataBroker);
- //terminationPointStateListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+ terminationPointStateListener = new TerminationPointStateListener(dataBroker);
+ terminationPointStateListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
flowBasedServicesConfigListener = new FlowBasedServicesConfigListener(dataBroker);
flowBasedServicesConfigListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
if(!(ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)&& ifTunnel.isInternal())){
return;
}
+ LOG.debug("stop LLDP monitoring for {}", trunkInterface.getName());
List<Long> monitorIds = getMonitorIdForInterface(dataBroker, trunkInterface.getName());
if (monitorIds == null) {
LOG.error("Monitor Id doesn't exist for Interface {}", trunkInterface);
return;
}
LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
- // Restart LLDP monitoring only if it's started already
- List<Long> monitorIds = getMonitorIdForInterface(dataBroker, interfaceName);
- if (monitorIds != null && monitorIds.size() > 1) {
- stopLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceOld);
- if(ifTunnelNew.isMonitorEnabled()) {
- startLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceNew);
- // Delete old profile from Aliveness Manager
- IfTunnel ifTunnelOld = interfaceOld.getAugmentation(IfTunnel.class);
- if(ifTunnelNew.getMonitorInterval() != ifTunnelOld.getMonitorInterval()) {
- LOG.debug("deleting older monitor profile for interface {}", interfaceName);
- long profileId = allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp);
- MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder().setProfileId(profileId).build();
- alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
- }
- }
+ stopLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceOld);
+ if(ifTunnelNew.isMonitorEnabled()) {
+ startLLDPMonitoring(alivenessMonitorService, dataBroker, interfaceNew);
+
+ // Delete old profile from Aliveness Manager
+ IfTunnel ifTunnelOld = interfaceOld.getAugmentation(IfTunnel.class);
+ if(ifTunnelNew.getMonitorInterval() != ifTunnelOld.getMonitorInterval()) {
+ LOG.debug("deleting older monitor profile for interface {}", interfaceName);
+ long profileId = allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp);
+ MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder().setProfileId(profileId).build();
+ alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
}
+ }
}
if(rpcResult.isSuccessful()) {
return rpcResult.getResult().getProfileId();
} else {
- LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}", rpcResult.getErrors());
+ LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID", rpcResult.getErrors());
+ try{
+ Profile createProfile = monitorProfileCreateInput.getProfile();
+ Future<RpcResult<MonitorProfileGetOutput>> existingProfile = alivenessMonitor.monitorProfileGet(buildMonitorGetProfile(createProfile.getMonitorInterval(), createProfile.getMonitorWindow(), createProfile.getFailureThreshold(), createProfile.getProtocolType()));
+ RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
+ if(rpcGetResult.isSuccessful()){
+ return rpcGetResult.getResult().getProfileId();
+ }else{
+ LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}", rpcGetResult.getErrors());
+ }
+ }catch(Exception e){
+ LOG.warn("Exception when getting existing profile",e);
+ }
}
} catch (InterruptedException | ExecutionException e) {
LOG.warn("Exception when allocating profile Id",e);
}
return 0;
}
+
+ private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow, long failureThreshold, EtherTypes protocolType){
+ MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
+ org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.ProfileBuilder profileBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.get.input.ProfileBuilder();
+ profileBuilder.setFailureThreshold(failureThreshold);
+ profileBuilder.setMonitorInterval(monitorInterval);
+ profileBuilder.setMonitorWindow(monitorWindow);
+ profileBuilder.setProtocolType(protocolType);
+ buildGetProfile.setProfile(profileBuilder.build());
+ return (buildGetProfile.build());
+ };
+
public static long allocateProfile(AlivenessMonitorService alivenessMonitor, long FAILURE_THRESHOLD, long MONITORING_INTERVAL,
long MONITORING_WINDOW, EtherTypes etherTypes) {
MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().
}
return vxlanList;
}
+
+ public static Interface getInterfaceFromConfigDS(String interfaceName, DataBroker dataBroker) {
+ InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
+ return getInterfaceFromConfigDS(interfaceKey, dataBroker);
+ }
+
public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
Optional<Interface> interfaceOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION, interfaceId, dataBroker);
public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(String interfaceName, DataBroker dataBroker) {
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
IfmUtil.buildStateInterfaceId(interfaceName);
+ return getInterfaceStateFromOperDS(ifStateId, dataBroker);
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS
+ (InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId, DataBroker dataBroker) {
Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional =
IfmUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker);
if (!ifStateOptional.isPresent()) {
MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, interfaceData);
}
- public static void updateTunnelMonitorDetailsInConfigDS(DataBroker broker, String interfaceName, boolean monitorEnabled, long monitorInterval) {
- InstanceIdentifier<Interface> id = IfmUtil.buildId(interfaceName);
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder();
- ifaceBuilder.setKey(new InterfaceKey(interfaceName));
- IfTunnelBuilder ifTunnelBuilder = new IfTunnelBuilder();
- ifTunnelBuilder.setMonitorEnabled(monitorEnabled);
- ifTunnelBuilder.setMonitorInterval(monitorInterval);
- ifaceBuilder.addAugmentation(IfTunnel.class, ifTunnelBuilder.build());
-
- LOG.trace("Updating trunk interface {} in Config DS", interfaceName);
- MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id, ifaceBuilder.build());
- }
-
public static void createInterfaceChildEntry( WriteTransaction t,
String parentInterface, String childInterface){
InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(parentInterface);
// install ingress flow
BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
long portNo = Long.valueOf(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
- if(interfaceInfo.isEnabled() && ifState.getOperStatus() == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
+ if(interfaceInfo != null && interfaceInfo.isEnabled() && ifState.getOperStatus() == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForVlanPortAtIngressTable(dpId, portNo, interfaceInfo);
FlowBasedServicesUtils.installVlanFlow(dpId, portNo, interfaceInfo, transaction, matches, ifIndex);
}
*/
public static void updateOpState(WriteTransaction transaction, String interfaceName,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus operStatus){
- LOG.debug("updating tep interface state for {}", interfaceName);
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
IfmUtil.buildStateInterfaceId(interfaceName);
+ LOG.debug("updating tep interface state as {} for {}", operStatus.name(), interfaceName);
InterfaceBuilder ifaceBuilder = new InterfaceBuilder().setOperStatus(operStatus);
ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(interfaceName));
transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier =
InterfaceMetaUtils.getBridgeEntryIdentifier(bridgeEntryKey);
+ LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier,
dataBroker);
}
}
- public static BridgeInterfaceEntry getBridgeInterfaceEntryFromConfigDS(
- InstanceIdentifier<BridgeInterfaceEntry> bridgeInterfaceEntryInstanceIdentifier, DataBroker dataBroker) {
- Optional<BridgeInterfaceEntry> bridgeInterfaceEntryOptional =
- IfmUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeInterfaceEntryInstanceIdentifier, dataBroker);
- if (!bridgeInterfaceEntryOptional.isPresent()) {
- return null;
- }
- return bridgeInterfaceEntryOptional.get();
- }
-
-
public static void createBridgeInterfaceEntryInConfigDS(BridgeEntryKey bridgeEntryKey,
BridgeInterfaceEntryKey bridgeInterfaceEntryKey,
String childInterface,
return intfIdBuilder.build();
}
+ public static InterfaceParentEntry getInterfaceParentEntryFromConfigDS(
+ String interfaceName, DataBroker dataBroker) {
+ InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(interfaceName);
+ InterfaceParentEntry interfaceParentEntry =
+ InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceParentEntryKey, dataBroker);
+ return interfaceParentEntry;
+ }
+
public static InterfaceParentEntry getInterfaceParentEntryFromConfigDS(
InterfaceParentEntryKey interfaceParentEntryKey, DataBroker dataBroker) {
InstanceIdentifier<InterfaceParentEntry> intfParentIid =
t.put(LogicalDatastoreType.OPERATIONAL, id, ifIndexInterface, true);
}
- public static void removeLportTagInterfaceMap(WriteTransaction t, IdManagerService idManager, DataBroker broker, String infName, Integer ifIndex) {
- InstanceIdentifier<IfIndexInterface> id = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(ifIndex)).build();
- Optional<IfIndexInterface> ifIndexesInterface = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
- if(ifIndexesInterface.isPresent()) {
- LOG.debug("removing lport tag to interface map for {}",infName);
- t.delete(LogicalDatastoreType.OPERATIONAL, id);
- }
- IfmUtil.releaseId(idManager, IfmConstants.IFM_IDPOOL_NAME, infName);
- }
-
public static void createBridgeRefEntry(BigInteger dpnId, InstanceIdentifier<?> bridgeIid,
WriteTransaction tx){
LOG.debug("Creating bridge ref entry for dpn: {} bridge: {}",
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
@Override
public void onMonitorEvent(MonitorEvent notification) {
Long monitorId = notification.getEventData().getMonitorId();
- String trunkInterfaceName = AlivenessMonitorUtils.getInterfaceFromMonitorId(dataBroker, monitorId);
- if (trunkInterfaceName == null) {
- LOG.debug("Either monitoring for interface - {} not started by Interfacemgr or it is not LLDP monitoring", trunkInterfaceName);
+ String tunnelInterface = AlivenessMonitorUtils.getInterfaceFromMonitorId(dataBroker, monitorId);
+ if (tunnelInterface == null) {
+ LOG.debug("Either monitoring for interface - {} not started by Interfacemgr or it is not LLDP monitoring", tunnelInterface);
return;
}
LivenessState livenessState = notification.getEventData().getMonitorState();
- Interface interfaceInfo = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(trunkInterfaceName),
- dataBroker);
- IfTunnel tunnelInfo = interfaceInfo.getAugmentation(IfTunnel.class);
- // Not handling monitoring event if it is GRE Trunk Interface.
- if (tunnelInfo.getTunnelInterfaceType().isAssignableFrom(TunnelTypeGre.class)) {
- return;
- }
+ LOG.debug("received monitor event for {} with livenessstate {}", tunnelInterface, livenessState);
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState =
livenessState == LivenessState.Up ? org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up :
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Down;
- InterfaceManagerCommonUtils.setOpStateForInterface(dataBroker, trunkInterfaceName, opState);
+ InterfaceManagerCommonUtils.setOpStateForInterface(dataBroker, tunnelInterface, opState);
}
-}
\ No newline at end of file
+}
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateRemoveHelper;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateUpdateHelper;
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.Tunnels;
}
@Override
- protected void remove(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelOld) {
- LOG.info("Received Remove DataChange Notification for identifier: {}, physicalSwitchAugmentation: {}",
- identifier, tunnelOld);
+ protected void remove(InstanceIdentifier<Tunnels> identifier, Tunnels tunnel) {
+ LOG.debug("Received Remove DataChange Notification for identifier: {}, physicalSwitchAugmentation: {}",
+ identifier, tunnel);
+ DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
+ RendererStateRemoveWorker rendererStateRemoveWorker = new RendererStateRemoveWorker(identifier, tunnel);
+ jobCoordinator.enqueueJob(tunnel.getTunnelUuid().getValue(), rendererStateRemoveWorker);
}
@Override
protected void update(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelOld,
Tunnels tunnelNew) {
- LOG.info("Received Update Tunnel Update Notification for identifier: {}", identifier);
+ LOG.debug("Received Update Tunnel Update Notification for identifier: {}", identifier);
DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
RendererStateUpdateWorker rendererStateUpdateWorker = new RendererStateUpdateWorker(identifier, tunnelNew, tunnelOld);
jobCoordinator.enqueueJob(tunnelNew.getTunnelUuid().getValue(), rendererStateUpdateWorker);
@Override
protected void add(InstanceIdentifier<Tunnels> identifier, Tunnels tunnelNew) {
- LOG.info("Received Add DataChange Notification for identifier: {}, tunnels: {}",
+ LOG.debug("Received Add DataChange Notification for identifier: {}, tunnels: {}",
identifier, tunnelNew);
DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, tunnelNew);
return HwVTEPInterfaceStateUpdateHelper.startBfdMonitoring(dataBroker, instanceIdentifier, tunnelsNew);
}
}
-}
\ No newline at end of file
+
+ private class RendererStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+ InstanceIdentifier<Tunnels> instanceIdentifier;
+ Tunnels tunnel;
+
+ public RendererStateRemoveWorker(InstanceIdentifier<Tunnels> instanceIdentifier,
+ Tunnels tunnel) {
+ this.instanceIdentifier = instanceIdentifier;
+ this.tunnel = tunnel;
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ // If another renderer(for eg : CSS) needs to be supported, check can be performed here
+ // to call the respective helpers.
+ return HwVTEPInterfaceStateRemoveHelper.removeExternalTunnel(dataBroker, instanceIdentifier);
+ }
+ }
+}
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
@Override
protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
- return AsyncDataBroker.DataChangeScope.BASE;
+ return AsyncDataBroker.DataChangeScope.ONE;
}
@Override
'}';
}
}
-}
\ No newline at end of file
+}
@Override
protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
- return AsyncDataBroker.DataChangeScope.ONE;
+ return AsyncDataBroker.DataChangeScope.SUBTREE;
}
@Override
protected void update(InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
OvsdbTerminationPointAugmentation tpOld,
OvsdbTerminationPointAugmentation tpNew) {
- LOG.debug("Received Update DataChange Notification for ovsdb termination point identifier: {}, old: {}, new: {}.",
- identifier, tpOld, tpNew);
+ LOG.debug("Received Update DataChange Notification for ovsdb termination point {}", tpNew.getName());
if (tpNew.getInterfaceBfdStatus() != null &&
!tpNew.getInterfaceBfdStatus().equals(tpOld.getInterfaceBfdStatus())) {
+ LOG.trace("Bfd Status changed for ovsdb termination point identifier: {}, old: {}, new: {}.",
+ identifier, tpOld, tpNew);
DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
RendererStateUpdateWorker rendererStateAddWorker = new RendererStateUpdateWorker(identifier, tpNew, tpOld);
jobCoordinator.enqueueJob(tpNew.getName(), rendererStateAddWorker);
*/
package org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers;
+import com.google.common.base.Optional;
import com.google.common.util.concurrent.ListenableFuture;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.utilities.SouthboundUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// create hwvtep through ovsdb plugin
WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
if(globalNodeId != null) {
- updateBfdMonitoring(dataBroker, physicalSwitchNodeId, ifTunnel);
+ updateBfdMonitoring(dataBroker, globalNodeId, physicalSwitchNodeId, ifTunnel);
}else{
LOG.debug("specified physical switch is not connected {}", physicalSwitchNodeId);
/*
* bfd monitoring interval and enable/disbale attributes can be modified
*/
- public static List<ListenableFuture<Void>> updateBfdMonitoring(DataBroker dataBroker, InstanceIdentifier<Node> nodeId,
+ public static List<ListenableFuture<Void>> updateBfdMonitoring(DataBroker dataBroker, InstanceIdentifier<Node> globalNodeId, InstanceIdentifier<Node> physicalSwitchId,
IfTunnel ifTunnel) {
List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
TunnelsBuilder tBuilder = new TunnelsBuilder();
InstanceIdentifier<TerminationPoint> localTEPInstanceIdentifier =
- SouthboundUtils.createTEPInstanceIdentifier(nodeId, ifTunnel.getTunnelSource());
+ SouthboundUtils.createTEPInstanceIdentifier(globalNodeId, ifTunnel.getTunnelSource());
InstanceIdentifier<TerminationPoint> remoteTEPInstanceIdentifier =
- SouthboundUtils.createTEPInstanceIdentifier(nodeId, ifTunnel.getTunnelDestination());
+ SouthboundUtils.createTEPInstanceIdentifier(globalNodeId, ifTunnel.getTunnelDestination());
InstanceIdentifier<Tunnels> tunnelsInstanceIdentifier = SouthboundUtils.
- createTunnelsInstanceIdentifier(nodeId, localTEPInstanceIdentifier, remoteTEPInstanceIdentifier);
+ createTunnelsInstanceIdentifier(physicalSwitchId, localTEPInstanceIdentifier, remoteTEPInstanceIdentifier);
LOG.debug("updating bfd monitoring parameters for the hwvtep {}", tunnelsInstanceIdentifier);
tBuilder.setKey(new TunnelsKey(new HwvtepPhysicalLocatorRef(localTEPInstanceIdentifier),
new HwvtepPhysicalLocatorRef(remoteTEPInstanceIdentifier)));
List <BfdParams> bfdParams = new ArrayList<>();
- SouthboundUtils.fillBfdParameters(bfdParams, null);
+ SouthboundUtils.fillBfdParameters(bfdParams, ifTunnel);
tBuilder.setBfdParams(bfdParams);
transaction.merge(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier,tBuilder.build(), true);
futures.add(transaction.submit());
--- /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.interfacemgr.renderer.hwvtep.statehelpers;
+
+import com.google.common.util.concurrent.ListenableFuture;
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HwVTEPInterfaceStateRemoveHelper {
+ private static final Logger LOG = LoggerFactory.getLogger(HwVTEPInterfaceStateRemoveHelper.class);
+
+ public static List<ListenableFuture<Void>> removeExternalTunnel(DataBroker dataBroker,
+ InstanceIdentifier<Tunnels> tunnelsInstanceIdentifier) {
+ List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+ LOG.debug("Removing HwVTEP tunnel entries for tunnel: {}", tunnelsInstanceIdentifier);
+ WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier);
+ futures.add(transaction.submit());
+ return futures;
+ }
+}
return (InstanceIdentifier<Node>) physicalSwitchAugmentation.getManagedBy().getValue();
}
- public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(NodeKey nodekey,
- String portName){
- InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
- .create(NetworkTopology.class)
- .child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
- .child(Node.class,nodekey)
- .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
-
- LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
- return terminationPointPath;
- }
-
public static InstanceIdentifier<TerminationPoint> createTEPInstanceIdentifier
(InstanceIdentifier<Node> nodeIid, IpAddress ipAddress) {
TerminationPointKey localTEP = SouthboundUtils.getTerminationPointKey(ipAddress.getIpv4Address().getValue());
InstanceIdentifier<TerminationPoint> remoteTEPInstanceIdentifier) {
TunnelsKey tunnelsKey = new TunnelsKey(new HwvtepPhysicalLocatorRef(localTEPInstanceIdentifier),
new HwvtepPhysicalLocatorRef(remoteTEPInstanceIdentifier));
- return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
+
+ InstanceIdentifier<Tunnels> tunnelInstanceId = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(HWVTEP_TOPOLOGY_ID))
.child(Node.class, new NodeKey(nodeId.firstKeyOf(Node.class))).augmentation(PhysicalSwitchAugmentation.class)
.child(Tunnels.class, tunnelsKey).build();
+ return tunnelInstanceId;
}
public static String getTerminationPointKeyString(String ipAddress) {
return tpKey;
}
- public static TerminationPoint getTEPFromConfigDS(InstanceIdentifier<TerminationPoint> tpPath,
- DataBroker dataBroker) {
- Optional<TerminationPoint> terminationPointOptional =
- IfmUtil.read(LogicalDatastoreType.CONFIGURATION, tpPath, dataBroker);
- if (!terminationPointOptional.isPresent()) {
- return null;
- }
- return terminationPointOptional.get();
- }
-
public static void setDstIp(HwvtepPhysicalLocatorAugmentationBuilder tpAugmentationBuilder, IpAddress ipAddress) {
IpAddress ip = new IpAddress(ipAddress);
tpAugmentationBuilder.setDstIp(ip);
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
if (ifState != null) {
LOG.debug("add interface state info for vlan member {}",interfaceNew.getName());
InterfaceManagerCommonUtils.addStateEntry(interfaceNew.getName(), t, dataBroker, idManager, ifState);
-
-
- // FIXME: Maybe, add the new interface to the higher-layer if of the parent interface-state.
- // That may not serve any purpose though for interface manager.... Unless some external parties are interested in it.
-
- /* FIXME -- Below code is needed to add vlan-trunks to the of-port. Is this really needed.
- String lowerLayerIf = ifState.getLowerLayerIf().get(0);
-
- NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
- BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
-
- BridgeRefEntryKey BridgeRefEntryKey = new BridgeRefEntryKey(dpId);
- InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid =
- InterfaceMetaUtils.getBridgeRefEntryIdentifier(BridgeRefEntryKey);
- BridgeRefEntry bridgeRefEntry =
- InterfaceMetaUtils.getBridgeRefEntryFromOperDS(dpnBridgeEntryIid, dataBroker);
- if (bridgeRefEntry != null) {
- InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
- (InstanceIdentifier<OvsdbBridgeAugmentation>)bridgeRefEntry.getBridgeReference().getValue();
- Optional<OvsdbBridgeAugmentation> bridgeNodeOptional =
- IfmUtil.read(LogicalDatastoreType.OPERATIONAL, bridgeIid, dataBroker);
- if (bridgeNodeOptional.isPresent()) {
- OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNodeOptional.get();
- String bridgeName = ovsdbBridgeAugmentation.getBridgeName().getValue();
- VlanTrunkSouthboundUtils.addVlanPortToBridge(bridgeIid, ifL2vlan,
- ovsdbBridgeAugmentation, bridgeName, parentRefs.getParentInterface(), dataBroker, t);
- }
- } */
- // FIXME: Need to add the Group here with actions: Push-Vlan, output_port. May not be needed here...
}
futures.add(t.submit());
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface>
higerLayerChildIfStateId = IfmUtil.buildStateInterfaceId(higherlayerChild.getChildInterface());
Interface higherLayerIfChildState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(higherlayerChild.getChildInterface(), dataBroker);
- if (interfaceState != null) {
+ if (interfaceState != null && higherLayerIfChildState != null) {
transaction.delete(LogicalDatastoreType.OPERATIONAL, higerLayerChildIfStateId);
FlowBasedServicesUtils.removeIngressFlow(higherLayerIfChildState.getName(), dpId, transaction);
}
futures.add(transaction.submit());
return futures;
}
-}
\ No newline at end of file
+}
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
import org.opendaylight.vpnservice.interfacemgr.commons.AlivenessMonitorUtils;
import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
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.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.AlivenessMonitorService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
FlowCapableNodeConnector flowCapableNodeConnectorOld) {
LOG.debug("Update of Interface State for port: {}", portName);
List<ListenableFuture<Void>> futures = new ArrayList<>();
- WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
- Interface.OperStatus operStatusNew =
- flowCapableNodeConnectorNew.getState().isLinkDown() ? Interface.OperStatus.Down : Interface.OperStatus.Up;
- Interface.AdminStatus adminStatusNew =
- flowCapableNodeConnectorNew.getState().isBlocked() ? Interface.AdminStatus.Down : Interface.AdminStatus.Up;
+ Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
- Interface.OperStatus operStatusOld =
- flowCapableNodeConnectorOld.getState().isLinkDown() ? Interface.OperStatus.Down : Interface.OperStatus.Up;
- Interface.AdminStatus adminStatusOld =
- flowCapableNodeConnectorOld.getState().isBlocked() ? Interface.AdminStatus.Down : Interface.AdminStatus.Up;
+ Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
boolean opstateModified = false;
- boolean adminStateModified = false;
boolean hardwareAddressModified = false;
if (!operStatusNew.equals(operStatusOld)) {
opstateModified = true;
}
- if (!adminStatusNew.equals(adminStatusOld)) {
- adminStateModified = true;
- }
if (!macAddressNew.equals(macAddressOld)) {
hardwareAddressModified = true;
}
- if (!opstateModified && !adminStateModified && !hardwareAddressModified) {
+ if (!opstateModified && !hardwareAddressModified) {
LOG.debug("If State entry for port: {} Not Modified.", portName);
return futures;
}
- InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(portName);
InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = null;
- boolean modified = false;
- if (opstateModified) {
- LOG.debug("Opstate Modified for Port: {}", portName);
- InterfaceKey interfaceKey = new InterfaceKey(portName);
- iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceKey, dataBroker);
-
- // If interface config admin state is disabled, set operstate of the Interface State entity to Down.
- if (iface != null && !iface.isEnabled()) {
- operStatusNew = Interface.OperStatus.Down;
- }
-
- ifaceBuilder.setOperStatus(operStatusNew);
- modified = true;
- }
-
- if (adminStateModified) {
- LOG.debug("Admin state Modified for Port: {}", portName);
- ifaceBuilder.setAdminStatus(adminStatusNew);
- modified = true;
- }
-
if (hardwareAddressModified) {
LOG.debug("Hw-Address Modified for Port: {}", portName);
PhysAddress physAddress = new PhysAddress(macAddressNew.getValue());
ifaceBuilder.setPhysAddress(physAddress);
- modified = true;
}
- /* FIXME: Is there chance that lower layer node-connector info is updated.
- Not Considering for now.
- */
-
- if (modified) {
- ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(portName));
- t.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
-
- InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(portName);
- InterfaceParentEntry interfaceParentEntry =
- InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceParentEntryKey, dataBroker);
- if (interfaceParentEntry == null || interfaceParentEntry.getInterfaceChildEntry() == null) {
- futures.add(t.submit());
- // start/stop monitoring based on opState
- IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
- if(ifTunnel != null) {
- if (operStatusNew == Interface.OperStatus.Down)
- AlivenessMonitorUtils.stopLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
- else
- AlivenessMonitorUtils.startLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
- }
- return futures;
- }
- for(InterfaceChildEntry higherlayerChild : interfaceParentEntry.getInterfaceChildEntry()) {
- InstanceIdentifier<Interface> higherLayerIfChildStateId =
- IfmUtil.buildStateInterfaceId(higherlayerChild.getChildInterface());
- t.merge(LogicalDatastoreType.OPERATIONAL, higherLayerIfChildStateId, ifaceBuilder.build());
- InterfaceParentEntryKey higherLayerParentEntryKey = new InterfaceParentEntryKey(higherlayerChild.getChildInterface());
+ NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ handleInterfaceStateUpdates(portName, nodeConnectorId,
+ transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
+
+ InterfaceParentEntry interfaceParentEntry =
+ InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(portName, dataBroker);
+ if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
+ for (InterfaceChildEntry higherlayerChild : interfaceParentEntry.getInterfaceChildEntry()) {
+ handleInterfaceStateUpdates(higherlayerChild.getChildInterface(),
+ nodeConnectorId, transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
InterfaceParentEntry higherLayerParent =
- InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(higherLayerParentEntryKey, dataBroker);
- if(higherLayerParent != null && higherLayerParent.getInterfaceChildEntry() != null) {
+ InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(higherlayerChild.getChildInterface(), dataBroker);
+ if (higherLayerParent != null && higherLayerParent.getInterfaceChildEntry() != null) {
for (InterfaceChildEntry interfaceChildEntry : higherLayerParent.getInterfaceChildEntry()) {
- LOG.debug("Updating if-state entries for Vlan-Trunk Members for port: {}", portName);
//FIXME: If the no. of child entries exceeds 100, perform txn updates in batches of 100.
- InstanceIdentifier<Interface> ifChildStateId =
- IfmUtil.buildStateInterfaceId(interfaceChildEntry.getChildInterface());
- t.merge(LogicalDatastoreType.OPERATIONAL, ifChildStateId, ifaceBuilder.build());
+ handleInterfaceStateUpdates(interfaceChildEntry.getChildInterface(), nodeConnectorId,
+ transaction, dataBroker, ifaceBuilder, opstateModified, operStatusNew);
}
}
}
+ }else {
+ handleTunnelMonitoringUpdates(alivenessMonitorService, dataBroker, iface, operStatusNew, opstateModified);
}
-
- futures.add(t.submit());
+ futures.add(transaction.submit());
return futures;
}
-}
\ No newline at end of file
+
+ public static Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector){
+ Interface.OperStatus operStatus =
+ (flowCapableNodeConnector.getState().isLive() &&
+ !flowCapableNodeConnector.getConfiguration().isPORTDOWN())
+ ? Interface.OperStatus.Up: Interface.OperStatus.Down;
+ return operStatus;
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
+ handleInterfaceStateUpdates(String interfaceName, NodeConnectorId nodeConnectorId,WriteTransaction transaction,
+ DataBroker dataBroker, InterfaceBuilder ifaceBuilder, boolean opStateModified,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState){
+ LOG.debug("updating interface state entry for {}", interfaceName);
+ InstanceIdentifier<Interface> ifStateId = IfmUtil.buildStateInterfaceId(interfaceName);
+ ifaceBuilder.setKey(new InterfaceKey(interfaceName));
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
+ if (modifyOpState(iface, opStateModified)) {
+ LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
+ ifaceBuilder.setOperStatus(opState);
+ }
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build());
+
+ // if opstate has changed, add or remove ingress flow for l2vlan interfaces accordingly
+ if(modifyIngressFlow(iface, opStateModified)) {
+ handleVlanIngressFlowUpdates(dataBroker, opState, transaction, iface, nodeConnectorId, ifStateId);
+ }
+ return iface;
+ }
+
+ public static void handleTunnelMonitoringUpdates(AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+ Interface.OperStatus operStatus, boolean opStateModified){
+ // start/stop monitoring based on opState
+ if(!modifyTunnel(iface, opStateModified)){
+ return;
+ }
+
+ LOG.debug("handling tunnel monitoring updates for {} due to opstate modification", iface.getName());
+ if (operStatus == Interface.OperStatus.Down)
+ AlivenessMonitorUtils.stopLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
+ else
+ AlivenessMonitorUtils.startLLDPMonitoring(alivenessMonitorService, dataBroker, iface);
+ }
+
+ public static boolean modifyOpState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+ boolean opStateModified){
+ return (opStateModified && (iface == null || iface != null && iface.isEnabled()));
+ }
+
+ public static boolean modifyIngressFlow(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+ boolean opStateModified){
+ return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) == null;
+ }
+
+ public static boolean modifyTunnel(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+ boolean opStateModified){
+ return modifyOpState(iface, opStateModified) && iface != null && iface.getAugmentation(IfTunnel.class) != null;
+ }
+
+ public static void handleVlanIngressFlowUpdates(DataBroker dataBroker, Interface.OperStatus opState, WriteTransaction transaction,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface,
+ NodeConnectorId nodeConnectorId, InstanceIdentifier<Interface> ifStateId){
+ LOG.debug("handling vlan ingress flow updates for {}", iface.getName());
+ Interface ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(ifStateId, dataBroker);
+ BigInteger dpId = new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
+ if (opState == org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Up) {
+ long portNo = Long.valueOf(IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId));
+ List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
+ FlowBasedServicesUtils.installVlanFlow(dpId, portNo, iface, transaction, matches, ifState.getIfIndex());
+ } else {
+ FlowBasedServicesUtils.removeIngressFlow(iface.getName(), dpId, transaction);
+ }
+ }
+}
// create bridge reference entry in interface meta operational DS
InterfaceMetaUtils.createBridgeRefEntry(dpnId, bridgeIid, writeTransaction);
- // FIX for OVSDB Bug - manually copying the bridge info from topology operational DS to config DS
- SouthboundUtils.addBridge(bridgeIid, bridgeNew, dataBroker, futures);
-
// handle pre-provisioning of tunnels for the newly connected dpn
BridgeEntry bridgeEntry = InterfaceMetaUtils.getBridgeEntryFromConfigDS(dpnId, dataBroker);
if (bridgeEntry == null) {
+ LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
futures.add(writeTransaction.submit());
return futures;
}
//delete bridge reference entry in interface meta operational DS
InterfaceMetaUtils.deleteBridgeRefEntry(dpnId, transaction);
- // Workaround for ovsdb bug for delete TEP..
- Optional<OvsdbBridgeAugmentation> bridgeNodeOptional =
- IfmUtil.read(LogicalDatastoreType.OPERATIONAL, bridgeIid, dataBroker);
- if (!bridgeNodeOptional.isPresent()) {
- SouthboundUtils.deleteBridge(bridgeIid, dataBroker, futures);
- }
-
futures.add(transaction.submit());
return futures;
}
import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils;
import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.utilities.SouthboundUtils;
-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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.BridgeEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.BridgeEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.bridge._interface.info.bridge.entry.BridgeInterfaceEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
OvsdbTerminationPointAugmentation terminationPointOld) {
List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+ if (InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(terminationPointNew.getName(), dataBroker) == null) {
+ return futures;
+ }
// update opstate of interface if TEP has gone down/up as a result of BFD monitoring
LOG.debug("updating tunnel state for interface {}", terminationPointNew.getName());
WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
}
}
- public static void addBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
- OvsdbBridgeAugmentation bridgeAugmentation,
- DataBroker dataBroker, List<ListenableFuture<Void>> futures){
- WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
- NodeId nodeId = InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)).getNodeId();
- NodeBuilder bridgeNodeBuilder = new NodeBuilder();
- bridgeNodeBuilder.setNodeId(nodeId);
- bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentation);
- tx.put(LogicalDatastoreType.CONFIGURATION, createNodeInstanceIdentifier(nodeId), bridgeNodeBuilder.build(), true);
- futures.add(tx.submit());
- }
-
- public static void deleteBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
- DataBroker dataBroker, List<ListenableFuture<Void>> futures){
- WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
- NodeId nodeId = InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)).getNodeId();
- tx.delete(LogicalDatastoreType.CONFIGURATION, createNodeInstanceIdentifier(nodeId));
- futures.add(tx.submit());
- }
-
private static void addVlanPortToBridge(InstanceIdentifier<?> bridgeIid, IfL2vlan ifL2vlan, IfTunnel ifTunnel,
OvsdbBridgeAugmentation bridgeAugmentation, String bridgeName,
String portName, DataBroker dataBroker, WriteTransaction t) {
}
Map<String, String> options = Maps.newHashMap();
- options.put("key", "flow");
+ if(!ifTunnel.getTunnelInterfaceType().equals(TunnelTypeMplsOverGre.class) ) {
+ options.put("key", "flow");
+ }
IpAddress localIp = ifTunnel.getTunnelSource();
options.put("local_ip", localIp.getIpv4Address().getValue());
return bfdBuilder.build();
}
- private static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node,
- String portName){
- InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
- .create(NetworkTopology.class)
- .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
- .child(Node.class,node.getKey())
- .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
-
- LOG.debug("Termination point InstanceIdentifier generated : {}", terminationPointPath);
- return terminationPointPath;
- }
-
public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(NodeKey nodekey,
String portName){
InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
return terminationPointPath;
}
-
- public static InstanceIdentifier<Node> createNodeInstanceIdentifier(NodeId nodeId) {
- return InstanceIdentifier
- .create(NetworkTopology.class)
- .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
- .child(Node.class,new NodeKey(nodeId));
- }
}
import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers.HwVTEPConfigRemoveHelper;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.confighelpers.HwVTEPInterfaceConfigAddHelper;
+import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateRemoveHelper;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.statehelpers.HwVTEPInterfaceStateUpdateHelper;
import org.opendaylight.vpnservice.interfacemgr.renderer.hwvtep.utilities.SouthboundUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
HwVTEPInterfaceConfigAddHelper addHelper;
HwVTEPConfigRemoveHelper removeHelper;
HwVTEPInterfaceStateUpdateHelper updateHelper;
+ HwVTEPInterfaceStateRemoveHelper stateRemoveHelper;
BigInteger dpId = BigInteger.valueOf(1);
Interface hwVTEPInterfaceEnabled;
//Verify
verify(mockWriteTx).put(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier, tBuilder.build(), true);
}
+
+ @Test
+ public void testRemoveExternalTunnels(){
+
+ stateRemoveHelper.removeExternalTunnel(dataBroker, tunnelsInstanceIdentifier);
+
+ //Verify
+ verify(mockWriteTx).delete(LogicalDatastoreType.CONFIGURATION, tunnelsInstanceIdentifier);
+ }
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
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.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
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.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
public class InterfaceManagerTestUtil {
public static final String interfaceName = "s1-eth1";
- public static final String interfaceName2 = "s1-eth2";
+ public static final String childInterface = "s1-eth1-trunk";
public static final String tunnelInterfaceName = "s2-gre1";
public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface buildStateInterface(String ifaceName, String physAddress,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus opState){
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
+ if(physAddress != null) {
+ ifaceBuilder.setPhysAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress.getDefaultInstance(physAddress));
+ }
+ ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(ifaceName));
+ ifaceBuilder.setOperStatus(opState);
+ return ifaceBuilder.build();
+ }
+
public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface buildStateInterface(
String ifName, NodeConnectorId ncId) {
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder =
IpAddress remoteIp = new IpAddress(Ipv4Address.getDefaultInstance(remoteIpStr));
IpAddress localIp = new IpAddress(Ipv4Address.getDefaultInstance(localIpStr));
IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(localIp).setTunnelSource(localIp)
- .setTunnelInterfaceType( tunType).setInternal(true).build();
+ .setTunnelInterfaceType( tunType).setInternal(true).setMonitorEnabled(false).build();
builder.addAugmentation(IfTunnel.class, tunnel);
return builder.build();
}
return ncBuilder.build();
}
+ public static FlowCapableNodeConnector buildFlowCapableNodeConnector(boolean isPortDown, boolean isLive, String macAddress) {
+ PortConfig portConfig = new PortConfig(false, false, false, isPortDown);
+ State state = new StateBuilder().setBlocked(true).setLinkDown(false).setLive(isLive).build();
+ FlowCapableNodeConnectorBuilder fcNodeConnector = new FlowCapableNodeConnectorBuilder().
+ setHardwareAddress(MacAddress.getDefaultInstance(macAddress)).setConfiguration(portConfig).setState(state);
+ return fcNodeConnector.build();
+ }
+
public static NodeConnectorId buildNodeConnectorId(BigInteger dpn, long portNo) {
return new NodeConnectorId(buildNodeConnectorString(dpn, portNo));
}
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 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,
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info._interface.parent.entry.InterfaceChildEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
IfindexInterface = InterfaceManagerTestUtil.buildIfIndexInterface(100, InterfaceManagerTestUtil.interfaceName);
ifIndexId = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(100)).build();
interfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.interfaceName));
- childInterfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.interfaceName2));
+ childInterfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(InterfaceManagerTestUtil.childInterface));
interfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.interfaceName);
- childInterfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.interfaceName2);
+ childInterfaceStateIdentifier = IfmUtil.buildStateInterfaceId(InterfaceManagerTestUtil.childInterface);
vlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName, "Test Vlan Interface1", true, L2vlan.class, BigInteger.valueOf(1));
vlanInterfaceDisabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName, "Test Vlan Interface1", false, L2vlan.class, BigInteger.valueOf(1));
tunnelInterfaceEnabled = InterfaceManagerTestUtil.buildTunnelInterface(dpId, InterfaceManagerTestUtil.tunnelInterfaceName ,"Test Tunnel Interface", true, TunnelTypeGre.class, "192.168.56.101", "192.168.56.102");
- childVlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.interfaceName2, "Test Vlan Interface2", true, L2vlan.class, BigInteger.valueOf(1));
+ childVlanInterfaceEnabled = InterfaceManagerTestUtil.buildInterface(InterfaceManagerTestUtil.childInterface, "Test Vlan Interface2", true, L2vlan.class, BigInteger.valueOf(1));
interfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.interfaceName);
interfaceParentEntryIdentifier = InterfaceMetaUtils.getInterfaceParentEntryIdentifier(interfaceParentEntryKey);
- higherLayerInterfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.interfaceName2);
+ higherLayerInterfaceParentEntryKey = new InterfaceParentEntryKey(InterfaceManagerTestUtil.childInterface);
higherLevelInterfaceParentEntryIdentifier= InterfaceMetaUtils.getInterfaceParentEntryIdentifier(higherLayerInterfaceParentEntryKey);
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
List<String> lowerLayerIfList = new ArrayList<>();
InterfaceParentEntryBuilder ifaceParentEntryBuilder = new InterfaceParentEntryBuilder();
List<InterfaceChildEntry> ifaceChildEntryList= new ArrayList<>();
- ifaceChildEntryList.add(new InterfaceChildEntryBuilder().setChildInterface(InterfaceManagerTestUtil.interfaceName2).build());
+ ifaceChildEntryList.add(new InterfaceChildEntryBuilder().setChildInterface(InterfaceManagerTestUtil.childInterface).build());
interfaceParentEntry = ifaceParentEntryBuilder.setInterfaceChildEntry(ifaceChildEntryList).build();
InterfaceParentEntryBuilder higherLayerIfParentEntryBuilder = new InterfaceParentEntryBuilder();
doReturn(idOutputOptional).when(idManager).allocateId(getIdInput);
AllocateIdInput getIdInput2 = new AllocateIdInputBuilder()
.setPoolName(IfmConstants.IFM_IDPOOL_NAME)
- .setIdKey(InterfaceManagerTestUtil.interfaceName2).build();
+ .setIdKey(InterfaceManagerTestUtil.childInterface).build();
doReturn(idOutputOptional2).when(idManager).allocateId(getIdInput2);
addHelper.addState(dataBroker, idManager, mdsalManager, alivenessMonitorService,
doReturn(Futures.immediateCheckedFuture(expectedStateInterface)).when(mockReadTx).read(
LogicalDatastoreType.OPERATIONAL, interfaceStateIdentifier);
+ doReturn(Futures.immediateCheckedFuture(expectedStateInterface)).when(mockReadTx).read(
+ LogicalDatastoreType.OPERATIONAL, childInterfaceStateIdentifier);
doReturn(Futures.immediateCheckedFuture(expectedParentEntry)).when(mockReadTx).read(
LogicalDatastoreType.CONFIGURATION, interfaceParentEntryIdentifier);
doReturn(Futures.immediateCheckedFuture(higherLayerParentOptional)).when(mockReadTx).read(
doReturn(Futures.immediateCheckedFuture(expectedChildInterface)).when(mockReadTx).read(
LogicalDatastoreType.CONFIGURATION, childInterfaceInstanceIdentifier);
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
- ifaceBuilder.setAdminStatus(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up)
- .setPhysAddress(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress.getDefaultInstance("AA:AA:AA:AA:AA:AA"));
- ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(InterfaceManagerTestUtil.interfaceName));
- ifaceBuilder.setOperStatus(OperStatus.Down);
-
- stateInterface = ifaceBuilder.build();
-
- FlowCapableNodeConnectorBuilder fcNodeConnectorOldupdate = new FlowCapableNodeConnectorBuilder().setHardwareAddress(MacAddress.getDefaultInstance("AA:AA:AA:AA:AA:AB"));
- FlowCapableNodeConnectorBuilder fcNodeConnectorNewupdate = new FlowCapableNodeConnectorBuilder().setHardwareAddress(MacAddress.getDefaultInstance("AA:AA:AA:AA:AA:AA"));
-
- StateBuilder b2 = new StateBuilder().setBlocked(true).setLinkDown(false);
- StateBuilder b3 = new StateBuilder().setBlocked(false).setLinkDown(true);
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface parentInterface = InterfaceManagerTestUtil.buildStateInterface(InterfaceManagerTestUtil.interfaceName, null, OperStatus.Down);
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface childInterface = InterfaceManagerTestUtil.buildStateInterface(InterfaceManagerTestUtil.childInterface, null, OperStatus.Down);
- fcNodeConnectorOldupdate.setState(b2.build());
- fcNodeConnectorNewupdate.setState(b3.build());
+ FlowCapableNodeConnector fcNodeConnectorOld = InterfaceManagerTestUtil.buildFlowCapableNodeConnector(false, true, "AA:AA:AA:AA:AA:AA");
+ FlowCapableNodeConnector fcNodeConnectorNew = InterfaceManagerTestUtil.buildFlowCapableNodeConnector(true, false, "AA:AA:AA:AA:AA:AA");
- updateHelper.updateState(fcNodeConnectorId, alivenessMonitorService, dataBroker, InterfaceManagerTestUtil.interfaceName, fcNodeConnectorNewupdate.build(), fcNodeConnectorOldupdate.build());
+ updateHelper.updateState(fcNodeConnectorId, alivenessMonitorService, dataBroker, InterfaceManagerTestUtil.interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
- verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,interfaceStateIdentifier,stateInterface);
- verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,childInterfaceStateIdentifier,stateInterface);
+ verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,interfaceStateIdentifier,parentInterface);
+ verify(mockWriteTx).merge(LogicalDatastoreType.OPERATIONAL,childInterfaceStateIdentifier,childInterface);
}
-}
\ No newline at end of file
+}
import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceTopologyStateUpdateHelper;
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.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatusBuilder;
BridgeEntry bridgeEntry = null;
ParentRefs parentRefs = null;
InstanceIdentifier<Interface> interfaceInstanceIdentifier = null;
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceStateIdentifier = null;
Interface tunnelInterfaceEnabled = null;
BridgeInterfaceEntry bridgeInterfaceEntry;
BridgeInterfaceEntryKey bridgeInterfaceEntryKey;
bridgeOld = InterfaceManagerTestUtil.getOvsdbBridgeRef("s1");
bridgeEntryIid = InterfaceMetaUtils.getBridgeEntryIdentifier(new BridgeEntryKey(dpId));
interfaceInstanceIdentifier = IfmUtil.buildId(InterfaceManagerTestUtil.tunnelInterfaceName);
+ interfaceStateIdentifier = IfmUtil.buildStateInterfaceId(newTerminationPoint.getName());
bridgeInterfaceEntryKey = new BridgeInterfaceEntryKey(InterfaceManagerTestUtil.tunnelInterfaceName);
bridgeInterfaceEntry =
new BridgeInterfaceEntryBuilder().setKey(bridgeInterfaceEntryKey)
interfaceBfdStatus.add(new InterfaceBfdStatusBuilder().setBfdStatusKey(SouthboundUtils.BFD_OP_STATE).setBfdStatusValue(SouthboundUtils.BFD_STATE_UP).build());
List bfdStatusSpy = spy(interfaceBfdStatus);
when(newTerminationPoint.getInterfaceBfdStatus()).thenReturn(bfdStatusSpy);
- updateHelper.updateTunnelState(dataBroker, newTerminationPoint, null);
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState = new InterfaceBuilder().setKey(new InterfaceKey(InterfaceManagerTestUtil.interfaceName)).build();
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> expectedInterface = Optional.of(ifState);
+
+ doReturn(Futures.immediateCheckedFuture(expectedInterface)).when(mockReadTx).read(
+ LogicalDatastoreType.OPERATIONAL, interfaceStateIdentifier);
+ updateHelper.updateTunnelState(dataBroker, newTerminationPoint, null);
+
//verify
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
IfmUtil.buildStateInterfaceId(null);
System.out.println(fmt.format(VXLAN_OUTPUT_FORMAT + "\n",
(interfaceInfo == null) ? InterfaceOpState.DOWN : interfaceInfo.getOpState(),
String.format("%s/%s", parentRefs.getDatapathNodeIdentifier(),
- parentRefs.getParentInterface()),
+ iface.getName()),
(interfaceInfo == null) ? UNSET : interfaceInfo.getInterfaceTag(), ""));
fmt.close();
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
public interface IITMProvider {
// APIs used by i
public DataBroker getDataBroker();
public void showTeps();
+ public void showState(TunnelList tunnels);
public void deleteVtep(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
String gatewayIp, String transportZone);
//Tunnel Monitoring
public static final boolean DEFAULT_MONITOR_ENABLED = true;
public static final int DEFAULT_MONITOR_INTERVAL = 10;
+ public static final int BFD_DEFAULT_MONITOR_INTERVAL = 100;
public static final String DUMMY_IP_ADDRESS = "0.0.0.0";
public static final String TUNNEL_TYPE_VXLAN = "VXLAN";
public static final String TUNNEL_TYPE_GRE = "GRE";
+ public static final String TUNNEL_TYPE_MPLS_OVER_GRE = "MPLS_OVER_GRE";
+ public static final String TUNNEL_TYPE_INVALID = "Invalid";
}
leaf destination-dpid {
type uint64;
}
+ leaf tunnel-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
}
output {
leaf interface-name {
leaf destination-ip {
type inet:ip-address;
}
+ leaf tunnel-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
}
output {
leaf interface-name {
leaf destination-node {
type string;
}
+ leaf tunnel-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
}
output {
leaf interface-name {
}
}
+ rpc add-l2-gw-mlag-device {
+ description "used for building tunnels between teps on all Dpns and hwVtep";
+ input {
+ leaf topology-id {
+ type string;
+ }
+ leaf-list node-id {
+ type string;
+ }
+ leaf ip-address {
+ type inet:ip-address;
+ }
+ }
+ }
rpc delete-l2-gw-device {
description "used for deleting tunnels between teps on all Dpns and hwVtep";
input {
}
}
+ rpc delete-l2-gw-mlag-device {
+ description "used for deleting tunnels between teps on all Dpns and hwVtep";
+ input {
+ leaf topology-id {
+ type string;
+ }
+ leaf-list node-id {
+ type string;
+ }
+ leaf ip-address {
+ type inet:ip-address;
+ }
+ }
+ }
}
\ No newline at end of file
/* Operational state */
+ identity tep-type-base {
+ description "Base TEP device type";
+ }
+ identity tep-type-internal {
+ base tep-type-base;
+ description "TEP type internal e.g. Compute OVS";
+ }
+ identity tep-type-external {
+ base tep-type-base;
+ description "TEP type external e.g. DC Gateway";
+ }
+ identity tep-type-hwvtep {
+ base tep-type-base;
+ description "TEP type Hwvtep e.g. TOR devices";
+ }
+ typedef tep-type {
+ type identityref {
+ base tep-type-base;
+ }
+ description "This type is used to refer to an TEP Device Type.";
+ }
container dpn-endpoints {
list DPN-TEPs-info {
/* Minimum 1 port. We may for now support only two ports */
list tunnel-end-points {
-
- key "portname VLAN-ID ip-address"; /* Multiple tunnels on the same physical port but on different VLAN can be supported */
+ ordered-by user;
+ key "portname VLAN-ID ip-address tunnel-type"; /* Multiple tunnels on the same physical port but on different VLAN can be supported */
leaf portname {
type string;
container tunnel-list {
list internal-tunnel {
- key "source-DPN destination-DPN";
+ key "source-DPN destination-DPN transport-type";
leaf source-DPN {
type uint64;
leaf destination-DPN {
type uint64;
}
+ leaf transport-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
/* logical-group interface id */
container external-tunnel-list {
list external-tunnel {
- key "source-device destination-device";
+ key "source-device destination-device transport-type";
leaf source-device {
type string; //dpnid or node-id
type string; //dpn-id or node-id or ip
}
+ leaf transport-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
/* logical-group interface id */
leaf tunnel-interface-name {
}
}
-
+ grouping tep-info-attributes {
+ leaf tep-device-type {
+ type identityref {
+ base tep-type-base;
+ }
+ }
+ leaf tep-device-id {
+ type string; //dpnid or node-id
+ }
+ leaf tep-ip {
+ type inet:ip-address; //dpnid or node-id
+ }
+ }
+
+ container tunnels_state {
+ list state-tunnel-list {
+ key "tunnel-interface-name";
+ leaf tunnel-interface-name {
+ type string;
+ }
+ leaf tunnel-state {
+ type boolean;
+ config false;
+ }
+ container src-info {
+ uses tep-info-attributes;
+ }
+ container dst-info {
+ uses tep-info-attributes;
+ }
+ leaf transport-type {
+ type identityref {
+ base odlif:tunnel-type-base;
+ }
+ }
+ }
+ }
notification itm-tunnel-build-complete{
}
container transport-zones {
list transport-zone {
+ ordered-by user;
key zone-name;
leaf zone-name {
type string;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
//import org.opendaylight.vpnservice.interfacemgr.util.OperationalIfmUtil;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan;
import org.opendaylight.vpnservice.itm.impl.ItmUtils;
import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
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.inet.types.rev100924.IpPrefix;
+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.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabledBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorIntervalBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZonesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.Vteps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.VtepsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.VtepsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
result.add(String.format("Tunnel Monitoring (for VXLAN tunnels): %s", (monitorEnabled ? "On" : "Off")));
result.add(String.format("Tunnel Monitoring Interval (for VXLAN tunnels): %d", monitorInterval));
result.add(System.lineSeparator());
- result.add(String.format("%-16s %-16s %-16s %-12s %-12s %-12s %-12s %-12s", "TransportZone", "TunnelType", "SubnetMask",
+ result.add(String.format("%-16s %-16s %-16s %-12s %-12s %-12s %-16s %-12s", "TransportZone", "TunnelType", "SubnetMask",
"GatewayIP", "VlanID", "DpnID", "IPAddress", "PortName"));
- result.add("--------------------------------------------------------------------------------------------------------------");
+ result.add("------------------------------------------------------------------------------------------------------------------------------");
for (TransportZone tZ : tZones.getTransportZone()) {
if (tZ.getSubnets() == null || tZ.getSubnets().isEmpty()) {
LOG.error("Transport Zone " + tZ.getZoneName() + "has no subnets");
strTunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
else
strTunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
- result.add(String.format("%-16s %-16s %-16s %-12s %-12s %-12s %-12s %-12s", tZ.getZoneName(), strTunnelType, sub
+ result.add(String.format("%-16s %-16s %-16s %-12s %-12s %-12s %-16s %-12s", tZ.getZoneName(), strTunnelType, sub
.getPrefix().getIpv4Prefix().getValue(), sub.getGatewayIp().getIpv4Address()
.getValue(), sub.getVlanId().toString(), vtep.getDpnId().toString(), vtep
.getIpAddress().getIpv4Address().getValue(), vtep.getPortname().toString()));
e.printStackTrace();
}
}
-/*
- public void showState(TunnelsState tunnelsState, boolean tunnelMonitorEnabled) {
- List<StateTunnelList> tunnelLists = tunnelsState.getStateTunnelList();
+
+ public void showState(TunnelList tunnels, boolean tunnelMonitorEnabled) {
+ IfTunnel tunnelInterface = null;
+ IfL2vlan l2Vlan = null;
+ List<InternalTunnel> tunnelLists = tunnels.getInternalTunnel();
if (tunnelLists == null || tunnelLists.isEmpty()) {
- System.out.println("No Logical Tunnels Exist");
+ System.out.println("No Internal Tunnels Exist");
return;
}
if (!tunnelMonitorEnabled) {
System.out.println("Tunnel Monitoring is Off");
}
- System.out.println(String.format("%-16s %-16s %-16s %-10s %-16s %-8s %-10s %-10s", "Source-DPN",
- "Destination-DPN", "SourcePortName", "Source-IP", "Destination-IP", "VLan-ID", "Trunk-State",
- "Logical-Tunnel-State"));
- System.out.println("----------------------------------------------------------------------------------------------------------------------");
-
- for (StateTunnelList tunnel : tunnelLists) {
- String logicaltunnelState = (tunnel.isLogicalTunnelState()) ? "UP" : "DOWN";
- try {
- List<String> trunks =
- interfaceManager.getTunnelInterfacesOfLogicalGroup(tunnel.getLogicalTunnelGroupName());
- if (trunks != null && !trunks.isEmpty()) {
- for (String trunk : trunks) {
- List<String> params = Arrays.asList(trunk.split(":"));
- LOG.trace("trunk {} for LogicalIf {} ", trunk, tunnel.getLogicalTunnelGroupName());
- String trunkState = (OperationalIfmUtil.isInterfaceUp(dataBroker, trunk)) ? "UP" : "DOWN";
- System.out.println(String.format("%-16s %-16s %-16s %-10s %-16s %-8s %-10s %-10s", tunnel
- .getSourceDPN().toString(), tunnel.getDestinationDPN().toString(), params
- .get(1), params.get(3), params.get(4), params.get(2), trunkState,
- logicaltunnelState));
- }
- } else {
- LOG.error("No trunks for " + tunnel.getLogicalTunnelGroupName());
+ String displayFormat = "%-16s %-16s %-16s %-16s %-16s %-8s %-10s %-10s";
+ System.out.println(String.format(displayFormat, "Tunnel Name", "Source-DPN",
+ "Destination-DPN", "Source-IP", "Destination-IP", "Vlan Id", "Trunk-State", "Transport Type"));
+ System.out.println("-------------------------------------------------------------------------------------------------------------------------------------");
+
+ for (InternalTunnel tunnel : tunnelLists) {
+ String tunnelInterfaceName = tunnel.getTunnelInterfaceName();
+ LOG.trace("tunnelInterfaceName::: {}", tunnelInterfaceName);
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
+ ItmUtils.buildStateInterfaceId(tunnelInterfaceName);
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional =
+ ItmUtils.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker);
+ String tunnelState = "DOWN" ;
+ if (ifStateOptional.isPresent()) {
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface iface = ifStateOptional.get() ;
+ if(iface.getAdminStatus() == AdminStatus.Up && iface.getOperStatus() == OperStatus.Up)
+ tunnelState = "UP" ;
+ }
+ InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+ Optional<Interface> ifaceObj = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, dataBroker) ;
+ if (ifaceObj.isPresent()) {
+ l2Vlan = (IfL2vlan) ifaceObj.get().getAugmentation(IfL2vlan.class);
+ tunnelInterface = (IfTunnel) ifaceObj.get().getAugmentation(IfTunnel.class);
}
- } catch (InterfaceNotFoundException e) {
- LOG.error("if not found " + tunnel.getLogicalTunnelGroupName());
- }
- }
+ Class<? extends TunnelTypeBase> tunType = tunnelInterface.getTunnelInterfaceType();
+ String tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
+ if( tunType.equals(TunnelTypeVxlan.class))
+ tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
+ else if( tunType.equals(TunnelTypeGre.class) )
+ tunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
+ int vlanId = 0;
+ if( l2Vlan != null ) {
+ vlanId = l2Vlan.getVlanId().getValue() ;
+ }
+ System.out.println(String.format(displayFormat, tunnel.getTunnelInterfaceName(), tunnel
+ .getSourceDPN().toString(), tunnel.getDestinationDPN().toString(), tunnelInterface.getTunnelSource().getIpv4Address().getValue(), tunnelInterface.getTunnelDestination().getIpv4Address().getValue(),vlanId, tunnelState ,
+ tunnelType));
+ }
}
-*/
+
// deletes from ADD-cache if it exists.
public boolean isInCache(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
String gatewayIp, String transportZone) {
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.itm.api.IITMProvider;
import org.opendaylight.vpnservice.itm.impl.ItmUtils;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import java.util.ArrayList;
@Override
protected Object doExecute() throws Exception {
- /*
+
DataBroker broker = itmProvider.getDataBroker();
List<String> result = new ArrayList<String>();
- InstanceIdentifier<TunnelsState> path = InstanceIdentifier.builder(TunnelsState.class).build();
- Optional<TunnelsState> tunnels = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, path, broker);
+ InstanceIdentifier<TunnelList> path = InstanceIdentifier.builder(TunnelList.class).build();
+ Optional<TunnelList> tunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
if (tunnels.isPresent()) {
itmProvider.showState(tunnels.get());
}
else
- System.out.println("No Logical Tunnels Exist");
- */
- System.out.println( "Logical Tunnels state is not currently supported");
+ System.out.println("No Internal Tunnels Exist");
return null;
}
}
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.itm.globals.ITMConstants;
import org.opendaylight.vpnservice.itm.impl.ItmUtils;
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.inet.types.rev100924.IpPrefix;
// CHECK -- Assumption -- Only one End Point / Dpn for GRE/Vxlan Tunnels
TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
String interfaceName = firstEndPt.getInterfaceName();
- String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName, firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue());
+ String tunTypeStr = tunType.getName();
+ String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName, firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue(), tunTypeStr);
char[] subnetMaskArray = firstEndPt.getSubnetMask().getValue();
String subnetMaskStr = String.valueOf(subnetMaskArray);
SubnetUtils utils = new SubnetUtils(subnetMaskStr);
String dcGwyIpStr = String.valueOf(extIp.getValue());
- IpAddress gwyIpAddress = (utils.getInfo().isInRange(dcGwyIpStr)) ? null : firstEndPt.getGwIpAddress();
- String ifDescription = tunType.getName();
+ IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+ IpAddress gwyIpAddress = (utils.getInfo().isInRange(dcGwyIpStr)) ? gatewayIpObj : firstEndPt.getGwIpAddress();
logger.debug(" Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, source IP - {}, DC Gateway IP - {} gateway IP - {}", trunkInterfaceName, interfaceName, firstEndPt.getIpAddress(), extIp, gwyIpAddress);
- Interface iface = ItmUtils.buildTunnelInterface(teps.getDPNID(), trunkInterfaceName, String.format("%s %s", ifDescription, "Trunk Interface"), true, tunType, firstEndPt.getIpAddress(), extIp, gwyIpAddress, firstEndPt.getVLANID(), false,false,null);
+ Interface iface = ItmUtils.buildTunnelInterface(teps.getDPNID(), trunkInterfaceName, String.format("%s %s", ItmUtils.convertTunnelTypetoString(tunType), "Trunk Interface"), true, tunType, firstEndPt.getIpAddress(), extIp, gwyIpAddress, firstEndPt.getVLANID(), false,false,null);
logger.debug(" Trunk Interface builder - {} ", iface);
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
logger.debug(" Trunk Interface Identifier - {} ", trunkIdentifier);
// update external_tunnel_list ds
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, new ExternalTunnelKey(extIp.toString(), teps.getDPNID().toString()));
- ExternalTunnel tnl = ItmUtils.buildExternalTunnel(teps.getDPNID().toString(), extIp.toString(), trunkInterfaceName);
+ .child(ExternalTunnel.class, new ExternalTunnelKey(extIp.toString(), teps.getDPNID().toString(), tunType));
+ ExternalTunnel tnl = ItmUtils.buildExternalTunnel( teps.getDPNID().toString(), extIp.toString(),
+ tunType, trunkInterfaceName);
t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
}
futures.add(t.submit());
String cssID = dpn.getDPNID().toString();
String nodeId = hwVtepDS.getNodeId();
//CSS-TOR
+ Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+ Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
logger.trace("wire up {} and {}",tep, hwVtepDS);
if (!wireUp(dpn.getDPNID(), tep.getPortname(), sub.getVlanId(), tep.getIpAddress(), nodeId, hwVtepDS.getIpAddress(), tep.getSubnetMask(),
- sub.getGatewayIp(), sub.getPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+ sub.getGatewayIp(), sub.getPrefix(), tZone.getTunnelType(),monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
logger.error("Unable to build tunnel {} -- {}", tep.getIpAddress(), hwVtepDS.getIpAddress());
//TOR-CSS
logger.trace("wire up {} and {}", hwVtepDS,tep);
if (!wireUp(hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), cssID, tep.getIpAddress(), sub.getPrefix(),
- sub.getGatewayIp(), tep.getSubnetMask(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+ sub.getGatewayIp(), tep.getSubnetMask(), tZone.getTunnelType(), monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
logger.error("Unable to build tunnel {} -- {}", hwVtepDS.getIpAddress(), tep.getIpAddress());
}
for (HwVtep hwTep : cfgdHwVteps) {
InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
if (tZoneOptional.isPresent()) {
TransportZone tZone = tZoneOptional.get();
//do we need to check tunnel type?
if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
continue;//dont mesh with self
//TOR1-TOR2
+ Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+ Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
logger.trace("wire up {} and {}",hwTep, hwVtepDS);
if (!wireUp(hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(),
- hwTep.getIpPrefix(), hwTep.getGatewayIP(), sub.getPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+ hwTep.getIpPrefix(), hwTep.getGatewayIP(), sub.getPrefix(), tunType,monitorEnabled,
+ ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
logger.error("Unable to build tunnel {} -- {}", hwTep.getHwIp(), hwVtepDS.getIpAddress());
//TOR2-TOR1
logger.trace("wire up {} and {}", hwVtepDS,hwTep);
if (!wireUp(hwTep.getTopo_id(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), hwTep.getNode_id(), hwTep.getHwIp(),
- sub.getPrefix(), sub.getGatewayIp(), hwTep.getIpPrefix(), tZone.getTunnelType(), idManagerService, dataBroker, futures, t))
+ sub.getPrefix(), sub.getGatewayIp(), hwTep.getIpPrefix(), tunType, monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t))
logger.error("Unable to build tunnel {} -- {}", hwVtepDS.getIpAddress(), hwTep.getHwIp());
}
}
for (Vteps vtep : sub.getVteps()) {
//TOR-CSS
String cssID = vtep.getDpnId().toString();
+ Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+ Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
logger.trace("wire up {} and {}",hwTep, vtep);
if(!wireUp(hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(), cssID, vtep.getIpAddress(), hwTep.getIpPrefix(),
- hwTep.getGatewayIP(), sub.getPrefix(), tZone.getTunnelType(),idManagerService, dataBroker, futures, t ))
+ hwTep.getGatewayIP(), sub.getPrefix(), tunType,monitorEnabled, ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL, idManagerService, dataBroker, futures, t ))
logger.error("Unable to build tunnel {} -- {}", hwTep.getHwIp(), vtep.getIpAddress());
//CSS-TOR
logger.trace("wire up {} and {}", vtep,hwTep);
if(!wireUp(vtep.getDpnId(), vtep.getPortname(), sub.getVlanId(), vtep.getIpAddress(),
- hwTep.getNode_id(),hwTep.getHwIp(),sub.getPrefix(), sub.getGatewayIp(),hwTep.getIpPrefix(),tZone.getTunnelType(),idManagerService, dataBroker, futures, t ));
+ hwTep.getNode_id(),hwTep.getHwIp(),sub.getPrefix(), sub.getGatewayIp(),hwTep.getIpPrefix(),
+ tunType,monitorEnabled,ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL,idManagerService, dataBroker, futures, t ));
}
//for tunnels from TOR device
private static boolean wireUp(String topo_id, String srcNodeid, IpAddress srcIp, String dstNodeId, IpAddress dstIp, IpPrefix srcSubnet,
- IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType, IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
- IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? null : gWIp;
+ IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType,Boolean monitorEnabled,
+ Integer monitorInterval,IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
+ IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+ IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? gatewayIpObj : gWIp;
String parentIf = ItmUtils.getHwParentIf(topo_id, srcNodeid);
- String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf, srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue());
+ String tunTypeStr = tunType.getName();
+ String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
+ srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue(), tunTypeStr);
logger.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp, dstIp, gwyIpAddress);
Interface hwTunnelIf = ItmUtils.buildHwTunnelInterface(tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"),
- true, topo_id, srcNodeid, tunType, srcIp, dstIp, gwyIpAddress, true);
+ true, topo_id, srcNodeid, tunType, srcIp, dstIp, gwyIpAddress, monitorEnabled, monitorInterval);
InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(tunnelIfName)).build();
logger.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, hwTunnelIf);
+ ItmUtils.itmCache.addInterface(hwTunnelIf);
t.merge(LogicalDatastoreType.CONFIGURATION, ifIID, hwTunnelIf, true);
// also update itm-state ds?
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), getExternalTunnelKey(srcNodeid)));
- ExternalTunnel tnl = ItmUtils.buildExternalTunnel(getExternalTunnelKey(srcNodeid), getExternalTunnelKey(dstNodeId), tunnelIfName);
+ .child(ExternalTunnel.class, new ExternalTunnelKey( getExternalTunnelKey(dstNodeId), getExternalTunnelKey(srcNodeid), tunType));
+ ExternalTunnel tnl = ItmUtils.buildExternalTunnel( getExternalTunnelKey(srcNodeid),
+ getExternalTunnelKey(dstNodeId),
+ tunType, tunnelIfName);
t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
+ ItmUtils.itmCache.addExternalTunnel(tnl);
return true;
}
//for tunnels from CSS
private static boolean wireUp(BigInteger dpnId,String portname, Integer vlanId, IpAddress srcIp, String dstNodeId, IpAddress dstIp, IpPrefix srcSubnet,
- IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType, IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
- IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? null : gWIp;
+ IpAddress gWIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType,Boolean monitorEnabled, Integer monitorInterval,
+ IdManagerService idManagerService, DataBroker dataBroker, List<ListenableFuture<Void>> futures, WriteTransaction t) {
+ IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+ IpAddress gwyIpAddress = (srcSubnet.equals(dstSubnet)) ? gatewayIpObj : gWIp;
String parentIf = ItmUtils.getInterfaceName(dpnId, portname, vlanId);
- String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf, srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue());
+ String tunTypeStr = tunType.getName();
+ String tunnelIfName = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
+ srcIp.getIpv4Address().getValue(), dstIp.getIpv4Address().getValue(), tunTypeStr);
logger.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp, dstIp, gwyIpAddress);
- Interface extTunnelIf = ItmUtils.buildTunnelInterface(dpnId, tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"), true, tunType, srcIp, dstIp, gwyIpAddress, vlanId, false, true, 5L);
+ Interface extTunnelIf = ItmUtils.buildTunnelInterface(dpnId, tunnelIfName, String.format("%s %s", tunType.getName(), "Trunk Interface"), true, tunType, srcIp, dstIp, gwyIpAddress, vlanId, false,monitorEnabled, monitorInterval);
InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(tunnelIfName)).build();
logger.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, extTunnelIf);
t.merge(LogicalDatastoreType.CONFIGURATION, ifIID, extTunnelIf, true);
+ ItmUtils.itmCache.addInterface(extTunnelIf);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), dpnId.toString()));
- ExternalTunnel tnl = ItmUtils.buildExternalTunnel(dpnId.toString(), getExternalTunnelKey(dstNodeId), tunnelIfName);
+ .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId), dpnId.toString(), tunType));
+ ExternalTunnel tnl = ItmUtils.buildExternalTunnel( dpnId.toString(),
+ getExternalTunnelKey(dstNodeId),
+ tunType, tunnelIfName);
t.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
+ ItmUtils.itmCache.addExternalTunnel(tnl);
return true;
}
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.itm.globals.ITMConstants;
import org.opendaylight.vpnservice.itm.impl.ItmUtils;
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.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
}
for( DPNTEPsInfo teps : dpnTepsList) {
TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0) ;
- if( firstEndPt.getTunnelType().equals(tunType)) {
String interfaceName = firstEndPt.getInterfaceName() ;
- String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue()) ;
+ String trunkInterfaceName = ItmUtils.getTrunkInterfaceName( idManagerService, interfaceName,
+ firstEndPt.getIpAddress().getIpv4Address().getValue(),
+ extIp.getIpv4Address().getValue(),
+ tunType.getName());
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
+ ItmUtils.itmCache.removeInterface(trunkInterfaceName);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey(extIp.toString(), teps.getDPNID().toString()));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(extIp.toString(),
+ teps.getDPNID().toString(),
+ tunType));
t.delete(LogicalDatastoreType.CONFIGURATION, path);
+ logger.debug( "Deleting tunnel towards DC gateway, Tunnel interface name {} ",trunkInterfaceName );
+ ItmUtils.itmCache.removeExternalTunnel(trunkInterfaceName);
// Release the Ids for the trunk interface Name
- ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue() );
+ ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,interfaceName,firstEndPt.getIpAddress().getIpv4Address().getValue(), extIp.getIpv4Address().getValue(),tunType.getName());
}
- }
futures.add(t.submit()) ;
return futures ;
}
public static List<ListenableFuture<Void>> deleteHwVtepsTunnels(DataBroker dataBroker, IdManagerService idManagerService, List<DPNTEPsInfo> delDpnList ,List<HwVtep> cfgdHwVteps) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
WriteTransaction t = dataBroker.newWriteOnlyTransaction();
- if (null != delDpnList) {
- tunnelsFromCSS(delDpnList, idManagerService , futures, t , dataBroker);
- }
- if (null != cfgdHwVteps) {
- tunnelsFromhWVtep(cfgdHwVteps, idManagerService, futures, t, dataBroker);
- }
if (delDpnList != null || cfgdHwVteps != null)
+ tunnelsDeletion(delDpnList, cfgdHwVteps, idManagerService, futures, t, dataBroker);
futures.add(t.submit());
return futures;
}
- private static void tunnelsFromCSS(List<DPNTEPsInfo> cfgdDpnList, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
+ private static void tunnelsDeletion(List<DPNTEPsInfo> cfgdDpnList, List<HwVtep> cfgdhwVteps, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
+ if (cfgdDpnList != null && !cfgdDpnList.isEmpty()) {
for (DPNTEPsInfo dpn : cfgdDpnList) {
if (dpn.getTunnelEndPoints() != null && !dpn.getTunnelEndPoints().isEmpty())
for (TunnelEndPoints srcTep : dpn.getTunnelEndPoints()) {
- InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((srcTep.getTransportZone()))).build();
+ InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey((srcTep.getTransportZone())))
+ .build();
Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
if (tZoneOptional.isPresent()) {
TransportZone tZone = tZoneOptional.get();
for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
String cssID = dpn.getDPNID().toString();
//CSS-TOR-CSS
- deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(),
- srcTep.getInterfaceName(), srcTep.getIpAddress(),
- hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
- hwVtepDS.getIpAddress(), t, futures);
+ deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(), srcTep.getInterfaceName(), srcTep.getIpAddress(),
+ hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), tZone.getTunnelType(),
+ t, futures);
+ }
+ }
+ }
+ }
+ if (cfgdhwVteps != null && !cfgdhwVteps.isEmpty()) {
+ for (HwVtep hwVtep : cfgdhwVteps) {
+ deleteTrunksCSSTOR(dataBroker, idManagerService, dpn.getDPNID(), srcTep.getInterfaceName(), srcTep.getIpAddress(),
+ hwVtep.getTopo_id(), hwVtep.getNode_id(), hwVtep.getHwIp(),
+ TunnelTypeVxlan.class, t, futures);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (cfgdhwVteps != null && !cfgdhwVteps.isEmpty()) {
+ for (HwVtep hwTep : cfgdhwVteps) {
+ logger.trace("processing hwTep from list {}", hwTep);
+ for (HwVtep hwTepRemote : cfgdhwVteps) {
+ if (!hwTep.getHwIp().equals(hwTepRemote.getHwIp())) {
+ deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
+ hwTep.getHwIp(), hwTepRemote.getTopo_id(), hwTepRemote.getNode_id(),
+ hwTepRemote.getHwIp(), TunnelTypeVxlan.class, t, futures);
+ }
+ }
+ InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
+ Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
+ if (tZoneOptional.isPresent()) {
+ TransportZone tZone = tZoneOptional.get();
+ logger.trace("subnets under tz {} are {}", tZone.getZoneName(), tZone.getSubnets());
+ if (tZone.getSubnets() != null && !tZone.getSubnets().isEmpty()) {
+ for (Subnets sub : tZone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
+ logger.trace("hwtepDS exists {}", hwVtepDS);
+ if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
+ continue;//dont delete tunnels with self
+ logger.trace("deleting tor-tor {} and {}", hwTep, hwVtepDS);
+ deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
+ hwTep.getHwIp(), hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
+ hwVtepDS.getIpAddress(), tZone.getTunnelType(),
+ t, futures);
}
}
+ if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+ for (Vteps vtep : sub.getVteps()) {
+ logger.trace("deleting tor-css-tor {} and {}", hwTep, vtep);
+ String parentIf = ItmUtils.getInterfaceName(vtep.getDpnId(), vtep.getPortname(), sub.getVlanId());
+ deleteTrunksCSSTOR(dataBroker, idManagerService, vtep.getDpnId(), parentIf, vtep.getIpAddress(),
+ hwTep.getTopo_id(), hwTep.getNode_id(), hwTep.getHwIp(),
+ tZone.getTunnelType(), t, futures);
+ }
+ }
}
}
}
- private static void tunnelsFromhWVtep(List<HwVtep> cfgdHwVteps, IdManagerService idManagerService, List<ListenableFuture<Void>> futures, WriteTransaction t, DataBroker dataBroker) {
- for (HwVtep hwTep : cfgdHwVteps) {
- logger.trace("processing hwTep from list {}",hwTep);
- InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class).child(TransportZone.class, new TransportZoneKey((hwTep.getTransportZone()))).build();
- Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
- if (tZoneOptional.isPresent()) {
- TransportZone tZone = tZoneOptional.get();
//do we need to check tunnel type?
- logger.trace("subnets under tz {} are {}",tZone.getZoneName(),tZone.getSubnets());
- if (tZone.getSubnets() != null && !tZone.getSubnets().isEmpty()) {
- for (Subnets sub : tZone.getSubnets()) {
- if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
- for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
- logger.trace("hwtepDS exists {}",hwVtepDS);
//do i need to check node-id?
//for mlag case and non-m-lag case, isnt it enough to just check ipaddress?
- if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp()))
- continue;//dont delete tunnels with self
//TOR-TOR
- logger.trace("deleting tor-tor {} and {}",hwTep,hwVtepDS);
- deleteTrunksTORTOR(dataBroker, idManagerService, hwTep.getTopo_id(), hwTep.getNode_id(),
- hwTep.getHwIp(), hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(),
- hwVtepDS.getIpAddress(), t, futures);
- }
- }
- if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
- for (Vteps vtep : sub.getVteps()) {
//TOR-CSS
- logger.trace("deleting tor-css-tor {} and {}",hwTep,vtep);
- String parentIf = ItmUtils.getInterfaceName(vtep.getDpnId(),vtep.getPortname(),sub.getVlanId());
- deleteTrunksCSSTOR(dataBroker,idManagerService,vtep.getDpnId(),parentIf,vtep.getIpAddress(),
- hwTep.getTopo_id(),hwTep.getNode_id(),hwTep.getHwIp(),t,futures );
- }
- }
- }
- }
- }
- }
- }
private static void deleteTrunksCSSTOR(DataBroker dataBroker, IdManagerService idManagerService, BigInteger dpnid,
String interfaceName, IpAddress cssIpAddress, String topologyId, String nodeId, IpAddress hWIpAddress,
- WriteTransaction t, List<ListenableFuture<Void>> futures) {
+ Class<? extends TunnelTypeBase> tunType, WriteTransaction t,
+ List<ListenableFuture<Void>> futures) {
//CSS-TOR
- if (trunkExists(dpnid.toString(), nodeId,dataBroker)) {
+ if (trunkExists(dpnid.toString(), nodeId, tunType, dataBroker)) {
logger.trace("deleting tunnel from {} to {} ", dpnid.toString(), nodeId);
String parentIf = interfaceName;
String fwdTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf,cssIpAddress.getIpv4Address().getValue(),
- hWIpAddress.getIpv4Address().getValue());
+ hWIpAddress.getIpv4Address().getValue(), tunType.getName());
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(fwdTrunkIf);
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey(nodeId, dpnid.toString()));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId, dpnid.toString(), tunType));
t.delete(LogicalDatastoreType.CONFIGURATION, path);
}
else {
logger.trace(" trunk from {} to {} already deleted",dpnid.toString(), nodeId);
}
//TOR-CSS
- if (trunkExists( nodeId, dpnid.toString(),dataBroker)) {
+ if (trunkExists( nodeId, dpnid.toString(), tunType, dataBroker)) {
logger.trace("deleting tunnel from {} to {} ",nodeId, dpnid.toString());
String parentIf = ItmUtils.getHwParentIf(topologyId,nodeId);
String revTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf, hWIpAddress.getIpv4Address().getValue(),
- cssIpAddress.getIpv4Address().getValue());
+ cssIpAddress.getIpv4Address().getValue(), tunType.getName());
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(revTrunkIf);
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey( dpnid.toString(),nodeId));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(dpnid.toString(),nodeId, tunType));
t.delete(LogicalDatastoreType.CONFIGURATION, path);
}
else {
private static void deleteTrunksTORTOR(DataBroker dataBroker, IdManagerService idManagerService,
String topologyId1, String nodeId1, IpAddress hWIpAddress1, String topologyId2, String nodeId2, IpAddress hWIpAddress2,
- WriteTransaction t, List<ListenableFuture<Void>> futures) {
+ Class<? extends TunnelTypeBase> tunType, WriteTransaction t, List<ListenableFuture<Void>> futures) {
//TOR1-TOR2
- if (trunkExists(nodeId1, nodeId2,dataBroker)) {
+ if (trunkExists(nodeId1, nodeId2, tunType, dataBroker)) {
logger.trace("deleting tunnel from {} to {} ", nodeId1, nodeId2);
String parentIf = ItmUtils.getHwParentIf(topologyId1,nodeId1);
String fwdTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService, parentIf,
- hWIpAddress1.getIpv4Address().getValue(), hWIpAddress2.getIpv4Address().getValue());
+ hWIpAddress1.getIpv4Address().getValue(),
+ hWIpAddress2.getIpv4Address().getValue(),
+ tunType.getName());
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(fwdTrunkIf);
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey(nodeId2, nodeId1));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId2, nodeId1, tunType));
t.delete(LogicalDatastoreType.CONFIGURATION, path);
}
else {
logger.trace(" trunk from {} to {} already deleted",nodeId1, nodeId2);
}
//TOR2-TOR1
- if (trunkExists( nodeId2, nodeId1,dataBroker)) {
+ if (trunkExists( nodeId2, nodeId1, tunType, dataBroker)) {
logger.trace("deleting tunnel from {} to {} ",nodeId2, nodeId1);
String parentIf = ItmUtils.getHwParentIf(topologyId2,nodeId2);
String revTrunkIf = ItmUtils.getTrunkInterfaceName(idManagerService,parentIf, hWIpAddress2.getIpv4Address().getValue(),
- hWIpAddress1.getIpv4Address().getValue());
+ hWIpAddress1.getIpv4Address().getValue(), tunType.getName());
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(revTrunkIf);
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey( nodeId1,nodeId2));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(nodeId1,nodeId2, tunType));
t.delete(LogicalDatastoreType.CONFIGURATION, path);
}
else {
}
}
- private static boolean trunkExists( String srcDpnOrNode, String dstDpnOrNode, DataBroker dataBroker) {
+ private static boolean trunkExists( String srcDpnOrNode, String dstDpnOrNode,
+ Class<? extends TunnelTypeBase> tunType,DataBroker dataBroker) {
boolean existsFlag = false ;
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, getExternalTunnelKey(dstDpnOrNode, srcDpnOrNode));
+ .child(ExternalTunnel.class, ItmUtils.getExternalTunnelKey(dstDpnOrNode, srcDpnOrNode, tunType));
Optional<ExternalTunnel> exTunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker) ;
- if( exTunnels.isPresent())
+ if( exTunnels.isPresent()) {
existsFlag = true ;
- return existsFlag ;
}
-
- static ExternalTunnelKey getExternalTunnelKey(String dst , String src) {
- if (src.indexOf("physicalswitch") > 0) {
- src = src.substring(0, src.indexOf("physicalswitch") - 1);
- }
- if (dst.indexOf("physicalswitch") > 0) {
- dst = dst.substring(0, dst.indexOf("physicalswitch") - 1);
- }
- return new ExternalTunnelKey(dst, src);
+ return existsFlag ;
}
logger.trace( "Wiring between source tunnel end points {}, destination tunnel end points {} " , srcte, dstte );
String interfaceName = srcte.getInterfaceName() ;
Class<? extends TunnelTypeBase> tunType = srcte.getTunnelType();
- String ifDescription = srcte.getTunnelType().getName();
+ String tunTypeStr = srcte.getTunnelType().getName();
// Form the trunk Interface Name
- String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,srcte.getIpAddress().getIpv4Address().getValue(), dstte.getIpAddress().getIpv4Address().getValue()) ;
- IpAddress gwyIpAddress = ( srcte.getSubnetMask().equals(dstte.getSubnetMask()) ) ? null : srcte.getGwIpAddress() ;
+ String trunkInterfaceName = ItmUtils.getTrunkInterfaceName( idManagerService, interfaceName,
+ srcte.getIpAddress().getIpv4Address().getValue(),
+ dstte.getIpAddress().getIpv4Address().getValue(),
+ tunTypeStr) ;
+ IpAddress gatewayIpObj = new IpAddress("0.0.0.0".toCharArray());
+ IpAddress gwyIpAddress = ( srcte.getSubnetMask().equals(dstte.getSubnetMask()) ) ? gatewayIpObj : srcte.getGwIpAddress() ;
logger.debug( " Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, source IP - {}, destination IP - {} gateway IP - {}",trunkInterfaceName, interfaceName, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress ) ;
- Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName,
- String.format("%s %s", ifDescription, "Trunk Interface"), true, tunType, srcte.getIpAddress(),
- dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true, false, null);
+ Boolean monitorEnabled = ItmUtils.readMonitoringStateFromDS(dataBroker);
+ Integer monitorInterval = ItmUtils.readMonitorIntervalfromDS(dataBroker);
+ if(monitorInterval == null)
+ monitorInterval = ITMConstants.DEFAULT_MONITOR_INTERVAL;
+ Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName, String.format( "%s %s",ItmUtils.convertTunnelTypetoString(srcte.getTunnelType()), "Trunk Interface"), true, tunType, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true, monitorEnabled, monitorInterval*1000);
logger.debug( " Trunk Interface builder - {} ", iface ) ;
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
logger.debug( " Trunk Interface Identifier - {} ", trunkIdentifier ) ;
logger.trace( " Writing Trunk Interface to Config DS {}, {} ", trunkIdentifier, iface ) ;
t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, iface, true);
+ ItmUtils.itmCache.addInterface(iface);
// also update itm-state ds?
InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId,srcDpnId ));
- InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, trunkInterfaceName);
+ .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, tunType));
+ InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName);
//ItmUtils.asyncUpdate(LogicalDatastoreType.CONFIGURATION, path, tnl, dataBroker, DEFAULT_CALLBACK);
t.merge(LogicalDatastoreType.CONFIGURATION,path, tnl, true) ;
+ ItmUtils.itmCache.addInternalTunnel(tnl);
return true;
}
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
}
for (DPNTEPsInfo srcDpn : dpnTepsList) {
logger.trace("Processing srcDpn " + srcDpn);
- List<TunnelEndPoints> meshedEndPtCache = new ArrayList<TunnelEndPoints>(srcDpn.getTunnelEndPoints()) ;
+ List<TunnelEndPoints> meshedEndPtCache = new ArrayList<TunnelEndPoints>(ItmUtils.getTEPsForDpn(srcDpn.getDPNID(), meshedDpnList)) ;
+ if(meshedEndPtCache == null ) {
+ logger.debug("No Tunnel End Point configured for this DPN {}", srcDpn.getDPNID());
+ continue ;
+ }
+ logger.debug( "Entries in meshEndPointCache {} ", meshedEndPtCache.size() );
for (TunnelEndPoints srcTep : srcDpn.getTunnelEndPoints()) {
logger.trace("Processing srcTep " + srcTep);
String srcTZone = srcTep.getTransportZone();
for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
logger.trace("Processing dstTep " + dstTep);
if (dstTep.getTransportZone().equals(srcTZone)) {
- if( checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(), dataBroker)) {
+ if( checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(), srcTep.getTunnelType(),dataBroker)) {
// remove all trunk interfaces
logger.trace("Invoking removeTrunkInterface between source TEP {} , Destination TEP {} " ,srcTep , dstTep);
removeTrunkInterface(dataBroker, idManagerService, srcTep, dstTep, srcDpn.getDPNID(), dstDpn.getDPNID(), t, futures);
InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.getKey())
.child(TunnelEndPoints.class, srcTep.getKey()).build();
- logger.trace("Tep Removal from DPNTEPSINFO CONFIG DS " + srcTep);
+ logger.trace("Tep Removal of TEP {} from DPNTEPSINFO CONFIG DS with Key {} " + srcTep, srcTep.getKey());
t.delete(LogicalDatastoreType.CONFIGURATION, tepPath);
// remove the tep from the cache
meshedEndPtCache.remove(srcTep) ;
TunnelEndPoints srcTep, TunnelEndPoints dstTep, BigInteger srcDpnId, BigInteger dstDpnId,
WriteTransaction t, List<ListenableFuture<Void>> futures) {
String trunkfwdIfName =
- ItmUtils.getTrunkInterfaceName(idManagerService, srcTep.getInterfaceName(), srcTep.getIpAddress()
- .getIpv4Address().getValue(), dstTep.getIpAddress().getIpv4Address()
- .getValue());
+ ItmUtils.getTrunkInterfaceName( idManagerService, srcTep.getInterfaceName(),
+ srcTep.getIpAddress().getIpv4Address().getValue(),
+ dstTep.getIpAddress().getIpv4Address().getValue(),
+ srcTep.getTunnelType().getName());
logger.trace("Removing forward Trunk Interface " + trunkfwdIfName);
InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkfwdIfName);
logger.debug( " Removing Trunk Interface Name - {} , Id - {} from Config DS ", trunkfwdIfName, trunkIdentifier ) ;
t.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
-
+ ItmUtils.itmCache.removeInterface(trunkfwdIfName);
// also update itm-state ds -- Delete the forward tunnel-interface from the tunnel list
InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey( srcDpnId, dstDpnId));
+ .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, srcTep.getTunnelType()));
t.delete(LogicalDatastoreType.CONFIGURATION,path) ;
+ ItmUtils.itmCache.removeInternalTunnel(trunkfwdIfName);
// Release the Ids for the forward trunk interface Name
ItmUtils.releaseIdForTrunkInterfaceName(idManagerService,srcTep.getInterfaceName(), srcTep.getIpAddress()
.getIpv4Address().getValue(), dstTep.getIpAddress().getIpv4Address()
- .getValue() );
+ .getValue(), srcTep.getTunnelType().getName() );
String trunkRevIfName =
- ItmUtils.getTrunkInterfaceName(idManagerService, dstTep.getInterfaceName(), dstTep.getIpAddress()
- .getIpv4Address().getValue(), srcTep.getIpAddress().getIpv4Address()
- .getValue());
+ ItmUtils.getTrunkInterfaceName( idManagerService, dstTep.getInterfaceName(),
+ dstTep.getIpAddress().getIpv4Address().getValue(),
+ srcTep.getIpAddress().getIpv4Address().getValue(),
+ srcTep.getTunnelType().getName());
logger.trace("Removing Reverse Trunk Interface " + trunkRevIfName);
trunkIdentifier = ItmUtils.buildId(trunkRevIfName);
logger.debug( " Removing Trunk Interface Name - {} , Id - {} from Config DS ", trunkRevIfName, trunkIdentifier ) ;
// also update itm-state ds -- Delete the reverse tunnel-interface from the tunnel list
path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId));
+ .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, srcTep.getTunnelType()));
t.delete(LogicalDatastoreType.CONFIGURATION,path) ;
// Release the Ids for the reverse trunk interface Name
ItmUtils.releaseIdForTrunkInterfaceName(idManagerService, dstTep.getInterfaceName(), dstTep.getIpAddress()
.getIpv4Address().getValue(), srcTep.getIpAddress().getIpv4Address()
- .getValue());
+ .getValue(),dstTep.getTunnelType().getName());
}
- private static boolean checkIfTrunkExists( BigInteger srcDpnId, BigInteger dstDpnId, DataBroker dataBroker) {
+ private static boolean checkIfTrunkExists(BigInteger srcDpnId, BigInteger dstDpnId, Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
boolean existsFlag = false ;
InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey( srcDpnId, dstDpnId));
+ .child(InternalTunnel.class, new InternalTunnelKey( dstDpnId, srcDpnId, tunType));
Optional<InternalTunnel> internalTunnels = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker) ;
if( internalTunnels.isPresent())
existsFlag = true ;
--- /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.itm.confighelpers;
+
+import com.google.common.util.concurrent.ListenableFuture;
+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.itm.impl.ItmUtils;
+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.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Created by eanraju on 23-Mar-16.
+ */
+public class ItmMonitorIntervalWorker implements Callable<List<ListenableFuture<Void>>> {
+ private static final Logger logger = LoggerFactory.getLogger(ItmMonitorIntervalWorker.class) ;
+ private DataBroker dataBroker;
+ private String tzone;
+ private Integer interval;
+ private List<HwVtep> hwVteps;
+ private Boolean exists;
+
+ public ItmMonitorIntervalWorker(List<HwVtep> hwVteps,String tzone,Integer interval, DataBroker dataBroker, Boolean exists){
+ this.dataBroker = dataBroker;
+ this.tzone = tzone;
+ this.interval = interval;
+ this.hwVteps = hwVteps;
+ this.exists = exists;
+ logger.trace("ItmMonitorToggleWorker initialized with tzone {} and Interval {}",tzone,interval );
+ }
+
+ @Override public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>() ;
+ logger.debug("Invoking Tunnel Monitor Worker tzone = {} Interval= {}",tzone,interval );
+ WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ toggleTunnelMonitoring(hwVteps,interval,tzone,t,exists);
+ futures.add(t.submit());
+ return futures;
+ }
+
+ private void toggleTunnelMonitoring(List<HwVtep> hwVteps,Integer interval, String tzone, WriteTransaction t,Boolean exists) {
+ //exists means hwVteps exist for this tzone
+
+ //List<String> TunnelList = ItmUtils.getTunnelsofTzone(hwVteps, tzone, dataBroker, exists);
+ List<String> TunnelList = ItmUtils.getInternalTunnelsofTzone(tzone,dataBroker);
+ if(TunnelList !=null &&!TunnelList.isEmpty()) {
+ for (String tunnel : TunnelList)
+ toggle(tunnel, interval,t);
+ }
+ }
+
+ private void toggle(String tunnelInterfaceName, Integer interval, WriteTransaction t) {
+ if (tunnelInterfaceName != null) {
+ logger.debug("tunnel {} will have monitor interval {}", tunnelInterfaceName, interval);
+ InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+ IfTunnel tunnel = new IfTunnelBuilder().setMonitorInterval(interval.longValue() * 1000).build();
+ InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelInterfaceName))
+ .addAugmentation(IfTunnel.class, tunnel);
+ t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, builder.build());
+ }
+ }
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 2015, 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.itm.confighelpers;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+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.itm.impl.ItmUtils;
+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.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Created by eanraju on 23-Mar-16.
+ */
+public class ItmMonitorToggleWorker implements Callable<List<ListenableFuture<Void>>> {
+ private static final Logger logger = LoggerFactory.getLogger(ItmMonitorToggleWorker.class) ;
+ private DataBroker dataBroker;
+ private String tzone;
+ private boolean enabled;
+ private List<HwVtep> hwVteps;
+ private Boolean exists;
+
+ public ItmMonitorToggleWorker(List<HwVtep> hwVteps,String tzone,boolean enabled, DataBroker dataBroker, Boolean exists){
+ this.dataBroker = dataBroker;
+ this.tzone = tzone;
+ this.enabled = enabled;
+ this.hwVteps = hwVteps;
+ this.exists = exists;
+ logger.trace("ItmMonitorToggleWorker initialized with tzone {} and toggleBoolean {}",tzone,enabled );
+ }
+
+ @Override public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>() ;
+ logger.debug("Invoking Tunnel Monitor Worker tzone = {} enabled {}",tzone,enabled );
+ WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ toggleTunnelMonitoring(hwVteps,enabled,tzone,t,exists);
+ futures.add(t.submit());
+ return futures;
+ }
+
+ private void toggleTunnelMonitoring(List<HwVtep> hwVteps,Boolean enabled, String tzone, WriteTransaction t,Boolean exists) {
+ //exists means hwVteps exist for this tzone
+
+ List<String> TunnelList = ItmUtils.getTunnelsofTzone(hwVteps,tzone,dataBroker,exists);
+ if(TunnelList !=null &&!TunnelList.isEmpty()) {
+ for (String tunnel : TunnelList)
+ toggle(tunnel, enabled,t);
+ }
+ }
+
+ private void toggle(String tunnelInterfaceName, boolean enabled, WriteTransaction t) {
+ if(tunnelInterfaceName!=null) {
+ InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(tunnelInterfaceName);
+ IfTunnel tunnel = new IfTunnelBuilder().setMonitorEnabled(enabled).build();
+ InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelInterfaceName))
+ .addAugmentation(IfTunnel.class, tunnel);
+ t.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, builder.build());
+ }
+ }
+}
+
+
+
+
--- /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.itm.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+
+public class ItmCache {
+ private ConcurrentHashMap<String, Interface> interfaces = null;
+ private ConcurrentHashMap<String, ExternalTunnel> externalTunnels = null;
+ private ConcurrentHashMap<String, InternalTunnel> internalTunnels = null;
+
+ public ItmCache() {
+ this.interfaces = new ConcurrentHashMap<>();
+ this.internalTunnels = new ConcurrentHashMap<>();
+ this.externalTunnels = new ConcurrentHashMap<>();
+ }
+
+ public void addInterface(Interface iface) {
+ this.interfaces.put(iface.getName(), iface);
+ }
+
+ public Interface getInterface(String name) {
+ return this.interfaces.get(name);
+ }
+
+ public Interface removeInterface(String name) {
+ return this.interfaces.remove(name);
+ }
+
+ public Collection<Interface> getAllInterfaces() {
+ return this.interfaces.values();
+ }
+
+ public void addExternalTunnel(ExternalTunnel tunnel) {
+ this.externalTunnels.put(tunnel.getTunnelInterfaceName(), tunnel);
+ }
+
+ public ExternalTunnel getExternalTunnel(String name) {
+ return this.externalTunnels.get(name);
+ }
+
+ public ExternalTunnel removeExternalTunnel(String name) {
+ return this.externalTunnels.remove(name);
+ }
+
+ public void addInternalTunnel(InternalTunnel tunnel) {
+ this.internalTunnels.put(tunnel.getTunnelInterfaceName(), tunnel);
+ }
+
+ public InternalTunnel getInternalTunnel(String name) {
+ return this.internalTunnels.get(name);
+ }
+
+ public InternalTunnel removeInternalTunnel(String name) {
+ return this.internalTunnels.remove(name);
+ }
+
+}
import org.opendaylight.vpnservice.itm.api.IITMProvider;
import org.opendaylight.vpnservice.itm.cli.TepCommandHelper;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.itm.listeners.InterfaceStateListener;
import org.opendaylight.vpnservice.itm.listeners.TransportZoneListener;
+import org.opendaylight.vpnservice.itm.listeners.TunnelMonitorChangeListener;
+import org.opendaylight.vpnservice.itm.listeners.TunnelMonitorIntervalListener;
import org.opendaylight.vpnservice.itm.listeners.VtepConfigSchemaListener;
+import org.opendaylight.vpnservice.itm.monitoring.ItmTunnelEventListener;
import org.opendaylight.vpnservice.itm.rpc.ItmManagerRpcService;
import org.opendaylight.vpnservice.itm.snd.ITMStatusMonitor;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
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.opendaylight.vpnservice.itm.op.rev150701.TunnelList ;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private NotificationService notificationService;
private TepCommandHelper tepCommandHelper;
private TransportZoneListener tzChangeListener;
+ private TunnelMonitorChangeListener tnlToggleListener;
+ private TunnelMonitorIntervalListener tnlIntervalListener;
private VtepConfigSchemaListener vtepConfigSchemaListener;
+ private InterfaceStateListener ifStateListener;
private RpcProviderRegistry rpcProviderRegistry;
private static final ITMStatusMonitor itmStatusMonitor = ITMStatusMonitor.getInstance();
+ private ItmTunnelEventListener itmStateListener;
static short flag = 0;
public ItmProvider() {
tzChangeListener = new TransportZoneListener(dataBroker, idManager) ;
itmRpcService = new ItmManagerRpcService(dataBroker, idManager);
vtepConfigSchemaListener = new VtepConfigSchemaListener(dataBroker);
+ this.ifStateListener = new InterfaceStateListener(dataBroker);
+ tnlToggleListener = new TunnelMonitorChangeListener(dataBroker);
+ tnlIntervalListener = new TunnelMonitorIntervalListener(dataBroker);
tepCommandHelper = new TepCommandHelper(dataBroker);
final BindingAwareBroker.RpcRegistration<ItmRpcService> rpcRegistration = getRpcProviderRegistry().addRpcImplementation(ItmRpcService.class, itmRpcService);
itmRpcService.setMdsalManager(mdsalManager);
tzChangeListener.setMdsalManager(mdsalManager);
tzChangeListener.setItmManager(itmManager);
tzChangeListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+ tnlIntervalListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+ tnlToggleListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
tepCommandHelper = new TepCommandHelper(dataBroker);
tepCommandHelper.setInterfaceManager(interfaceManager);
+ itmStateListener =new ItmTunnelEventListener(dataBroker);
createIdPool();
itmStatusMonitor.reportStatus("OPERATIONAL");
} catch (Exception e) {
if (tzChangeListener != null) {
tzChangeListener.close();
}
-
+ if (tnlIntervalListener != null) {
+ tnlIntervalListener.close();
+ }
+ if(tnlToggleListener!= null){
+ tnlToggleListener.close();
+ }
LOG.info("ItmProvider Closed");
}
tepCommandHelper.showTeps(itmManager.getTunnelMonitorEnabledFromConfigDS(),
itmManager.getTunnelMonitorIntervalFromConfigDS());
}
+ public void showState(TunnelList tunnels) {
+ if (tunnels != null)
+ tepCommandHelper.showState(tunnels, itmManager.getTunnelMonitorEnabledFromConfigDS());
+ else
+ LOG.debug("No tunnels available");
+ }
public void deleteVtep(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
String gatewayIp, String transportZone) {
this);
if (ItmUtils.getDpnIdList(schema.getDpnIds()) == null) {
VtepConfigSchemaBuilder builder = new VtepConfigSchemaBuilder(schema);
+ if (ItmUtils.getDpnIdList(schema.getDpnIds()).isEmpty()) {
builder.setDpnIds(schema.getDpnIds());
schema = builder.build();
} else {
if (lstDpnsForAdd != null && !lstDpnsForAdd.isEmpty()) {
- ItmUtils.getDpnIdList(schema.getDpnIds()).addAll(lstDpnsForAdd);
+ List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(schema.getDpnIds()) ;
+ originalDpnList.addAll(lstDpnsForAdd) ;
+ builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList));
}
if (lstDpnsForDelete != null && !lstDpnsForDelete.isEmpty()) {
- ItmUtils.getDpnIdList(schema.getDpnIds()).removeAll(lstDpnsForDelete);
+ List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(schema.getDpnIds()) ;
+ originalDpnList.removeAll(lstDpnsForAdd) ;
+ builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList)) ;
}
}
+ schema = builder.build();
MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
ItmUtils.getVtepConfigSchemaIdentifier(schemaName), schema);
LOG.debug("Vtep config schema {} updated to config DS with DPN's {}", schemaName, ItmUtils.getDpnIdList(schema.getDpnIds()));
}
-
+ }
/*
* (non-Javadoc)
*
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
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.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.VtepConfigSchemas;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.VtepIpPools;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.interfaces._interface.NodeIdentifierKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpointsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
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.inet.types.rev100924.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIds ;
//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice._interface.service.rev150602._interface.service.info.ServiceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIdsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIdsKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.Vteps;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
public static final String TUNNEL_TYPE_VXLAN = "VXLAN";
public static final String TUNNEL_TYPE_GRE = "GRE";
public static final String TUNNEL = "TUNNEL";
+ public static ItmCache itmCache = new ItmCache();
private static final Logger LOG = LoggerFactory.getLogger(ItmUtils.class);
return dpnId;
}
- public static String getTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName) {
- String trunkInterfaceName = String.format("%s:%s:%s", parentInterfaceName, localHostName, remoteHostName);
+ public static String getTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName,
+ String localHostName, String remoteHostName, String tunnelType) {
+ String tunnelTypeStr;
+ if(tunnelType.contains("TunnelTypeGre")) {
+ tunnelTypeStr = ITMConstants.TUNNEL_TYPE_GRE;
+ } else {
+ tunnelTypeStr = ITMConstants.TUNNEL_TYPE_VXLAN;
+ }
+ String trunkInterfaceName = String.format( "%s:%s:%s:%s", parentInterfaceName, localHostName,
+ remoteHostName, tunnelTypeStr);
+ LOG.trace("trunk interface name is {}", trunkInterfaceName);
trunkInterfaceName = String.format("%s:%s", TUNNEL, getUniqueId(idManager, trunkInterfaceName));
return trunkInterfaceName;
}
- public static void releaseIdForTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName) {
- String trunkInterfaceName = String.format("%s:%s:%s", parentInterfaceName, localHostName, remoteHostName);
+ public static void releaseIdForTrunkInterfaceName(IdManagerService idManager, String parentInterfaceName, String localHostName, String remoteHostName, String tunnelType) {
+ String tunnelTypeStr;
+ if(tunnelType.contains("TunnelTypeGre")) {
+ tunnelTypeStr = ITMConstants.TUNNEL_TYPE_GRE;
+ } else {
+ tunnelTypeStr = ITMConstants.TUNNEL_TYPE_VXLAN;
+ }
+ String trunkInterfaceName = String.format("%s:%s:%s:%s", parentInterfaceName, localHostName, remoteHostName, tunnelTypeStr);
LOG.trace("Releasing Id for trunkInterface - {}", trunkInterfaceName );
releaseId(idManager, trunkInterfaceName) ;
}
public static InstanceIdentifier<DPNTEPsInfo> getDPNTEPInstance(BigInteger dpIdKey) {
InstanceIdentifier.InstanceIdentifierBuilder<DPNTEPsInfo> dpnTepInfoBuilder =
- InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpIdKey));
+ InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class,
+ new DPNTEPsInfoKey(dpIdKey));
InstanceIdentifier<DPNTEPsInfo> dpnInfo = dpnTepInfoBuilder.build();
return dpnInfo;
}
public static TunnelEndPoints createTunnelEndPoints(BigInteger dpnId, IpAddress ipAddress, String portName, int vlanId,
IpPrefix prefix, IpAddress gwAddress, String zoneName, Class<? extends TunnelTypeBase> tunnel_type) {
// when Interface Mgr provides support to take in Dpn Id
- return new TunnelEndPointsBuilder().setKey(new TunnelEndPointsKey(ipAddress, portName, vlanId))
+ return new TunnelEndPointsBuilder().setKey(new TunnelEndPointsKey(ipAddress, portName,tunnel_type, vlanId))
.setSubnetMask(prefix).setGwIpAddress(gwAddress).setTransportZone(zoneName)
.setInterfaceName(ItmUtils.getInterfaceName(dpnId, portName, vlanId)).setTunnelType(tunnel_type).build();
}
}
public static Interface buildTunnelInterface(BigInteger dpn, String ifName, String desc, boolean enabled, Class<? extends TunnelTypeBase> tunType,
- IpAddress localIp, IpAddress remoteIp, IpAddress gatewayIp,Integer vlanId, boolean internal, boolean monitorEnabled, Long monitorInterval) {
+ IpAddress localIp, IpAddress remoteIp, IpAddress gatewayIp,Integer vlanId, boolean internal, Boolean monitorEnabled, Integer monitorInterval) {
InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(ifName)).setName(ifName)
.setDescription(desc).setEnabled(enabled).setType(Tunnel.class);
ParentRefs parentRefs = new ParentRefsBuilder().setDatapathNodeIdentifier(dpn).build();
IfL2vlan l2vlan = new IfL2vlanBuilder().setVlanId(new VlanId(vlanId)).build();
builder.addAugmentation(IfL2vlan.class, l2vlan);
}
- //use default monitoring value from Global Constants
- Long monitoringInterval = 10000L;
+ Long monitoringInterval = (long) ITMConstants.DEFAULT_MONITOR_INTERVAL;
+ Boolean monitoringEnabled = true;
if(monitorInterval!= null)
- monitoringInterval = monitorInterval;
- IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(gatewayIp).setTunnelSource(localIp)
- .setTunnelInterfaceType(tunType).setInternal(internal).setMonitorEnabled(monitorEnabled).setMonitorInterval(monitoringInterval).build();
+ monitoringInterval = monitorInterval.longValue();
+ if(monitorEnabled!=null )
+ monitoringEnabled = monitorEnabled;
+ IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(remoteIp).setTunnelGateway(
+ gatewayIp).setTunnelSource(localIp)
+ .setTunnelInterfaceType(tunType).setInternal(internal).setMonitorEnabled(
+ monitoringEnabled).setMonitorInterval(monitoringInterval).build();
builder.addAugmentation(IfTunnel.class, tunnel);
return builder.build();
}
- public static Interface buildHwTunnelInterface(String tunnelIfName, String desc , boolean enabled, String topo_id, String node_id,
- Class<? extends TunnelTypeBase> tunType, IpAddress srcIp , IpAddress destIp, IpAddress gWIp,
- boolean monitor_enabled
- ){
- InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelIfName)).setName(tunnelIfName).setDescription(desc).
+ public static Interface buildHwTunnelInterface(String tunnelIfName, String desc, boolean enabled, String topo_id,
+ String node_id, Class<? extends TunnelTypeBase> tunType, IpAddress srcIp, IpAddress destIp,
+ IpAddress gWIp, Boolean monitor_enabled, Integer monitor_interval){
+ InterfaceBuilder builder = new InterfaceBuilder().setKey(new InterfaceKey(tunnelIfName)).setName(
+ tunnelIfName).setDescription(desc).
setEnabled(enabled).setType(Tunnel.class);
List<NodeIdentifier> nodeIds = new ArrayList<NodeIdentifier>();
NodeIdentifier hWnode = new NodeIdentifierBuilder().setKey(new NodeIdentifierKey(topo_id)).setTopologyId(
nodeIds.add(hWnode);
ParentRefs parent = new ParentRefsBuilder().setNodeIdentifier(nodeIds).build();
builder.addAugmentation(ParentRefs.class , parent);
+ Long monitoringInterval = (long) ITMConstants.DEFAULT_MONITOR_INTERVAL;
+ Boolean monitoringEnabled = true;
+ if(monitor_interval!= null)
+ monitoringInterval = monitor_interval.longValue();
+ if(monitor_enabled!=null )
+ monitoringEnabled = monitor_enabled;
IfTunnel tunnel = new IfTunnelBuilder().setTunnelDestination(destIp).setTunnelGateway(gWIp).setTunnelSource(
- srcIp).setMonitorEnabled(monitor_enabled).setTunnelInterfaceType(tunType).setInternal(false).build();
+ srcIp).setMonitorEnabled(monitoringEnabled).setMonitorInterval(100L).
+ setTunnelInterfaceType(tunType).setInternal(false).build();
builder.addAugmentation(IfTunnel.class, tunnel);
LOG.trace("iftunnel {} built from hwvtep {} ",tunnel,node_id);
return builder.build();
}
- public static InternalTunnel buildInternalTunnel( BigInteger srcDpnId, BigInteger dstDpnId, String trunkInterfaceName) {
- InternalTunnel tnl = new InternalTunnelBuilder().setKey(new InternalTunnelKey(dstDpnId,srcDpnId)).setDestinationDPN(dstDpnId)
- .setSourceDPN(srcDpnId)
+ public static InternalTunnel buildInternalTunnel( BigInteger srcDpnId, BigInteger dstDpnId,
+ Class<? extends TunnelTypeBase> tunType,
+ String trunkInterfaceName) {
+ InternalTunnel tnl = new InternalTunnelBuilder().setKey(new InternalTunnelKey(dstDpnId, srcDpnId, tunType)).setDestinationDPN(dstDpnId)
+ .setSourceDPN(srcDpnId).setTransportType(tunType)
.setTunnelInterfaceName(trunkInterfaceName).build();
return tnl ;
}
- public static ExternalTunnel buildExternalTunnel(String srcNode, String dstNode, String trunkInterfaceName) {
+ public static ExternalTunnel buildExternalTunnel(String srcNode, String dstNode,
+ Class<? extends TunnelTypeBase> tunType,
+ String trunkInterfaceName) {
ExternalTunnel extTnl = new ExternalTunnelBuilder().setKey(
- new ExternalTunnelKey(dstNode, srcNode)).setSourceDevice(srcNode).setDestinationDevice(dstNode).setTunnelInterfaceName(trunkInterfaceName).build();
+ new ExternalTunnelKey(dstNode, srcNode, tunType))
+ .setSourceDevice(srcNode).setDestinationDevice(dstNode)
+ .setTunnelInterfaceName(trunkInterfaceName)
+ .setTransportType(tunType).build();
return extTnl ;
}
return dpnIdList;
}
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
+ InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
+ InstanceIdentifier.builder(InterfacesState.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+ interfaceName));
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
+ return id;
+}
+ public static Boolean readMonitoringStateFromDS(DataBroker dataBroker) {
+ InstanceIdentifier<TunnelMonitorEnabled> iid = InstanceIdentifier.create(TunnelMonitorEnabled.class);
+ Optional<TunnelMonitorEnabled> tunnelMonitorEnabledOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
+ iid, dataBroker);
+ if(tunnelMonitorEnabledOptional.isPresent())
+ return tunnelMonitorEnabledOptional.get().isEnabled();
+ return null;
+ }
+
+ public static Integer readMonitorIntervalfromDS(DataBroker dataBroker) {
+ InstanceIdentifier<TunnelMonitorInterval> iid = InstanceIdentifier.create(TunnelMonitorInterval.class);
+ Optional<TunnelMonitorInterval> tunnelMonitorIOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+ if(tunnelMonitorIOptional.isPresent())
+ return tunnelMonitorIOptional.get().getInterval();
+ return null;
+ }
+ public static List<String> getTunnelsofTzone(List<HwVtep> hwVteps, String tzone, DataBroker dataBroker, Boolean hwVtepsExist) {
+ List<String> tunnels = new ArrayList<String>();
+ InstanceIdentifier<TransportZone> path = InstanceIdentifier.builder(TransportZones.class).
+ child(TransportZone.class, new TransportZoneKey(tzone)).build();
+ Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
+ Class<? extends TunnelTypeBase> tunType = tZoneOptional.get().getTunnelType();
+ if (tZoneOptional.isPresent()) {
+ if (tZoneOptional.get().getSubnets() != null && !tZoneOptional.get().getSubnets().isEmpty()) {
+ for (Subnets sub : tZoneOptional.get().getSubnets()) {
+ if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+ for (Vteps vtepLocal : sub.getVteps()) {
+ for (Vteps vtepRemote : sub.getVteps()) {
+ if (!vtepLocal.equals(vtepRemote)) {
+ InternalTunnelKey key = new InternalTunnelKey(vtepRemote.getDpnId(), vtepLocal.getDpnId(), tunType);
+ InstanceIdentifier<InternalTunnel> intIID =
+ InstanceIdentifier.builder(TunnelList.class).
+ child(InternalTunnel.class, key).build();
+ Optional<InternalTunnel> TunnelsOptional =
+ ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+ if (TunnelsOptional.isPresent()) {
+ LOG.trace("Internal Tunnel added {}",TunnelsOptional.get().getTunnelInterfaceName());
+ tunnels.add(TunnelsOptional.get().getTunnelInterfaceName());
+ }
+ }
+ }
+ if(hwVteps!= null && !hwVteps.isEmpty()) {
+ for (HwVtep hwVtep : hwVteps) {
+ tunnels.add(getExtTunnel(hwVtep.getNode_id(), vtepLocal.getDpnId().toString(),
+ tunType, dataBroker));
+ tunnels.add(getExtTunnel(vtepLocal.getDpnId().toString(), hwVtep.getNode_id(),
+ tunType, dataBroker));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (hwVtepsExist) {
+ for (HwVtep hwVtep : hwVteps) {
+ for (HwVtep hwVtepOther : hwVteps) {
+ if (!hwVtep.getHwIp().equals(hwVtepOther.getHwIp())) {
+ tunnels.add(getExtTunnel(hwVtep.getNode_id(), hwVtepOther.getNode_id(), tunType, dataBroker));
+ tunnels.add(getExtTunnel(hwVtepOther.getNode_id(), hwVtep.getNode_id(), tunType, dataBroker));
+ }
+ }
+ }
+ }
+ return tunnels;
+ }
+ public static List<String> getInternalTunnelsofTzone(String tzone, DataBroker dataBroker) {
+ List<String> tunnels = new ArrayList<String>();
+ LOG.trace("Getting internal tunnels of {}",tzone);
+ InstanceIdentifier<TransportZone> path = InstanceIdentifier.builder(TransportZones.class).
+ child(TransportZone.class, new TransportZoneKey(tzone)).build();
+ Optional<TransportZone> tZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
+ if (tZoneOptional.isPresent()) {
+ if (tZoneOptional.get().getSubnets() != null && !tZoneOptional.get().getSubnets().isEmpty()) {
+ for (Subnets sub : tZoneOptional.get().getSubnets()) {
+ if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
+ for (Vteps vtepLocal : sub.getVteps()) {
+ for (Vteps vtepRemote : sub.getVteps()) {
+ if (!vtepLocal.equals(vtepRemote)) {
+ InternalTunnelKey key = new InternalTunnelKey(vtepRemote.getDpnId(), vtepLocal.getDpnId(), tZoneOptional.get().getTunnelType());
+ InstanceIdentifier<InternalTunnel> intIID =
+ InstanceIdentifier.builder(TunnelList.class).
+ child(InternalTunnel.class, key).build();
+ Optional<InternalTunnel> TunnelsOptional =
+ ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+ if (TunnelsOptional.isPresent()) {
+ LOG.trace("Internal Tunnel added {}",
+ TunnelsOptional.get().getTunnelInterfaceName());
+ tunnels.add(TunnelsOptional.get().getTunnelInterfaceName());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return tunnels;
+ }
+ private static String getExtTunnel(String node_id, String dpId,Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
+ LOG.trace("getting ext tunnel for {} and dpId {}",node_id,dpId);
+ ExternalTunnelKey key = getExternalTunnelKey(dpId,node_id, tunType);
+ InstanceIdentifier<ExternalTunnel> intIID = InstanceIdentifier.builder(ExternalTunnelList.class).
+ child(ExternalTunnel.class, key).build();
+ Optional<ExternalTunnel> TunnelsOptional =
+ ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intIID, dataBroker);
+ if (TunnelsOptional.isPresent()) {
+ LOG.trace("ext tunnel returned {} ",TunnelsOptional.get().getTunnelInterfaceName());
+ return TunnelsOptional.get().getTunnelInterfaceName();
+ }
+ return null;
+ }
+ public static ExternalTunnelKey getExternalTunnelKey(String dst , String src, Class<? extends TunnelTypeBase> tunType) {
+ if (src.indexOf("physicalswitch") > 0) {
+ src = src.substring(0, src.indexOf("physicalswitch") - 1);
+ }
+ if (dst.indexOf("physicalswitch") > 0) {
+ dst = dst.substring(0, dst.indexOf("physicalswitch") - 1);
+ }
+ return new ExternalTunnelKey(dst, src, tunType);
+ }
+ public static List<TunnelEndPoints> getTEPsForDpn( BigInteger srcDpn, List<DPNTEPsInfo> dpnList) {
+ for (DPNTEPsInfo dpn : dpnList) {
+ if( dpn.getDPNID().equals(srcDpn)) {
+ return dpn.getTunnelEndPoints() ;
+ }
+ }
+ return null ;
+ }
+ public static TunnelList getAllInternalTunnels(DataBroker broker) {
+ InstanceIdentifier<TunnelList> tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class).build();
+ Optional<TunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier, broker);
+ if (tunnelList.isPresent()) {
+ return tunnelList.get();
+ }
+ return null;
+ }
+ public static InternalTunnel getInternalTunnel(String interfaceName, DataBroker broker) {
+ InternalTunnel internalTunnel = null;
+ TunnelList tunnelList = getAllInternalTunnels(broker);
+ if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
+ List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
+ for (InternalTunnel tunnel : internalTunnels) {
+ if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
+ internalTunnel = tunnel;
+ break;
+ }
+ }
+ }
+ return internalTunnel;
+ }
+ public static ExternalTunnel getExternalTunnel(String interfaceName, DataBroker broker) {
+ ExternalTunnel externalTunnel = null;
+ List<ExternalTunnel> externalTunnels = getAllExternalTunnels(broker);
+ for (ExternalTunnel tunnel : externalTunnels) {
+ if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+ externalTunnel = tunnel;
+ break;
+ }
+ }
+ return externalTunnel;
+ }
+ public static List<ExternalTunnel> getAllExternalTunnels(DataBroker broker) {
+ List<ExternalTunnel> result = null;
+ InstanceIdentifier<ExternalTunnelList> id = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+ Optional<ExternalTunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, id, broker);
+ if (tunnelList.isPresent()) {
+ result = tunnelList.get().getExternalTunnel();
+ }
+ if (result == null) {
+ result = Collections.emptyList();
+ }
+ return result;
+ }
+ public static String convertTunnelTypetoString(Class<? extends TunnelTypeBase> tunType ) {
+ String tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
+ if( tunType.equals(TunnelTypeVxlan.class))
+ tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN ;
+ else if( tunType.equals(TunnelTypeGre.class) )
+ tunnelType = ITMConstants.TUNNEL_TYPE_GRE ;
+ else if (tunnelType.equals(TunnelTypeMplsOverGre.class))
+ tunnelType = ITMConstants.TUNNEL_TYPE_MPLS_OVER_GRE;
+ return tunnelType ;
+ }
+ public static boolean isItmIfType(Class<? extends InterfaceType> ifType) {
+ if( (ifType != null) && (ifType.isAssignableFrom(Tunnel.class)) ) {
+ return true;
+ }
+ return false;
+ }
+ public static StateTunnelListKey getTunnelStateKey( org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface iface) {
+ StateTunnelListKey key = null;
+ if(isItmIfType(iface.getType())) {
+ key = new StateTunnelListKey(iface.getName());
+ }
+ return key;
+ }
+ public static void updateTunnelsCache(DataBroker broker) {
+ List<InternalTunnel> internalTunnels = getAllInternalTunnels(broker, LogicalDatastoreType.CONFIGURATION);
+ for (InternalTunnel tunnel : internalTunnels) {
+ itmCache.addInternalTunnel(tunnel);
+ }
+ List<ExternalTunnel> externalTunnels = getAllExternalTunnels(broker, LogicalDatastoreType.CONFIGURATION);
+ for (ExternalTunnel tunnel : externalTunnels) {
+ itmCache.addExternalTunnel(tunnel);
+ }
+ }
+ public static List<ExternalTunnel> getAllExternalTunnels(DataBroker dataBroker, LogicalDatastoreType datastoreType) {
+ List<ExternalTunnel> result = null;
+ InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+ Optional<ExternalTunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+ if (tunnelList.isPresent()) {
+ result = tunnelList.get().getExternalTunnel();
+ }
+ if (result == null) {
+ result = Collections.emptyList();
+ }
+ return result;
+ }
+ public static List<InternalTunnel> getAllInternalTunnels(DataBroker dataBroker, LogicalDatastoreType datastoreType) {
+ List<InternalTunnel> result = null;
+ InstanceIdentifier<TunnelList> iid = InstanceIdentifier.builder(TunnelList.class).build();
+ Optional<TunnelList> tunnelList = read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
+ if (tunnelList.isPresent()) {
+ result = tunnelList.get().getInternalTunnel();
+ }
+ if (result == null) {
+ result = Collections.emptyList();
+ }
+ return result;
+ }
+ public static Interface getInterface(
+ String name, DataBroker broker) {
+ Interface result = itmCache.getInterface(name);
+ if (result == null) {
+ InstanceIdentifier<Interface> iid =
+ InstanceIdentifier.builder(Interfaces.class)
+ .child(Interface.class, new InterfaceKey(name)).build();
+ Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, iid, broker);
+ if (optInterface.isPresent()) {
+ result = optInterface.get();
+ itmCache.addInterface(result);
+ }
+ }
+ return result;
+ }
}
-
--- /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.itm.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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeHwvtep;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelsState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.DstInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.SrcInfoBuilder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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.net.InetAddresses;
+
+public class InterfaceStateListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class);
+
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+
+ public InterfaceStateListener(final DataBroker db) {
+ super(Interface.class);
+ broker = db;
+ registerListener(db);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up interface state listener", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.info("Interface state listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), InterfaceStateListener.this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("ITM Interfaces State listener registration fail!", e);
+ throw new IllegalStateException("ITM Interfaces State listener registration failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, Interface iface) {
+ LOG.trace("Interface added: {}", iface);
+ if(ItmUtils.isItmIfType(iface.getType())) {
+ LOG.debug("Interface of type Tunnel added: {}", iface.getName());
+ updateItmState(iface);
+ }
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier,
+ Interface iface) {
+ LOG.trace("Interface deleted: {}", iface);
+ if(ItmUtils.isItmIfType(iface.getType())) {
+ LOG.debug("Tunnel interface deleted: {}", iface.getName());
+ StateTunnelListKey tlKey = null;
+ tlKey = ItmUtils.getTunnelStateKey(iface);
+ InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
+ LOG.trace("Deleting tunnel_state for Id: {}", stListId);
+ ItmUtils.asyncDelete(LogicalDatastoreType.OPERATIONAL, stListId, broker, ItmUtils.DEFAULT_CALLBACK);
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier,
+ Interface original, Interface update) {
+ /*
+ * update contains only delta, may not include iftype
+ * Note: This assumes type can't be edited on the fly
+ */
+ if(ItmUtils.isItmIfType(original.getType())) {
+ LOG.trace("Interface updated. Old: {} New: {}", original, update);
+ OperStatus operStatus = update.getOperStatus();
+ if( operStatus != null ) {
+ LOG.debug("Tunnel Interface {} changed state to {}", original.getName(), operStatus);
+ updateItmState(update);
+ }
+ }
+ }
+
+ private void updateItmState(Interface iface) {
+ StateTunnelListKey tlKey = null;
+ tlKey = ItmUtils.getTunnelStateKey(iface);
+ LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, iface.getName());
+ InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
+ Optional<StateTunnelList> tunnelsState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, stListId, broker);
+ StateTunnelList tunnelStateList;
+ StateTunnelListBuilder stlBuilder;
+ boolean tunnelState = (iface.getOperStatus().equals(OperStatus.Up)) ? (true):(false);
+ if(tunnelsState.isPresent()) {
+ tunnelStateList = tunnelsState.get();
+ stlBuilder = new StateTunnelListBuilder(tunnelStateList);
+ stlBuilder.setTunnelState(tunnelState);
+ StateTunnelList stList = stlBuilder.build();
+ LOG.trace("Updating tunnel_state: {} for Id: {}",stList, stListId);
+ ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, stList, broker, ItmUtils.DEFAULT_CALLBACK);
+ } else {
+ // Create new Tunnel State
+ try {
+ /*FIXME:
+ * A defensive try-catch to find issues without disrupting existing behavior.
+ */
+ tunnelStateList = buildStateTunnelList(tlKey, iface.getName(), tunnelState);
+ LOG.trace("Creating tunnel_state: {} for Id: {}", tunnelStateList, stListId);
+ ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, tunnelStateList, broker,
+ ItmUtils.DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.warn("Exception trying to create tunnel state for {}", iface.getName(), e);
+ }
+ }
+ }
+
+ private StateTunnelList buildStateTunnelList(StateTunnelListKey tlKey, String name, boolean state) {
+ StateTunnelListBuilder stlBuilder = new StateTunnelListBuilder();
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
+ ItmUtils.getInterface(name, broker);
+ IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
+ ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
+ if(ifTunnel == null && parentRefs == null) {
+ return null;
+ }
+ DstInfoBuilder dstInfoBuilder = new DstInfoBuilder();
+ SrcInfoBuilder srcInfoBuilder = new SrcInfoBuilder();
+ dstInfoBuilder.setTepIp(ifTunnel.getTunnelDestination());
+ srcInfoBuilder.setTepIp(ifTunnel.getTunnelSource());
+ //TODO: Add/Improve logic for device type
+ InternalTunnel internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
+ ExternalTunnel externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
+ if(internalTunnel == null && externalTunnel == null) {
+ // both not present in cache. let us update and try again.
+ ItmUtils.updateTunnelsCache(broker);
+ internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
+ externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
+ }
+ if(internalTunnel != null) {
+ srcInfoBuilder.setTepDeviceId(internalTunnel.getSourceDPN().toString()).setTepDeviceType(TepTypeInternal.class);
+ dstInfoBuilder.setTepDeviceId(internalTunnel.getDestinationDPN().toString())
+ .setTepDeviceType(TepTypeInternal.class);
+ stlBuilder.setTransportType(internalTunnel.getTransportType());
+ } else if(externalTunnel != null) {
+ ExternalTunnel tunnel = ItmUtils.itmCache.getExternalTunnel(name);
+ srcInfoBuilder.setTepDeviceId(tunnel.getSourceDevice())
+ .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()));
+ dstInfoBuilder.setTepDeviceId(tunnel.getDestinationDevice())
+ .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()))
+ .setTepIp(ifTunnel.getTunnelDestination());
+ stlBuilder.setTransportType(tunnel.getTransportType());
+ }
+ stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setTunnelState(state)
+ .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build());
+ return stlBuilder.build();
+ }
+
+ private Class<? extends TepTypeBase> getDeviceType(String device) {
+ if(device.startsWith("hwvtep")) {
+ return TepTypeHwvtep.class;
+ } else if(InetAddresses.isInetAddress(device)) {
+ return TepTypeExternal.class;
+ } else {
+ return TepTypeInternal.class;
+ }
+ }
+
+ private InstanceIdentifier<StateTunnelList> buildStateTunnelListId(StateTunnelListKey tlKey) {
+ InstanceIdentifier<StateTunnelList> stListId =
+ InstanceIdentifier.builder(TunnelsState.class).child(StateTunnelList.class, tlKey).build();
+ return stListId;
+ }
+
+}
LOG.trace("Delete: Invoking deleteTunnels in ItmManager with DpnList {}", opDpnList);
if(opDpnList.size()>0 || hwVtepList.size()>0) {
LOG.trace("Delete: Invoking ItmManager");
- LOG.trace("Add: Invoking ItmManager with hwVtep List {} " , hwVtepList);
+ LOG.trace("Delete: Invoking ItmManager with hwVtep List {} " , hwVtepList);
// itmManager.deleteTunnels(opDpnList);
DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(opDpnList,hwVtepList, dataBroker, idManagerService, mdsalManager);
int vlanID = subnet.getVlanId();
LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
List<Vteps> vtepsList = subnet.getVteps();
+ if(vtepsList!=null && !vtepsList.isEmpty()) {
for (Vteps vteps : vtepsList) {
BigInteger dpnID = vteps.getDpnId();
String port = vteps.getPortname();
IpAddress ipAddress = vteps.getIpAddress();
LOG.trace("DpnID: {}, port: {}, ipAddress: {}", dpnID, port, ipAddress);
- TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port, vlanID, ipPrefix, gatewayIP, zone_name, tunnel_type);
+ TunnelEndPoints tunnelEndPoints =
+ ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port, vlanID, ipPrefix,
+ gatewayIP, zone_name, tunnel_type);
List<TunnelEndPoints> tunnelEndPointsList = mapDPNToTunnelEndpt.get(dpnID);
if (tunnelEndPointsList != null) {
LOG.trace("Existing DPN info list in the Map: {} ", dpnID);
tunnelEndPointsList = new ArrayList<TunnelEndPoints>();
tunnelEndPointsList.add(tunnelEndPoints);
mapDPNToTunnelEndpt.put(dpnID, tunnelEndPointsList);
+ }
}
}
}
--- /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.itm.listeners;
+
+import com.google.common.base.Optional;
+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.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.vpnservice.itm.confighelpers.HwVtep;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorToggleWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmTepAddWorker;
+import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVteps;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TunnelMonitorChangeListener extends AsyncDataTreeChangeListenerBase<TunnelMonitorEnabled, TunnelMonitorChangeListener>
+ implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(TunnelMonitorChangeListener.class);
+ private final DataBroker broker;
+ // private final IInterfaceManager interfaceManager;
+
+ public TunnelMonitorChangeListener(final DataBroker db) {
+ super(TunnelMonitorEnabled.class, TunnelMonitorChangeListener.class);
+ broker = db;
+ // interfaceManager = ifManager;
+ // registerListener(db);
+ }
+
+ /* private void registerListener(final DataBroker db) {
+ try {
+ TunnelMonitorChangeListener monitorEnabledChangeListener = new TunnelMonitorChangeListener();
+ monitorEnabledListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ monitorEnabledChangeListener.getWildCardPath(), monitorEnabledChangeListener, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("ITM Monitor Interfaces DataChange listener registration fail!", e);
+ throw new IllegalStateException("ITM Monitor registration Listener failed.", e);
+ }
+ }
+*/ @Override
+ public void close() throws Exception {
+ /* if (monitorEnabledListenerRegistration != null) {
+ try {
+ monitorEnabledListenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DataChangeListener.", e);
+ }
+ monitorEnabledListenerRegistration = null;
+ }
+
+ if (monitorIntervalListenerRegistration != null) {
+ try {
+ monitorIntervalListenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DataChangeListener.", e);
+ }
+ monitorIntervalListenerRegistration = null;
+ }
+*/
+ LOG.info("Tunnel Monitor listeners Closed");
+ }
+
+ @Override protected InstanceIdentifier<TunnelMonitorEnabled> getWildCardPath() {
+ return InstanceIdentifier.create(TunnelMonitorEnabled.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<TunnelMonitorEnabled> key, TunnelMonitorEnabled dataObjectModification) {
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }
+ LOG.debug("Remove:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.isEnabled());
+ ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+ false, broker, hwVtepsExist);
+ coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+ }
+ }
+ }
+
+
+ @Override protected void update(InstanceIdentifier<TunnelMonitorEnabled> key,
+ TunnelMonitorEnabled dataObjectModificationBefore,
+ TunnelMonitorEnabled dataObjectModificationAfter) {
+ LOG.debug("update TunnelMonitorChangeListener called with {}",dataObjectModificationAfter.isEnabled());
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;//gets set to true only if this particular tzone has
+ LOG.debug("Update:Calling TunnelMonitorToggleWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }
+ LOG.debug("Update:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModificationAfter.isEnabled());
+ ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+ dataObjectModificationAfter.isEnabled(), broker, hwVtepsExist);
+ coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+ }
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<TunnelMonitorEnabled> key, TunnelMonitorEnabled dataObjectModification) {
+ LOG.debug("add TunnelMonitorChangeListener called with {}",dataObjectModification.isEnabled());
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }
+ LOG.debug("Add:Calling TunnelMonitorToggleWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.isEnabled());
+ ItmMonitorToggleWorker toggleWorker = new ItmMonitorToggleWorker(hwVteps, tzone.getZoneName(),
+ dataObjectModification.isEnabled(), broker, hwVtepsExist);
+ coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+ }
+ }
+ }
+
+ @Override protected TunnelMonitorChangeListener getDataTreeChangeListener() {
+ return TunnelMonitorChangeListener.this;
+ }
+
+}
--- /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.itm.listeners;
+
+import com.google.common.base.Optional;
+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.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.vpnservice.itm.confighelpers.HwVtep;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorIntervalWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmMonitorToggleWorker;
+import org.opendaylight.vpnservice.itm.confighelpers.ItmTepAddWorker;
+import org.opendaylight.vpnservice.itm.globals.ITMConstants;
+import org.opendaylight.vpnservice.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+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.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorEnabled;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.TunnelMonitorInterval;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVteps;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TunnelMonitorIntervalListener extends AsyncDataTreeChangeListenerBase<TunnelMonitorInterval, TunnelMonitorIntervalListener>
+ implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(TunnelMonitorIntervalListener.class);
+ private ListenerRegistration<DataChangeListener> monitorIntervalListenerRegistration;
+ private final DataBroker broker;
+
+ public TunnelMonitorIntervalListener(DataBroker db) {
+ super(TunnelMonitorInterval.class, TunnelMonitorIntervalListener.class);
+ broker = db;
+ }
+
+ @Override protected InstanceIdentifier<TunnelMonitorInterval> getWildCardPath() {
+ return InstanceIdentifier.create(TunnelMonitorInterval.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<TunnelMonitorInterval> key, TunnelMonitorInterval dataObjectModification) {
+ LOG.debug("remove TunnelMonitorIntervalListener called with {}",dataObjectModification.getInterval());
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ /* hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;
+ LOG.debug("Remove:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }*/
+ //if you remove configuration, the last configured interval is only set i.e no change
+ LOG.debug("Remove:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.getInterval());
+ ItmMonitorIntervalWorker toggleWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+ dataObjectModification.getInterval(), broker, hwVtepsExist);
+ coordinator.enqueueJob(tzone.getZoneName(), toggleWorker);
+ }
+ }
+ }
+
+ @Override protected void update(InstanceIdentifier<TunnelMonitorInterval> key,
+ TunnelMonitorInterval dataObjectModificationBefore,
+ TunnelMonitorInterval dataObjectModificationAfter) {
+ LOG.debug("update TunnelMonitorIntervalListener called with {}",dataObjectModificationAfter.getInterval());
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ /*hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;//gets set to true only if this particular tzone has
+ LOG.debug("Update:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }*/
+ LOG.debug("Update:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModificationAfter.getInterval());
+ ItmMonitorIntervalWorker intervalWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+ dataObjectModificationAfter.getInterval(), broker, hwVtepsExist);
+ coordinator.enqueueJob(tzone.getZoneName(), intervalWorker);
+ }
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<TunnelMonitorInterval> key, TunnelMonitorInterval dataObjectModification) {
+ LOG.debug("Add TunnelMonitorIntervalListener called with {}",dataObjectModification.getInterval());
+ List<HwVtep> hwVteps = new ArrayList<HwVtep>();
+ Boolean hwVtepsExist = false;
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ InstanceIdentifier<TransportZones> path = InstanceIdentifier.builder(TransportZones.class).build();
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, broker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ for (TransportZone tzone : tZones.getTransportZone()) {
+ /*hwVtepsExist = false;
+ hwVteps = new ArrayList<HwVtep>();
+ if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
+ for (Subnets sub : tzone.getSubnets()) {
+ if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
+ hwVtepsExist = true;
+ LOG.debug("Add:Calling TunnelMonitorIntervalWorker with tzone = {} and hwtepExist",tzone.getZoneName());
+ for (DeviceVteps deviceVtep : sub.getDeviceVteps()) {
+ HwVtep hwVtep = ItmUtils.createHwVtepObject(deviceVtep.getTopologyId(), deviceVtep.getNodeId(),
+ deviceVtep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(), sub.getVlanId(),
+ tzone.getTunnelType(), tzone);
+ hwVteps.add(hwVtep);
+ }
+ }
+ }
+ }*/
+ LOG.debug("Add:Calling TunnelMonitorIntervalWorker with tzone = {} and {}",tzone.getZoneName(),dataObjectModification.getInterval());
+ ItmMonitorIntervalWorker intervalWorker = new ItmMonitorIntervalWorker(hwVteps, tzone.getZoneName(),
+ dataObjectModification.getInterval(), broker, hwVtepsExist);
+ //conversion to milliseconds done while writing to i/f-mgr config DS
+ coordinator.enqueueJob(tzone.getZoneName(), intervalWorker);
+ }
+ }
+ }
+
+ @Override protected TunnelMonitorIntervalListener getDataTreeChangeListener() {
+ return TunnelMonitorIntervalListener.this;
+ }
+}
* 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.itm.listeners;
import java.math.BigInteger;
--- /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.itm.monitoring;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import java.util.ArrayList;
+
+/**
+ * Created by emnqrrw on 10/27/2015.
+ */
+public class DataPathAlarm extends NotificationBroadcasterSupport implements DataPathAlarmMBean {
+
+ ArrayList<String> raiseAlarmObject = new ArrayList<String>();
+ ArrayList<String> clearAlarmObject = new ArrayList<String>();
+ private long sequenceNumber = 1;
+
+ public void setRaiseAlarmObject(ArrayList<String> raiseAlarmObject) {
+ this.raiseAlarmObject = raiseAlarmObject;
+
+ Notification n = new AttributeChangeNotification(this,
+ sequenceNumber++, System.currentTimeMillis(),
+ "raise alarm object notified ", "raiseAlarmObject", "ArrayList",
+ "", this.raiseAlarmObject);
+ sendNotification(n);
+ }
+
+ public ArrayList<String> getRaiseAlarmObject() {
+ return raiseAlarmObject;
+ }
+
+ public void setClearAlarmObject(ArrayList<String> clearAlarmObject) {
+ this.clearAlarmObject = clearAlarmObject;
+
+ Notification n = new AttributeChangeNotification(this,
+ sequenceNumber++, System.currentTimeMillis(),
+ "clear alarm object notified ", "clearAlarmObject", "ArrayList",
+ "", this.clearAlarmObject);
+ sendNotification(n);
+ }
+
+ public ArrayList<String> getClearAlarmObject() {
+ return clearAlarmObject;
+ }
+
+ public synchronized void raiseAlarm(String alarmName, String additionalText, String source){
+ raiseAlarmObject.add(alarmName);
+ raiseAlarmObject.add(additionalText);
+ raiseAlarmObject.add(source);
+ setRaiseAlarmObject(raiseAlarmObject);
+ raiseAlarmObject.clear();
+ }
+ public synchronized void clearAlarm(String alarmName, String additionalText, String source){
+ clearAlarmObject.add(alarmName);
+ clearAlarmObject.add(additionalText);
+ clearAlarmObject.add(source);
+ setClearAlarmObject(clearAlarmObject);
+ clearAlarmObject.clear();
+ }
+}
--- /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.itm.monitoring;
+
+import java.util.ArrayList;
+
+/**
+ * Created by emnqrrw on 10/27/2015.
+ */
+public interface DataPathAlarmMBean {
+ public void setRaiseAlarmObject(ArrayList<String> raiseAlarmObject);
+ public ArrayList<String> getRaiseAlarmObject();
+ public void setClearAlarmObject(ArrayList<String> clearAlarmObject);
+ public ArrayList<String> getClearAlarmObject();
+ public void raiseAlarm(String alarmName, String additionalText, String source);
+ public void clearAlarm(String alarmName, String additionalText, String source);
+}
--- /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.itm.monitoring;
+
+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.itm.impl.ItmUtils;
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+
+/**
+ * Created by emnqrrw on 11/2/2015.
+ */
+public class ItmTunnelEventListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(ItmTunnelEventListener.class);
+ private final DataBroker broker;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ public static final JMXAlarmAgent alarmAgent = new JMXAlarmAgent();
+
+ public ItmTunnelEventListener(final DataBroker db){
+ super(Interface.class);
+ broker = db;
+ registerListener(db);
+ alarmAgent.registerMbean();
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), ItmTunnelEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ logger.error("ITM Monitor Interfaces DataChange listener registration fail!", e);
+ throw new IllegalStateException("ITM Monitor registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+ String ifName = del.getName() ;
+ if( del.getType() != null && del.getType().equals(Tunnel.class)) {
+ InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+ if( internalTunnel != null) {
+ BigInteger srcDpId = internalTunnel.getSourceDPN();
+ BigInteger dstDpId = internalTunnel.getDestinationDPN();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+ logger.trace("ITM Tunnel removed b/w srcDpn: {} and dstDpn: {} for tunnelType: {}", srcDpId, dstDpId, tunnelType);
+ clearInternalDataPathAlarm(srcDpId.toString(),dstDpId.toString(),tunnelType);
+ }else {
+ ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+ if( externalTunnel != null) {
+ String srcNode = externalTunnel.getSourceDevice();
+ String dstNode = externalTunnel.getDestinationDevice();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+ logger.trace("ITM Tunnel removed b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+ clearExternalDataPathAlarm(srcNode,dstNode,tunnelType);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+ String ifName = update.getName() ;
+ if( update.getType() != null && update.getType().equals(Tunnel.class)) {
+ InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+ if( internalTunnel != null) {
+ BigInteger srcDpId = internalTunnel.getSourceDPN();
+ BigInteger dstDpId = internalTunnel.getDestinationDPN();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+ logger.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}", isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
+ if(isTunnelInterfaceUp(update)) {
+ logger.trace("ITM Tunnel State is UP b/w srcDpn: {} and dstDpn: {} for tunnelType {} ", srcDpId, dstDpId, tunnelType);
+ clearInternalDataPathAlarm(srcDpId.toString(),dstDpId.toString(),tunnelType);
+ }else {
+ logger.trace("ITM Tunnel State is DOWN b/w srcDpn: {} and dstDpn: {}", srcDpId, dstDpId);
+ StringBuilder alarmText = new StringBuilder();
+ alarmText.append("Data Path Connectivity is lost between ").append("openflow:").append(srcDpId).append(" and openflow:")
+ .append(dstDpId).append(" for tunnelType:").append(tunnelType);
+ raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType,alarmText.toString());
+ }
+ }else{
+ ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+ if( externalTunnel != null) {
+ String srcNode = externalTunnel.getSourceDevice();
+ String dstNode = externalTunnel.getDestinationDevice();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+ logger.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}", isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
+ if(isTunnelInterfaceUp(update)) {
+ logger.trace("ITM Tunnel State is UP b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+ clearExternalDataPathAlarm(srcNode.toString(),dstNode.toString(),tunnelType);
+ }else {
+ logger.trace("ITM Tunnel State is DOWN b/w srcNode: {} and dstNode: {}", srcNode, dstNode);
+ StringBuilder alarmText = new StringBuilder();
+ alarmText.append("Data Path Connectivity is lost between ").append(srcNode).append(dstNode).append(" for tunnelType:").append(tunnelType);
+ raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType,alarmText.toString());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
+ String ifName = add.getName() ;
+ if( add.getType() != null && add.getType().equals(Tunnel.class)) {
+ InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName,broker);
+ if( internalTunnel != null) {
+ BigInteger srcDpId = internalTunnel.getSourceDPN();
+ BigInteger dstDpId = internalTunnel.getDestinationDPN();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
+ if(!isTunnelInterfaceUp(add)) {
+ logger.trace("ITM Tunnel State during tep add is DOWN b/w srcDpn: {} and dstDpn: {} for tunnelType: {}", srcDpId, dstDpId, tunnelType);
+ StringBuilder alarmText = new StringBuilder();
+ alarmText.append("Data Path Connection is down between ").append("openflow:").append(srcDpId).append(" and openflow:")
+ .append(dstDpId).append(" for tunnelType:").append(tunnelType).append(" during initial state");
+ raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText.toString());
+ }
+ }else {
+ ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
+ if( externalTunnel != null) {
+ String srcNode = externalTunnel.getSourceDevice();
+ String dstNode = externalTunnel.getDestinationDevice();
+ String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
+ if(!isTunnelInterfaceUp(add)) {
+ logger.trace("ITM Tunnel State during tep add is DOWN b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode, tunnelType);
+ StringBuilder alarmText = new StringBuilder();
+ alarmText.append("Data Path Connection is down between ").append(srcNode).append(dstNode).append(" for tunnelType:").append(tunnelType).append(" during initial state");
+ raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType,alarmText.toString());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ }
+
+ public void raiseInternalDataPathAlarm(String srcDpnId,String dstDpnId,String tunnelType,String alarmText) {
+
+ StringBuilder source = new StringBuilder();
+ source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId).append("-tunnelType").append(tunnelType);
+
+ logger.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
+ //Invokes JMX raiseAlarm method
+ alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
+ }
+
+ public void clearInternalDataPathAlarm(String srcDpnId,String dstDpnId,String tunnelType) {
+ StringBuilder source = new StringBuilder();
+
+ source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId).append("-tunnelType").append(tunnelType);
+ logger.trace("Clearing DataPathConnectionFailure alarm of source {} ", source);
+ //Invokes JMX clearAlarm method
+ alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", "Clearing ITM Tunnel down alarm", source.toString());
+ }
+
+ public void raiseExternalDataPathAlarm(String srcDevice,String dstDevice,String tunnelType, String alarmText) {
+
+ StringBuilder source = new StringBuilder();
+ source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType").append(tunnelType);
+
+ logger.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
+ //Invokes JMX raiseAlarm method
+ alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
+ }
+
+
+ public void clearExternalDataPathAlarm(String srcDevice,String dstDevice,String tunnelType) {
+
+ StringBuilder source = new StringBuilder();
+
+ source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType").append(tunnelType);
+
+ //logger.trace("Clearing DataPathConnectionFailure alarm of source {} ", source);
+ //Invokes JMX clearAlarm method
+ alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", "Clearing ITM Tunnel down alarm", source.toString());
+
+ }
+
+ private boolean isTunnelInterfaceUp( Interface intf) {
+ boolean interfaceUp = (intf.getOperStatus().equals(Interface.OperStatus.Up)) ? true :false ;
+ return interfaceUp ;
+ }
+
+}
--- /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.itm.monitoring;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.*;
+import java.lang.management.ManagementFactory;
+/**
+ * Created by emnqrrw on 11/2/2015.
+ */
+public class JMXAlarmAgent {
+ static Logger s_logger = LoggerFactory.getLogger(JMXAlarmAgent.class);
+ private MBeanServer mbs = null;
+ private ObjectName alarmName = null;
+ private static final String BEANNAME = "SDNC.FM:name=DataPathAlarmBean";
+ private static DataPathAlarm alarmBean= new DataPathAlarm();
+
+ public JMXAlarmAgent() {
+ // Get the platform MBeanServer
+ mbs = ManagementFactory.getPlatformMBeanServer();
+ try {
+ alarmName = new ObjectName(BEANNAME);
+ } catch (MalformedObjectNameException e) {
+ s_logger.error("ObjectName instance creation failed for BEANAME {} : {}",BEANNAME, e);
+ }
+ }
+
+ public void registerMbean() {
+ // Unique identification of MBeans
+ try {
+ // Uniquely identify the MBeans and register them with the platform MBeanServer
+ if(!mbs.isRegistered(alarmName)) {
+ mbs.registerMBean(alarmBean, alarmName);
+ s_logger.debug("Registered Mbean {} successfully", alarmName);
+ }
+ } catch(Exception e) {
+ s_logger.error("Registeration failed for Mbean {} :{}", alarmName,e);
+ }
+ }
+
+ public void unregisterMbean() {
+ try {
+ if(mbs.isRegistered(alarmName)) {
+ mbs.unregisterMBean(alarmName);
+ s_logger.debug("Unregistered Mbean {} successfully", alarmName);
+ }
+ } catch (Exception e) {
+ s_logger.error("UnRegisteration failed for Mbean {} :{}", alarmName,e);
+ }
+ }
+
+ public void invokeFMraisemethod(String alarmId,String text,String src) {
+ try {
+ mbs.invoke(alarmName, "raiseAlarm", new Object[]{alarmId, text, src}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()});
+ s_logger.trace("Invoked raiseAlarm function for Mbean {} with source {}", BEANNAME, src);
+ } catch (Exception e) {
+ s_logger.error("Invoking raiseAlarm method failed for Mbean {} :{}", alarmName,e);
+ }
+ }
+
+ public void invokeFMclearmethod(String alarmId,String text,String src) {
+ try {
+ mbs.invoke(alarmName, "clearAlarm", new Object[]{alarmId, text, src}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()});
+ s_logger.trace("Invoked clearAlarm function for Mbean {} with source {}",BEANNAME,src);
+ } catch (Exception e) {
+ s_logger.error("Invoking clearAlarm method failed for Mbean {} :{}", alarmName,e);
+ }
+ }
+}
/*
- * Copyright (c) 2015, 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 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,
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.vpnservice.mdsalutil.*;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
BigInteger destinationDpn = input.getDestinationDpid() ;
InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey( destinationDpn,sourceDpn));
+ .child(InternalTunnel.class, new InternalTunnelKey(destinationDpn, sourceDpn, input.getTunnelType()));
Optional<InternalTunnel> tnl = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
String dstNode = input.getDestinationNode();
InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, new ExternalTunnelKey(dstNode, sourceNode));
+ .child(ExternalTunnel.class, new ExternalTunnelKey(dstNode, sourceNode, input.getTunnelType()));
Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}", input.getDpnId() , input.getServiceId(), input.getInstruction());
final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
int serviceId = input.getServiceId() ;
- List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ List<MatchInfo> mkMatches = getTunnelMatchesForServiceId(serviceId);
byte[] vxLANHeader = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Flags Byte
byte Flags = (byte) 0x08;
vxLANHeader[6] = (byte) (serviceId >> 0);
// Matching metadata
- mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
- new BigInteger(1, vxLANHeader),
- MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
+// mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
+// new BigInteger(1, vxLANHeader),
+// MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,serviceId), 5, String.format("%s:%d","ITM Flow Entry ",serviceId),
IpAddress dstIp = input.getDestinationIp() ;
InstanceIdentifier<ExternalTunnel> path1 = InstanceIdentifier.create(
ExternalTunnelList.class)
- .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp), srcDpn.toString()));
+ .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp), srcDpn.toString(), TunnelTypeMplsOverGre.class));
Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
if (dstIp.equals(firstEndPt.getIpAddress())) {
InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
TunnelList.class)
- .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(),srcDpn));
+ .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(), srcDpn, input.getTunnelType()));
Optional<InternalTunnel>
tnl =
}
});
}
+ else {
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
+ return result;
+ }
return result;
} catch (Exception e) {
RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
}
}
+ @Override
+ public Future<RpcResult<java.lang.Void>> addL2GwMlagDevice(AddL2GwMlagDeviceInput input)
+ {
+ final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+ try {
+ final IpAddress hwIp = input.getIpAddress();
+ final List<String> node_id = input.getNodeId();
+ InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
+ LOG.error("No teps configured");
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
+ return result;
+ }
+ String transportZone = tZones.getTransportZone().get(0).getZoneName();
+ if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
+ return result;
+ }
+ SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
+ DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id.get(0));
+ InstanceIdentifier<DeviceVteps> path =
+ InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey(transportZone))
+ .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build();
+ DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp).setNodeId(node_id.get(0)).setTopologyId(input.getTopologyId()).build();
+ WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ LOG.trace("writing hWvtep{}",deviceVtep);
+ t.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true);
+ if(node_id.size() == 2) {
+ LOG.trace("second node-id {}",node_id.get(1));
+ DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, node_id.get(1));
+ InstanceIdentifier<DeviceVteps> path2 = InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey(transportZone))
+ .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey2).build();
+ DeviceVteps deviceVtep2 = new DeviceVtepsBuilder().setKey(deviceVtepKey2).setIpAddress(hwIp).setNodeId(node_id.get(1))
+ .setTopologyId(input.getTopologyId()).build();
+ LOG.trace("writing {}",deviceVtep2);
+ t.put(LogicalDatastoreType.CONFIGURATION, path2, deviceVtep2, true);
+ }ListenableFuture<Void> futureCheck = t.submit();
+ Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void aVoid) {
+ result.set(RpcResultBuilder.<Void>success().build());
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
+ LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+ }
+ });
+ }
+ return result;
+ } catch (Exception e) {
+ RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
+ withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
+ return Futures.immediateFuture(resultBuilder.build());
+ }
+ }
+ @Override
+ public Future<RpcResult<Void>> deleteL2GwMlagDevice(DeleteL2GwMlagDeviceInput input) {
+ final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+ try {
+ final IpAddress hwIp = input.getIpAddress();
+ final List<String> node_id = input.getNodeId();
+ InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
+ Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
+ if (tZonesOptional.isPresent()) {
+ TransportZones tZones = tZonesOptional.get();
+ if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
+ LOG.error("No teps configured");
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
+ return result;
+ }
+ String transportZone = tZones.getTransportZone().get(0).getZoneName();
+ if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
+ return result;
+ }
+ SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
+ DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id.get(0));
+ InstanceIdentifier<DeviceVteps> path =
+ InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey(transportZone))
+ .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+ deviceVtepKey).build();
+ WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ t.delete(LogicalDatastoreType.CONFIGURATION, path);
+ DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, node_id.get(1));
+ InstanceIdentifier<DeviceVteps> path2 =
+ InstanceIdentifier.builder(TransportZones.class)
+ .child(TransportZone.class, new TransportZoneKey(transportZone))
+ .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+ deviceVtepKey2).build();
+ t.delete(LogicalDatastoreType.CONFIGURATION, path2);
+ ListenableFuture<Void> futureCheck = t.submit();
+ Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void aVoid) {
+ result.set(RpcResultBuilder.<Void>success().build());
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
+ LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
+ result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+ }
+ });
+ }
+ return result;
+ } catch (Exception e) {
+ RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
+ withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
+ return Futures.immediateFuture(resultBuilder.build());
+ }
+ }
}
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 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,
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 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,
@Override
public java.lang.AutoCloseable createInstance() {
- ItmProvider provider = new ItmProvider();
+ ItmProvider provider = new ItmProvider();
provider.setMdsalApiManager(getMdsalutilDependency());
provider.setNotificationPublishService(getNotificationPublishServiceDependency());
provider.setNotificationService(getNotificationServiceDependency());
--- /dev/null
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <reference id="itmProviderRef" interface="org.opendaylight.vpnservice.itm.api.IITMProvider" availability="optional" />
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepAdd">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepDelete">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepShow">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepCommit">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepShowState">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepConfigureTunnelType">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepMonitor">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepDeleteDatastore">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaAdd">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaShow">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaUpdate">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.VtepSchemaDelete">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ <command>
+ <action class="org.opendaylight.vpnservice.itm.cli.TepEnableTunnelMonitor">
+ <property name="itmProvider" ref="itmProviderRef" />
+ </action>
+ </command>
+ </command-bundle>
+</blueprint>
\ No newline at end of file
public class ClusteringUtils {
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+ if (dataStoreJobCoordinator == null) {
+ dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+ }
+ return dataStoreJobCoordinator;
+ }
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
String entityType, String nodeId) {
return checkNodeEntityOwner(entityOwnershipService, new Entity(entityType, nodeId),
public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
Entity entity, long sleepBetweenRetries, int maxRetries) {
SettableFuture<Boolean> checkNodeEntityfuture = SettableFuture.create();
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
CheckEntityOwnerTask checkEntityOwnerTask = new CheckEntityOwnerTask(entityOwnershipService, entity,
checkNodeEntityfuture, sleepBetweenRetries, maxRetries);
- dataStoreCoordinator.enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
+ getDataStoreJobCoordinator().enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
return checkNodeEntityfuture;
}
--- /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.utils.clustering;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.*;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+public class EntityOwnerUtils {
+ public static final String ENTITY_OWNER_CACHE = "entity.owner.cache";
+ private static final Logger LOG = LoggerFactory.getLogger(EntityOwnerUtils.class);
+
+ static {
+ createEntityOwnerCache();
+ }
+ private static void createEntityOwnerCache() {
+ if (CacheUtil.getCache(ENTITY_OWNER_CACHE) == null) {
+ CacheUtil.createCache(ENTITY_OWNER_CACHE);
+ }
+ }
+
+ private static String getEntity(String entityType, String entityName) {
+ return entityType;
+ }
+
+ private static void updateEntityOwner(String entityType, String entityName, Boolean isOwner) {
+ ConcurrentMap<String, Boolean> entityOwnerCache =
+ (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+ String entity = getEntity(entityType, entityName);
+ if (entityOwnerCache != null) {
+ LOG.trace("updating entity owner "+isOwner+ " "+entity );
+ entityOwnerCache.put(entity, isOwner);
+ }
+ }
+
+ public static boolean amIEntityOwner(String entityType, String entityName) {
+ ConcurrentMap<String, Boolean> entityOwnerCache =
+ (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+ String entity = getEntity(entityType, entityName);
+ boolean ret = false;
+ if (entityOwnerCache != null) {
+ if (entityOwnerCache.get(entity) != null) {
+ ret = entityOwnerCache.get(entity);
+ }
+ } else {
+ LOG.error("entity owner cache null");
+ }
+ LOG.trace("get entity owner result {} for type {}" ,ret ,entity);
+ return ret;
+ }
+
+ /**
+ * Registers the entityName for ownership for given entityType
+ * adds a local listener which takes care of updating the cached entity status
+ * @param entityOwnershipService
+ * @param entityType
+ * @param entityName
+ * @param listener also adds this listener for ownership events if provided
+ * @throws CandidateAlreadyRegisteredException
+ */
+ public static void registerEntityCandidateForOwnerShip (
+ EntityOwnershipService entityOwnershipService,
+ String entityType, String entityName, EntityOwnershipListener listener)
+ throws CandidateAlreadyRegisteredException {
+ LOG.info("registering for entity ownership for type "+entityType);
+ Entity candidateEntity = new Entity(entityType, entityName);
+ EntityOwnershipCandidateRegistration candidateRegistration = entityOwnershipService.registerCandidate(
+ candidateEntity);
+ EntityOwnershipListenerRegistration listenerRegistration = entityOwnershipService.registerListener(entityType,
+ entityOwnershipListener);
+ if (listener != null) {
+ entityOwnershipService.registerListener(entityType, listener);
+ }
+ LOG.info("registered for entity ownership for type "+entityType);
+ //TODO track registrations for closing
+ }
+
+ private static Listener entityOwnershipListener = new Listener();
+ static class Listener implements EntityOwnershipListener {
+
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ String entityType = ownershipChange.getEntity().getType();
+ String entityName = ownershipChange.getEntity().getId().toString();
+ LOG.info("entity ownership changed for "+entityType);
+ if (ownershipChange.hasOwner() && ownershipChange.isOwner()) {
+ LOG.info("entity ownership change became owner for type "+entityType);
+ updateEntityOwner(entityType, entityName, Boolean.TRUE);
+ } else {
+ LOG.info("entity ownership lost ownership for type "+entityType);
+ updateEntityOwner(entityType, entityName, Boolean.FALSE);
+ }
+ }
+ }
+}
\ No newline at end of file
public static final Object PSWITCH_URI_PREFIX = "physicalswitch";
public static final ImmutableBiMap<Class<? extends EncapsulationTypeBase>, String> ENCAPS_TYPE_MAP = new ImmutableBiMap.Builder<Class<? extends EncapsulationTypeBase>, String>()
.put(EncapsulationTypeVxlanOverIpv4.class, "vxlan_over_ipv4").build();
-
+ public static final String ELAN_ENTITY_TYPE = "elan";
+ public static final String ELAN_ENTITY_NAME = "elan";
+ public static final String TEP_PREFIX = "vxlan_over_ipv4:";
}
.child(Node.class, new NodeKey(nodeId));
}
+
+ public static InstanceIdentifier<TerminationPoint> createTerminationPointId(NodeId nodeId,
+ TerminationPointKey tpKey) {
+ return createInstanceIdentifier(nodeId).child(TerminationPoint.class, tpKey);
+ }
/**
* Creates the logical switches instance identifier.
*
return vbBuilder.build();
}
+ public static TerminationPointKey getTerminationPointKey(String ipAddress) {
+ TerminationPointKey tpKey = null;
+ String tpKeyStr = getTerminationPointKeyString(ipAddress);
+ if(tpKeyStr != null) {
+ tpKey = new TerminationPointKey(new TpId(tpKeyStr));
+ }
+ return tpKey;
+ }
+ public static String getTerminationPointKeyString(String ipAddress) {
+ String tpKeyStr = null;
+ if(ipAddress != null) {
+ tpKeyStr = new StringBuilder(HwvtepSouthboundConstants.TEP_PREFIX).
+ append(ipAddress).toString();
+ }
+ return tpKeyStr;
+ }
+
}
package org.opendaylight.vpnservice.utils.hwvtep;
+import java.util.ArrayList;
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
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;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, NodeId nodeId,
LogicalSwitches logicalSwitch) {
WriteTransaction transaction = broker.newWriteOnlyTransaction();
- putLogicalSwitch(transaction, nodeId, logicalSwitch);
+ putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
return transaction.submit();
}
+ public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, LogicalDatastoreType logicalDatastoreType,
+ NodeId nodeId,
+ LogicalSwitches logicalSwitch) {
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ putLogicalSwitch(transaction,logicalDatastoreType, nodeId, logicalSwitch);
+ return transaction.submit();
+ }
/**
* Put the logical switches in the transaction.
*
final List<LogicalSwitches> lstSwitches) {
if (lstSwitches != null) {
for (LogicalSwitches logicalSwitch : lstSwitches) {
- putLogicalSwitch(transaction, nodeId, logicalSwitch);
+ putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
}
}
}
* @param logicalSwitch
* the logical switch
*/
- public static void putLogicalSwitch(final WriteTransaction transaction, final NodeId nodeId,
- final LogicalSwitches logicalSwitch) {
+ public static void putLogicalSwitch(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+ final NodeId nodeId, final LogicalSwitches logicalSwitch) {
InstanceIdentifier<LogicalSwitches> iid = HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId,
logicalSwitch.getHwvtepNodeName());
- transaction.put(LogicalDatastoreType.CONFIGURATION, iid, logicalSwitch, true);
+ transaction.put(logicalDatastoreType, iid, logicalSwitch, true);
}
/**
transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true);
}
+ public static void putRemoteMcastMac(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+ final NodeId nodeId,
+ RemoteMcastMacs remoteMcastMac) {
+ InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+ remoteMcastMac.getKey());
+ transaction.put(logicalDatastoreType, iid, remoteMcastMac, true);
+ }
/**
* Gets the remote mcast mac.
*
}
return null;
}
+
+ /**
+ * 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.
+ */
+ public static ListenableFuture<Void> installUcastMacs(DataBroker broker,
+ 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);
+ }
+
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../../commons/config-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>natservice-api</artifactId>
+ <version>${vpnservices.version}</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-yang-types-20130715</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+module odl-nat {
+ namespace "urn:opendaylight:vpnservice:natservice";
+ prefix odl-nat;
+
+ import ietf-yang-types { prefix "yang"; /*revision-date 2013-07-15; */}
+ import ietf-inet-types { prefix "inet"; }
+
+ revision "2016-01-11" {
+ description "NAT Manager module";
+ }
+
+ container external-networks {
+ list networks {
+ key id;
+ leaf id {
+ type yang:uuid;
+ }
+ leaf vpnid { type yang:uuid; }
+ leaf-list router-ids { type yang:uuid; }
+ }
+ }
+
+ container ext-routers {
+ list routers {
+ key router-name;
+ leaf router-name { type string; }
+ leaf network-id { type yang:uuid; }
+ leaf enable-snat { type boolean; }
+ leaf-list external-ips {
+ type string; //format - ipaddress\prefixlength
+ }
+ leaf-list subnet-ids { type yang:uuid; }
+ leaf ext_gw_mac_address { type string; }
+ }
+ }
+
+
+ grouping external-interface-info {
+ leaf internal-ip { type string; }
+ leaf external-ip { type string; }
+ leaf label { type uint16; config false; }
+ }
+
+ container floating-ip-info {
+ config true;
+ list router-ports {
+ key router-id;
+ leaf router-id { type string; }
+ leaf external-network-id { type yang:uuid; }
+ list ports {
+ key port-name;
+ leaf port-name { type string; }
+ list ip-mapping {
+ key "internal-ip";
+ uses external-interface-info;
+ }
+ }
+ }
+ }
+
+ container napt-switches {
+ list router-to-napt-switch {
+ key router-name;
+ leaf router-name { type string; }
+ leaf primary-switch-id { type uint64; }
+ }
+ }
+
+ grouping ip-port-entity {
+ leaf ip-address { type string; }
+ leaf port-num { type uint16; }
+ }
+
+ typedef protocol-types {
+ type enumeration {
+ enum TCP;
+ enum UDP;
+ }
+ }
+
+ container intext-ip-port-map {
+ config true;
+ list ip-port-mapping {
+ key router-id;
+ leaf router-id { type uint32; }
+ list intext-ip-protocol-type {
+ key protocol;
+ leaf protocol { type protocol-types; }
+ list ip-port-map {
+ key ip-port-internal;
+ description "internal to external ip-port mapping";
+ leaf ip-port-internal { type string; }
+ container ip-port-external {
+ uses ip-port-entity;
+ }
+ }
+ }
+ }
+ }
+
+ container snatint-ip-port-map {
+ list intip-port-map {
+ key router-id;
+ leaf router-id { type uint32; }
+ list ip-port {
+ key internal-ip;
+ leaf internal-ip { type string; }
+ list int-ip-proto-type {
+ key protocol;
+ leaf protocol { type protocol-types; }
+ leaf-list ports { type uint16; }
+ }
+ }
+ }
+ }
+
+ container intext-ip-map {
+ config false;
+ list ip-mapping {
+ key segment-id;
+ leaf segment-id { type uint32; }
+ list ip-map {
+ key internal-ip;
+ leaf internal-ip { type string; }
+ leaf external-ip { type string; }
+ leaf label {type uint32;}
+ }
+ }
+ }
+
+ container router-to-vpn-mapping {
+ list routermapping {
+ key router-name;
+ leaf router-name { type string; }
+ leaf vpn-id { type uint32; }
+ leaf vpn-name { type string; }
+ }
+ }
+
+ container router-id-name {
+ list routerIds {
+ key router-id;
+ leaf router-id {type uint32;}
+ leaf router-name { type string; }
+ }
+ }
+
+ container external-ips-counter {
+ config false;
+ list external-counters{
+ key segment-id;
+ leaf segment-id { type uint32; }
+ list external-ip-counter {
+ key external-ip;
+ leaf external-ip { type string; }
+ leaf counter { type uint8; }
+ }
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: --><!--
+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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../../commons/config-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>natservice-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>org.opendaylight.vpnservice</groupId>
+ <artifactId>natservice-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsalutil-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>itm-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>bgpmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>vpnmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>fibmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>idmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>interfacemgr-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>neutronvpn-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-net</groupId>
+ <artifactId>commons-net</artifactId>
+ </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>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+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
+-->
+<snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:natservice:impl?module=natservice-impl&revision=2016-01-11</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: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:bgpmanager:api?module=bgpmanager-api&revision=2015-04-20</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&revision=2015-04-10</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:natservice:impl">prefix:natservice-impl</type>
+ <name>natservice-default</name>
+ <broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <name>binding-osgi-broker</name>
+ </broker>
+ <rpc-registry>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+ <name>binding-rpc-broker</name>
+ </rpc-registry>
+ <bgpmanager>
+ <type xmlns:bgpmanager="urn:opendaylight:params:xml:ns:yang:bgpmanager:api">bgpmanager:bgpmanager-api</type>
+ <name>bgpmanager</name>
+ </bgpmanager>
+ <notification-service>
+ <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>
+ <mdsalutil>
+ <type xmlns:mdsalutil="urn:opendaylight:params:xml:ns:yang:mdsalutil:api">mdsalutil:odl-mdsalutil</type>
+ <name>mdsalutil-service</name>
+ </mdsalutil>
+ </module>
+ </modules>
+ </data>
+ </configuration>
+</snapshot>
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+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.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AddDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.add.dpn.event.AddEventData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RemoveDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.OdlL3vpnListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class DpnInVpnListener implements OdlL3vpnListener {
+ private static final Logger LOG = LoggerFactory.getLogger(DpnInVpnListener.class);
+ private DataBroker dataBroker;
+ private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+ private NaptSwitchHA naptSwitchHA;
+ private IMdsalApiManager mdsalManager;
+ private IdManagerService idManager;
+
+ public DpnInVpnListener(DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+ this.defaultRouteProgrammer = defaultRouteProgrammer;
+ }
+
+ void setNaptSwitchHA(NaptSwitchHA switchHA) {
+ naptSwitchHA = switchHA;
+ }
+
+ void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
+ public void onAddDpnEvent(AddDpnEvent notification) {
+/*
+ AddEventData eventData = notification.getAddEventData();
+ BigInteger dpnId = eventData.getDpnId();
+ String vpnName = eventData.getVpnName();
+ LOG.info("Received add dpn {} in vpn {} event", dpnId, vpnName);
+ String routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+ if (routerId != null) {
+ //check router is associated to external network
+ InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ Uuid networkId = routerData.get().getNetworkId();
+ if(networkId != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+ long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
+ if(vpnId != NatConstants.INVALID_ID) {
+ //Install default entry in FIB to SNAT table
+ LOG.debug("Installing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+ } else {
+ LOG.debug("Add DPN Event: Could not read vpnId for vpnName {}", vpnName);
+ }
+ if (routerData.get().isEnableSnat()) {
+ LOG.info("SNAT enabled for router {}", routerId);
+ handleSNATForDPN(dpnId, routerId);
+ } else {
+ LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
+ }
+ }
+ }
+ }
+*/
+ }
+
+ void handleSNATForDPN(BigInteger dpnId, String routerName) {
+ //Check if primary and secondary switch are selected, If not select the role
+ //Install select group to NAPT switch
+ //Install default miss entry to NAPT switch
+/*
+ BigInteger naptSwitch;
+ try {
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return;
+ }
+ BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ if (naptId == null || naptId.equals(BigInteger.ZERO)) {
+ LOG.debug("No Naptswitch is selected for router {}", routerName);
+
+ naptSwitch = dpnId;
+ boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
+ if(!naptstatus) {
+ LOG.error("Failed to update newNaptSwitch {} for routername {}",naptSwitch,routerName);
+ return;
+ }
+ LOG.debug("Switch {} is elected as NaptSwitch for router {}",dpnId,routerName);
+
+ //installing group
+ List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
+ naptSwitchHA.installSnatGroupEntry(naptSwitch,bucketInfo,routerName);
+
+ naptSwitchHA.installSnatFlows(routerName,routerId,naptSwitch);
+
+ } else {
+ LOG.debug("Napt switch with Id {} is already elected for router {}",naptId, routerName);
+ naptSwitch = naptId;
+
+ //installing group
+ List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
+ if (bucketInfo == null) {
+ LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}",dpnId,routerName,
+ naptSwitch);
+ return;
+ }
+ naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
+ }
+ // Install miss entry (table 26) pointing to group
+ long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+ FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,NatConstants.ADD_FLOW);
+ if (flowEntity == null) {
+ LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}",routerName,dpnId,groupId);
+ return;
+ }
+ LOG.debug("Successfully installed flow for dpnId {} router {} group {}",dpnId,routerName,groupId);
+ mdsalManager.installFlow(flowEntity);
+ } catch (Exception ex) {
+ LOG.error("Exception in handleSNATForDPN method : {}",ex);
+ }
+*/
+ }
+
+ public void onRemoveDpnEvent(RemoveDpnEvent notification) {
+/*
+ RemoveEventData eventData = notification.getRemoveEventData();
+ BigInteger dpnId = eventData.getDpnId();
+ String vpnName = eventData.getVpnName();
+ LOG.info("Received remove dpn {} in vpn {} event", dpnId, vpnName);
+ String routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+ if (routerId != null) {
+ //check router is associated to external network
+ InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ Uuid networkId = routerData.get().getNetworkId();
+ if(networkId != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+ long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
+ if(vpnId != NatConstants.INVALID_ID) {
+ //Remove default entry in FIB
+ LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
+ } else {
+ LOG.debug("Remove DPN Event: Could not read vpnId for vpnName {}", vpnName);
+ }
+ if (routerData.get().isEnableSnat()) {
+ LOG.info("SNAT enabled for router {}", routerId);
+ removeSNATFromDPN(dpnId,routerId);
+ } else {
+ LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
+ }
+ }
+ }
+ }
+*/
+ }
+
+ /*void removeSNATFromDPN(BigInteger dpnId, String routerName) {
+ //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+ //remove miss entry to NAPT switch
+ //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return;
+ }
+ BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+ LOG.debug("No naptSwitch is selected for router {}", routerName);
+ return;
+ }
+ try {
+ boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch);
+ if (!naptStatus) {
+ LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+ dpnId, routerName);
+ } else {
+ naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
+ }
+ } catch (Exception ex) {
+ LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);
+ }
+
+ long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+ FlowEntity flowEntity = null;
+ try {
+ flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, NatConstants.DEL_FLOW);
+ if (flowEntity == null) {
+ LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
+ return;
+ }
+ LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
+ mdsalManager.removeFlow(flowEntity);
+
+ } catch (Exception ex) {
+ LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+ return;
+ }
+ LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+ //remove group
+ GroupEntity groupEntity = null;
+ try {
+ groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+ GroupTypes.GroupAll, null);
+ LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
+ mdsalManager.removeGroup(groupEntity);
+ } catch (Exception ex) {
+ LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
+ return;
+ }
+ LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
+ }*/
+}
\ 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.natservice.internal;
+
+import java.util.concurrent.BlockingQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EventDispatcher implements Runnable {
+ private BlockingQueue<NAPTEntryEvent> eventQueue;
+ private NaptEventHandler naptEventHandler;
+ private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
+
+ EventDispatcher(BlockingQueue<NAPTEntryEvent> eventQueue, NaptEventHandler naptEventHandler){
+ this.eventQueue = eventQueue;
+ this.naptEventHandler = naptEventHandler;
+ }
+
+ public void addNaptEvent(NAPTEntryEvent naptEntryEvent){
+ this.eventQueue.add(naptEntryEvent);
+ }
+
+ public void run(){
+ while(true) {
+ try {
+ NAPTEntryEvent event = eventQueue.take();
+ naptEventHandler.handleEvent(event);
+ } catch (InterruptedException e) {
+ LOG.error("EventDispatcher : Error in handling the event queue : ", e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+}
--- /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.natservice.internal;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+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.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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import com.google.common.base.Optional;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.ArrayList;
+
+
+public class ExternalNetworkListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<Networks> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+ private IMdsalApiManager mdsalManager;
+
+ public ExternalNetworkListener (final DataBroker db) {
+ super(Networks.class);
+ broker = db;
+ //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("ExternalNetwork Listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), ExternalNetworkListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("External Network DataChange listener registration fail!", e);
+ throw new IllegalStateException("External Network registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Networks> getWildCardPath() {
+ return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ @Override
+ protected void add(final InstanceIdentifier<Networks> identifier,
+ final Networks nw) {
+ LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
+ processExternalNwAdd(identifier, nw);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Networks> identifier, Networks nw) {
+ LOG.trace("External Network remove mapping method - key: " + identifier + ", value=" + nw );
+ processExternalNwDel(identifier, nw);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
+ LOG.trace("External Network update mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
+ //check if a new router has been added or an already existing router has been deleted from the external nw to router association
+ List<Uuid> oldRtrs = original.getRouterIds();
+ List<Uuid> newRtrs = update.getRouterIds();
+ if (oldRtrs != newRtrs) {
+ //handle both addition and removal of routers
+ for (Uuid rtr : newRtrs) {
+ if (oldRtrs.contains(rtr)) {
+ oldRtrs.remove(rtr);
+ } else {
+ // new router case
+ //Routers added need to have the corresponding default Fib entry added to the switches in the router
+ String routerId = rtr.getValue();
+ addOrDelDefFibRouteToSNAT(routerId, true);
+
+ }
+ }
+
+ //Routers removed need to have the corresponding default Fib entry removed from the switches in the router
+ for (Uuid rtr : oldRtrs) {
+ String routerId = rtr.getValue();
+ addOrDelDefFibRouteToSNAT(routerId, false);
+ }
+ }
+ }
+
+ private void processExternalNwAdd(final InstanceIdentifier<Networks> identifier,
+ final Networks network) {
+ LOG.trace("Add event - key: {}, value: {}", identifier, network);
+ List<Uuid> routerList = network.getRouterIds();
+
+ if(routerList == null) {
+ LOG.debug("No routers associated with external network {}", identifier);
+ return;
+ }
+
+ for(Uuid router: routerList) {
+ String routerId = router.getValue();
+ addOrDelDefFibRouteToSNAT(routerId, true);
+ }
+ }
+
+ private void processExternalNwDel(final InstanceIdentifier<Networks> identifier,
+ final Networks network) {
+ LOG.trace("Add event - key: {}, value: {}", identifier, network);
+ List<Uuid> routerList = network.getRouterIds();
+
+ for(Uuid router: routerList) {
+ String routerId = router.getValue();
+ addOrDelDefFibRouteToSNAT(routerId, false);
+ }
+ }
+
+ private void addOrDelDefFibRouteToSNAT(String routerId, boolean create) {
+ //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
+ InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerId);
+ Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (vpnInstOp.isPresent()) {
+ List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
+ for (VpnToDpnList dpn : dpnListInVpn) {
+ BigInteger dpnId = dpn.getDpnId();
+ long vpnId = NatUtil.readVpnId(broker, vpnInstOp.get().getVrfId());
+ if (create == true) {
+ installDefNATRouteInDPN(dpnId, vpnId);
+ } else {
+ removeDefNATRouteInDPN(dpnId, vpnId);
+ }
+ }
+ }
+ }
+
+ private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
+
+ InetAddress defaultIP = null;
+
+ try {
+ defaultIP = InetAddress.getByName("0.0.0.0");
+
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
+ return null;
+ }
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ //add match for default route "0.0.0.0/0"
+ //matches.add(new MatchInfo(MatchFieldType.ipv4_src, new long[] {
+ // NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+ //add match for vrfid
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.L3_FIB_TABLE, defaultIP);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+
+
+ }
+
+ private void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ private void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.removeFlow(flowEntity);
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.vpnservice.natservice.internal;\r
+\r
+import com.google.common.base.Optional;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;\r
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;\r
+import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
+import org.opendaylight.yangtools.yang.common.RpcResult;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import java.math.BigInteger;\r
+import java.util.List;\r
+import java.util.concurrent.ExecutionException;\r
+import java.util.concurrent.Future;\r
+\r
+import org.opendaylight.bgpmanager.api.IBgpManager;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;\r
+\r
+/**\r
+ * Created by ESUMAMS on 1/21/2016.\r
+ */\r
+public class ExternalNetworksChangeListener extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener>\r
+{\r
+ private static final Logger LOG = LoggerFactory.getLogger( ExternalNetworksChangeListener.class);\r
+\r
+ private ListenerRegistration<DataChangeListener> listenerRegistration;\r
+ private final DataBroker dataBroker;\r
+ private IMdsalApiManager mdsalManager;\r
+ //private VpnFloatingIpHandler vpnFloatingIpHandler;\r
+ private FloatingIPListener floatingIpListener;\r
+ private ExternalRoutersListener externalRouterListener;\r
+ private OdlInterfaceRpcService interfaceManager;\r
+ private NaptManager naptManager;\r
+\r
+ private IBgpManager bgpManager;\r
+ private VpnRpcService vpnService;\r
+ private FibRpcService fibService;\r
+\r
+\r
+ private ExternalRoutersListener externalRoutersListener;\r
+\r
+ void setMdsalManager(IMdsalApiManager mdsalManager) {\r
+ this.mdsalManager = mdsalManager;\r
+ }\r
+\r
+ void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {\r
+ this.interfaceManager = interfaceManager;\r
+ }\r
+\r
+ void setFloatingIpListener(FloatingIPListener floatingIpListener) {\r
+ this.floatingIpListener = floatingIpListener;\r
+ }\r
+\r
+ void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {\r
+ this.externalRouterListener = externalRoutersListener;\r
+ }\r
+\r
+ public void setBgpManager(IBgpManager bgpManager) {\r
+ this.bgpManager = bgpManager;\r
+ }\r
+\r
+ public void setNaptManager(NaptManager naptManager) {\r
+ this.naptManager = naptManager;\r
+ }\r
+\r
+ public void setVpnService(VpnRpcService vpnService) {\r
+ this.vpnService = vpnService;\r
+ }\r
+\r
+ public void setFibService(FibRpcService fibService) {\r
+ this.fibService = fibService;\r
+ }\r
+\r
+ public void setListenerRegistration(ListenerRegistration<DataChangeListener> listenerRegistration) {\r
+ this.listenerRegistration = listenerRegistration;\r
+ }\r
+\r
+ public ExternalNetworksChangeListener(final DataBroker dataBroker ) {\r
+ super( Networks.class, ExternalNetworksChangeListener.class );\r
+ this.dataBroker = dataBroker;\r
+ }\r
+\r
+\r
+ protected InstanceIdentifier<Networks> getWildCardPath() {\r
+ return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);\r
+ }\r
+\r
+\r
+ @Override\r
+ protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {\r
+\r
+ }\r
+\r
+ @Override\r
+ protected ExternalNetworksChangeListener getDataTreeChangeListener() {\r
+ return ExternalNetworksChangeListener.this;\r
+ }\r
+\r
+ @Override\r
+ protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {\r
+ if( identifier == null || networks == null || networks.getRouterIds().isEmpty() ) {\r
+ LOG.info( "ExternalNetworksChangeListener:remove:: returning without processing since networks/identifier is null" );\r
+ return;\r
+ }\r
+\r
+ for( Uuid routerId: networks.getRouterIds() ) {\r
+ String routerName = routerId.toString();\r
+\r
+ InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =\r
+ getRouterToNaptSwitchInstanceIdentifier( routerName);\r
+\r
+ MDSALUtil.syncDelete( dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier );\r
+\r
+ LOG.debug( "ExternalNetworksChangeListener:delete:: successful deletion of data in napt-switches container" );\r
+ }\r
+ }\r
+\r
+ private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier( String routerName ) {\r
+\r
+ return InstanceIdentifier.builder( NaptSwitches.class )\r
+ .child( RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();\r
+\r
+ }\r
+\r
+ public void close() throws Exception {\r
+ if (listenerRegistration != null) {\r
+ try {\r
+ listenerRegistration.close();\r
+ }\r
+ catch (final Exception e) {\r
+ LOG.error("Error when cleaning up ExternalNetworksChangeListener.", e);\r
+ }\r
+\r
+ listenerRegistration = null;\r
+ }\r
+ LOG.debug("ExternalNetworksChangeListener Closed");\r
+ }\r
+\r
+\r
+ @Override\r
+ protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {\r
+ //Check for VPN disassociation\r
+ Uuid originalVpn = original.getVpnid();\r
+ Uuid updatedVpn = update.getVpnid();\r
+ if(originalVpn == null && updatedVpn != null) {\r
+ //external network is dis-associated from L3VPN instance\r
+ associateExternalNetworkWithVPN(update);\r
+ } else if(originalVpn != null && updatedVpn == null) {\r
+ //external network is associated with vpn\r
+ disassociateExternalNetworkFromVPN(update, originalVpn.getValue());\r
+ //Remove the SNAT entries\r
+ removeSnatEntries(original, original.getId());\r
+ }\r
+ }\r
+\r
+ private void removeSnatEntries(Networks original, Uuid networkUuid) {\r
+ List<Uuid> routerUuids = original.getRouterIds();\r
+ for (Uuid routerUuid : routerUuids) {\r
+ Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());\r
+ if (routerId == NatConstants.INVALID_ID) {\r
+ LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerUuid.getValue());\r
+ return;\r
+ }\r
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);\r
+ externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps, false, original.getVpnid().getValue());\r
+ }\r
+ }\r
+\r
+ private void associateExternalNetworkWithVPN(Networks network) {\r
+ List<Uuid> routerIds = network.getRouterIds();\r
+ for(Uuid routerId : routerIds) {\r
+ //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+\r
+ InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
+ Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
+ if(!optRouterPorts.isPresent()) {\r
+ LOG.debug("Could not read Router Ports data object with id: {} to handle associate ext nw {}", routerId, network.getId());\r
+ continue;\r
+ }\r
+ RouterPorts routerPorts = optRouterPorts.get();\r
+ List<Ports> interfaces = routerPorts.getPorts();\r
+ for(Ports port : interfaces) {\r
+ String portName = port.getPortName();\r
+ BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
+ if(dpnId.equals(BigInteger.ZERO)) {\r
+ LOG.debug("DPN not found for {}, skip handling of ext nw {} association", portName, network.getId());\r
+ continue;\r
+ }\r
+ List<IpMapping> ipMapping = port.getIpMapping();\r
+ for(IpMapping ipMap : ipMapping) {\r
+ String externalIp = ipMap.getExternalIp();\r
+ //remove all VPN related entries\r
+ floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
+ }\r
+ }\r
+ }\r
+\r
+ // SNAT\r
+ for(Uuid routerId : routerIds) {\r
+ LOG.debug("NAT Service : associateExternalNetworkWithVPN() for routerId {}", routerId);\r
+ Uuid networkId = network.getId();\r
+ if(networkId == null) {\r
+ LOG.error("NAT Service : networkId is null for the router ID {}", routerId);\r
+ return;\r
+ }\r
+ final String vpnName = network.getVpnid().getValue();\r
+ if(vpnName == null) {\r
+ LOG.error("NAT Service : No VPN associated with ext nw {} for router {}", networkId, routerId);\r
+ return;\r
+ }\r
+\r
+ BigInteger dpnId = new BigInteger("0");\r
+ InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());\r
+ Optional<RouterToNaptSwitch> rtrToNapt = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch );\r
+ if(rtrToNapt.isPresent()) {\r
+ dpnId = rtrToNapt.get().getPrimarySwitchId();\r
+ }\r
+ LOG.debug("NAT Service : got primarySwitch as dpnId{} ", dpnId);\r
+\r
+ Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+ InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder =\r
+ InstanceIdentifier.builder(IntextIpMap.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerIdentifier));\r
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> id = idBuilder.build();\r
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);\r
+ if (ipMapping.isPresent()) {\r
+ List<IpMap> ipMaps = ipMapping.get().getIpMap();\r
+ for (IpMap ipMap : ipMaps) {\r
+ String externalIp = ipMap.getExternalIp();\r
+ LOG.debug("NAT Service : got externalIp as {}", externalIp);\r
+ LOG.debug("NAT Service : About to call advToBgpAndInstallFibAndTsFlows for dpnId {}, vpnName {} and externalIp {}", dpnId, vpnName, externalIp);\r
+ externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);\r
+ }\r
+ } else {\r
+ LOG.warn("NAT Service : No ipMapping present fot the routerId {}", routerId);\r
+ }\r
+\r
+ long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
+ // Install 47 entry to point to 21\r
+ if(vpnId != -1) {\r
+ LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for donId {} and vpnId {}", dpnId, vpnId);\r
+ externalRouterListener.installNaptPfibEntry(dpnId, vpnId);\r
+ }\r
+\r
+ }\r
+\r
+ }\r
+\r
+ private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {\r
+ List<Uuid> routerIds = network.getRouterIds();\r
+\r
+ //long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
+ for(Uuid routerId : routerIds) {\r
+ //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
+\r
+ InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
+ Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
+ if(!optRouterPorts.isPresent()) {\r
+ LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate ext nw {}", routerId, network.getId());\r
+ continue;\r
+ }\r
+ RouterPorts routerPorts = optRouterPorts.get();\r
+ List<Ports> interfaces = routerPorts.getPorts();\r
+ for(Ports port : interfaces) {\r
+ String portName = port.getPortName();\r
+ BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
+ if(dpnId.equals(BigInteger.ZERO)) {\r
+ LOG.debug("DPN not found for {}, skip handling of ext nw {} disassociation", portName, network.getId());\r
+ continue;\r
+ }\r
+ List<IpMapping> ipMapping = port.getIpMapping();\r
+ for(IpMapping ipMap : ipMapping) {\r
+ String externalIp = ipMap.getExternalIp();\r
+ floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {\r
+ BigInteger nodeId = BigInteger.ZERO;\r
+ try {\r
+ GetDpidFromInterfaceInput\r
+ dpIdInput =\r
+ new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();\r
+ Future<RpcResult<GetDpidFromInterfaceOutput>>\r
+ dpIdOutput =\r
+ interfaceManagerRpcService.getDpidFromInterface(dpIdInput);\r
+ RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();\r
+ if (dpIdResult.isSuccessful()) {\r
+ nodeId = dpIdResult.getResult().getDpid();\r
+ } else {\r
+ LOG.error("Could not retrieve DPN Id for interface {}", ifName);\r
+ }\r
+ } catch (InterruptedException | ExecutionException e) {\r
+ LOG.error("Exception when getting dpn for interface {}", ifName, e);\r
+ }\r
+ return nodeId;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*
+ * Copyright (c) 2015 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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
+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.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
+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.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+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.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.list.Action;
+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.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+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.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+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.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+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.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.RouterIdName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+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.Optional;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Created by EYUGSAR on 2/20/2016.
+ */
+
+public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener>{
+
+ private static final Logger LOG = LoggerFactory.getLogger( ExternalRoutersListener.class);
+ private static long label;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker dataBroker;
+ private IMdsalApiManager mdsalManager;
+ private ItmRpcService itmManager;
+ private OdlInterfaceRpcService interfaceManager;
+ private IdManagerService idManager;
+ private NaptManager naptManager;
+ private NAPTSwitchSelector naptSwitchSelector;
+ private IBgpManager bgpManager;
+ private VpnRpcService vpnService;
+ private FibRpcService fibService;
+ private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+ private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+ static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
+ private NaptEventHandler naptEventHandler;
+ private NaptPacketInHandler naptPacketInHandler;
+
+ public void setNaptEventHandler(NaptEventHandler naptEventHandler) {
+ this.naptEventHandler = naptEventHandler;
+ }
+
+ public void setNaptPacketInHandler(NaptPacketInHandler naptPacketInHandler) {
+ this.naptPacketInHandler = naptPacketInHandler;
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setItmManager(ItmRpcService itmManager) {
+ this.itmManager = itmManager;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ createGroupIdPool();
+ }
+
+ void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+ this.defaultRouteProgrammer = defaultRouteProgrammer;
+ }
+
+
+ public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
+ public void setNaptManager(NaptManager naptManager) {
+ this.naptManager = naptManager;
+ }
+
+ public void setNaptSwitchSelector(NAPTSwitchSelector naptSwitchSelector) {
+ this.naptSwitchSelector = naptSwitchSelector;
+ }
+
+ public void setBgpManager(IBgpManager bgpManager) {
+ this.bgpManager = bgpManager;
+ }
+
+ public void setVpnService(VpnRpcService vpnService) {
+ this.vpnService = vpnService;
+ }
+
+ public void setFibService(FibRpcService fibService) {
+ this.fibService = fibService;
+ }
+
+ public ExternalRoutersListener(DataBroker dataBroker )
+ {
+ super( Routers.class, ExternalRoutersListener.class );
+ this.dataBroker = dataBroker;
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+
+ LOG.info( "NAT Service : Add external router event for {}", routers.getRouterName() );
+
+ LOG.info("Installing NAT default route on all dpns part of router {}", routers.getRouterName());
+ addOrDelDefFibRouteToSNAT(routers.getRouterName(), true);
+
+ if( !routers.isEnableSnat()) {
+ LOG.info( "SNAT is disabled for external router {} ", routers.getRouterName());
+ return;
+ }
+
+ // Populate the router-id-name container
+ String routerName = routers.getRouterName();
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(routerId)).setRouterId(routerId).setRouterName(routerName).build();
+ MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(routerId), rtrs);
+
+ handleEnableSnat(routers);
+ }
+
+ public void handleEnableSnat(Routers routers){
+ String routerName = routers.getRouterName();
+ LOG.info("NAT Service : Handling SNAT for router {}", routerName);
+
+ long segmentId = NatUtil.getVpnId(dataBroker, routerName);
+ naptManager.initialiseExternalCounter(routers, segmentId);
+
+ // Allocate Primary Napt Switch for this router
+ BigInteger primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+ LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
+ if(primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)){
+ LOG.error("NAT Service : Unable to to select the primary NAPT switch");
+ }
+ LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}", primarySwitchId, routerName);
+
+ long bgpVpnId = NatConstants.INVALID_ID;
+ Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+ if(bgpVpnUuid != null){
+ bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+ }
+ if(bgpVpnId != NatConstants.INVALID_ID){
+
+ String bgpVpnName = bgpVpnUuid.getValue();
+ LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
+ RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
+ MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
+
+ long groupId = 0;
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ if(switches == null){
+ LOG.error("NAT Service : No DPNS associated for the router {}", routerName);
+ return;
+ }
+ for (BigInteger dpnId : switches) {
+ // Handle switches and NAPT switches separately
+ if (!dpnId.equals(primarySwitchId)) {
+ LOG.debug("NAT Service : Install group in Ordinary switch {}", dpnId);
+ List<BucketInfo> bucketInfoForNonNaptSwitches = getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
+ groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
+ }else{
+ LOG.debug("NAT Service : Install group in Primary switch {}", dpnId);
+ List<BucketInfo> bucketInfoForNaptSwitches = getBucketInfoForPrimaryNaptSwitch();
+ groupId = installGroup(dpnId, routerName, bucketInfoForNaptSwitches);
+
+ Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
+ //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+ if(vpnId != null && vpnId != NatConstants.INVALID_ID) {
+ installNaptPfibEntry(dpnId, vpnId);
+ }
+
+ }
+ installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, bgpVpnId, routerId);
+ }
+ }else {
+ // write metadata and punt
+ installOutboundMissEntry(routerName, primarySwitchId);
+ // Now install entries in SNAT tables to point to Primary for each router
+ List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+ for (BigInteger dpnId : switches) {
+ // Handle switches and NAPT switches separately
+ if (!dpnId.equals(primarySwitchId)) {
+ LOG.debug("NAT Service : Handle Ordinary switch");
+ handleSwitches(dpnId, routerName, primarySwitchId);
+ } else {
+ LOG.debug("NAT Service : Handle NAPT switch");
+ handlePrimaryNaptSwitch(dpnId, routerName, primarySwitchId);
+ }
+ }
+ }
+
+ // call registerMapping Api
+ LOG.debug("NAT Service : Preparing to call registerMapping for routerName {} and Id {}", routerName, segmentId);
+
+ List<Uuid> subnetList = null;
+ List<String> externalIps = null;
+
+ InstanceIdentifier<Routers> id = InstanceIdentifier
+ .builder(ExtRouters.class)
+ .child(Routers.class, new RoutersKey(routerName))
+ .build();
+
+ Optional<Routers> extRouters = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+
+ if(extRouters.isPresent())
+ {
+ LOG.debug("NAT Service : Fetching values from extRouters model");
+ Routers routerEntry= extRouters.get();
+ subnetList = routerEntry.getSubnetIds();
+ externalIps = routerEntry.getExternalIps();
+ int counter = 0;
+ int extIpCounter = externalIps.size();
+ LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
+ for(Uuid subnet : subnetList) {
+ LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
+ InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
+ .builder(Subnetmaps.class)
+ .child(Subnetmap.class, new SubnetmapKey(subnet))
+ .build();
+ Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
+ if(sn.isPresent()){
+ // subnets
+ Subnetmap subnetmapEntry = sn.get();
+ String subnetString = subnetmapEntry.getSubnetIp();
+ String[] subnetSplit = subnetString.split("/");
+ String subnetIp = subnetSplit[0];
+ String subnetPrefix = "0";
+ if(subnetSplit.length == 2) {
+ subnetPrefix = subnetSplit[1];
+ }
+ IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
+ LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}", subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
+ //externalIps
+ LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
+ if(extIpCounter != 0) {
+ if(counter < extIpCounter) {
+ String[] IpSplit = externalIps.get(counter).split("/");
+ String externalIp = IpSplit[0];
+ String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+ if(IpSplit.length==2) {
+ extPrefix = IpSplit[1];
+ }
+ IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
+ LOG.debug("NAT Service : externalIp is {} and extPrefix is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
+ naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
+ LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
+ externalIp, extPrefix);
+
+ String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
+ LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+ handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
+
+ } else {
+ counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
+ LOG.debug("NAT Service : Counter on externalIps got reset");
+ String[] IpSplit = externalIps.get(counter).split("/");
+ String externalIp = IpSplit[0];
+ String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+ if(IpSplit.length==2) {
+ extPrefix = IpSplit[1];
+ }
+ IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
+ LOG.debug("NAT Service : externalIp is {} and extPrefix is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
+ naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
+ LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
+ externalIp, extPrefix);
+
+ String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
+ LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+ handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
+
+ }
+ }
+ counter++;
+ LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
+
+ } else {
+ LOG.warn("NAT Service : No internal subnets present in extRouters Model");
+ }
+ }
+ }
+
+ LOG.info("NAT Service : handleEnableSnat() Exit");
+ }
+
+ private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
+ //Check if BGP VPN exists. If exists then invoke the new method.
+ long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+ if(bgpVpnId != NatConstants.INVALID_ID) {
+ addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, create);
+ return;
+ }
+
+ //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
+ addOrDelDefaultFibRouteForSNAT(routerName, create);
+/* InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerName);
+ Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ if (vpnInstOp.isPresent()) {
+ addOrDelDefaultFibRouteForSNAT(routerName, create);
+ } *//*else {
+ //Check if this router is associated with any external VPN
+ LOG.debug("Checking if router {} is associated with BGP VPN", routerName);
+ Uuid vpnId = NatUtil.getVpnForRouter(dataBroker, routerName);
+ if(vpnId != null) {
+ String vpnName = vpnId.getValue();
+ LOG.debug("Router {} is associated with VPN {}", routerName, vpnName);
+ InstanceIdentifier<VpnInstanceOpDataEntry> vid = NatUtil.getVpnInstanceOpDataIdentifier(vpnName);
+ vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vid);
+ if (vpnInstOp.isPresent()) {
+ addOrDelDefaultFibRouteForSNAT(routerName, vpnInstOp.get(), create);
+ }
+ }
+ }*/
+ }
+
+ private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
+/*
+ List<VpnToDpnList> dpnListInVpn = vpnInstOp.getVpnToDpnList();
+ List<BigInteger> switches = new ArrayList<>();
+ if(dpnListInVpn == null || dpnListInVpn.isEmpty()) {
+ LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+ switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ if(switches == null || switches.isEmpty()){
+ LOG.error("NAT Service : addOrDelDefaultFibRouteForSNAT : NO SWITCHES ARE PART OF ROUTER {}", routerName);
+ return;
+ }
+ }else{
+ for (VpnToDpnList dpn : dpnListInVpn) {
+ switches.add(dpn.getDpnId());
+ }
+ }
+*/
+ List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+ long routerId = NatUtil.readVpnId(dataBroker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
+ return;
+ }
+ for (BigInteger dpnId : switches) {
+ if (create == true) {
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
+ } else {
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
+ }
+ }
+ }
+
+ private void addOrDelDefaultFibRouteForSNATWIthBgpVpn(String routerName, long bgpVpnId, boolean create) {
+ List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ if(dpnIds == null || dpnIds.isEmpty()) {
+ LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
+ return;
+ }
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ for (BigInteger dpnId : dpnIds) {
+ if (create == true) {
+ if(bgpVpnId != NatConstants.INVALID_ID) {
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
+ }else{
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
+ }
+ } else {
+ if(bgpVpnId != NatConstants.INVALID_ID) {
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
+ }else{
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
+ }
+ }
+ }
+ }
+
+ public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
+ {
+ ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+ Optional<T> result = Optional.absent();
+ try
+ {
+ result = tx.read(datastoreType, path).get();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ return result;
+ }
+
+ public void close() throws Exception
+ {
+ if (listenerRegistration != null)
+ {
+ try
+ {
+ listenerRegistration.close();
+ }
+ catch (final Exception e)
+ {
+ LOG.error("Error when cleaning up ExternalRoutersListener.", e);
+ }
+
+ listenerRegistration = null;
+ }
+ LOG.debug("ExternalRoutersListener Closed");
+ }
+
+ protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
+ if(routerId != NatConstants.INVALID_ID) {
+ LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
+ createOutboundTblEntry(primarySwitchId, routerId);
+ } else {
+ LOG.error("NAT Service : Unable to fetch Router Id for RouterName {}, failed to createAndInstallMissEntry", routerName);
+ }
+ }
+
+ public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
+ return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ public BigInteger getCookieOutboundFlow(long routerId) {
+ return NatConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
+ BigInteger.valueOf(routerId));
+ }
+
+ protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
+ LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+ BigInteger cookie = getCookieOutboundFlow(routerId);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ 5, flowRef, 0, 0,
+ cookie, matches, instructions);
+ LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
+ return flowEntity;
+ }
+
+ public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
+ LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
+ FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
+ LOG.debug("NAT Service : Installing flow {}", flowEntity);
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+ RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
+ try {
+ Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+ .setSourceDpid(srcDpId)
+ .setDestinationDpid(dstDpId)
+// .setTunnelType(tunType)
+ .build());
+ rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ tunType = TunnelTypeGre.class ;
+ result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+ .setSourceDpid(srcDpId)
+ .setDestinationDpid(dstDpId)
+// .setTunnelType(tunType)
+ .build());
+ rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ } catch (InterruptedException | ExecutionException | NullPointerException e) {
+ LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstDpId);
+ }
+
+ return null;
+ }
+
+ protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
+ LOG.debug("NAT Service : getEgressActionsForInterface called for interface {}", ifName);
+ List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
+ try {
+ Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+ interfaceManager.getEgressActionsForInterface(
+ new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
+ RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
+ } else {
+ List<Action> actions =
+ rpcResult.getResult().getAction();
+ for (Action action : actions) {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
+ if (actionClass instanceof OutputActionCase) {
+ listActionInfo.add(new ActionInfo(ActionType.output,
+ new String[] {((OutputActionCase)actionClass).getOutputAction()
+ .getOutputNodeConnector().getValue()}));
+ } else if (actionClass instanceof PushVlanActionCase) {
+ listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
+ } else if (actionClass instanceof SetFieldCase) {
+ if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
+ int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
+ listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
+ new String[] { Long.toString(vlanVid) }));
+ }
+ }
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when egress actions for interface {}", ifName, e);
+ }
+ return listActionInfo;
+ }
+
+ protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+ LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId, bucketInfo.get(0));
+ // Install the select group
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+ LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
+ mdsalManager.installGroup(groupEntity);
+ // Install miss entry pointing to group
+ FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo){
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+ LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
+ mdsalManager.installGroup(groupEntity);
+ return groupId;
+ }
+
+ public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
+
+ LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}", dpId, routerName, groupId );
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+ ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+ BigInteger.valueOf(routerId)}) ;
+ actionsInfo.add(actionSetField);
+ LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
+ actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+ String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+
+ LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
+ return flowEntity;
+ }
+
+ // TODO : Replace this with ITM Rpc once its available with full functionality
+ protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
+ LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}", dpnId, routerName);
+ FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
+ mdsalManager.installFlow(flowEntity);
+
+ }
+
+ private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
+
+ BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {routerId }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
+ { routerId, MetaDataUtil.METADATA_MASK_VRFID }));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
+ { NatConstants.OUTBOUND_NAPT_TABLE }));
+ String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_TS_TABLE, matches, instructions);
+ return flowEntity;
+ }
+
+ public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
+ return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+ return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ private String getGroupIdKey(String routerName){
+ String groupIdKey = new String("snatmiss." + routerName);
+ return groupIdKey;
+ }
+
+ protected long createGroupId(String groupIdKey) {
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+ .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
+ .build();
+ try {
+ Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+ RpcResult<AllocateIdOutput> rpcResult = result.get();
+ return rpcResult.getResult().getIdValue();
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ LOG.trace("",e);
+ }
+ return 0;
+ }
+
+ protected void createGroupIdPool() {
+ CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+ .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
+ .setLow(NatConstants.SNAT_ID_LOW_VALUE)
+ .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
+ .build();
+ try {
+ Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+ if ((result != null) && (result.get().isSuccessful())) {
+ LOG.debug("NAT Service : Created GroupIdPool");
+ } else {
+ LOG.error("NAT Service : Unable to create GroupIdPool");
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to create PortPool for NAPT Service",e);
+ }
+ }
+
+ protected void handleSwitches (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
+ LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+ String ifNamePrimary = getTunnelInterfaceName( dpnId, primarySwitchId);
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+ if(ifNamePrimary != null) {
+ LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
+ listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+ }
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+
+ listBucketInfo.add(0, bucketPrimary);
+ installSnatMissEntry(dpnId, listBucketInfo, routerName);
+
+ }
+ List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId, BigInteger primarySwitchId, String routerName) {
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+ String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
+ List<BucketInfo> listBucketInfo = new ArrayList<>();
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+ if (ifNamePrimary != null) {
+ LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
+ listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+ }
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+
+ listBucketInfo.add(0, bucketPrimary);
+ return listBucketInfo;
+ }
+ protected void handlePrimaryNaptSwitch (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
+
+ /*
+ * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
+ */
+
+ LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
+
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
+ listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(0, bucketPrimary);
+
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+ installSnatMissEntry(dpnId, listBucketInfo, routerName);
+ installTerminatingServiceTblEntry(dpnId, routerName);
+ //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
+ installNaptPfibEntry(dpnId, routerId);
+ Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
+ //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+ if(vpnId != null && vpnId != NatConstants.INVALID_ID) {
+ installNaptPfibEntry(dpnId, vpnId);
+ }
+ }
+
+ List<BucketInfo> getBucketInfoForPrimaryNaptSwitch(){
+ List<BucketInfo> listBucketInfo = new ArrayList<>();
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
+ listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(0, bucketPrimary);
+ return listBucketInfo;
+ }
+
+ public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
+ LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
+ FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
+ mdsalManager.installFlow(naptPfibFlowEntity);
+ }
+
+ public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
+
+ LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId );
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+ ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+ listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+ instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+
+ String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+
+ LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
+ return flowEntity;
+ }
+
+ private void handleSnatReverseTraffic(BigInteger dpnId, long routerId, String externalIp) {
+ LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+ if(networkId == null) {
+ LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
+ return;
+ }
+ final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+ if(vpnName == null) {
+ LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip configuration {} in router {}",
+ networkId, externalIp, routerId);
+ return;
+ }
+ advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+ LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
+ }
+
+ public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName, final long routerId, final String externalIp,
+ VpnRpcService vpnService, final FibRpcService fibService, final IBgpManager bgpManager, final DataBroker dataBroker,
+ final Logger log){
+ LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} and externalIp {}", dpnId, tableId, vpnName, externalIp);
+ //Generate VPN label for the external IP
+ GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+ Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
+
+ //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
+ ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
+
+ @Override
+ public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
+ if (result.isSuccessful()) {
+ LOG.debug("NAT Service : inside apply with result success");
+ GenerateVpnLabelOutput output = result.getResult();
+ long label = output.getLabel();
+
+ //Inform BGP
+ String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+ String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+ NatUtil.addPrefixToBGP(bgpManager, rd, externalIp, nextHopIp, label, log);
+
+ //Get IPMaps from the DB for the router ID
+ List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
+ if (dbIpMaps != null) {
+ for (IpMap dbIpMap : dbIpMaps) {
+ String dbExternalIp = dbIpMap.getExternalIp();
+ //Select the IPMap, whose external IP is the IP for which FIB is installed
+ if (externalIp.equals(dbExternalIp)) {
+ String dbInternalIp = dbIpMap.getInternalIp();
+ IpMapKey dbIpMapKey = dbIpMap.getKey();
+ LOG.debug("Setting label {} for internalIp {} and externalIp {}", label, dbInternalIp, externalIp);
+ IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp).setExternalIp(dbExternalIp).setLabel(label).build();
+ MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
+ break;
+ }
+ }
+ } else {
+ LOG.error("NAT Service : Failed to write label {} for externalIp {} for routerId {} in DS", label, externalIp, routerId);
+ }
+
+ //Install custom FIB routes
+ List<Instruction> customInstructions = new ArrayList<>();
+ customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(0));
+ makeTunnelTableEntry(dpnId, label, customInstructions);
+ makeLFibTableEntry(dpnId, label, tableId);
+
+ CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId)
+ .setIpAddress(externalIp).setServiceId(label).setInstruction(customInstructions).build();
+ Future<RpcResult<Void>> future = fibService.createFibEntry(input);
+ return JdkFutureAdapters.listenInPoolThread(future);
+ } else {
+ LOG.error("NAT Service : inside apply with result failed");
+ String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ }
+ });
+
+ Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
+
+ @Override
+ public void onFailure(Throwable error) {
+ log.error("NAT Service : Error in generate label or fib install process", error);
+ }
+
+ @Override
+ public void onSuccess(RpcResult<Void> result) {
+ if (result.isSuccessful()) {
+ log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
+ } else {
+ log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
+ }
+ }
+ });
+ }
+
+ private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[]{0x8847L}));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ List<Instruction> instructions = new ArrayList<Instruction>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+ Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
+ instructions.add(writeInstruction);
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
+
+ // Install the flow entry in L3_LFIB_TABLE
+ String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ 10, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+ mdsalManager.installFlow(dpId, flowEntity);
+
+ LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+ }
+
+ private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+ LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+ Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d", "TST Flow Entry ", serviceId),
+ 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
+
+ mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+ }
+
+ protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
+ InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
+ RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
+ return id;
+ }
+
+ private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+ return new StringBuilder(64).append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+ String routerName = original.getRouterName();
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ Uuid networkId = original.getNetworkId();
+
+ // Check if its update on SNAT flag
+ boolean originalSNATEnabled = original.isEnableSnat();
+ boolean updatedSNATEnabled = update.isEnableSnat();
+ LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag as {} and {}", originalSNATEnabled, updatedSNATEnabled);
+ if(originalSNATEnabled != updatedSNATEnabled) {
+ if(originalSNATEnabled) {
+ //SNAT disabled for the router
+ Uuid networkUuid = original.getNetworkId();
+ LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
+ return;
+ }
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+ handleDisableSnat(routerName, networkUuid, externalIps, false, null);
+ } else {
+ LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
+ handleEnableSnat(original);
+ }
+ }
+
+ //Check if the Update is on External IPs
+ LOG.debug("NAT Service : Checking if this is update on External IPs");
+ List<String> originalExternalIpsList = original.getExternalIps();
+ List<String> updatedExternalIpsList = update.getExternalIps();
+ Set<String> originalExternalIps = Sets.newHashSet(originalExternalIpsList);
+ Set<String> updatedExternalIps = Sets.newHashSet(updatedExternalIpsList);
+
+ //Check if the External IPs are added during the update.
+ SetView<String> addedExternalIps = Sets.difference(updatedExternalIps, originalExternalIps);
+ if(addedExternalIps.size() != 0) {
+ LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
+ for (String addedExternalIp : addedExternalIps) {
+ /*
+ 1) Do nothing in the IntExtIp model.
+ 2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
+ */
+ String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
+ String externalIp = externalIpParts[0];
+ String externalIpPrefix = externalIpParts[1];
+ String externalpStr = externalIp + "/" + externalIpPrefix;
+ LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the router ID {} in the ExternalIpsCounter model.",
+ externalpStr, routerId);
+ naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
+ }
+ LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
+ }
+
+ //Check if the External IPs are removed during the update.
+ SetView<String> removedExternalIps = Sets.difference(originalExternalIps, updatedExternalIps);
+ if(removedExternalIps.size() > 0) {
+ LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
+ List<String> removedExternalIpsAsList = new ArrayList<>();
+ for (String removedExternalIp : removedExternalIps) {
+ /*
+ 1) Remove the mappings in the IntExt IP model which has external IP.
+ 2) Remove the external IP in the ExternalCounter model.
+ 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least loaded external IP.
+ Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
+ 4) Increase the count of the allocated external IP by one.
+ 5) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
+ 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs and also from the model.
+ 7) Advertise to the BGP for removing the route for the removed external IPs.
+ */
+
+ String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
+ String externalIp = externalIpParts[0];
+ String externalIpPrefix = externalIpParts[1];
+ String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
+
+ LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS entries for removed external IP {}", externalIpAddrStr);
+ Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+ String vpnName = "";
+ if(vpnUuId != null){
+ vpnName = vpnUuId.getValue();
+ }
+ clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
+
+ LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
+ //Get the internal IPs which are associated to the removed external IPs
+ List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
+ List<String> removedInternalIps = new ArrayList<>();
+ for(IpMap ipMap : ipMaps){
+ if(ipMap.getExternalIp().equals(externalIpAddrStr)){
+ removedInternalIps.add(ipMap.getInternalIp());
+ }
+ }
+
+ LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
+ for(String removedInternalIp : removedInternalIps){
+ LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the router ID {} from the IntExtIP model",
+ removedInternalIp, routerId);
+ naptManager.removeFromIpMapDS(routerId, removedInternalIp);
+ }
+
+ LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the router ID {} from the ExternalIpsCounter model.",
+ externalIpAddrStr, routerId );
+ naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
+ removedExternalIpsAsList.add(externalIpAddrStr);
+
+ LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets whose external IPs were removed.");
+ for(String removedInternalIp : removedInternalIps) {
+ allocateExternalIp(dpnId, routerId, networkId, removedInternalIp);
+ }
+
+ LOG.debug("NAT Service : Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs.");
+ //Get the internalIP and internal Port which were associated to the removed external IP.
+ List<Integer> externalPorts = new ArrayList<>();
+ Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
+ InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
+ .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
+ Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
+ if (ipPortMapping.isPresent()) {
+ List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
+ for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+ ProtocolTypes protoType = intextIpProtocolType.getProtocol();
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+ for(IpPortMap ipPortMap : ipPortMaps){
+ IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+ if(ipPortExternal.getIpAddress().equals(externalIp)){
+ externalPorts.add(ipPortExternal.getPortNum());
+ List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
+ if(removedInternalIpPorts != null){
+ removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
+ protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
+ }else{
+ removedInternalIpPorts = new ArrayList<>();
+ removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
+ protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
+ }
+ }
+ }
+ }
+ }
+
+ //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP.
+ Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
+ Map<String, List<String>> internalIpPortMap = new HashMap<>();
+ for(Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts){
+ ProtocolTypes protocolType = (ProtocolTypes)protoTypesIntIpPort.getKey();
+ List<String> removedInternalIpPorts = (List<String>)protoTypesIntIpPort.getValue();
+ for(String removedInternalIpPort : removedInternalIpPorts){
+ //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP
+ naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
+ //Remove the IP port incomint packer map.
+ naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
+ String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
+ if(removedInternalIpPortParts.length == 2){
+ String removedInternalIp = removedInternalIpPortParts[0];
+ String removedInternalPort = removedInternalIpPortParts[1];
+ List<String> removedInternalPortsList = internalIpPortMap.get(removedInternalPort);
+ if (removedInternalPortsList != null){
+ removedInternalPortsList.add(removedInternalPort);
+ internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+ }else{
+ removedInternalPortsList = new ArrayList<>();
+ removedInternalPortsList.add(removedInternalPort);
+ internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+ }
+ }
+ }
+ }
+
+ // Delete the entry from SnatIntIpPortMap DS
+ Set<String> internalIps = internalIpPortMap.keySet();
+ for(String internalIp : internalIps){
+ LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the model SnatIntIpPortMap", internalIp);
+ naptManager.removeFromSnatIpPortDS(routerId, internalIp);
+ }
+
+ naptManager.removeNaptPortPool(externalIp);
+
+ LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed external IP {}", externalIp);
+ for(Integer externalPort : externalPorts) {
+ //Remove the NAPT translation entries from Inbound NAPT table
+ naptEventHandler.removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, externalIp, externalPort);
+ }
+
+ Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
+ for(Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
+ String internalIp = internalIpPort.getKey();
+ LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for the removed internal IP {}", internalIp);
+ List<String> internalPorts = internalIpPort.getValue();
+ for(String internalPort : internalPorts){
+ //Remove the NAPT translation entries from Outbound NAPT table
+ naptEventHandler.removeNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, Integer.valueOf(internalPort));
+ }
+ }
+ }
+ LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
+ }
+
+ //Check if its Update on subnets
+ LOG.debug("NAT Service : Checking if this is update on subnets");
+ List<Uuid> originalSubnetIdsList = original.getSubnetIds();
+ List<Uuid> updatedSubnetIdsList = update.getSubnetIds();
+ Set<Uuid> originalSubnetIds = Sets.newHashSet(originalSubnetIdsList);
+ Set<Uuid> updatedSubnetIds = Sets.newHashSet(updatedSubnetIdsList);
+ SetView<Uuid> addedSubnetIds = Sets.difference(updatedSubnetIds, originalSubnetIds);
+
+ //Check if the Subnet IDs are added during the update.
+ if(addedSubnetIds.size() != 0){
+ LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
+ for(Uuid addedSubnetId : addedSubnetIds){
+ /*
+ 1) Select the least loaded external IP for the subnet and store the mapping of the subnet IP and the external IP in the IntExtIp model.
+ 2) Increase the count of the selected external IP by one.
+ 3) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
+ */
+ String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
+ if(subnetIp != null) {
+ allocateExternalIp(dpnId, routerId, networkId, subnetIp);
+ }
+ }
+ LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
+ }
+
+ //Check if the Subnet IDs are removed during the update.
+ SetView<Uuid> removedSubnetIds = Sets.difference(originalSubnetIds, updatedSubnetIds);
+ if(removedSubnetIds.size() != 0){
+ LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
+ for(Uuid removedSubnetId : removedSubnetIds){
+ String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
+ if(subnetAddr != null){
+ /*
+ 1) Remove the subnet IP and the external IP in the IntExtIp map
+ 2) Decrease the count of the coresponding external IP by one.
+ 3) Advertise to the BGP for removing the routes of the corresponding external IP if its not allocated to any other internal IP.
+ */
+ LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and internal IP {}", routerId, subnetAddr[0]);
+ naptManager.removeFromIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
+ }
+ }
+ LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
+ }
+ }
+
+ private void allocateExternalIp(BigInteger dpnId, long routerId, Uuid networkId, String subnetIp){
+ String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
+ if (leastLoadedExtIpAddr != null) {
+ String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
+ String leastLoadedExtIp = externalIpParts[0];
+ String leastLoadedExtIpPrefix = externalIpParts[1];
+ String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
+ IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
+ String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
+ subnetIp = subnetIpParts[0];
+ String subnetIpPrefix = subnetIpParts[1];
+ IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
+ LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal IP {} and prefix {} -> external IP {} and prefix {}",
+ routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
+ naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
+
+
+ //Check if external IP is already assigned a route. (i.e. External IP is previously allocated to any of the subnets)
+ //If external IP is already assigned a route, (, do not re-advertise to the BGP
+ if(checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr)){
+ return;
+ }
+
+ //Re-advertise to the BGP for the external IP, which is allocated to the subnet for the first time and hence not having a route.
+ //Get the VPN Name using the network ID
+ final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+ if (vpnName != null) {
+ LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
+ advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId,
+ leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, vpnService, fibService, bgpManager, dataBroker, LOG);
+ }
+ }
+ }
+
+ private boolean checkExternalIpLabel(long routerId, String externalIp){
+ List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
+ for(IpMap ipMap : ipMaps){
+ if(ipMap.getExternalIp().equals(externalIp)){
+ if (ipMap.getLabel() != null){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+ LOG.trace("NAT Service : Router delete method");
+ {
+ /*
+ ROUTER DELETE SCENARIO
+ 1) Get the router ID from the event.
+ 2) Build the cookie information from the router ID.
+ 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
+ 4) Build the flow with the cookie value.
+ 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
+ 6) Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
+ 7) Get the list of external IP address maintained for the router ID.
+ 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
+ 9) Withdraw the corresponding routes from the BGP.
+ */
+
+ if (identifier == null || router == null) {
+ LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: returning without processing since routers is null");
+ return;
+ }
+
+ String routerName = router.getRouterName();
+ LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
+ addOrDelDefFibRouteToSNAT(routerName, false);
+ Uuid networkUuid = router.getNetworkId();
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
+ return;
+ }
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+ handleDisableSnat(routerName, networkUuid, externalIps, true, null);
+ }
+ }
+
+ public void handleDisableSnat(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
+ LOG.info("NAT Service : handleDisableSnat() Entry");
+ try {
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+ BigInteger naptSwitchDpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
+ if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)){
+ LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the router ID {} from RouterNaptSwitch model", routerId);
+ return;
+ }
+ removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
+ removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
+ try {
+ clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
+ } catch (Exception ex) {
+ LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
+ }
+
+ //Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained for the router ID.
+ LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the router ID {} in the DS", routerId);
+ naptManager.removeMapping(routerId);
+
+ if(routerFlag) {
+ removeNaptSwitch(routerName);
+ } else {
+ updateNaptSwitch(routerName, BigInteger.ZERO);
+ }
+
+ LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
+ naptManager.removeExternalCounter(routerId);
+ } catch (Exception ex) {
+ LOG.error("Exception while handling disableSNAT : {}", ex);
+ }
+ LOG.info("NAT Service : handleDisableSnat() Exit");
+ }
+
+ public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
+ LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
+ try {
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ BigInteger naptSwitchDpnId = null;
+ InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerName);
+ Optional<RouterToNaptSwitch> rtrToNapt = read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch);
+ if (rtrToNapt.isPresent()) {
+ naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
+ }
+ LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
+
+ removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
+ try {
+ clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
+ } catch (Exception ex) {
+ LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
+ }
+ } catch (Exception ex) {
+ LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
+ }
+ LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
+ }
+
+ public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+ RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
+ .setPrimarySwitchId(naptSwitchId).build();
+ try {
+ MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+ NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
+ } catch (Exception ex) {
+ LOG.error("Failed to write naptSwitch {} for router {} in ds",
+ naptSwitchId,routerName);
+ }
+ LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
+ naptSwitchId,routerName);
+ }
+
+ protected void removeNaptSwitch(String routerName){
+ // Remove router and switch from model
+ InstanceIdentifier<RouterToNaptSwitch> id = InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+ LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
+ MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ }
+
+ public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
+
+ LOG.debug("NAT Service : Remove NAPT flows from Active switch");
+ BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+
+ //Remove the PSNAT entry which forwards the packet to Terminating Service table
+ String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, routerName);
+ FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(pSNatFlowEntity);
+
+ //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
+
+ LOG.info("NAT Service : Remove the group {} for the active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
+ mdsalManager.removeGroup(pSNatGroupEntity);
+
+ //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
+ String tsFlowRef = getFlowRefTs(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
+ FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.TERMINATING_SERVICE_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(tsNatFlowEntity);
+
+ //Remove the Outbound flow entry which forwards the packet to FIB Table
+ String outboundNatFlowRef = getFlowRefOutbound(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+ FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(outboundNatFlowEntity);
+
+ //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
+ String natPfibFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, routerId);
+ FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(natPfibFlowEntity);
+
+ //Long vpnId = NatUtil.getVpnId(dataBroker, routerId); - This does not work since ext-routers is deleted already - no network info
+ //Get the VPN ID from the ExternalNetworks model
+ long vpnId = -1;
+ if( (vpnName == null) || (vpnName.isEmpty()) ) {
+ // ie called from router delete cases
+ Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+ LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
+ if(vpnUuid != null) {
+ vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+ LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId );
+ }
+ } else {
+ // ie called from disassociate vpn case
+ LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
+ vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
+ }
+
+ if(vpnId != NatConstants.INVALID_ID){
+ //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+ String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
+ FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
+ mdsalManager.removeFlow(natPfibVpnFlowEntity);
+ }
+
+ //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+ if(ipPortMapping == null){
+ LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+ return;
+ }
+
+ List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+ for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+ for(IpPortMap ipPortMap : ipPortMaps){
+ String ipPortInternal = ipPortMap.getIpPortInternal();
+ String[] ipPortParts = ipPortInternal.split(":");
+ if(ipPortParts.length != 2) {
+ LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+ return;
+ }
+ String internalIp = ipPortParts[0];
+ String internalPort = ipPortParts[1];
+
+ //Build the flow for the outbound NAPT table
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
+ FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+ IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+ String externalIp = ipPortExternal.getIpAddress();
+ int externalPort = ipPortExternal.getPortNum();
+
+ //Build the flow for the inbound NAPT table
+ switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
+ FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(inboundNaptFlowEntity);
+ }
+ }
+ }
+
+ public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
+
+ LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
+ BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+
+ //Remove the NAPT PFIB TABLE entry
+ long vpnId = -1;
+ if(vpnName != null) {
+ // ie called from disassociate vpn case
+ LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
+ vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
+ }
+
+ if(vpnId != NatConstants.INVALID_ID){
+ //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
+ String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
+ FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
+ mdsalManager.removeFlow(natPfibVpnFlowEntity);
+
+ // Remove IP-PORT active NAPT entries and release port from IdManager
+ //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+ if(ipPortMapping == null){
+ LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+ return;
+ }
+ List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+ for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+ for(IpPortMap ipPortMap : ipPortMaps){
+ String ipPortInternal = ipPortMap.getIpPortInternal();
+ String[] ipPortParts = ipPortInternal.split(":");
+ if(ipPortParts.length != 2) {
+ LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+ return;
+ }
+ String internalIp = ipPortParts[0];
+ String internalPort = ipPortParts[1];
+
+ //Build the flow for the outbound NAPT table
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
+ FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+ IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+ String externalIp = ipPortExternal.getIpAddress();
+ int externalPort = ipPortExternal.getPortNum();
+
+ //Build the flow for the inbound NAPT table
+ switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
+ FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+ LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(inboundNaptFlowEntity);
+
+ // Finally release port from idmanager
+ String internalIpPort = internalIp +":"+internalPort;
+ naptManager.removePortFromPool(internalIpPort, externalIp);
+
+ //Remove sessions from models
+ naptManager.removeIpPortMappingForRouterID(routerId);
+ naptManager.removeIntIpPortMappingForRouterID(routerId);
+ }
+ }
+ } else {
+ LOG.error("NAT Service : Invalid vpnId {}", vpnId);
+ }
+ }
+
+ public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId){
+ LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
+
+ //Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
+ List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
+ if(allSwitchList == null || allSwitchList.isEmpty()){
+ LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
+ return;
+ }
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ for (BigInteger dpnId : allSwitchList) {
+ if (!naptSwitchDpnId.equals(dpnId)) {
+ LOG.info("NAT Service : Handle Ordinary switch");
+
+ //Remove the PSNAT entry which forwards the packet to Terminating Service table
+ String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, String.valueOf(routerName));
+ FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
+
+ LOG.info("Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the non active switch with the DPN ID {} and router ID {}", dpnId, routerId);
+ mdsalManager.removeFlow(pSNatFlowEntity);
+
+ //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
+
+ LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
+ mdsalManager.removeGroup(pSNatGroupEntity);
+
+ }
+ }
+ }
+
+ public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
+ //Withdraw the corresponding routes from the BGP.
+ //Get the network ID using the router ID.
+ LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {}, network Id {} and vpnName {}",
+ externalIps,routerId,networkUuid, vpnName);
+ if(networkUuid == null ){
+ LOG.error("NAT Service : networkId is null");
+ return;
+ }
+
+ if (externalIps == null || externalIps.isEmpty()) {
+ LOG.debug("NAT Service : externalIps is null");
+ return;
+ }
+
+ if(vpnName ==null) {
+ //Get the VPN Name using the network ID
+ vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
+ if (vpnName == null) {
+ LOG.error("No VPN associated with ext nw {} for the router {}",
+ networkUuid, routerId);
+ return;
+ }
+ }
+ LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
+
+ //Remove custom FIB routes
+ //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+ for (String extIp : externalIps) {
+ clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
+ }
+ }
+
+ private void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName){
+ //Inform BGP about the route removal
+ String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+ NatUtil.removePrefixFromBGP(bgpManager, rd, extIp, LOG);
+
+ LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
+ //Get IPMaps from the DB for the router ID
+ List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
+ if (dbIpMaps == null || dbIpMaps.isEmpty()) {
+ LOG.error("NAT Service : IPMaps not found for router {}",routerId);
+ return;
+ }
+
+ long tempLabel = NatConstants.INVALID_ID;
+ for (IpMap dbIpMap : dbIpMaps) {
+ String dbExternalIp = dbIpMap.getExternalIp();
+ LOG.debug("Retrieved dbExternalIp {} for router id {}",dbExternalIp,routerId);
+ //Select the IPMap, whose external IP is the IP for which FIB is installed
+ if (extIp.equals(dbExternalIp)) {
+ tempLabel = dbIpMap.getLabel();
+ LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",tempLabel,dbExternalIp,routerId);
+ break;
+ }
+ }
+ if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
+ LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
+ return;
+ }
+
+ final long label = tempLabel;
+ final String externalIp = extIp;
+
+ RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
+ Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+ ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+ @Override
+ public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+ //Release label
+ if (result.isSuccessful()) {
+ removeTunnelTableEntry(dpnId, label);
+ removeLFibTableEntry(dpnId, label);
+ RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+ Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+ return JdkFutureAdapters.listenInPoolThread(labelFuture);
+ } else {
+ String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ }
+
+ });
+
+ Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
+ }
+
+ @Override
+ public void onSuccess(RpcResult<Void> result) {
+ if (result.isSuccessful()) {
+ LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+ } else {
+ LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+ }
+ }
+ });
+ }
+
+ private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+ LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ // Matching metadata
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+ 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+ COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+ mdsalManager.removeFlow(dpnId, flowEntity);
+ LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+ private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x8847L }));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ 10, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, null);
+
+ mdsalManager.removeFlow(dpnId, flowEntity);
+
+ LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+ protected InstanceIdentifier<Routers> getWildCardPath()
+ {
+ return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
+ }
+
+
+ /**
+ * router association to vpn
+ *
+ */
+ public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName){
+ LOG.debug("NAT Service : Router associated to BGP VPN");
+ if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
+ long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+
+ LOG.debug("BGP VPN ID value {} ", bgpVpnId);
+
+ if(bgpVpnId != NatConstants.INVALID_ID){
+ LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
+ RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
+ MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
+
+ // Get the allocated Primary NAPT Switch for this router
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ LOG.debug("Router ID value {} ", routerId);
+ BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+
+ LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
+ addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, true);
+
+ // Get the group ID
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, bgpVpnId, routerId);
+ }
+ }
+ }
+
+ /**
+ * router disassociation from vpn
+ *
+ */
+ public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName){
+ LOG.debug("NAT Service : Router dissociated from BGP VPN");
+ if(chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
+ long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+ LOG.debug("BGP VPN ID value {} ", bgpVpnId);
+
+ // Get the allocated Primary NAPT Switch for this router
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ LOG.debug("Router ID value {} ", routerId);
+ BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+
+ LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
+ addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, NatConstants.INVALID_ID, true);
+
+ // Get the group ID
+ long groupId = createGroupId(getGroupIdKey(routerName));
+ installFlowsWithUpdatedVpnId(primarySwitchId, routerName, groupId, NatConstants.INVALID_ID, routerId);
+ }
+ }
+
+ boolean chkExtRtrAndSnatEnbl(Uuid routerUuid){
+ InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
+ (Routers.class, new RoutersKey(routerUuid.getValue())).build();
+ Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
+ if (routerData.isPresent() && routerData.get().isEnableSnat()) {
+ return true;
+ }
+ return false;
+ }
+
+ public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long groupId, long bgpVpnId, long routerId){
+ long changedVpnId = bgpVpnId;
+ String logMsg = "NAT Service : Update the BGP VPN ID {}";
+ if (bgpVpnId == NatConstants.INVALID_ID){
+ changedVpnId = routerId;
+ logMsg = "NAT Service : Update the router ID {}";
+ }
+
+ LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
+ changedVpnId, groupId, primarySwitchId);
+ FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(primarySwitchId, routerName, groupId, changedVpnId);
+ mdsalManager.installFlow(flowEntity);
+
+ LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet" +
+ " to the table 46 in the Primary switch {}", changedVpnId, primarySwitchId);
+ installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
+
+ LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the" +
+ " controller in the Primary switch {}", changedVpnId, primarySwitchId);
+ createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
+
+ LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the Primary switch {}",
+ changedVpnId, primarySwitchId);
+ installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
+
+ LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the INBOUND NAPT table (table ID 44)" +
+ " in the Primary switch {}", changedVpnId, primarySwitchId);
+ updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
+
+ List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ for(BigInteger dpnId : switches) {
+ // Update the BGP VPN ID in the SNAT miss entry to group
+ if( !dpnId.equals(primarySwitchId) ) {
+ LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
+ changedVpnId, groupId, dpnId);
+ flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
+ mdsalManager.installFlow(flowEntity);
+ }
+ }
+ }
+
+ public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId){
+ //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+ if(ipPortMapping == null){
+ LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
+ return;
+ }
+
+ List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+ for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+ for(IpPortMap ipPortMap : ipPortMaps){
+ String ipPortInternal = ipPortMap.getIpPortInternal();
+ String[] ipPortParts = ipPortInternal.split(":");
+ if(ipPortParts.length != 2) {
+ LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
+ return;
+ }
+ String internalIp = ipPortParts[0];
+ String internalPort = ipPortParts[1];
+
+ ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
+ NAPTEntryEvent.Protocol protocol;
+ switch (protocolTypes){
+ case TCP:
+ protocol = NAPTEntryEvent.Protocol.TCP;
+ break;
+ case UDP:
+ protocol = NAPTEntryEvent.Protocol.UDP;
+ break;
+ default:
+ protocol = NAPTEntryEvent.Protocol.TCP;
+ }
+ SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
+ SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
+ long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
+ naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
+ internalAddress, externalAddress, protocol);
+ naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
+ externalAddress, internalAddress, protocol);
+
+ }
+ }
+ }
+
+ public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId, long changedVpnId) {
+
+ LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} changed VPN ID {}", dpId, routerName, groupId, changedVpnId );
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ List<ActionInfo> actionsInfo = new ArrayList<>();
+
+ ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+ BigInteger.valueOf(changedVpnId)}) ;
+ actionsInfo.add(actionSetField);
+ LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
+ actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+ String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+
+ LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
+ return flowEntity;
+ }
+
+ // TODO : Replace this with ITM Rpc once its available with full functionality
+ protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName, long changedVpnId) {
+ LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
+ FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
+ mdsalManager.installFlow(flowEntity);
+
+ }
+
+ private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
+ LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpId, routerName, changedVpnId);
+ BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
+ BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {bgpVpnIdAsBigInt }));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
+ { bgpVpnIdAsBigInt, MetaDataUtil.METADATA_MASK_VRFID }));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
+ { NatConstants.OUTBOUND_NAPT_TABLE }));
+ String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
+ NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_TS_TABLE, matches, instructions);
+ return flowEntity;
+ }
+
+ public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
+ LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}", dpnId, routerId, changedVpnId);
+ FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
+ LOG.debug("NAT Service : Installing flow {}", flowEntity);
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
+ LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}", dpId, routerId, changedVpnId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[]{0x0800L}));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[]{
+ BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+
+ String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+ BigInteger cookie = getCookieOutboundFlow(routerId);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
+ 5, flowRef, 0, 0,
+ cookie, matches, instructions);
+ LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
+ return flowEntity;
+ }
+
+ public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
+ LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}", dpnId, segmentId, changedVpnId);
+ FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
+ mdsalManager.installFlow(naptPfibFlowEntity);
+ }
+
+ public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
+
+ LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+ ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+ listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+ instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+
+ String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
+
+ LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
+ return flowEntity;
+ }
+
+ @Override
+ protected ExternalRoutersListener getDataTreeChangeListener()
+ {
+ return ExternalRoutersListener.this;
+ }
+
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+
+public interface FloatingIPHandler {
+
+ void onAddFloatingIp(BigInteger dpnId, String routerId, Uuid networkId, String interfaceName, String externalIp,
+ String internalIp);
+
+ void onRemoveFloatingIp(BigInteger dpnId, String routerId, Uuid networkId, String externalIp, String internalIp,
+ long label);
+
+}
--- /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.natservice.internal;
+
+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.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+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.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.NetworksKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
+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.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by emhamla on 1/18/2016.
+ */
+public class FloatingIPListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<IpMapping> implements AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+ private OdlInterfaceRpcService interfaceManager;
+ private IMdsalApiManager mdsalManager;
+ private FloatingIPHandler handler;
+
+
+ public FloatingIPListener (final DataBroker db) {
+ super(IpMapping.class);
+ broker = db;
+ registerListener(db);
+ }
+
+ void setFloatingIpHandler(FloatingIPHandler handler) {
+ this.handler = handler;
+ }
+
+ @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("FloatingIP Listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), FloatingIPListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("FloatingIP DataChange listener registration fail!", e);
+ throw new IllegalStateException("FloatingIP Listener registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<IpMapping> getWildCardPath() {
+ return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class).child(IpMapping.class);
+ }
+
+ public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ @Override
+ protected void add(final InstanceIdentifier<IpMapping> identifier,
+ final IpMapping mapping) {
+ LOG.trace("FloatingIPListener add ip mapping method - key: " + identifier + ", value=" + mapping );
+ processFloatingIPAdd(identifier, mapping);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<IpMapping> identifier, IpMapping mapping) {
+ LOG.trace("FloatingIPListener remove ip mapping method - key: " + identifier + ", value=" + mapping );
+ processFloatingIPDel(identifier, mapping);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<IpMapping> identifier, IpMapping original, IpMapping update) {
+ LOG.trace("FloatingIPListener update ip mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
+ }
+
+ public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
+ BigInteger nodeId = BigInteger.ZERO;
+ try {
+ GetDpidFromInterfaceInput
+ dpIdInput =
+ new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
+ Future<RpcResult<GetDpidFromInterfaceOutput>>
+ dpIdOutput =
+ interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
+ RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
+ if (dpIdResult.isSuccessful()) {
+ nodeId = dpIdResult.getResult().getDpid();
+ } else {
+ LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Exception when getting dpn for interface {}", ifName, e);
+ }
+ return nodeId;
+ }
+
+ private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId) {
+ return buildPreDNATFlowEntity(dpId, internalIp, externalIp, routerId, vpnId, NatConstants.INVALID_ID);
+ }
+
+ private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpn) {
+ LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
+
+ long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+ LOG.debug("Segment id {} in build preDNAT Flow", segmentId);
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+ externalIp, "32" }));
+
+// matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+// BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
+ (segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.DNAT_TABLE }));
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+ }
+
+
+
+ private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+ return buildDNATFlowEntity(dpId, internalIp, externalIp, routerId, NatConstants.INVALID_ID);
+ }
+
+ private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long associatedVpn) {
+
+ LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
+
+ long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+ LOG.debug("Segment id {} in build DNAT", segmentId);
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+ // externalIp, "32" }));
+ internalIp, "32" }));
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+// actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+// instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
+// (routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+ actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+
+ }
+
+ private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId) {
+ return buildPreSNATFlowEntity(dpId, internalIp, externalIp, vpnId, routerId, NatConstants.INVALID_ID);
+ }
+
+ private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId, long associatedVpn) {
+
+ LOG.info("Building PSNAT Flow entity for ip {} ", internalIp);
+
+ long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
+
+ LOG.debug("Segment id {} in build preSNAT flow", segmentId);
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
+ internalIp, "32" }));
+
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.SNAT_TABLE }));
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+ }
+
+ private FlowEntity buildSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, String macAddress) {
+
+ LOG.info("Building SNAT Flow entity for ip {} ", internalIp);
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
+ // internalIp, "32" }));
+ externalIp, "32" }));
+
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+// actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
+
+ //TODO: Set external gateway mac address
+ if(!Strings.isNullOrEmpty(macAddress)) {
+ LOG.debug("Setting ext gw mac address {} in SNAT {} flow action", macAddress, internalIp);
+ actionsInfos.add(new ActionInfo(ActionType.set_field_eth_dest, new String[]{ macAddress }));
+ }
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ //instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+ actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, vpnId, internalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+
+
+ }
+
+ private void createDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpnId) {
+ FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
+ mdsalManager.installFlow(pFlowEntity);
+
+ FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId) {
+ FlowEntity pFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId );
+ mdsalManager.removeFlow(pFlowEntity);
+
+ FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId);
+ mdsalManager.removeFlow(flowEntity);
+ }
+
+ private void createSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long vpnId, long routerId, String macAddress, long associatedVpnId) {
+ FlowEntity pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
+ mdsalManager.installFlow(pFlowEntity);
+
+ FlowEntity flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddress);
+ mdsalManager.installFlow(flowEntity);
+
+ }
+
+ private void removeSNATTblEntry(BigInteger dpnId, String internalIp, long routerId, String externalIp, long vpnId) {
+ FlowEntity pFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId, externalIp);
+ mdsalManager.removeFlow(pFlowEntity);
+
+ FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, internalIp, vpnId, externalIp);
+ mdsalManager.removeFlow(flowEntity);
+
+ }
+
+ private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> pIdentifier) {
+ Optional<RouterPorts> rtrPort = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, pIdentifier);
+ if(!rtrPort.isPresent()) {
+ LOG.error("Unable to read router port entry for {}", pIdentifier);
+ return null;
+ }
+
+ Uuid extNwId = rtrPort.get().getExternalNetworkId();
+ return extNwId;
+ }
+
+ private long getVpnId(Uuid extNwId) {
+ InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class, new NetworksKey(extNwId)).build();
+ Optional<Networks> nw = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, nwId);
+ if(!nw.isPresent()) {
+ LOG.error("Unable to read external network for {}", extNwId);
+ return NatConstants.INVALID_ID;
+ }
+
+ Uuid vpnUuid = nw.get().getVpnid();
+ if(vpnUuid == null) {
+ return NatConstants.INVALID_ID;
+ }
+
+ //Get the id using the VPN UUID (also vpn instance name)
+ return NatUtil.readVpnId(broker, vpnUuid.getValue());
+ }
+
+ private void processFloatingIPAdd(final InstanceIdentifier<IpMapping> identifier,
+ final IpMapping mapping) {
+ LOG.trace("Add event - key: {}, value: {}", identifier, mapping);
+
+ final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
+ final PortsKey pKey = identifier.firstKeyOf(Ports.class);
+ String interfaceName = pKey.getPortName();
+
+ InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
+ createNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
+ }
+
+ private void processFloatingIPDel(final InstanceIdentifier<IpMapping> identifier,
+ final IpMapping mapping) {
+ LOG.trace("Del event - key: {}, value: {}", identifier, mapping);
+
+ final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
+ final PortsKey pKey = identifier.firstKeyOf(Ports.class);
+ String interfaceName = pKey.getPortName();
+
+ InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
+ removeNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
+ }
+
+ private InetAddress getInetAddress(String ipAddr) {
+ InetAddress ipAddress = null;
+ try {
+ ipAddress = InetAddress.getByName(ipAddr);
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException for ip {}", ipAddr);
+ }
+ return ipAddress;
+ }
+
+ private boolean validateIpMapping(IpMapping mapping) {
+ return getInetAddress(mapping.getInternalIp()) != null &&
+ getInetAddress(mapping.getExternalIp()) != null;
+ }
+
+ void createNATFlowEntries(String interfaceName, final IpMapping mapping,
+ final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
+ if(!validateIpMapping(mapping)) {
+ LOG.warn("Not a valid ip addresses in the mapping {}", mapping);
+ return;
+ }
+
+ //Get the DPN on which this interface resides
+ BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
+
+ if(dpnId.equals(BigInteger.ZERO)) {
+ LOG.error("No DPN for interface {}. NAT flow entries for ip mapping {} will not be installed",
+ interfaceName, mapping);
+ return;
+ }
+
+ long routerId = NatUtil.getVpnId(broker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
+ return;
+ }
+ //Check if the router to vpn association is present
+ //long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
+ Uuid associatedVpn = NatUtil.getVpnForRouter(broker, routerName);
+ long associatedVpnId = NatConstants.INVALID_ID;
+ if(associatedVpn == null) {
+ LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
+ } else {
+ LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpn);
+ associatedVpnId = NatUtil.getVpnId(broker, associatedVpn.getValue());
+ LOG.debug("vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
+ //routerId = associatedVpnId;
+ }
+
+ Uuid extNwId = getExtNetworkId(pIdentifier);
+ if(extNwId == null) {
+ LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
+ LOG.error("NAT flow entries will not be installed {}", mapping);
+ return;
+ }
+ long vpnId = getVpnId(extNwId);
+ if(vpnId < 0) {
+ LOG.error("No VPN associated with Ext nw {}. Unable to create SNAT table entry for fixed ip {}",
+ extNwId, mapping.getInternalIp());
+ return;
+ }
+
+ //Create the DNAT and SNAT table entries
+ createDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId, vpnId, associatedVpnId);
+
+
+ String macAddr = getExternalGatewayMacAddress(routerName);
+ createSNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), vpnId, routerId, macAddr, associatedVpnId);
+
+ handler.onAddFloatingIp(dpnId, routerName, extNwId, interfaceName, mapping.getExternalIp(), mapping
+ .getInternalIp());
+ }
+
+ void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
+ long routerId = NatUtil.getVpnId(broker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
+ return;
+ }
+ //Check if the router to vpn association is present
+ long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
+ if(associatedVpnId == NatConstants.INVALID_ID) {
+ LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
+ } else {
+ LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpnId);
+ //routerId = associatedVpnId;
+ }
+
+ long vpnId = getVpnId(externalNetworkId);
+ if(vpnId < 0) {
+ LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
+ return;
+ }
+ //Create the DNAT and SNAT table entries
+ createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId);
+
+ String macAddr = getExternalGatewayMacAddress(routerName);
+ createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr, associatedVpnId);
+
+ handler.onAddFloatingIp(dpnId, routerName, externalNetworkId, interfaceName, externalIp, internalIp);
+ }
+
+ void createNATOnlyFlowEntries(BigInteger dpnId, String interfaceName, String routerName, String associatedVPN, Uuid externalNetworkId, String internalIp, String externalIp) {
+ //String segmentId = associatedVPN == null ? routerName : associatedVPN;
+ LOG.debug("Retrieving vpn id for VPN {} to proceed with create NAT Flows", routerName);
+ long routerId = NatUtil.getVpnId(broker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve vpn id for {} to create NAT Flow entries", routerName);
+ return;
+ }
+ long associatedVpnId = NatUtil.getVpnId(broker, associatedVPN);
+ LOG.debug("Associated VPN Id {} for router {}", associatedVpnId, routerName);
+ long vpnId = getVpnId(externalNetworkId);
+ if(vpnId < 0) {
+ LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
+ return;
+ }
+ //Create the DNAT and SNAT table entries
+ //createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId);
+ FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
+ mdsalManager.installFlow(pFlowEntity);
+
+ FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
+ mdsalManager.installFlow(flowEntity);
+
+ String macAddr = getExternalGatewayMacAddress(routerName);
+ //createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr);
+ pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
+ mdsalManager.installFlow(pFlowEntity);
+
+ flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddr);
+ mdsalManager.installFlow(flowEntity);
+
+ }
+
+ private String getExternalGatewayMacAddress(String routerName) {
+ InstanceIdentifier<Routers> routersIdentifier = NatUtil.buildRouterIdentifier(routerName);
+ Optional<Routers> optRouters = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, routersIdentifier);
+ if(optRouters.isPresent()) {
+ Routers routers = optRouters.get();
+ return routers.getExtGwMacAddress();
+ }
+ return "";
+ }
+
+ void removeNATFlowEntries(String interfaceName, final IpMapping mapping,
+ final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
+
+ //Get the DPN on which this interface resides
+ BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
+ if(dpnId.equals(BigInteger.ZERO)) {
+ LOG.info("Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
+ return;
+ }
+
+ long routerId = NatUtil.getVpnId(broker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+ return;
+ }
+ //if(routerId == NatConstants.INVALID_ID) {
+ //The router could be associated with BGP VPN
+ Uuid associatedVPN = NatUtil.getVpnForRouter(broker, routerName);
+ long associatedVpnId = NatConstants.INVALID_ID;
+ if(associatedVPN == null) {
+ LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+ } else {
+ LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", associatedVPN.getValue());
+ associatedVpnId = NatUtil.getVpnId(broker, associatedVPN.getValue());
+ }
+
+ //Delete the DNAT and SNAT table entries
+ removeDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId);
+
+ Uuid extNwId = getExtNetworkId(pIdentifier);
+ if(extNwId == null) {
+ LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
+ return;
+ }
+ long vpnId = getVpnId(extNwId);
+ if(vpnId < 0) {
+ LOG.error("No VPN associated with ext nw {}. Unable to delete SNAT table entry for fixed ip {}",
+ extNwId, mapping.getInternalIp());
+ return;
+ }
+ removeSNATTblEntry(dpnId, mapping.getInternalIp(), routerId, mapping.getExternalIp(), vpnId);
+
+ long label = getOperationalIpMapping(routerName, interfaceName, mapping.getInternalIp());
+ if(label < 0) {
+ LOG.error("Could not retrieve label for prefix {} in router {}", mapping.getInternalIp(), routerId);
+ return;
+ }
+ //Uuid extNwId = getExtNetworkId(pIdentifier);
+// Uuid extNwId = getExternalNetworkForRouter(routerName);
+// if(extNwId == null) {
+// LOG.error("External network associated with router {} could not be retrieved", routerName);
+// return;
+// }
+ handler.onRemoveFloatingIp(dpnId, routerName, extNwId, mapping.getExternalIp(), mapping.getInternalIp(), (int) label);
+ removeOperationalDS(routerName, interfaceName, mapping.getInternalIp(), mapping.getExternalIp());
+
+ }
+
+ void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
+ long routerId = NatUtil.getVpnId(broker, routerName);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+ return;
+ }
+
+ long vpnId = NatUtil.getVpnId(broker, vpnName);
+ if(vpnId == NatConstants.INVALID_ID) {
+ LOG.warn("VPN Id not found for {} to remove NAT flow entries {}", vpnName, internalIp);
+ }
+
+ //Delete the DNAT and SNAT table entries
+ removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
+
+ removeSNATTblEntry(dpnId, internalIp, routerId, externalIp, vpnId);
+
+ long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
+ if(label < 0) {
+ LOG.error("Could not retrieve label for prefix {} in router {}", internalIp, routerId);
+ return;
+ }
+ //handler.onRemoveFloatingIp(dpnId, routerName, externalNetworkId, externalIp, internalIp, (int)label);
+ ((VpnFloatingIpHandler)handler).cleanupFibEntries(dpnId, vpnName, externalIp, label);
+ removeOperationalDS(routerName, interfaceName, internalIp, externalIp);
+ }
+
+ void removeNATOnlyFlowEntries(BigInteger dpnId, String interfaceName, String routerName, String associatedVPN,
+ String internalIp, String externalIp) {
+ String segmentId = associatedVPN == null ? routerName : associatedVPN;
+ LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", segmentId);
+ long routerId = NatUtil.getVpnId(broker, segmentId);
+ if(routerId == NatConstants.INVALID_ID) {
+ LOG.warn("Could not retrieve vpn id for {} to remove NAT Flow entries", segmentId);
+ return;
+ }
+ //Delete the DNAT and SNAT table entries
+ removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
+
+ //removeSNATTblEntry(dpnId, internalIp, routerId, externalIp);
+ }
+
+ private long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
+ InstanceIdentifier<IpMapping> ipMappingIdentifier = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
+ Optional<IpMapping> ipMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, ipMappingIdentifier);
+ if(ipMapping.isPresent()) {
+ return ipMapping.get().getLabel();
+ }
+ return NatConstants.INVALID_ID;
+ }
+
+ private Uuid getExternalNetworkForRouter(String routerId) {
+ InstanceIdentifier<RouterPorts> identifier = NatUtil.getRouterPortsId(routerId);
+ Optional<RouterPorts> optRouterPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+ if(optRouterPorts.isPresent()) {
+ RouterPorts routerPorts = optRouterPorts.get();
+ return routerPorts.getExternalNetworkId();
+ }
+ return null;
+ }
+
+ void updateOperationalDS(String routerId, String interfaceName, int label, String internalIp, String externalIp) {
+
+ LOG.info("Updating operational DS for floating ip config : {} with label {}", internalIp, label);
+ InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
+ Optional<Ports> optPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portsId);
+ IpMapping ipMapping = new IpMappingBuilder().setKey(new IpMappingKey(internalIp)).setInternalIp(internalIp)
+ .setExternalIp(externalIp).setLabel(label).build();
+ if(optPorts.isPresent()) {
+ LOG.debug("Ports {} entry already present. Updating ipmapping for internal ip {}", interfaceName, internalIp);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId.child(IpMapping.class, new IpMappingKey(internalIp)), ipMapping);
+ } else {
+ LOG.debug("Adding Ports entry {} along with ipmapping {}", interfaceName, internalIp);
+ List<IpMapping> ipMappings = new ArrayList<>();
+ ipMappings.add(ipMapping);
+ Ports ports = new PortsBuilder().setKey(new PortsKey(interfaceName)).setPortName(interfaceName).setIpMapping(ipMappings).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
+ }
+ }
+
+ void removeOperationalDS(String routerId, String interfaceName, String internalIp, String externalIp) {
+ LOG.info("Remove operational DS for floating ip config: {}", internalIp);
+ InstanceIdentifier<IpMapping> ipMappingId = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, ipMappingId);
+ }
+
+ private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+
+ LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+ return flowEntity;
+ }
+
+
+
+ private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
+
+ LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+ return flowEntity;
+
+ }
+
+ private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
+
+ LOG.info("Building Delete PSNAT Flow entity for ip {} ", internalIp);
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+ return flowEntity;
+ }
+
+ private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
+
+ LOG.info("Building Delete SNAT Flow entity for ip {} ", internalIp);
+
+ String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, routerId, internalIp);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, null, null);
+
+ return flowEntity;
+
+
+ }
+}
+
--- /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.natservice.internal;
+
+public class IPAddress {
+
+ private String ipAddress;
+ private int prefixLength;
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+
+ public IPAddress(String ipAddress, int prefixLength) {
+ this.ipAddress = ipAddress;
+ this.prefixLength = prefixLength;
+ }
+}
\ 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.natservice.internal;
+
+import com.google.common.collect.Lists;
+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.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+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.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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.Optional;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class InterfaceStateEventListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateEventListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker dataBroker;
+ private IMdsalApiManager mdsalManager;
+ private FloatingIPListener floatingIPListener;
+ private NaptManager naptManager;
+ private NeutronvpnService neutronVpnService;
+
+ public InterfaceStateEventListener(final DataBroker db){
+ super(Interface.class);
+ dataBroker = db;
+ registerListener(db);
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setFloatingIpListener(FloatingIPListener floatingIPListener) {
+ this.floatingIPListener = floatingIPListener;
+ }
+
+ public void setNeutronVpnService(NeutronvpnService neutronVpnService) {
+ this.neutronVpnService = neutronVpnService;
+ }
+
+ public void setNaptManager(NaptManager naptManager) {
+ this.naptManager = naptManager;
+
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), InterfaceStateEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("Interface DataChange listener registration failed", e);
+ throw new IllegalStateException("Nexthop Manager registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface delintrf) {
+ LOG.trace("NAT Service : Interface {} removed event received", delintrf);
+ try {
+ if (delintrf != null) {
+ String interfaceName = delintrf.getName();
+ LOG.trace("NAT Service : Port removed event received for interface {} ", interfaceName);
+
+ BigInteger dpnId = NatUtil.getDpIdFromInterface(delintrf);
+ LOG.trace("NAT Service : PORT_REMOVE: Interface {} down in Dpn {}", interfaceName, dpnId);
+
+ String routerName = getRouterIdForPort(dataBroker, interfaceName);
+ if (routerName != null) {
+ processInterfaceRemoved(interfaceName, routerName);
+ removeSnatEntriesForPort(interfaceName,routerName);
+ } else {
+ LOG.debug("NAT Service : PORT_REMOVE: Router Id is null either Interface {} is not associated " +
+ "to router or failed to retrieve routerId due to exception", interfaceName);
+ }
+ }
+ } catch(Exception e) {
+ LOG.error("NAT Service : Exception caught in InterfaceOperationalStateRemove : {}", e);
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+ LOG.trace("NAT Service : Operation Interface update event - Old: {}, New: {}", original, update);
+ String interfaceName = update.getName();
+ if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
+ LOG.trace("NAT Service : Port UP event received for interface {} ", interfaceName);
+ } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
+ try {
+ LOG.trace("NAT Service : Port DOWN event received for interface {} ", interfaceName);
+
+ BigInteger dpnId = NatUtil.getDpIdFromInterface(update);
+ LOG.trace("NAT Service : PORT_DOWN: Interface {} down in Dpn {}", interfaceName, dpnId);
+
+ String routerName = getRouterIdForPort(dataBroker, interfaceName);
+ if (routerName != null) {
+ removeSnatEntriesForPort(interfaceName,routerName);
+ } else {
+ LOG.debug("NAT Service : PORT_DOWN: Router Id is null, either Interface {} is not associated " +
+ "to router or failed to retrieve routerId due to exception", interfaceName);
+ }
+ } catch (Exception ex) {
+ LOG.error("NAT Service : Exception caught in InterfaceOperationalStateDown : {}",ex);
+ }
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
+ LOG.trace("NAT Service : Interface {} up event received", intrf);
+ try {
+ String interfaceName = intrf.getName();
+ LOG.trace("NAT Service : Port added event received for interface {} ", interfaceName);
+ String routerId = getRouterIdForPort(dataBroker,interfaceName);
+ if (routerId != null) {
+ processInterfaceAdded(interfaceName, routerId);
+ }
+ } catch (Exception ex) {
+ LOG.error("NAT Service : Exception caught in Interface Operational State Up event: {}", ex);
+ }
+ }
+
+ private void removeSnatEntriesForPort(String interfaceName,String routerName) {
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("NAT Service : routerId not found for routername {}",routerName);
+ return;
+ }
+ BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker,routerName);
+ if (naptSwitch == null) {
+ LOG.error("NAT Service : NaptSwitch is not elected for router {} with Id {}",routerName,routerId);
+ return;
+ }
+ //getInternalIp for port
+ List<String> fixedIps = getFixedIpsForPort(interfaceName);
+ if (fixedIps == null) {
+ LOG.debug("NAT Service : Internal Ips not found for InterfaceName {} in router {} with id {}",interfaceName,routerName,routerId);
+ return;
+ }
+ List<ProtocolTypes> protocolTypesList = getPortocolList();
+ for (String internalIp : fixedIps) {
+ LOG.debug("NAT Service : Internal Ip retrieved for interface {} is {} in router with Id {}",interfaceName,internalIp,routerId);
+ for(ProtocolTypes protocol : protocolTypesList) {
+ List<Integer> portList = NatUtil.getInternalIpPortListInfo(dataBroker, routerId, internalIp, protocol);
+ if (portList != null) {
+ for (Integer portnum : portList) {
+ //build and remove the flow in outbound table
+ try {
+ removeNatFlow(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
+ } catch (Exception ex) {
+ LOG.error("NAT Service : Failed to remove snat flow for internalIP {} with Port {} protocol {} for routerId {} " +
+ "in OUTBOUNDTABLE of NaptSwitch {}: {}",internalIp,portnum,protocol,routerId,naptSwitch,ex);
+ }
+ //Get the external IP address and the port from the model
+ NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString()) ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+ IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+ internalIp, String.valueOf(portnum), proto);
+ if (ipPortExternal == null) {
+ LOG.error("Mapping for internalIp {} with port {} is not found in router with Id {}",internalIp,portnum,routerId);
+ return;
+ }
+ String externalIpAddress = ipPortExternal.getIpAddress();
+ Integer portNumber = ipPortExternal.getPortNum();
+
+ //build and remove the flow in inboundtable
+ try {
+ removeNatFlow(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,routerId, externalIpAddress, portNumber);
+ } catch (Exception ex) {
+ LOG.error("NAT Service : Failed to remove snat flow internalIP {} with Port {} protocol {} for routerId {} " +
+ "in INBOUNDTABLE of naptSwitch {} : {}",externalIpAddress,portNumber,protocol,routerId,naptSwitch,ex);
+ }
+
+ String internalIpPort = internalIp + ":" + portnum;
+ // delete the entry from IntExtIpPortMap DS
+ try {
+ naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
+ naptManager.removePortFromPool(internalIpPort,externalIpAddress);
+ } catch (Exception ex){
+ LOG.error("NAPT Service : releaseIpExtPortMapping failed, Removal of ipportmap {} for router {} failed {}" ,
+ internalIpPort, routerId, ex);
+ }
+ }
+ // delete the entry from SnatIntIpPortMap DS
+ LOG.debug("NAT Service : Removing InternalIp :{} portlist :{} for protocol :{} of router {}",internalIp,portList,protocol,routerId);
+ naptManager.removeFromSnatIpPortDS(routerId,internalIp);
+ } else {
+ LOG.debug("NAT Service : No {} session for interface {} with internalIP {} in router with id {}",protocol,interfaceName,internalIp,routerId);
+ }
+ }
+ }
+ }
+
+ private String getRouterIdForPort(DataBroker dataBroker,String interfaceName) {
+ String vpnName = null, routerName = null;
+ if (NatUtil.isVpnInterfaceConfigured(dataBroker, interfaceName)) {
+ //getVpnInterface
+ VpnInterface vpnInterface = null;
+ try {
+ vpnInterface = NatUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
+ } catch (Exception ex) {
+ LOG.error("NAT Service : Unable to process for interface {} as it is not configured", interfaceName);
+ }
+ if (vpnInterface != null) {
+ //getVpnName
+ try {
+ vpnName = vpnInterface.getVpnInstanceName();
+ LOG.debug("NAT Service : Retrieved VpnName {}", vpnName);
+ } catch (Exception e) {
+ LOG.error("NAT Service : Unable to get vpnname for vpninterface {} - {}", vpnInterface, e);
+ }
+ if (vpnName != null) {
+ try {
+ routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+ } catch (Exception e) {
+ LOG.error("NAT Service : Unable to get routerId for vpnName {} - {}", vpnName, e);
+ }
+ if (routerName != null) {
+ //check router is associated to external network
+ if (NatUtil.isSnatEnabledForRouterId(dataBroker, routerName)) {
+ LOG.debug("NAT Service : Retreived Router Id {} for vpnname {} associated to interface {}",
+ routerName,vpnName,interfaceName);
+ return routerName;
+ } else {
+ LOG.info("NAT Service : Interface {} associated to routerId {} is not associated to external network",
+ interfaceName, routerName);
+ }
+ } else {
+ LOG.debug("Router is not associated to vpnname {} for interface {}",vpnName,interfaceName);
+ }
+ } else {
+ LOG.debug("NAT Service : vpnName not found for vpnInterface {} of port {}",vpnInterface,interfaceName);
+ }
+ }
+ } else {
+ LOG.debug("NAT Service : Interface {} is not a vpninterface",interfaceName);
+ }
+ return null;
+ }
+
+ private List<ProtocolTypes> getPortocolList() {
+ List<ProtocolTypes> protocollist = Lists.newArrayList();
+ protocollist.add(ProtocolTypes.TCP);
+ protocollist.add(ProtocolTypes.UDP);
+ return protocollist;
+ }
+
+ private BigInteger getNaptSwitchforRouter(DataBroker broker,String routerName) {
+ InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class).child
+ (RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+ Optional<RouterToNaptSwitch> routerToNaptSwitchData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, rtrNaptSw);
+ if (routerToNaptSwitchData.isPresent()) {
+ RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
+ return routerToNaptSwitchInstance.getPrimarySwitchId();
+ }
+ return null;
+ }
+
+ private void removeNatFlow(BigInteger dpnId, short tableId,Long routerId, String ipAddress,int ipPort) {
+
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
+ FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+
+ mdsalManager.removeFlow(snatFlowEntity);
+ LOG.debug("NAT Service : Removed the flow in table {} for the switch with the DPN ID {} for router {} ip {} port {}",
+ tableId,dpnId,routerId,ipAddress,ipPort);
+ }
+
+ private void processInterfaceAdded(String portName, String rtrId) {
+ LOG.trace("Processing Interface Add Event for interface {}", portName);
+ String routerId = getRouterIdForPort(dataBroker, portName);
+ List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
+ if (ipMappingList == null || ipMappingList.isEmpty()) {
+ LOG.trace("Ip Mapping list is empty/null for portname {}", portName);
+ return;
+ }
+ InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
+ for (IpMapping ipMapping : ipMappingList) {
+ floatingIPListener.createNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
+ }
+ }
+
+ private void processInterfaceRemoved(String portName, String rtrId) {
+ LOG.trace("Processing Interface Removed Event for interface {}", portName);
+ String routerId = getRouterIdForPort(dataBroker, portName);
+ List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
+ if (ipMappingList == null || ipMappingList.isEmpty()) {
+ LOG.trace("Ip Mapping list is empty/null for portName {}", portName);
+ return;
+ }
+ InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
+ for (IpMapping ipMapping : ipMappingList) {
+ floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
+ }
+ }
+
+ private List<IpMapping> getIpMappingForPortName(String portName, String routerId) {
+ InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
+ Optional<Ports> port = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
+ if(!port.isPresent()) {
+ LOG.error("NAT Service : Unable to read router port entry for router ID {} and port name {}", routerId, portName);
+ return null;
+ }
+ List<IpMapping> ipMappingList = port.get().getIpMapping();
+ return ipMappingList;
+ }
+
+ private List<String> getFixedIpsForPort (String interfname) {
+ LOG.debug("getFixedIpsForPort method is called for interface {}",interfname);
+ try {
+ Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
+ neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
+ .setPortId(new Uuid(interfname)).build());
+
+ RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("NAT Service : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getFixedIPs();
+ }
+ } catch (InterruptedException | ExecutionException | NullPointerException ex ) {
+ LOG.error("NAT Service : Exception while receiving fixedIps for port {}",interfname);
+ }
+ return null;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("NAT Service : Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.info("NAT Service : Interface listener Closed");
+ }
+}
\ 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.natservice.internal;
+
+
+public class NAPTEntryEvent {
+ private String ipAddress;
+ private int portNumber;
+ private Long routerId;
+ private Operation op;
+ private Protocol protocol;
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public int getPortNumber() {
+ return portNumber;
+ }
+
+ public Long getRouterId() {
+ return routerId;
+ }
+
+ public Operation getOperation() {
+ return op;
+ }
+
+ public Protocol getProtocol() {
+ return protocol;
+ }
+
+ NAPTEntryEvent(String ipAddress, int portNumber, Long routerId, Operation op, Protocol protocol){
+ this.ipAddress = ipAddress;
+ this.portNumber = portNumber;
+ this.routerId = routerId;
+ this.op = op;
+ this.protocol = protocol;
+ }
+
+ public enum Operation{
+ ADD, DELETE;
+ }
+
+ public enum Protocol{
+ TCP, UDP;
+ }
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class NAPTSwitchSelector {
+ private static final Logger LOG = LoggerFactory.getLogger(NAPTSwitchSelector.class);
+
+ private DataBroker dataBroker;
+ public NAPTSwitchSelector(DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ BigInteger selectNewNAPTSwitch(String routerName) {
+ LOG.info("NAT Service : Select a new NAPT switch for router {}", routerName);
+ Map<BigInteger, Integer> naptSwitchWeights = constructNAPTSwitches();
+ List<BigInteger> routerSwitches = getDpnsForVpn(routerName);
+ if(routerSwitches == null || routerSwitches.isEmpty()) {
+ LOG.debug("NAT Service : No switches are part of router {}", routerName);
+ LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
+ return BigInteger.ZERO;
+ }
+
+ Set<SwitchWeight> switchWeights = new TreeSet<>();
+ for(BigInteger dpn : routerSwitches) {
+ if(naptSwitchWeights.get(dpn) != null) {
+ switchWeights.add(new SwitchWeight(dpn, naptSwitchWeights.get(dpn)));
+ } else {
+ switchWeights.add(new SwitchWeight(dpn, 0));
+ }
+ }
+
+ BigInteger primarySwitch;
+
+ if(!switchWeights.isEmpty()) {
+
+ LOG.debug("NAT Service : Current switch weights for router {} - {}", routerName, switchWeights);
+
+ Iterator<SwitchWeight> it = switchWeights.iterator();
+ RouterToNaptSwitchBuilder routerToNaptSwitchBuilder = new RouterToNaptSwitchBuilder().setRouterName(routerName);
+ if ( switchWeights.size() == 1 )
+ {
+ SwitchWeight singleSwitchWeight = null;
+ while(it.hasNext() ) {
+ singleSwitchWeight = it.next();
+ }
+ primarySwitch = singleSwitchWeight.getSwitch();
+ RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
+
+ MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
+
+ LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container for single switch" );
+ return primarySwitch;
+ }
+ else
+ {
+ SwitchWeight firstSwitchWeight = null;
+ while(it.hasNext() ) {
+ firstSwitchWeight = it.next();
+ }
+ primarySwitch = firstSwitchWeight.getSwitch();
+ RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(primarySwitch).build();
+
+ MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier(routerName), id);
+
+ LOG.debug( "NAT Service : successful addition of RouterToNaptSwitch to napt-switches container");
+ return primarySwitch;
+ }
+ } else {
+
+ primarySwitch = BigInteger.ZERO;
+
+ LOG.debug("NAT Service : switchWeights empty, primarySwitch: {} ", primarySwitch);
+ return primarySwitch;
+ }
+
+
+ }
+
+ private Map<BigInteger, Integer> constructNAPTSwitches() {
+ Optional<NaptSwitches> optNaptSwitches = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
+ Map<BigInteger, Integer> switchWeights = new HashMap<>();
+
+ if(optNaptSwitches.isPresent()) {
+ NaptSwitches naptSwitches = optNaptSwitches.get();
+ List<RouterToNaptSwitch> routerToNaptSwitches = naptSwitches.getRouterToNaptSwitch();
+
+ for(RouterToNaptSwitch naptSwitch : routerToNaptSwitches) {
+ BigInteger primarySwitch = naptSwitch.getPrimarySwitchId();
+ //update weight
+ Integer weight = switchWeights.get(primarySwitch);
+ if(weight == null) {
+ switchWeights.put(primarySwitch, 1);
+ } else {
+ switchWeights.put(primarySwitch, ++weight);
+ }
+ }
+ }
+ return switchWeights;
+ }
+
+ private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
+ return InstanceIdentifier.create(NaptSwitches.class);
+ }
+
+ private InstanceIdentifier<RouterToNaptSwitch> getNaptSwitchesIdentifier(String routerName) {
+ return InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+ }
+
+ public List<BigInteger> getDpnsForVpn(String routerName ) {
+ LOG.debug( "NAT Service : getVpnToDpnList called for RouterName {}", routerName );
+ long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+ if(bgpVpnId != NatConstants.INVALID_ID){
+ return NatUtil.getDpnsForRouter(dataBroker, routerName);
+ }
+ InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(routerName))
+ .build();
+
+ List<BigInteger> dpnsInVpn = new ArrayList<>();
+ Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+
+ if(vpnInstanceOpData.isPresent()) {
+ LOG.debug( "NAT Service : getVpnToDpnList able to fetch vpnInstanceOpData" );
+ VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
+ List<VpnToDpnList> vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
+ if(vpnDpnList != null) {
+ for(VpnToDpnList vpnToDpn: vpnDpnList) {
+ dpnsInVpn.add(vpnToDpn.getDpnId());
+ }
+ }
+ }
+
+ if(dpnsInVpn == null || dpnsInVpn.isEmpty()) {
+ LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+ dpnsInVpn = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ if(dpnsInVpn == null || dpnsInVpn.isEmpty()){
+ LOG.debug("NAT Service : No switches are part of router {}", routerName);
+ return dpnsInVpn;
+ }
+ }
+
+ LOG.debug( "NAT Service : getVpnToDpnList returning vpnDpnList {}", dpnsInVpn);
+ return dpnsInVpn;
+
+
+ }
+
+ private static class SwitchWeight implements Comparable<SwitchWeight>
+ {
+ private BigInteger swich;
+ private int weight;
+
+ public SwitchWeight( BigInteger swich, int weight )
+ {
+ this.swich = swich;
+ this.weight = weight;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((swich == null) ? 0 : swich.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SwitchWeight other = (SwitchWeight) obj;
+ if (swich == null) {
+ if (other.swich != null)
+ return false;
+ } else if (!swich.equals(other.swich))
+ return false;
+ return true;
+ }
+
+ public BigInteger getSwitch() {
+ return swich;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void incrementWeight() {
+ ++ weight;
+ }
+
+ @Override
+ public int compareTo(SwitchWeight o) {
+ return o.getWeight() - weight;
+ }
+ }
+}
--- /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.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NaptEventHandler {
+ private NaptManager naptManager;
+ private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
+ private static IMdsalApiManager mdsalManager;
+ private DataBroker dataBroker;
+
+ public NaptEventHandler(final DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setNaptManager(NaptManager naptManager) {
+ this.naptManager = naptManager;
+ }
+
+
+ public void handleEvent(NAPTEntryEvent naptEntryEvent){
+ /*
+ Flow programming logic of the OUTBOUND NAPT TABLE :
+ 1) Get the internal IP address, port number, router ID from the event.
+ 2) Use the NAPT service getExternalAddressMapping() to get the External IP and the port.
+ 3) Build the flow for replacing the Internal IP and port with the External IP and port.
+ a) Write the matching criteria.
+ b) Match the router ID in the metadata.
+ d) Write the VPN ID to the metadata.
+ e) Write the other data.
+ f) Set the apply actions instruction with the action setfield.
+ 4) Write the flow to the OUTBOUND NAPT Table and forward to FIB table for routing the traffic.
+
+ Flow programming logic of the INBOUND NAPT TABLE :
+ Same as Outbound table logic except that :
+ 1) Build the flow for replacing the External IP and port with the Internal IP and port.
+ 2) Match the VPN ID in the metadata.
+ 3) Write the router ID to the metadata.
+ 5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
+ */
+ Long routerId = naptEntryEvent.getRouterId();
+ LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+
+ //Get the DPN ID
+ BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ long bgpVpnId = NatConstants.INVALID_ID;
+ if(dpnId == null ){
+ LOG.warn("NAT Service : dpnId is null. Assuming the router ID {} as the BGP VPN ID and proceeding....", routerId);
+ bgpVpnId = routerId;
+ LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
+ String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
+ String routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+ routerId = NatUtil.getVpnId(dataBroker, routerName);
+ LOG.debug("NAT Service : Router ID {}", routerId);
+ dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ if(dpnId == null){
+ LOG.error("NAT Service : dpnId is null for the router {}", routerId);
+ return;
+ }
+ }
+ if(naptEntryEvent.getOperation() == NAPTEntryEvent.Operation.ADD) {
+ LOG.debug("NAT Service : Inside Add operation of NaptEventHandler");
+
+ //Get the external network ID from the ExternalRouter model
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+ if(networkId == null ){
+ LOG.error("NAT Service : networkId is null");
+ return;
+ }
+
+ //Get the VPN ID from the ExternalNetworks model
+ Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+ if(vpnUuid == null ){
+ LOG.error("NAT Service : vpnUuid is null");
+ return;
+ }
+ Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+
+ //Get the internal IpAddress, internal port number from the event
+ String internalIpAddress = naptEntryEvent.getIpAddress();
+ int internalPort = naptEntryEvent.getPortNumber();
+ SessionAddress internalAddress = new SessionAddress(internalIpAddress, internalPort);
+ NAPTEntryEvent.Protocol protocol = naptEntryEvent.getProtocol();
+
+ //Get the external IP address for the corresponding internal IP address
+ SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, naptEntryEvent.getProtocol());
+ if(externalAddress == null ){
+ if(externalAddress == null){
+ LOG.error("NAT Service : externalAddress is null");
+ return;
+ }
+ }
+ //Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
+ buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, internalAddress, externalAddress, protocol);
+ buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, externalAddress, internalAddress, protocol);
+
+ }else{
+ LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
+ removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
+ }
+
+ LOG.info("NAT Service : handleNaptEvent() exited for IP, port, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+ }
+
+ public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId, long bgpVpnId, SessionAddress actualSourceAddress,
+ SessionAddress translatedSourceAddress, NAPTEntryEvent.Protocol protocol){
+ LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for dpnId {} and routerId {}", dpnId, routerId);
+ //Build the flow for replacing the actual IP and port with the translated IP and port.
+ String actualIp = actualSourceAddress.getIpAddress();
+ int actualPort = actualSourceAddress.getPortNumber();
+ String translatedIp = translatedSourceAddress.getIpAddress();
+ String translatedPort = String.valueOf(translatedSourceAddress.getPortNumber());
+ int idleTimeout=0;
+ if(tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+ idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
+ }
+ long metaDataValue = routerId;
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metaDataValue), actualIp, actualPort);
+
+ long intranetVpnId;
+ if(bgpVpnId != NatConstants.INVALID_ID){
+ intranetVpnId = bgpVpnId;
+ }else{
+ intranetVpnId = routerId;
+ }
+ LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
+ LOG.debug("NAT Service : Router ID {}", routerId);
+ FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef, NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME,
+ idleTimeout, 0, NatUtil.getCookieNaptFlow(metaDataValue), buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
+ buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId, protocol));
+
+ snatFlowEntity.setSendFlowRemFlag(true);
+
+ LOG.debug("NAT Service : Installing the NAPT flow in the table {} for the switch with the DPN ID {} ", tableId, dpnId);
+ mdsalManager.installFlow(snatFlowEntity);
+ }
+
+ private static List<MatchInfo> buildAndGetMatchInfo(String ip, int port, short tableId, NAPTEntryEvent.Protocol protocol, long segmentId, long vpnId){
+ MatchInfo ipMatchInfo = null;
+ MatchInfo portMatchInfo = null;
+ MatchInfo protocolMatchInfo = null;
+ InetAddress ipAddress = null;
+ String ipAddressAsString = null;
+ try {
+ ipAddress = InetAddress.getByName(ip);
+ ipAddressAsString = ipAddress.getHostAddress();
+
+ } catch (UnknownHostException e) {
+ LOG.error("NAT Service : UnknowHostException in buildAndGetMatchInfo. Failed to build NAPT Flow for ip {}", ipAddress);
+ return null;
+ }
+
+ MatchInfo metaDataMatchInfo = null;
+ if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+ ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_source, new String[] {ipAddressAsString, "32" });
+ if(protocol == NAPTEntryEvent.Protocol.TCP) {
+ protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
+ portMatchInfo = new MatchInfo(MatchFieldType.tcp_src, new long[]{port});
+ } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+ protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
+ portMatchInfo = new MatchInfo(MatchFieldType.udp_src, new long[]{port});
+ }
+ metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID});
+ }else{
+ ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });
+ if(protocol == NAPTEntryEvent.Protocol.TCP) {
+ protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
+ portMatchInfo = new MatchInfo(MatchFieldType.tcp_dst, new long[]{port});
+ } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+ protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
+ portMatchInfo = new MatchInfo(MatchFieldType.udp_dst, new long[]{port});
+ }
+ //metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID});
+ }
+ ArrayList<MatchInfo> matchInfo = new ArrayList<>();
+ matchInfo.add(new MatchInfo(MatchFieldType.eth_type, new long[] { 0x0800L }));
+ matchInfo.add(ipMatchInfo);
+ matchInfo.add(protocolMatchInfo);
+ matchInfo.add(portMatchInfo);
+ if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+ matchInfo.add(metaDataMatchInfo);
+ }
+ return matchInfo;
+ }
+
+ private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, String port, long segmentId, long vpnId, short tableId, NAPTEntryEvent.Protocol protocol) {
+ ActionInfo ipActionInfo = null;
+ ActionInfo portActionInfo = null;
+ ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
+ ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+
+ if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+ ipActionInfo = new ActionInfo(ActionType.set_source_ip, new String[] {ipAddress});
+ if(protocol == NAPTEntryEvent.Protocol.TCP) {
+ portActionInfo = new ActionInfo( ActionType.set_tcp_source_port, new String[] {port});
+ } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+ portActionInfo = new ActionInfo( ActionType.set_udp_source_port, new String[] {port});
+ }
+ instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID}));
+ }else{
+ ipActionInfo = new ActionInfo(ActionType.set_destination_ip, new String[] {ipAddress});
+ if(protocol == NAPTEntryEvent.Protocol.TCP) {
+ portActionInfo = new ActionInfo( ActionType.set_tcp_destination_port, new String[] {port});
+ } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
+ portActionInfo = new ActionInfo( ActionType.set_udp_destination_port, new String[] {port});
+ }
+ instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+ }
+
+ listActionInfo.add(ipActionInfo);
+ listActionInfo.add(portActionInfo);
+
+ instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
+ instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.NAPT_PFIB_TABLE }));
+
+ return instructionInfo;
+ }
+
+ void removeNatFlows(BigInteger dpnId, short tableId ,long segmentId, String ip, int port){
+ if(dpnId == null || dpnId.equals(BigInteger.ZERO)){
+ LOG.error("NAT Service : DPN ID {} is invalid" , dpnId);
+ }
+ LOG.debug("NAT Service : Remove NAPT flows for dpnId {}, segmentId {}, ip {} and port {} ", dpnId, segmentId, ip, port);
+
+ //Build the flow with the port IP and port as the match info.
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
+ FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+ LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NatConstants.INBOUND_NAPT_TABLE, dpnId);
+ mdsalManager.removeFlow(snatFlowEntity);
+
+ }
+
+}
--- /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.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
+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.SwitchFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedReasonFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import java.math.BigInteger;
+
+public class NaptFlowRemovedEventHandler implements SalFlowListener{
+ private DataBroker dataBroker;
+ private final EventDispatcher naptEventdispatcher;
+ private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
+ private final NaptPacketInHandler naptPacketInHandler;
+ private IMdsalApiManager mdsalManager;
+ private NaptManager naptManager;
+
+ public NaptFlowRemovedEventHandler(EventDispatcher eventDispatcher, DataBroker dataBroker, NaptPacketInHandler handler,
+ IMdsalApiManager mdsalManager, NaptManager naptManager) {
+ this.naptEventdispatcher = eventDispatcher;
+ this.dataBroker = dataBroker;
+ this.naptPacketInHandler = handler;
+ this.mdsalManager = mdsalManager;
+ this.naptManager = naptManager;
+ }
+
+ @Override
+ public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
+
+/*
+ If the removed flow is from the OUTBOUND NAPT table :
+ 1) Get the ActionInfo of the flow.
+ 2) From the ActionInfo of the flow get the internal IP address, port and the protocol.
+ 3) Get the Metadata matching info of the flow.
+ 4) From the Metadata matching info of the flow get router ID.
+ 5) Querry the container intext-ip-port-map using the router ID
+ and the internal IP address, port to get the external IP address, port
+ 6) Instantiate an NaptEntry event and populate the external IP address, port and the router ID.
+ 7) Place the NaptEntry event to the queue.
+*/
+
+ short tableId = switchFlowRemoved.getTableId();
+ RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
+
+ if (tableId == NatConstants.OUTBOUND_NAPT_TABLE && removedReasonFlag.isIDLETIMEOUT()) {
+ LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
+
+ //Get the internal internal IP address and the port number from the IPv4 match.
+ Ipv4Prefix internalIpv4Address = null;
+ Layer3Match layer3Match = switchFlowRemoved.getMatch().getLayer3Match();
+ if (layer3Match instanceof Ipv4Match) {
+ Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
+ internalIpv4Address = internalIpv4Match.getIpv4Source();
+ }
+ if(internalIpv4Address == null){
+ LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
+ return;
+ }
+ //Get the internal IP as a string
+ String internalIpv4AddressAsString = internalIpv4Address.getValue();
+ String[] internalIpv4AddressParts = internalIpv4AddressAsString.split("/");
+ String internalIpv4HostAddress = null;
+ if(internalIpv4AddressParts.length >= 1){
+ internalIpv4HostAddress = internalIpv4AddressParts[0];
+ }
+
+ //Get the protocol from the layer4 match
+ NAPTEntryEvent.Protocol protocol = null;
+ Integer internalPortNumber = null;
+ Layer4Match layer4Match = switchFlowRemoved.getMatch().getLayer4Match();
+ if (layer4Match instanceof TcpMatch) {
+ TcpMatchFields tcpMatchFields = (TcpMatchFields)layer4Match;
+ internalPortNumber = tcpMatchFields.getTcpSourcePort().getValue();
+ protocol = NAPTEntryEvent.Protocol.TCP;
+ }else if (layer4Match instanceof UdpMatch){
+ UdpMatchFields udpMatchFields = (UdpMatchFields)layer4Match;
+ internalPortNumber = udpMatchFields.getUdpSourcePort().getValue();
+ protocol = NAPTEntryEvent.Protocol.UDP;
+ }
+ if(protocol == null){
+ LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
+ return;
+ }
+
+ //Get the router ID from the metadata.
+ Long routerId;
+ BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
+ if(MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
+ routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
+ }else {
+ LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
+ return;
+ }
+
+ //Get the external IP address and the port from the model
+ IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
+ if(ipPortExternal == null){
+ LOG.error("NaptFlowRemovedEventHandler : IpPortExternal is null while querried from the model");
+ return;
+ }
+ String externalIpAddress = ipPortExternal.getIpAddress();
+ int externalPortNumber = ipPortExternal.getPortNum();
+
+ //Create an NAPT event and place it in the queue.
+ NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(externalIpAddress, externalPortNumber, routerId, NAPTEntryEvent.Operation.DELETE, protocol);
+ naptEventdispatcher.addNaptEvent(naptEntryEvent);
+
+ //Get the DPN ID from the Node
+ InstanceIdentifier<Node> nodeRef = switchFlowRemoved.getNode().getValue().firstIdentifierOf(Node.class);
+ String dpn = nodeRef.firstKeyOf(Node.class).getId().getValue();
+ BigInteger dpnId = getDpnId(dpn);
+ String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metadata), internalIpv4HostAddress, internalPortNumber);
+
+ //Inform the MDSAL manager to inform about the flow removal.
+ LOG.debug("NaptFlowRemovedEventHandler : DPN ID {}, Metadata {}, SwitchFlowRef {}, internalIpv4HostAddress{}", dpnId, metadata, switchFlowRef, internalIpv4AddressAsString);
+ FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+ mdsalManager.removeFlow(snatFlowEntity);
+
+ LOG.debug("Received flow removed notification due to idleTimeout of flow from switch for flowref {}",switchFlowRef);
+ //Remove the SourceIP:Port key from the Napt packet handler map.
+ String internalIpPortKey = internalIpv4HostAddress + ":" + internalPortNumber;
+ naptPacketInHandler.removeIncomingPacketMap(internalIpPortKey);
+
+ //Remove the mapping of internal fixed ip/port to external ip/port from the datastore.
+ SessionAddress internalSessionAddress = new SessionAddress(internalIpv4HostAddress, internalPortNumber);
+ naptManager.releaseIpExtPortMapping(routerId, internalSessionAddress, protocol);
+ LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() exit");
+ }else {
+ LOG.debug("Received flow removed notification due to flowdelete from switch for flowref");
+ }
+
+ }
+
+ private BigInteger getDpnId(String node) {
+ //openflow:1]
+ String temp[] = node.split(":");
+ BigInteger dpnId = new BigInteger(temp[1]);
+ return dpnId;
+
+ }
+
+ @Override
+ public void onFlowAdded(FlowAdded arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onFlowRemoved(FlowRemoved arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onFlowUpdated(FlowUpdated arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onNodeErrorNotification(NodeErrorNotification arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /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
+ */
+
+/*
+ * Created eyugsar 2016/12/1
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCountersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternalBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+public class NaptManager {
+ private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
+ private final DataBroker broker;
+ private IdManagerService idManager;
+ private static final long LOW_PORT = 49152L;
+ private static final long HIGH_PORT = 65535L;
+ private static boolean EXTSUBNET_FLAG = false;
+ private static boolean NEXT_EXTIP_FLAG = false;
+
+ public NaptManager(final DataBroker db) {
+ this.broker = db;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
+ protected void createNaptPortPool(String PoolName) {
+ LOG.debug("NAPT Service : createPortPool requested for : {}", PoolName);
+ CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+ .setPoolName(PoolName)
+ .setLow(LOW_PORT)
+ .setHigh(HIGH_PORT)
+ .build();
+ try {
+ Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+ if ((result != null) && (result.get().isSuccessful())) {
+ LOG.debug("NAPT Service : Created PortPool");
+ } else {
+ LOG.error("NAPT Service : Unable to create PortPool");
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to create PortPool for NAPT Service",e);
+ }
+ }
+
+ void removeNaptPortPool(String poolName) {
+ DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
+ LOG.debug("NAPT Service : Remove Napt port pool requested for : {}", poolName);
+ try {
+ Future<RpcResult<Void>> result = idManager.deleteIdPool(deleteIdPoolInput);
+ if ((result != null) && (result.get().isSuccessful())) {
+ LOG.debug("NAPT Service : Deleted PortPool {}", poolName);
+ } else {
+ LOG.error("NAPT Service : Unable to delete PortPool {}", poolName);
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to delete PortPool {} for NAPT Service", poolName, e);
+ }
+ }
+
+ // 1. napt service functions
+ /**
+ * this method is used to inform this service of what external IP address to be used
+ * as mapping when requested one for the internal IP address given in the input
+ * @param segmentId – segmentation in which the mapping to be used. Eg; routerid
+ * @param internal subnet prefix or ip address
+ * @param external subnet prefix or ip address
+ */
+
+ public void registerMapping(long segmentId, IPAddress internal, IPAddress external) {
+
+ LOG.debug("NAPT Service : registerMapping called with segmentid {}, internalIp {}, prefix {}, externalIp {} and prefix {} ", segmentId, internal.getIpAddress(),
+ internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength());
+ // Create Pool per ExternalIp and not for all IPs in the subnet. Create new Pools during getExternalAddressMapping if exhausted.
+ String externalIpPool;
+ if (external.getPrefixLength() !=0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) { // subnet case
+ String externalSubnet = new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+ LOG.debug("NAPT Service : externalSubnet is : {}", externalSubnet);
+ SubnetUtils subnetUtils = new SubnetUtils(externalSubnet);
+ SubnetInfo subnetInfo = subnetUtils.getInfo();
+ externalIpPool = subnetInfo.getLowAddress();
+ } else { // ip case
+ externalIpPool = external.getIpAddress();
+ }
+ createNaptPortPool(externalIpPool);
+
+ // Store the ip to ip map in Operational DS
+ String internalIp = internal.getIpAddress();
+ if(internal.getPrefixLength() != 0) {
+ internalIp = new StringBuilder(64).append(internal.getIpAddress()).append("/").append(internal.getPrefixLength()).toString();
+ }
+ String externalIp = external.getIpAddress();
+ if(external.getPrefixLength() != 0) {
+ externalIp = new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+ }
+ updateCounter(segmentId, externalIp, true);
+ //update the actual ip-map
+ IpMap ipm = new IpMapBuilder().setKey(new IpMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getIpMapIdentifier(segmentId, internalIp), ipm);
+ LOG.debug("NAPT Service : registerMapping exit after updating DS with internalIP {}, externalIP {}", internalIp, externalIp);
+ }
+
+ public void updateCounter(long segmentId, String externalIp, boolean isAdd){
+ short counter = 0;
+ InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
+ Optional <ExternalIpCounter> externalIpCounter = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (externalIpCounter.isPresent()) {
+ counter = externalIpCounter.get().getCounter();
+ if(isAdd){
+ counter++;
+ LOG.debug("NAT Service : externalIp and counter after increment are {} and {}", externalIp, counter);
+ }else{
+ if(counter > 0){
+ counter--;
+ }
+ LOG.debug("NAT Service : externalIp and counter after decrement are {} and {}", externalIp, counter);
+ }
+
+ }else if(isAdd){
+ counter = 1;
+ }
+
+ //update the new counter value for this externalIp
+ ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter(counter).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(segmentId, externalIp), externalIpCounterData);
+
+ }
+
+ /**
+ * method to get external ip/port mapping when provided with internal ip/port pair
+ * If already a mapping exist for the given input, then the existing mapping is returned
+ * instead of overwriting with new ip/port pair.
+ * @param segmentId
+ * @param sourceAddress - internal ip address/port pair
+ * @return external ip address/port
+ */
+ public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) {
+ LOG.debug("NAPT Service : getExternalAddressMapping called with segmentId {}, internalIp {} and port {}",
+ segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
+ /*
+ 1. Get Internal IP, Port in IP:Port format
+ 2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
+ 3. If True return SessionAddress of ExternalIp and Port
+ 4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
+ */
+
+ //SessionAddress externalIpPort = new SessionAddress();
+ String internalIpPort = new StringBuilder(64).append(sourceAddress.getIpAddress()).append(":").append(sourceAddress.getPortNumber()).toString();
+
+ // First check existing Port Map.
+ SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+ if(existingIpPort != null) {
+ // populate externalIpPort from IpPortMap and return
+ LOG.debug("NAPT Service : getExternalAddressMapping successfully returning existingIpPort as {} and {}", existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
+ return existingIpPort;
+ } else {
+ // Now check in ip-map
+ String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
+ if(externalIp == null) {
+ LOG.error("NAPT Service : getExternalAddressMapping, Unexpected error, internal to external ip map does not exist");
+ return null;
+ } else {
+ /* Logic assuming internalIp is always ip and not subnet
+ * case 1: externalIp is ip
+ * a) goto externalIp pool and getPort and return
+ * b) else return error
+ * case 2: externalIp is subnet
+ * a) Take first externalIp and goto that Pool and getPort
+ * if port -> return
+ * else Take second externalIp and create that Pool and getPort
+ * if port ->return
+ * else
+ * Continue same with third externalIp till we exhaust subnet
+ * b) Nothing worked return error
+ */
+ SubnetUtils externalIpSubnet;
+ List<String> allIps = new ArrayList<String>();
+ String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
+ if( !externalIp.contains(subnetPrefix) ) {
+ EXTSUBNET_FLAG = true;
+ externalIpSubnet = new SubnetUtils(externalIp);
+ allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
+ LOG.debug("NAPT Service : total count of externalIps available {}", externalIpSubnet.getInfo().getAddressCount());
+ } else {
+ LOG.debug("NAPT Service : getExternalAddress single ip case");
+ if(externalIp.contains(subnetPrefix)) {
+ String[] externalIpSplit = externalIp.split("/");
+ String extIp = externalIpSplit[0];
+ externalIp = extIp; //remove /32 what we got from checkIpMap
+ }
+ allIps.add(externalIp);
+ }
+
+ for(String extIp : allIps) {
+ LOG.info("NAPT Service : Looping externalIPs with externalIP now as {}", extIp);
+ if(NEXT_EXTIP_FLAG) {
+ createNaptPortPool(extIp);
+ LOG.debug("NAPT Service : Created Pool for next Ext IP {}", extIp);
+ }
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+ .setPoolName(extIp).setIdKey(internalIpPort)
+ .build();
+ try {
+ Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+ RpcResult<AllocateIdOutput> rpcResult;
+ if ((result != null) && (result.get().isSuccessful())) {
+ LOG.debug("NAPT Service : Got id from idManager");
+ rpcResult = result.get();
+ } else {
+ LOG.error("NAPT Service : getExternalAddressMapping, idManager could not allocate id retry if subnet");
+ if(!EXTSUBNET_FLAG) {
+ LOG.error("NAPT Service : getExternalAddressMapping returning null for single IP case, may be ports exhausted");
+ return null;
+ }
+ LOG.debug("NAPT Service : Could be ports exhausted case, try with another externalIP if possible");
+ NEXT_EXTIP_FLAG = true;
+ continue;
+ }
+ int extPort= rpcResult.getResult().getIdValue().intValue();
+ SessionAddress externalIpPort = new SessionAddress(extIp, extPort);
+ // Write to ip-port-map before returning
+ IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
+ IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build();
+ IpPortMap ipm = new IpPortMapBuilder().setKey(new IpPortMapKey(internalIpPort))
+ .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
+ LOG.debug("NAPT Service : getExternalAddressMapping writing into ip-port-map with externalIP {} and port {}",
+ ipPortExt.getIpAddress(), ipPortExt.getPortNum());
+ try {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
+ } catch (UncheckedExecutionException uee) {
+ LOG.error("NAPT Service : Failed to write into ip-port-map with exception {}", uee.getMessage() );
+ }
+
+ // Write to snat-internal-ip-port-info
+ String internalIpAddress = sourceAddress.getIpAddress();
+ int ipPort = sourceAddress.getPortNumber();
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,internalIpAddress,protocolType);
+ if (portList == null) {
+ portList = Lists.newArrayList();
+ }
+ portList.add(ipPort);
+
+ IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+ IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+ try {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+ NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType), intIpProtocolType);
+ } catch (Exception ex) {
+ LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+ }
+
+ LOG.debug("NAPT Service : getExternalAddressMapping successfully returning externalIP {} and port {}",
+ externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+ return externalIpPort;
+ } catch(InterruptedException | ExecutionException e) {
+ LOG.error("NAPT Service : getExternalAddressMapping, Exception caught {}",e);
+ return null;
+ }
+ }// end of for loop
+ }// end of else ipmap present
+ }// end of else check ipmap
+ LOG.error("NAPT Service: getExternalAddressMapping returning null, nothing worked or externalIPs exhausted");
+ return null;
+ }
+
+
+ /**
+ * release the existing mapping of internal ip/port to external ip/port pair
+ * if no mapping exist for given internal ip/port, it returns false
+ * @param segmentId
+ * @param address
+ * @return true if mapping exist and the mapping is removed successfully
+ */
+
+ public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+
+ LOG.debug("NAPT Service : releaseAddressMapping called with segmentId {}, internalIP {}, port {}", segmentId, address.getIpAddress(), address.getPortNumber());
+ // delete entry from IpPort Map and IP Map if exists
+ String internalIpPort = new StringBuilder(64).append(address.getIpAddress()).append(":").append(address.getPortNumber()).toString();
+ SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+ if(existingIpPort != null) {
+ // delete the entry from IpPortMap DS
+ try {
+ removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+ } catch (Exception e){
+ LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" , internalIpPort, segmentId, e);
+ return false;
+ }
+ } else {
+ LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+ return false;
+ }
+ String existingIp = checkIpMap(segmentId, address.getIpAddress());
+ if(existingIp != null) {
+ // delete the entry from IpMap DS
+ try {
+ removeFromIpMapDS(segmentId, address.getIpAddress());
+ } catch (Exception e){
+ LOG.error("NAPT Service : Removal of ipmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+ return false;
+ }
+ //delete the entry from snatIntIpportinfo
+ try {
+ removeFromSnatIpPortDS(segmentId, address.getIpAddress());
+ } catch (Exception e){
+ LOG.error("NAPT Service : releaseAddressMapping failed, Removal of snatipportmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+ return false;
+ }
+ } else {
+ LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpMap DS", segmentId, internalIpPort);
+ return false;
+ }
+ // Finally release port from idmanager
+ removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+
+ LOG.debug("NAPT Service : Exit of releaseAddressMapping successfully for segmentId {} and internalIpPort {}", segmentId, internalIpPort);
+ return true;
+
+ }
+
+ protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+ String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
+ SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+ if(existingIpPort != null) {
+ // delete the entry from IpPortMap DS
+ try {
+ removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+ // Finally release port from idmanager
+ removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+ } catch (Exception e){
+ LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" ,
+ internalIpPort, segmentId, e);
+ }
+ } else {
+ LOG.error("NAPT Service : releaseIpExtPortMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+ }
+
+ //delete the entry of port for InternalIp from snatIntIpportMappingDS
+ try {
+ removeSnatIntIpPortDS(segmentId,address, protocol);
+ } catch (Exception e){
+ LOG.error("NAPT Service : releaseSnatIpPortMapping failed, Removal of snatipportmap {} for router {} failed {}" ,
+ address.getIpAddress(), segmentId, e);
+ }
+ }
+
+ /**
+ * removes the internal ip to external ip mapping if present
+ * @param segmentId
+ * @return true if successfully removed
+ */
+ public boolean removeMapping(long segmentId) {
+ try {
+ removeIpMappingForRouterID(segmentId);
+ removeIpPortMappingForRouterID(segmentId);
+ removeIntIpPortMappingForRouterID(segmentId);
+ } catch (Exception e){
+ LOG.error("NAPT Service : Removal of IPMapping for router {} failed {}" , segmentId, e);
+ return false;
+ }
+
+ //TODO : This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
+ return false;
+ }
+
+ // 2. Utility functions
+ protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
+ InstanceIdentifier<IpMap> id = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segid)).child(IpMap.class, new IpMapKey(internal)).build();
+ return id;
+ }
+
+ protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
+ InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId))
+ .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
+ return id;
+ }
+
+ public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
+ InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
+ Optional<IpMapping> ipMappingListData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (ipMappingListData.isPresent()) {
+ IpMapping ipMapping = ipMappingListData.get();
+ return ipMapping.getIpMap();
+ }
+ return null;
+ }
+
+ protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
+ InstanceIdentifier<IpMapping> id = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
+ return id;
+ }
+
+ protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal, NAPTEntryEvent.Protocol protocol) {
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ InstanceIdentifier<IpPortMap> id = InstanceIdentifier.builder(
+ IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segid)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)).
+ child(IpPortMap.class, new IpPortMapKey(internal)).build();
+ return id;
+ }
+
+ protected SessionAddress checkIpPortMap(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+
+ LOG.debug("NAPT Service : checkIpPortMap called with segmentId {} and internalIpPort {}", segmentId, internalIpPort);
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ // check if ip-port-map node is there
+ InstanceIdentifierBuilder<IntextIpProtocolType> idBuilder =
+ InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType));
+ InstanceIdentifier<IntextIpProtocolType> id = idBuilder.build();
+ Optional<IntextIpProtocolType> intextIpProtocolType = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (intextIpProtocolType.isPresent()) {
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.get().getIpPortMap();
+ for (IpPortMap ipPortMap : ipPortMaps) {
+ if (ipPortMap.getIpPortInternal().equals(internalIpPort)) {
+ LOG.debug("NAPT Service : IpPortMap : {}", ipPortMap);
+ SessionAddress externalIpPort = new SessionAddress(ipPortMap.getIpPortExternal().getIpAddress(),
+ ipPortMap.getIpPortExternal().getPortNum());
+ LOG.debug("NAPT Service : checkIpPortMap returning successfully externalIP {} and port {}",
+ externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+ return externalIpPort;
+ }
+ }
+ }
+ // return null if not found
+ LOG.error("NAPT Service : no-entry in checkIpPortMap, returning NULL [should be OK] for segmentId {} and internalIPPort {}", segmentId, internalIpPort);
+ return null;
+ }
+
+ protected String checkIpMap(long segmentId, String internalIp) {
+
+ LOG.debug("NAPT Service : checkIpMap called with segmentId {} and internalIp {}", segmentId, internalIp);
+ String externalIp;
+ // check if ip-map node is there
+ InstanceIdentifierBuilder<IpMapping> idBuilder =
+ InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
+ InstanceIdentifier<IpMapping> id = idBuilder.build();
+ Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (ipMapping.isPresent()) {
+ List<IpMap> ipMaps = ipMapping.get().getIpMap();
+ for (IpMap ipMap : ipMaps) {
+ if (ipMap.getInternalIp().equals(internalIp)) {
+ LOG.debug("NAPT Service : IpMap : {}", ipMap);
+ externalIp = ipMap.getExternalIp().toString();
+ LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+ return externalIp;
+ } else if (ipMap.getInternalIp().contains("/")) { // subnet case
+ SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
+ SubnetInfo subnetInfo = subnetUtils.getInfo();
+ if (subnetInfo.isInRange(internalIp)) {
+ LOG.debug("NAPT Service : internalIp {} found to be IpMap of internalIpSubnet {}", internalIp, ipMap.getInternalIp());
+ externalIp = ipMap.getExternalIp().toString();
+ LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+ return externalIp;
+ }
+ }
+ }
+ }
+ // return null if not found
+ LOG.error("NAPT Service : checkIpMap failed, returning NULL for segmentId {} and internalIp {}", segmentId, internalIp);
+ return null;
+ }
+
+ protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address,NAPTEntryEvent.Protocol protocol) {
+ LOG.trace("NAPT Service : removeSnatIntIpPortDS method called for IntIpport {} of router {} ",address,segmentId);
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,address.getIpAddress(),protocolType);
+ if (portList == null || portList.isEmpty() || !portList.contains(address.getPortNumber())) {
+ LOG.debug("Internal IP {} for port {} entry not found in SnatIntIpPort DS",address.getIpAddress(),address.getPortNumber());
+ return;
+ }
+ LOG.trace("NAPT Service : PortList {} retrieved for InternalIp {} of router {}",portList,address.getIpAddress(),segmentId);
+ Integer port = address.getPortNumber();
+ portList.remove(port);
+
+ IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+ IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+ try {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType), intIpProtocolType);
+ } catch (Exception ex) {
+ LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+ }
+ LOG.debug("NAPT Service : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore : {}"
+ ,address.getIpAddress(),address.getPortNumber(),segmentId);
+ }
+
+ protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
+ InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+ (IntipPortMap.class, new IntipPortMapKey(segmentId)).child(IpPort.class, new IpPortKey(internalIp)).build();
+ // remove from SnatIpPortDS
+ LOG.debug("NAPT Service : Removing SnatIpPort from datastore : {}", intIp);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
+
+ }
+
+ protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
+ }
+
+ protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
+ InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
+ .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
+ .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
+ InstanceIdentifier<IpPortMap> id = idBuilder.build();
+ // remove from ipportmap DS
+ LOG.debug("NAPT Service : Removing ipportmap from datastore : {}", id);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+ }
+
+ protected void removeFromIpMapDS(long segmentId, String internalIp) {
+ InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+ .child(IpMapping.class, new IpMappingKey(segmentId))
+ .child(IpMap.class, new IpMapKey(internalIp));
+ InstanceIdentifier<IpMap> id = idBuilder.build();
+ // Get externalIp and decrement the counter
+ String externalIp = null;
+ Optional<IpMap> ipMap = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (ipMap.isPresent()) {
+ externalIp = ipMap.get().getExternalIp();
+ LOG.debug("NAT Service : externalIP is {}", externalIp);
+ }else{
+ LOG.warn("NAT Service : ipMap not present for the internal IP {}", internalIp);
+ }
+
+ if(externalIp!=null) {
+ updateCounter(segmentId, externalIp, false);
+ // remove from ipmap DS
+ LOG.debug("NAPT Service : Removing ipmap from datastore");
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+ }else{
+ LOG.warn("NAT Service : externalIp not present for the internal IP {}", internalIp);
+ }
+ }
+
+ private void removeIpMappingForRouterID(long segmentId) {
+ InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+ .child(IpMapping.class, new IpMappingKey(segmentId));
+ InstanceIdentifier<IpMapping> id = idBuilder.build();
+ // Get all externalIps and decrement their counters before deleting the ipmap
+ String externalIp = null;
+ Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (ipMapping.isPresent()) {
+ List<IpMap> ipMaps = ipMapping.get().getIpMap();
+ for (IpMap ipMap : ipMaps) {
+ externalIp = ipMap.getExternalIp();
+ LOG.debug("NAT Service : externalIP is {}", externalIp);
+ if(externalIp!=null) {
+ updateCounter(segmentId, externalIp, false);
+ }
+ }
+ }
+ // remove from ipmap DS
+ LOG.debug("NAPT Service : Removing Ipmap for router {} from datastore",segmentId);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+ }
+
+ void removeIpPortMappingForRouterID(long segmentId) {
+ InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
+ .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
+ // remove from IntExtIpPortmap DS
+ LOG.debug("NAPT Service : Removing IntExtIpPort map for router {} from datastore",segmentId);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idBuilder);
+ }
+
+ void removeIntIpPortMappingForRouterID(long segmentId) {
+ InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+ (IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
+ // remove from SnatIntIpPortmap DS
+ LOG.debug("NAPT Service : Removing SnatIntIpPort from datastore : {}", intIp);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
+ }
+
+ void removePortFromPool(String internalIpPort, String externalIp) {
+ LOG.debug("NAPT Service : removePortFromPool method called");
+ ReleaseIdInput idInput = new ReleaseIdInputBuilder().
+ setPoolName(externalIp)
+ .setIdKey(internalIpPort).build();
+ try {
+ Future<RpcResult<Void>> result = idManager.releaseId(idInput);
+ RpcResult<Void> rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.error("NAPT Service : idmanager failed to remove port from pool {}", rpcResult.getErrors());
+ }
+ LOG.debug("NAPT Service : Removed port from pool for InternalIpPort {} with externalIp {}",internalIpPort,externalIp);
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("NAPT Service : idmanager failed with Exception {} when removing entry in pool with key {}, ", e, internalIpPort);
+ }
+ }
+
+ protected void initialiseExternalCounter(Routers routers, long routerId){
+ LOG.debug("NAPT Service : Initialise External IPs counter");
+ List<String> externalIps = routers.getExternalIps();
+
+ //update the new counter value for this externalIp
+ for(String externalIp : externalIps) {
+ String[] IpSplit = externalIp.split("/");
+ String extIp = IpSplit[0];
+ String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
+ if(IpSplit.length==2) {
+ extPrefix = IpSplit[1];
+ }
+ extIp = extIp + "/" + extPrefix;
+ initialiseNewExternalIpCounter(routerId, extIp);
+ }
+ }
+
+ protected void initialiseNewExternalIpCounter(long routerId, String ExternalIp){
+ ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(ExternalIp)).
+ setExternalIp(ExternalIp).setCounter((short) 0).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(routerId, ExternalIp), externalIpCounterData);
+ }
+
+ protected void removeExternalCounter(long routerId){
+ // Remove from external-counters model
+ InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
+ LOG.debug("NAPT Service : Removing ExternalCounterd from datastore");
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+ }
+
+ protected void removeExternalIpCounter(long routerId, String externalIp){
+ // Remove from external-counters model
+ InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class,
+ new ExternalCountersKey(routerId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
+ LOG.debug("NAPT Service : Removing ExternalIpsCounter from datastore");
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+ }
+
+}
\ 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.natservice.internal;
+
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
+import org.opendaylight.vpnservice.mdsalutil.packet.TCP;
+import org.opendaylight.vpnservice.mdsalutil.packet.UDP;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.HashSet;
+import com.google.common.primitives.Ints;
+
+public class NaptPacketInHandler implements PacketProcessingListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NaptPacketInHandler.class);
+ private final static HashSet<String> incomingPacketMap = new HashSet<>();
+ private final EventDispatcher naptEventdispatcher;
+
+ public NaptPacketInHandler(EventDispatcher eventDispatcher) {
+ this.naptEventdispatcher = eventDispatcher;
+ }
+
+ @Override
+ public void onPacketReceived(PacketReceived packetReceived) {
+ String internalIPAddress = "";
+ int portNumber = 0;
+ long routerId = 0L;
+ NAPTEntryEvent.Operation operation = NAPTEntryEvent.Operation.ADD;
+ NAPTEntryEvent.Protocol protocol;
+
+ Short tableId = packetReceived.getTableId().getValue();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("packet: {}, tableId {}", packetReceived, tableId);
+ }
+
+ if (tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+ LOG.debug("NAT Service : NAPTPacketInHandler Packet for Outbound NAPT Table");
+ byte[] inPayload = packetReceived.getPayload();
+ Ethernet ethPkt = new Ethernet();
+ if (inPayload != null) {
+ try {
+ ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
+ } catch (Exception e) {
+ LOG.warn("Failed to decode Packet", e);
+ return;
+ }
+ if (ethPkt.getPayload() instanceof IPv4) {
+ IPv4 ipPkt = (IPv4) ethPkt.getPayload();
+ byte[] ipSrc = Ints.toByteArray(ipPkt.getSourceAddress());
+
+ internalIPAddress = NatUtil.toStringIpAddress(ipSrc, LOG);
+ LOG.trace("Retrieved internalIPAddress {}", internalIPAddress);
+ if (ipPkt.getPayload() instanceof TCP) {
+ TCP tcpPkt = (TCP) ipPkt.getPayload();
+ portNumber = tcpPkt.getSourcePort();
+ if(portNumber < 0){
+ portNumber = 32767 + portNumber + 32767 + 2;
+ LOG.trace("Retrieved and extracted TCP portNumber {}", portNumber);
+ }
+ protocol = NAPTEntryEvent.Protocol.TCP;
+ LOG.trace("Retrieved TCP portNumber {}", portNumber);
+ } else if (ipPkt.getPayload() instanceof UDP) {
+ UDP udpPkt = (UDP) ipPkt.getPayload();
+ portNumber = udpPkt.getSourcePort();
+ if(portNumber < 0){
+ portNumber = 32767 + portNumber + 32767 + 2;
+ LOG.trace("Retrieved and extracted UDP portNumber {}", portNumber);
+ }
+ protocol = NAPTEntryEvent.Protocol.UDP;
+ LOG.trace("Retrieved UDP portNumber {}", portNumber);
+ } else {
+ LOG.error("Incoming Packet is neither TCP or UDP packet");
+ return;
+ }
+ } else {
+ LOG.error("Incoming Packet is not IPv4 packet");
+ return;
+ }
+
+ if(internalIPAddress != null) {
+ String sourceIPPortKey = internalIPAddress + ":" + portNumber;
+ LOG.debug("NAT Service : sourceIPPortKey {} mapping maintained in the map", sourceIPPortKey);
+ if (!incomingPacketMap.contains(sourceIPPortKey)) {
+ incomingPacketMap.add(internalIPAddress + portNumber);
+
+ BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
+ routerId = (metadata.and(MetaDataUtil.METADATA_MASK_VRFID)).longValue();
+ if( routerId <= 0) {
+ LOG.error("Nat Service : Router ID is invalid");
+ return;
+ }
+ //send to Event Queue
+ NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(internalIPAddress,portNumber,routerId,
+ operation,protocol);
+ naptEventdispatcher.addNaptEvent(naptEntryEvent);
+ } else {
+ LOG.trace("Ignore the packet, already processed");
+ }
+ }else {
+ LOG.error("Nullpointer exception in retrieving internalIPAddress");
+ }
+ }
+ }else {
+ LOG.trace("Packet is not from the Outbound NAPT table");
+ }
+ }
+
+ public void removeIncomingPacketMap(String sourceIPPortKey) {
+ incomingPacketMap.remove(sourceIPPortKey);
+ LOG.debug("NAT Service : sourceIPPortKey {} mapping is removed from map", sourceIPPortKey);
+ }
+}
\ 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.natservice.internal;
+
+import com.google.common.base.Optional;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.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.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+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.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
+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.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+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.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class NaptSwitchHA {
+ private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
+ private final DataBroker dataBroker;
+ private IMdsalApiManager mdsalManager;
+ private ItmRpcService itmManager;
+ private OdlInterfaceRpcService interfaceManager;
+ private IdManagerService idManager;
+ private NAPTSwitchSelector naptSwitchSelector;
+ private ExternalRoutersListener externalRouterListener;
+ private IBgpManager bgpManager;
+ private VpnRpcService vpnService;
+ private FibRpcService fibService;
+
+ public NaptSwitchHA(DataBroker broker,NAPTSwitchSelector selector){
+ dataBroker = broker;
+ naptSwitchSelector = selector;
+ }
+
+ public void setItmManager(ItmRpcService itmManager) {
+ this.itmManager = itmManager;
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
+ void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
+ this.externalRouterListener = externalRoutersListener;
+ }
+
+ public void setBgpManager(IBgpManager bgpManager) {
+ this.bgpManager = bgpManager;
+ }
+
+ public void setVpnService(VpnRpcService vpnService) {
+ this.vpnService = vpnService;
+ }
+
+ public void setFibService(FibRpcService fibService) {
+ this.fibService = fibService;
+ }
+
+ /* This method checks the switch that gone down is a NaptSwitch for a router.
+ If it is a NaptSwitch
+ 1) selects new NAPT switch
+ 2) installs nat flows in new NAPT switch
+ table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
+ 3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
+ 4) Remove nat flows in oldNaptSwitch
+ */
+ /*public void handleNaptSwitchDown(BigInteger dpnId){
+
+ LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
+ BigInteger naptSwitch;
+ try {
+ NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
+ if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
+ LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
+ return;
+ }
+ for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
+ String routerName = routerToNaptSwitch.getRouterName();
+ naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
+ boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
+ if (!naptStatus) {
+ LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+ dpnId, routerName);
+ } else {
+ removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
+ return;
+ }
+ }
+ } catch (Exception ex) {
+ LOG.error("Exception in handleNaptSwitchDown method {}",ex);
+ }
+ }*/
+
+ protected void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch) {
+ //remove SNAT flows in old NAPT SWITCH
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return;
+ }
+
+ //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
+ String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
+ FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
+
+ LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
+ ,NatConstants.TERMINATING_SERVICE_TABLE, naptSwitch, routerId);
+ mdsalManager.removeFlow(tsNatFlowEntity);
+
+ //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
+ String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
+ FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+ NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
+ LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
+ ,NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
+ mdsalManager.removeFlow(outboundNatFlowEntity);
+
+ //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic matching on the router ID.
+ String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, routerId);
+ FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptPFibflowRef);
+ LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
+ NatConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
+ mdsalManager.removeFlow(naptPFibFlowEntity);
+
+ //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic matching on the vpn ID.
+ Long vpnId = getVpnIdForRouter(routerId);
+ if (vpnId != NatConstants.INVALID_ID) {
+ String naptFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, vpnId);
+ FlowEntity naptFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptFibflowRef);
+ LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and vpnId {}",
+ NatConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
+ mdsalManager.removeFlow(naptFibFlowEntity);
+ } else {
+ LOG.error("Invalid vpnId retrieved for routerId {}",routerId);
+ return;
+ }
+
+ //Remove Fib entries and 36-> 44
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+ if (networkId != null) {
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+ if (externalIps != null) {
+ externalRouterListener.clrRtsFromBgpAndDelFibTs(naptSwitch, routerId, networkId, externalIps, null);
+ LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} with networkId {} and externalIps {}",
+ naptSwitch,routerId,networkId,externalIps);
+ } else {
+ LOG.debug("ExternalIps not found for router {} with networkId {}", routerName, networkId);
+ }
+ } else {
+ LOG.debug("network not associated to router {}", routerId);
+ }
+
+ //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+ if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+ LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be removed in" +
+ "oldNaptSwitch {}", routerId, naptSwitch);
+ return;
+ }
+ BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+ List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+ for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
+ if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
+ LOG.debug("No {} session associated to router {},no flows need to be removed in oldNaptSwitch {}",
+ intextIpProtocolType.getProtocol(),routerId,naptSwitch);
+ break;
+ }
+ List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+ for(IpPortMap ipPortMap : ipPortMaps) {
+ String ipPortInternal = ipPortMap.getIpPortInternal();
+ String[] ipPortParts = ipPortInternal.split(":");
+ if(ipPortParts.length != 2) {
+ LOG.error("Unable to retrieve the Internal IP and port");
+ continue;
+ }
+ String internalIp = ipPortParts[0];
+ String internalPort = ipPortParts[1];
+
+ //Build and remove flow in outbound NAPT table
+ String switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
+ internalIp, Integer.valueOf(internalPort));
+ FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+ cookieSnatFlow, switchFlowRef);
+
+ LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
+ NatConstants.OUTBOUND_NAPT_TABLE,naptSwitch, routerId);
+ mdsalManager.removeFlow(outboundNaptFlowEntity);
+
+ IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
+ if (ipPortExternal == null) {
+ LOG.debug("External Ipport mapping not found for internalIp {} with port {} for router", internalIp,
+ internalPort, routerId);
+ continue;
+ }
+ String externalIp = ipPortExternal.getIpAddress();
+ int externalPort = ipPortExternal.getPortNum();
+
+ //Build and remove flow in inbound NAPT table
+ switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
+ externalIp, externalPort);
+ FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+ cookieSnatFlow, switchFlowRef);
+
+ LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
+ NatConstants.INBOUND_NAPT_TABLE,naptSwitch, routerId);
+ mdsalManager.removeFlow(inboundNaptFlowEntity);
+ }
+ }
+
+ }
+
+ /*public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch) {
+ if (!naptSwitch.equals(dpnId)) {
+ LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
+ return false;
+ }
+ LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
+ //elect a new NaptSwitch
+ naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+ if (naptSwitch.equals(BigInteger.ZERO)) {
+ LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
+ boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
+ if(!naptUpdatedStatus) {
+ LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
+ }
+ return true;
+ }
+ //checking elected switch health status
+ if (!getSwitchStatus(naptSwitch)) {
+ LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
+ return true;
+ }
+ LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}", routerName);
+ return true;
+ }
+ //update napt model for new napt switch
+ boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
+ if (naptUpdated) {
+ //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
+ updateNaptSwitchBucketStatus(routerName, naptSwitch);
+ } else {
+ LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
+ }
+
+ installSnatFlows(routerName,routerId,naptSwitch);
+
+ boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch);
+ if (flowInstalledStatus) {
+ LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
+ } else {
+ LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
+ }
+ return true;
+ }*/
+
+ public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId) {
+ if (!naptSwitch.equals(dpnId)) {
+ LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
+ return false;
+ }
+ LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
+ //elect a new NaptSwitch
+ naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+ if (naptSwitch.equals(BigInteger.ZERO)) {
+ LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
+ boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
+ if(!naptUpdatedStatus) {
+ LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
+ }
+ return true;
+ }
+ //checking elected switch health status
+ if (!getSwitchStatus(naptSwitch)) {
+ LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
+ return true;
+ }
+ LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}", routerName);
+ return true;
+ }
+ //update napt model for new napt switch
+ boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
+ if (naptUpdated) {
+ //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
+ updateNaptSwitchBucketStatus(routerName, naptSwitch);
+ } else {
+ LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
+ }
+
+ installSnatFlows(routerName,routerId,naptSwitch,routerVpnId);
+
+ boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch,routerVpnId);
+ if (flowInstalledStatus) {
+ LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
+ } else {
+ LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
+ }
+ return true;
+ }
+
+ private String getExtNetworkVpnName(long routerId) {
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+ if(networkId == null) {
+ LOG.error("networkId is null for the router ID {}", routerId);
+ } else {
+ final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+ if (vpnName != null) {
+ LOG.debug("retrieved vpn name {} associated with ext nw {} in router {}",
+ vpnName,networkId,routerId);
+ return vpnName;
+ } else {
+ LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
+ networkId, routerId);
+ }
+ }
+ return null;
+ }
+
+ public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
+ LOG.debug("updateNaptSwitchBucketStatus method is called");
+
+ List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
+ //List<BigInteger> dpnList = getDpnListForRouter(routerName);
+ for (BigInteger dpn : dpnList) {
+ if (dpn.equals(naptSwitch)) {
+ LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is naptSwitch for router {}",dpn,routerName);
+ List<BucketInfo> bucketInfoList = handleGroupInPrimarySwitch();
+ modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
+ } else {
+ LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}",dpn,routerName);
+ List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
+ if (bucketInfoList == null) {
+ LOG.debug("Failed to populate bucketInfo for orinaryswitch {} whose naptSwitch {} for router {} ",
+ dpn,naptSwitch,routerName);
+ return;
+ }
+ modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
+ }
+ }
+ }
+
+ /*private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch) {
+
+ LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
+ if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+ LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
+ "newNaptSwitch {}", routerId, newNaptSwitch);
+ return true;
+ }
+ //getvpnId
+ Long vpnId = getVpnIdForRouter(routerId);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId for routerId {}",routerId);
+ return false;
+ }
+ Long bgpVpnId = NatConstants.INVALID_ID;
+ for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
+ if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
+ LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
+ return true;
+ }
+ for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
+ String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
+ String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
+
+ //Get the external IP address and the port from the model
+ NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
+ ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+ IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+ internalIpAddress, intportnum, proto);
+ if (ipPortExternal == null) {
+ LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
+ continue;
+ }
+ String externalIpAddress = ipPortExternal.getIpAddress();
+ Integer extportNumber = ipPortExternal.getPortNum();
+ LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
+ internalIpAddress,intportnum);
+
+ SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
+ SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
+
+ //checking naptSwitch status before installing flows
+ if(getSwitchStatus(newNaptSwitch)) {
+ //Install the flow in newNaptSwitch Outbound NAPT table.
+ try {
+ NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+ vpnId, routerId, bgpVpnId ,sourceAddress, externalAddress, proto);
+ } catch (Exception ex) {
+ LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
+ "extIpport {}:{}", routerId, newNaptSwitch, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber);
+ return false;
+ }
+ LOG.debug("Succesfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
+ "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber);
+ //Install the flow in newNaptSwitch Inbound NAPT table.
+ try {
+ NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+ vpnId, routerId, bgpVpnId,externalAddress, sourceAddress, proto);
+ } catch (Exception ex) {
+ LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{}",
+ routerId, newNaptSwitch, externalAddress, extportNumber,
+ proto, internalIpAddress, intportnum);
+ return false;
+ }
+ LOG.debug("Succesfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
+ "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber);
+
+ } else {
+ LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
+ newNaptSwitch,oldNaptSwitch);
+ return false;
+ }
+ }
+ }
+ return true;
+ }*/
+
+ private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch,Long routerVpnId) {
+
+ LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
+ IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
+ if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+ LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
+ "newNaptSwitch {}", routerId, newNaptSwitch);
+ return true;
+ }
+ //getvpnId
+ Long vpnId = getVpnIdForRouter(routerId);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId for routerId {}",routerId);
+ return false;
+ }
+ Long bgpVpnId;
+ if(routerId.equals(routerVpnId)) {
+ bgpVpnId = NatConstants.INVALID_ID;
+ } else {
+ bgpVpnId = routerVpnId;
+ }
+ LOG.debug("retrieved bgpVpnId {} for router {}",bgpVpnId,routerId);
+ for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
+ if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
+ LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
+ return true;
+ }
+ for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
+ String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
+ String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
+
+ //Get the external IP address and the port from the model
+ NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
+ ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
+ IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
+ internalIpAddress, intportnum, proto);
+ if (ipPortExternal == null) {
+ LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
+ continue;
+ }
+ String externalIpAddress = ipPortExternal.getIpAddress();
+ Integer extportNumber = ipPortExternal.getPortNum();
+ LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
+ internalIpAddress,intportnum);
+
+ SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
+ SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
+
+ //checking naptSwitch status before installing flows
+ if(getSwitchStatus(newNaptSwitch)) {
+ //Install the flow in newNaptSwitch Outbound NAPT table.
+ try {
+ NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
+ vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto);
+ } catch (Exception ex) {
+ LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
+ "extIpport {}:{} BgpVpnId {} - {}", routerId, newNaptSwitch, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
+ return false;
+ }
+ LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
+ "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
+ //Install the flow in newNaptSwitch Inbound NAPT table.
+ try {
+ NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+ vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto);
+ } catch (Exception ex) {
+ LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} " +
+ "ipport {}:{} BgpVpnId {}", routerId, newNaptSwitch, externalAddress, extportNumber, proto,
+ internalIpAddress, intportnum,bgpVpnId);
+ return false;
+ }
+ LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
+ "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
+ , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
+
+ } else {
+ LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
+ newNaptSwitch,oldNaptSwitch);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private Long getVpnIdForRouter(Long routerId) {
+ try {
+ //getvpnId
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
+ if (networkId == null) {
+ LOG.debug("network is not associated to router {}", routerId);
+ } else {
+ Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+ if (vpnUuid == null) {
+ LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
+ } else {
+ Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+ if (vpnId > 0) {
+ LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
+ return vpnId;
+ } else {
+ LOG.debug("retrieved invalid vpn Id");
+ }
+ }
+ }
+ } catch (Exception ex){
+ LOG.debug("Exception while retrieving vpnId for router {} - {}", routerId, ex);
+ }
+ return NatConstants.INVALID_ID;
+ }
+
+/*
+ private List<BigInteger> getDpnListForRouter(String routerName) {
+ long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
+ if (bgpVpnId != NatConstants.INVALID_ID) {
+ return NatUtil.getDpnsForRouter(dataBroker, routerName);
+ }
+ List<BigInteger> dpnList = new ArrayList<BigInteger>();
+ List<VpnToDpnList> vpnDpnList = NatUtil.getVpnToDpnList(dataBroker, routerName);
+ if (vpnDpnList == null || vpnDpnList.isEmpty()) {
+ LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
+ dpnList = NatUtil.getDpnsForRouter(dataBroker, routerName);
+ if(dpnList == null || dpnList.isEmpty()){
+ LOG.debug("NAT Service : No switches are part of router {}", routerName);
+ LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
+ }
+ } else {
+ for (VpnToDpnList vpnToDpn : vpnDpnList) {
+ dpnList.add(vpnToDpn.getDpnId());
+ }
+ }
+ return dpnList;
+ }
+*/
+
+ public boolean getSwitchStatus(BigInteger switchId){
+ NodeId nodeId = new NodeId("openflow:" + switchId);
+ LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
+ InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, new NodeKey(nodeId)).build();
+ Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
+ if (nodeOptional.isPresent()) {
+ LOG.debug("Switch {} is up", nodeId);
+ return true;
+ }
+ LOG.debug("Switch {} is down", nodeId);
+ return false;
+ }
+
+ public List<BucketInfo> handleGroupInPrimarySwitch() {
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
+ listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
+ new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(bucketPrimary);
+ return listBucketInfo;
+ }
+
+ public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
+ List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+ String ifNamePrimary;
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return listBucketInfo;
+ }
+ ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
+ if (ifNamePrimary != null) {
+ LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
+ List<ActionInfo> listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ listBucketInfo.add(bucketPrimary);
+ } else {
+ LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
+ }
+ return listBucketInfo;
+ }
+
+ protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+ GroupEntity groupEntity = null;
+ try {
+ long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+ LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
+ groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+ GroupTypes.GroupAll, bucketInfo);
+ mdsalManager.installGroup(groupEntity);
+ LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
+ } catch (Exception ex) {
+ LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
+ }
+ }
+
+ private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+ installSnatGroupEntry(dpnId,bucketInfo,routerName);
+ LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
+ }
+
+ protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
+ RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
+
+ try {
+ Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
+ new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId).
+// .setTunnelType(tunType).
+ build());
+ rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ tunType = TunnelTypeGre.class;
+ result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+ .setSourceDpid(srcDpId)
+ .setDestinationDpid(dstDpId)
+// .setTunnelType(tunType)
+ .build());
+ rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+ } else {
+ return rpcResult.getResult().getInterfaceName();
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {} : {}",
+ srcDpId, dstDpId, e);
+ }
+
+ return null;
+ }
+
+ protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
+ LOG.debug("getEgressActionsForInterface called for interface {}", ifName);
+ List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
+ try {
+ Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+ interfaceManager.getEgressActionsForInterface(
+ new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
+ RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+ if(!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}"
+ , ifName, rpcResult.getErrors());
+ } else {
+ List<Action> actions =
+ rpcResult.getResult().getAction();
+ for (Action action : actions) {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
+ if (actionClass instanceof OutputActionCase) {
+ listActionInfo.add(new ActionInfo(ActionType.output,
+ new String[] {((OutputActionCase)actionClass).getOutputAction()
+ .getOutputNodeConnector().getValue()}));
+ } else if (actionClass instanceof PushVlanActionCase) {
+ listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
+ } else if (actionClass instanceof SetFieldCase) {
+ if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
+ int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch()
+ .getVlanId().getVlanId().getValue();
+ listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
+ new String[] { Long.toString(vlanVid) }));
+ }
+ }
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when egress actions for interface {}", ifName, e);
+ }
+ return listActionInfo;
+ }
+
+ public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+ RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
+ .setPrimarySwitchId(naptSwitchId).build();
+ try {
+ MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+ NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
+ } catch (Exception ex) {
+ LOG.error("Failed to write naptSwitch {} for router {} in ds",
+ naptSwitchId,routerName);
+ return false;
+ }
+ LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
+ naptSwitchId,routerName);
+ return true;
+ }
+
+ /*public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, int addordel) {
+
+ FlowEntity flowEntity;
+ long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return null;
+ }
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[]{ 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+
+ if (addordel == NatConstants.ADD_FLOW) {
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+ ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+ BigInteger.valueOf(routerId)}) ;
+ actionsInfo.add(actionSetField);
+ LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
+ actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+
+ flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ } else {
+ flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, null);
+ }
+ return flowEntity;
+ }*/
+
+ public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, long routerVpnId, int addordel) {
+
+ FlowEntity flowEntity;
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[]{ 0x0800L }));
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
+
+ if (addordel == NatConstants.ADD_FLOW) {
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
+
+ ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
+ BigInteger.valueOf(routerVpnId)}) ;
+ actionsInfo.add(actionSetField);
+ LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
+ actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
+
+ flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
+ } else {
+ flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
+ NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_SNAT_TABLE, matches, null);
+ }
+ return flowEntity;
+ }
+
+ private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+ return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ /*protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch) {
+ //36 -> 46 ..Install flow forwarding packet to table46 from table36
+ LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
+ externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
+
+ //Install default flows punting to controller in table 46(OutBoundNapt table)
+ LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
+ externalRouterListener.installOutboundMissEntry(routerName, naptSwitch);
+
+ //Table 47 point to table 21 for inbound traffic
+ LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for routerId {}", naptSwitch, routerId);
+ externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
+
+ String vpnName = getExtNetworkVpnName(routerId);
+ if(vpnName != null) {
+ //Table 47 point to table 21 for outbound traffic
+ long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ if(vpnId > 0) {
+ LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for vpnId {}", naptSwitch, vpnId);
+ externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
+ } else {
+ LOG.debug("Associated vpnId not found for router {}",routerId);
+ }
+
+ //Install Fib entries for ExternalIps & program 36 -> 44
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+ if (externalIps != null) {
+ for (String externalIp : externalIps) {
+ LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
+ naptSwitch, vpnName, externalIp);
+ externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+ vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+ LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
+ routerId, externalIp);
+ }
+ } else {
+ LOG.debug("External Ip not found for routerId {}",routerId);
+ }
+ } else {
+ LOG.debug("Associated vpnName not found for router {}",routerId);
+ }
+ }*/
+
+ protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch,Long routerVpnId) {
+
+ if(routerId.equals(routerVpnId)) {
+ LOG.debug("Installing flows for router with internalvpnId");
+ //36 -> 46 ..Install flow forwarding packet to table46 from table36
+ LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
+ naptSwitch, routerName,routerId);
+ externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
+
+ //Install default flows punting to controller in table 46(OutBoundNapt table)
+ LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
+ naptSwitch, routerName, routerId);
+ externalRouterListener.createOutboundTblEntry(naptSwitch, routerId);
+
+ //Table 47 point to table 21 for inbound traffic
+ LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {}", naptSwitch, routerId);
+ externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
+ } else {
+ //36 -> 46 ..Install flow forwarding packet to table46 from table36
+ LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
+ naptSwitch, routerName, routerVpnId);
+ externalRouterListener.installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerVpnId);
+
+ //Install default flows punting to controller in table 46(OutBoundNapt table)
+ LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
+ naptSwitch, routerName, routerVpnId);
+ externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
+
+ //Table 47 point to table 21 for inbound traffic
+ LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {} with BgpVpnId {}",
+ naptSwitch, routerId, routerVpnId);
+ externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
+ }
+
+ String vpnName = getExtNetworkVpnName(routerId);
+ if(vpnName != null) {
+ //Table 47 point to table 21 for outbound traffic
+ long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ if(vpnId > 0) {
+ LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for BgpVpnId {}", naptSwitch, vpnId);
+ externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
+ } else {
+ LOG.debug("Associated BgpvpnId not found for router {}",routerId);
+ }
+
+ //Install Fib entries for ExternalIps & program 36 -> 44
+ List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+ if (externalIps != null) {
+ for (String externalIp : externalIps) {
+ LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
+ naptSwitch, vpnName, externalIp);
+ externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
+ vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
+ LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
+ routerId, externalIp);
+ }
+ } else {
+ LOG.debug("External Ip not found for routerId {}",routerId);
+ }
+ } else {
+ LOG.debug("Associated vpnName not found for router {}",routerId);
+ }
+ }
+}
\ 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.natservice.internal;
+
+import java.math.BigInteger;
+
+
+public class NatConstants {
+ public static final short INBOUND_NAPT_TABLE = 44;
+ public static final short OUTBOUND_NAPT_TABLE = 46;
+ public static final short NAPT_PFIB_TABLE = 47;
+ public static final short TERMINATING_SERVICE_TABLE = 36;
+ public static final short DEFAULT_NAPT_FLOW_PRIORITY = 10;
+ public static final String NAPT_FLOW_NAME = "SNAT";
+ public static BigInteger COOKIE_NAPT_BASE = new BigInteger("8000000", 16);
+ public static final String NAPT_FLOWID_PREFIX = "SNAT.";
+ public static final String FLOWID_SEPARATOR = ".";
+ public static final int DEFAULT_NAPT_IDLE_TIMEOUT = 300;
+ public static int EVENT_QUEUE_LENGTH = 1000000;
+ public static final short PDNAT_TABLE = 25;
+ public static final short DNAT_TABLE = 27;
+ public static final short SNAT_TABLE = 28;
+ public static final short PSNAT_TABLE = 26;
+ public static final short L3_FIB_TABLE = 21;
+ public static final String FLOWID_PREFIX = "L3.";
+ public static final int DEFAULT_DNAT_FLOW_PRIORITY = 10;
+ public static final BigInteger COOKIE_DNAT_TABLE = new BigInteger("8000004", 16);
+ public static final long INVALID_ID = -1;
+ public static final BigInteger COOKIE_OUTBOUND_NAPT_TABLE = new BigInteger("8000008", 16);
+ public static final short DEFAULT_SNAT_FLOW_PRIORITY = 10;
+ public static final short DEFAULT_PSNAT_FLOW_PRIORITY = 5;
+ public static final String SNAT_FLOW_NAME = "SNAT";
+ public static final String SNAT_FLOWID_PREFIX = "SNAT.";
+ public static final BigInteger COOKIE_SNAT_TABLE = new BigInteger("8000006", 16);
+ public static final String SNAT_IDPOOL_NAME = "snatGroupIdPool";
+ public static final long SNAT_ID_LOW_VALUE = 200000L;
+ public static final long SNAT_ID_HIGH_VALUE = 225000L;
+ public static final int DEFAULT_TS_FLOW_PRIORITY = 10;
+ public static final BigInteger COOKIE_TS_TABLE = new BigInteger("8000002", 16);
+ public static final short DEFAULT_PREFIX = 32;
+
+ // Flow Actions
+ public static final int ADD_FLOW = 0;
+ public static final int DEL_FLOW = 1;
+
+}
--- /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.natservice.internal;
+
+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.mdsalutil.AbstractDataChangeListener;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+
+public class NatNodeEventListener extends AbstractDataChangeListener<Node> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NatNodeEventListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private NaptSwitchHA naptSwitchHA;
+
+ public NatNodeEventListener(final DataBroker db,final NaptSwitchHA napt) {
+ super(Node.class);
+ naptSwitchHA = napt;
+ registerListener(db);
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), NatNodeEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("NatNodeEventListener: DataChange listener registration fail!", e);
+ throw new IllegalStateException("NatNodeEventListener: registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<Node> getWildCardPath() {
+ return InstanceIdentifier.create(Nodes.class).child(Node.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Node> identifier, Node del) {
+ LOG.debug("NatNodeEventListener: Node removed received");
+ NodeId nodeId = del.getId();
+ String[] node = nodeId.getValue().split(":");
+ if(node.length < 2) {
+ LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+ return;
+ }
+ BigInteger dpnId = new BigInteger(node[1]);
+ LOG.debug("NodeId removed is {}",dpnId);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Node> identifier, Node add) {
+ LOG.debug("NatNodeEventListener: Node added received");
+ NodeId nodeId = add.getId();
+ String[] node = nodeId.getValue().split(":");
+ if(node.length < 2) {
+ LOG.warn("Unexpected nodeId {}", nodeId.getValue());
+ return;
+ }
+ BigInteger dpnId = new BigInteger(node[1]);
+ LOG.debug("NodeId added is {}",dpnId);
+ }
+
+ @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("NatNodeEventListener 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.natservice.internal;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+public class NatServiceProvider implements BindingAwareProvider, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NatServiceProvider.class);
+ private IMdsalApiManager mdsalManager;
+ private RpcProviderRegistry rpcProviderRegistry;
+ private NotificationService notificationService;
+ private ItmRpcService itmManager;
+ private FloatingIPListener floatingIpListener;
+ private ExternalNetworkListener extNwListener;
+ private NaptManager naptManager;
+ private NaptEventHandler naptEventHandler;
+ private BlockingQueue<NAPTEntryEvent> naptEventQueue;
+ private ExternalNetworksChangeListener externalNetworksChangeListener;
+ private ExternalRoutersListener externalRouterListener;
+ private NaptPacketInHandler naptPacketInHandler;
+ private EventDispatcher eventDispatcher;
+ private IBgpManager bgpManager;
+ private NaptFlowRemovedEventHandler naptFlowRemovedEventHandler;
+ private InterfaceStateEventListener interfaceStateEventListener;
+ private NatNodeEventListener natNodeEventListener;
+ private NAPTSwitchSelector naptSwitchSelector;
+ private RouterPortsListener routerPortsListener;
+
+ public NatServiceProvider(RpcProviderRegistry rpcProviderRegistry) {
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ }
+
+ public void setNotificationService(NotificationService notificationService) {
+ this.notificationService = notificationService;
+ }
+
+ public void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setBgpManager(IBgpManager bgpManager) {
+ LOG.debug("BGP Manager reference initialized");
+ this.bgpManager = bgpManager;
+ }
+
+ @Override
+ public void close() throws Exception {
+ floatingIpListener.close();
+ extNwListener.close();
+ externalNetworksChangeListener.close();
+ externalRouterListener.close();
+ routerPortsListener.close();
+ }
+
+ @Override
+ public void onSessionInitiated(ProviderContext session) {
+ LOG.info("NAT Manager Provider Session Initiated");
+ try {
+ //Get the DataBroker, PacketProcessingService, IdManagerService and the OdlInterfaceRpcService instances
+ final DataBroker dataBroker = session.getSALService(DataBroker.class);
+ PacketProcessingService pktProcessingService = session.getRpcService(PacketProcessingService.class);
+ IdManagerService idManager = rpcProviderRegistry.getRpcService(IdManagerService.class);
+ OdlInterfaceRpcService interfaceService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class);
+ NeutronvpnService neutronvpnService = rpcProviderRegistry.getRpcService(NeutronvpnService.class);
+ itmManager = rpcProviderRegistry.getRpcService(ItmRpcService.class);
+
+ //Instantiate FloatingIPListener and set the MdsalManager and OdlInterfaceRpcService in it.
+ floatingIpListener = new FloatingIPListener(dataBroker);
+ floatingIpListener.setInterfaceManager(interfaceService);
+ floatingIpListener.setMdsalManager(mdsalManager);
+
+ //Instantiate ExternalNetworkListener and set the MdsalManager in it.
+ extNwListener = new ExternalNetworkListener(dataBroker);
+ extNwListener.setMdsalManager(mdsalManager);
+
+ //Instantiate NaptManager and set the IdManagerService in it.
+ naptManager = new NaptManager(dataBroker);
+ naptManager.setIdManager(idManager);
+
+ //Instantiate NaptEventHandler and start it as a Thread.
+ naptEventHandler = new NaptEventHandler(dataBroker);
+ naptEventHandler.setMdsalManager(mdsalManager);
+ naptEventHandler.setNaptManager(naptManager);
+ naptEventQueue = new ArrayBlockingQueue<>(NatConstants.EVENT_QUEUE_LENGTH);
+ eventDispatcher = new EventDispatcher(naptEventQueue, naptEventHandler);
+ new Thread(eventDispatcher).start();
+
+ //Instantiate NaptPacketInHandler and register it in the notification service.
+ naptPacketInHandler = new NaptPacketInHandler(eventDispatcher);
+ notificationService.registerNotificationListener(naptPacketInHandler);
+
+ //Floating ip Handler
+ VpnRpcService vpnService = rpcProviderRegistry.getRpcService(VpnRpcService.class);
+ FibRpcService fibService = rpcProviderRegistry.getRpcService(FibRpcService.class);
+ VpnFloatingIpHandler handler = new VpnFloatingIpHandler(vpnService, bgpManager, fibService);
+ handler.setBroker(dataBroker);
+ handler.setMdsalManager(mdsalManager);
+ handler.setListener(floatingIpListener);
+ floatingIpListener.setFloatingIpHandler(handler);
+
+ //Instantiate NaptSwitchSelector and set the dataBroker in it.
+ naptSwitchSelector = new NAPTSwitchSelector( dataBroker );
+
+ //Instantiate ExternalRouterListener and set the dataBroker in it.
+ externalRouterListener = new ExternalRoutersListener( dataBroker );
+ externalRouterListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker );
+ externalRouterListener.setMdsalManager(mdsalManager);
+ externalRouterListener.setItmManager(itmManager);
+ externalRouterListener.setInterfaceManager(interfaceService);
+ externalRouterListener.setIdManager(idManager);
+ externalRouterListener.setNaptManager(naptManager);
+ externalRouterListener.setBgpManager(bgpManager);
+ externalRouterListener.setFibService(fibService);
+ externalRouterListener.setVpnService(vpnService);
+ externalRouterListener.setNaptSwitchSelector(naptSwitchSelector);
+ externalRouterListener.setNaptEventHandler(naptEventHandler);
+ externalRouterListener.setNaptPacketInHandler(naptPacketInHandler);
+
+ //Instantiate ExternalNetworksChangeListener and set the dataBroker in it.
+ externalNetworksChangeListener = new ExternalNetworksChangeListener( dataBroker );
+ externalNetworksChangeListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+ externalNetworksChangeListener.setMdsalManager(mdsalManager);
+ externalNetworksChangeListener.setInterfaceManager(interfaceService);
+ externalNetworksChangeListener.setFloatingIpListener(floatingIpListener);
+ externalNetworksChangeListener.setBgpManager(bgpManager);
+ externalNetworksChangeListener.setFibService(fibService);
+ externalNetworksChangeListener.setVpnService(vpnService);
+ externalNetworksChangeListener.setExternalRoutersListener(externalRouterListener);
+ externalNetworksChangeListener.setNaptManager(naptManager);
+ externalNetworksChangeListener.setExternalRoutersListener(externalRouterListener);
+
+ //Instantiate NaptFlowRemovedHandler and register it in the notification service.
+ naptFlowRemovedEventHandler = new NaptFlowRemovedEventHandler(eventDispatcher, dataBroker, naptPacketInHandler, mdsalManager, naptManager);
+ notificationService.registerNotificationListener(naptFlowRemovedEventHandler);
+
+ //Instantiate interfaceStateEventListener and set the MdsalManager in it.
+ interfaceStateEventListener = new InterfaceStateEventListener(dataBroker);
+ interfaceStateEventListener.setMdsalManager(mdsalManager);
+ interfaceStateEventListener.setFloatingIpListener(floatingIpListener);
+ interfaceStateEventListener.setNeutronVpnService(neutronvpnService);
+ interfaceStateEventListener.setNaptManager(naptManager);
+
+ SNATDefaultRouteProgrammer defaultRouteProgrammer = new SNATDefaultRouteProgrammer(mdsalManager);
+ DpnInVpnListener dpnInVpnListener = new DpnInVpnListener(dataBroker);
+ dpnInVpnListener.setDefaultProgrammer(defaultRouteProgrammer);
+ notificationService.registerNotificationListener(dpnInVpnListener);
+
+ externalRouterListener.setDefaultProgrammer(defaultRouteProgrammer);
+
+ NaptSwitchHA naptSwitchHA = new NaptSwitchHA(dataBroker,naptSwitchSelector);
+ naptSwitchHA.setIdManager(idManager);
+ naptSwitchHA.setInterfaceManager(interfaceService);
+ naptSwitchHA.setMdsalManager(mdsalManager);
+ naptSwitchHA.setItmManager(itmManager);
+ naptSwitchHA.setBgpManager(bgpManager);
+ naptSwitchHA.setFibService(fibService);
+ naptSwitchHA.setVpnService(vpnService);
+ naptSwitchHA.setExternalRoutersListener(externalRouterListener);
+
+ natNodeEventListener = new NatNodeEventListener(dataBroker,naptSwitchHA);
+
+ dpnInVpnListener.setNaptSwitchHA(naptSwitchHA);
+ dpnInVpnListener.setMdsalManager(mdsalManager);
+ dpnInVpnListener.setIdManager(idManager);
+
+ routerPortsListener = new RouterPortsListener(dataBroker);
+
+ RouterDpnChangeListener routerDpnChangeListener = new RouterDpnChangeListener(dataBroker);
+ routerDpnChangeListener.setDefaultProgrammer(defaultRouteProgrammer);
+ routerDpnChangeListener.setIdManager(idManager);
+ routerDpnChangeListener.setMdsalManager(mdsalManager);
+ routerDpnChangeListener.setNaptSwitchHA(naptSwitchHA);
+
+ RouterToVpnListener routerToVpnListener = new RouterToVpnListener(dataBroker);
+ routerToVpnListener.setFloatingIpListener(floatingIpListener);
+ routerToVpnListener.setInterfaceManager(interfaceService);
+ routerToVpnListener.setExternalRoutersListener(externalRouterListener);
+ notificationService.registerNotificationListener(routerToVpnListener);
+ } catch (Exception e) {
+ LOG.error("Error initializing NAT Manager service", e);
+ }
+ }
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
+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.natservice.rev160111.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCountersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.RouterToVpnMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.Routermapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.VpnMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.NetworksKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.DpnEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfoKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+
+
+public class NatUtil {
+
+ private static String OF_URI_SEPARATOR = ":";
+ private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);
+
+ /*
+ getCookieSnatFlow() computes and returns a unique cookie value for the NAT flows using the router ID as the reference value.
+ */
+ public static BigInteger getCookieSnatFlow(long routerId) {
+ return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0110000", 16)).add(
+ BigInteger.valueOf(routerId));
+ }
+
+ /*
+ getCookieNaptFlow() computes and returns a unique cookie value for the NAPT flows using the router ID as the reference value.
+ */
+ public static BigInteger getCookieNaptFlow(long routerId) {
+ return NatConstants.COOKIE_NAPT_BASE.add(new BigInteger("0111000", 16)).add(
+ BigInteger.valueOf(routerId));
+ }
+
+ /*
+ getVpnId() returns the VPN ID from the VPN name
+ */
+ public static long getVpnId(DataBroker broker, String vpnName) {
+ if(vpnName == null) {
+ return NatConstants.INVALID_ID;
+ }
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+ = getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ long vpnId = NatConstants.INVALID_ID;
+ if(vpnInstance.isPresent()) {
+ vpnId = vpnInstance.get().getVpnId();
+ }
+ return vpnId;
+ }
+
+ public static Long getVpnId(DataBroker broker, long routerId){
+ //Get the external network ID from the ExternalRouter model
+ Uuid networkId = NatUtil.getNetworkIdFromRouterId(broker, routerId);
+ if(networkId == null ){
+ LOG.error("NAT Service : networkId is null");
+ return null;
+ }
+
+ //Get the VPN ID from the ExternalNetworks model
+ Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(broker, networkId);
+ if(vpnUuid == null ){
+ LOG.error("NAT Service : vpnUuid is null");
+ return null;
+ }
+ Long vpnId = NatUtil.getVpnId(broker, vpnUuid.getValue());
+ return vpnId;
+ }
+
+ static InstanceIdentifier<RouterPorts> getRouterPortsId(String routerId) {
+ return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId)).build();
+ }
+
+ static InstanceIdentifier<Routermapping> getRouterVpnMappingId(String routerId) {
+ return InstanceIdentifier.builder(RouterToVpnMapping.class).child(Routermapping.class, new RoutermappingKey(routerId)).build();
+ }
+
+ static InstanceIdentifier<Ports> getPortsIdentifier(String routerId, String portName) {
+ return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
+ .child(Ports.class, new PortsKey(portName)).build();
+ }
+
+ static InstanceIdentifier<IpMapping> getIpMappingIdentifier(String routerId, String portName, String internalIp) {
+ return InstanceIdentifier.builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerId))
+ .child(Ports.class, new PortsKey(portName))
+ .child(IpMapping.class, new IpMappingKey(internalIp)).build();
+ }
+
+ /*
+ getVpnInstanceToVpnIdIdentifier() returns the VPN instance from the below model using the VPN name as the key.
+ list vpn-instance {
+ key "vpn-instance-name"
+ leaf vpn-instance-name {
+ type string;
+ }
+ leaf vpn-id {
+ type uint32;
+ }
+ leaf vrf-id {
+ type string;
+ }
+ }
+ */
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+ getVpnInstanceToVpnIdIdentifier(String vpnName) {
+ return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
+ }
+
+ /*
+ getFlowRef() returns a string identfier for the SNAT flows using the router ID as the reference.
+ */
+ public static String getFlowRef(BigInteger dpnId, short tableId, long routerID, String ip) {
+ return new StringBuffer().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID)
+ .append(NatConstants.FLOWID_SEPARATOR).append(ip).toString();
+ }
+
+ public static String getNaptFlowRef(BigInteger dpnId, short tableId, String routerID, String ip, int port) {
+ return new StringBuffer().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).append(NatConstants.FLOWID_SEPARATOR).append(ip).
+ append(NatConstants.FLOWID_SEPARATOR).append(port).toString();
+ }
+
+ /*
+ getNetworkIdFromRouterId() returns the network-id from the below model using the router-id as the key
+ container ext-routers {
+ list routers {
+ key router-name;
+ leaf router-name { type string; }
+ leaf network-id { type yang:uuid; }
+ leaf enable-snat { type boolean; }
+ leaf-list external-ips {
+ type string; //format - ipaddress\prefixlength
+ }
+ leaf-list subnet-ids { type yang:uuid; }
+ }
+ }
+
+ */
+ static Uuid getNetworkIdFromRouterId(DataBroker broker, long routerId) {
+ String routerName = getRouterName(broker, routerId);
+ InstanceIdentifier id = buildRouterIdentifier(routerName);
+ Optional<Routers> routerData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ return routerData.get().getNetworkId();
+ }
+ return null;
+ }
+
+ static InstanceIdentifier<Routers> buildRouterIdentifier(String routerId) {
+ InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
+ (Routers.class, new RoutersKey(routerId)).build();
+ return routerInstanceIndentifier;
+ }
+
+ /*
+ * getEnableSnatFromRouterId() returns IsSnatEnabled true is routerID is present in external n/w otherwise returns false
+ */
+ static boolean isSnatEnabledForRouterId(DataBroker broker, String routerId){
+ InstanceIdentifier id = buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ return routerData.get().isEnableSnat();
+ }
+ return false;
+ }
+ /*
+ getVpnIdfromNetworkId() returns the vpnid from the below model using the network ID as the key.
+ container external-networks {
+ list networks {
+ key id;
+ leaf id {
+ type yang:uuid;
+ }
+ leaf vpnid { type yang:uuid; }
+ leaf-list router-ids { type yang:uuid; }
+ leaf-list subnet-ids{ type yang:uuid; }
+ }
+ }
+ */
+ public static Uuid getVpnIdfromNetworkId(DataBroker broker, Uuid networkId) {
+ InstanceIdentifier id = buildNetworkIdentifier(networkId);
+ Optional<Networks> networkData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (networkData.isPresent()) {
+ return networkData.get().getVpnid();
+ }
+ return null;
+ }
+
+ static String getAssociatedExternalNetwork(DataBroker dataBroker, String routerId) {
+ InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ Uuid networkId = routerData.get().getNetworkId();
+ if(networkId != null) {
+ return networkId.getValue();
+ }
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<Networks> buildNetworkIdentifier(Uuid networkId) {
+ InstanceIdentifier<Networks> network = InstanceIdentifier.builder(ExternalNetworks.class).child
+ (Networks.class, new NetworksKey(networkId)).build();
+ return network;
+ }
+
+
+
+
+ /*
+ getNaptSwitchesDpnIdsfromRouterId() returns the primary-switch-id and the secondary-switch-id in a array using the router-id; as the key.
+ container napt-switches {
+ list router-to-napt-switch {
+ key router-id;
+ leaf router-id { type uint32; }
+ leaf primary-switch-id { type uint64; }
+ leaf secondary-switch-id { type uint64; }
+ }
+ }
+ */
+ public static BigInteger getPrimaryNaptfromRouterId(DataBroker broker, Long routerId) {
+ // convert routerId to Name
+ String routerName = getRouterName(broker, routerId);
+ InstanceIdentifier id = buildNaptSwitchIdentifier(routerName);
+ Optional<RouterToNaptSwitch> routerToNaptSwitchData = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (routerToNaptSwitchData.isPresent()) {
+ RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
+ return routerToNaptSwitchInstance.getPrimarySwitchId();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchIdentifier(String routerId) {
+ InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class).child
+ (RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerId)).build();
+ return rtrNaptSw;
+ }
+
+ public static String getRouterName(DataBroker broker, Long routerId) {
+ InstanceIdentifier id = buildRouterIdentifier(routerId);
+ Optional<RouterIds> routerIdsData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerIdsData.isPresent()) {
+ RouterIds routerIdsInstance = routerIdsData.get();
+ return routerIdsInstance.getRouterName();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<RouterIds> buildRouterIdentifier(Long routerId) {
+ InstanceIdentifier<RouterIds> routerIds = InstanceIdentifier.builder(RouterIdName.class).child
+ (RouterIds.class, new RouterIdsKey(routerId)).build();
+ return routerIds;
+ }
+
+ public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+ InstanceIdentifier<T> path) {
+
+ ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+ Optional<T> result = Optional.absent();
+ try {
+ result = tx.read(datastoreType, path).get();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return result;
+ }
+
+ static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String vrfId) {
+ return InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vrfId)).build();
+ }
+
+ public static long readVpnId(DataBroker broker, String vpnName) {
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+ = getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ long vpnId = NatConstants.INVALID_ID;
+ if(vpnInstance.isPresent()) {
+ vpnId = vpnInstance.get().getVpnId();
+ }
+ return vpnId;
+ }
+
+ public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, BigInteger cookie) {
+ FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(tableId);
+ flowEntity.setCookie(cookie);
+ return flowEntity;
+ }
+
+ public static long getIpAddress(byte[] rawIpAddress) {
+ return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
+ + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
+ }
+
+ public static String getFlowRef(BigInteger dpnId, short tableId, InetAddress destPrefix) {
+ return new StringBuilder(64).append(NatConstants.FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(destPrefix.getHostAddress()).toString();
+ }
+
+ public static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
+ String nextHopIp = null;
+ InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
+ InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
+ Optional<DPNTEPsInfo> tunnelInfo = read(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
+ if (tunnelInfo.isPresent()) {
+ List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
+ if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
+ nextHopIp = nexthopIpList.get(0).getIpAddress().getIpv4Address().getValue();
+ }
+ }
+ return nextHopIp;
+ }
+
+ /*
+ getVpnRd returns the rd (route distinguisher) which is the VRF ID from the below model using the vpnName
+ list vpn-instance {
+ key "vpn-instance-name"
+ leaf vpn-instance-name {
+ type string;
+ }
+ leaf vpn-id {
+ type uint32;
+ }
+ leaf vrf-id {
+ type string;
+ }
+ }
+ */
+ public static String getVpnRd(DataBroker broker, String vpnName) {
+
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
+ = getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ String rd = null;
+ if(vpnInstance.isPresent()) {
+ rd = vpnInstance.get().getVrfId();
+ }
+ return rd;
+ }
+
+ /* getExternalIPPortMap() returns the internal IP and the port for the querried router ID, external IP and the port.
+ container intext-ip-port-map {
+ config true;
+ list ip-port-mapping {
+ key router-id;
+ leaf router-id { type uint32; }
+ list intext-ip-protocol-type {
+ key protocol;
+ leaf protocol { type protocol-types; }
+ list ip-port-map {
+ key ip-port-internal;
+ description "internal to external ip-port mapping";
+ leaf ip-port-internal { type string; }
+ container ip-port-external {
+ uses ip-port-entity;
+ }
+ }
+ }
+ }
+ }
+ */
+ public static IpPortExternal getExternalIpPortMap(DataBroker broker, Long routerId, String internalIpAddress, String internalPort, NAPTEntryEvent.Protocol protocol) {
+ ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+ InstanceIdentifier ipPortMapId = buildIpToPortMapIdentifier(routerId, internalIpAddress, internalPort, protocolType);
+ Optional<IpPortMap> ipPortMapData = read(broker, LogicalDatastoreType.CONFIGURATION, ipPortMapId);
+ if (ipPortMapData.isPresent()) {
+ IpPortMap ipPortMapInstance = ipPortMapData.get();
+ return ipPortMapInstance.getIpPortExternal();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<IpPortMap> buildIpToPortMapIdentifier(Long routerId, String internalIpAddress, String internalPort , ProtocolTypes protocolType) {
+ InstanceIdentifier<IpPortMap> ipPortMapId = InstanceIdentifier.builder(IntextIpPortMap.class).child
+ (IpPortMapping.class, new IpPortMappingKey(routerId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
+ .child(IpPortMap.class, new IpPortMapKey(internalIpAddress + ":" + internalPort)).build();
+ return ipPortMapId;
+ }
+
+ public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId, int priority, String flowName,
+ BigInteger cookie, List<MatchInfo> listMatchInfo) {
+
+ FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(tableId);
+ flowEntity.setFlowId(flowId);
+ flowEntity.setPriority(priority);
+ flowEntity.setFlowName(flowName);
+ flowEntity.setCookie(cookie);
+ flowEntity.setMatchInfoList(listMatchInfo);
+ return flowEntity;
+ }
+
+ static boolean isVpnInterfaceConfigured(DataBroker broker, String interfaceName)
+ {
+ InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
+ Optional<VpnInterface> configuredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
+
+ if (configuredVpnInterface.isPresent()) {
+ return true;
+ }
+ return false;
+ }
+
+ static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
+ return InstanceIdentifier.builder(VpnInterfaces.class)
+ .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
+ }
+
+ static VpnInterface getConfiguredVpnInterface(DataBroker broker, String interfaceName) {
+ InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
+ Optional<VpnInterface> configuredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
+
+ if (configuredVpnInterface.isPresent()) {
+ return configuredVpnInterface.get();
+ }
+ return null;
+ }
+
+ public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
+ /*
+ * NodeConnectorId is of form 'openflow:dpnid:portnum'
+ */
+ String[] split = portId.getValue().split(OF_URI_SEPARATOR);
+ return split[1];
+ }
+
+ public static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
+ String lowerLayerIf = ifState.getLowerLayerIf().get(0);
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
+ return new BigInteger(getDpnFromNodeConnectorId(nodeConnectorId));
+ }
+
+
+ /*
+ container vpnMaps {
+ list vpnMap {
+ key vpn-id;
+ leaf vpn-id {
+ type yang:uuid;
+ description "vpn-id";
+ }
+ leaf name {
+ type string;
+ description "vpn name";
+ }
+ leaf tenant-id {
+ type yang:uuid;
+ description "The UUID of the tenant that will own the subnet.";
+ }
+
+ leaf router-id {
+ type yang:uuid;
+ description "UUID of router ";
+ }
+ leaf-list network_ids {
+ type yang:uuid;
+ description "UUID representing the network ";
+ }
+ }
+ }
+ Method returns router Id associated to a VPN
+ */
+
+ public static String getRouterIdfromVpnId(DataBroker broker,String vpnName){
+ InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
+ .child(VpnMap.class, new VpnMapKey(new Uuid(vpnName))).build();
+ Optional<VpnMap> optionalVpnMap = read(broker, LogicalDatastoreType.CONFIGURATION,
+ vpnMapIdentifier);
+ if (optionalVpnMap.isPresent()) {
+ return optionalVpnMap.get().getRouterId().getValue();
+ }
+ return null;
+ }
+
+ static Uuid getVpnForRouter(DataBroker broker, String routerId) {
+ InstanceIdentifier<VpnMaps> vpnMapsIdentifier = InstanceIdentifier.builder(VpnMaps.class).build();
+ Optional<VpnMaps> optionalVpnMaps = read(broker, LogicalDatastoreType.CONFIGURATION,
+ vpnMapsIdentifier);
+ if (optionalVpnMaps.isPresent() && optionalVpnMaps.get().getVpnMap() != null) {
+ List<VpnMap> allMaps = optionalVpnMaps.get().getVpnMap();
+ if (routerId != null) {
+ for (VpnMap vpnMap : allMaps) {
+ if (vpnMap.getRouterId() != null &&
+ routerId.equals(vpnMap.getRouterId().getValue()) &&
+ !routerId.equals(vpnMap.getVpnId().getValue())) {
+ return vpnMap.getVpnId();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ static long getAssociatedVpn(DataBroker broker, String routerName) {
+ InstanceIdentifier<Routermapping> routerMappingId = NatUtil.getRouterVpnMappingId(routerName);
+ Optional<Routermapping> optRouterMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId);
+ if(optRouterMapping.isPresent()) {
+ Routermapping routerMapping = optRouterMapping.get();
+ return routerMapping.getVpnId();
+ }
+ return NatConstants.INVALID_ID;
+ }
+
+
+ public static List<VpnToDpnList> getVpnToDpnList(DataBroker dataBroker, String vrfId )
+ {
+ List<VpnToDpnList> vpnDpnList = null;
+
+ InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier
+ .builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vrfId))
+ .build();
+
+ Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+
+ if(vpnInstanceOpData.isPresent())
+ {
+ VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpData.get();
+ vpnDpnList = vpnInstanceOpDataEntry.getVpnToDpnList();
+ }
+
+ return vpnDpnList;
+ }
+
+ public static String getAssociatedVPN(DataBroker dataBroker, Uuid networkId, Logger log) {
+ Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
+ if(vpnUuid == null ){
+ log.error("No VPN instance associated with ext network {}", networkId);
+ return null;
+ }
+ return vpnUuid.getValue();
+ }
+
+ public static void addPrefixToBGP(IBgpManager bgpManager, String rd, String prefix, String nextHopIp, long label, Logger log) {
+ try {
+ bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label);
+ } catch(Exception e) {
+ log.error("Add prefix failed", e);
+ }
+ }
+
+ static InstanceIdentifier<Ports> buildPortToIpMapIdentifier(String routerId, String portName) {
+ InstanceIdentifier<Ports> ipPortMapId = InstanceIdentifier.builder(FloatingIpInfo.class).child
+ (RouterPorts.class, new RouterPortsKey(routerId)).child(Ports.class, new PortsKey(portName)).build();
+ return ipPortMapId;
+ }
+
+ static InstanceIdentifier<RouterPorts> buildRouterPortsIdentifier(String routerId) {
+ InstanceIdentifier<RouterPorts> routerInstanceIndentifier = InstanceIdentifier.builder(FloatingIpInfo.class).child
+ (RouterPorts.class, new RouterPortsKey(routerId)).build();
+ return routerInstanceIndentifier;
+ }
+
+ /* container snatint-ip-port-map {
+ list intip-port-map {
+ key router-id;
+ leaf router-id { type uint32; }
+ list ip-port {
+ key internal-ip;
+ leaf internal-ip { type string; }
+ list int-ip-proto-type {
+ key protocol;
+ leaf protocol { type protocol-types; }
+ leaf-list ports { type uint16; }
+ }
+ }
+ }
+ }
+ Method returns InternalIp port List
+ */
+
+ public static List<Integer> getInternalIpPortListInfo(DataBroker dataBroker,Long routerId, String internalIpAddress, ProtocolTypes protocolType){
+ Optional<IntIpProtoType> optionalIpProtoType = read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSnatIntIpPortIdentifier(routerId, internalIpAddress, protocolType));
+ if (optionalIpProtoType.isPresent()) {
+ return optionalIpProtoType.get().getPorts();
+ }
+ return null;
+ }
+
+ public static InstanceIdentifier<IntIpProtoType> buildSnatIntIpPortIdentifier(Long routerId, String internalIpAddress, ProtocolTypes protocolType) {
+ InstanceIdentifier<IntIpProtoType> intIpProtocolTypeId = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+ (IntipPortMap.class, new IntipPortMapKey(routerId)).child(IpPort.class, new IpPortKey(internalIpAddress)).child
+ (IntIpProtoType.class, new IntIpProtoTypeKey(protocolType)).build();
+ return intIpProtocolTypeId;
+ }
+
+ public static ProtocolTypes getProtocolType(NAPTEntryEvent.Protocol protocol) {
+ ProtocolTypes protocolType = ProtocolTypes.TCP.toString().equals(protocol.toString()) ? ProtocolTypes.TCP : ProtocolTypes.UDP;
+ return protocolType;
+ }
+
+ public static NaptSwitches getNaptSwitch(DataBroker broker) {
+ Optional<NaptSwitches> switchesOptional = read(broker, LogicalDatastoreType.OPERATIONAL, getNaptSwitchesIdentifier());
+ if(switchesOptional.isPresent()) {
+ return switchesOptional.get();
+ }
+ return null;
+ }
+
+ public static InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
+ return InstanceIdentifier.create(NaptSwitches.class);
+ }
+
+ public static InstanceIdentifier<RouterToNaptSwitch> buildNaptSwitchRouterIdentifier(String routerId) {
+ return InstanceIdentifier.create(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerId));
+ }
+
+ public static String toStringIpAddress(byte[] ipAddress, Logger log)
+ {
+ String ip = "";
+ if (ipAddress == null) {
+ return ip;
+ }
+
+ try {
+ ip = InetAddress.getByAddress(ipAddress).getHostAddress();
+ } catch(UnknownHostException e) {
+ log.error("NAT Service : Caught exception during toStringIpAddress()");
+ }
+
+ return ip;
+ }
+
+ public static String getGroupIdKey(String routerName){
+ String groupIdKey = new String("snatmiss." + routerName);
+ return groupIdKey;
+ }
+
+ public static long createGroupId(String groupIdKey,IdManagerService idManager) {
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+ .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
+ .build();
+ try {
+ Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+ RpcResult<AllocateIdOutput> rpcResult = result.get();
+ return rpcResult.getResult().getIdValue();
+ } catch (NullPointerException | InterruptedException | ExecutionException e) {
+ LOG.trace("", e);
+ }
+ return 0;
+ }
+
+ public static void removePrefixFromBGP(IBgpManager bgpManager, String rd, String prefix, Logger log) {
+ try {
+ bgpManager.deletePrefix(rd, prefix);
+ } catch(Exception e) {
+ log.error("Delete prefix failed", e);
+ }
+ }
+
+ public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, BigInteger cookie, String flowId) {
+ FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(tableId);
+ flowEntity.setCookie(cookie);
+ flowEntity.setFlowId(flowId);
+ return flowEntity;
+ }
+
+ public static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId) {
+ FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(tableId);
+ flowEntity.setFlowId(flowId);
+ return flowEntity;
+ }
+
+ public static IpPortMapping getIportMapping(DataBroker broker, long routerId) {
+ Optional<IpPortMapping> getIportMappingData = read(broker, LogicalDatastoreType.CONFIGURATION, getIportMappingIdentifier(routerId));
+ if(getIportMappingData.isPresent()) {
+ return getIportMappingData.get();
+ }
+ return null;
+ }
+
+ public static InstanceIdentifier<IpPortMapping> getIportMappingIdentifier(long routerId) {
+ return InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
+ }
+
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> getIpMappingBuilder(Long routerId) {
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerId)).build();
+ return idBuilder;
+ }
+
+ public static List<String> getExternalIpsForRouter(DataBroker dataBroker,Long routerId) {
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMappingOptional = read(dataBroker,
+ LogicalDatastoreType.OPERATIONAL, getIpMappingBuilder(routerId));
+ List<String> externalIps = new ArrayList<>();
+ if (ipMappingOptional.isPresent()) {
+ List<IpMap> ipMaps = ipMappingOptional.get().getIpMap();
+ for (IpMap ipMap : ipMaps) {
+ externalIps.add(ipMap.getExternalIp());
+ }
+ return externalIps;
+ }
+ return null;
+ }
+
+ /*
+ container external-ips-counter {
+ config false;
+ list external-counters{
+ key segment-id;
+ leaf segment-id { type uint32; }
+ list external-ip-counter {
+ key external-ip;
+ leaf external-ip { type string; }
+ leaf counter { type uint8; }
+ }
+ }
+ }
+ */
+
+ public static String getLeastLoadedExternalIp(DataBroker dataBroker, long segmentId){
+ String leastLoadedExternalIp = null;
+ InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId)).build();
+ Optional <ExternalCounters> externalCountersData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ if (externalCountersData.isPresent()) {
+ ExternalCounters externalCounter = externalCountersData.get();
+ List<ExternalIpCounter> externalIpCounterList = externalCounter.getExternalIpCounter();
+ short countOfLstLoadExtIp = 32767;
+ for(ExternalIpCounter externalIpCounter : externalIpCounterList){
+ String curExternalIp = externalIpCounter.getExternalIp();
+ short countOfCurExtIp = externalIpCounter.getCounter();
+ if( countOfCurExtIp < countOfLstLoadExtIp ){
+ countOfLstLoadExtIp = countOfCurExtIp;
+ leastLoadedExternalIp = curExternalIp;
+ }
+ }
+ }
+ return leastLoadedExternalIp;
+ }
+
+ public static String[] getSubnetIpAndPrefix(DataBroker dataBroker, Uuid subnetId){
+ String subnetIP = getSubnetIp(dataBroker, subnetId);
+ if(subnetId != null){
+ return getSubnetIpAndPrefix(subnetIP);
+ }
+ return null;
+ }
+
+ public static String getSubnetIp(DataBroker dataBroker, Uuid subnetId){
+ InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
+ .builder(Subnetmaps.class)
+ .child(Subnetmap.class, new SubnetmapKey(subnetId))
+ .build();
+ Optional<Subnetmap> removedSubnet = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
+ if(removedSubnet.isPresent()) {
+ Subnetmap subnetMapEntry = removedSubnet.get();
+ return subnetMapEntry.getSubnetIp();
+ }
+ return null;
+
+ }
+ public static String[] getSubnetIpAndPrefix(String subnetString){
+ String[] subnetSplit = subnetString.split("/");
+ String subnetIp = subnetSplit[0];
+ String subnetPrefix = "0";
+ if (subnetSplit.length == 2) {
+ subnetPrefix = subnetSplit[1];
+ }
+ return new String[] {subnetIp, subnetPrefix};
+ }
+
+ public static String[] getExternalIpAndPrefix(String leastLoadedExtIpAddr){
+ String[] leastLoadedExtIpAddrSplit = leastLoadedExtIpAddr.split("/");
+ String leastLoadedExtIp = leastLoadedExtIpAddrSplit[0];
+ String leastLoadedExtIpPrefix = String.valueOf(NatConstants.DEFAULT_PREFIX);
+ if (leastLoadedExtIpAddrSplit.length == 2) {
+ leastLoadedExtIpPrefix = leastLoadedExtIpAddrSplit[1];
+ }
+ return new String[] {leastLoadedExtIp, leastLoadedExtIpPrefix};
+ }
+
+ public static List<BigInteger> getDpnsForRouter(DataBroker dataBroker, String routerUuid){
+ InstanceIdentifier id = InstanceIdentifier.builder(NeutronRouterDpns.class).child(RouterDpnList.class, new RouterDpnListKey(routerUuid)).build();
+ Optional<RouterDpnList> routerDpnListData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ List<BigInteger> dpns = new ArrayList<>();
+ if (routerDpnListData.isPresent()) {
+ List<DpnVpninterfacesList> dpnVpninterfacesList = routerDpnListData.get().getDpnVpninterfacesList();
+ for (DpnVpninterfacesList dpnVpnInterface : dpnVpninterfacesList) {
+ dpns.add(dpnVpnInterface.getDpnId());
+ }
+ return dpns;
+ }
+ return null;
+ }
+
+ public static long getBgpVpnId(DataBroker dataBroker, String routerName){
+ long bgpVpnId = NatConstants.INVALID_ID;
+ Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+ if(bgpVpnUuid != null){
+ bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+ }
+ return bgpVpnId;
+ }
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.List;
+
+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.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.*;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class RouterDpnChangeListener extends AbstractDataChangeListener<DpnVpninterfacesList> implements AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker dataBroker;
+ private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+ private NaptSwitchHA naptSwitchHA;
+ private IMdsalApiManager mdsalManager;
+ private IdManagerService idManager;
+
+ public RouterDpnChangeListener (final DataBroker db) {
+ super(DpnVpninterfacesList.class);
+ dataBroker = db;
+ registerListener(db);
+ }
+
+ void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
+ this.defaultRouteProgrammer = defaultRouteProgrammer;
+ }
+
+ void setNaptSwitchHA(NaptSwitchHA switchHA) {
+ naptSwitchHA = switchHA;
+ }
+
+ void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
+ @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("Router ports Listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), RouterDpnChangeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("RouterPorts DataChange listener registration fail!", e);
+ throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
+ return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class).child(DpnVpninterfacesList.class);
+ }
+
+ @Override
+ protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
+ LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
+ final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+ BigInteger dpnId = dpnInfo.getDpnId();
+ //check router is associated to external network
+ InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ Uuid networkId = routerData.get().getNetworkId();
+ if(networkId != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+ Uuid vpnName = NatUtil.getVpnForRouter(dataBroker,routerId);
+ Long vpnId;
+ if (vpnName == null) {
+ LOG.debug("Internal vpn associated to router {}",routerId);
+ vpnId = NatUtil.getVpnId(dataBroker,routerId);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId returned for routerName {}",routerId);
+ return;
+ }
+ LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+ //Install default entry in FIB to SNAT table
+ LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...", dpnId,routerId,vpnId);
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+ } else {
+ LOG.debug("External BGP vpn associated to router {}",routerId);
+ vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId returned for routerName {}", routerId);
+ return;
+ }
+ Long routId = NatUtil.getVpnId(dataBroker, routerId);
+ if (routId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routId returned for routerName {}",routerId);
+ return;
+ }
+ LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+ //Install default entry in FIB to SNAT table
+ LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...", dpnId,routerId,vpnId);
+ defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
+ }
+
+ if (routerData.get().isEnableSnat()) {
+ LOG.info("SNAT enabled for router {}", routerId);
+ handleSNATForDPN(dpnId, routerId ,vpnId);
+ } else {
+ LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
+ }
+ }
+ } else {
+ LOG.debug("Router {} is not associated with External network", routerId);
+ }
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
+ LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
+ final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+ BigInteger dpnId = dpnInfo.getDpnId();
+ //check router is associated to external network
+ InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
+ Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (routerData.isPresent()) {
+ Uuid networkId = routerData.get().getNetworkId();
+ if (networkId != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
+ Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
+ Long vpnId;
+ if (vpnName == null) {
+ LOG.debug("Internal vpn associated to router {}", routerId);
+ vpnId = NatUtil.getVpnId(dataBroker, routerId);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId returned for routerName {}", routerId);
+ return;
+ }
+ LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+ //Remove default entry in FIB
+ LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
+ } else {
+ LOG.debug("External vpn associated to router {}", routerId);
+ vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid vpnId returned for routerName {}", routerId);
+ return;
+ }
+ Long routId = NatUtil.getVpnId(dataBroker, routerId);
+ if (routId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routId returned for routerName {}",routerId);
+ return;
+ }
+ LOG.debug("Retrieved vpnId {} for router {}",vpnId,routerId);
+ //Remove default entry in FIB
+ LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
+ defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId,vpnId,routId);
+ }
+
+ if (routerData.get().isEnableSnat()) {
+ LOG.info("SNAT enabled for router {}", routerId);
+ removeSNATFromDPN(dpnId, routerId, vpnId);
+ } else {
+ LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original, DpnVpninterfacesList update) {
+ LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
+ }
+ void handleSNATForDPN(BigInteger dpnId, String routerName,Long routerVpnId) {
+ //Check if primary and secondary switch are selected, If not select the role
+ //Install select group to NAPT switch
+ //Install default miss entry to NAPT switch
+ BigInteger naptSwitch;
+ try {
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}", routerName);
+ return;
+ }
+ BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ if (naptId == null || naptId.equals(BigInteger.ZERO)) {
+ LOG.debug("No NaptSwitch is selected for router {}", routerName);
+
+ naptSwitch = dpnId;
+ boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
+ if (!naptstatus) {
+ LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
+ return;
+ }
+ LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
+
+ //installing group
+ List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
+ naptSwitchHA.installSnatGroupEntry(naptSwitch, bucketInfo, routerName);
+
+ naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
+
+ } else {
+ LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
+ naptSwitch = naptId;
+
+ //installing group
+ List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
+ if (bucketInfo == null) {
+ LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}", dpnId, routerName,
+ naptSwitch);
+ return;
+ }
+ naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
+ }
+ // Install miss entry (table 26) pointing to group
+ long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+ FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
+ if (flowEntity == null) {
+ LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}", routerName, dpnId, groupId);
+ return;
+ }
+ LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
+ mdsalManager.installFlow(flowEntity);
+ } catch (Exception ex) {
+ LOG.error("Exception in handleSNATForDPN method : {}", ex);
+ }
+ }
+
+ void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
+ //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+ //remove miss entry to NAPT switch
+ //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+ Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+ if (routerId == NatConstants.INVALID_ID) {
+ LOG.error("Invalid routerId returned for routerName {}",routerName);
+ return;
+ }
+ BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+ if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+ LOG.debug("No naptSwitch is selected for router {}", routerName);
+ return;
+ }
+ try {
+ boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId);
+ if (!naptStatus) {
+ LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+ dpnId, routerName);
+ } else {
+ naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch);
+ }
+ } catch (Exception ex) {
+ LOG.debug("Exception while handling naptSwitch down for router {} : {}",routerName,ex);
+ }
+
+ long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+ FlowEntity flowEntity = null;
+ try {
+ flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
+ if (flowEntity == null) {
+ LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
+ return;
+ }
+ LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
+ mdsalManager.removeFlow(flowEntity);
+
+ } catch (Exception ex) {
+ LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+ return;
+ }
+ LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+ //remove group
+ GroupEntity groupEntity = null;
+ try {
+ groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+ GroupTypes.GroupAll, null);
+ LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
+ mdsalManager.removeGroup(groupEntity);
+ } catch (Exception ex) {
+ LOG.debug("NAT Service : Failed to remove group entity {} : {}",groupEntity,ex);
+ return;
+ }
+ LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
+ }
+}
--- /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.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.vpnservice.natservice.rev160111.FloatingIpInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.Routermapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.to.vpn.mapping.RoutermappingKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class RouterPortsListener extends AbstractDataChangeListener<RouterPorts> implements AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(RouterPortsListener.class);
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+
+
+ public RouterPortsListener (final DataBroker db) {
+ super(RouterPorts.class);
+ broker = db;
+ 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("Router ports Listener Closed");
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), RouterPortsListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("RouterPorts DataChange listener registration fail!", e);
+ throw new IllegalStateException("RouterPorts Listener registration Listener failed.", e);
+ }
+ }
+
+ private InstanceIdentifier<RouterPorts> getWildCardPath() {
+ return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class);
+ }
+
+
+ @Override
+ protected void add(final InstanceIdentifier<RouterPorts> identifier, final RouterPorts routerPorts) {
+ LOG.trace("Add router ports method - key: " + identifier + ", value=" + routerPorts );
+ Optional<RouterPorts> optRouterPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+ if(optRouterPorts.isPresent()) {
+ RouterPorts ports = optRouterPorts.get();
+ String routerName = ports.getRouterId();
+ MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier,
+ new RouterPortsBuilder().setKey(new RouterPortsKey(routerName)).setRouterId(routerName)
+ .setExternalNetworkId(routerPorts.getExternalNetworkId()).build());
+ } else {
+ String routerName = routerPorts.getRouterId();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, identifier,
+ new RouterPortsBuilder().setKey(new RouterPortsKey(routerName)).setRouterId(routerName)
+ .setExternalNetworkId(routerPorts.getExternalNetworkId()).build());
+ }
+ //Check if the router is associated with any BGP VPN and update the association
+ String routerName = routerPorts.getRouterId();
+ Uuid vpnName = NatUtil.getVpnForRouter(broker, routerName);
+ if(vpnName != null) {
+ InstanceIdentifier<Routermapping> routerMappingId = NatUtil.getRouterVpnMappingId(routerName);
+ Optional<Routermapping> optRouterMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId);
+ if(!optRouterMapping.isPresent()){
+ Long vpnId = NatUtil.getVpnId(broker, vpnName.getValue());
+ LOG.debug("Updating router {} to VPN {} association with Id {}", routerName, vpnName, vpnId);
+ Routermapping routerMapping = new RoutermappingBuilder().setKey(new RoutermappingKey(routerName))
+ .setRouterName(routerName).setVpnName(vpnName.getValue()).setVpnId(vpnId).build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerMappingId, routerMapping);
+ }
+ }
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<RouterPorts> identifier, RouterPorts routerPorts) {
+ LOG.trace("Remove router ports method - key: " + identifier + ", value=" + routerPorts );
+ //MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+ //Remove the router to vpn association mapping entry if at all present
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, NatUtil.getRouterVpnMappingId(routerPorts.getRouterId()));
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<RouterPorts> identifier, RouterPorts original, RouterPorts update) {
+ LOG.trace("Update router ports method - key: " + identifier + ", original=" + original + ", update=" + update );
+ }
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+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.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
+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.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterAssociatedToVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterDisassociatedFromVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetAddedToVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetDeletedFromVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortAddedToSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortRemovedFromSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetUpdatedInVpn;
+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.Optional;
+
+public class RouterToVpnListener implements NeutronvpnListener {
+ private static final Logger LOG = LoggerFactory.getLogger(RouterToVpnListener.class);
+ private DataBroker dataBroker;
+ private FloatingIPListener floatingIpListener;
+ private OdlInterfaceRpcService interfaceManager;
+
+
+ private ExternalRoutersListener externalRoutersListener;
+
+ public RouterToVpnListener(DataBroker db) {
+ dataBroker = db;
+ }
+
+ void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
+ void setFloatingIpListener(FloatingIPListener floatingIpListener) {
+ this.floatingIpListener = floatingIpListener;
+ }
+
+ void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
+ this.externalRoutersListener = externalRoutersListener;
+ }
+
+ /**
+ * router association to vpn
+ *
+ */
+ @Override
+ public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
+ String routerName = notification.getRouterId().getValue();
+ String vpnName = notification.getVpnId().getValue();
+ //check router is associated to external network
+ String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
+ if(extNetwork != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork);
+ handleDNATConfigurationForRouterAssociation(routerName, vpnName, extNetwork);
+ externalRoutersListener.changeLocalVpnIdToBgpVpnId(routerName, vpnName);
+ } else {
+ LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName);
+ }
+
+ }
+
+ /**
+ * router disassociation from vpn
+ *
+ */
+ @Override
+ public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
+ String routerName = notification.getRouterId().getValue();
+ String vpnName = notification.getVpnId().getValue();
+ //check router is associated to external network
+ String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName);
+ if(extNetwork != null) {
+ LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork);
+ handleDNATConfigurationForRouterDisassociation(routerName, vpnName, extNetwork);
+ externalRoutersListener.changeBgpVpnIdToLocalVpnId(routerName, vpnName);
+ } else {
+ LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName);
+ }
+ }
+
+ void handleDNATConfigurationForRouterAssociation(String routerName, String vpnName, String externalNetwork) {
+ InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+ Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
+ if(!optRouterPorts.isPresent()) {
+ LOG.debug("Could not read Router Ports data object with id: {} to handle associate vpn {}", routerName, vpnName);
+ return;
+ }
+ Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
+ RouterPorts routerPorts = optRouterPorts.get();
+ List<Ports> interfaces = routerPorts.getPorts();
+ Map<String, BigInteger> portToDpnMap = new HashMap<>();
+ for(Ports port : interfaces) {
+ String portName = port.getPortName();
+ BigInteger dpnId = getDpnForInterface(interfaceManager, portName);
+ if(dpnId.equals(BigInteger.ZERO)) {
+ LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName);
+ continue;
+ }
+ portToDpnMap.put(portName, dpnId);
+ List<IpMapping> ipMapping = port.getIpMapping();
+ for(IpMapping ipMap : ipMapping) {
+ String externalIp = ipMap.getExternalIp();
+ //remove all NAT related entries with routerName
+ //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, null, ipMap.getInternalIp(), externalIp);
+ //Create NAT entries with VPN Id
+ LOG.debug("Updating DNAT flows with VPN metadata {} ", vpnName);
+ floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, networkId, ipMap.getInternalIp(), externalIp);
+ }
+ }
+ }
+
+ void handleDNATConfigurationForRouterDisassociation(String routerName, String vpnName, String externalNetwork) {
+ InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+ Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);
+ if(!optRouterPorts.isPresent()) {
+ LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate vpn {}", routerName, vpnName);
+ return;
+ }
+ Uuid networkId = Uuid.getDefaultInstance(externalNetwork);
+ RouterPorts routerPorts = optRouterPorts.get();
+ List<Ports> interfaces = routerPorts.getPorts();
+ for(Ports port : interfaces) {
+ String portName = port.getPortName();
+ BigInteger dpnId = getDpnForInterface(interfaceManager, portName);
+ if(dpnId.equals(BigInteger.ZERO)) {
+ LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName);
+ continue;
+ }
+ List<IpMapping> ipMapping = port.getIpMapping();
+ for(IpMapping ipMap : ipMapping) {
+ String externalIp = ipMap.getExternalIp();
+ //remove all NAT related entries with routerName
+ //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, ipMap.getInternalIp(), externalIp);
+ //Create NAT entries with VPN Id
+ floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, null, networkId, ipMap.getInternalIp(), externalIp);
+ }
+ }
+ }
+
+ private BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
+ BigInteger nodeId = BigInteger.ZERO;
+ try {
+ GetDpidFromInterfaceInput
+ dpIdInput =
+ new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
+ Future<RpcResult<GetDpidFromInterfaceOutput>>
+ dpIdOutput =
+ interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
+ RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
+ if (dpIdResult.isSuccessful()) {
+ nodeId = dpIdResult.getResult().getDpid();
+ } else {
+ LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Exception when getting dpn for interface {}", ifName, e);
+ }
+ return nodeId;
+ }
+
+ @Override
+ public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
+ throw new RuntimeException("Unsupported notification");
+ }
+
+ @Override
+ public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
+ throw new RuntimeException("Unsupported notification");
+ }
+
+ @Override
+ public void onPortAddedToSubnet(PortAddedToSubnet notification) {
+ throw new RuntimeException("Unsupported notification");
+ }
+
+ @Override
+ public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
+ throw new RuntimeException("Unsupported notification");
+ }
+
+ @Override
+ public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
+ throw new RuntimeException("Unsupported notification");
+ }
+
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+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.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SNATDefaultRouteProgrammer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SNATDefaultRouteProgrammer.class);
+ private IMdsalApiManager mdsalManager;
+
+ public SNATDefaultRouteProgrammer(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
+
+ InetAddress defaultIP = null;
+
+ try {
+ defaultIP = InetAddress.getByName("0.0.0.0");
+
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
+ return null;
+ }
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ //add match for default route "0.0.0.0/0"
+// matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
+// NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+ //add match for vrfid
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+ String flowRef = getFlowRefFib(dpId, NatConstants.L3_FIB_TABLE, vpnId);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+
+
+ }
+
+ private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long bgpVpnId, long routerId) {
+
+ InetAddress defaultIP = null;
+
+ try {
+ defaultIP = InetAddress.getByName("0.0.0.0");
+
+ } catch (UnknownHostException e) {
+ LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
+ return null;
+ }
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ //add match for default route "0.0.0.0/0"
+// matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
+// NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
+
+ //add match for vrfid
+ matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+ BigInteger.valueOf(bgpVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
+
+ String flowRef = getFlowRefFib(dpId, NatConstants.L3_FIB_TABLE, routerId);
+
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
+ NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
+
+ return flowEntity;
+
+
+ }
+
+ private String getFlowRefFib(BigInteger dpnId, short tableId, long routerID) {
+ return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+ append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
+ }
+
+ void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ void installDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.installFlow(flowEntity);
+ }
+
+ void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.removeFlow(flowEntity);
+ }
+
+ void removeDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId) {
+ FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
+ if(flowEntity == null) {
+ LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
+ return;
+ }
+ mdsalManager.removeFlow(flowEntity);
+ }
+
+}
--- /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.natservice.internal;
+
+public class SessionAddress {
+
+ private String ipAddress;
+ private int portNumber;
+
+ public SessionAddress(String ipAddress, int portNumber) {
+ this.ipAddress = ipAddress;
+ this.portNumber = portNumber;
+ }
+ public String getIpAddress() {
+ return ipAddress;
+ }
+ public int getPortNumber() {
+ return portNumber;
+ }
+
+}
--- /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.natservice.internal;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.concurrent.Future;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+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.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+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.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class VpnFloatingIpHandler implements FloatingIPHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
+ private VpnRpcService vpnService;
+ private FibRpcService fibService;
+ private IBgpManager bgpManager;
+ private DataBroker dataBroker;
+ private IMdsalApiManager mdsalManager;
+ private FloatingIPListener listener;
+
+ static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+ static final String FLOWID_PREFIX = "NAT.";
+ static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
+
+ public VpnFloatingIpHandler(VpnRpcService vpnService, IBgpManager bgpManager, FibRpcService fibService) {
+ this.vpnService = vpnService;
+ this.fibService = fibService;
+ this.bgpManager = bgpManager;
+ }
+
+ void setListener(FloatingIPListener listener) {
+ this.listener = listener;
+ }
+
+ void setBroker(DataBroker broker) {
+ dataBroker = broker;
+ }
+
+ void setMdsalManager(IMdsalApiManager mdsalManager) {
+ this.mdsalManager = mdsalManager;
+ }
+
+ @Override
+ public void onAddFloatingIp(final BigInteger dpnId, final String routerId,
+ Uuid networkId, final String interfaceName, final String externalIp, final String internalIp) {
+ final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+ if(vpnName == null) {
+ LOG.info("No VPN associated with ext nw {} to handle add floating ip configuration {} in router {}",
+ networkId, externalIp, routerId);
+ return;
+ }
+
+ GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+ Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
+
+ ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
+
+ @Override
+ public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
+ if(result.isSuccessful()) {
+ GenerateVpnLabelOutput output = result.getResult();
+ long label = output.getLabel();
+ LOG.debug("Generated label {} for prefix {}", label, externalIp);
+ listener.updateOperationalDS(routerId, interfaceName, (int)label, internalIp, externalIp);
+
+ //Inform BGP
+ String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+ String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+ LOG.debug("Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
+ NatUtil.addPrefixToBGP(bgpManager, rd, externalIp + "/32", nextHopIp, label, LOG);
+
+ List<Instruction> instructions = new ArrayList<Instruction>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.PDNAT_TABLE) }));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0));
+ makeTunnelTableEntry(dpnId, label, instructions);
+
+ //Install custom FIB routes
+ List<Instruction> customInstructions = new ArrayList<>();
+ customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PDNAT_TABLE }).buildInstruction(0));
+ makeLFibTableEntry(dpnId, label, NatConstants.PDNAT_TABLE);
+ CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setInstruction(customInstructions)
+ .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+ //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
+ Future<RpcResult<Void>> future = fibService.createFibEntry(input);
+ return JdkFutureAdapters.listenInPoolThread(future);
+ } else {
+ String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ }
+ });
+
+ Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Error in generate label or fib install process", error);
+ }
+
+ @Override
+ public void onSuccess(RpcResult<Void> result) {
+ if(result.isSuccessful()) {
+ LOG.info("Successfully installed custom FIB routes for prefix {}", externalIp);
+ } else {
+ LOG.error("Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, Uuid networkId, final String externalIp,
+ String internalIp, final long label) {
+ final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+ if(vpnName == null) {
+ LOG.info("No VPN associated with ext nw {} to handle remove floating ip configuration {} in router {}",
+ networkId, externalIp, routerId);
+ return;
+ }
+ //Remove Prefix from BGP
+ String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+ removePrefixFromBGP(rd, externalIp + "/32");
+
+ //Remove custom FIB routes
+ //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+ RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
+ Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+ ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+ @Override
+ public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+ //Release label
+ if(result.isSuccessful()) {
+ removeTunnelTableEntry(dpnId, label);
+ removeLFibTableEntry(dpnId, label);
+ RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+ Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+ return JdkFutureAdapters.listenInPoolThread(labelFuture);
+ } else {
+ String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ }
+ });
+
+ Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Error in removing the label or custom fib entries", error);
+ }
+
+ @Override
+ public void onSuccess(RpcResult<Void> result) {
+ if(result.isSuccessful()) {
+ LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+ } else {
+ LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+ }
+ }
+ });
+ }
+
+ private void removePrefixFromBGP(String rd, String prefix) {
+ try {
+ bgpManager.deletePrefix(rd, prefix);
+ } catch(Exception e) {
+ LOG.error("Delete prefix failed", e);
+ }
+ }
+
+ void cleanupFibEntries(final BigInteger dpnId, final String vpnName, final String externalIp, final long label ) {
+ //Remove Prefix from BGP
+ String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+ removePrefixFromBGP(rd, externalIp + "/32");
+
+ //Remove custom FIB routes
+
+ //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
+ RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
+ Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
+
+ ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
+ new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
+
+ @Override
+ public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+ //Release label
+ if(result.isSuccessful()) {
+ removeTunnelTableEntry(dpnId, label);
+ removeLFibTableEntry(dpnId, label);
+ RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
+ Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
+ return JdkFutureAdapters.listenInPoolThread(labelFuture);
+ } else {
+ String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+ LOG.error(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+ }
+ }
+ });
+
+ Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Error in removing the label or custom fib entries", error);
+ }
+
+ @Override
+ public void onSuccess(RpcResult<Void> result) {
+ if(result.isSuccessful()) {
+ LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
+ } else {
+ LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+ }
+ }
+ });
+ }
+
+ private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
+ return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+ }
+
+ private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
+ LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+ // Matching metadata
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+ 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+ COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+ mdsalManager.removeFlow(dpnId, flowEntity);
+ LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+ private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+ List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+
+ LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
+
+ mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+
+ Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+ getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
+ 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+
+ mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+ }
+
+ private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x8847L }));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ List<Instruction> instructions = new ArrayList<Instruction>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+ Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
+ instructions.add(writeInstruction);
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
+
+ // Install the flow entry in L3_LFIB_TABLE
+ String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ 10, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, instructions);
+
+ mdsalManager.installFlow(dpId, flowEntity);
+
+ LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+ }
+
+ private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x8847L }));
+ matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
+
+ LOG.debug("removing LFib entry with flow ref {}", flowRef);
+
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
+ 10, flowRef, 0, 0,
+ COOKIE_VM_LFIB_TABLE, matches, null);
+
+ mdsalManager.removeFlow(dpnId, flowEntity);
+
+ LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+ }
+
+}
+
--- /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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111;
+
+import org.opendaylight.vpnservice.natservice.internal.NatServiceProvider;
+
+public class NATServiceModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111.AbstractNATServiceModule {
+ public NATServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NATServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111.NATServiceModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ NatServiceProvider provider = new NatServiceProvider(getRpcRegistryDependency());
+ provider.setNotificationService(getNotificationServiceDependency());
+ provider.setMdsalManager(getMdsalutilDependency());
+ provider.setBgpManager(getBgpmanagerDependency());
+ getBrokerDependency().registerProvider(provider);
+ return provider;
+ }
+}
--- /dev/null
+/*
+* Generated file
+*
+* Generated from: yang module name: natmanager-impl yang module local name: natservice-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Jan 20 15:47:25 IST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111;
+public class NATServiceModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.natservice.impl.rev160111.AbstractNATServiceModuleFactory {
+
+}
--- /dev/null
+module natservice-impl {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:natservice:impl";
+ prefix "natservice-impl";
+
+ 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 odl-mdsalutil { prefix odl-mdsal; revision-date 2015-04-10;}
+ import bgpmanager-api { prefix bgpmgr-api; revision-date 2015-04-20;}
+
+ description
+ "Service definition for NAT Service module";
+
+ revision "2016-01-11" {
+ description
+ "Initial revision";
+ }
+
+ identity natservice-impl {
+ base config:module-type;
+ config:java-name-prefix NATService;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case natservice-impl {
+ when "/config:modules/config:module/config:type = 'natservice-impl'";
+ container broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-broker-osgi-registry;
+ }
+ }
+ }
+ container rpc-registry {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-rpc-registry;
+ }
+ }
+ }
+ container bgpmanager {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity bgpmgr-api:bgpmanager-api;
+ }
+ }
+ }
+ container notification-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding-impl:binding-new-notification-service;
+ }
+ }
+ }
+ container mdsalutil {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity odl-mdsal:odl-mdsalutil;
+ }
+ }
+ }
+ }
+ }
+}
\ 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.natservice.internal.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+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.interfaces.IMdsalApiManager;
+import org.opendaylight.vpnservice.natservice.internal.ExternalNetworksChangeListener;
+import org.opendaylight.vpnservice.natservice.internal.NatUtil;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDSALUtil.class)
+public class ExternalNetworksChangeListenerTest {
+
+ @Mock DataBroker dataBroker;
+ @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+ @Mock IMdsalApiManager mdsalManager;
+ @Mock FlowEntity flowMock;
+ @Mock GroupEntity groupMock;
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks> id = null;
+ org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks networks = null;
+ private ExternalNetworksChangeListener extNetworks;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(dataBroker.registerDataChangeListener(
+ any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(DataChangeListener.class),
+ any(DataChangeScope.class)))
+ .thenReturn(dataChangeListenerRegistration);
+ extNetworks = new ExternalNetworksChangeListener(dataBroker);
+
+ PowerMockito.mockStatic(MDSALUtil.class);
+ }
+
+
+ @Test
+ public void testSnatFlowEntity() {
+ FlowEntity flowMock = mock(FlowEntity.class);
+ final short SNAT_TABLE = 40;
+ final int DEFAULT_SNAT_FLOW_PRIORITY = 0;
+ final String FLOWID_SEPARATOR = ".";
+ String SNAT_FLOWID_PREFIX = "SNAT.";
+
+
+ BigInteger dpnId = new BigInteger("100");
+ String routerName = new String("200");
+ long routerId = 200;
+ long groupId = 300;
+ List<BucketInfo> bucketInfo = new ArrayList<BucketInfo>();
+ List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
+ listActionInfoPrimary.add(new ActionInfo(ActionType.output,
+ new String[] {"3"}));
+ BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
+ List<ActionInfo> listActionInfoSecondary = new ArrayList<ActionInfo>();
+ listActionInfoSecondary.add(new ActionInfo(ActionType.output,
+ new String[] {"4"}));
+ BucketInfo bucketSecondary = new BucketInfo(listActionInfoPrimary);
+ bucketInfo.add(0, bucketPrimary);
+ bucketInfo.add(1, bucketSecondary);
+
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ matches.add(new MatchInfo(MatchFieldType.eth_type,
+ new long[] { 0x0800L }));
+
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+
+
+ String flowRef = new StringBuffer().append(SNAT_FLOWID_PREFIX).append(dpnId).append(FLOWID_SEPARATOR).
+ append(SNAT_TABLE).append(FLOWID_SEPARATOR).append(routerId).toString();
+
+ BigInteger cookieSnat = NatUtil.getCookieSnatFlow(routerId);
+ try {
+ PowerMockito.when(MDSALUtil.class, "buildFlowEntity", dpnId, SNAT_TABLE, flowRef,
+ DEFAULT_SNAT_FLOW_PRIORITY, flowRef, 0, 0,
+ cookieSnat, matches, instructions ).thenReturn(flowMock);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ /* TODO : Fix this to mock it properly when it reads DS
+ extNetworks.buildSnatFlowEntity(dpnId, routerName, groupId);
+ PowerMockito.verifyStatic(); */
+
+ }
+
+}
--- /dev/null
+package org.opendaylight.vpnservice.natservice.internal.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.OngoingStubbing;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.eq;
+
+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.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.natservice.internal.IPAddress;
+import org.opendaylight.vpnservice.natservice.internal.NaptManager;
+import org.opendaylight.vpnservice.natservice.internal.SessionAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+import com.google.common.util.concurrent.Futures;
+
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDSALUtil.class)
+public class NaptManagerTest {
+
+ @Mock IdManagerService idMgr;
+ @Mock DataBroker dataBroker;
+ @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap> ipmapId = null;
+ org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap ipmap = null;
+
+ private NaptManager naptManager;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ when(dataBroker.registerDataChangeListener(
+ any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(DataChangeListener.class),
+ any(DataChangeScope.class)))
+ .thenReturn(dataChangeListenerRegistration);
+ naptManager = new NaptManager(dataBroker);
+ when(idMgr.createIdPool(any(CreateIdPoolInput.class)))
+ .thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
+ naptManager.setIdManager(idMgr);
+
+ PowerMockito.mockStatic(MDSALUtil.class);
+
+ }
+
+
+ @Ignore @Test
+ public void testRegisterMappingIpIP() {
+ // TODO : This needs to be modified to make it work
+ // TODO : Issue with Mockito.any() usage, so for now run registerMapping testcases as seperate Tests. This needs to be fixed properly.
+ ipmapId = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L)).child(IpMap.class, new IpMapKey("10.0.0.1")).build();
+ ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.17.13.1").build();
+ try {
+ PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ IPAddress internal = new IPAddress("10.0.0.1",0);
+ IPAddress external = new IPAddress("192.17.13.1", 0);
+ naptManager.registerMapping(5, internal, external);
+ PowerMockito.verifyStatic();
+
+ }
+
+ @Ignore @Test
+ public void testRegisterMappingIpSubnet() {
+ // TODO : This needs to be modified to make it work
+ ipmapId = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L)).child(IpMap.class, new IpMapKey("10.0.0.1")).build();
+ ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.17.13.1/24").build();
+ try {
+ PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ IPAddress internal = new IPAddress("10.0.0.1",0);
+ IPAddress external = new IPAddress("192.17.13.1", 24);
+ naptManager.registerMapping(5, internal, external);
+ PowerMockito.verifyStatic();
+ }
+
+ @Ignore @Test
+ public void testRegisterMappingSubnetIp() {
+ // TODO : This needs to be modified to make it work
+ ipmapId = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(6L)).child(IpMap.class, new IpMapKey("10.0.2.1/16")).build();
+ ipmap = new IpMapBuilder().setKey(new IpMapKey("10.0.0.1")).setInternalIp("10.0.0.1").setExternalIp("192.19.15.3").build();
+ try {
+ PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ IPAddress internal = new IPAddress("10.0.2.1",16);
+ IPAddress external = new IPAddress("192.19.15.3", 0);
+ naptManager.registerMapping(6, internal, external);
+ PowerMockito.verifyStatic();
+ }
+
+ @Ignore @Test
+ public void testRegisterMappingSubnetSubnet() {
+ // TODO : This needs to be modified to make it work
+ ipmapId = InstanceIdentifier.builder(
+ IntextIpMap.class).child(IpMapping.class, new IpMappingKey(6L)).child(IpMap.class, new IpMapKey("10.2.0.1/24")).build();
+ ipmap = new IpMapBuilder().setKey(new IpMapKey("10.2.0.1/24")).setInternalIp("10.2.0.1/24").setExternalIp("192.21.16.1/16").build();
+ try {
+ PowerMockito.doNothing().when(MDSALUtil.class, "syncWrite", dataBroker, LogicalDatastoreType.OPERATIONAL, ipmapId, ipmap);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ IPAddress internal = new IPAddress("10.2.0.1",24);
+ IPAddress external = new IPAddress("192.21.16.1", 16);
+ naptManager.registerMapping(6, internal, external);
+ PowerMockito.verifyStatic();
+ }
+
+
+ @Test
+ public void testgetExternalAddressMapping() {
+ // TODO : This needs to be modified to make it work
+ // Testcase to test when no entry exists in ip-pot-map
+ /*SessionAddress internalIpPort = new SessionAddress("10.0.0.1", 2);
+ InstanceIdentifierBuilder<IpPortMapping> idBuilder =
+ InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(5L));
+ InstanceIdentifier<IpPortMapping> id = idBuilder.build();
+ try {
+ PowerMockito.when(MDSALUtil.class, "read", dataBroker, LogicalDatastoreType.CONFIGURATION, id).thenReturn(null);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ naptManager.getExternalAddressMapping(5, internalIpPort);
+ PowerMockito.verifyStatic(); */
+ }
+
+ @Test
+ public void testReleaseAddressMapping() {
+ // TODO : Below needs to be modified to make it work
+ /* InstanceIdentifierBuilder<IpMapping> idBuilder =
+ InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(5L));
+ InstanceIdentifier<IpMapping> id = idBuilder.build();
+ try {
+ PowerMockito.doNothing().when(MDSALUtil.class, "read", dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ } catch (Exception e) {
+ // Test failed anyways
+ assertEquals("true", "false");
+ }
+ IPAddress internal = new IPAddress("10.0.0.1",0);
+ IPAddress external = new IPAddress("192.17.13.1", 0);
+ naptManager.registerMapping(5, internal, external);
+ SessionAddress internalSession = new SessionAddress("10.0.0.1", 0);
+ naptManager.releaseAddressMapping(5L, internalSession);*/
+ }
+
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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 INTERNAL
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>natservice-aggregator</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <name>natservice</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <modules>
+ <module>natservice-api</module>
+ <module>natservice-impl</module>
+ </modules>
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
.getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
return cachedMap.get(devicename);
}
+
+ public static ConcurrentMap<String, L2GatewayDevice> getCache() {
+ return (ConcurrentMap<String, L2GatewayDevice>) CacheUtil
+ .getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
+ }
}
--- /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.neutronvpn.api.utils;
+
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+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.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+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;
+
+public class NeutronUtils {
+ public static final String VNIC_TYPE_NORMAL = "normal";
+
+ public 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);
+ }
+
+ public static String getSegmentationIdFromNeutronNetwork(Network network) {
+ String segmentationId = null;
+ 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;
+ }
+
+ static boolean isNetworkSegmentTypeVxlan(Segments providerSegment) {
+ Class<? extends NetworkTypeBase> networkType = providerSegment.getNetworkType();
+ return (networkType != null && networkType.isAssignableFrom(NetworkTypeVxlan.class));
+ }
+}
}
}
+
+ container router-interfaces-map {
+ list router-interfaces {
+ key router-id;
+ leaf router-id { type yang:uuid; }
+ list interfaces {
+ key interface-id;
+ leaf interface-id { type string; }
+ }
+ }
+ }
+
+
/* container for DHCP Configuration */
container dhcp-config {
list configs {
}
}
-}
\ No newline at end of file
+ notification router-associated-to-vpn {
+ description "router association to vpn";
+ leaf router-id{
+ type yang:uuid;
+ }
+ leaf vpn-id{
+ type yang:uuid;
+ }
+ }
+
+ notification router-disassociated-from-vpn {
+ description "router disassociation from vpn";
+ leaf router-id{
+ type yang:uuid;
+ }
+ leaf vpn-id{
+ type yang:uuid;
+ }
+ }
+
+}
</type>
<name>mdsalutil-service</name>
</mdsalutil>
- <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>
<notification-publish-service>
<type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
<name>binding-notification-publish-adapter</name>
<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>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
+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.rev150712.Neutron;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
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.instances.ElanInstanceBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
-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.rev150712.Neutron;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
private void createElanInstance(Network input) {
String elanInstanceName = input.getUuid().getValue();
- String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(input);
+ String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(input);
ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName);
if (segmentationId != null) {
elanInstanceBuilder.setVni(Long.valueOf(segmentationId));
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
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.InterfaceBuilder;
}
private void handleNeutronPortCreated(Port port) {
- if (!NeutronvpnUtils.isPortVnicTypeNormal(port)) {
+ if (!NeutronUtils.isPortVnicTypeNormal(port)) {
LOG.info("Port {} is not a NORMAL VNIC Type port; OF Port interfaces are not created",
port.getUuid().getValue());
return;
// create vpn-interface on this neutron port
LOG.debug("Adding VPN Interface");
nvpnManager.createVpnInterface(vpnId, port);
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+ if(routerId != null) {
+ nvpnManager.addToNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
+ }
}
}
// ELAN interface is also implicitly deleted as part of this operation
deleteOfPortInterface(port);
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+ if(routerId != null) {
+ nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
+ }
+
}
private void handleNeutronPortUpdated(Port portoriginal, Port portupdate) {
if (vpnIdup != null) {
nvpnManager.createVpnInterface(vpnIdup, portupdate);
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdup).getRouterId();
+ if(routerId != null) {
+ nvpnManager.addToNeutronRouterInterfacesMap(routerId, portupdate.getUuid().getValue());
+ }
}
// remove port FixedIP from local Subnets DS
if (vpnIdor != null) {
nvpnManager.deleteVpnInterface(portoriginal);
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdor).getRouterId();
+ if(routerId != null) {
+ nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portoriginal.getUuid().getValue());
+ }
}
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterInterfacesMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesKey;
+
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
long elanTag = elanInstance.get().getElanTag();
- if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
- else {isExternalVpn = true;}
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+ if (vpnId.equals(routerId)) {
+ isExternalVpn = false;
+ } else {
+ isExternalVpn = true;
+ }
try {
isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
checkAndPublishSubnetAddNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
}
}
+
+
+ // router-interfaces-map
+// list router-interfaces {
+// key router-id;
+// leaf router-id { type yang:uuid; }
+// list interfaces {
+// key interface-id;
+// leaf interface-id { type yang:uuid; }
+// }
+// }
+////}
+ InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
+ return InstanceIdentifier.builder(RouterInterfacesMap.class)
+ .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
+ }
+ void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
+ InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
+ Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+ Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName)).setInterfaceId(interfaceName).build();
+ if(optRouterInterfaces.isPresent()) {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
+ } else {
+ RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
+ List<Interfaces> interfaces = new ArrayList<>();
+ interfaces.add(routerInterface);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId, builder.setInterfaces(interfaces).build());
+ }
+ }
+
+ void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
+ InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
+ Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+ Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName)).setInterfaceId(interfaceName).build();
+ if(optRouterInterfaces.isPresent()) {
+ RouterInterfaces routerInterfaces = optRouterInterfaces.get();
+ List<Interfaces> interfaces = routerInterfaces.getInterfaces();
+ if(interfaces != null && interfaces.remove(routerInterface)) {
+ if(interfaces.isEmpty()) {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
+ } else {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
+ }
+ }
+ }
+ }
+
protected List<Adjacency> addAdjacencyforExtraRoute(List<Routes> routeList, boolean rtrUp, String vpnifname) {
List<Adjacency> adjList = new ArrayList<Adjacency>();
for (Routes route : routeList) {
InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
long elanTag = elanInstance.get().getElanTag();
- if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
- else {isExternalVpn = true;}
+ Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
+ if (vpnId.equals(routerId)) {
+ isExternalVpn = false;
+ } else {
+ isExternalVpn = true;
+ }
try {
isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
checkAndPublishSubnetDelNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
for (Uuid port : sn.getPortList()) {
logger.debug("removing vpn-interface for port {}", port.getValue());
deleteVpnInterface(NeutronvpnUtils.getNeutronPort(broker, port));
+ if (routerId != null) {
+ removeFromNeutronRouterInterfacesMap(routerId, port.getValue());
+ }
}
}
// update subnet-vpn association
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
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.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
import org.opendaylight.vpnservice.neutronvpn.l2gw.L2GatewayProvider;
private NeutronPortChangeListener portListener;
private RpcProviderRegistry rpcProviderRegistry;
private L2GatewayProvider l2GatewayProvider;
- private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private NotificationPublishService notificationPublishService;
private NotificationService notificationService;
+ private EntityOwnershipService entityOwnershipService;
public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
NotificationService notificationService) {
this.entityOwnershipService = entityOwnershipService;
}
- public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
- }
-
@Override
public void onSessionInitiated(ProviderContext session) {
try {
portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
portListener.setLockManager(lockManager);
nvManager.setLockManager(lockManager);
- l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
- bindingNormalizedNodeSerializer);
+ l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService);
LOG.info("NeutronvpnProvider Session Initiated");
} catch (Exception e) {
return null;
}
- protected static String getSegmentationIdFromNeutronNetwork(Network network) {
- String segmentationId = null;
- 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;
- }
-
protected static List<Uuid> getNeutronRouterSubnetIds(DataBroker broker, Uuid routerId) {
logger.info("getNeutronRouterSubnetIds for {}", routerId.getValue());
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));
- }
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-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.yangtools.yang.common.RpcResult;
private final DataBroker broker;
private ItmRpcService itmRpcService;
private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
public L2GatewayListener(final DataBroker db, RpcProviderRegistry rpcRegistry,
- EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ EntityOwnershipService entityOwnershipService) {
super(L2gateway.class, L2GatewayListener.class);
broker = db;
this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
itmRpcService = rpcRegistry.getRpcService(ItmRpcService.class);
registerListener(db);
}
final String hwvtepId = l2GwDevice.getHwvtepNodeId();
InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
final String hwvtepId = l2GwDevice.getHwvtepNodeId();
InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private L2GatewayListener l2GatewayListener;
public L2GatewayProvider(DataBroker broker, RpcProviderRegistry rpcRegistry,
- EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ EntityOwnershipService entityOwnershipService) {
L2GatewayCacheUtils.createL2DeviceCache();
- l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService,
- bindingNormalizedNodeSerializer);
+ l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService);
LOG.info("L2GatewayProvider Initialized");
}
provider.setMdsalManager(getMdsalutilDependency());
provider.setLockManager(lockManagerService);
provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
- provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
}
}
}
- 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;
- }
- }
- }
-
container notification-publish-service {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity md-sal-binding-impl:binding-new-notification-service;
}
+ }
+ }
+
+ container entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
}
}
}
<module>neutronvpn</module>
<module>dhcpservice</module>
<module>itm</module>
+ <module>natservice</module>
<module>distribution/karaf</module>
<module>features</module>
<module>vpnservice-artifacts</module>
<module>vpnintent</module>
+ <module>fcapsmanager</module>
</modules>
<!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
type string;
}
}
+ list ip-addresses {
+ key ip-address;
+ leaf ip-address {
+ type string;
+ }
+ }
}
}
}
}
}
-}
\ No newline at end of file
+ grouping dpn-in-vpn-event {
+ leaf dpn-id { type uint64; }
+ leaf vpn-name { type string; }
+ leaf rd { type string; }
+ }
+
+ notification add-dpn-event {
+ container add-event-data {
+ uses dpn-in-vpn-event;
+ }
+ }
+
+ notification remove-dpn-event {
+ container remove-event-data {
+ uses dpn-in-vpn-event;
+ }
+ }
+
+
+ /* container to maintain mapping between neutron router and DPN(s) on which vpn-interfaces for router are present */
+ container neutron-router-dpns {
+ list router-dpn-list {
+ key router-id;
+ leaf router-id { type string;}
+ list dpn-vpninterfaces-list {
+ key dpn-id;
+ leaf dpn-id { type uint64;}
+ list router-interfaces {
+ key interface;
+ leaf interface { type string; }
+ }
+ }
+ }
+ }
+
+
+ container router-interfaces {
+ list router-interface {
+ key interface-name;
+ leaf interface-name { type string; }
+ leaf router-name { type string; }
+ }
+ }
+
+}
--- /dev/null
+module vpn-rpc {\r
+ namespace "urn:opendaylight:vpnservice:vpn:rpc";\r
+ prefix "vpn-rpc";\r
+\r
+ revision "2016-02-01" {\r
+ description "VPN Service RPC Module";\r
+ }\r
+\r
+ /* RPCs */\r
+\r
+ rpc generate-vpn-label {\r
+ description "to generate label for the given ip prefix from the associated VPN";\r
+ input {\r
+ leaf vpn-name {\r
+ type string;\r
+ }\r
+ leaf ip-prefix {\r
+ type string;\r
+ }\r
+ }\r
+ output {\r
+ leaf label {\r
+ type uint32;\r
+ }\r
+ }\r
+ }\r
+\r
+ rpc remove-vpn-label {\r
+ description "to remove label for the given ip prefix from the associated VPN";\r
+ input {\r
+ leaf vpn-name {\r
+ type string;\r
+ }\r
+ leaf ip-prefix {\r
+ type string;\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
*/
package org.opendaylight.vpnservice;
+import com.google.common.base.Optional;
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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
} else {
vpnInterfaceManager.processVpnInterfaceUp(dpnId, interfaceName, intrf.getIfIndex());
vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(intrf);
+ handleRouterInterfacesUpEvent(interfaceName);
}
} catch (Exception e) {
LOG.error("Exception caught in Interface Operational State Up event", e);
if (VpnUtil.isVpnInterfaceConfigured(broker, interfaceName)) {
vpnInterfaceManager.processVpnInterfaceDown(dpId, interfaceName, intrf.getIfIndex(), true);
vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(intrf);
+ handleRouterInterfacesDownEvent(interfaceName,dpId);
}
}
} catch (Exception e) {
if(update.getOperStatus().equals(Interface.OperStatus.Up)) {
//advertise all prefixes in all vpns for this dpn to bgp
// vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.ADVERTISE_ROUTE);
- vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
} else if(update.getOperStatus().equals(Interface.OperStatus.Down)) {
//withdraw all prefixes in all vpns for this dpn from bgp
// vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
- vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
}*/
}
}
+ void handleRouterInterfacesUpEvent(String interfaceName) {
+ Optional<RouterInterface> optRouterInterface = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, VpnUtil.getRouterInterfaceId(interfaceName));
+ if(optRouterInterface.isPresent()) {
+ RouterInterface routerInterface = optRouterInterface.get();
+ String routerName = routerInterface.getRouterName();
+ LOG.debug("Handling UP event for router interface {} in Router {}", interfaceName, routerName);
+ vpnInterfaceManager.addToNeutronRouterDpnsMap(routerName, interfaceName);
+ } else {
+ LOG.debug("No Router interface configured to handle UP event for {}", interfaceName);
+ }
+ }
+
+ void handleRouterInterfacesDownEvent(String interfaceName,BigInteger dpnId) {
+ Optional<RouterInterface> optRouterInterface = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, VpnUtil.getRouterInterfaceId(interfaceName));
+ if(optRouterInterface.isPresent()) {
+ RouterInterface routerInterface = optRouterInterface.get();
+ String routerName = routerInterface.getRouterName();
+ LOG.debug("Handling DOWN event for router interface {} in Router {}", interfaceName, routerName);
+ vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerName, interfaceName,dpnId);
+ } else {
+ LOG.debug("No Router interface configured to handle DOWN event for {}", interfaceName);
+ }
+ }
+
}
--- /dev/null
+/*\r
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.vpnservice;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
+import org.opendaylight.vpnservice.utilities.InterfaceUtils;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterInterfacesMap;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;\r
+import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class RouterInterfaceListener extends AbstractDataChangeListener<Interfaces> {\r
+ private static final Logger LOG = LoggerFactory.getLogger(RouterInterfaceListener.class);\r
+ private ListenerRegistration<DataChangeListener> listenerRegistration;\r
+ private DataBroker broker;\r
+ private VpnInterfaceManager vpnInterfaceManager;\r
+\r
+ public RouterInterfaceListener(final DataBroker db) {\r
+ super(Interfaces.class);\r
+ broker = db;\r
+ registerListener(db);\r
+ }\r
+\r
+ void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {\r
+ this.vpnInterfaceManager = vpnInterfaceManager;\r
+ }\r
+\r
+ private void registerListener(final DataBroker db) {\r
+ try {\r
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
+ getWildCardPath(), RouterInterfaceListener.this, DataChangeScope.SUBTREE);\r
+ } catch (final Exception e) {\r
+ LOG.error("Router interface DataChange listener registration fail !", e);\r
+ }\r
+ }\r
+\r
+ private InstanceIdentifier<?> getWildCardPath() {\r
+ return InstanceIdentifier.create(RouterInterfacesMap.class).child(RouterInterfaces.class).child(Interfaces.class);\r
+ }\r
+\r
+ @Override\r
+ protected void add(InstanceIdentifier<Interfaces> identifier, Interfaces interfaceInfo) {\r
+ LOG.trace("Add event - key: {}, value: {}", identifier, interfaceInfo);\r
+ final String routerId = identifier.firstKeyOf(RouterInterfaces.class).getRouterId().getValue();\r
+ String interfaceName = interfaceInfo.getInterfaceId();\r
+\r
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, \r
+ VpnUtil.getRouterInterfaceId(interfaceName), VpnUtil.getRouterInterface(interfaceName, routerId));\r
+\r
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =\r
+ InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);\r
+ if (interfaceState != null) {\r
+ LOG.debug("Handling interface {} in router {} add scenario", interfaceName, routerId);\r
+ vpnInterfaceManager.addToNeutronRouterDpnsMap(routerId, interfaceName);\r
+ } else {\r
+ LOG.warn("Interface {} not yet operational to handle router interface add event in router {}", interfaceName, routerId);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void remove(InstanceIdentifier<Interfaces> identifier, Interfaces interfaceInfo) {\r
+ LOG.trace("Remove event - key: {}, value: {}", identifier, interfaceInfo);\r
+ final String routerId = identifier.firstKeyOf(RouterInterfaces.class).getRouterId().getValue();\r
+ String interfaceName = interfaceInfo.getInterfaceId();\r
+ vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerId, interfaceName);\r
+ }\r
+\r
+ @Override\r
+ protected void update(InstanceIdentifier<Interfaces> identifier, Interfaces original, Interfaces update) {\r
+ LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);\r
+ }\r
+\r
+}\r
import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
import org.opendaylight.vpnservice.mdsalutil.ActionType;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
public class SubnetRoutePacketInHandler implements PacketProcessingListener {
public void onPacketReceived(PacketReceived notification) {
- s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
+ s_logger.trace("SubnetRoutePacketInHandler: PacketReceived invoked...");
short tableId = notification.getTableId().getValue();
byte[] data = notification.getPayload();
BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
Ethernet res = new Ethernet();
- if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
+ if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
+ s_logger.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
try {
- s_logger.debug("SubnetRoutePacketInHandler: Some packet received");
res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+ } catch (Exception e) {
+ s_logger.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
+ return;
+ }
+ try {
Packet pkt = res.getPayload();
if (pkt instanceof IPv4) {
IPv4 ipv4 = (IPv4) pkt;
return;
}
long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
- s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
if (elanTag == 0) {
s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
"Packet received with Target IP {}", dstIpStr);
return;
}
s_logger.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
- + "and Target IP {}", srcIpStr, dstIpStr);
- BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag, ipv4.getDestinationAddress());
+ + "and Target IP {} and elan Tag {}", srcIpStr, dstIpStr, elanTag);
+ BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag, ipv4.getDestinationAddress());
//Handle subnet routes ip requests
if (dpnId != BigInteger.ZERO) {
long groupid = VpnUtil.getRemoteBCGroup(elanTag);
String key = srcIpStr + dstIpStr;
sendArpRequest(dpnId, groupid, srcMac, srcIp, dstIp);
- arpList.add(key);
}
return;
}
+ } catch (Exception ex) {
+ //Failed to handle packet
+ s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
+ }
+ return;
+ }
+ if (tableId == NwConstants.L3_INTERFACE_TABLE) {
+ s_logger.trace("SubnetRoutePacketInHandler: Packet from Table {} received as {}",
+ NwConstants.L3_INTERFACE_TABLE, notification);
+ try {
+ res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+ } catch (Exception e) {
+ s_logger.warn("SubnetRoutePacketInHandler: Failed to decode Table " + NwConstants.L3_INTERFACE_TABLE + " Packet ", e);
+ return;
+ }
+ try {
+ Packet pkt = res.getPayload();
if (pkt instanceof ARP) {
s_logger.debug("SubnetRoutePacketInHandler: ARP packet received");
ARP arpPacket = (ARP) pkt;
byte[] respDst = arpPacket.getTargetProtocolAddress();
String respIp = toStringIpAddress(respSrc);
String check = toStringIpAddress(respDst) + respIp;
- if (arpList.contains(check)) {
- s_logger.debug("SubnetRoutePacketInHandler: ARP reply received for listening target IP " + respIp);
- String destination = VpnUtil.getIpPrefix(respIp);
- long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
- s_logger.debug("SubnetRoutePacketInHandler Lport Tag of arp replier " + portTag);
- IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
- String ifName = interfaceInfo.getInterfaceName();
- InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
- VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
+ if (VpnUtil.getNeutronPortNamefromPortFixedIp(broker, respIp) != null) {
+ s_logger.debug("SubnetRoutePacketInHandler: ARP reply Packet received with "
+ + "Source IP {} which is a valid Neutron port, ignoring subnet route processing", respIp);
+ return;
+ }
+ String destination = VpnUtil.getIpPrefix(respIp);
+ long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+ s_logger.info("SubnetRoutePacketInHandler: ARP reply received for target IP {} from LPort {}" + respIp, portTag);
+ IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
+ String ifName = interfaceInfo.getInterfaceName();
+ InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
+ VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
- //Get VPN interface adjacencies
- if (vpnInterface != null) {
- InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
- Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
- String nextHopIpAddr = null;
- String nextHopMacAddress = null;
- if (adjacencies.isPresent()) {
- List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
- for (Adjacency adjacs : adjacencyList) {
- if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
- nextHopIpAddr = adjacs.getIpAddress();
- nextHopMacAddress = adjacs.getMacAddress();
- break;
- }
- }
- if (nextHopMacAddress != null && destination != null) {
- String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
- long label =
- VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
- VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
- String nextHopIp = nextHopIpAddr.split("/")[0];
- Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
- (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
- adjacencyList.add(newAdj);
- Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
- VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
- setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
- addAugmentation(Adjacencies.class, aug).build();
- VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
- s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+ //Get VPN interface adjacencies
+ if (vpnInterface != null) {
+ InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
+ Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+ String nextHopIpAddr = null;
+ String nextHopMacAddress = null;
+ if (adjacencies.isPresent()) {
+ List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
+ for (Adjacency adjacs : adjacencyList) {
+ if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
+ nextHopIpAddr = adjacs.getIpAddress();
+ nextHopMacAddress = adjacs.getMacAddress();
+ break;
}
}
+ if (nextHopMacAddress != null && destination != null) {
+ String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
+ long label =
+ VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
+ String nextHopIp = nextHopIpAddr.split("/")[0];
+ Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
+ (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
+ adjacencyList.add(newAdj);
+ Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
+ VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
+ setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
+ addAugmentation(Adjacencies.class, aug).build();
+ VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
+ s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+ }
}
- //Remove from list once response was processed
- arpList.remove(check);
}
}
}
} catch (Exception ex) {
//Failed to decode packet
- s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
+ s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute Table " + NwConstants.L3_INTERFACE_TABLE +
+ " packets ", ex);
}
}
}
}
InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
.child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
- s_logger.trace("SubnetRoutePacketInHandler: Obtained target ip address as " + ipAddress);
- s_logger.trace("SubnetRoutePacketInHandler: Obtained elanTag as " + elanTag);
- s_logger.trace("SubnetRoutePacketInHandler: Obtained elanInfo as " + elanInfo);
- s_logger.trace("SubnetRoutePacketInHandler: Obtained network name as " + elanInfo.getName());
Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
if (optionalNetworkMap.isPresent()) {
if (!optionalSubs.isPresent()) {
continue;
}
- s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId.getValue());
SubnetOpDataEntry subOpEntry = optionalSubs.get();
if (subOpEntry.getNhDpnId() != null) {
+ s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId);
boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
if (match) {
private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
byte[] abyTargetIpAddress) {
- s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderMAC {}, senderIPAddress {}, targetIPAddress {}",
- dpnId, groupId,new String(abySenderMAC, StandardCharsets.UTF_8),
+ s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderIPAddress {}, targetIPAddress {}",
+ dpnId, groupId,
toStringIpAddress(abySenderIpAddress),toStringIpAddress(abyTargetIpAddress));
if (abySenderIpAddress != null) {
byte[] arpPacket;
arp.setTargetProtocolAddress(targetIP);
rawArpPkt = arp.serialize();
} catch (Exception ex) {
- s_logger.error("VPNUtil: Serialized ARP packet with senderMacAddress {} senderIp {} targetIP {} exception {}",
- senderMacAddress, senderIP, targetIP, ex);
+ s_logger.error("VPNUtil: Serialized ARP packet with senderIp {} targetIP {} exception ",
+ senderIP, targetIP, ex);
}
return rawArpPkt;
ethernet.setRawPayload(arp);
rawEthPkt = ethernet.serialize();
} catch (Exception ex) {
- s_logger.error("VPNUtil: Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception {}",
+ s_logger.error("VPNUtil: Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception ",
sourceMAC, targetMAC, ex);
}
return rawEthPkt;
public static final BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
public static final BigInteger COOKIE_L3_BASE = new BigInteger("8000000", 16);
public static final String FLOWID_PREFIX = "L3.";
- public static final long WAIT_TIME_IN_MILLISECONDS = 5000;
+ public static final long MIN_WAIT_TIME_IN_MILLISECONDS = 10000;
+ public static final long MAX_WAIT_TIME_IN_MILLISECONDS = 90000;
public static final int ELAN_GID_MIN = 200000;
public static final short ELAN_SMAC_TABLE = 50;
public static final short FIB_TABLE = 21;
import org.opendaylight.controller.md.sal.binding.api.*;
import org.opendaylight.vpnservice.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.opendaylight.l3vpn.rev130911.NeutronRouterDpns;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
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.l3vpn.rev130911.PrefixToInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
- instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+ instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
// Install the flow entry in L3_INTERFACE_TABLE
String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
vpnIntfMap.put(interfaceName, notifyTask);
synchronized (notifyTask) {
try {
- notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
+ notifyTask.wait(VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS);
} catch (InterruptedException e) {
}
}
Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
+ LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", intf.getName(),
+ intf.getVpnInstanceName(), rd);
if (adjacencies.isPresent()) {
List<Adjacency> nextHops = adjacencies.get().getAdjacency();
if (!nextHops.isEmpty()) {
LOG.trace("NextHops are " + nextHops);
for (Adjacency nextHop : nextHops) {
- VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ // Commenting the release of ID here as it will be released by FIB
+ /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
- /*VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
VpnUtil.getPrefixToInterfaceIdentifier(
VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
nextHop.getIpAddress()),
while (adjIt.hasNext()) {
Adjacency adjElem = adjIt.next();
if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
- VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
- VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));
+ // Commenting the release of ID here as it will be released by FIB
+ /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));*/
adjIt.remove();
Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
String interfaceName = key.getName();
-
- //increment the vpn interface count in Vpn Instance Op Data
- Long ifCnt = 0L;
- String rd = getRouteDistinguisher(del.getVpnInstanceName());
- if(rd == null || rd.isEmpty()) rd = del.getVpnInstanceName();
- VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
- if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
- ifCnt = vpnInstOp.getVpnInterfaceCount();
- }
-
- LOG.trace("VpnInterfaceOpListener remove: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
-
- if(ifCnt != 0) {
- VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
- VpnUtil.getVpnInstanceOpDataIdentifier(rd),
- VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
- }
-
- // Vpn Interface removed => No more adjacencies from it.
- // Hence clean up interface from vpn-dpn-interface list.
- Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
- Optional<Prefixes> prefixToInterface = Optional.absent();
- prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
- VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
- VpnUtil.getIpPrefix(adjacency.getIpAddress())));
- if (!prefixToInterface.isPresent()) {
- prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
- VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
- VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
- }
- if (prefixToInterface.isPresent()) {
- VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
- VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
- prefixToInterface.get().getIpAddress()),
- VpnUtil.DEFAULT_CALLBACK);
- updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
+ String vpnName = del.getVpnInstanceName();
+
+ LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
+ //decrement the vpn interface count in Vpn Instance Op Data
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
+ id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
+ = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+ if (vpnInstance.isPresent()) {
+ String rd = null;
+ rd = vpnInstance.get().getVrfId();
+ //String rd = getRouteDistinguisher(del.getVpnInstanceName());
+
+ VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
+ LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
+ interfaceName, rd, vpnName, vpnInstOp);
+
+ if (vpnInstOp != null) {
+ // Vpn Interface removed => No more adjacencies from it.
+ // Hence clean up interface from vpn-dpn-interface list.
+ Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
+ Optional<Prefixes> prefixToInterface = Optional.absent();
+ prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+ VpnUtil.getIpPrefix(adjacency.getIpAddress())));
+ if (!prefixToInterface.isPresent()) {
+ prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+ VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
+ }
+ if (prefixToInterface.isPresent()) {
+ VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+ prefixToInterface.get().getIpAddress()),
+ VpnUtil.DEFAULT_CALLBACK);
+ updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
+ }
+ Long ifCnt = 0L;
+ ifCnt = vpnInstOp.getVpnInterfaceCount();
+ LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} Intf count {}",
+ interfaceName, rd, vpnName, ifCnt);
+ if ((ifCnt != null) && (ifCnt > 0)) {
+ VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getVpnInstanceOpDataIdentifier(rd),
+ VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
+ }
+ }
+ } else {
+ LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
}
notifyTaskIfRequired(interfaceName);
}
}
}
+ InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
+ return InstanceIdentifier.builder(NeutronRouterDpns.class)
+ .child(RouterDpnList.class, new RouterDpnListKey(routerName))
+ .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
+ }
+
+ InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
+ return InstanceIdentifier.builder(NeutronRouterDpns.class)
+ .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
+ }
+
+ protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+ BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
+ if(dpId.equals(BigInteger.ZERO)) {
+ LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
+ return;
+ }
+ InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+
+ Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+ .CONFIGURATION, routerDpnListIdentifier);
+ RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+ if (optionalRouterDpnList.isPresent()) {
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+ RouterInterfaces.class, new RouterInterfacesKey(vpnInterfaceName)), routerInterface);
+ } else {
+ MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
+ getRouterId(routerName),
+ new RouterDpnListBuilder().setRouterId(routerName).build());
+ //VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
+ DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
+ List<RouterInterfaces> routerInterfaces = new ArrayList<>();
+ routerInterfaces.add(routerInterface);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier,
+ dpnVpnList.setRouterInterfaces(routerInterfaces).build());
+ }
+ }
+
+ protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+ BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
+ if(dpId.equals(BigInteger.ZERO)) {
+ LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
+ return;
+ }
+ InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+ Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+ .CONFIGURATION, routerDpnListIdentifier);
+ if (optionalRouterDpnList.isPresent()) {
+ List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
+ RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+
+ if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
+ if (routerInterfaces.isEmpty()) {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier);
+ } else {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+ RouterInterfaces.class,
+ new RouterInterfacesKey(vpnInterfaceName)));
+ }
+ }
+ }
+ }
+
+ protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,BigInteger dpId) {
+ if(dpId.equals(BigInteger.ZERO)) {
+ LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
+ return;
+ }
+ InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
+ Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+ .CONFIGURATION, routerDpnListIdentifier);
+ if (optionalRouterDpnList.isPresent()) {
+ List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
+ RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
+
+ if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
+ if (routerInterfaces.isEmpty()) {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier);
+ } else {
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routerDpnListIdentifier.child(
+ RouterInterfaces.class,
+ new RouterInterfacesKey(vpnInterfaceName)));
+ }
+ }
+ }
+ }
+
}
getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
- opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
getVpnInstanceOpListenerPath(), vpnInstOpListener, DataChangeScope.SUBTREE);
} catch (final Exception e) {
this.vpnInterfaceManager = vpnInterfaceManager;
}
- private void waitForOpDataRemoval(String id) {
+ private void waitForOpRemoval(String id, long timeout) {
//wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is zero
Runnable notifyTask = new VpnNotifyTask();
synchronized (id.intern()) {
- vpnOpMap.put(id, notifyTask);
- synchronized (notifyTask) {
- try {
- notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
- } catch (InterruptedException e) {
+ try {
+ vpnOpMap.put(id, notifyTask);
+ synchronized (notifyTask) {
+ try {
+ notifyTask.wait(timeout);
+ } catch (InterruptedException e) {
+ }
}
+ } finally {
+ vpnOpMap.remove(id);
}
}
@Override
protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
- LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
+ LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
String vpnName = del.getVpnInstanceName();
+ String rd = del.getIpv4Family().getRouteDistinguisher();
+ long vpnId = VpnUtil.getVpnId(broker, vpnName);
- //Clean up vpn Interface
- InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
- Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
+ //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
+ Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
+ if ((rd != null) && (!rd.isEmpty())) {
+ vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getVpnInstanceOpDataIdentifier(rd));
+ } else {
+ vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
+ }
- if(optionalVpnInterfaces.isPresent()) {
- List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
- for(VpnInterface vpnInterface : vpnInterfaces) {
- if(vpnInterface.getVpnInstanceName().equals(vpnName)) {
- LOG.debug("VpnInterface {} will be removed from VPN {}", vpnInterface.getName(), vpnName);
- vpnInterfaceManager.remove(
- VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+ if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
+ VpnInstanceOpDataEntry vpnOpEntry = null;
+ long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
+ Long intfCount = 0L;
+
+ vpnOpEntry = vpnOpValue.get();
+ intfCount = vpnOpEntry.getVpnInterfaceCount();
+ if (intfCount != null && intfCount > 0) {
+ // Minimum wait time of 10 seconds for one VPN Interface clearance (inclusive of full trace on)
+ timeout = intfCount * 10000;
+ // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
+ if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
+ timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
}
+ LOG.trace("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
+ intfCount, rd, vpnName);
}
- }
- InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
- vpnIdentifier = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
- delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
-
- VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
- String rd = del.getIpv4Family().getRouteDistinguisher();
+ LOG.trace("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
+ (timeout/1000), rd, vpnName);
- if (rd !=null) {
+ if ((rd != null) && (!rd.isEmpty())) {
+ waitForOpRemoval(rd, timeout);
+ } else {
+ waitForOpRemoval(vpnName, timeout);
+ }
+ LOG.trace("Returned out of waiting for Op Data removal for rd {}, vpnname {}", rd, vpnName);
+ }
+ // Clean up VpnInstanceToVpnId from Config DS
+ VpnUtil.removeVpnInstanceToVpnId(broker, vpnName);
+ LOG.trace("Removed vpnIdentifier for rd{} vpnname {}", rd, vpnName);
+ if (rd != null) {
try {
bgpManager.deleteVrf(rd);
} catch (Exception e) {
- LOG.error("Exception when removing VRF from BGP", e);
+ LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
}
- waitForOpDataRemoval(rd);
- delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd));
+
+ // Clean up VPNExtraRoutes Operational DS
+ VpnUtil.removeVpnExtraRouteForVpn(broker, rd);
+
+ // Clean up VPNInstanceOpDataEntry
+ VpnUtil.removeVpnOpInstance(broker, rd);
} else {
- waitForOpDataRemoval(vpnName);
- delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
+ // Clean up FIB Entries Config DS
+ VpnUtil.removeVrfTableForVpn(broker, vpnName);
+
+ // Clean up VPNExtraRoutes Operational DS
+ VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName);
+
+ // Clean up VPNInstanceOpDataEntry
+ VpnUtil.removeVpnOpInstance(broker, vpnName);
}
+
+ // Clean up PrefixToInterface Operational DS
+ VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId);
+
+ // Clean up L3NextHop Operational DS
+ VpnUtil.removeL3nexthopForVpnId(broker, vpnId);
+
+ // Release the ID used for this VPN back to IdManager
+
+ VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
}
@Override
protected void update(InstanceIdentifier<VpnInstance> identifier,
VpnInstance original, VpnInstance update) {
- LOG.trace("Update event - Key: {}, value: {}", identifier, update);
+ LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
}
@Override
protected void add(InstanceIdentifier<VpnInstance> identifier,
VpnInstance value) {
- LOG.trace("VPN Instance key: {}, value: {}", identifier, value);
+ LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
VpnAfConfig config = value.getIpv4Family();
String rd = config.getRouteDistinguisher();
if(rd == null) {
+ VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder();
+ builder.setVrfId(value.getVpnInstanceName()).setVpnId(vpnId);
+ builder.setVpnInterfaceCount(0L);
syncWrite(LogicalDatastoreType.OPERATIONAL,
VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()),
- VpnUtil.getVpnInstanceOpDataBuilder(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK);
+ builder.build(), DEFAULT_CALLBACK);
} else {
+ VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder();
+ builder.setVrfId(rd).setVpnId(vpnId);
+ builder.setVpnInterfaceCount(0L);
syncWrite(LogicalDatastoreType.OPERATIONAL,
VpnUtil.getVpnInstanceOpDataIdentifier(rd),
- VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId), DEFAULT_CALLBACK);
+ builder.build(), DEFAULT_CALLBACK);
List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
}
}
//Try to add up vpn Interfaces if already in Operational Datastore
- LOG.trace("Trying to add the vpn interfaces -1.");
InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
private void notifyTaskIfRequired(String vpnName) {
Runnable notifyTask = vpnOpMap.remove(vpnName);
if (notifyTask == null) {
+ LOG.trace("VpnInstanceOpListener update: No Notify Task queued for vpnName {}", vpnName);
return;
}
executorService.execute(notifyTask);
SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
subOpBuilder.setSubnetId(subnetId);
subOpBuilder.setSubnetCidr(subnetIp);
- String rd = VpnUtil.getVpnRd(broker, vpnName);
+ String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(broker, vpnName);
if (rd == null) {
logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
return;
throw e;
}
}
+
+ @Override
+ public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
+ }
+
+ @Override
+ public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
+
+ }
}
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.router.interfaces.RouterInterfaceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
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.dpn.interfaces.ElanDpnInterfacesListKey;
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.fibmanager.rev150330.FibEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
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.l3nexthop.rev150409.L3nexthop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthops;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronPortData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortNameKey;
return rd;
}
+ static String getVpnRdFromVpnInstanceConfig(DataBroker broker, String vpnName) {
+ InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
+ .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
+ Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ String rd = null;
+ if(vpnInstance.isPresent()) {
+ VpnInstance instance = vpnInstance.get();
+ VpnAfConfig config = instance.getIpv4Family();
+ rd = config.getRouteDistinguisher();
+ }
+ return rd;
+ }
+
static org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
getVpnInstanceToVpnId(String vpnName, long vpnId, String rd) {
return new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceBuilder()
return new VpnInstanceOpDataEntryBuilder().setVpnInterfaceCount(count).setVrfId(vrfId).build();
}
+ static InstanceIdentifier<RouterInterface> getRouterInterfaceId(String interfaceName) {
+ return InstanceIdentifier.builder(RouterInterfaces.class)
+ .child(RouterInterface.class, new RouterInterfaceKey(interfaceName)).build();
+ }
+
+ static RouterInterface getRouterInterface(String interfaceName, String routerName) {
+ return new RouterInterfaceBuilder().setKey(new RouterInterfaceKey(interfaceName))
+ .setInterfaceName(interfaceName).setRouterName(routerName).build();
+ }
+
static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(broker, LogicalDatastoreType.OPERATIONAL, id);
public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
String[] subSplit = subnetCidr.split("/");
- LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet Split " + subSplit);
if (subSplit.length < 2) {
return false;
}
}
int prefixLength = Integer.valueOf(subSplit[1]);
int mask = -1 << (32 - prefixLength);
- LOG.trace("SubnetRoutePacketInHandler: prefixLength " + prefixLength + " mask " + mask);
- LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (subnet & mask));
- LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (ipAddress & mask));
if ((subnet & mask) == (ipAddress & mask)) {
return true;
}
return false;
}
+ public static void removePrefixToInterfaceForVpnId(DataBroker broker, long vpnId) {
+ try {
+ // Clean up PrefixToInterface Operational DS
+ delete(broker, LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.builder(PrefixToInterface.class).child(VpnIds.class, new VpnIdsKey(vpnId)).build(),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during cleanup of PrefixToInterface for VPN ID {}", vpnId, e);
+ }
+ }
+
+ public static void removeVpnExtraRouteForVpn(DataBroker broker, String vpnName) {
+ try {
+ // Clean up VPNExtraRoutes Operational DS
+ delete(broker, LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.builder(VpnToExtraroute.class).child(Vpn.class, new VpnKey(vpnName)).build(),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during cleanup of VPNToExtraRoute for VPN {}", vpnName, e);
+ }
+ }
+
+ public static void removeVpnOpInstance(DataBroker broker, String vpnName) {
+ try {
+ // Clean up VPNInstanceOpDataEntry
+ delete(broker, LogicalDatastoreType.OPERATIONAL, getVpnInstanceOpDataIdentifier(vpnName),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during cleanup of VPNInstanceOpDataEntry for VPN {}", vpnName, e);
+ }
+ }
+
+ public static void removeVpnInstanceToVpnId(DataBroker broker, String vpnName) {
+ try {
+ delete(broker, LogicalDatastoreType.CONFIGURATION, getVpnInstanceToVpnIdIdentifier(vpnName),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during clean up of VpnInstanceToVpnId for VPN {}", vpnName, e);
+ }
+ }
+
+ public static void removeVrfTableForVpn(DataBroker broker, String vpnName) {
+ // Clean up FIB Entries Config DS
+ try {
+ delete(broker, LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(vpnName)).build(),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during clean up of VrfTable from FIB for VPN {}", vpnName, e);
+ }
+ }
+
+ public static void removeL3nexthopForVpnId(DataBroker broker, long vpnId) {
+ try {
+ // Clean up L3NextHop Operational DS
+ delete(broker, LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).build(),
+ DEFAULT_CALLBACK);
+ } catch (Exception e) {
+ LOG.error("Exception during cleanup of L3NextHop for VPN ID {}", vpnId, e);
+ }
+ }
}
\ No newline at end of file
notificationService.registerNotificationListener(subnetRoutePacketInHandler);
vpnManager.setVpnInterfaceManager(vpnInterfaceManager);
createIdPool();
+
+ RouterInterfaceListener routerListener = new RouterInterfaceListener(dataBroker);
+ routerListener.setVpnInterfaceManager(vpnInterfaceManager);
} catch (Exception e) {
LOG.error("Error initializing services", e);
}
import org.opendaylight.vpnservice.VpnSubnetRouteHandler;
import org.opendaylight.vpnservice.interfacemgr.globals.IfmConstants;
import org.opendaylight.vpnservice.utilities.InterfaceUtils;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4Family;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance
+ .Ipv4FamilyBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
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.inet.types.rev100924.IpAddressBuilder;
SubnetToDpn subnetToDpn = null;
RdToElanOpEntry rdToElanOpEntry = null;
String subnetIp = "10.1.1.24";
+ String routeDistinguisher = "100:1";
String nexthopIp = null;
String poolName = null;
String interfaceName = "VPN";
DPNTEPsInfo dpntePsInfo = null;
TunnelEndPoints tunlEndPts = null;
IpAddress ipAddress = null;
+ Ipv4Family ipv4Family = null;
String idKey = null;
AllocateIdOutput allocateIdOutput = null;
AllocateIdInput allocateIdInput = null;
+ org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance vpnInstnce;
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
.state.Interface> ifStateId = InterfaceUtils.buildStateInterfaceId(portKey);
child(RdToElanOpEntry.class, new RdToElanOpEntryKey(interfaceName, subnetIp)).build();
InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id
.VpnInstance> instVpnInstance = getVpnInstanceToVpnIdIdentifier(interfaceName);
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.
+ VpnInstance> vpnInstanceIdentifier = InstanceIdentifier.builder(VpnInstances.class).child(org.opendaylight
+ .yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance.class,
+ new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances
+ .VpnInstanceKey(interfaceName)).build();
@Mock DataBroker dataBroker;
@Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
Optional<RdToElanOpEntry> optionalRd;
Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
optionalVpnInstnce;
+ Optional<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance>
+ vpnInstanceOptional;
@Before
public void setUp() throws Exception {
optionalSubnetMap = Optional.of(subnetmap);
optionalRd = Optional.of(rdToElanOpEntry);
optionalVpnInstnce = Optional.of(vpnInstance);
+ vpnInstanceOptional = Optional.of(vpnInstnce);
doReturn(Futures.immediateCheckedFuture(optionalRd)).when(mockReadTx).read(LogicalDatastoreType.OPERATIONAL,
rdIdentifier);
.CONFIGURATION, subMapid);
doReturn(Futures.immediateCheckedFuture(optionalVpnInstnce)).when(mockReadTx).read(LogicalDatastoreType
.CONFIGURATION, instVpnInstance);
+ doReturn(Futures.immediateCheckedFuture(vpnInstanceOptional)).when(mockReadTx).read(LogicalDatastoreType
+ .CONFIGURATION,vpnInstanceIdentifier);
doReturn(idOutputOptional).when(idManager).allocateId(allocateIdInput);
}
private void setupMocks() {
nexthopIp = "10.1.1.25";
- idKey = "VPN.10.1.1.24";
+ idKey = "100:1.10.1.1.24";
poolName = "vpnservices";
elanTag = Long.valueOf(2);
longId = Long.valueOf("100");
.setSubnetIp(subnetIp).setVpnName(interfaceName).setElanTag(elanTag).build();
subnetOp = new SubnetOpDataEntryBuilder().setElanTag(elanTag).setNhDpnId(dpId).setSubnetCidr(subnetIp)
.setSubnetId(subnetId).setKey(new SubnetOpDataEntryKey(subnetId)).setVpnName(interfaceName)
- .setVrfId(interfaceName).setSubnetToDpn(subToDpn).setRouteAdvState(TaskState.Done).build();
+ .setVrfId(routeDistinguisher).setSubnetToDpn(subToDpn).setRouteAdvState(TaskState.Done).build();
vpnInstance = new VpnInstanceBuilder().setVpnId(elanTag).setVpnInstanceName(interfaceName).setVrfId
(interfaceName).setKey(new VpnInstanceKey(interfaceName)).build();
subnetmap = new SubnetmapBuilder().setSubnetIp(subnetIp).setId(subnetId).setNetworkId(portId).setKey(new
rdToElanOpEntry = new RdToElanOpEntryBuilder().setElanTag(elanTag).setRd(interfaceName).setVpnName
(interfaceName).setNextHopIp(nexthopIp)
.setKey(new RdToElanOpEntryKey(interfaceName, subnetIp)).setSubnetIp(subnetIp).build();
+ ipv4Family = new Ipv4FamilyBuilder().setRouteDistinguisher(routeDistinguisher).build();
+ vpnInstnce = new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances
+ .VpnInstanceBuilder().setKey(new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
+ .rev140815.vpn.instances.VpnInstanceKey(interfaceName)).setVpnInstanceName(interfaceName)
+ .setIpv4Family(ipv4Family).build();
doReturn(mockReadTx).when(dataBroker).newReadOnlyTransaction();
doReturn(mockWriteTx).when(dataBroker).newWriteOnlyTransaction();
doReturn(Futures.immediateCheckedFuture(null)).when(mockWriteTx).submit();