--- /dev/null
+package org.opendaylight.openflowplugin.openflow.md.lldp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.LLDP;
+import org.opendaylight.controller.sal.packet.LLDPTLV;
+import org.opendaylight.controller.sal.packet.PacketException;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.openflowplugin.openflow.md.ModelDrivenSwitch;
+import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class LLDPSpeaker {
+ private static Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class);
+
+ private final Map<InstanceIdentifier<NodeConnector>,TransmitPacketInput> nodeConnectorMap = new ConcurrentHashMap<InstanceIdentifier<NodeConnector>,TransmitPacketInput>();
+ private final Map<InstanceIdentifier<Node>,ModelDrivenSwitch> nodeMap = new ConcurrentHashMap<InstanceIdentifier<Node>,ModelDrivenSwitch>();
+ private static final LLDPSpeaker instance = new LLDPSpeaker();
+ private Timer timer = new Timer();
+ private static final int DELAY = 0;
+ private static final int PERIOD = 1000*5;
+
+ private LLDPSpeaker() {
+ timer.schedule(new LLDPSpeakerTask(), DELAY, PERIOD);
+ }
+
+ public static LLDPSpeaker getInstance() {
+ return instance;
+ }
+
+ public void addModelDrivenSwitch(InstanceIdentifier<Node> nodeInstanceId, ModelDrivenSwitch sw) {
+ nodeMap.put(nodeInstanceId,sw);
+ }
+
+ public void removeModelDrivenSwitch(InstanceIdentifier<Node> nodeInstanceId) {
+ nodeMap.remove(nodeInstanceId);
+ for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
+ if(nodeInstanceId.equals(nodeConnectorInstanceId.firstIdentifierOf(Node.class))) {
+ nodeConnectorMap.remove(nodeConnectorInstanceId);
+ }
+ }
+ }
+
+ public void addNodeConnector(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId, NodeConnector nodeConnector) {
+ InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
+ NodeKey nodeKey = InstanceIdentifier.keyOf(nodeInstanceId);
+ NodeId nodeId = nodeKey.getId();
+ NodeConnectorId nodeConnectorId = nodeConnector.getId();
+ FlowCapableNodeConnector flowConnector = nodeConnector.<FlowCapableNodeConnector>getAugmentation(FlowCapableNodeConnector.class);
+ TransmitPacketInputBuilder tpib = new TransmitPacketInputBuilder();
+ tpib.setEgress(new NodeConnectorRef(nodeConnectorInstanceId));
+ tpib.setNode(new NodeRef(nodeInstanceId));
+ tpib.setPayload(lldpDataFrom(nodeInstanceId,nodeConnectorInstanceId,flowConnector.getHardwareAddress()));
+ nodeConnectorMap.put(nodeConnectorInstanceId, tpib.build());
+ ModelDrivenSwitch md = nodeMap.get(nodeInstanceId);
+ md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
+ }
+
+ public void removeNodeConnector(
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
+ NodeConnector nodeConnector) {
+ nodeConnectorMap.remove(nodeConnectorInstanceId);
+ }
+
+ private byte[] lldpDataFrom(InstanceIdentifier<Node> nodeInstanceId,InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,MacAddress src) {
+
+ NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId();
+ NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
+ // Create LLDP TTL TLV
+ byte[] ttl = new byte[] { (byte) 0, (byte) 120 };
+ LLDPTLV ttlTlv = new LLDPTLV();
+ ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
+
+ // Create LLDP ChassisID TLV
+ byte[] cidValue = LLDPTLV.createChassisIDTLVValue(colonize(StringUtils.leftPad(Long.toHexString(InventoryDataServiceUtil.dataPathIdFromNodeId(nodeId)),16,"0")));
+ LLDPTLV chassisIdTlv = new LLDPTLV();
+ chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
+ chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
+ .setValue(cidValue);
+
+ // Create LLDP SystemName TLV
+ byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeId.getValue());
+ LLDPTLV systemNameTlv = new LLDPTLV();
+ systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
+ systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
+ .setValue(snValue);
+
+ // Create LLDP PortID TL
+ Long portNo = InventoryDataServiceUtil.portNumberfromNodeConnectorId(nodeConnectorId);
+ String hexString = Long.toHexString(portNo);
+ byte[] pidValue = LLDPTLV.createPortIDTLVValue(hexString);
+ LLDPTLV portIdTlv = new LLDPTLV();
+ portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue);
+ portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
+
+ // Create LLDP Custom TLV
+ NodeConnectorRef ncref = new NodeConnectorRef(nodeConnectorInstanceId);
+ byte[] customValue = LLDPTLV.createCustomTLVValue(ncref.toString());
+ LLDPTLV customTlv = new LLDPTLV();
+ customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length)
+ .setValue(customValue);
+
+ // Create LLDP Custom Option list
+ List<LLDPTLV> customList = new ArrayList<LLDPTLV>();
+ customList.add(customTlv);
+
+ // Create discovery pkt
+ LLDP discoveryPkt = new LLDP();
+ discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
+ .setOptionalTLVList(customList);
+
+ // Create ethernet pkt
+ byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue());
+ Ethernet ethPkt = new Ethernet();
+ ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac)
+ .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt);
+
+ try {
+ byte[] data = ethPkt.serialize();
+ return data;
+ } catch (PacketException e) {
+ LOG.error("Error creating LLDP packet",e);
+ }
+ return null;
+ }
+
+ private class LLDPSpeakerTask extends TimerTask {
+
+ @Override
+ public void run() {
+ for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap.keySet()) {
+ InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class);
+ ModelDrivenSwitch md = nodeMap.get(nodeInstanceId);
+ md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId));
+ }
+
+ }
+
+ }
+
+ private String colonize(String orig) {
+ return orig.replaceAll("(?<=..)(..)", ":$1");
+ }
+}
--- /dev/null
+package org.opendaylight.openflowplugin.openflow.md.lldp;
+
+import org.opendaylight.openflowplugin.openflow.md.queue.PopListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class LLDPSpeakerPopListener<T> implements PopListener<T> {
+
+
+ @Override
+ public void onPop(T processedMessage) {
+ if(processedMessage instanceof NodeConnectorUpdated) {
+ NodeConnectorUpdated connector = (NodeConnectorUpdated) processedMessage;
+ FlowCapableNodeConnectorUpdated flowConnector = connector.<FlowCapableNodeConnectorUpdated>getAugmentation(FlowCapableNodeConnectorUpdated.class);
+ if(flowConnector != null) {
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = (InstanceIdentifier<NodeConnector>) connector.getNodeConnectorRef().getValue();
+ NodeConnectorBuilder ncb = new NodeConnectorBuilder(connector);
+ FlowCapableNodeConnectorBuilder fcncb = new FlowCapableNodeConnectorBuilder(flowConnector);
+ ncb.addAugmentation(FlowCapableNodeConnector.class, fcncb.build());
+ PortState portState = flowConnector.getState();
+ PortConfig portConfig = flowConnector.getConfiguration();
+ if((portState ==null || !portState.equals(PortState.LinkDown)) && (portConfig == null || !portConfig.isPORTDOWN())) {
+ LLDPSpeaker.getInstance().addNodeConnector(nodeConnectorInstanceId,ncb.build());
+ } else {
+ LLDPSpeaker.getInstance().removeNodeConnector(nodeConnectorInstanceId,ncb.build());
+ }
+ }
+ }
+ }
+
+}