LLDPSpeaker - Periodically sends out LLDP packets on interfaces
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / lldp / LLDPSpeaker.java
1 package org.opendaylight.openflowplugin.openflow.md.lldp;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.Timer;
7 import java.util.TimerTask;
8 import java.util.concurrent.ConcurrentHashMap;
9
10 import org.apache.commons.lang3.StringUtils;
11 import org.opendaylight.controller.sal.packet.Ethernet;
12 import org.opendaylight.controller.sal.packet.LLDP;
13 import org.opendaylight.controller.sal.packet.LLDPTLV;
14 import org.opendaylight.controller.sal.packet.PacketException;
15 import org.opendaylight.controller.sal.utils.EtherTypes;
16 import org.opendaylight.controller.sal.utils.HexEncode;
17 import org.opendaylight.openflowplugin.openflow.md.ModelDrivenSwitch;
18 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35 public class LLDPSpeaker {
36     private static Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class);
37         
38         private  final Map<InstanceIdentifier<NodeConnector>,TransmitPacketInput> nodeConnectorMap = new ConcurrentHashMap<InstanceIdentifier<NodeConnector>,TransmitPacketInput>();
39         private  final Map<InstanceIdentifier<Node>,ModelDrivenSwitch> nodeMap = new ConcurrentHashMap<InstanceIdentifier<Node>,ModelDrivenSwitch>();
40         private static final LLDPSpeaker instance = new LLDPSpeaker();
41         private Timer timer = new Timer();
42         private static final int DELAY = 0;
43         private static final int PERIOD = 1000*5;
44         
45         private LLDPSpeaker() {
46             timer.schedule(new LLDPSpeakerTask(), DELAY, PERIOD);
47         }
48         
49         public static LLDPSpeaker getInstance() {
50             return instance;
51         }
52         
53         public  void addModelDrivenSwitch(InstanceIdentifier<Node> nodeInstanceId, ModelDrivenSwitch sw) {
54                 nodeMap.put(nodeInstanceId,sw);         
55         }
56         
57         public void removeModelDrivenSwitch(InstanceIdentifier<Node> nodeInstanceId) {
58             nodeMap.remove(nodeInstanceId);
59             for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
60                 if(nodeInstanceId.equals(nodeConnectorInstanceId.firstIdentifierOf(Node.class))) {
61                     nodeConnectorMap.remove(nodeConnectorInstanceId);
62                 }
63             }
64         }
65
66         public  void addNodeConnector(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId, NodeConnector nodeConnector) {
67         InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
68         NodeKey nodeKey = InstanceIdentifier.keyOf(nodeInstanceId);
69         NodeId nodeId = nodeKey.getId();
70         NodeConnectorId nodeConnectorId = nodeConnector.getId();
71         FlowCapableNodeConnector flowConnector = nodeConnector.<FlowCapableNodeConnector>getAugmentation(FlowCapableNodeConnector.class);
72         TransmitPacketInputBuilder tpib = new TransmitPacketInputBuilder();
73         tpib.setEgress(new NodeConnectorRef(nodeConnectorInstanceId));
74         tpib.setNode(new NodeRef(nodeInstanceId));
75         tpib.setPayload(lldpDataFrom(nodeInstanceId,nodeConnectorInstanceId,flowConnector.getHardwareAddress()));
76         nodeConnectorMap.put(nodeConnectorInstanceId, tpib.build());
77         ModelDrivenSwitch md = nodeMap.get(nodeInstanceId);
78         md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
79         }
80
81         public  void removeNodeConnector(
82                         InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
83                         NodeConnector nodeConnector) {
84                 nodeConnectorMap.remove(nodeConnectorInstanceId);               
85         }
86         
87         private  byte[] lldpDataFrom(InstanceIdentifier<Node> nodeInstanceId,InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,MacAddress src) {
88                 
89             NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId();
90             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
91                 // Create LLDP TTL TLV
92         byte[] ttl = new byte[] { (byte) 0, (byte) 120 };
93         LLDPTLV ttlTlv = new LLDPTLV();
94         ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
95                 
96         // Create LLDP ChassisID TLV
97         byte[] cidValue = LLDPTLV.createChassisIDTLVValue(colonize(StringUtils.leftPad(Long.toHexString(InventoryDataServiceUtil.dataPathIdFromNodeId(nodeId)),16,"0")));
98         LLDPTLV chassisIdTlv = new LLDPTLV();
99         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
100         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
101                 .setValue(cidValue);
102
103         // Create LLDP SystemName TLV
104         byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeId.getValue());
105         LLDPTLV systemNameTlv = new LLDPTLV();
106         systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
107         systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
108                 .setValue(snValue);
109
110         // Create LLDP PortID TL
111         Long portNo = InventoryDataServiceUtil.portNumberfromNodeConnectorId(nodeConnectorId);
112         String hexString = Long.toHexString(portNo);
113         byte[] pidValue = LLDPTLV.createPortIDTLVValue(hexString);
114         LLDPTLV portIdTlv = new LLDPTLV();
115         portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue);
116         portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
117
118         // Create LLDP Custom TLV
119         NodeConnectorRef ncref = new NodeConnectorRef(nodeConnectorInstanceId);
120         byte[] customValue = LLDPTLV.createCustomTLVValue(ncref.toString());
121         LLDPTLV customTlv = new LLDPTLV();
122         customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length)
123                 .setValue(customValue);
124
125         // Create LLDP Custom Option list
126         List<LLDPTLV> customList = new ArrayList<LLDPTLV>();
127         customList.add(customTlv);
128
129         // Create discovery pkt
130         LLDP discoveryPkt = new LLDP();
131         discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
132                 .setOptionalTLVList(customList);
133
134         // Create ethernet pkt
135         byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue());
136         Ethernet ethPkt = new Ethernet();
137         ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac)
138                 .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt);
139
140         try {
141             byte[] data = ethPkt.serialize();
142             return data;
143         } catch (PacketException e) {
144             LOG.error("Error creating LLDP packet",e);
145         }
146         return null;
147         }
148         
149         private class LLDPSpeakerTask extends TimerTask {
150
151         @Override
152         public void run() {
153             for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
154                 InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
155                 ModelDrivenSwitch md = nodeMap.get(nodeInstanceId);
156                 md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
157             }
158             
159         }
160             
161         }
162         
163         private String colonize(String orig) {
164             return orig.replaceAll("(?<=..)(..)", ":$1");
165         }
166 }