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

Revision history [back]

click to hide/show revision 1
initial version

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;
        }

        processSpecialPingPacket(ethernetPacket, rawPacket, packetReceived.getPayload(), timeReceivedInMs);
    }

    private void processSpecialPingPacket(EthernetPacket ethernetPacket, RawPacket rawPacket, byte[] payload, long timeReceivedInMs) {
        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
        }

As you can see, I'm using code that's already in ODL. The classes are either taken from l2switch or openflowplugin, I don't remember. You might also 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.

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;
        }

        processSpecialPingPacket(ethernetPacket, rawPacket, packetReceived.getPayload(), timeReceivedInMs);
    }

    private void processSpecialPingPacket(EthernetPacket ethernetPacket, RawPacket rawPacket, byte[] payload, long timeReceivedInMs) {
payload = packetReceived.getPayload();
        int offset = 6 + 6 + 2; // source mac + dest mac + ethernet type
        // (timestamp timestamp is contained in 8 bytes)
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
        }

As you can see, I'm using code that's already in ODL. The classes are either taken from l2switch or openflowplugin, I don't remember. You might also 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.

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
        }

As you can see, I'm using code that's already in ODL. The classes are either from ODL (either taken from l2switch or openflowplugin, I don't remember. remember). You might also 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.