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.*;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * Objects of this class send LLDP frames over all flow-capable ports that can
31 * be discovered through inventory.
33 public class LLDPSpeaker implements AutoCloseable, NodeConnectorEventsObserver, Runnable {
34 private static final Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class);
35 private static final long LLDP_FLOOD_PERIOD = 5;
37 private final PacketProcessingService packetProcessingService;
38 private final ScheduledExecutorService scheduledExecutorService;
39 private final Map<InstanceIdentifier<NodeConnector>, TransmitPacketInput> nodeConnectorMap =
40 new ConcurrentHashMap<>();
41 private final ScheduledFuture<?> scheduledSpeakerTask;
43 public LLDPSpeaker(PacketProcessingService packetProcessingService) {
44 this(packetProcessingService, Executors.newSingleThreadScheduledExecutor());
47 public LLDPSpeaker(PacketProcessingService packetProcessingService,
48 ScheduledExecutorService scheduledExecutorService) {
49 this.scheduledExecutorService = scheduledExecutorService;
50 scheduledSpeakerTask = this.scheduledExecutorService.scheduleAtFixedRate(
51 this, LLDP_FLOOD_PERIOD, LLDP_FLOOD_PERIOD, TimeUnit.SECONDS);
52 this.packetProcessingService = packetProcessingService;
53 LOG.info("LLDPSpeaker started, it will send LLDP frames each {} seconds", LLDP_FLOOD_PERIOD);
57 * Closes this resource, relinquishing any underlying resources.
61 nodeConnectorMap.clear();
62 scheduledExecutorService.shutdown();
63 scheduledSpeakerTask.cancel(true);
64 LOG.trace("LLDPSpeaker stopped sending LLDP frames.");
68 * Send LLDPDU frames to all known openflow switch ports.
72 LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap.keySet().size());
74 for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
75 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
76 LOG.trace("Sending LLDP through port {}", nodeConnectorId.getValue());
77 packetProcessingService.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
85 public void nodeConnectorAdded(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
86 FlowCapableNodeConnector flowConnector) {
87 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
89 // nodeConnectorAdded can be called even if we already sending LLDP frames to
90 // port, so first we check if we actually need to perform any action
91 if (nodeConnectorMap.containsKey(nodeConnectorInstanceId)) {
92 LOG.trace("Port {} already in LLDPSpeaker.nodeConnectorMap, no need for additional processing",
93 nodeConnectorId.getValue());
97 // Prepare to build LLDP payload
98 InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
99 NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId();
100 MacAddress srcMacAddress = flowConnector.getHardwareAddress();
101 Long outputPortNo = flowConnector.getPortNumber().getUint32();
103 // No need to send LLDP frames on local ports
104 if (outputPortNo == null) {
105 LOG.trace("Port {} is local, not sending LLDP frames through it",
106 nodeConnectorId.getValue());
110 // Generate packet with destination switch and port
111 TransmitPacketInput packet = new TransmitPacketInputBuilder()
112 .setEgress(new NodeConnectorRef(nodeConnectorInstanceId))
113 .setNode(new NodeRef(nodeInstanceId))
114 .setPayload(LLDPUtil.buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress, outputPortNo))
117 // Save packet to node connector id -> packet map to transmit it every 5 seconds
118 nodeConnectorMap.put(nodeConnectorInstanceId, packet);
119 LOG.trace("Port {} added to LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());
121 // Transmit packet for first time immediately
122 packetProcessingService.transmitPacket(packet);
129 public void nodeConnectorRemoved(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
130 nodeConnectorMap.remove(nodeConnectorInstanceId);
131 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
132 LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());