/*
* Copyright (c) 2014 Pacnet and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.applications.lldpspeaker;
import static org.opendaylight.controller.liblldp.LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC;
import static org.opendaylight.openflowplugin.applications.topology.lldp.utils.LLDPDiscoveryUtils.getValueForLLDPPacketIntegrityEnsuring;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.liblldp.EtherTypes;
import org.opendaylight.controller.liblldp.Ethernet;
import org.opendaylight.controller.liblldp.HexEncode;
import org.opendaylight.controller.liblldp.LLDP;
import org.opendaylight.controller.liblldp.LLDPTLV;
import org.opendaylight.controller.liblldp.PacketException;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility class for dealing with LLDP packets.
*/
public final class LLDPUtil {
private static final Logger LOG = LoggerFactory.getLogger(LLDPUtil.class);
private static final String OF_URI_PREFIX = "openflow:";
static byte[] buildLldpFrame(final NodeId nodeId,
final NodeConnectorId nodeConnectorId,
final MacAddress src,
final Long outPortNo,
final MacAddress destinationAddress) {
// Create discovery pkt
LLDP discoveryPkt = new LLDP();
// Create LLDP ChassisID TLV
BigInteger dataPathId = dataPathIdFromNodeId(nodeId);
byte[] cidValue = LLDPTLV.createChassisIDTLVValue(colonize(bigIntegerToPaddedHex(dataPathId)));
LLDPTLV chassisIdTlv = new LLDPTLV();
chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue())
.setLength((short) cidValue.length)
.setValue(cidValue);
discoveryPkt.setChassisId(chassisIdTlv);
// Create LLDP PortID TL
String hexString = Long.toHexString(outPortNo);
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());
discoveryPkt.setPortId(portIdTlv);
// Create LLDP TTL TLV
byte[] ttl = new byte[] { (byte) 0x13, (byte) 0x37 };
LLDPTLV ttlTlv = new LLDPTLV();
ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
discoveryPkt.setTtl(ttlTlv);
// 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);
discoveryPkt.setSystemNameId(systemNameTlv);
// Create LLDP Custom TLV
byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnectorId.getValue());
LLDPTLV customTlv = new LLDPTLV();
customTlv.setType(LLDPTLV.TLVType.Custom.getValue())
.setLength((short) customValue.length)
.setValue(customValue);
discoveryPkt.addCustomTLV(customTlv);
//Create LLDP CustomSec TLV
byte[] pureValue = new byte[1];
try {
pureValue = getValueForLLDPPacketIntegrityEnsuring(nodeConnectorId);
byte[] customSecValue = LLDPTLV.createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, pureValue);
LLDPTLV customSecTlv = new LLDPTLV();
customSecTlv.setType(LLDPTLV.TLVType.Custom.getValue())
.setLength((short)customSecValue.length)
.setValue(customSecValue);
discoveryPkt.addCustomTLV(customSecTlv);
} catch (NoSuchAlgorithmException e1) {
LOG.info("LLDP extra authenticator creation failed: {}", e1.getMessage());
LOG.debug("Reason why LLDP extra authenticator creation failed: ", e1);
}
// Create ethernet pkt
byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue());
Ethernet ethPkt = new Ethernet();
ethPkt.setSourceMACAddress(sourceMac)
.setEtherType(EtherTypes.LLDP.shortValue())
.setPayload(discoveryPkt);
if (destinationAddress == null) {
ethPkt.setDestinationMACAddress(LLDP.LLDPMulticastMac);
} else {
ethPkt.setDestinationMACAddress(HexEncode.bytesFromHexString(destinationAddress.getValue()));
}
try {
return ethPkt.serialize();
} catch (PacketException e) {
LOG.warn("Error creating LLDP packet: {}", e.getMessage());
LOG.debug("Error creating LLDP packet.. ", e);
}
return null;
}
private static String colonize(final String orig) {
return orig.replaceAll("(?<=..)(..)", ":$1");
}
private static BigInteger dataPathIdFromNodeId(final NodeId nodeId) {
String dpids = nodeId.getValue().replace(OF_URI_PREFIX, "");
return new BigInteger(dpids);
}
private static String bigIntegerToPaddedHex(final BigInteger dataPathId) {
return StringUtils.leftPad(dataPathId.toString(16), 16, "0");
}
static byte[] buildLldpFrame(final NodeId nodeId,
final NodeConnectorId nodeConnectorId,
final MacAddress srcMacAddress,
final Long outputPortNo) {
return buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress, outputPortNo, null);
}
}