use of net.floodlightcontroller.packet.LLDPTLV in project open-kilda by telstra.
the class PathVerificationService method handlePacketIn.
private IListener.Command handlePacketIn(IOFSwitch sw, OFPacketIn pkt, FloodlightContext context) {
long time = System.currentTimeMillis();
logger.debug("packet_in {} received from {}", pkt.getXid(), sw.getId());
VerificationPacket verificationPacket = null;
Ethernet eth = IFloodlightProviderService.bcStore.get(context, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
try {
verificationPacket = deserialize(eth);
} catch (Exception exception) {
logger.error("Deserialization failure: {}, exception: {}", exception.getMessage(), exception);
return Command.CONTINUE;
}
try {
OFPort inPort = pkt.getVersion().compareTo(OFVersion.OF_12) < 0 ? pkt.getInPort() : pkt.getMatch().get(MatchField.IN_PORT);
ByteBuffer portBB = ByteBuffer.wrap(verificationPacket.getPortId().getValue());
portBB.position(1);
OFPort remotePort = OFPort.of(portBB.getShort());
long timestamp = 0;
int pathOrdinal = 10;
IOFSwitch remoteSwitch = null;
boolean signed = false;
for (LLDPTLV lldptlv : verificationPacket.getOptionalTLVList()) {
if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 && lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 && lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x0) {
ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
remoteSwitch = switchService.getSwitch(DatapathId.of(dpidBB.getLong(4)));
} else if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 && lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 && lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x01) {
ByteBuffer tsBB = ByteBuffer.wrap(lldptlv.getValue());
/* skip OpenFlow OUI (4 bytes above) */
long swLatency = sw.getLatency().getValue();
timestamp = tsBB.getLong(4);
/* include the RX switch latency to "subtract" it */
timestamp = timestamp + swLatency;
} else if (lldptlv.getType() == 127 && lldptlv.getLength() == 8 && lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 && lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x02) {
ByteBuffer typeBB = ByteBuffer.wrap(lldptlv.getValue());
pathOrdinal = typeBB.getInt(4);
} else if (lldptlv.getType() == 127 && lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 && lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x03) {
ByteBuffer bb = ByteBuffer.wrap(lldptlv.getValue());
bb.position(4);
byte[] tokenArray = new byte[lldptlv.getLength() - 4];
bb.get(tokenArray, 0, tokenArray.length);
String token = new String(tokenArray);
try {
DecodedJWT jwt = verifier.verify(token);
signed = true;
} catch (JWTVerificationException e) {
logger.error("Packet verification failed", e);
return Command.STOP;
}
}
}
if (remoteSwitch == null) {
return Command.STOP;
}
if (!signed) {
logger.warn("verification packet without sign");
return Command.STOP;
}
U64 latency = (timestamp != 0 && (time - timestamp) > 0) ? U64.of(time - timestamp) : U64.ZERO;
logger.debug("link discovered: {}-{} ===( {} ms )===> {}-{}", remoteSwitch.getId(), remotePort, latency.getValue(), sw.getId(), inPort);
// this verification packet was sent from remote switch/port to received switch/port
// so the link direction is from remote switch/port to received switch/port
List<PathNode> nodes = Arrays.asList(new PathNode(remoteSwitch.getId().toString(), remotePort.getPortNumber(), 0, latency.getValue()), new PathNode(sw.getId().toString(), inPort.getPortNumber(), 1));
OFPortDesc port = sw.getPort(inPort);
long speed = Integer.MAX_VALUE;
if (port.getVersion().compareTo(OFVersion.OF_13) > 0) {
for (OFPortDescProp prop : port.getProperties()) {
if (prop.getType() == 0x0) {
speed = ((OFPortDescPropEthernet) prop).getCurrSpeed();
}
}
} else {
speed = port.getCurrSpeed();
}
IslInfoData path = new IslInfoData(latency.getValue(), nodes, speed, IslChangeType.DISCOVERED, getAvailableBandwidth(speed));
Message message = new InfoMessage(path, System.currentTimeMillis(), "system", null);
final String json = MAPPER.writeValueAsString(message);
logger.debug("about to send {}", json);
producer.send(new ProducerRecord<>(TOPIC, json));
logger.debug("packet_in processed for {}-{}", sw.getId(), inPort);
} catch (JsonProcessingException exception) {
logger.error("could not create json for path packet_in: {}", exception.getMessage(), exception);
} catch (UnsupportedOperationException exception) {
logger.error("could not parse packet_in message: {}", exception.getMessage(), exception);
} catch (Exception exception) {
logger.error("unknown error during packet_in message processing: {}", exception.getMessage(), exception);
throw exception;
}
return Command.STOP;
}
use of net.floodlightcontroller.packet.LLDPTLV in project open-kilda by telstra.
the class PathVerificationService method generateVerificationPacket.
public OFPacketOut generateVerificationPacket(IOFSwitch srcSw, OFPort port, IOFSwitch dstSw, boolean sign) {
try {
OFPortDesc ofPortDesc = srcSw.getPort(port);
byte[] chassisId = new byte[] { 4, 0, 0, 0, 0, 0, 0 };
byte[] portId = new byte[] { 2, 0, 0 };
byte[] ttlValue = new byte[] { 0, 0x78 };
byte[] dpidTLVValue = new byte[] { 0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127).setLength((short) dpidTLVValue.length).setValue(dpidTLVValue);
byte[] dpidArray = new byte[8];
ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
DatapathId dpid = srcSw.getId();
dpidBB.putLong(dpid.getLong());
System.arraycopy(dpidArray, 2, chassisId, 1, 6);
// Set the optionalTLV to the full SwitchID
System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
byte[] zeroMac = { 0, 0, 0, 0, 0, 0 };
byte[] srcMac = ofPortDesc.getHwAddr().getBytes();
if (Arrays.equals(srcMac, zeroMac)) {
int portVal = ofPortDesc.getPortNo().getPortNumber();
// this is a common scenario
logger.debug("Port {}/{} has zero hardware address: overwrite with lower 6 bytes of dpid", dpid.toString(), portVal);
System.arraycopy(dpidArray, 2, srcMac, 0, 6);
}
portBB.putShort(port.getShortPortNumber());
VerificationPacket vp = new VerificationPacket();
vp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId));
vp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId));
vp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue));
vp.getOptionalTLVList().add(dpidTLV);
// Add the controller identifier to the TLV value.
// vp.getOptionalTLVList().add(controllerTLV);
// Add T0 based on format from Floodlight LLDP
long time = System.currentTimeMillis();
long swLatency = srcSw.getLatency().getValue();
byte[] timestampTLVValue = ByteBuffer.allocate(Long.SIZE / 8 + 4).put((byte) 0x00).put((byte) 0x26).put((byte) 0xe1).put(// 0x01 is what we'll use to differentiate DPID (0x00) from time (0x01)
(byte) 0x01).putLong(time + swLatency).array();
LLDPTLV timestampTLV = new LLDPTLV().setType((byte) 127).setLength((short) timestampTLVValue.length).setValue(timestampTLVValue);
vp.getOptionalTLVList().add(timestampTLV);
// Type
byte[] typeTLVValue = ByteBuffer.allocate(Integer.SIZE / 8 + 4).put((byte) 0x00).put((byte) 0x26).put((byte) 0xe1).put((byte) 0x02).putInt(PathType.ISL.ordinal()).array();
LLDPTLV typeTLV = new LLDPTLV().setType((byte) 127).setLength((short) typeTLVValue.length).setValue(typeTLVValue);
vp.getOptionalTLVList().add(typeTLV);
if (sign) {
String token = JWT.create().withClaim("dpid", dpid.getLong()).withClaim("ts", time + swLatency).sign(algorithm);
byte[] tokenBytes = token.getBytes(Charset.forName("UTF-8"));
byte[] tokenTLVValue = ByteBuffer.allocate(4 + tokenBytes.length).put((byte) 0x00).put((byte) 0x26).put((byte) 0xe1).put((byte) 0x03).put(tokenBytes).array();
LLDPTLV tokenTLV = new LLDPTLV().setType((byte) 127).setLength((short) tokenTLVValue.length).setValue(tokenTLVValue);
vp.getOptionalTLVList().add(tokenTLV);
}
MacAddress dstMac = MacAddress.of(VERIFICATION_BCAST_PACKET_DST);
if (dstSw != null) {
OFPortDesc sw2OfPortDesc = dstSw.getPort(port);
dstMac = sw2OfPortDesc.getHwAddr();
}
Ethernet l2 = new Ethernet().setSourceMACAddress(MacAddress.of(srcMac)).setDestinationMACAddress(dstMac).setEtherType(EthType.IPv4);
IPv4Address dstIp = IPv4Address.of(VERIFICATION_PACKET_IP_DST);
if (dstSw != null) {
dstIp = IPv4Address.of(((InetSocketAddress) dstSw.getInetAddress()).getAddress().getAddress());
}
IPv4 l3 = new IPv4().setSourceAddress(IPv4Address.of(((InetSocketAddress) srcSw.getInetAddress()).getAddress().getAddress())).setDestinationAddress(dstIp).setTtl((byte) 64).setProtocol(IpProtocol.UDP);
UDP l4 = new UDP();
l4.setSourcePort(TransportPort.of(VERIFICATION_PACKET_UDP_PORT));
l4.setDestinationPort(TransportPort.of(VERIFICATION_PACKET_UDP_PORT));
l2.setPayload(l3);
l3.setPayload(l4);
l4.setPayload(vp);
byte[] data = l2.serialize();
OFPacketOut.Builder pob = srcSw.getOFFactory().buildPacketOut().setBufferId(OFBufferId.NO_BUFFER).setActions(getDiscoveryActions(srcSw, port)).setData(data);
OFMessageUtils.setInPort(pob, OFPort.CONTROLLER);
return pob.build();
} catch (Exception exception) {
logger.error("error generating verification packet: {}", exception);
}
return null;
}
use of net.floodlightcontroller.packet.LLDPTLV in project open-kilda by telstra.
the class VerificationPacket method serialize.
public byte[] serialize() {
int length = 2 + this.chassisId.getLength() + 2 + this.portId.getLength() + 2 + this.ttl.getLength() + 2;
for (LLDPTLV tlv : this.optionalTLVList) {
if (tlv != null)
length += 2 + tlv.getLength();
}
byte[] data = new byte[length];
ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.chassisId.serialize());
bb.put(this.portId.serialize());
bb.put(this.ttl.serialize());
for (LLDPTLV tlv : this.optionalTLVList) {
if (tlv != null)
bb.put(tlv.serialize());
}
// End of LLDPDU
bb.putShort((short) 0);
return data;
}
use of net.floodlightcontroller.packet.LLDPTLV in project open-kilda by telstra.
the class VerificationPacket method toString.
@Override
public String toString() {
String str = "";
str += "chassisId=" + ((this.chassisId == null) ? "null" : this.chassisId.toString());
str += " portId=" + ((this.portId == null) ? "null" : this.portId.toString());
str += " ttl=" + ((this.ttl == null) ? "null" : this.ttl.toString());
str += " etherType=" + ethType.toString();
str += " optionalTlvList=[";
if (this.optionalTLVList != null) {
for (LLDPTLV l : optionalTLVList) str += l.toString() + ", ";
}
str += "]";
return str;
}
use of net.floodlightcontroller.packet.LLDPTLV in project open-kilda by telstra.
the class VerificationPacket method deserialize.
public IPacket deserialize(byte[] data, int offset, int length) {
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
LLDPTLV tlv;
do {
tlv = new LLDPTLV().deserialize(bb);
// if there was a failure to deserialize stop processing TLVs
if (tlv == null)
break;
switch(tlv.getType()) {
case 0x0:
// can throw this one away, its just an end delimiter
break;
case 0x1:
this.chassisId = tlv;
break;
case 0x2:
this.portId = tlv;
break;
case 0x3:
this.ttl = tlv;
break;
default:
this.optionalTLVList.add(tlv);
break;
}
} while (tlv.getType() != 0 && bb.hasRemaining());
return this;
}
Aggregations