2 * Copyright (c) 2013 Cisco Systems, Inc. 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
8 package org.opendaylight.openflowplugin.openflow.md.lldp;
10 import org.opendaylight.controller.sal.packet.Ethernet;
11 import org.opendaylight.controller.sal.packet.LLDP;
12 import org.opendaylight.controller.sal.packet.LLDPTLV;
13 import org.opendaylight.controller.sal.packet.PacketException;
14 import org.opendaylight.controller.sal.utils.EtherTypes;
15 import org.opendaylight.controller.sal.utils.HexEncode;
16 import org.opendaylight.openflowplugin.openflow.md.ModelDrivenSwitch;
17 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
18 import org.opendaylight.openflowplugin.openflow.md.util.OpenflowVersion;
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;
34 import java.math.BigInteger;
35 import java.util.Collections;
36 import java.util.List;
38 import java.util.Timer;
39 import java.util.TimerTask;
40 import java.util.concurrent.ConcurrentHashMap;
43 public class LLDPSpeaker {
44 private static Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class);
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;
53 private LLDPSpeaker() {
54 timer.schedule(new LLDPSpeakerTask(), DELAY, PERIOD);
57 public static LLDPSpeaker getInstance() {
61 public void addModelDrivenSwitch(InstanceIdentifier<Node> nodeInstanceId, ModelDrivenSwitch sw) {
62 nodeMap.put(nodeInstanceId,sw);
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);
74 public void addNodeConnector(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId, NodeConnector nodeConnector) {
75 InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
76 ModelDrivenSwitch md = nodeMap.get(nodeInstanceId);
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());
89 md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
92 public void removeNodeConnector(
93 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
94 NodeConnector nodeConnector) {
95 nodeConnectorMap.remove(nodeConnectorInstanceId);
98 private byte[] lldpDataFrom(InstanceIdentifier<Node> nodeInstanceId,InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,MacAddress src,
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);
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)
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)
124 // Create LLDP PortID TL
125 Long portNo = InventoryDataServiceUtil.portNumberfromNodeConnectorId(OpenflowVersion.get(version), nodeConnectorId);
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());
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);
139 // Create LLDP Custom Option list
140 List<LLDPTLV> customList = Collections.singletonList(customTlv);
142 // Create discovery pkt
143 LLDP discoveryPkt = new LLDP();
144 discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
145 .setOptionalTLVList(customList);
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);
154 byte[] data = ethPkt.serialize();
156 } catch (PacketException e) {
157 LOG.error("Error creating LLDP packet",e);
162 private class LLDPSpeakerTask extends TimerTask {
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));
176 private String colonize(String orig) {
177 return orig.replaceAll("(?<=..)(..)", ":$1");