Merge "OPNFLWPLUG-929 : Remove deprecated guava library"
[openflowplugin.git] / applications / lldp-speaker / src / main / java / org / opendaylight / openflowplugin / applications / lldpspeaker / LLDPSpeaker.java
1 /*
2  * Copyright (c) 2014 Pacnet and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.openflowplugin.applications.lldpspeaker;
10
11 import java.util.Map;
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.rev130715.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;
32
33 /**
34  * Objects of this class send LLDP frames over all flow-capable ports that can
35  * be discovered through inventory.
36  */
37 public class LLDPSpeaker implements AutoCloseable, NodeConnectorEventsObserver, Runnable {
38     private static final Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class);
39     private static final long LLDP_FLOOD_PERIOD = 5;
40     private long currentFloodPeriod = LLDP_FLOOD_PERIOD;
41
42     private final PacketProcessingService packetProcessingService;
43     private final ScheduledExecutorService scheduledExecutorService;
44     private final Map<InstanceIdentifier<NodeConnector>, TransmitPacketInput> nodeConnectorMap = new
45             ConcurrentHashMap<>();
46     private ScheduledFuture<?> scheduledSpeakerTask;
47     private final MacAddress addressDestionation;
48     private volatile OperStatus operationalStatus = OperStatus.RUN;
49
50     public LLDPSpeaker(final PacketProcessingService packetProcessingService, final MacAddress addressDestionation) {
51         this(packetProcessingService, Executors.newSingleThreadScheduledExecutor(), addressDestionation);
52     }
53
54     public void setOperationalStatus(final OperStatus operationalStatus) {
55         LOG.info("Setting operational status to {}", operationalStatus);
56         this.operationalStatus = operationalStatus;
57         if (operationalStatus.equals(OperStatus.STANDBY)) {
58             nodeConnectorMap.clear();
59         }
60     }
61
62     public OperStatus getOperationalStatus() {
63         return operationalStatus;
64     }
65
66     public void setLldpFloodInterval(long time) {
67         this.currentFloodPeriod = time;
68         scheduledSpeakerTask.cancel(false);
69         scheduledSpeakerTask = this.scheduledExecutorService.scheduleAtFixedRate(this, time, time, TimeUnit.SECONDS);
70         LOG.info("LLDPSpeaker restarted, it will send LLDP frames each {} seconds", time);
71     }
72
73     public long getLldpFloodInterval() {
74         return currentFloodPeriod;
75     }
76
77     public LLDPSpeaker(final PacketProcessingService packetProcessingService,
78                        final ScheduledExecutorService scheduledExecutorService, final MacAddress addressDestionation) {
79         this.addressDestionation = addressDestionation;
80         this.scheduledExecutorService = scheduledExecutorService;
81         scheduledSpeakerTask = this.scheduledExecutorService.scheduleAtFixedRate(this, LLDP_FLOOD_PERIOD,
82                 LLDP_FLOOD_PERIOD, TimeUnit.SECONDS);
83         this.packetProcessingService = packetProcessingService;
84         LOG.info("LLDPSpeaker started, it will send LLDP frames each {} seconds", LLDP_FLOOD_PERIOD);
85     }
86
87     /**
88      * Closes this resource, relinquishing any underlying resources.
89      */
90     @Override
91     public void close() {
92         nodeConnectorMap.clear();
93         scheduledExecutorService.shutdown();
94         scheduledSpeakerTask.cancel(true);
95         LOG.trace("LLDPSpeaker stopped sending LLDP frames.");
96     }
97
98     /**
99      * Send LLDPDU frames to all known openflow switch ports.
100      */
101     @Override
102     public void run() {
103         if (OperStatus.RUN.equals(operationalStatus)) {
104             LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap.keySet().size());
105             for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
106                 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
107                 LOG.trace("Sending LLDP through port {}", nodeConnectorId.getValue());
108                 packetProcessingService.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
109             }
110         }
111     }
112
113     @Override
114     public void nodeConnectorAdded(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
115                                    final FlowCapableNodeConnector flowConnector) {
116         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
117
118         // nodeConnectorAdded can be called even if we already sending LLDP
119         // frames to
120         // port, so first we check if we actually need to perform any action
121         if (nodeConnectorMap.containsKey(nodeConnectorInstanceId)) {
122             LOG.trace("Port {} already in LLDPSpeaker.nodeConnectorMap, no need for additional processing",
123                     nodeConnectorId.getValue());
124             return;
125         }
126
127         // Prepare to build LLDP payload
128         InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
129         NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId();
130         MacAddress srcMacAddress = flowConnector.getHardwareAddress();
131         Long outputPortNo = flowConnector.getPortNumber().getUint32();
132
133         // No need to send LLDP frames on local ports
134         if (outputPortNo == null) {
135             LOG.trace("Port {} is local, not sending LLDP frames through it", nodeConnectorId.getValue());
136             return;
137         }
138
139         // Generate packet with destination switch and port
140         TransmitPacketInput packet = new TransmitPacketInputBuilder()
141                 .setEgress(new NodeConnectorRef(nodeConnectorInstanceId))
142                 .setNode(new NodeRef(nodeInstanceId)).setPayload(LLDPUtil.buildLldpFrame(nodeId,
143                         nodeConnectorId, srcMacAddress, outputPortNo, addressDestionation)).build();
144
145         // Save packet to node connector id -> packet map to transmit it every 5
146         // seconds
147         nodeConnectorMap.put(nodeConnectorInstanceId, packet);
148         LOG.trace("Port {} added to LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());
149
150         // Transmit packet for first time immediately
151         packetProcessingService.transmitPacket(packet);
152     }
153
154     @Override
155     public void nodeConnectorRemoved(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
156         nodeConnectorMap.remove(nodeConnectorInstanceId);
157         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
158         LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());
159     }
160
161 }