Ask is moving to Stack Overflow and Serverfault.com! Please use the "opendaylight" tag on either of these sites. This site is now in Read-Only mode

0

Extracting MAC address of packets

asked 2017-09-11 14:58:30 -0800

Hello,

Are there utilities available in ODL for packet manpulation. I'd like to extract various things from the data packet. Are there any utility classes available for that?

I've seen some code in the openflow plugin example that uses offsets into the data packet to get the MAC etc. but I'd prefer to use a standard utility package for this if available.

Thank you

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
0

answered 2017-09-13 08:45:01 -0800

Posting here in case somebody finds it useful.

https://stackoverflow.com/questions/4...

See answer from Karthik Prasad.

edit flag offensive delete publish link more
0

answered 2017-09-15 05:06:35 -0800

VincentJahjah gravatar image

updated 2017-09-15 05:09:28 -0800

I did exactly that in my project. I wanted a ping-like packet to calculate latencies across the network, but since one can generally only send packets from the controller, I had to make a slightly different kind of ping. The ping protocol packet was contained in an ethernet frame + 8 bytes containing the timestamp at which it was sent.

Here's the code I used:

public class ... implements EthernetPacketListener {
...
public static final MacAddress CONTROLLER_REFERENCE = new MacAddress("ff:ff:ff:ff:ff:fd");
...
@Override
public void onEthernetPacketReceived(EthernetPacketReceived packetReceived) {
        long timeReceivedInMs = System.currentTimeMillis();

        if (packetReceived == null || packetReceived.getPacketChain() == null) {
            return;
        }

        RawPacket rawPacket = null;
        EthernetPacket ethernetPacket = null;
        for (PacketChain packetChain : packetReceived.getPacketChain()) {
            if (packetChain.getPacket() instanceof RawPacket) {
                rawPacket = (RawPacket) packetChain.getPacket();
            } else if (packetChain.getPacket() instanceof EthernetPacket) {
                ethernetPacket = (EthernetPacket) packetChain.getPacket();
            }
        }
        if (rawPacket == null || ethernetPacket == null) {
            return;
        }
        if (ethernetPacket.getEthertype() != null) {
            return;
        }

        byte[] payload = packetReceived.getPayload();
        int offset = 6 + 6 + 2; // source mac + dest mac + ethernet type
        // timestamp is contained in 8 bytes
        long timeSentInMs = Utils.bytesToLong(new byte[]{payload[offset],   payload[offset+1], 
                                                         payload[offset+2], payload[offset+3],
                                                         payload[offset+4], payload[offset+5],
                                                         payload[offset+6], payload[offset+7]});

        if (ethernetPacket.getSourceMac().equals(CONTROLLER_REFERENCE)) {
            // and so on
        }

I'm using classes from ODL (either taken from l2switch or openflowplugin, I don't remember). You might find the following code of mine useful as well (if you want to send packets with specific mac addresses):

public static final short SPECIAL_PING_ETHERTYPE = 0x07c4;
...
private byte[] makePayLoad(MacAddress source, MacAddress destination) {
    Ethernet ethPkt = new Ethernet();

    ethPkt.setSourceMACAddress(Utils.macAddressToBytes(source))
          .setDestinationMACAddress(Utils.macAddressToBytes(destination))
          .setEtherType(SPECIAL_PING_ETHERTYPE)
          .setRawPayload(Utils.getNBytesFromLong(System.currentTimeMillis(), 8));

    try {
        return ethPkt.serialize();
    } catch (PacketException e) {
        LOG.warn("Error creating Ethernet frame {}", e.getMessage());
        return new byte[]{};
    }
}

This will require the following:

<dependency>
        <groupId>org.opendaylight.controller</groupId>
        <artifactId>liblldp</artifactId>
        <version>${lldp.version}</version>
</dependency>

Here are my utility functions (the first one is probably overzealous):

public static byte[] getNBytesFromLong(Long value, int byteNb) {
    if (byteNb < Long.BYTES && value > Math.pow(256, byteNb) - 1) {
        return null;
    }
    byte[] result = new byte[byteNb];
    for (int i = 0; i < byteNb && i < Long.BYTES; i++) {
        result[byteNb-1-i] = (byte) (0xFF & value%256);
        value /= 256;
    }
    for (int i = Long.BYTES; i < byteNb; i++) {
        result[byteNb-1-i] = (byte) (0x00 & 255);
    }
    return result;
}

public static byte[] macAddressToBytes(MacAddress macAddress) {
    ByteBuffer buffer = ByteBuffer.allocate(6);
    String[] strs = macAddress.getValue().split(":");
    // We need to do the fancy bit-mask because bytes are signed, so 255 is too large.
    // Bit masks are blind to sign, so it works.
    byte[] bytes = new byte[]{(byte) (0xFF & Integer.parseInt(strs[0], 16)),
                              (byte) (0xFF & Integer.parseInt(strs[1], 16)),
                              (byte) (0xFF & Integer.parseInt(strs[2], 16)),
                              (byte) (0xFF & Integer.parseInt(strs[3], 16)),
                              (byte) (0xFF & Integer.parseInt(strs[4], 16)),
                              (byte) (0xFF & Integer.parseInt(strs[5], 16))};
    buffer.put(bytes);

    return buffer.array();
}

Note: I encoded my ethertype wrong, I think, because it's null every time (as you can see from my code). I did something wrong there, take notice.

edit flag offensive delete publish link more
Login/Signup to Answer

Question Tools

Follow
1 follower

Stats

Asked: 2017-09-11 14:58:30 -0800

Seen: 25 times

Last updated: Sep 15