From: Vivek Srivastava Date: Thu, 10 Dec 2015 11:51:53 +0000 (+0000) Subject: Merge "Yang changes for l3vpn" X-Git-Tag: release/beryllium~87 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=vpnservice.git;a=commitdiff_plain;h=9f4df02dabc7024ddf94562f7f3e997717fd80b4;hp=3f33c68b5de131d65593dbea1581edf05ce5e0c2 Merge "Yang changes for l3vpn" --- diff --git a/alivenessmonitor/alivenessmonitor-api/pom.xml b/alivenessmonitor/alivenessmonitor-api/pom.xml new file mode 100644 index 00000000..3dfa2e04 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-api/pom.xml @@ -0,0 +1,42 @@ + + + + + org.opendaylight.vpnservice + config-parent + 0.2.0-SNAPSHOT + ../../commons/config-parent + + + 4.0.0 + org.opendaylight.vpnservice + alivenessmonitor-api + ${vpnservices.version} + bundle + + + + org.opendaylight.controller + liblldp + ${liblldp.version} + + + org.opendaylight.mdsal + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.mdsal.model + ietf-inet-types + + + diff --git a/alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang b/alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang new file mode 100644 index 00000000..a9828107 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-api/src/main/yang/aliveness-monitor.yang @@ -0,0 +1,180 @@ +module aliveness-monitor { + namespace "urn:opendaylight:vpnservice:alivenessmonitor"; + prefix alivenessmon; + + import ietf-inet-types { + prefix inet; + } + + revision "2015-06-29" { + description "YANG model describes methods for monitoring endpoints."; + } + + typedef ether-types { + type enumeration { + enum arp; + enum lldp; + } + } + + typedef monitoring-mode { + type enumeration { + enum one-one; + } + } + + grouping endpoint { + choice endpoint-type { + case ip-address { + leaf ip-address { type inet:ip-address; } + } + case interface { + leaf interface-ip { type inet:ip-address; } + leaf interface-name { type string; } + } + case host-name { + leaf host-name { type string; } + } + } + } + + grouping monitor-profile-params { + leaf monitor-interval { type uint32; } //Monitoring interval in milli-seconds + leaf monitor-window { type uint32; } //Number M of consecutive intervals to consider for monitoring + leaf failure-threshold { type uint32; } //Number N of missing messages in window to detect failure ("N out of M") + leaf protocol-type { type ether-types; } + } + + grouping monitor-params { + leaf mode { type monitoring-mode; } + container source { uses endpoint; } + container destination { uses endpoint; } + leaf profile-id { type uint32; } + } + + // RPC Methods + rpc monitor-profile-create { + input { + container profile { + uses monitor-profile-params; + } + } + output { + leaf profile-id { type uint32; } + } + } + + rpc monitor-start { + input { + container config { + uses monitor-params; + } + } + output { + leaf monitor-id { type uint32; } + } + } + + rpc monitor-pause { + input { + leaf monitor-id { type uint32; } + } + } + + rpc monitor-unpause { + input { + leaf monitor-id { type uint32; } + } + } + + + rpc monitor-stop { + input { + leaf monitor-id { type uint32; } + } + } + + rpc monitor-profile-delete { + input { + leaf profile-id { type uint32; } + } + } + + // YANG Notifications + typedef liveness-state { + type enumeration { + enum up; + enum down; + enum unknown; + } + } + + grouping liveness-event-state { + leaf monitor-id { type uint32; } + leaf monitor-state { type liveness-state; } + } + + notification monitor-event { + container event-data { + uses liveness-event-state; + } + } + + //Operational Model + container monitor-profiles { + config false; + list monitor-profile { + key "id"; + leaf id { type uint32; } + uses monitor-profile-params; + } + } + + container monitor-configs { + config false; + list monitoring-info { + key "id"; + leaf id { type uint32; } + uses monitor-params; + } + } + + typedef monitor-status { + type enumeration { + enum started; + enum paused; + enum stopped; + } + } + + container monitoring-states { + config false; + list monitoring-state { + key "monitor-key"; + leaf monitor-key { type string; } //Key to identify monitor-id from packet-in + leaf monitor-id { type uint32; } + leaf response-pending-count { type uint32; } + leaf request-count { type uint32; } + leaf state { type liveness-state; } + leaf status { type monitor-status; } + } + } + + container monitorid-key-map { + config false; + list monitorid-key-entry { + key "monitor-id"; + leaf monitor-id { type uint32; } + leaf monitor-key { type string; } + } + } + + container interface-monitor-map { + config false; + list interface-monitor-entry { + key "interface-name"; + leaf interface-name { type string; } + leaf-list monitor-ids { type uint32; } + } + } +} \ No newline at end of file diff --git a/alivenessmonitor/alivenessmonitor-impl/pom.xml b/alivenessmonitor/alivenessmonitor-impl/pom.xml new file mode 100644 index 00000000..88a49f63 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/pom.xml @@ -0,0 +1,74 @@ + + + + + + org.opendaylight.vpnservice + config-parent + 0.2.0-SNAPSHOT + ../../commons/config-parent + + + 4.0.0 + org.opendaylight.vpnservice + alivenessmonitor-impl + ${vpnservices.version} + bundle + + + org.opendaylight.vpnservice + alivenessmonitor-api + ${vpnservices.version} + + + org.opendaylight.controller + liblldp + ${liblldp.version} + + + org.opendaylight.vpnservice + mdsalutil-api + ${vpnservices.version} + + + org.opendaylight.openflowplugin.model + model-flow-service + ${openflowplugin.version} + + + org.opendaylight.controller.model + model-inventory + ${controller.mdsal.version} + + + org.opendaylight.mdsal.model + ietf-interfaces + + + org.opendaylight.vpnservice + idmanager-api + ${vpnservices.version} + + + org.opendaylight.vpnservice + interfacemgr-api + ${vpnservices.version} + + + org.opendaylight.controller + sal-binding-broker-impl + + + org.opendaylight.vpnservice + arputil-api + ${vpnservices.version} + + + + diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/config/default-config.xml b/alivenessmonitor/alivenessmonitor-impl/src/main/config/default-config.xml new file mode 100644 index 00000000..22b2f23d --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/config/default-config.xml @@ -0,0 +1,44 @@ + + + + + + urn:opendaylight:params:xml:ns:yang:alivenessmonitor:impl?module=alivenessmonitor-impl&revision=2015-07-06 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 + urn:opendaylight:vpnservice:interfacemgr?module=odl-interface&revision=2015-03-31 + + + + + + + prefix:alivenessmonitor-impl + alivenessmonitor-default + + binding:binding-broker-osgi-registry + binding-osgi-broker + + + binding:binding-rpc-registry + binding-rpc-broker + + + bindingimpl:binding-new-notification-publish-service + binding-notification-publish-adapter + + + bindingimpl:binding-new-notification-service + binding-notification-adapter + + + + + + \ No newline at end of file diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java new file mode 100644 index 00000000..9537a9f6 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AbstractAlivenessProtocolHandler.java @@ -0,0 +1,130 @@ +/* + * 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.alivenessmonitor.internal; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +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.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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetNodeconnectorIdFromInterfaceInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetNodeconnectorIdFromInterfaceOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +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.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +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.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; + +abstract class AbstractAlivenessProtocolHandler implements AlivenessProtocolHandler { + + protected ServiceProvider serviceProvider; + private InventoryReader inventoryReader; + + public AbstractAlivenessProtocolHandler(ServiceProvider serviceProvider) { + this.serviceProvider = serviceProvider; + inventoryReader = new InventoryReader(serviceProvider.getDataBroker()); + } + + private InstanceIdentifier getNodeConnectorId(String interfaceName) { + InstanceIdentifier id = InstanceIdentifier.builder(Interfaces.class) + .child(Interface.class, new InterfaceKey(interfaceName)).build(); + + Optional port = read(LogicalDatastoreType.CONFIGURATION, id); + if(port.isPresent()) { + NodeConnectorId ncId = getNodeConnectorIdFromInterface(interfaceName); + NodeId nodeId = getNodeIdFromNodeConnectorId(ncId); + + InstanceIdentifier ncIdentifier = + InstanceIdentifier.builder(Nodes.class) + .child(Node.class, new NodeKey(nodeId)) + .child(NodeConnector.class, new NodeConnectorKey(ncId)).build(); + return ncIdentifier; + } + return null; + } + + private NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName) { + GetNodeconnectorIdFromInterfaceInput input = new GetNodeconnectorIdFromInterfaceInputBuilder().setIntfName(interfaceName).build(); + Future> output = serviceProvider.getInterfaceManager().getNodeconnectorIdFromInterface(input); + RpcResult result = null; + try { + result = output.get(); + if(result.isSuccessful()) { + GetNodeconnectorIdFromInterfaceOutput ncIdOutput = result.getResult(); + return ncIdOutput.getNodeconnectorId(); + } + } catch(ExecutionException | InterruptedException e) { + //TODO: Handle exception + } + + return null; + } + + private NodeId getNodeIdFromNodeConnectorId(NodeConnectorId ncId) { + return new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":"))); + } + + protected byte[] getMacAddress(String interfaceName) { + InstanceIdentifier ncId = getNodeConnectorId(interfaceName); + if(ncId != null) { + String macAddress = inventoryReader.getMacAddress(ncId); + if(!Strings.isNullOrEmpty(macAddress)) { + return AlivenessMonitorUtil.parseMacAddress(macAddress); + } + } + return null; + } + + private InstanceIdentifier getInterfaceIdentifier(InterfaceKey interfaceKey) { + InstanceIdentifier.InstanceIdentifierBuilder interfaceInstanceIdentifierBuilder = + InstanceIdentifier.builder(Interfaces.class).child(Interface.class, interfaceKey); + return interfaceInstanceIdentifierBuilder.build(); + } + + protected Interface getInterfaceFromConfigDS(String interfaceName) { + InterfaceKey interfaceKey = new InterfaceKey(interfaceName); + InstanceIdentifier interfaceId = getInterfaceIdentifier(interfaceKey); + Optional interfaceOptional = read(LogicalDatastoreType.CONFIGURATION, interfaceId); + if (!interfaceOptional.isPresent()) { + return null; + } + + return interfaceOptional.get(); + } + + + private Optional read(LogicalDatastoreType datastoreType, + InstanceIdentifier path) { + + ReadOnlyTransaction tx = serviceProvider.getDataBroker().newReadOnlyTransaction(); + + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + tx.close(); + } + + return result; + } + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java new file mode 100644 index 00000000..a00c7a64 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitor.java @@ -0,0 +1,1288 @@ +/* + * 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.alivenessmonitor.internal; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; +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.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.AlivenessMonitorService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.EtherTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.LivenessState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorEventBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorPauseInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileDeleteInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStatus; +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._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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.EndpointType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfoBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.event.EventData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.event.EventDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.create.input.Profile; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfile; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfileBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.start.input.Config; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringStateBuilder; +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.idmanager.rev150403.ReleaseIdInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; +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.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; +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.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Strings; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +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; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import static org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessMonitorUtil.*; + +public class AlivenessMonitor implements AlivenessMonitorService, PacketProcessingListener, + ServiceProvider, InterfaceStateListener, AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitor.class); + private final DataBroker broker; + private IdManagerService idManager; + private PacketProcessingService packetProcessingService; + private NotificationPublishService notificationPublishService; + private OdlInterfaceRpcService interfaceManager; + private Map, AlivenessProtocolHandler> packetTypeToProtocolHandler; + private Map ethTypeToProtocolHandler; + private ConcurrentMap> monitoringTasks; + private LoadingCache monitorIdKeyCache; + private ScheduledExecutorService monitorService; + private ExecutorService callbackExecutorService; + + private static final int THREAD_POOL_SIZE = 4; + private static final boolean INTERRUPT_TASK = true; + private static final int NO_DELAY = 0; + private static final Long INITIAL_COUNT = 0L; + private static final boolean CREATE_MISSING_PARENT = true; + private static final int INVALID_ID = 0; + private ConcurrentMap lockMap = new ConcurrentHashMap<>(); + + private class FutureCallbackImpl implements FutureCallback { + private String message; + public FutureCallbackImpl(String message) { + this.message = message; + } + + @Override + public void onFailure(Throwable error) { + LOG.warn("Error in Datastore operation - {}", message, error); + } + + @Override + public void onSuccess(Void result) { + LOG.debug("Success in Datastore operation - {}", message); + } + } + + private class AlivenessMonitorTask implements Runnable { + private MonitoringInfo monitoringInfo; + + public AlivenessMonitorTask(MonitoringInfo monitoringInfo) { + this.monitoringInfo = monitoringInfo; + } + + @Override + public void run() { + if(LOG.isTraceEnabled()) { + LOG.trace("send monitor packet - {}", monitoringInfo); + } + sendMonitorPacket(monitoringInfo); + } + } + + public AlivenessMonitor(DataBroker dataBroker) { + broker = dataBroker; + ethTypeToProtocolHandler = new EnumMap<>(EtherTypes.class); + packetTypeToProtocolHandler = new HashMap<>(); + monitorService = Executors.newScheduledThreadPool(THREAD_POOL_SIZE, + getMonitoringThreadFactory("Aliveness Monitoring Task")); + callbackExecutorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE, + getMonitoringThreadFactory("Aliveness Callback Handler")); + monitoringTasks = new ConcurrentHashMap<>(); + initilizeCache(); + } + + private ThreadFactory getMonitoringThreadFactory(String threadNameFormat) { + ThreadFactoryBuilder builder = new ThreadFactoryBuilder(); + builder.setNameFormat(threadNameFormat); + builder.setUncaughtExceptionHandler( new UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error("Received Uncaught Exception event in Thread: {}", t.getName(), e); + } + }); + return builder.build(); + } + + private void initilizeCache() { + monitorIdKeyCache = CacheBuilder.newBuilder() + .build(new CacheLoader() { + @Override + public String load(Long monitorId) throws Exception { + String monitorKey = null; + Optional optKey = read(LogicalDatastoreType.OPERATIONAL, getMonitorMapId(monitorId)); + if(optKey.isPresent()) { + monitorKey = optKey.get().getMonitorKey(); + } + return monitorKey; + } + }); + } + + @Override + public void close() throws Exception { + monitorIdKeyCache.cleanUp(); + monitorService.shutdown(); + callbackExecutorService.shutdown(); + } + + @Override + public DataBroker getDataBroker() { + return broker; + } + + @Override + public OdlInterfaceRpcService getInterfaceManager() { + return interfaceManager; + } + + public void setPacketProcessingService(PacketProcessingService pktProcessingService) { + this.packetProcessingService = pktProcessingService; + } + + public void setNotificationPublishService(NotificationPublishService notificationPublishService) { + this.notificationPublishService = notificationPublishService; + } + + public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) { + this.interfaceManager = interfaceManager; + } + + public void setIdManager(IdManagerService idManager) { + this.idManager = idManager; + createIdPool(); + } + + public void registerHandler(EtherTypes etherType, AlivenessProtocolHandler protocolHandler) { + ethTypeToProtocolHandler.put(etherType, protocolHandler); + packetTypeToProtocolHandler.put(protocolHandler.getPacketClass(), protocolHandler); + } + + private void createIdPool() { + CreateIdPoolInput createPool = new CreateIdPoolInputBuilder() + .setPoolName(AlivenessMonitorConstants.MONITOR_IDPOOL_NAME) + .setLow(AlivenessMonitorConstants.MONITOR_IDPOOL_START) + .setHigh(AlivenessMonitorConstants.MONITOR_IDPOOL_SIZE) + .build(); + Future> result = idManager.createIdPool(createPool); + Futures.addCallback(JdkFutureAdapters.listenInPoolThread(result), new FutureCallback>() { + + @Override + public void onFailure(Throwable error) { + LOG.error("Failed to create idPool for Aliveness Monitor Service",error); + } + + @Override + public void onSuccess(RpcResult result) { + if(result.isSuccessful()) { + LOG.debug("Created IdPool for Aliveness Monitor Service"); + } else { + LOG.error("RPC to create Idpool failed {}", result.getErrors()); + } + } + }); + } + + private int getUniqueId(final String idKey) { + AllocateIdInput getIdInput = new AllocateIdInputBuilder() + .setPoolName(AlivenessMonitorConstants.MONITOR_IDPOOL_NAME) + .setIdKey(idKey).build(); + + Future> result = idManager.allocateId(getIdInput); + + try { + RpcResult rpcResult = result.get(); + if(rpcResult.isSuccessful()) { + return rpcResult.getResult().getIdValue().intValue(); + } else { + 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); + } + return INVALID_ID; + } + + private void releaseId(String idKey) { + ReleaseIdInput idInput = new ReleaseIdInputBuilder() + .setPoolName(AlivenessMonitorConstants.MONITOR_IDPOOL_NAME) + .setIdKey(idKey).build(); + try { + Future> result = idManager.releaseId(idInput); + RpcResult rpcResult = result.get(); + if(!rpcResult.isSuccessful()) { + LOG.warn("RPC Call to release Id {} with Key {} returned with Errors {}", + idKey, rpcResult.getErrors()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when releasing Id for key {}", idKey, e); + } + } + + @Override + public void onPacketReceived(PacketReceived packetReceived) { + Class pktInReason = packetReceived.getPacketInReason(); + if(LOG.isTraceEnabled()) { + LOG.trace("Packet Received {}", packetReceived ); + } + + if (pktInReason == SendToController.class) { + Packet packetInFormatted; + byte[] data = packetReceived.getPayload(); + Ethernet res = new Ethernet(); + try { + packetInFormatted = res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte); + } catch (Exception e) { + LOG.warn("Failed to decode packet: {}", e.getMessage()); + return; + } + + if(packetInFormatted == null) { + LOG.warn("Failed to deserialize Received Packet from table {}", packetReceived.getTableId().getValue()); + return; + } + + Object objPayload = packetInFormatted.getPayload(); + + if(objPayload == null) { + LOG.trace("Unsupported packet type. Ignoring the packet..."); + return; + } + + if (LOG.isTraceEnabled()) { + LOG.trace("onPacketReceived packet: {}, packet class: {}", packetReceived, + objPayload.getClass()); + } + + AlivenessProtocolHandler livenessProtocolHandler = packetTypeToProtocolHandler.get(objPayload.getClass()); + if (livenessProtocolHandler == null) { + return; + } + + String monitorKey = livenessProtocolHandler.handlePacketIn(packetInFormatted.getPayload(), packetReceived); + + if(monitorKey != null) { + processReceivedMonitorKey(monitorKey); + } else { + LOG.debug("No monitorkey associated with received packet"); + } + } + } + + private void processReceivedMonitorKey(final String monitorKey) { + Preconditions.checkNotNull(monitorKey, "Monitor Key required to process the state"); + + LOG.debug("Processing monitorKey: {} for received packet", monitorKey); + + final Semaphore lock = lockMap.get(monitorKey); + LOG.debug("Acquiring lock for monitor key : {} to process monitor packet", monitorKey); + acquireLock(lock); + + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + + ListenableFuture> stateResult = tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey)); + + //READ Callback + Futures.addCallback(stateResult, new FutureCallback>() { + + @Override + public void onSuccess(Optional optState) { + + if(optState.isPresent()) { + final MonitoringState currentState = optState.get(); + + if(LOG.isTraceEnabled()) { + LOG.trace("OnPacketReceived : Monitoring state from ODS : {} ", currentState); + } + + Long responsePendingCount = currentState.getResponsePendingCount(); + + //Need to relook at the pending count logic to support N out of M scenarios +// if(currentState.getState() != LivenessState.Up) { +// //Reset responsePendingCount when state changes from DOWN to UP +// responsePendingCount = INITIAL_COUNT; +// } +// +// if(responsePendingCount > INITIAL_COUNT) { +// responsePendingCount = currentState.getResponsePendingCount() - 1; +// } + responsePendingCount = INITIAL_COUNT; + + final boolean stateChanged = (currentState.getState() == LivenessState.Down || + currentState.getState() == LivenessState.Unknown); + + final MonitoringState state = new MonitoringStateBuilder().setMonitorKey(monitorKey).setState(LivenessState.Up) + .setResponsePendingCount(responsePendingCount).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey), state); + ListenableFuture writeResult = tx.submit(); + + //WRITE Callback + Futures.addCallback(writeResult, new FutureCallback() { + @Override + public void onSuccess(Void noarg) { + releaseLock(lock); + if(stateChanged) { + //send notifications + LOG.info("Sending notification for monitor Id : {} with Current State: {}", + currentState.getMonitorId(), LivenessState.Up); + publishNotification(currentState.getMonitorId(), LivenessState.Up); + } else { + if(LOG.isTraceEnabled()) { + LOG.trace("Successful in writing monitoring state {} to ODS", state); + } + } + } + + @Override + public void onFailure(Throwable error) { + releaseLock(lock); + LOG.warn("Error in writing monitoring state : {} to Datastore", monitorKey, error); + if(LOG.isTraceEnabled()) { + LOG.trace("Error in writing monitoring state: {} to Datastore", state); + } + } + }); + } else { + LOG.warn("Monitoring State not available for key: {} to process the Packet received", monitorKey); + //Complete the transaction + tx.submit(); + releaseLock(lock); + } + } + + @Override + public void onFailure(Throwable error) { + LOG.error("Error when reading Monitoring State for key: {} to process the Packet received", monitorKey, error); + //FIXME: Not sure if the transaction status is valid to cancel + tx.cancel(); + releaseLock(lock); + } + }); + } + + @Override + public PacketProcessingService getPacketProcessingService() { + return packetProcessingService; + } + + private String getIpAddress(EndpointType endpoint) { + String ipAddress = ""; + if( endpoint instanceof IpAddress) { + ipAddress = ((IpAddress) endpoint).getIpAddress().getIpv4Address().getValue(); + } else if (endpoint instanceof Interface) { + ipAddress = ((Interface)endpoint).getInterfaceIp().getIpv4Address().getValue(); + } + return ipAddress; + } + + private String getUniqueKey(String interfaceName, String ethType, EndpointType source, EndpointType destination) { + StringBuilder builder = new StringBuilder().append(interfaceName).append(AlivenessMonitorConstants.SEPERATOR) + .append(ethType); + if(source != null) { + builder.append(AlivenessMonitorConstants.SEPERATOR).append(getIpAddress(source)); + } + + if(destination != null) { + builder.append(AlivenessMonitorConstants.SEPERATOR).append(getIpAddress(destination)); + } + return builder.toString(); + } + + @Override + public Future> monitorStart(MonitorStartInput input) { + RpcResultBuilder rpcResultBuilder; + final Config in = input.getConfig(); + Long profileId = in.getProfileId(); + LOG.debug("Monitor Start invoked with Config: {}, Profile Id: {}", in, profileId); + + try { + if(in.getMode() != MonitoringMode.OneOne) { + throw new UnsupportedConfigException( + "Unsupported Monitoring mode. Currently one-one mode is supported"); + } + + Optional optProfile = read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId)); + final MonitorProfile profile; + if(!optProfile.isPresent()) { + String errMsg = String.format("No monitoring profile associated with Id: %d", profileId); + LOG.error("Monitor start failed. {}", errMsg); + throw new RuntimeException(errMsg); + } else { + profile = optProfile.get(); + } + + EtherTypes ethType = profile.getProtocolType(); + + String interfaceName = null; + EndpointType srcEndpointType = in.getSource().getEndpointType(); + + if( srcEndpointType instanceof Interface) { + Interface endPoint = (Interface) srcEndpointType; + interfaceName = endPoint.getInterfaceName(); + } else { + throw new UnsupportedConfigException( + "Unsupported source Endpoint type. Only Interface Endpoint currently supported for monitoring"); + } + + if(Strings.isNullOrEmpty(interfaceName)) { + throw new RuntimeException("Interface Name not defined in the source Endpoint"); + } + + //Initially the support is for one monitoring per interface. + //Revisit the retrieving monitor id logic when the multiple monitoring for same interface is needed. + EndpointType destEndpointType = null; + if(in.getDestination() != null) { + destEndpointType = in.getDestination().getEndpointType(); + } + String idKey = getUniqueKey(interfaceName, ethType.toString(), srcEndpointType, destEndpointType); + final long monitorId = getUniqueId(idKey); + Optional optKey = read(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId)); + + if(optKey.isPresent()) { + String message = String.format("Monitoring for the interface %s with this configuration is already registered.", interfaceName); + LOG.warn(message); + MonitorStartOutput output = new MonitorStartOutputBuilder().setMonitorId(monitorId).build(); + rpcResultBuilder = RpcResultBuilder.success(output).withWarning(ErrorType.APPLICATION, "config-exists", message); + return Futures.immediateFuture(rpcResultBuilder.build()); + } else { + //Construct the monitor key + final MonitoringInfo monitoringInfo = new MonitoringInfoBuilder() + .setId(monitorId) + .setMode(in.getMode()) + .setProfileId(profileId) + .setDestination(in.getDestination()) + .setSource(in.getSource()).build(); + //Construct the initial monitor state + AlivenessProtocolHandler handler = ethTypeToProtocolHandler.get(ethType); + final String monitoringKey = handler.getUniqueMonitoringKey(monitoringInfo); + + MonitoringState monitoringState = new MonitoringStateBuilder() + .setMonitorKey(monitoringKey) + .setMonitorId(monitorId) + .setState(LivenessState.Unknown) + .setStatus(MonitorStatus.Started) + .setRequestCount(INITIAL_COUNT) + .setResponsePendingCount(INITIAL_COUNT).build(); + + MonitoridKeyEntry mapEntry = new MonitoridKeyEntryBuilder().setMonitorId(monitorId) + .setMonitorKey(monitoringKey).build(); + + WriteTransaction tx = broker.newWriteOnlyTransaction(); + + tx.put(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId), monitoringInfo, CREATE_MISSING_PARENT); + + tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitoringKey), monitoringState, CREATE_MISSING_PARENT); + + tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorMapId(monitorId), mapEntry, CREATE_MISSING_PARENT); + + Futures.addCallback(tx.submit(), new FutureCallback() { + @Override + public void onFailure(Throwable error) { + String errorMsg = String.format("Adding Monitoring info: %s in Datastore failed", monitoringInfo); + LOG.warn(errorMsg, error); + throw new RuntimeException(errorMsg, error); + } + + @Override + public void onSuccess(Void noarg) { + //Schedule task + LOG.debug("Scheduling monitor task for config: {}", in); + scheduleMonitoringTask(monitoringInfo, profile.getMonitorInterval()); + lockMap.put(monitoringKey, new Semaphore(1, true)); + } + }); + } + + associateMonitorIdWithInterface(monitorId, interfaceName); + + MonitorStartOutput output = new MonitorStartOutputBuilder() + .setMonitorId(monitorId).build(); + + rpcResultBuilder = RpcResultBuilder.success(output); + } catch(Exception e) { + LOG.error("Start Monitoring Failed. {}", e.getMessage(), e); + rpcResultBuilder = RpcResultBuilder.failed().withError(ErrorType.APPLICATION, e.getMessage(), e); + } + return Futures.immediateFuture(rpcResultBuilder.build()); + } + + private void associateMonitorIdWithInterface(final Long monitorId, final String interfaceName) { + LOG.debug("associate monitor Id {} with interface {}", monitorId, interfaceName); + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + ListenableFuture> readFuture = + tx.read(LogicalDatastoreType.OPERATIONAL, getInterfaceMonitorMapId(interfaceName)); + ListenableFuture updateFuture = + Futures.transform(readFuture, new AsyncFunction, Void>() { + + @Override + public ListenableFuture apply(Optional optEntry) throws Exception { + if(optEntry.isPresent()) { + InterfaceMonitorEntry entry = optEntry.get(); + List monitorIds = entry.getMonitorIds(); + monitorIds.add(monitorId); + InterfaceMonitorEntry newEntry = new InterfaceMonitorEntryBuilder() + .setKey(new InterfaceMonitorEntryKey(interfaceName)).setMonitorIds(monitorIds).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, getInterfaceMonitorMapId(interfaceName), newEntry); + } else { + //Create new monitor entry + LOG.debug("Adding new interface-monitor association for interface {} with id {}", interfaceName, monitorId); + List monitorIds = new ArrayList<>(); + monitorIds.add(monitorId); + InterfaceMonitorEntry newEntry = + new InterfaceMonitorEntryBuilder().setInterfaceName(interfaceName).setMonitorIds(monitorIds).build(); + tx.put(LogicalDatastoreType.OPERATIONAL, + getInterfaceMonitorMapId(interfaceName), newEntry, CREATE_MISSING_PARENT); + } + return tx.submit(); + } + }); + + Futures.addCallback(updateFuture, new FutureCallbackImpl( + String.format("Association of monitorId %d with Interface %s", monitorId, interfaceName))); + } + + private void scheduleMonitoringTask(MonitoringInfo monitoringInfo, long monitorInterval) { + AlivenessMonitorTask monitorTask = new AlivenessMonitorTask(monitoringInfo); + ScheduledFuture scheduledFutureResult = monitorService.scheduleAtFixedRate( + monitorTask, NO_DELAY, monitorInterval, TimeUnit.MILLISECONDS); + monitoringTasks.put(monitoringInfo.getId(), scheduledFutureResult); + } + + @Override + public Future> monitorPause(MonitorPauseInput input) { + LOG.debug("Monitor Pause operation invoked for monitor id: {}", input.getMonitorId()); + SettableFuture> result = SettableFuture.create(); + final Long monitorId = input.getMonitorId(); + + //Set the monitoring status to Paused + updateMonitorStatusTo(monitorId, MonitorStatus.Paused, new Predicate() { + @Override + public boolean apply(MonitorStatus currentStatus) { + return currentStatus == MonitorStatus.Started; + } + }); + + if(stopMonitoringTask(monitorId)) { + result.set(RpcResultBuilder.success().build()); + } else { + String errorMsg = String.format("No Monitoring Task availble to pause for the given monitor id : %d", monitorId); + LOG.error("Monitor Pause operation failed- {}",errorMsg); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, errorMsg).build()); + } + + return result; + } + + @Override + public Future> monitorUnpause(MonitorUnpauseInput input) { + LOG.debug("Monitor Unpause operation invoked for monitor id: {}", input.getMonitorId()); + final SettableFuture> result = SettableFuture.create(); + + final Long monitorId = input.getMonitorId(); + final ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + ListenableFuture> readInfoResult = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId)); + + Futures.addCallback(readInfoResult, new FutureCallback>() { + + @Override + public void onFailure(Throwable error) { + String msg = String.format("Unable to read monitoring info associated with monitor id %d", monitorId); + LOG.error("Monitor unpause Failed. {}", msg, error); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg, error).build()); + } + + @Override + public void onSuccess(Optional optInfo) { + if(optInfo.isPresent()) { + final MonitoringInfo info = optInfo.get(); + ListenableFuture> readProfile = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(info.getProfileId())); + Futures.addCallback(readProfile, new FutureCallback>(){ + + @Override + public void onFailure(Throwable error) { + String msg = String.format("Unable to read Monitoring profile associated with id %d", info.getProfileId()); + LOG.warn("Monitor unpause Failed. {}", msg, error); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg, error).build()); + } + + @Override + public void onSuccess(Optional optProfile) { + tx.close(); + if(optProfile.isPresent()) { + updateMonitorStatusTo(monitorId, MonitorStatus.Started, new Predicate() { + @Override + public boolean apply(MonitorStatus currentStatus) { + return (currentStatus == MonitorStatus.Paused || + currentStatus == MonitorStatus.Stopped); + } + }); + MonitorProfile profile = optProfile.get(); + LOG.debug("Monitor Resume - Scheduling monitoring task with Id: {}", monitorId); + scheduleMonitoringTask(info, profile.getMonitorInterval()); + result.set(RpcResultBuilder.success().build()); + } else { + String msg = String.format("Monitoring profile associated with id %d is not present", info.getProfileId()); + LOG.warn("Monitor unpause Failed. {}", msg); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg).build()); + } + } + }); + } else { + tx.close(); + String msg = String.format("Monitoring info associated with id %d is not present", monitorId); + LOG.warn("Monitor unpause Failed. {}", msg); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg).build()); + } + } + }, callbackExecutorService); + + return result; + } + + private boolean stopMonitoringTask(Long monitorId) { + return stopMonitoringTask(monitorId, INTERRUPT_TASK); + } + + private boolean stopMonitoringTask(Long monitorId, boolean interruptTask) { + ScheduledFuture scheduledFutureResult = monitoringTasks.get(monitorId); + if(scheduledFutureResult != null) { + scheduledFutureResult.cancel(interruptTask); + return true; + } + return false; + } + + private Optional getMonitorProfile(Long profileId) { + return read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId)); + } + + private void acquireLock(Semaphore lock) { + if(lock == null) { + return; + } + + boolean acquiredLock = false; + try { + acquiredLock = lock.tryAcquire(50, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + LOG.warn("Thread interrupted when waiting to acquire the lock"); + } + + if(!acquiredLock) { + LOG.warn("Previous transaction did not complete in time. Releasing the lock to proceed"); + lock.release(); + try { + lock.acquire(); + LOG.trace("Lock acquired successfully"); + } catch (InterruptedException e) { + LOG.warn("Acquire failed"); + } + } else { + LOG.trace("Lock acquired successfully"); + } + } + + private void releaseLock(Semaphore lock) { + if(lock != null) { + lock.release(); + } + } + + private void sendMonitorPacket(final MonitoringInfo monitoringInfo) { + //TODO: Handle interrupts + final Long monitorId = monitoringInfo.getId(); + final String monitorKey = monitorIdKeyCache.getUnchecked(monitorId); + if(monitorKey == null) { + LOG.warn("No monitor Key associated with id {} to send the monitor packet", monitorId); + return; + } else { + LOG.debug("Sending monitoring packet for key: {}", monitorKey); + } + + final MonitorProfile profile; + Optional optProfile = getMonitorProfile(monitoringInfo.getProfileId()); + if(optProfile.isPresent()) { + profile = optProfile.get(); + } else { + LOG.warn("No monitor profile associated with id {}. " + + "Could not send Monitor packet for monitor-id {}", monitoringInfo.getProfileId(), monitorId); + return; + } + + final Semaphore lock = lockMap.get(monitorKey); + LOG.debug("Acquiring lock for monitor key : {} to send monitor packet", monitorKey); + acquireLock(lock); + + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + ListenableFuture> readResult = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey)); + ListenableFuture writeResult = Futures.transform(readResult, new AsyncFunction, Void>() { + + @Override + public ListenableFuture apply(Optional optState) + throws Exception { + if(optState.isPresent()) { + MonitoringState state = optState.get(); + + //Increase the request count + Long requestCount = state.getRequestCount() + 1; + + //Check with the monitor window + LivenessState currentLivenessState = state.getState(); + + //Increase the pending response count + long responsePendingCount = state.getResponsePendingCount(); + if(responsePendingCount < profile.getMonitorWindow()) { + responsePendingCount = responsePendingCount + 1; + } + + //Check with the failure thresold + if(responsePendingCount >= profile.getFailureThreshold()) { + //Change the state to down and notify + if(currentLivenessState != LivenessState.Down) { + LOG.debug("Response pending Count: {}, Failure threshold: {} for monitorId {}", + responsePendingCount, profile.getFailureThreshold(), state.getMonitorId()); + LOG.info("Sending notification for monitor Id : {} with State: {}", + state.getMonitorId(), LivenessState.Down); + publishNotification(monitorId, LivenessState.Down); + currentLivenessState = LivenessState.Down; + //Reset requestCount when state changes from UP to DOWN + requestCount = INITIAL_COUNT; + } + } + + //Update the ODS with state + MonitoringState updatedState = new MonitoringStateBuilder(/*state*/).setMonitorKey(state.getMonitorKey()) + .setRequestCount(requestCount) + .setResponsePendingCount(responsePendingCount) + .setState(currentLivenessState).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(state.getMonitorKey()), updatedState); + return tx.submit(); + } else { + //Close the transaction + tx.submit(); + String errorMsg = String.format("Monitoring State associated with id %d is not present to send packet out.", monitorId); + return Futures.immediateFailedFuture(new RuntimeException(errorMsg)); + } + } + + }); + + Futures.addCallback(writeResult, new FutureCallback() { + @Override + public void onSuccess(Void noarg) { + //invoke packetout on protocol handler + AlivenessProtocolHandler handler = ethTypeToProtocolHandler.get(profile.getProtocolType()); + if(handler != null) { + LOG.debug("Sending monitoring packet {}", monitoringInfo); + handler.sendPacketOut(monitoringInfo); + } + releaseLock(lock); + } + + @Override + public void onFailure(Throwable error) { + LOG.warn("Updating monitoring state for key: {} failed. Monitoring packet is not sent", monitorKey, error); + releaseLock(lock); + } + + }); + + } + + private void publishNotification(final Long monitorId, final LivenessState state) { + LOG.debug("Sending notification for id {} - state {}", monitorId, state); + EventData data = new EventDataBuilder().setMonitorId(monitorId) + .setMonitorState(state).build(); + MonitorEvent event = new MonitorEventBuilder().setEventData(data).build();; + final ListenableFuture eventFuture = notificationPublishService.offerNotification(event); + Futures.addCallback(eventFuture, new FutureCallback() { + @Override + public void onFailure(Throwable error) { + LOG.warn("Error in notifying listeners for id {} - state {}", monitorId, state, error); + } + + @Override + public void onSuccess(Object arg) { + LOG.trace("Successful in notifying listeners for id {} - state {}", monitorId, state); + } + }); + } + + @Override + public Future> monitorProfileCreate(final MonitorProfileCreateInput input) { + LOG.debug("Monitor Profile Create operation - {}", input.getProfile()); + final SettableFuture> result = SettableFuture.create(); + Profile profile = input.getProfile(); + final Long failureThreshold = profile.getFailureThreshold(); + final Long monitorInterval = profile.getMonitorInterval(); + final Long monitorWindow = profile.getMonitorWindow(); + final EtherTypes ethType = profile.getProtocolType(); + String idKey = getUniqueProfileKey(failureThreshold, monitorInterval, monitorWindow, ethType); + final Long profileId = Long.valueOf(getUniqueId(idKey)); + + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + ListenableFuture> readFuture = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId)); + ListenableFuture> resultFuture = + Futures.transform(readFuture, new AsyncFunction, RpcResult>() { + + @Override + public ListenableFuture> apply( + Optional optProfile) throws Exception { + if(optProfile.isPresent()) { + tx.cancel(); + MonitorProfileCreateOutput output = new MonitorProfileCreateOutputBuilder() + .setProfileId(profileId).build(); + String msg = String.format("Monitor profile %s already present for the given input", input); + LOG.warn(msg); + result.set(RpcResultBuilder.success(output) + .withWarning(ErrorType.PROTOCOL, "profile-exists", msg).build()); + } else { + final MonitorProfile monitorProfile = new MonitorProfileBuilder().setId(profileId) + .setFailureThreshold(failureThreshold) + .setMonitorInterval(monitorInterval) + .setMonitorWindow(monitorWindow) + .setProtocolType(ethType).build(); + tx.put(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId), monitorProfile, CREATE_MISSING_PARENT); + Futures.addCallback(tx.submit(), new FutureCallback() { + @Override + public void onFailure(Throwable error) { + String msg = + String.format("Error when storing monitorprofile %s in datastore", monitorProfile); + LOG.error(msg, error); + result.set(RpcResultBuilder.failed() + .withError(ErrorType.APPLICATION, msg, error).build()); + } + @Override + public void onSuccess(Void noarg) { + MonitorProfileCreateOutput output = new MonitorProfileCreateOutputBuilder() + .setProfileId(profileId).build(); + result.set(RpcResultBuilder.success(output).build()); + } + }); + } + return result; + } + }, callbackExecutorService); + Futures.addCallback(resultFuture, new FutureCallback>() { + @Override + public void onFailure(Throwable error) { + //This would happen when any error happens during reading for monitoring profile + String msg = String.format("Error in creating monitorprofile - %s", input); + result.set(RpcResultBuilder.failed() + .withError(ErrorType.APPLICATION, msg, error).build()); + LOG.error(msg, error); + } + + @Override + public void onSuccess(RpcResult result) { + LOG.debug("Successfully created monitor Profile {} ", input); + } + }, callbackExecutorService); + return result; + } + + private String getUniqueProfileKey(Long failureThreshold,Long monitorInterval,Long monitorWindow,EtherTypes ethType) { + return new StringBuilder().append(failureThreshold).append(AlivenessMonitorConstants.SEPERATOR) + .append(monitorInterval).append(AlivenessMonitorConstants.SEPERATOR) + .append(monitorWindow).append(AlivenessMonitorConstants.SEPERATOR) + .append(ethType).append(AlivenessMonitorConstants.SEPERATOR).toString(); + } + + @Override + public Future> monitorProfileDelete(final MonitorProfileDeleteInput input) { + LOG.debug("Monitor Profile delete for Id: {}", input.getProfileId()); + final SettableFuture> result = SettableFuture.create(); + final Long profileId = input.getProfileId(); + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + ListenableFuture> readFuture = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId)); + ListenableFuture> writeFuture = + Futures.transform(readFuture, new AsyncFunction, RpcResult>() { + + @Override + public ListenableFuture> apply(final Optional optProfile) throws Exception { + if(optProfile.isPresent()) { + tx.delete(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(profileId)); + Futures.addCallback(tx.submit(), new FutureCallback() { + @Override + public void onFailure(Throwable error) { + String msg = String.format("Error when removing monitor profile %d from datastore", profileId); + LOG.error(msg, error); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg, error).build()); + } + + @Override + public void onSuccess(Void noarg) { + MonitorProfile profile = optProfile.get(); + String id = getUniqueProfileKey(profile.getFailureThreshold(), profile.getMonitorInterval(), + profile.getMonitorWindow(), profile.getProtocolType()); + releaseId(id); + result.set(RpcResultBuilder.success().build()); + } + }); + } else { + String msg = String.format("Monitor profile with Id: %d does not exist", profileId); + LOG.info(msg); + result.set(RpcResultBuilder.success().withWarning(ErrorType.PROTOCOL, "invalid-value", msg).build()); + } + return result; + } + }, callbackExecutorService); + + Futures.addCallback(writeFuture, new FutureCallback>() { + + @Override + public void onFailure(Throwable error) { + String msg = String.format("Error when removing monitor profile %d from datastore", profileId); + LOG.error(msg, error); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg, error).build()); + } + + @Override + public void onSuccess(RpcResult noarg) { + LOG.debug("Successfully removed Monitor Profile {}", profileId); + } + }, callbackExecutorService); + return result; + } + + @Override + public Future> monitorStop(MonitorStopInput input) { + LOG.debug("Monitor Stop operation for monitor id - {}", input.getMonitorId()); + SettableFuture> result = SettableFuture.create(); + + final Long monitorId = input.getMonitorId(); + Optional optInfo = read(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId)); + if(optInfo.isPresent()) { + //Stop the monitoring task + stopMonitoringTask(monitorId); + + //Cleanup the Data store + WriteTransaction tx = broker.newWriteOnlyTransaction(); + String monitorKey = monitorIdKeyCache.getUnchecked(monitorId); + if(monitorKey != null) { + tx.delete(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey)); + monitorIdKeyCache.invalidate(monitorId); + } + + tx.delete(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId)); + Futures.addCallback(tx.submit(), + new FutureCallbackImpl(String.format("Delete monitor state with Id %d", monitorId))); + + MonitoringInfo info = optInfo.get(); + String interfaceName = getInterfaceName(info.getSource().getEndpointType()); + if(interfaceName != null) { + removeMonitorIdFromInterfaceAssociation(monitorId, interfaceName); + } + releaseIdForMonitoringInfo(info); + + lockMap.remove(monitorKey); + + result.set(RpcResultBuilder.success().build()); + } else { + String errorMsg = String.format("Do not have monitoring information associated with key %d", monitorId); + LOG.error("Delete monitoring operation Failed - {}", errorMsg); + result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, errorMsg).build()); + } + + return result; + } + + private void removeMonitorIdFromInterfaceAssociation(final Long monitorId, final String interfaceName) { + LOG.debug("Remove monitorId {} from Interface association {}", monitorId, interfaceName); + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + ListenableFuture> readFuture = tx.read(LogicalDatastoreType.OPERATIONAL, getInterfaceMonitorMapId(interfaceName)); + ListenableFuture updateFuture = Futures.transform(readFuture, new AsyncFunction, Void>() { + + @Override + public ListenableFuture apply(Optional optEntry) throws Exception { + if(optEntry.isPresent()) { + InterfaceMonitorEntry entry = optEntry.get(); + List monitorIds = entry.getMonitorIds(); + monitorIds.remove(monitorId); + InterfaceMonitorEntry newEntry = new InterfaceMonitorEntryBuilder(entry) + .setKey(new InterfaceMonitorEntryKey(interfaceName)).setMonitorIds(monitorIds).build(); + tx.put(LogicalDatastoreType.OPERATIONAL, getInterfaceMonitorMapId(interfaceName), newEntry, CREATE_MISSING_PARENT); + return tx.submit(); + } else { + LOG.warn("No Interface map entry found {} to remove monitorId {}", interfaceName, monitorId); + tx.cancel(); + return Futures.immediateFuture(null); + } + } + }); + + Futures.addCallback(updateFuture, new FutureCallbackImpl( + String.format("Dis-association of monitorId %d with Interface %s", monitorId, interfaceName))); + } + + + private void releaseIdForMonitoringInfo(MonitoringInfo info) { + Long monitorId = info.getId(); + EndpointType source = info.getSource().getEndpointType(); + String interfaceName = getInterfaceName(source); + if(!Strings.isNullOrEmpty(interfaceName)) { + Optional optProfile = read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(info.getProfileId())); + if(optProfile.isPresent()) { + EtherTypes ethType = optProfile.get().getProtocolType(); + EndpointType destination = (info.getDestination() != null) ? info.getDestination().getEndpointType() : null; + String idKey = getUniqueKey(interfaceName, ethType.toString(), source, destination); + releaseId(idKey); + } else { + LOG.warn("Could not release monitorId {}. No profile associated with it", monitorId); + } + } + } + + private String getInterfaceName(EndpointType endpoint) { + String interfaceName = null; + if(endpoint instanceof Interface) { + interfaceName = ((Interface)endpoint).getInterfaceName(); + } + return interfaceName; + } + + private void stopMonitoring(long monitorId) { + updateMonitorStatusTo(monitorId, MonitorStatus.Stopped, new Predicate() { + @Override + public boolean apply(MonitorStatus currentStatus) { + return currentStatus != MonitorStatus.Stopped; + } + }); + if(!stopMonitoringTask(monitorId)) { + LOG.warn("No monitoring task running to perform cancel operation for monitorId {}", monitorId); + } + } + + private void updateMonitorStatusTo(final Long monitorId, final MonitorStatus newStatus, final Predicate isValidStatus) { + final String monitorKey = monitorIdKeyCache.getUnchecked(monitorId); + if(monitorKey == null) { + LOG.warn("No monitor Key associated with id {} to change the monitor status to {}", monitorId, newStatus); + return; + } + final ReadWriteTransaction tx = broker.newReadWriteTransaction(); + + ListenableFuture> readResult = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey)); + + ListenableFuture writeResult = Futures.transform(readResult, new AsyncFunction, Void>() { + @Override + public ListenableFuture apply(Optional optState) throws Exception { + if(optState.isPresent()) { + MonitoringState state = optState.get(); + if(isValidStatus.apply(state.getStatus())) { + MonitoringState updatedState = new MonitoringStateBuilder().setMonitorKey(monitorKey) + .setStatus(newStatus).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey), updatedState); + } else { + LOG.warn("Invalid Monitoring status {}, cannot be updated to {} for monitorId {}" + , state.getStatus(), newStatus, monitorId); + } + } else { + LOG.warn("No associated monitoring state data available to update the status to {} for {}", newStatus, monitorId); + } + return tx.submit(); + } + }); + + Futures.addCallback(writeResult, + new FutureCallbackImpl(String.format("Monitor status update for %d to %s", monitorId, newStatus.toString()))); + } + + private void resumeMonitoring(final long monitorId) { + final ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + ListenableFuture> readInfoResult = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitoringInfoId(monitorId)); + + Futures.addCallback(readInfoResult, new FutureCallback>() { + + @Override + public void onFailure(Throwable error) { + String msg = String.format("Unable to read monitoring info associated with monitor id %d", monitorId); + LOG.error("Monitor resume Failed. {}", msg, error); + } + + @Override + public void onSuccess(Optional optInfo) { + if(optInfo.isPresent()) { + final MonitoringInfo info = optInfo.get(); + ListenableFuture> readProfile = + tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorProfileId(info.getProfileId())); + Futures.addCallback(readProfile, new FutureCallback>(){ + + @Override + public void onFailure(Throwable error) { + String msg = String.format("Unable to read Monitoring profile associated with id %d", info.getProfileId()); + LOG.warn("Monitor resume Failed. {}", msg, error); + } + + @Override + public void onSuccess(Optional optProfile) { + tx.close(); + if(optProfile.isPresent()) { + updateMonitorStatusTo(monitorId, MonitorStatus.Started, new Predicate() { + @Override + public boolean apply(MonitorStatus currentStatus) { + return currentStatus != MonitorStatus.Started; + } + }); + MonitorProfile profile = optProfile.get(); + LOG.debug("Monitor Resume - Scheduling monitoring task for Id: {}", monitorId); + scheduleMonitoringTask(info, profile.getMonitorInterval()); + } else { + String msg = String.format("Monitoring profile associated with id %d is not present", info.getProfileId()); + LOG.warn("Monitor resume Failed. {}", msg); + } + } + }); + } else { + tx.close(); + String msg = String.format("Monitoring info associated with id %d is not present", monitorId); + LOG.warn("Monitor resume Failed. {}", msg); + } + } + }); + } + + //DATA STORE OPERATIONS + private Optional read(LogicalDatastoreType datastoreType, InstanceIdentifier path) { + ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Error reading data from path {} in datastore {}", path, datastoreType, e); + } finally { + tx.close(); + } + + return result; + } + + @Override + public void onInterfaceStateUp(String interfaceName) { + List monitorIds = getMonitorIds(interfaceName); + if(monitorIds.isEmpty()) { + LOG.warn("Could not get monitorId for interface: {}", interfaceName); + return; + } + for(Long monitorId : monitorIds) { + LOG.debug("Resume monitoring on interface: {} with monitorId: {}", interfaceName, monitorId); + resumeMonitoring(monitorId); + } + } + + @Override + public void onInterfaceStateDown(String interfaceName) { + List monitorIds = getMonitorIds(interfaceName); + if(monitorIds.isEmpty()) { + LOG.warn("Could not get monitorIds for interface: {}", interfaceName); + return; + } + for(Long monitorId : monitorIds) { + LOG.debug("Suspend monitoring on interface: {} with monitorId: {}", interfaceName, monitorId); + stopMonitoring(monitorId); + } + } + + private List getMonitorIds(String interfaceName) { + Optional optEntry = read(LogicalDatastoreType.OPERATIONAL, + getInterfaceMonitorMapId(interfaceName)); + if(optEntry.isPresent()) { + InterfaceMonitorEntry entry = optEntry.get(); + return entry.getMonitorIds(); + } + return Collections.emptyList(); + } + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorConstants.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorConstants.java new file mode 100644 index 00000000..55176012 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorConstants.java @@ -0,0 +1,16 @@ +/* + * 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.alivenessmonitor.internal; + +public class AlivenessMonitorConstants { + static final String MONITOR_IDPOOL_NAME = "aliveness-monitor"; + static final long MONITOR_IDPOOL_START = 1L; + static final long MONITOR_IDPOOL_SIZE = 65535; + static final short L3_INTERFACE_TABLE = 80; + static final String SEPERATOR = "."; +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorProvider.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorProvider.java new file mode 100644 index 00000000..d118cc95 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorProvider.java @@ -0,0 +1,95 @@ +/* + * 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.alivenessmonitor.internal; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +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.alivenessmonitor.rev150629.AlivenessMonitorService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.EtherTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService; +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.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AlivenessMonitorProvider implements BindingAwareProvider, + AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorProvider.class); + private AlivenessMonitor alivenessMonitor; + private RpcProviderRegistry rpcProviderRegistry; + private OdlInterfaceRpcService interfaceManager; + private RpcRegistration rpcRegistration; + private ListenerRegistration listenerRegistration; + private NotificationService notificationService; + private NotificationPublishService notificationPublishService; + + public AlivenessMonitorProvider(RpcProviderRegistry rpcProviderRegistry) { + this.rpcProviderRegistry = rpcProviderRegistry; + } + + public RpcProviderRegistry getRpcProviderRegistry() { + return rpcProviderRegistry; + } + + public void setNotificationService(NotificationService notificationService) { + this.notificationService = notificationService; + } + + public void setNotificationPublishService(NotificationPublishService notificationPublishService) { + this.notificationPublishService = notificationPublishService; + } + + @Override + public void close() throws Exception { + rpcRegistration.close(); + listenerRegistration.close(); + alivenessMonitor.close(); + } + + @Override + public void onSessionInitiated(ProviderContext session) { + LOG.info("AlivenessMonitorProvider Session Initiated"); + try { + 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); + alivenessMonitor = new AlivenessMonitor(dataBroker); + alivenessMonitor.setPacketProcessingService(pktProcessingService); + alivenessMonitor.setNotificationPublishService(notificationPublishService); + alivenessMonitor.setIdManager(idManager); + alivenessMonitor.setInterfaceManager(interfaceService); + rpcRegistration = getRpcProviderRegistry().addRpcImplementation(AlivenessMonitorService.class, alivenessMonitor); + listenerRegistration = notificationService.registerNotificationListener(alivenessMonitor); + + //ARP Handler + AlivenessProtocolHandler arpHandler = new AlivenessProtocolHandlerARP(alivenessMonitor); + OdlArputilService arpService = rpcProviderRegistry.getRpcService(OdlArputilService.class); + ((AlivenessProtocolHandlerARP) arpHandler).setArpManagerService(arpService); + alivenessMonitor.registerHandler(EtherTypes.Arp, arpHandler); + + //LLDP Handler + AlivenessProtocolHandler lldpHandler = new AlivenessProtocolHandlerLLDP(alivenessMonitor); + alivenessMonitor.registerHandler(EtherTypes.Lldp, lldpHandler); + + //TODO: Enable Interface Event Listener + //DelegatingInterfaceEventListener listener = new DelegatingInterfaceEventListener(alivenessMonitor); + //interfaceListenerRegistration = notificationService.registerNotificationListener(listener); + } catch (Exception e) { + LOG.error("Error initializing AlivenessMonitor service", e); + } + } + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorUtil.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorUtil.java new file mode 100644 index 00000000..d85d09ac --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessMonitorUtil.java @@ -0,0 +1,119 @@ +/* + * 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.alivenessmonitor.internal; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.InterfaceMonitorMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorConfigs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfiles; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitoridKeyMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitoringStates; +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.InterfaceMonitorEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfoKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfile; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfileKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringStateKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.primitives.UnsignedBytes; + +public class AlivenessMonitorUtil { + + static InstanceIdentifier getMonitorStateId(String keyId) { + return InstanceIdentifier.builder(MonitoringStates.class) + .child(MonitoringState.class, new MonitoringStateKey(keyId)).build(); + } + + static InstanceIdentifier getMonitoringInfoId(Long monitorId) { + return InstanceIdentifier.builder(MonitorConfigs.class) + .child(MonitoringInfo.class, new MonitoringInfoKey(monitorId)).build(); + } + + static InstanceIdentifier getMonitorProfileId(Long profileId) { + return InstanceIdentifier.builder(MonitorProfiles.class) + .child(MonitorProfile.class, new MonitorProfileKey(profileId)).build(); + } + + static InstanceIdentifier getMonitorMapId(Long keyId) { + return InstanceIdentifier.builder(MonitoridKeyMap.class) + .child(MonitoridKeyEntry.class, new MonitoridKeyEntryKey(keyId)).build(); + } + + static InstanceIdentifier getInterfaceMonitorMapId(String interfaceName) { + return InstanceIdentifier.builder(InterfaceMonitorMap.class) + .child(InterfaceMonitorEntry.class, new InterfaceMonitorEntryKey(interfaceName)).build(); + } + + public static String toStringIpAddress(byte[] ipAddress) + { + String ip = ""; + if (ipAddress == null) { + return ip; + } + + try { + ip = InetAddress.getByAddress(ipAddress).getHostAddress(); + } catch(UnknownHostException e) { } + + return ip; + } + + public static String toStringMacAddress(byte[] macAddress) + { + if (macAddress == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(18); + + for (int i = 0; i < macAddress.length; i++) { + sb.append(UnsignedBytes.toString(macAddress[i], 16).toUpperCase()); + sb.append(":"); + } + + sb.setLength(17); + return sb.toString(); + } + + public static byte[] parseIpAddress(String ipAddress) { + byte cur; + + String[] addressPart = ipAddress.split("."); + int size = addressPart.length; + + byte[] part = new byte[size]; + for (int i = 0; i < size; i++) { + cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16); + part[i] = cur; + } + + return part; + } + + public static byte[] parseMacAddress(String macAddress) { + byte cur; + + String[] addressPart = macAddress.split(":"); + int size = addressPart.length; + + byte[] part = new byte[size]; + for (int i = 0; i < size; i++) { + cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16); + part[i] = cur; + } + + return part; + } +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandler.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandler.java new file mode 100644 index 00000000..5fcc8a5d --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandler.java @@ -0,0 +1,29 @@ +/* + * 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.alivenessmonitor.internal; + +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; + +/** + * Protocol specific Handler interface defined by the Aliveness monitor service + * Handler will be registered with Alivnessmonitor service along with the protocol type + * it supports. + * + */ +public interface AlivenessProtocolHandler { + + Class getPacketClass(); + + String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived); + + void sendPacketOut(MonitoringInfo monitorInfo); + + String getUniqueMonitoringKey(MonitoringInfo monitorInfo); +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerARP.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerARP.java new file mode 100644 index 00000000..33fb6ad9 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerARP.java @@ -0,0 +1,186 @@ +/* + * 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.alivenessmonitor.internal; + +import static org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessMonitorUtil.toStringIpAddress; +import static org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessMonitorConstants.*; + +import java.math.BigInteger; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; +import org.opendaylight.vpnservice.mdsalutil.packet.ARP; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.EtherTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.EndpointType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.interfaces.InterfaceAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.interfaces.InterfaceAddressBuilder; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.JdkFutureAdapters; + +public class AlivenessProtocolHandlerARP extends AbstractAlivenessProtocolHandler { + private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerARP.class); + private OdlArputilService arpService; + + public AlivenessProtocolHandlerARP(ServiceProvider serviceProvider) { + super(serviceProvider); + } + + void setArpManagerService(OdlArputilService arpService) { + this.arpService = arpService; + } + + @Override + public Class getPacketClass() { + return ARP.class; + } + + @Override + public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) { + ARP packet = (ARP) protocolPacket; + short tableId = packetReceived.getTableId().getValue(); + int arpType = packet.getOpCode(); + + if (LOG.isTraceEnabled()) { + LOG.trace("packet: {}, tableId {}, arpType {}", packetReceived, tableId, arpType); + } + + if (tableId == AlivenessMonitorConstants.L3_INTERFACE_TABLE) { + if (arpType == ARP.REPLY) { + if (LOG.isTraceEnabled()) { + LOG.trace("packet: {}, monitorKey {}", packetReceived); + } + + BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata(); + int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue(); + String interfaceName = null; + NodeConnectorId connId = packetReceived.getMatch().getInPort(); +// try { +// interfaceName = serviceProvider.getInterfaceManager().getInterfaceNameForInterfaceTag(portTag); +// } catch(InterfaceNotFoundException e) { +// LOG.warn("Error retrieving interface Name for tag {}", portTag, e); +// } + if(!Strings.isNullOrEmpty(interfaceName)) { + String sourceIp = toStringIpAddress(packet.getSenderProtocolAddress()); + String targetIp = toStringIpAddress(packet.getTargetProtocolAddress()); + return getMonitoringKey(interfaceName, targetIp, sourceIp); + } else { + LOG.debug("No interface associated with tag {} to interpret the received ARP Reply", portTag); + } + } + } + return null; + } + + @Override + public void sendPacketOut(MonitoringInfo monitorInfo) { + if(arpService == null) { + LOG.debug("ARP Service not available to send the packet"); + return; + } + EndpointType source = monitorInfo.getSource().getEndpointType(); + final String sourceInterface = Preconditions.checkNotNull(getInterfaceName(source), + "Source interface is required to send ARP Packet for monitoring"); + + final String srcIp = Preconditions.checkNotNull(getIpAddress(source), + "Source Ip address is required to send ARP Packet for monitoring"); + + EndpointType target = monitorInfo.getDestination().getEndpointType(); + final String targetIp = Preconditions.checkNotNull(getIpAddress(target), + "Target Ip address is required to send ARP Packet for monitoring"); + + if (LOG.isTraceEnabled()) { + LOG.trace("sendArpRequest interface {}, senderIPAddress {}, targetAddress {}", sourceInterface, srcIp, targetIp); + } + + List addresses = Collections.singletonList( + new InterfaceAddressBuilder().setInterface(sourceInterface) + .setIpAddress(IpAddressBuilder.getDefaultInstance(srcIp)).build()); + SendArpRequestInput input = new SendArpRequestInputBuilder().setInterfaceAddress(addresses) + .setIpaddress(IpAddressBuilder.getDefaultInstance(targetIp)).build(); + Future> future = arpService.sendArpRequest(input); + + final String msgFormat = String.format("Send ARP Request on interface %s to destination %s", sourceInterface, targetIp); + Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback>() { + @Override + public void onFailure(Throwable error) { + LOG.error("Error - {}", msgFormat, error); + } + + @Override + public void onSuccess(RpcResult result) { + if(!result.isSuccessful()) { + LOG.warn("Rpc call to {} failed {}", msgFormat, getErrorText(result.getErrors())); + } else { + LOG.debug("Successful RPC Result - {}", msgFormat); + } + } + }); + } + + private String getErrorText(Collection errors) { + StringBuilder errorText = new StringBuilder(); + for(RpcError error : errors) { + errorText.append(",").append(error.getErrorType()).append("-") + .append(error.getMessage()); + } + return errorText.toString(); + } + + @Override + public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) { + String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType()); + String sourceIp = getIpAddress(monitorInfo.getSource().getEndpointType()); + String targetIp = getIpAddress(monitorInfo.getDestination().getEndpointType()); + return getMonitoringKey(interfaceName, sourceIp, targetIp); + } + + private String getMonitoringKey(String interfaceName, String sourceIp, String targetIp) { + return new StringBuilder().append(interfaceName).append(SEPERATOR).append(sourceIp) + .append(SEPERATOR).append(targetIp).append(SEPERATOR).append(EtherTypes.Arp).toString(); + } + + private String getIpAddress(EndpointType source) { + String ipAddress = null; + if( source instanceof IpAddress) { + ipAddress = ((IpAddress) source).getIpAddress().getIpv4Address().getValue(); + } else if (source instanceof Interface) { + ipAddress = ((Interface)source).getInterfaceIp().getIpv4Address().getValue(); + } + return ipAddress; + } + + private String getInterfaceName(EndpointType endpoint) { + String interfaceName = null; + if(endpoint instanceof Interface) { + interfaceName = ((Interface)endpoint).getInterfaceName(); + } + return interfaceName; + } + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java new file mode 100644 index 00000000..d0391519 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/AlivenessProtocolHandlerLLDP.java @@ -0,0 +1,319 @@ +/* + * 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.alivenessmonitor.internal; + +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.Future; + +import org.apache.commons.lang3.StringUtils; +import org.opendaylight.controller.liblldp.EtherTypes; +import org.opendaylight.controller.liblldp.LLDP; +import org.opendaylight.controller.liblldp.LLDPTLV; +import org.opendaylight.controller.liblldp.LLDPTLV.TLVType; +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.controller.liblldp.PacketException; +import org.opendaylight.vpnservice.mdsalutil.ActionInfo; +import org.opendaylight.vpnservice.mdsalutil.ActionType; +import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; +import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; +import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.EndpointType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +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.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +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.GetDpidFromInterfaceInput; +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.GetPortFromInterfaceInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Strings; + +public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandler { + private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerLLDP.class); + private AtomicInteger packetId = new AtomicInteger(0); + + public AlivenessProtocolHandlerLLDP(ServiceProvider serviceProvider) { + super(serviceProvider); + } + + @Override + public Class getPacketClass() { + return LLDP.class; + } + + @Override + public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) { + String sSourceDpnId = null; + String sPortNumber = null; + int nServiceId = -1; + int packetId = 0; + + String sTmp = null; + + byte lldpTlvTypeCur; + + LLDP lldpPacket = (LLDP)protocolPacket; + + LLDPTLV lldpTlvCur = lldpPacket.getSystemNameId(); + if (lldpTlvCur != null) { + sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset()); + } + + lldpTlvCur = lldpPacket.getPortId(); + if (lldpTlvCur != null) { + sPortNumber = new String(lldpTlvCur.getValue(), Charset.defaultCharset()); + } + + for (LLDPTLV lldpTlv : lldpPacket.getOptionalTLVList()) { + lldpTlvTypeCur = lldpTlv.getType(); + + if (lldpTlvTypeCur == LLDPTLV.TLVType.SystemName.getValue()) { + sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset()); + } + } + + for (LLDPTLV lldpTlv : lldpPacket.getCustomTlvList()) { + lldpTlvTypeCur = lldpTlv.getType(); + + if (lldpTlvTypeCur == LLDPTLV.TLVType.Custom.getValue()) { + sTmp = new String(lldpTlv.getValue()); + nServiceId = 0; + } + } + + String interfaceName = null; + + //TODO: Check if the below fields are required + if (!Strings.isNullOrEmpty(sTmp) && sTmp.contains("#")) { + String[] asTmp = sTmp.split("#"); + interfaceName = asTmp[0]; + packetId = Integer.parseInt(asTmp[1]); + LOG.debug("Custom LLDP Value on received packet: " + sTmp); + } + + BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata(); + int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue(); + if(portTag == 0) { + LOG.trace("Ignoring Packet-in for interface tag 0"); + return null; + } + + String destInterfaceName = null; + //TODO: Use latest interface RPC +// try { +// destInterfaceName = serviceProvider.getInterfaceManager().getInterfaceNameForInterfaceTag(portTag); +// } catch(InterfaceNotFoundException e) { +// LOG.warn("Error retrieving interface Name for tag {}", portTag, e); +// } + + if(!Strings.isNullOrEmpty(interfaceName)) { + String monitorKey = new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString(); + return monitorKey; + } else { + LOG.debug("No interface associated with tag {} to handle received LLDP Packet", portTag); + } + return null; + } + + @Override + public void sendPacketOut(MonitoringInfo monitorInfo) { + String sourceInterface; + + EndpointType source = monitorInfo.getSource().getEndpointType(); + if( source instanceof Interface) { + Interface intf = (Interface)source; + sourceInterface = intf.getInterfaceName(); + } else { + LOG.warn("Invalid source endpoint. Could not retrieve source interface to send LLDP Packet"); + return; + } + + //Get Mac Address for the source interface + byte[] sourceMac = getMacAddress(sourceInterface); + if(sourceMac == null) { + LOG.error("Could not read mac address for the source interface {} from the Inventory. " + + "LLDP packet cannot be send.", sourceInterface); + return; + } + + OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager(); + + long nodeId = -1, portNum = -1; + try { + GetDpidFromInterfaceInput dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(sourceInterface).build(); + Future> dpIdOutput = interfaceService.getDpidFromInterface(dpIdInput); + RpcResult dpIdResult = dpIdOutput.get(); + if(dpIdResult.isSuccessful()) { + GetDpidFromInterfaceOutput output = dpIdResult.getResult(); + nodeId = output.getDpid().longValue(); + } else { + LOG.error("Could not retrieve DPN Id for interface {}", sourceInterface); + return; + } + + + GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(sourceInterface).build(); + Future> portOutput = interfaceService.getPortFromInterface(input); + RpcResult result = portOutput.get(); + if(result.isSuccessful()) { + GetPortFromInterfaceOutput output = result.getResult(); + portNum = output.getPortno(); + } else { + LOG.error("Could not retrieve port number for interface {}", sourceInterface); + return; + } + }catch(InterruptedException | ExecutionException e) { + LOG.error("Failed to retrieve RPC Result ", e); + return; + } + + Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface); + + try { + List actions = getInterfaceActions(sourceInterface); + if(actions.isEmpty()) { + LOG.error("No interface actions to send packet out over interface {}", sourceInterface); + return; + } + TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions, + ethenetLLDPPacket.serialize(), nodeId, MDSALUtil.getNodeConnRef(BigInteger.valueOf(nodeId), "0xfffffffd")); + serviceProvider.getPacketProcessingService().transmitPacket(transmitPacketInput); + } catch (Exception e) { + LOG.error("Error while sending LLDP Packet", e); + } + } + + private List getInterfaceActions(String interfaceName) throws InterruptedException, ExecutionException { + + OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager(); + + long portNum = -1; + GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(interfaceName).build(); + Future> portOutput = interfaceService.getPortFromInterface(input); + RpcResult result = portOutput.get(); + if(result.isSuccessful()) { + GetPortFromInterfaceOutput output = result.getResult(); + portNum = output.getPortno(); + } else { + LOG.error("Could not retrieve port number for interface {} to construct actions", interfaceName); + return Collections.emptyList(); + } + + Class intfType = null; + 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(); + } else { + LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceName); + return Collections.emptyList(); + } + + List actionInfos = new ArrayList(); + + if(Tunnel.class.equals(intfType)) { + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { + MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(0x08000000), + MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID})); + } + actionInfos.add(new ActionInfo(ActionType.output, new String[] { Long.toString(portNum) })); + return actionInfos; + } + + private static LLDPTLV buildLLDTLV(LLDPTLV.TLVType tlvType,byte[] abyTLV) { + return new LLDPTLV().setType(tlvType.getValue()).setLength((short) abyTLV.length).setValue(abyTLV); + } + + private int getPacketId() { + int id = packetId.incrementAndGet(); + if(id > 16000) { + LOG.debug("Resetting the LLDP Packet Id counter"); + packetId.set(0); + } + + return id; + } + + public Ethernet makeLLDPPacket(String nodeId, + long portNum, int serviceId, byte[] srcMac, String sourceInterface) { + + // Create LLDP TTL TLV + LLDPTLV lldpTlvTTL = buildLLDTLV(LLDPTLV.TLVType.TTL, new byte[] { (byte) 0, (byte) 120 }); + + LLDPTLV lldpTlvChassisId = buildLLDTLV(LLDPTLV.TLVType.ChassisID, LLDPTLV.createChassisIDTLVValue(colonize(StringUtils + .leftPad(Long.toHexString(MDSALUtil.getDpnIdFromNodeName(nodeId).longValue()), 16, + "0")))); + LLDPTLV lldpTlvSystemName = buildLLDTLV(TLVType.SystemName, LLDPTLV.createSystemNameTLVValue(nodeId)); + + LLDPTLV lldpTlvPortId = buildLLDTLV(TLVType.PortID, LLDPTLV.createPortIDTLVValue( + Long.toHexString(portNum))); + + String customValue = sourceInterface + "#" + getPacketId(); + + LOG.debug("Sending LLDP packet, custome value " + customValue); + + LLDPTLV lldpTlvCustom = buildLLDTLV(TLVType.Custom, customValue.getBytes()); + + List lstLLDPTLVCustom = new ArrayList<>(); + lstLLDPTLVCustom.add(lldpTlvCustom); + + LLDP lldpDiscoveryPacket = new LLDP(); + lldpDiscoveryPacket.setChassisId(lldpTlvChassisId) + .setPortId(lldpTlvPortId) + .setTtl(lldpTlvTTL) + .setSystemNameId(lldpTlvSystemName) + .setOptionalTLVList(lstLLDPTLVCustom); + + byte[] destMac = LLDP.LLDPMulticastMac; + + Ethernet ethernetPacket = new Ethernet(); + ethernetPacket.setSourceMACAddress(srcMac) + .setDestinationMACAddress(destMac) + .setEtherType(EtherTypes.LLDP.shortValue()) + .setPayload(lldpDiscoveryPacket); + + return ethernetPacket; + } + + private String colonize(String orig) { + return orig.replaceAll("(?<=..)(..)", ":$1"); + } + + @Override + public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) { + String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType()); + return new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString(); + } + + private String getInterfaceName(EndpointType endpoint) { + String interfaceName = null; + if(endpoint instanceof Interface) { + interfaceName = ((Interface)endpoint).getInterfaceName(); + } + return interfaceName; + } + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InterfaceStateListener.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InterfaceStateListener.java new file mode 100644 index 00000000..7494e2e2 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InterfaceStateListener.java @@ -0,0 +1,16 @@ +/* + * 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.alivenessmonitor.internal; + +interface InterfaceStateListener { + + void onInterfaceStateUp(String interfaceName); + + void onInterfaceStateDown(String interfaceName); + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InventoryReader.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InventoryReader.java new file mode 100644 index 00000000..941d3023 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/InventoryReader.java @@ -0,0 +1,59 @@ +/* + * 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.alivenessmonitor.internal; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +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.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.primitives.UnsignedBytes; + +class InventoryReader { + private Logger LOG = LoggerFactory.getLogger(InventoryReader.class); + private DataBroker dataService; + + public InventoryReader(DataBroker dataService) { + this.dataService = dataService; + } + + public String getMacAddress(InstanceIdentifier nodeConnectorId) { + //TODO: Use mdsal apis to read + Optional optNc = read(LogicalDatastoreType.OPERATIONAL, nodeConnectorId); + if(optNc.isPresent()) { + NodeConnector nc = optNc.get(); + FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); + MacAddress macAddress = fcnc.getHardwareAddress(); + return macAddress.getValue(); + } + return null; + } + + private Optional read(LogicalDatastoreType datastoreType, + InstanceIdentifier path) { + + ReadOnlyTransaction tx = dataService.newReadOnlyTransaction(); + + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + tx.close(); + + return result; + } +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/ServiceProvider.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/ServiceProvider.java new file mode 100644 index 00000000..4f92d078 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/ServiceProvider.java @@ -0,0 +1,26 @@ +/* + * 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.alivenessmonitor.internal; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +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; + +/** + * Provides access methods to retrieve the reference to the dependent service + * + */ +interface ServiceProvider { + + DataBroker getDataBroker(); + + PacketProcessingService getPacketProcessingService(); + + OdlInterfaceRpcService getInterfaceManager(); + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/UnsupportedConfigException.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/UnsupportedConfigException.java new file mode 100644 index 00000000..121ae23c --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/vpnservice/alivenessmonitor/internal/UnsupportedConfigException.java @@ -0,0 +1,21 @@ +/* + * 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.alivenessmonitor.internal; + +/** + * Exception indicating the config provided is not supported currently + * + * + */ +public class UnsupportedConfigException extends Exception { + private static final long serialVersionUID = 1L; + + public UnsupportedConfigException(String message){ + super(message); + } +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModule.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModule.java new file mode 100644 index 00000000..2e303f41 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModule.java @@ -0,0 +1,34 @@ +/* + * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alivenessmonitor.impl.rev150706; + +import org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessMonitorProvider; + +public class AlivenessMonitorModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alivenessmonitor.impl.rev150706.AbstractAlivenessMonitorModule { + public AlivenessMonitorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public AlivenessMonitorModule(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.alivenessmonitor.impl.rev150706.AlivenessMonitorModule 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() { + AlivenessMonitorProvider provider = new AlivenessMonitorProvider(getRpcRegistryDependency()); + provider.setNotificationPublishService(getNotificationPublishServiceDependency()); + provider.setNotificationService(getNotificationServiceDependency()); + getBrokerDependency().registerProvider(provider); + return provider; + } +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModuleFactory.java b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModuleFactory.java new file mode 100644 index 00000000..b237356b --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/alivenessmonitor/impl/rev150706/AlivenessMonitorModuleFactory.java @@ -0,0 +1,21 @@ +/* + * 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 + */ + +/* +* Generated file +* +* Generated from: yang module name: alivenessmonitor-impl yang module local name: alivenessmonitor-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon Jul 06 11:45:33 IST 2015 +* +* 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.alivenessmonitor.impl.rev150706; +public class AlivenessMonitorModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alivenessmonitor.impl.rev150706.AbstractAlivenessMonitorModuleFactory { + +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/main/yang/alivenessmonitor-impl.yang b/alivenessmonitor/alivenessmonitor-impl/src/main/yang/alivenessmonitor-impl.yang new file mode 100644 index 00000000..5a5508dd --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/main/yang/alivenessmonitor-impl.yang @@ -0,0 +1,62 @@ +module alivenessmonitor-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:alivenessmonitor:impl"; + prefix "alivenessmonitor-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-interface {prefix odlif; revision-date 2015-03-31;} + //import aliveness-monitor { prefix aliveness-mon; revision-date 2015-06-29; } + + description + "Service definition for aliveness monitor module"; + + revision "2015-07-06" { + description + "Initial revision"; + } + + identity alivenessmonitor-impl { + base config:module-type; + config:java-name-prefix AlivenessMonitor; + } + + augment "/config:modules/config:module/config:configuration" { + case alivenessmonitor-impl { + when "/config:modules/config:module/config:type = 'alivenessmonitor-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 notification-publish-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding-impl:binding-new-notification-publish-service; + } + } + } + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding-impl:binding-new-notification-service; + } + } + } + } + } +} diff --git a/alivenessmonitor/alivenessmonitor-impl/src/test/java/org/opendaylight/controller/alivenessmonitor/test/AlivenessMonitorTest.java b/alivenessmonitor/alivenessmonitor-impl/src/test/java/org/opendaylight/controller/alivenessmonitor/test/AlivenessMonitorTest.java new file mode 100644 index 00000000..a48ae635 --- /dev/null +++ b/alivenessmonitor/alivenessmonitor-impl/src/test/java/org/opendaylight/controller/alivenessmonitor/test/AlivenessMonitorTest.java @@ -0,0 +1,318 @@ +/* + * 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.controller.alivenessmonitor.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; +import static org.mockito.Matchers.argThat; + +import java.util.Arrays; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Matchers; +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.NotificationPublishService; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessMonitor; +import org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessProtocolHandler; +import org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessProtocolHandlerARP; +import org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessProtocolHandlerLLDP; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.EtherTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorPauseInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorPauseInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileCreateOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileDeleteInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorProfileDeleteInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStartOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStopInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorStopInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorUnpauseInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitorUnpauseInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.MonitoringMode; +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.endpoint.endpoint.type.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfoBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.params.DestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.params.SourceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profile.create.input.ProfileBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfile; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.profiles.MonitorProfileBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.start.input.ConfigBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitorid.key.map.MonitoridKeyEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitoring.states.MonitoringStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutputBuilder; +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.idmanager.rev150403.ReleaseIdInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; + +public class AlivenessMonitorTest { + + @Mock private DataBroker dataBroker; + @Mock private IdManagerService idManager; + @Mock private PacketProcessingService packetProcessingService; + @Mock private NotificationPublishService notificationPublishService; + private AlivenessMonitor alivenessMonitor; + private AlivenessProtocolHandler arpHandler; + private AlivenessProtocolHandler lldpHandler; + private long mockId; + @Mock private ReadOnlyTransaction readTx; + @Mock private WriteTransaction writeTx; + @Mock private ReadWriteTransaction readWriteTx; + @Captor ArgumentCaptor stateCaptor; + + private Matcher> isType(final Class klass) { + return new TypeSafeMatcher>() { + @Override + public void describeTo(Description desc) { + desc.appendText("Instance Identifier should have Target Type " + klass); + } + + @Override + protected boolean matchesSafely(InstanceIdentifier id) { + return id.getTargetType().equals(klass); + } + }; + } + + private Matcher hasErrorType(final ErrorType errorType) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description desc) { + desc.appendText("Error type do not match " + errorType); + } + + @Override + protected boolean matchesSafely(RpcError error) { + return error.getErrorType().equals(errorType); + } + }; + } + + @SuppressWarnings("unchecked") + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + alivenessMonitor = new AlivenessMonitor(dataBroker); + when(idManager.createIdPool(any(CreateIdPoolInput.class))) + .thenReturn(Futures.immediateFuture(RpcResultBuilder.success().build())); + alivenessMonitor.setIdManager(idManager); + alivenessMonitor.setNotificationPublishService(notificationPublishService); + alivenessMonitor.setPacketProcessingService(packetProcessingService); + + arpHandler = new AlivenessProtocolHandlerARP(alivenessMonitor); + alivenessMonitor.registerHandler(EtherTypes.Arp, arpHandler); + + lldpHandler = new AlivenessProtocolHandlerLLDP(alivenessMonitor); + alivenessMonitor.registerHandler(EtherTypes.Lldp, lldpHandler); + mockId = 1L; + when(idManager.allocateId(any(AllocateIdInput.class))) + .thenReturn(Futures.immediateFuture(RpcResultBuilder.success(new AllocateIdOutputBuilder().setIdValue(mockId++).build()).build())); + when(idManager.releaseId(any(ReleaseIdInput.class))).thenReturn(Futures.immediateFuture(RpcResultBuilder.success().build())); + doReturn(readTx).when(dataBroker).newReadOnlyTransaction(); + doReturn(writeTx).when(dataBroker).newWriteOnlyTransaction(); + doReturn(readWriteTx).when(dataBroker).newReadWriteTransaction(); + doNothing().when(writeTx).put(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class), any(DataObject.class)); + doReturn(Futures.immediateCheckedFuture(null)).when(writeTx).submit(); + doReturn(Futures.immediateCheckedFuture(null)).when(readWriteTx).submit(); + } + + @After + public void tearDown() throws Exception { + alivenessMonitor.close(); + } + + @Test + public void testMonitorProfileCreate() throws Throwable { + MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(new ProfileBuilder().setFailureThreshold(10L) + .setMonitorInterval(10000L).setMonitorWindow(10L).setProtocolType(EtherTypes.Arp).build()).build(); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(readWriteTx).read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class))); + doReturn(Futures.immediateCheckedFuture(null)).when(readWriteTx).submit(); + RpcResult output = alivenessMonitor.monitorProfileCreate(input).get(); + assertTrue("Monitor Profile Create result", output.isSuccessful()); + assertNotNull("Monitor Profile Output", output.getResult().getProfileId()); + } + + @Test + public void testMonitorProfileCreateAlreadyExist() throws Throwable { + MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(new ProfileBuilder().setFailureThreshold(10L) + .setMonitorInterval(10000L).setMonitorWindow(10L).setProtocolType(EtherTypes.Arp).build()).build(); + @SuppressWarnings("unchecked") + Optional optionalProfile = (Optional)mock(Optional.class); + CheckedFuture, ReadFailedException> proFuture = Futures.immediateCheckedFuture(optionalProfile); + doReturn(true).when(optionalProfile).isPresent(); + doReturn(proFuture).when(readWriteTx).read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class))); + RpcResult output = alivenessMonitor.monitorProfileCreate(input).get(); + assertTrue("Monitor Profile Create result", output.isSuccessful()); + assertThat(output.getErrors(), CoreMatchers.hasItem(hasErrorType(ErrorType.PROTOCOL))); + } + + @Test + public void testMonitorStart() throws Throwable { + Long profileId = createProfile(); + MonitorStartInput input = new MonitorStartInputBuilder().setConfig(new ConfigBuilder() + .setDestination(new DestinationBuilder().setEndpointType(getInterface("10.0.0.1")).build()) + .setSource(new SourceBuilder().setEndpointType(getInterface("testInterface", "10.1.1.1")).build()) + .setMode(MonitoringMode.OneOne) + .setProfileId(profileId).build()).build(); + @SuppressWarnings("unchecked") + Optional optionalProfile = (Optional)mock(Optional.class); + CheckedFuture, ReadFailedException> proFuture = Futures.immediateCheckedFuture(optionalProfile); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class)))).thenReturn(proFuture); + doReturn(true).when(optionalProfile).isPresent(); + doReturn(getTestMonitorProfile()).when(optionalProfile).get(); + CheckedFuture, ReadFailedException> outFuture = Futures.immediateCheckedFuture(Optional.absent()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringInfo.class)))).thenReturn(outFuture); + RpcResult output = alivenessMonitor.monitorStart(input).get(); + verify(idManager, times(2)).allocateId(any(AllocateIdInput.class)); + assertTrue("Monitor start output result", output.isSuccessful()); + assertNotNull("Monitor start output", output.getResult().getMonitorId()); + } + + @Test + public void testMonitorPause() throws Throwable { + MonitorPauseInput input = new MonitorPauseInputBuilder().setMonitorId(2L).build(); + Optional optState = Optional.of(new MonitoringStateBuilder().setStatus(MonitorStatus.Started).build()); + when(readWriteTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringState.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optState)); + Optional optMap = Optional.of(new MonitoridKeyEntryBuilder().setMonitorId(2L).setMonitorKey("Test monitor Key").build()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoridKeyEntry.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optMap)); + alivenessMonitor.monitorPause(input).get(); + verify(readWriteTx).merge(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringState.class)), stateCaptor.capture()); + assertEquals(MonitorStatus.Paused, stateCaptor.getValue().getStatus()); + } + + @Test + public void testMonitorUnpause() throws Throwable { + MonitorUnpauseInput input = new MonitorUnpauseInputBuilder().setMonitorId(2L).build(); + Optional optState = Optional.of(new MonitoringStateBuilder().setStatus(MonitorStatus.Paused).build()); + when(readWriteTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringState.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optState)); + Optional optInfo = Optional.of(new MonitoringInfoBuilder().setId(2L).setProfileId(1L).build()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringInfo.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optInfo)); + Optional optProfile = Optional.of(getTestMonitorProfile()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optProfile)); + Optional optMap = Optional.of(new MonitoridKeyEntryBuilder().setMonitorId(2L).setMonitorKey("Test monitor Key").build()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoridKeyEntry.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optMap)); + RpcResult result = alivenessMonitor.monitorUnpause(input).get(); + verify(readWriteTx).merge(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringState.class)), stateCaptor.capture()); + assertEquals(MonitorStatus.Started, stateCaptor.getValue().getStatus()); + assertTrue("Monitor unpause rpc result", result.isSuccessful()); + } + + @Test + public void testMonitorStop() throws Throwable { + MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(2L).build(); + Optional optInfo = Optional.of( + new MonitoringInfoBuilder().setSource(new SourceBuilder().setEndpointType(getInterface("testInterface", "10.1.1.1")).build()).build()); + CheckedFuture, ReadFailedException> outFuture = Futures.immediateCheckedFuture(optInfo); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoringInfo.class)))).thenReturn(outFuture); + Optional optMap = Optional.of(new MonitoridKeyEntryBuilder().setMonitorId(2L).setMonitorKey("Test monitor Key").build()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitoridKeyEntry.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optMap)); + Optional optProfile = Optional.of(getTestMonitorProfile()); + when(readTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optProfile)); + Optional optEntry = Optional.of(getInterfaceMonitorEntry()); + when(readWriteTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(InterfaceMonitorEntry.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optEntry)); + RpcResult result = alivenessMonitor.monitorStop(input).get(); + verify(idManager).releaseId(any(ReleaseIdInput.class)); + verify(writeTx, times(2)).delete(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)); + assertTrue("Monitor stop rpc result", result.isSuccessful()); + } + + @Test + public void testMonitorProfileDelete() throws Throwable { + MonitorProfileDeleteInput input = new MonitorProfileDeleteInputBuilder().setProfileId(1L).build(); + Optional optProfile = Optional.of(getTestMonitorProfile()); + when(readWriteTx.read(eq(LogicalDatastoreType.OPERATIONAL), argThat(isType(MonitorProfile.class)))). + thenReturn(Futures., ReadFailedException>immediateCheckedFuture(optProfile)); + RpcResult result = alivenessMonitor.monitorProfileDelete(input).get(); + verify(idManager).releaseId(any(ReleaseIdInput.class)); + verify(readWriteTx).delete(eq(LogicalDatastoreType.OPERATIONAL), Matchers.>any()); + assertTrue("Monitor profile delete result", result.isSuccessful()); + } + + @SuppressWarnings("unchecked") + private long createProfile() throws Throwable{ + MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(new ProfileBuilder().setFailureThreshold(10L) + .setMonitorInterval(10000L).setMonitorWindow(10L).setProtocolType(EtherTypes.Arp).build()).build(); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(readWriteTx).read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)); + doReturn(Futures.immediateCheckedFuture(null)).when(readWriteTx).submit(); + RpcResult output = alivenessMonitor.monitorProfileCreate(input).get(); + return output.getResult().getProfileId(); + } + + private MonitorProfile getTestMonitorProfile() { + return new MonitorProfileBuilder().setFailureThreshold(10L).setMonitorInterval(10000L) + .setMonitorWindow(10L).setProtocolType(EtherTypes.Arp).build(); + } + + private InterfaceMonitorEntry getInterfaceMonitorEntry() { + return new InterfaceMonitorEntryBuilder().setInterfaceName("test-interface").setMonitorIds(Arrays.asList(1L, 2L)).build(); + } + + private Interface getInterface(String ipAddress) { + return new InterfaceBuilder().setInterfaceIp(IpAddressBuilder.getDefaultInstance(ipAddress)).build(); + } + + private Interface getInterface(String interfaceName, String ipAddress) { + return new InterfaceBuilder().setInterfaceIp(IpAddressBuilder.getDefaultInstance(ipAddress)).setInterfaceName(interfaceName).build(); + } +} diff --git a/alivenessmonitor/pom.xml b/alivenessmonitor/pom.xml new file mode 100644 index 00000000..838abc82 --- /dev/null +++ b/alivenessmonitor/pom.xml @@ -0,0 +1,49 @@ + + + + + + org.opendaylight.odlparent + odlparent + 1.6.0-SNAPSHOT + + + + org.opendaylight.controller + alivenessmonitor-aggregator + 0.2.0-SNAPSHOT + alivenessmonitor + pom + 4.0.0 + + 3.1.1 + + + alivenessmonitor-api + alivenessmonitor-impl + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + diff --git a/arputil/arputil-api/pom.xml b/arputil/arputil-api/pom.xml new file mode 100644 index 00000000..6c26ad34 --- /dev/null +++ b/arputil/arputil-api/pom.xml @@ -0,0 +1,56 @@ + + + + org.opendaylight.vpnservice + config-parent + 0.2.0-SNAPSHOT + ../../commons/config-parent + + 4.0.0 + org.opendaylight.vpnservice + arputil-api + ${vpnservices.version} + bundle + + + + org.opendaylight.openflowplugin.model + model-flow-base + ${openflowplugin.version} + + + org.opendaylight.openflowplugin.model + model-flow-service + ${openflowplugin.version} + + + org.opendaylight.mdsal + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.mdsal.model + yang-ext + + + org.opendaylight.mdsal.model + ietf-inet-types + + + org.opendaylight.mdsal.model + ietf-yang-types + + + org.opendaylight.mdsal.model + ietf-interfaces + + + org.opendaylight.mdsal.model + iana-if-type-2014-05-08 + + + diff --git a/arputil/arputil-api/src/main/yang/odl-arputil.yang b/arputil/arputil-api/src/main/yang/odl-arputil.yang new file mode 100644 index 00000000..3f176957 --- /dev/null +++ b/arputil/arputil-api/src/main/yang/odl-arputil.yang @@ -0,0 +1,139 @@ +module odl-arputil { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:arputil"; + prefix "odl-arputil"; + + import ietf-interfaces { + prefix if; + } + + import ietf-inet-types { + prefix inet; + } + + import ietf-yang-types { + prefix yang; + } + + import opendaylight-inventory { + prefix inv; revision-date 2013-08-19; + } + + import config { + prefix config; revision-date 2013-04-05; + } + + revision "2015-11-26" { + description "Arp Util module"; + } + + + grouping interfaces { + list interface-address { + key interface; + leaf interface { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + } + leaf ip-address { + type inet:ip-address; + } + } + } + + + rpc get-mac { + input { + leaf ipaddress { + type inet:ip-address; + } + uses interfaces; + } + output { + leaf macaddress { + type yang:phys-address; + } + } + } + + rpc send-arp-request { + input { + leaf ipaddress { + type inet:ip-address; + } + uses interfaces; + } + } + + rpc send-arp-response { + input { + leaf ipaddress { + type inet:ip-address; + } + leaf macaddress { + type yang:phys-address; + } + leaf interface { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + } + leaf src-ip-address { + type inet:ip-address; + } + } + } + + + notification mac-changed { + leaf ipaddress { + type inet:ip-address; + } + leaf macaddress { + type yang:phys-address; + } + leaf interface { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + } + } + + notification arp-request-received { + leaf dst-ipaddress { + type inet:ip-address; + } + leaf src-ipaddress { + type inet:ip-address; + } + leaf src-mac { + type yang:phys-address; + } + leaf of-table-id { + type uint32; + } + leaf interface { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + } + } + + notification arp-response-received { + leaf ipaddress { + type inet:ip-address; + } + leaf macaddress { + type yang:phys-address; + } + leaf of-table-id { + type uint32; + } + leaf interface { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + } + } +} \ No newline at end of file diff --git a/arputil/arputil-impl/pom.xml b/arputil/arputil-impl/pom.xml new file mode 100644 index 00000000..b5de1cc6 --- /dev/null +++ b/arputil/arputil-impl/pom.xml @@ -0,0 +1,94 @@ + + + + org.opendaylight.vpnservice + config-parent + 0.2.0-SNAPSHOT + ../../commons/config-parent + + 4.0.0 + org.opendaylight.vpnservice + arputil-impl + ${vpnservices.version} + bundle + + + + + ${project.groupId} + interfacemgr-api + ${project.version} + + + org.opendaylight.controller + sal-binding-api + + + org.opendaylight.mdsal + yang-binding + + + org.opendaylight.yangtools + yang-common + + + ${project.groupId} + mdsalutil-api + ${vpnservices.version} + + + org.opendaylight.mdsal.model + yang-ext + + + org.opendaylight.controller + liblldp + ${liblldp.version} + + + org.opendaylight.mdsal.model + ietf-inet-types + + + ${project.groupId} + arputil-api + ${project.version} + + + org.opendaylight.mdsal.model + ietf-yang-types + + + org.opendaylight.mdsal.model + ietf-interfaces + + + org.opendaylight.mdsal.model + iana-if-type-2014-05-08 + + + org.opendaylight.openflowplugin.model + model-flow-base + ${openflowplugin.version} + + + org.opendaylight.openflowplugin.model + model-flow-service + ${openflowplugin.version} + + + org.opendaylight.controller + sal-binding-broker-impl + test + + + org.opendaylight.controller + sal-binding-broker-impl + ${mdsal.version} + test + test-jar + + + + diff --git a/arputil/arputil-impl/src/main/config/default-config.xml b/arputil/arputil-impl/src/main/config/default-config.xml new file mode 100644 index 00000000..dcd772c5 --- /dev/null +++ b/arputil/arputil-impl/src/main/config/default-config.xml @@ -0,0 +1,47 @@ + + + + + urn:opendaylight:params:xml:ns:yang:arputil:impl?module=arputil-impl&revision=2015-11-26 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:mdsalutil:api?module=odl-mdsalutil&revision=2015-04-10 + + + + + + + prefix:arputil-impl + arputil-default + + binding:binding-broker-osgi-registry + binding-osgi-broker + + + binding:binding-rpc-registry + binding-rpc-broker + + + mdsalutil:odl-mdsalutil + mdsalutil-service + + + bindingimpl:binding-new-notification-publish-service + binding-notification-publish-adapter + + + bindingimpl:binding-new-notification-service + binding-notification-adapter + + + + + + diff --git a/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpPacketUtil.java b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpPacketUtil.java new file mode 100644 index 00000000..46af8e80 --- /dev/null +++ b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpPacketUtil.java @@ -0,0 +1,53 @@ +/* + * 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.arputil.internal; + +import org.opendaylight.controller.liblldp.EtherTypes; +import org.opendaylight.controller.liblldp.PacketException; +import org.opendaylight.vpnservice.mdsalutil.packet.ARP; +import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet; + +public class ArpPacketUtil { + + public static byte[] EthernetDestination_Broadcast = new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }; + public static byte[] MAC_Broadcast = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 }; + + public static byte[] getPayload(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress, + byte[] targetIP) throws PacketException { + ARP arp = createARPPacket(opCode, senderMacAddress, senderIP, targetMacAddress, targetIP); + Ethernet ethernet = createEthernetPacket(senderMacAddress, targetMacAddress, arp); + return ethernet.serialize(); + } + + public static ARP createARPPacket(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress, + byte[] targetIP) { + ARP arp = new ARP(); + arp.setHardwareType(ARP.HW_TYPE_ETHERNET); + arp.setProtocolType(EtherTypes.IPv4.shortValue()); + arp.setHardwareAddressLength((byte) 6); + arp.setProtocolAddressLength((byte) 4); + arp.setOpCode(opCode); + arp.setSenderHardwareAddress(senderMacAddress); + arp.setSenderProtocolAddress(senderIP); + arp.setTargetHardwareAddress(targetMacAddress); + arp.setTargetProtocolAddress(targetIP); + return arp; + } + + public static Ethernet createEthernetPacket(byte[] sourceMAC, byte[] targetMAC, ARP arp) + throws PacketException { + Ethernet ethernet = new Ethernet(); + ethernet.setSourceMACAddress(sourceMAC); + ethernet.setDestinationMACAddress(targetMAC); + ethernet.setEtherType(EtherTypes.ARP.shortValue()); + ethernet.setPayload(arp); + return ethernet; + } +} \ No newline at end of file diff --git a/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilImpl.java b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilImpl.java new file mode 100644 index 00000000..45f6824e --- /dev/null +++ b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilImpl.java @@ -0,0 +1,538 @@ +/* + * 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.arputil.internal; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; +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.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; +import org.opendaylight.vpnservice.mdsalutil.NWUtil; +import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.vpnservice.mdsalutil.packet.ARP; +import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.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.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +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.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.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.ArpRequestReceivedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.ArpResponseReceivedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.MacChangedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.interfaces.InterfaceAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.BaseIds; +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.RpcError.ErrorType; +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 com.google.common.util.concurrent.JdkFutureAdapters; +import com.google.common.util.concurrent.SettableFuture; + +public class ArpUtilImpl implements OdlArputilService, + PacketProcessingListener, AutoCloseable { + + private static final String FAILED_TO_GET_SRC_IP_FOR_INTERFACE = "Failed to get src ip for %s"; + + private static final String FAILED_TO_GET_SRC_MAC_FOR_INTERFACE = "Failed to get src mac for interface %s iid %s "; + + private static final String FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE = "failed to send arp req for interface "; + + private static final String UNKNOWN_IP_ADDRESS_SUPPLIED = "unknown ip address supplied"; + + private static final String NODE_CONNECTOR_NOT_FOUND_ERROR = "Node connector id not found for interface %s"; + + private static final String DPN_NOT_FOUND_ERROR = "dpn not found for interface %s "; + + private static final short ARP_REQUEST_OP = (short) 1; + + private static final short ARP_RESPONSE_OP = (short) 2; + + private static final Logger LOGGER = LoggerFactory + .getLogger(ArpUtilImpl.class); + + ExecutorService threadPool = Executors.newFixedThreadPool(1); + + DataBroker dataBroker; + PacketProcessingService packetProcessingService; + NotificationPublishService notificationPublishService; + NotificationService notificationService; + IMdsalApiManager mdsalMgr; + + ListenerRegistration listenerRegistration; + + ConcurrentMap macsDB = new ConcurrentHashMap<>(); + ConcurrentMap>> getMacFutures = new ConcurrentHashMap<>(); + + public ArpUtilImpl(DataBroker db, + PacketProcessingService packetProcessingService, + NotificationPublishService notificationPublishService, + NotificationService notificationService, + IMdsalApiManager mdsalApiManager) { + + this.dataBroker = db; + this.packetProcessingService = packetProcessingService; + this.notificationPublishService = notificationPublishService; + this.mdsalMgr = mdsalApiManager; + this.notificationService = notificationService; + + listenerRegistration = notificationService + .registerNotificationListener(this); + LOGGER.info("ArpUtil Manager Initialized "); + } + + @Override + public void close() throws Exception { + listenerRegistration.close(); + LOGGER.trace("ArpUtil manager Closed"); + } + + String getIpAddressInString(IpAddress ipAddress) + throws UnknownHostException { + return InetAddress.getByName(ipAddress.getIpv4Address().getValue()) + .getHostAddress(); + } + + public Future> getMac(GetMacInput input) { + + try { + final String dstIpAddress = getIpAddressInString(input + .getIpaddress()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("getMac rpc invoked for ip " + dstIpAddress); + } + if (getMacFutures.get(dstIpAddress) != null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("get mac already in progress for the ip " + + dstIpAddress); + } + return getMacFutures.get(dstIpAddress); + } + SendArpRequestInputBuilder builder = new SendArpRequestInputBuilder() + .setInterfaceAddress(input.getInterfaceAddress()) + .setIpaddress(input.getIpaddress()); + Future> arpReqFt = sendArpRequest(builder.build()); + final SettableFuture> ft = SettableFuture + .create(); + + Futures.addCallback( + JdkFutureAdapters.listenInPoolThread(arpReqFt, threadPool), + new FutureCallback>() { + @Override + public void onFailure(Throwable e) { + RpcResultBuilder resultBuilder = RpcResultBuilder + . failed().withError( + ErrorType.APPLICATION, + e.getMessage(), e); + ft.set(resultBuilder.build()); + } + + @Override + public void onSuccess(RpcResult result) { + LOGGER.trace("Successfully sent the arp pkt out for ip " + + dstIpAddress); + } + }); + + getMacFutures.put(dstIpAddress, ft); + return ft; + } catch (Exception e) { + LOGGER.trace("failed to handle getMac request for {} {}", + input.getIpaddress(), e); + RpcResultBuilder resultBuilder = RpcResultBuilder + . failed().withError(ErrorType.APPLICATION, + e.getMessage(), e); + return Futures.immediateFuture(resultBuilder.build()); + } + } + + byte[] getIpAddressBytes(IpAddress ip) throws UnknownHostException { + return InetAddress.getByName(ip.getIpv4Address().getValue()) + .getAddress(); + } + + @Override + public Future> sendArpRequest( + SendArpRequestInput arpReqInput) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("rpc sendArpRequest invoked for ip " + + arpReqInput.getIpaddress()); + } + BigInteger dpnId; + long groupId; + byte payload[]; + String interfaceName = null; + byte srcIpBytes[]; + byte[] dstIpBytes = null; + + RpcResultBuilder failureBuilder = RpcResultBuilder + . failed(); + RpcResultBuilder successBuilder = RpcResultBuilder + . success(); + + try { + dstIpBytes = getIpAddressBytes(arpReqInput.getIpaddress()); + } catch (Exception e) { + failureBuilder.withError(ErrorType.APPLICATION, + UNKNOWN_IP_ADDRESS_SUPPLIED); + return Futures.immediateFuture(failureBuilder.build()); + } + + int localErrorCount = 0; + for (InterfaceAddress interfaceAddress : arpReqInput + .getInterfaceAddress()) { + try { + interfaceName = interfaceAddress.getInterface(); + srcIpBytes = getIpAddressBytes(interfaceAddress.getIpAddress()); + + NodeConnectorId id = getNodeConnectorFromDataStore(interfaceName); + + dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(id)); + Long portid = MDSALUtil.getOfPortNumberFromPortName(id); + checkArgument(null != dpnId && BigInteger.ZERO != dpnId, + DPN_NOT_FOUND_ERROR, interfaceName); + + NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, + portid.toString()); + checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace( + "sendArpRequest received dpnId {} out interface {}", + dpnId, interfaceName); + } + byte srcMac[] = MDSALUtil.getMacAddressForNodeConnector( + dataBroker, + (InstanceIdentifier) ref.getValue()); + checkNotNull(srcMac, FAILED_TO_GET_SRC_MAC_FOR_INTERFACE, + interfaceName, ref.getValue()); + checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE, + interfaceName); + + payload = ArpPacketUtil.getPayload(ARP_REQUEST_OP, srcMac, + srcIpBytes, ArpPacketUtil.EthernetDestination_Broadcast, + dstIpBytes); + + sendPacketOut(dpnId, payload, ref); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("sent arp request for " + + arpReqInput.getIpaddress()); + } + } catch (Exception e) { + LOGGER.trace("failed to send arp req for {} on interface {}", + arpReqInput.getIpaddress(), interfaceName); + + failureBuilder + .withError(ErrorType.APPLICATION, + FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + + interfaceName, e); + successBuilder + .withError(ErrorType.APPLICATION, + FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + + interfaceName, e); + localErrorCount++; + } + } + if (localErrorCount == arpReqInput.getInterfaceAddress().size()) { + // All the requests failed + return Futures.immediateFuture(failureBuilder.build()); + } + return Futures.immediateFuture(successBuilder.build()); + } + + public Future> sendPacketOut(BigInteger dpnId, + byte[] payload, NodeConnectorRef ref) { + + NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, + "0xfffffffd"); + return packetProcessingService + .transmitPacket(new TransmitPacketInputBuilder() + .setPayload(payload) + .setNode( + new NodeRef(InstanceIdentifier + .builder(Nodes.class) + .child(Node.class, + new NodeKey(new NodeId( + "openflow:" + dpnId))) + .toInstance())) + .setIngress(nodeConnectorRef).setEgress(ref).build()); + } + + @Override + public Future> sendArpResponse(SendArpResponseInput input) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("sendArpResponse rpc invoked"); + } + BigInteger dpnId; + long groupId; + byte payload[]; + + try { + String interfaceName = input.getInterface(); + NodeConnectorId id = getNodeConnectorFromDataStore(interfaceName); + + dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(id)); + Long portid = MDSALUtil.getOfPortNumberFromPortName(id); + + NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, + portid.toString()); + checkArgument(null != dpnId && BigInteger.ZERO != dpnId, + DPN_NOT_FOUND_ERROR, interfaceName); + checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace( + "sendArpRequest received dpnId {} out interface {}", + dpnId, interfaceName); + } + + byte[] srcIpBytes = getIpAddressBytes(input.getSrcIpAddress()); + byte[] dstIpBytes = getIpAddressBytes(input.getIpaddress()); + byte srcMac[] = MDSALUtil.getMacAddressForNodeConnector(dataBroker, + (InstanceIdentifier) ref.getValue()); + byte[] dstMac = NWUtil.parseMacAddress(input.getMacaddress() + .getValue()); + checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE, + interfaceName); + payload = ArpPacketUtil.getPayload(ARP_RESPONSE_OP, srcMac, srcIpBytes, + dstMac, dstIpBytes); + + sendPacketOut(dpnId, payload, ref); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("sent the arp response for " + + input.getSrcIpAddress()); + } + } catch (Exception e) { + LOGGER.trace("failed to send arp response for {} {}", + input.getSrcIpAddress(), e); + return RpcResultBuilder. failed() + .withError(ErrorType.APPLICATION, e.getMessage(), e) + .buildFuture(); + } + RpcResultBuilder rpcResultBuilder = RpcResultBuilder.success(); + return Futures.immediateFuture(rpcResultBuilder.build()); + } + + @Override + public void onPacketReceived(PacketReceived packetReceived) { + Class pktInReason = packetReceived + .getPacketInReason(); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Packet Received {}", packetReceived); + } + + if (pktInReason == SendToController.class) { + + try { + int tableId = packetReceived.getTableId().getValue(); + + byte[] data = packetReceived.getPayload(); + Ethernet ethernet = new Ethernet(); + + ethernet.deserialize(data, 0, data.length + * NetUtils.NumBitsInAByte); + if (ethernet.getEtherType() != ARP_REQUEST_OP + && ethernet.getEtherType() != ARP_REQUEST_OP) { + return; + } + + Packet pkt = ethernet.getPayload(); + ARP arp = (ARP) pkt; + InetAddress srcInetAddr = InetAddress.getByAddress(arp + .getSenderProtocolAddress()); + InetAddress dstInetAddr = InetAddress.getByAddress(arp + .getTargetProtocolAddress()); + byte[] srcMac = ethernet.getSourceMACAddress(); + + NodeConnectorRef ref = packetReceived.getIngress(); + + String interfaceName = MDSALUtil.getInterfaceName(ref, dataBroker); + + checkAndFireMacChangedNotification(interfaceName, srcInetAddr, + srcMac); + + macsDB.put(interfaceName + "-" + srcInetAddr.getHostAddress(), + NWUtil.toStringMacAddress(srcMac)); + + if (arp.getOpCode() == ARP_REQUEST_OP) { + fireArpReqRecvdNotification(interfaceName, srcInetAddr, + srcMac, dstInetAddr, tableId); + } else { + fireArpRespRecvdNotification(interfaceName, srcInetAddr, + srcMac, tableId); + } + if (getMacFutures.get(srcInetAddr.getHostAddress()) != null) { + threadPool.submit(new MacResponderTask(arp)); + } + + } catch (Exception e) { + LOGGER.trace("Failed to decode packet: {}", e); + } + } + } + + class MacResponderTask implements Runnable { + ARP arp; + + MacResponderTask(ARP arp) { + this.arp = arp; + } + + @Override + public void run() { + InetAddress srcAddr; + GetMacOutputBuilder outputBuilder; + String srcMac; + SettableFuture> future = null; + RpcResultBuilder resultBuilder; + try { + srcAddr = InetAddress.getByAddress(arp + .getSenderProtocolAddress()); + srcMac = NWUtil.toStringMacAddress(arp + .getSenderHardwareAddress()); + future = getMacFutures.remove(srcAddr.getHostAddress()); + if (future == null) { + LOGGER.trace("There are no pending mac requests."); + return; + } + outputBuilder = new GetMacOutputBuilder() + .setMacaddress(new PhysAddress(srcMac)); + resultBuilder = RpcResultBuilder.success(outputBuilder.build()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("sent the mac response for ip {}", + srcAddr.getHostAddress()); + } + } catch (Exception e) { + LOGGER.trace("failed to send mac response {} ", e); + resultBuilder = RpcResultBuilder. failed() + .withError(ErrorType.APPLICATION, e.getMessage(), e); + } + future.set(resultBuilder.build()); + } + } + + private void fireArpRespRecvdNotification(String interfaceName, + InetAddress inetAddr, byte[] macAddressBytes, int tableId) + throws InterruptedException { + + IpAddress ip = new IpAddress(inetAddr.getHostAddress().toCharArray()); + String macAddress = NWUtil.toStringMacAddress(macAddressBytes); + PhysAddress mac = new PhysAddress(macAddress); + ArpResponseReceivedBuilder builder = new ArpResponseReceivedBuilder(); + builder.setInterface(interfaceName); + builder.setIpaddress(ip); + builder.setOfTableId((long) tableId); + builder.setMacaddress(mac); + notificationPublishService.putNotification(builder.build()); + } + + private void fireArpReqRecvdNotification(String interfaceName, + InetAddress srcInetAddr, byte[] srcMac, InetAddress dstInetAddr, + int tableId) throws InterruptedException { + String macAddress = NWUtil.toStringMacAddress(srcMac); + ArpRequestReceivedBuilder builder = new ArpRequestReceivedBuilder(); + builder.setInterface(interfaceName); + builder.setOfTableId((long) tableId); + builder.setSrcIpaddress(new IpAddress(srcInetAddr.getHostAddress() + .toCharArray())); + builder.setDstIpaddress(new IpAddress(dstInetAddr.getHostAddress() + .toCharArray())); + builder.setSrcMac(new PhysAddress(macAddress)); + notificationPublishService.putNotification(builder.build()); + } + + private void checkAndFireMacChangedNotification(String interfaceName, + InetAddress inetAddr, byte[] macAddressBytes) + throws InterruptedException { + + IpAddress ip = new IpAddress(inetAddr.getHostAddress().toCharArray()); + String macAddress = NWUtil.toStringMacAddress(macAddressBytes); + PhysAddress mac = new PhysAddress(macAddress); + + if (!macAddress.equals(macsDB.get(interfaceName + "-" + + inetAddr.getHostAddress()))) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("mac address changed for " + inetAddr); + } + MacChangedBuilder builder = new MacChangedBuilder(); + builder.setInterface(interfaceName); + builder.setIpaddress(ip); + builder.setMacaddress(mac); + notificationPublishService.putNotification(builder.build()); + } + } + + private InstanceIdentifier buildInterfaceId(String interfaceName) { + InstanceIdentifierBuilder idBuilder = InstanceIdentifier + .builder(Interfaces.class).child(Interface.class, + new InterfaceKey(interfaceName)); + InstanceIdentifier id = idBuilder.build(); + return id; + } + + + private NodeConnectorId getNodeConnectorFromDataStore(String interfaceName) { + InstanceIdentifier id = buildInterfaceId(interfaceName); + Optional interf = MDSALUtil.read(dataBroker, + LogicalDatastoreType.CONFIGURATION, + id); + if (interf.isPresent()) { + return interf.get().getAugmentation(BaseIds.class).getOfPortId(); + } + return null; + } + +} diff --git a/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilProvider.java b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilProvider.java new file mode 100644 index 00000000..d22f6996 --- /dev/null +++ b/arputil/arputil-impl/src/main/java/org/opendaylight/vpnservice/arputil/internal/ArpUtilProvider.java @@ -0,0 +1,81 @@ +/* + * 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.arputil.internal; + +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.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.vpnservice.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArpUtilProvider implements BindingAwareProvider, AutoCloseable { + + private static final Logger s_logger = LoggerFactory.getLogger(ArpUtilProvider.class); + + RpcProviderRegistry rpcProviderRegistry; + + NotificationService notificationService; + + NotificationPublishService notificationPublishService; + + ArpUtilImpl arpManager; + + IMdsalApiManager mdsalApiManager; + + BindingAwareBroker.RpcRegistration rpcRegistration; + + public ArpUtilProvider(RpcProviderRegistry rpcRegistry, + NotificationPublishService publishService, + NotificationService notificationService, + IMdsalApiManager iMdsalApiManager) { + + this.rpcProviderRegistry = rpcRegistry; + this.mdsalApiManager = iMdsalApiManager; + this.notificationPublishService = publishService; + this.notificationService = notificationService; + } + + public ArpUtilProvider() { + } + + @Override + public void onSessionInitiated(final ProviderContext session){ + + s_logger.info( " Session Initiated for Arp Provider") ; + + try { + DataBroker dataBroker = session.getSALService(DataBroker.class); + PacketProcessingService packetProcessingService = + session.getRpcService(PacketProcessingService.class); + + arpManager = new ArpUtilImpl( dataBroker, packetProcessingService, + notificationPublishService, notificationService, + mdsalApiManager) ; + + rpcRegistration = rpcProviderRegistry. + addRpcImplementation(OdlArputilService.class, arpManager); + s_logger.info( " Session Initialized for Arp Provider") ; + }catch( Exception e) { + s_logger.error( "Error initializing Arp " , e ); + } + } + + @Override + public void close() throws Exception { + rpcRegistration.close(); + arpManager.close(); + s_logger.info("ArpManager Manager Closed"); + } +} diff --git a/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModule.java b/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModule.java new file mode 100644 index 00000000..83f95792 --- /dev/null +++ b/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModule.java @@ -0,0 +1,30 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.impl.rev151126; + +import org.opendaylight.vpnservice.arputil.internal.ArpUtilProvider; + +public class ArputilImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.impl.rev151126.AbstractArputilImplModule { + public ArputilImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ArputilImplModule(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.arputil.impl.rev151126.ArputilImplModule 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() { + ArpUtilProvider provider = new ArpUtilProvider(getRpcRegistryDependency(), + getNotificationPublishServiceDependency(), + getNotificationServiceDependency(), + getMdsalutilDependency() + ); + getBrokerDependency().registerProvider(provider); + return provider; + } + +} diff --git a/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModuleFactory.java b/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModuleFactory.java new file mode 100644 index 00000000..af7a5753 --- /dev/null +++ b/arputil/arputil-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/arputil/impl/rev151126/ArputilImplModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: arputil-impl yang module local name: arputil-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon Dec 07 21:19:46 IST 2015 +* +* 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.arputil.impl.rev151126; +public class ArputilImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.impl.rev151126.AbstractArputilImplModuleFactory { + +} diff --git a/arputil/arputil-impl/src/main/yang/arputil-impl.yang b/arputil/arputil-impl/src/main/yang/arputil-impl.yang new file mode 100644 index 00000000..2107ff3a --- /dev/null +++ b/arputil/arputil-impl/src/main/yang/arputil-impl.yang @@ -0,0 +1,70 @@ +module arputil-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:arputil:impl"; + prefix "arputil-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 ietf-inet-types { prefix inet; } + import ietf-yang-types { prefix yang;} + + description + "Service definition for mdsal project"; + + revision "2015-11-26" { + description + "Initial revision"; + } + + identity arputil-impl { + base config:module-type; + } + + augment "/config:modules/config:module/config:configuration" { + case arputil-impl { + when "/config:modules/config:module/config:type = 'arputil-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 mdsalutil { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity odl-mdsal:odl-mdsalutil; + } + } + } + container notification-publish-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding-impl:binding-new-notification-publish-service; + } + } + } + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding-impl:binding-new-notification-service; + } + } + } + } + } +} diff --git a/arputil/pom.xml b/arputil/pom.xml new file mode 100644 index 00000000..a65eb708 --- /dev/null +++ b/arputil/pom.xml @@ -0,0 +1,49 @@ + + + + + + org.opendaylight.odlparent + odlparent + 1.6.0-SNAPSHOT + + + + org.opendaylight.vpnservice + arputil-aggregator + 0.2.0-SNAPSHOT + arputil + pom + 4.0.0 + + 3.1.1 + + + arputil-api + arputil-impl + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + diff --git a/commons/config-parent/pom.xml b/commons/config-parent/pom.xml index 0a47ecfa..60c9534b 100644 --- a/commons/config-parent/pom.xml +++ b/commons/config-parent/pom.xml @@ -30,6 +30,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html 2013.07.15.8-SNAPSHOT 0.2.0-SNAPSHOT 1.2.1-SNAPSHOT + 0.10.0-SNAPSHOT diff --git a/features/pom.xml b/features/pom.xml index 72b6f763..7d93dd38 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -28,6 +28,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL 0.8.0-SNAPSHOT 0.2.0-SNAPSHOT 1.2.1-SNAPSHOT + 0.10.0-SNAPSHOT + ${vpnservices.version} ${vpnservices.version} ${vpnservices.version} ${vpnservices.version} @@ -116,11 +118,29 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL ${vpnmanager.version} config xml - + + ${project.groupId} mdsalutil-impl ${mdsalutil.version} + + ${project.groupId} + arputil-api + ${arputil.version} + + + ${project.groupId} + arputil-impl + ${arputil.version} + config + xml + + + ${project.groupId} + arputil-impl + ${arputil.version} + ${project.groupId} mdsalutil-impl @@ -150,6 +170,28 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL interfacemgr-api ${interfacemgr.version} + + org.opendaylight.controller + liblldp + ${liblldp.version} + + + ${project.groupId} + alivenessmonitor-impl + ${vpnservices.version} + + + ${project.groupId} + alivenessmonitor-impl + ${vpnservices.version} + config + xml + + + ${project.groupId} + alivenessmonitor-api + ${vpnservices.version} + ${project.groupId} vpnmanager-api diff --git a/features/src/main/features/features.xml b/features/src/main/features/features.xml index 270db04d..a71d0af4 100644 --- a/features/src/main/features/features.xml +++ b/features/src/main/features/features.xml @@ -20,9 +20,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html odl-mdsal-broker odl-mdsal-models odl-openflowplugin-nsf-model + mvn:org.opendaylight.controller/liblldp/${liblldp.version} mvn:org.opendaylight.vpnservice/model-bgp/{{VERSION}} mvn:org.opendaylight.vpnservice/lockmanager-api/${lockmanager.version} mvn:org.opendaylight.vpnservice/idmanager-api/${idmanager.version} + mvn:org.opendaylight.vpnservice/arputil-api/${arputil.version} + mvn:org.opendaylight.vpnservice/alivenessmonitor-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/vpnmanager-api/${vpnmanager.version} mvn:org.opendaylight.vpnservice/nexthopmgr-api/${nexthopmgr.version} mvn:org.opendaylight.vpnservice/fibmanager-api/${fibmanager.version} @@ -39,6 +42,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html mvn:org.opendaylight.vpnservice/bgpmanager-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version} mvn:org.opendaylight.vpnservice/mdsalutil-api/${interfacemgr.version} + mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version} + mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version} mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version} mvn:org.opendaylight.vpnservice/interfacemgr-api/${interfacemgr.version} mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version} @@ -55,6 +60,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version}/xml/config mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version}/xml/config mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version}/xml/config + mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version}/xml/config + mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version}/xml/config mvn:org.opendaylight.vpnservice/vpnmanager-impl/${vpnmanager.version}/xml/config mvn:org.opendaylight.vpnservice/nexthopmgr-impl/${nexthopmgr.version}/xml/config mvn:org.opendaylight.vpnservice/fibmanager-impl/${fibmanager.version}/xml/config diff --git a/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java b/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java index 507dad2b..ebf4cd73 100644 --- a/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java +++ b/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdUtils.java @@ -52,15 +52,8 @@ class IdUtils { private static int BLADE_ID; static { - String hostName; try { - hostName = InetAddress.getLocalHost().getHostName(); BLADE_ID = InetAddresses.coerceToInteger(InetAddress.getLocalHost()); - if (hostName.indexOf("-") > 0) { - BLADE_ID = new Integer(hostName.split("-")[1].toString()).intValue(); - } else { - LOGGER.error("Host name {} is not matching with the condition!! PL-X is expected", hostName); - } } catch (Exception e) { LOGGER.error("IdManager - Exception - {}", e.getMessage()); } diff --git a/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java b/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java index d141e3ee..17f99bef 100644 --- a/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java +++ b/idmanager/idmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/idmanager/impl/rev150325/IdmanagerImplModule.java @@ -11,6 +11,7 @@ package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.idmanag import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.idmanager.IdManagerServiceProvider; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService; public class IdmanagerImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.idmanager.impl.rev150325.AbstractIdmanagerImplModule { public IdmanagerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { @@ -23,7 +24,9 @@ public class IdmanagerImplModule extends org.opendaylight.yang.gen.v1.urn.openda @Override public java.lang.AutoCloseable createInstance() { + LockManagerService lockManagerService = getRpcRegistryDependency().getRpcService(LockManagerService.class); IdManagerServiceProvider provider = new IdManagerServiceProvider(getRpcRegistryDependency()); + provider.setLockManager(lockManagerService); getBrokerDependency().registerProvider(provider); return provider; } diff --git a/idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java b/idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java index 181cc499..9833d04c 100644 --- a/idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java +++ b/idmanager/idmanager-impl/src/test/java/org/opendaylight/idmanager/test/IdManagerTest.java @@ -69,15 +69,8 @@ public class IdManagerTest { private static final Logger LOG = LoggerFactory.getLogger(IdManagerTest.class); private static int BLADE_ID; static { - String hostName; try { - hostName = InetAddress.getLocalHost().getHostName(); BLADE_ID = InetAddresses.coerceToInteger(InetAddress.getLocalHost()); - if (hostName.indexOf("-") > 0) { - BLADE_ID = new Integer(hostName.split("-")[1].toString()).intValue(); - } else { - LOG.error("Host name {} is not matching with the condition!! PL-X is expected", hostName); - } } catch (Exception e) { LOG.error("IdManager - Exception - {}", e.getMessage()); } diff --git a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang index 66b4a850..ef6aa20a 100644 --- a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang +++ b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-meta.yang @@ -61,4 +61,17 @@ module odl-interface-meta { } } } + + container if-indexes-interface-map { + config false; + list if-index-interface { + key if-index; + leaf if-index { + type int32; + } + leaf interface-name { + type string; + } + } + } } \ No newline at end of file diff --git a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang index 88ce5ac6..ef1cad59 100644 --- a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang +++ b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface-rpc.yang @@ -128,4 +128,18 @@ module odl-interface-rpc { } } } + + rpc get-interface-from-if-index { + description "to get interface associated with an if-index"; + input { + leaf if-index { + type int32; + } + } + output { + leaf interface-name { + type string; + } + } + } } \ No newline at end of file diff --git a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang index 9f6308e3..828ede50 100644 --- a/interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang +++ b/interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang @@ -160,6 +160,13 @@ module odl-interface { ext:augment-identifier "if-tunnel"; when "if:type = 'ianaift:tunnel'"; + leaf internal { + type boolean; + default "false"; + description + "represents whether this is an internal or external tunnel."; + } + leaf tunnel-interface-type { type identityref { base tunnel-type-base; diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java index ebfed475..26366286 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/IfmUtil.java @@ -38,9 +38,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150 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 IfmUtil { - + private static final Logger LOG = LoggerFactory.getLogger(IfmUtil.class); + private static final int INVALID_ID = 0; public static String getDpnFromNodeConnectorId(NodeConnectorId portId) { /* * NodeConnectorId is of form 'openflow:dpnid:portnum' @@ -154,6 +158,37 @@ public class IfmUtil { return new BigInteger[] { metadata, metadataMask }; } + public static Integer allocateId(IdManagerService idManager, String poolName, String idKey) { + AllocateIdInput getIdInput = new AllocateIdInputBuilder() + .setPoolName(poolName) + .setIdKey(idKey).build(); + try { + Future> result = idManager.allocateId(getIdInput); + RpcResult rpcResult = result.get(); + if(rpcResult.isSuccessful()) { + return rpcResult.getResult().getIdValue().intValue(); + } else { + LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when getting Unique Id",e); + } + return INVALID_ID; + } - + public static void releaseId(IdManagerService idManager, String poolName, String idKey) { + ReleaseIdInput idInput = new ReleaseIdInputBuilder() + .setPoolName(poolName) + .setIdKey(idKey).build(); + try { + Future> result = idManager.releaseId(idInput); + RpcResult rpcResult = result.get(); + if(!rpcResult.isSuccessful()) { + LOG.warn("RPC Call to release Id {} with Key {} returned with Errors {}", + idKey, rpcResult.getErrors()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when releasing Id for key {}", idKey, e); + } + } } diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java index e886115f..f519acf3 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java @@ -13,7 +13,6 @@ 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.idmanager.IdManager; import org.opendaylight.vpnservice.interfacemgr.listeners.InterfaceConfigListener; import org.opendaylight.vpnservice.interfacemgr.listeners.InterfaceInventoryStateListener; import org.opendaylight.vpnservice.interfacemgr.listeners.InterfaceTopologyStateListener; @@ -28,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. 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.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.*; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; @@ -43,7 +43,7 @@ public class InterfacemgrProvider implements BindingAwareProvider, AutoCloseable private static final Logger LOG = LoggerFactory.getLogger(InterfacemgrProvider.class); private RpcProviderRegistry rpcProviderRegistry; - private IdManager idManager; + private IdManagerService idManager; private InterfaceConfigListener interfaceConfigListener; private InterfaceTopologyStateListener topologyStateListener; @@ -64,7 +64,7 @@ public class InterfacemgrProvider implements BindingAwareProvider, AutoCloseable LOG.info("InterfacemgrProvider Session Initiated"); try { final DataBroker dataBroker = session.getSALService(DataBroker.class); - idManager = new IdManager(dataBroker); + idManager = rpcProviderRegistry.getRpcService(IdManagerService.class); createIdPool(); interfaceManagerRpcService = new InterfaceManagerRpcService(dataBroker); @@ -74,7 +74,7 @@ public class InterfacemgrProvider implements BindingAwareProvider, AutoCloseable interfaceConfigListener = new InterfaceConfigListener(dataBroker, idManager); interfaceConfigListener.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker); - interfaceInventoryStateListener = new InterfaceInventoryStateListener(dataBroker); + interfaceInventoryStateListener = new InterfaceInventoryStateListener(dataBroker, idManager); interfaceInventoryStateListener.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker); topologyStateListener = new InterfaceTopologyStateListener(dataBroker); diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java index f8aaaf6b..a123fccc 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/commons/InterfaceMetaUtils.java @@ -11,10 +11,17 @@ import com.google.common.base.Optional; 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.idmanager.IdManager; +import org.opendaylight.vpnservice.interfacemgr.IfmConstants; import org.opendaylight.vpnservice.interfacemgr.IfmUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.BridgeInterfaceInfo; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.BridgeRefInfo; +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.InterfaceChildInfo; +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.IfIndexInterfaceBuilder; +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.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; @@ -146,4 +153,19 @@ public class InterfaceMetaUtils { } return interfaceChildEntryOptional.get(); } + + public static void createLportTagInterfaceMap(WriteTransaction t, String infName, Integer ifIndex) { + InstanceIdentifier id = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(ifIndex)).build(); + IfIndexInterface ifIndexInterface = new IfIndexInterfaceBuilder().setIfIndex(ifIndex).setKey(new IfIndexInterfaceKey(ifIndex)).setInterfaceName(infName).build(); + t.put(LogicalDatastoreType.OPERATIONAL, id, ifIndexInterface, true); + } + + public static void removeLportTagInterfaceMap(WriteTransaction t, IdManagerService idManager, DataBroker broker, String infName, Integer ifIndex) { + InstanceIdentifier id = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(ifIndex)).build(); + Optional ifIndexesInterface = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker); + if(ifIndexesInterface.isPresent()) { + t.delete(LogicalDatastoreType.OPERATIONAL, id); + } + IfmUtil.releaseId(idManager, IfmConstants.IFM_IDPOOL_NAME, infName); + } } \ No newline at end of file diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java index a8457c55..6e911667 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceConfigListener.java @@ -18,6 +18,7 @@ import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.confighelpers.OvsIn import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.confighelpers.OvsInterfaceConfigUpdateHelper; 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.idmanager.rev150403.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; @@ -33,9 +34,9 @@ import java.util.concurrent.Callable; public class InterfaceConfigListener extends AsyncDataTreeChangeListenerBase { private static final Logger LOG = LoggerFactory.getLogger(InterfaceConfigListener.class); private DataBroker dataBroker; - private IdManager idManager; + private IdManagerService idManager; - public InterfaceConfigListener(final DataBroker dataBroker, final IdManager idManager) { + public InterfaceConfigListener(final DataBroker dataBroker, final IdManagerService idManager) { super(Interface.class, InterfaceConfigListener.class); this.dataBroker = dataBroker; this.idManager = idManager; diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java index 8629a75c..f496bbc0 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/InterfaceInventoryStateListener.java @@ -10,16 +10,19 @@ package org.opendaylight.vpnservice.interfacemgr.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; +import org.opendaylight.idmanager.IdManager; import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase; import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator; import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceStateAddHelper; import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceStateRemoveHelper; +import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceStateRemoveHelper; import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.statehelpers.OvsInterfaceStateUpdateHelper; 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.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,10 +41,12 @@ import java.util.concurrent.Callable; public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase implements AutoCloseable{ private static final Logger LOG = LoggerFactory.getLogger(InterfaceInventoryStateListener.class); private DataBroker dataBroker; + private IdManagerService idManager; - public InterfaceInventoryStateListener(final DataBroker dataBroker) { + public InterfaceInventoryStateListener(final DataBroker dataBroker, final IdManagerService idManager) { super(FlowCapableNodeConnector.class, InterfaceInventoryStateListener.class); this.dataBroker = dataBroker; + this.idManager = idManager; } @Override @@ -68,7 +73,7 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId(); DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance(); - InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(key, + InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager, key, flowCapableNodeConnectorOld, portName); coordinator.enqueueJob(portName, interfaceStateRemoveWorker); } @@ -92,7 +97,7 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId(); DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance(); - InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(nodeConnectorId, + InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(idManager, nodeConnectorId, fcNodeConnectorNew, portName); coordinator.enqueueJob(portName, ifStateAddWorker); } @@ -101,20 +106,22 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase private final NodeConnectorId nodeConnectorId; private final FlowCapableNodeConnector fcNodeConnectorNew; private final String portName; + private final IdManagerService idManager; - public InterfaceStateAddWorker(NodeConnectorId nodeConnectorId, + public InterfaceStateAddWorker(IdManagerService idManager, NodeConnectorId nodeConnectorId, FlowCapableNodeConnector fcNodeConnectorNew, String portName) { this.nodeConnectorId = nodeConnectorId; this.fcNodeConnectorNew = fcNodeConnectorNew; this.portName = portName; + this.idManager = idManager; } @Override public Object call() throws Exception { // If another renderer(for eg : CSS) needs to be supported, check can be performed here // to call the respective helpers. - return OvsInterfaceStateAddHelper.addState(dataBroker, nodeConnectorId, + return OvsInterfaceStateAddHelper.addState(dataBroker, idManager, nodeConnectorId, portName, fcNodeConnectorNew); } @@ -168,20 +175,23 @@ public class InterfaceInventoryStateListener extends AsyncDataChangeListenerBase InstanceIdentifier key; FlowCapableNodeConnector fcNodeConnectorOld; private final String portName; + private final IdManagerService idManager; - public InterfaceStateRemoveWorker(InstanceIdentifier key, + public InterfaceStateRemoveWorker(IdManagerService idManager, + InstanceIdentifier key, FlowCapableNodeConnector fcNodeConnectorOld, String portName) { this.key = key; this.fcNodeConnectorOld = fcNodeConnectorOld; this.portName = portName; + this.idManager = idManager; } @Override public Object call() throws Exception { // If another renderer(for eg : CSS) needs to be supported, check can be performed here // to call the respective helpers. - return OvsInterfaceStateRemoveHelper.removeState(key, dataBroker, portName, fcNodeConnectorOld); + return OvsInterfaceStateRemoveHelper.removeState(idManager, key, dataBroker, portName, fcNodeConnectorOld); } @Override diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java index 2d947162..eb43d689 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/listeners/VlanMemberConfigListener.java @@ -17,6 +17,7 @@ import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.confighelpers.OvsVl import org.opendaylight.vpnservice.interfacemgr.renderer.ovs.confighelpers.OvsVlanMemberConfigUpdateHelper; 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.idmanager.rev150403.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -29,9 +30,9 @@ import java.util.concurrent.Callable; public class VlanMemberConfigListener extends AsyncDataTreeChangeListenerBase { private static final Logger LOG = LoggerFactory.getLogger(VlanMemberConfigListener.class); private DataBroker dataBroker; - private IdManager idManager; + private IdManagerService idManager; - public VlanMemberConfigListener(final DataBroker dataBroker, final IdManager idManager) { + public VlanMemberConfigListener(final DataBroker dataBroker, final IdManagerService idManager) { super(Interface.class, VlanMemberConfigListener.class); this.dataBroker = dataBroker; this.idManager = idManager; diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java index 323ac880..17d4cf6b 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigAddHelper.java @@ -13,6 +13,7 @@ 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.idmanager.IdManager; +import org.opendaylight.vpnservice.interfacemgr.IfmConstants; import org.opendaylight.vpnservice.interfacemgr.IfmUtil; import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils; import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils; @@ -25,6 +26,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; 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; @@ -51,7 +53,7 @@ public class OvsInterfaceConfigAddHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigAddHelper.class); public static List> addConfiguration(DataBroker dataBroker, ParentRefs parentRefs, - Interface interfaceNew, IdManager idManager) { + Interface interfaceNew, IdManagerService idManager) { List> futures = new ArrayList<>(); IfTunnel ifTunnel = interfaceNew.getAugmentation(IfTunnel.class); @@ -60,19 +62,20 @@ public class OvsInterfaceConfigAddHelper { return futures; } - addVlanConfiguration(interfaceNew, dataBroker, futures); + addVlanConfiguration(interfaceNew, dataBroker, idManager, futures); return futures; } - private static void addVlanConfiguration(Interface interfaceNew, DataBroker dataBroker, + private static void addVlanConfiguration(Interface interfaceNew, DataBroker dataBroker, IdManagerService idManager, List> futures) { WriteTransaction t = dataBroker.newWriteOnlyTransaction(); org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceNew.getName(), dataBroker); + if (ifState == null) { return; } - updateStateEntry(interfaceNew, t, ifState); + updateStateEntry(interfaceNew, ifState.getIfIndex(), t, ifState); IfL2vlan ifL2vlan = interfaceNew.getAugmentation(IfL2vlan.class); if (ifL2vlan == null || ifL2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Trunk) { @@ -120,7 +123,7 @@ public class OvsInterfaceConfigAddHelper { } private static void addTunnelConfiguration(DataBroker dataBroker, ParentRefs parentRefs, - Interface interfaceNew, IdManager idManager, + Interface interfaceNew, IdManagerService idManager, List> futures) { LOG.debug("adding tunnel configuration for {}", interfaceNew.getName()); WriteTransaction t = dataBroker.newWriteOnlyTransaction(); @@ -168,17 +171,16 @@ public class OvsInterfaceConfigAddHelper { } } - private static void updateStateEntry(Interface interfaceNew, WriteTransaction t, + private static void updateStateEntry(Interface interfaceNew, Integer ifIndex, WriteTransaction t, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) { - OperStatus operStatus; + InstanceIdentifier ifStateId = + IfmUtil.buildStateInterfaceId(interfaceNew.getName()); + InterfaceBuilder ifaceBuilder = new InterfaceBuilder(); if (!interfaceNew.isEnabled() && ifState.getOperStatus() != OperStatus.Down) { - operStatus = OperStatus.Down; - InstanceIdentifier ifStateId = - IfmUtil.buildStateInterfaceId(interfaceNew.getName()); - InterfaceBuilder ifaceBuilder = new InterfaceBuilder(); - ifaceBuilder.setOperStatus(operStatus); - ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(interfaceNew.getName())); - t.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build()); + ifaceBuilder.setOperStatus(OperStatus.Down); } + ifaceBuilder.setIfIndex(ifIndex); + ifaceBuilder.setKey(IfmUtil.getStateInterfaceKeyFromName(interfaceNew.getName())); + t.merge(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build()); } } diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java index bb55c4f7..03f9c060 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigRemoveHelper.java @@ -23,6 +23,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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.idmanager.rev150403.IdManagerService; 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; @@ -49,21 +50,16 @@ public class OvsInterfaceConfigRemoveHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigRemoveHelper.class); public static List> removeConfiguration(DataBroker dataBroker, Interface interfaceOld, - IdManager idManager, ParentRefs parentRefs) { + IdManagerService idManager, ParentRefs parentRefs) { List> futures = new ArrayList<>(); WriteTransaction t = dataBroker.newWriteOnlyTransaction(); IfTunnel ifTunnel = interfaceOld.getAugmentation(IfTunnel.class); if (ifTunnel != null) { removeTunnelConfiguration(parentRefs, dataBroker, interfaceOld, idManager, t); - futures.add(t.submit()); - return futures; + }else { + removeVlanConfiguration(dataBroker, interfaceOld, t); } - - removeVlanConfiguration(dataBroker, interfaceOld, t); - - /* FIXME: Deallocate ID from Idmanager. */ - futures.add(t.submit()); return futures; } @@ -128,7 +124,7 @@ public class OvsInterfaceConfigRemoveHelper { } private static void removeTunnelConfiguration(ParentRefs parentRefs, DataBroker dataBroker, Interface interfaceOld, - IdManager idManager, WriteTransaction t) { + IdManagerService idManager, WriteTransaction t) { BigInteger dpId = null; if (parentRefs != null) { diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java index b7c2bb09..0770bd5b 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsInterfaceConfigUpdateHelper.java @@ -22,6 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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.idmanager.rev150403.IdManagerService; 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; @@ -38,7 +39,7 @@ import java.util.List; public class OvsInterfaceConfigUpdateHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceConfigUpdateHelper.class); - public static List> updateConfiguration(DataBroker dataBroker, IdManager idManager, + public static List> updateConfiguration(DataBroker dataBroker, IdManagerService idManager, Interface interfaceNew, Interface interfaceOld) { List> futures = new ArrayList<>(); diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java index 78f87f34..d9dd3762 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigAddHelper.java @@ -23,6 +23,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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.interfaces.rev140508.interfaces.state.InterfaceBuilder; 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.vpnservice.idmanager.rev150403.IdManagerService; 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.InterfaceParentEntryBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._interface.child.info.InterfaceParentEntryKey; @@ -42,7 +43,7 @@ public class OvsVlanMemberConfigAddHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsVlanMemberConfigAddHelper.class); public static List> addConfiguration(DataBroker dataBroker, ParentRefs parentRefs, Interface interfaceNew, IfL2vlan ifL2vlan, - IdManager idManager) { + IdManagerService idManager) { List> futures = new ArrayList<>(); WriteTransaction t = dataBroker.newWriteOnlyTransaction(); @@ -137,18 +138,16 @@ public class OvsVlanMemberConfigAddHelper { } } - private static long createInterfaceChildEntry(DataBroker dataBroker, IdManager idManager, WriteTransaction t, + private static long createInterfaceChildEntry(DataBroker dataBroker, IdManagerService idManager, WriteTransaction t, InterfaceParentEntryKey interfaceParentEntryKey, String childInterface){ - //TODO FIXME -// long lportTag = InterfaceManagerCommonUtils.getUniqueId(idManager, childInterface); -// InterfaceChildEntryKey interfaceChildEntryKey = new InterfaceChildEntryKey(childInterface); -// InstanceIdentifier intfId = -// InterfaceMetaUtils.getInterfaceChildEntryIdentifier(interfaceParentEntryKey, interfaceChildEntryKey); -// InterfaceChildEntryBuilder entryBuilder = new InterfaceChildEntryBuilder().setKey(interfaceChildEntryKey) -// .setChildInterface(childInterface); -// t.put(LogicalDatastoreType.CONFIGURATION, intfId, entryBuilder.build(),true); -// return lportTag; - return 0L; + long lportTag = IfmUtil.allocateId(idManager, IfmConstants.IFM_IDPOOL_NAME, childInterface); + InterfaceChildEntryKey interfaceChildEntryKey = new InterfaceChildEntryKey(childInterface); + InstanceIdentifier intfId = + InterfaceMetaUtils.getInterfaceChildEntryIdentifier(interfaceParentEntryKey, interfaceChildEntryKey); + InterfaceChildEntryBuilder entryBuilder = new InterfaceChildEntryBuilder().setKey(interfaceChildEntryKey) + .setChildInterface(childInterface); + t.put(LogicalDatastoreType.CONFIGURATION, intfId, entryBuilder.build(),true); + return lportTag; } } diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java index a0b404f3..cb039796 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigRemoveHelper.java @@ -16,6 +16,7 @@ import org.opendaylight.vpnservice.interfacemgr.IfmUtil; 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.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; 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; @@ -33,7 +34,7 @@ public class OvsVlanMemberConfigRemoveHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsVlanMemberConfigRemoveHelper.class); public static List> removeConfiguration(DataBroker dataBroker, ParentRefs parentRefs, Interface interfaceOld, IfL2vlan ifL2vlan, - IdManager idManager) { + IdManagerService idManager) { List> futures = new ArrayList<>(); WriteTransaction t = dataBroker.newWriteOnlyTransaction(); diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java index 73edde02..70332265 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/confighelpers/OvsVlanMemberConfigUpdateHelper.java @@ -18,6 +18,7 @@ import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils; 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.interfaces.rev140508.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; 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.InterfaceChildEntryKey; @@ -34,7 +35,7 @@ public class OvsVlanMemberConfigUpdateHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsVlanMemberConfigUpdateHelper.class); public static List> updateConfiguration(DataBroker dataBroker, ParentRefs parentRefsNew, Interface interfaceOld, IfL2vlan ifL2vlanNew, - Interface interfaceNew, IdManager idManager) { + Interface interfaceNew, IdManagerService idManager) { List> futures = new ArrayList<>(); ParentRefs parentRefsOld = interfaceOld.getAugmentation(ParentRefs.class); diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java index 95df1987..9891226d 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateAddHelper.java @@ -11,6 +11,8 @@ 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.idmanager.IdManager; +import org.opendaylight.vpnservice.interfacemgr.IfmConstants; import org.opendaylight.vpnservice.interfacemgr.IfmUtil; import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils; import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceMetaUtils; @@ -20,6 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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.vpnservice.idmanager.rev150403.IdManagerService; 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; @@ -42,7 +45,7 @@ import java.util.List; public class OvsInterfaceStateAddHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceStateAddHelper.class); - public static List> addState(DataBroker dataBroker, NodeConnectorId nodeConnectorId, + public static List> addState(DataBroker dataBroker, IdManagerService idManager, NodeConnectorId nodeConnectorId, String portName, FlowCapableNodeConnector fcNodeConnectorNew) { LOG.debug("Adding Interface State to Oper DS for port: {}", portName); List> futures = new ArrayList<>(); @@ -69,12 +72,15 @@ public class OvsInterfaceStateAddHelper { List lowerLayerIfList = new ArrayList<>(); lowerLayerIfList.add(nodeConnectorId.getValue()); + Integer ifIndex = IfmUtil.allocateId(idManager, IfmConstants.IFM_IDPOOL_NAME, portName); InstanceIdentifier ifStateId = IfmUtil.buildStateInterfaceId(portName); InterfaceBuilder ifaceBuilder = new InterfaceBuilder().setOperStatus(operStatus) - .setAdminStatus(adminStatus).setPhysAddress(physAddress).setLowerLayerIf(lowerLayerIfList) + .setAdminStatus(adminStatus).setPhysAddress(physAddress).setIfIndex(ifIndex).setLowerLayerIf(lowerLayerIfList) .setKey(IfmUtil.getStateInterfaceKeyFromName(portName)); t.put(LogicalDatastoreType.OPERATIONAL, ifStateId, ifaceBuilder.build(), true); + // allocate lport tag and set in if-index + InterfaceMetaUtils.createLportTagInterfaceMap(t, portName, ifIndex); if (iface == null) { futures.add(t.submit()); return futures; diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java index 26734cac..9d9c668e 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/renderer/ovs/statehelpers/OvsInterfaceStateRemoveHelper.java @@ -17,6 +17,7 @@ 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; 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; @@ -30,13 +31,19 @@ import java.util.List; public class OvsInterfaceStateRemoveHelper { private static final Logger LOG = LoggerFactory.getLogger(OvsInterfaceStateRemoveHelper.class); - public static List> removeState(InstanceIdentifier key, + public static List> removeState(IdManagerService idManager, + InstanceIdentifier key, DataBroker dataBroker, String portName, FlowCapableNodeConnector fcNodeConnectorOld) { LOG.debug("Removing interface-state for port: {}", portName); List> futures = new ArrayList<>(); WriteTransaction t = dataBroker.newWriteOnlyTransaction(); InstanceIdentifier ifStateId = IfmUtil.buildStateInterfaceId(portName); + /* Remove entry from if-index-interface-name map and deallocate Id from Idmanager. */ + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = + InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(portName, dataBroker); + InterfaceMetaUtils.removeLportTagInterfaceMap(t, idManager, dataBroker, interfaceState.getName(), interfaceState.getIfIndex()); + t.delete(LogicalDatastoreType.OPERATIONAL, ifStateId); // For Vlan-Trunk Interface, remove the trunk-member operstates as well... diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java index a2d26912..ef70eb84 100644 --- a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java +++ b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/rpcservice/InterfaceManagerRpcService.java @@ -31,7 +31,10 @@ 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.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.InterfaceChildInfo; +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.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; @@ -214,6 +217,26 @@ public class InterfaceManagerRpcService implements OdlInterfaceRpcService { return Futures.immediateFuture(rpcResultBuilder.build()); } + @Override + public Future> getInterfaceFromIfIndex(GetInterfaceFromIfIndexInput input) { + Integer ifIndex = input.getIfIndex(); + RpcResultBuilder rpcResultBuilder = null; + try { + InstanceIdentifier id = InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class, new IfIndexInterfaceKey(ifIndex)).build(); + Optional ifIndexesInterface = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, dataBroker); + if(ifIndexesInterface.isPresent()) { + String interfaceName = ifIndexesInterface.get().getInterfaceName(); + GetInterfaceFromIfIndexOutputBuilder output = new GetInterfaceFromIfIndexOutputBuilder().setInterfaceName(interfaceName); + rpcResultBuilder = RpcResultBuilder.success(); + rpcResultBuilder.withResult(output.build()); + } + } catch (Exception e) { + LOG.error("Retrieval of interfaceName for the key {} failed due to {}", ifIndex, e); + rpcResultBuilder = RpcResultBuilder.failed(); + } + return Futures.immediateFuture(rpcResultBuilder.build()); + } + public List getEgressActionInfosForInterface(String interfaceName) { Interface interfaceInfo = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName), dataBroker); diff --git a/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java b/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java index 92c0b743..24fa511b 100644 --- a/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java +++ b/interfacemgr/interfacemgr-impl/src/test/java/org/opendaylight/vpnservice/interfacemgr/test/TunnelInterfaceConfigurationTest.java @@ -33,6 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.No import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre; 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.OvsdbBridgeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; 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; @@ -82,7 +83,7 @@ public class TunnelInterfaceConfigurationTest { TerminationPoint terminationPoint; @Mock DataBroker dataBroker; - @Mock IdManager idManager; + @Mock IdManagerService idManager; @Mock ListenerRegistration dataChangeListenerRegistration; @Mock ReadOnlyTransaction mockReadTx; @Mock WriteTransaction mockWriteTx; diff --git a/lockmanager/lockmanager-api/pom.xml b/lockmanager/lockmanager-api/pom.xml index 4b9fe8c7..6b5be0f5 100644 --- a/lockmanager/lockmanager-api/pom.xml +++ b/lockmanager/lockmanager-api/pom.xml @@ -22,14 +22,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html - org.opendaylight.yangtools + org.opendaylight.mdsal yang-binding - ${yangtools.version} org.opendaylight.yangtools yang-common - ${yangtools.version} diff --git a/mdsalutil/mdsalutil-api/pom.xml b/mdsalutil/mdsalutil-api/pom.xml index 61410f8c..424319fa 100644 --- a/mdsalutil/mdsalutil-api/pom.xml +++ b/mdsalutil/mdsalutil-api/pom.xml @@ -1,14 +1,14 @@ - + org.opendaylight.vpnservice config-parent 0.2.0-SNAPSHOT ../../commons/config-parent - + 4.0.0 org.opendaylight.vpnservice mdsalutil-api @@ -16,16 +16,20 @@ bundle - - org.opendaylight.openflowplugin.model - model-flow-base - ${openflowplugin.version} - - - org.opendaylight.openflowplugin.model - model-flow-service - ${openflowplugin.version} + + org.opendaylight.openflowplugin.model + model-flow-base + ${openflowplugin.version} + + + org.opendaylight.openflowplugin.model + model-flow-service + ${openflowplugin.version} + + + org.opendaylight.controller + liblldp + ${liblldp.version} - diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java index 5ccaa576..1d10a69a 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/MDSALUtil.java @@ -17,6 +17,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +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.yang.types.rev100924.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; @@ -62,6 +66,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +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.binding.DataObject; @@ -72,7 +77,8 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.controller.liblldp.HexEncode; import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.primitives.Bytes; @@ -314,6 +320,12 @@ public class MDSALUtil { return getOfPortNumberFromPortName(nodeConnectorId.getValue()); } + public static long getDpnIdFromPortName(NodeConnectorId nodeConnectorId) { + String ofPortName = nodeConnectorId.getValue(); + return Long.parseLong(ofPortName.substring(ofPortName.indexOf(":")+1, + ofPortName.lastIndexOf(":"))); + } + public static long getOfPortNumberFromPortName(String sMdsalPortName) { String sPortNumber = sMdsalPortName.substring(sMdsalPortName.lastIndexOf(":") + 1); return Long.parseLong(sPortNumber); @@ -374,7 +386,6 @@ public class MDSALUtil { } catch (Exception e) { throw new RuntimeException(e); } - return result; } @@ -418,4 +429,52 @@ public class MDSALUtil { throw new RuntimeException(e.getMessage()); } } + + public static byte[] getMacAddressForNodeConnector(DataBroker broker, + InstanceIdentifier nodeConnectorId) { + Optional optNc = MDSALDataStoreUtils.read(broker, + LogicalDatastoreType.OPERATIONAL, nodeConnectorId); + if(optNc.isPresent()) { + NodeConnector nc = optNc.get(); + FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); + MacAddress macAddress = fcnc.getHardwareAddress(); + return HexEncode.bytesFromHexString(macAddress.getValue()); + } + return null; + } + + public static NodeId getNodeIdFromNodeConnectorId(NodeConnectorId ncId) { + return new NodeId(ncId.getValue().substring(0, + ncId.getValue().lastIndexOf(":"))); + } + + public static String getInterfaceName(NodeConnectorRef ref, DataBroker dataBroker) { + NodeConnectorId nodeConnectorId = getNodeConnectorId(dataBroker, ref); + NodeId nodeId = getNodeIdFromNodeConnectorId(nodeConnectorId); + InstanceIdentifier ncIdentifier = InstanceIdentifier + .builder(Nodes.class) + .child(Node.class, new NodeKey(nodeId)) + .child(NodeConnector.class, + new NodeConnectorKey(nodeConnectorId)).build(); + + Optional nodeConnectorOptional = read( + dataBroker, + LogicalDatastoreType.OPERATIONAL, ncIdentifier); + if (!nodeConnectorOptional.isPresent()) { + return null; + } + NodeConnector nc = nodeConnectorOptional.get(); + FlowCapableNodeConnector fc = nc + .getAugmentation(FlowCapableNodeConnector.class); + return fc.getName(); + } + + public static NodeConnectorId getNodeConnectorId(DataBroker dataBroker, + NodeConnectorRef ref) { + Optional nc = (Optional) read( + dataBroker, + LogicalDatastoreType.CONFIGURATION, ref.getValue()); + return nc.get().getId(); + } + } diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NWUtil.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NWUtil.java new file mode 100644 index 00000000..e2f3d635 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/NWUtil.java @@ -0,0 +1,92 @@ +/* + * 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.mdsalutil; + +import java.net.InetAddress; + +import com.google.common.primitives.UnsignedBytes; + +public class NWUtil { + + public static long convertInetAddressToLong(InetAddress address) { + byte[] ipAddressRaw = address.getAddress(); + return (((ipAddressRaw[0] & 0xFF) << (3 * 8)) + + ((ipAddressRaw[1] & 0xFF) << (2 * 8)) + + ((ipAddressRaw[2] & 0xFF) << (1 * 8)) + + (ipAddressRaw[3] & 0xFF)) + & 0xffffffffL; + } + + public static byte[] parseIpAddress(String ipAddress) { + byte cur; + + String[] addressPart = ipAddress.split("."); + int size = addressPart.length; + + byte[] part = new byte[size]; + for (int i = 0; i < size; i++) { + cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16); + part[i] = cur; + } + + return part; + } + + public static byte[] parseMacAddress(String macAddress) { + byte cur; + + String[] addressPart = macAddress.split(":"); + int size = addressPart.length; + + byte[] part = new byte[size]; + for (int i = 0; i < size; i++) { + cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16); + part[i] = cur; + } + + return part; + } + + public static String toStringIpAddress(byte[] ipAddress) + { + if (ipAddress == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(18); + + for (int i = 0; i < ipAddress.length; i++) { + sb.append(UnsignedBytes.toString(ipAddress[i], 10)); + sb.append("."); + } + + sb.setLength(17); + return sb.toString(); + } + + public static String toStringMacAddress(byte[] macAddress) + { + if (macAddress == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(18); + + for (int i = 0; i < macAddress.length; i++) { + String tmp = UnsignedBytes.toString(macAddress[i], 16).toUpperCase(); + if(tmp.length() == 1 || macAddress[i] == (byte)0) { + sb.append("0"); + } + sb.append(tmp); + sb.append(":"); + } + + sb.setLength(17); + return sb.toString(); + } +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java new file mode 100644 index 00000000..5f502d07 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2013, 2015 Cisco Systems, Inc. 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.mdsalutil.packet; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.Packet; + +/** + * Class that represents the ARP packet objects + * taken from opendaylight(helium) adsal bundle + * + */ + +public class ARP extends Packet { + private static final String HWTYPE = "HardwareType"; + private static final String PTYPE = "ProtocolType"; + private static final String HWADDRLENGTH = "HardwareAddressLength"; + private static final String PADDRLENGTH = "ProtocolAddressLength"; + private static final String OPCODE = "OpCode"; + private static final String SENDERHWADDR = "SenderHardwareAddress"; + private static final String SENDERPADDR = "SenderProtocolAddress"; + private static final String TARGETHWADDR = "TargetHardwareAddress"; + private static final String TARGETPADDR = "TargetProtocolAddress"; + + public static short HW_TYPE_ETHERNET = (short) 0x1; + public static short REQUEST = (short) 0x1; + public static short REPLY = (short) 0x2; + + public static short PROTO_TYPE_IP = 0x800; + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(HWTYPE, new ImmutablePair(0, 16)); + put(PTYPE, new ImmutablePair(16, 16)); + put(HWADDRLENGTH, new ImmutablePair(32, 8)); + put(PADDRLENGTH, new ImmutablePair(40, 8)); + put(OPCODE, new ImmutablePair(48, 16)); + put(SENDERHWADDR, new ImmutablePair(64, 48)); + put(SENDERPADDR, new ImmutablePair(112, 32)); + put(TARGETHWADDR, new ImmutablePair(144, 48)); + put(TARGETPADDR, new ImmutablePair(192, 32)); + + } + }; + private Map fieldValues; + + /** + * Default constructor that creates and sets the HashMap + */ + public ARP() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + /** + * Constructor that sets the access level for the packet and + * creates and sets the HashMap + */ + public ARP(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + public short getHardwareType() { + return (BitBufferHelper.getShort(fieldValues.get(HWTYPE))); + + } + + public short getProtocolType() { + return (BitBufferHelper.getShort(fieldValues.get(PTYPE))); + } + + public byte getHardwareAddressLength() { + return (BitBufferHelper.getByte(fieldValues.get(HWADDRLENGTH))); + } + + public byte getProtocolAddressLength() { + return (BitBufferHelper.getByte(fieldValues.get(PADDRLENGTH))); + } + + public short getOpCode() { + return (BitBufferHelper.getShort(fieldValues.get(OPCODE))); + } + + public byte[] getSenderHardwareAddress() { + return (fieldValues.get(SENDERHWADDR)); + } + + public byte[] getSenderProtocolAddress() { + return (fieldValues.get(SENDERPADDR)); + } + + public byte[] getTargetHardwareAddress() { + return (fieldValues.get(TARGETHWADDR)); + } + + public ARP setHardwareType(short hardwareType) { + byte[] hwType = BitBufferHelper.toByteArray(hardwareType); + fieldValues.put(HWTYPE, hwType); + return this; + } + + public ARP setProtocolType(short protocolType) { + byte[] protType = BitBufferHelper.toByteArray(protocolType); + fieldValues.put(PTYPE, protType); + return this; + } + + public ARP setHardwareAddressLength(byte hardwareAddressLength) { + byte[] hwAddressLength = BitBufferHelper + .toByteArray(hardwareAddressLength); + fieldValues.put(HWADDRLENGTH, hwAddressLength); + return this; + } + + public ARP setProtocolAddressLength(byte protocolAddressLength) { + byte[] protocolAddrLength = BitBufferHelper + .toByteArray(protocolAddressLength); + fieldValues.put(PADDRLENGTH, protocolAddrLength); + return this; + } + + public ARP setOpCode(short opCode) { + byte[] operationCode = BitBufferHelper.toByteArray(opCode); + fieldValues.put(OPCODE, operationCode); + return this; + } + + public ARP setSenderHardwareAddress(byte[] senderHardwareAddress) { + fieldValues.put(SENDERHWADDR, senderHardwareAddress); + return this; + } + + public ARP setTargetHardwareAddress(byte[] targetHardwareAddress) { + fieldValues.put(TARGETHWADDR, targetHardwareAddress); + return this; + } + + public ARP setTargetProtocolAddress(byte[] targetProtocolAddress) { + fieldValues.put(TARGETPADDR, targetProtocolAddress); + return this; + } + + public ARP setSenderProtocolAddress(byte[] senderIP) { + fieldValues.put(SENDERPADDR, senderIP); + return this; + } + + public byte[] getTargetProtocolAddress() { + return fieldValues.get(TARGETPADDR); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + + ((fieldValues == null) ? 0 : fieldValues.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ARP other = (ARP) obj; + if (fieldValues == null) { + if (other.fieldValues != null) { + return false; + } + } else if (!fieldValues.equals(other.fieldValues)) { + return false; + } + return true; + } +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java new file mode 100644 index 00000000..5fce3de1 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2013, 2015 Cisco Systems, Inc. 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.mdsalutil.packet; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.EtherTypes; +import org.opendaylight.controller.liblldp.LLDP; +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; + +/** + * Class that represents the Ethernet frame objects + * taken from opendaylight(helium) adsal bundle + */ +public class Ethernet extends Packet { + private static final String DMAC = "DestinationMACAddress"; + private static final String SMAC = "SourceMACAddress"; + private static final String ETHT = "EtherType"; + + // TODO: This has to be outside and it should be possible for osgi + // to add new coming packet classes + public static final Map> etherTypeClassMap; + static { + etherTypeClassMap = new HashMap>(); + etherTypeClassMap.put(EtherTypes.ARP.shortValue(), ARP.class); + // TODO: Add support for more classes here + // etherTypeClassMap.put(EtherTypes.VLANTAGGED.shortValue(), IEEE8021Q.class); + // etherTypeClassMap.put(EtherTypes.OLDQINQ.shortValue(), IEEE8021Q.class); + // etherTypeClassMap.put(EtherTypes.QINQ.shortValue(), IEEE8021Q.class); + // etherTypeClassMap.put(EtherTypes.CISCOQINQ.shortValue(), IEEE8021Q.class); + } + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(DMAC, new ImmutablePair(0, 48)); + put(SMAC, new ImmutablePair(48, 48)); + put(ETHT, new ImmutablePair(96, 16)); + } + }; + private final Map fieldValues; + + /** + * Default constructor that creates and sets the HashMap + */ + public Ethernet() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + /** + * Constructor that sets the access level for the packet and + * creates and sets the HashMap + */ + public Ethernet(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + @Override + public void setHeaderField(String headerField, byte[] readValue) { + if (headerField.equals(ETHT)) { + payloadClass = etherTypeClassMap.get(BitBufferHelper + .getShort(readValue)); + } + hdrFieldsMap.put(headerField, readValue); + } + + public byte[] getDestinationMACAddress() { + return fieldValues.get(DMAC); + } + + public byte[] getSourceMACAddress() { + return fieldValues.get(SMAC); + } + + public short getEtherType() { + return BitBufferHelper.getShort(fieldValues.get(ETHT)); + } + + public boolean isBroadcast(){ + return NetUtils.isBroadcastMACAddr(getDestinationMACAddress()); + } + + public boolean isMulticast(){ + return NetUtils.isMulticastMACAddr(getDestinationMACAddress()); + } + + public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) { + fieldValues.put(DMAC, destinationMACAddress); + return this; + } + + public Ethernet setSourceMACAddress(byte[] sourceMACAddress) { + fieldValues.put(SMAC, sourceMACAddress); + return this; + } + + public Ethernet setEtherType(short etherType) { + byte[] ethType = BitBufferHelper.toByteArray(etherType); + fieldValues.put(ETHT, ethType); + return this; + } + +} diff --git a/mdsalutil/mdsalutil-impl/pom.xml b/mdsalutil/mdsalutil-impl/pom.xml index dcc08370..0e9aeaf7 100644 --- a/mdsalutil/mdsalutil-impl/pom.xml +++ b/mdsalutil/mdsalutil-impl/pom.xml @@ -1,7 +1,7 @@ - + org.opendaylight.vpnservice config-parent @@ -13,10 +13,7 @@ mdsalutil-impl 0.2.0-SNAPSHOT bundle - - - 2.4.3 - + org.opendaylight.controller @@ -27,6 +24,11 @@ model-flow-base ${openflowplugin.version} + + org.opendaylight.controller + liblldp + ${liblldp.version} + org.opendaylight.openflowplugin.model model-flow-service diff --git a/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java b/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java index f44e8419..4f384474 100644 --- a/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java +++ b/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopManager.java @@ -64,7 +64,7 @@ public class NexthopManager implements L3nexthopService, AutoCloseable { private final DataBroker broker; private IMdsalApiManager mdsalManager; private IInterfaceManager interfaceManager; - private IdManager idManager; + private IdManagerService idManager; private static final short LPORT_INGRESS_TABLE = 0; private static final short LFIB_TABLE = 20; private static final short FIB_TABLE = 21; @@ -103,7 +103,7 @@ public class NexthopManager implements L3nexthopService, AutoCloseable { this.mdsalManager = mdsalManager; } - public void setIdManager(IdManager idManager) { + public void setIdManager(IdManagerService idManager) { this.idManager = idManager; } diff --git a/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java b/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java index de61812f..5855c759 100644 --- a/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java +++ b/nexthopmgr/nexthopmgr-impl/src/main/java/org/opendaylight/vpnservice/nexthopmgr/NexthopmgrProvider.java @@ -14,6 +14,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.vpnservice.nexthopmgr.NexthopManager; import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager; import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.L3nexthopService; import org.opendaylight.idmanager.IdManager; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; @@ -28,7 +29,7 @@ public class NexthopmgrProvider implements BindingAwareProvider, AutoCloseable { private NexthopManager nhManager; private IMdsalApiManager mdsalManager; private IInterfaceManager interfaceManager; - private IdManager idManager; + private IdManagerService idManager; private RpcProviderRegistry rpcProviderRegistry; public RpcProviderRegistry getRpcProviderRegistry() { @@ -46,7 +47,7 @@ public class NexthopmgrProvider implements BindingAwareProvider, AutoCloseable { nhManager = new NexthopManager(dbx); vpnIfListener = new VpnInterfaceChangeListener(dbx, nhManager); odlIfListener = new OdlInterfaceChangeListener(dbx, nhManager, interfaceManager); - idManager = new IdManager(dbx); + idManager = rpcProviderRegistry.getRpcService(IdManagerService.class); final BindingAwareBroker.RpcRegistration rpcRegistration = getRpcProviderRegistry().addRpcImplementation(L3nexthopService.class, nhManager); nhManager.setMdsalManager(mdsalManager); nhManager.setInterfaceManager(interfaceManager); diff --git a/pom.xml b/pom.xml index d1924206..880e5f3f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,8 +22,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL mdsalutil lockmanager idmanager + arputil vpnmanager interfacemgr + alivenessmonitor nexthopmgr fibmanager bgpmanager