2 * Copyright (c) 2014 Pacnet and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowplugin.applications.lldpspeaker;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.Executors;
14 import java.util.concurrent.ScheduledExecutorService;
15 import java.util.concurrent.ScheduledFuture;
16 import java.util.concurrent.TimeUnit;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.applications.lldp.speaker.rev141023.OperStatus;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Objects of this class send LLDP frames over all flow-capable ports that can
35 * be discovered through inventory.
37 public class LLDPSpeaker implements AutoCloseable, NodeConnectorEventsObserver,
40 private static final Logger LOG = LoggerFactory
41 .getLogger(LLDPSpeaker.class);
42 private static final long LLDP_FLOOD_PERIOD = 5;
44 private final PacketProcessingService packetProcessingService;
45 private final ScheduledExecutorService scheduledExecutorService;
46 private final Map<InstanceIdentifier<NodeConnector>, TransmitPacketInput> nodeConnectorMap = new ConcurrentHashMap<>();
47 private final ScheduledFuture<?> scheduledSpeakerTask;
48 private final MacAddress addressDestionation;
49 private volatile OperStatus operationalStatus = OperStatus.RUN;
51 public LLDPSpeaker(final PacketProcessingService packetProcessingService,
52 final MacAddress addressDestionation) {
53 this(packetProcessingService, Executors
54 .newSingleThreadScheduledExecutor(), addressDestionation);
57 public void setOperationalStatus(final OperStatus operationalStatus) {
58 LOG.info("Setting operational status to {}", operationalStatus);
59 this.operationalStatus = operationalStatus;
60 if (operationalStatus.equals(OperStatus.STANDBY)) {
61 nodeConnectorMap.clear();
65 public OperStatus getOperationalStatus() {
66 return operationalStatus;
69 public LLDPSpeaker(final PacketProcessingService packetProcessingService,
70 final ScheduledExecutorService scheduledExecutorService,
71 final MacAddress addressDestionation) {
72 this.addressDestionation = addressDestionation;
73 this.scheduledExecutorService = scheduledExecutorService;
74 scheduledSpeakerTask = this.scheduledExecutorService
75 .scheduleAtFixedRate(this, LLDP_FLOOD_PERIOD,
76 LLDP_FLOOD_PERIOD, TimeUnit.SECONDS);
77 this.packetProcessingService = packetProcessingService;
79 "LLDPSpeaker started, it will send LLDP frames each {} seconds",
84 * Closes this resource, relinquishing any underlying resources.
88 nodeConnectorMap.clear();
89 scheduledExecutorService.shutdown();
90 scheduledSpeakerTask.cancel(true);
91 LOG.trace("LLDPSpeaker stopped sending LLDP frames.");
95 * Send LLDPDU frames to all known openflow switch ports.
99 if (OperStatus.RUN.equals(operationalStatus)) {
100 LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap
103 for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap
105 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
106 nodeConnectorInstanceId).getId();
107 LOG.trace("Sending LLDP through port {}",
108 nodeConnectorId.getValue());
109 packetProcessingService.transmitPacket(nodeConnectorMap
110 .get(nodeConnectorInstanceId));
119 public void nodeConnectorAdded(
120 final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
121 final FlowCapableNodeConnector flowConnector) {
122 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
123 nodeConnectorInstanceId).getId();
125 // nodeConnectorAdded can be called even if we already sending LLDP
127 // port, so first we check if we actually need to perform any action
128 if (nodeConnectorMap.containsKey(nodeConnectorInstanceId)) {
130 "Port {} already in LLDPSpeaker.nodeConnectorMap, no need for additional processing",
131 nodeConnectorId.getValue());
135 // Prepare to build LLDP payload
136 InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId
137 .firstIdentifierOf(Node.class);
138 NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId();
139 MacAddress srcMacAddress = flowConnector.getHardwareAddress();
140 Long outputPortNo = flowConnector.getPortNumber().getUint32();
142 // No need to send LLDP frames on local ports
143 if (outputPortNo == null) {
144 LOG.trace("Port {} is local, not sending LLDP frames through it",
145 nodeConnectorId.getValue());
149 // Generate packet with destination switch and port
150 TransmitPacketInput packet = new TransmitPacketInputBuilder()
151 .setEgress(new NodeConnectorRef(nodeConnectorInstanceId))
152 .setNode(new NodeRef(nodeInstanceId))
154 LLDPUtil.buildLldpFrame(nodeId, nodeConnectorId,
155 srcMacAddress, outputPortNo,
156 addressDestionation)).build();
158 // Save packet to node connector id -> packet map to transmit it every 5
160 nodeConnectorMap.put(nodeConnectorInstanceId, packet);
161 LOG.trace("Port {} added to LLDPSpeaker.nodeConnectorMap",
162 nodeConnectorId.getValue());
164 // Transmit packet for first time immediately
165 packetProcessingService.transmitPacket(packet);
172 public void nodeConnectorRemoved(
173 final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
174 nodeConnectorMap.remove(nodeConnectorInstanceId);
175 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
176 nodeConnectorInstanceId).getId();
177 LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap",
178 nodeConnectorId.getValue());