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