/*
* Copyright (c) 2016 Pantheon Technologies s.r.o. 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.impl.protocol.serialization.messages;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
import org.opendaylight.openflowjava.protocol.api.util.OxmMatchConstants;
import org.opendaylight.openflowjava.protocol.impl.util.ActionConstants;
import org.opendaylight.openflowjava.protocol.impl.util.InstructionConstants;
import org.opendaylight.openflowjava.util.ByteBufUtils;
import org.opendaylight.openflowplugin.impl.protocol.serialization.AbstractSerializerTest;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.dst.action._case.SetTpDstActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.src.action._case.SetTpSrcActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessageBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModCommand;
public class FlowMessageSerializerTest extends AbstractSerializerTest {
private static final byte PADDING_IN_FLOW_MOD_MESSAGE = 2;
private static final Long XID = 42L;
private static final Short VERSION = EncodeConstants.OF13_VERSION_ID;
private static final Short TABLE_ID = 2;
private static final Boolean STRICT = true;
private static final Integer PRIORITY = 10;
private static final FlowModCommand COMMAND = FlowModCommand.OFPFCADD;
private static final Boolean BARRIER = false;
private static final Long BUFFER_ID = 12L;
private static final String CONTAINER_NAME = "openflow:1";
private static final FlowCookie COOKIE = new FlowCookie(BigInteger.ONE);
private static final FlowCookie COOKIE_MASK = new FlowCookie(BigInteger.ZERO);
private static final String FLOW_NAME = "flowflow";
private static final Integer HARD_TIMEOUT = 10;
private static final Integer IDLE_TIMEOUT = 5;
private static final Boolean INSTALL_HW = true;
private static final Long OUT_GROUP = 1L;
private static final BigInteger OUT_PORT = BigInteger.TEN;
private static final Boolean IS_CHECKOVERLAP = true;
private static final Boolean IS_NOBYTCOUNTS = false;
private static final Boolean IS_NOPKTCOUNTS = false;
private static final Boolean IS_RESETCOUNTS = true;
private static final Boolean IS_SENDFLOWREM = false;
private static final FlowModFlags FLAGS = new FlowModFlags(
IS_CHECKOVERLAP,
IS_NOBYTCOUNTS,
IS_NOPKTCOUNTS,
IS_RESETCOUNTS,
IS_SENDFLOWREM);
private static final Integer VLAN_ID = 1;
private static final Short IP_PROTOCOL = (short) 6; // TCP
private static final Integer TP_SRC_PORT = 22;
private static final Integer TP_DST_PORT = 23;
private static final Instructions INSTRUCTIONS = new InstructionsBuilder()
.setInstruction(Arrays.asList(
new InstructionBuilder()
.setOrder(0)
.setKey(new InstructionKey(0))
.setInstruction(new ApplyActionsCaseBuilder()
.setApplyActions(new ApplyActionsBuilder()
.setAction(Collections.singletonList(new ActionBuilder()
.setOrder(0)
.setKey(new ActionKey(0))
.setAction(new SetVlanIdActionCaseBuilder()
.setSetVlanIdAction(new SetVlanIdActionBuilder()
.setVlanId(new VlanId(VLAN_ID))
.build())
.build())
.build()))
.build())
.build())
.build(),
new InstructionBuilder()
.setOrder(2)
.setKey(new InstructionKey(2))
.setInstruction(new ApplyActionsCaseBuilder()
.setApplyActions(new ApplyActionsBuilder()
.setAction(Collections.singletonList(new ActionBuilder()
.setOrder(0)
.setKey(new ActionKey(0))
.setAction(new SetTpDstActionCaseBuilder()
.setSetTpDstAction(new SetTpDstActionBuilder()
.setIpProtocol(IP_PROTOCOL)
.setPort(new PortNumber(TP_DST_PORT))
.build())
.build())
.build()))
.build())
.build())
.build(),
new InstructionBuilder()
.setOrder(1)
.setKey(new InstructionKey(1))
.setInstruction(new ApplyActionsCaseBuilder()
.setApplyActions(new ApplyActionsBuilder()
.setAction(Collections.singletonList(new ActionBuilder()
.setOrder(0)
.setKey(new ActionKey(0))
.setAction(new SetTpSrcActionCaseBuilder()
.setSetTpSrcAction(new SetTpSrcActionBuilder()
.setIpProtocol(IP_PROTOCOL)
.setPort(new PortNumber(TP_SRC_PORT))
.build())
.build())
.build()))
.build())
.build())
.build()))
.build();
private static final Short IP_PROTOCOL_MATCH = (short) 17;
private static final Match MATCH = new MatchBuilder()
.setIpMatch(new IpMatchBuilder()
.setIpProtocol(IP_PROTOCOL_MATCH)
.build())
.build();
private static final FlowMessage MESSAGE = new FlowMessageBuilder()
.setXid(XID)
.setVersion(VERSION)
.setTableId(TABLE_ID)
.setStrict(STRICT)
.setPriority(PRIORITY)
.setCommand(COMMAND)
.setBarrier(BARRIER)
.setBufferId(BUFFER_ID)
.setContainerName(CONTAINER_NAME)
.setCookie(COOKIE)
.setCookieMask(COOKIE_MASK)
.setFlags(FLAGS)
.setFlowName(FLOW_NAME)
.setHardTimeout(HARD_TIMEOUT)
.setIdleTimeout(IDLE_TIMEOUT)
.setInstallHw(INSTALL_HW)
.setOutGroup(OUT_GROUP)
.setOutPort(OUT_PORT)
.setInstructions(INSTRUCTIONS)
.setMatch(MATCH)
.build();
private FlowMessageSerializer serializer;
@Override
protected void init() {
serializer = getRegistry().getSerializer(new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, FlowMessage.class));
}
@Test
public void testSerialize() throws Exception {
final ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
serializer.serialize(MESSAGE, out);
// Our message was split to 2 flows because it contained set_vlan_id action
testVlanFalse(out);
testVlanTrue(out);
assertEquals(out.readableBytes(), 0);
}
private void testVlanFalse(final ByteBuf out) {
// Header
assertEquals(out.readByte(), VERSION.shortValue());
assertEquals(out.readByte(), serializer.getMessageType());
assertEquals(out.readUnsignedShort(), 144);
assertEquals(out.readInt(), XID.intValue());
// Body
assertEquals(out.readLong(), COOKIE.getValue().longValue());
assertEquals(out.readLong(), COOKIE_MASK.getValue().longValue());
assertEquals(out.readUnsignedByte(), TABLE_ID.shortValue());
assertEquals(out.readUnsignedByte(), COMMAND.getIntValue());
assertEquals(out.readUnsignedShort(), IDLE_TIMEOUT.intValue());
assertEquals(out.readUnsignedShort(), HARD_TIMEOUT.intValue());
assertEquals(out.readUnsignedShort(), PRIORITY.intValue());
assertEquals(out.readUnsignedInt(), BUFFER_ID.longValue());
assertEquals(out.readUnsignedInt(), OUT_PORT.longValue());
assertEquals(out.readUnsignedInt(), OUT_GROUP.longValue());
assertEquals(out.readUnsignedShort(), ByteBufUtils.fillBitMask(0,
IS_SENDFLOWREM,
IS_CHECKOVERLAP,
IS_RESETCOUNTS,
IS_NOPKTCOUNTS,
IS_NOBYTCOUNTS));
out.skipBytes(PADDING_IN_FLOW_MOD_MESSAGE);
// Body match
int matchLength = 15;
assertEquals(out.readShort(), 1); // OXM match type
assertEquals(out.readUnsignedShort(), matchLength); // OXM match length
// Vlan false match
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.VLAN_VID << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), 0);
// Ip proto match
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.IP_PROTO << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
assertEquals(out.readUnsignedByte(), IP_PROTOCOL_MATCH.shortValue());
int paddingRemainder = matchLength % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction
int applyActionsLength = 32;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Push vlan action (was injected because we had setvlanid action)
assertEquals(out.readUnsignedShort(), ActionConstants.PUSH_VLAN_CODE);
assertEquals(out.readUnsignedShort(), ActionConstants.GENERAL_ACTION_LENGTH);
assertEquals(out.readUnsignedShort(), 0x8100);
out.skipBytes(ActionConstants.ETHERTYPE_ACTION_PADDING);
// Set vlan id action
int setVlanIdLength = 16;
int setVlanStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setVlanIdLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.VLAN_VID << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), VLAN_ID | (1 << 12));
paddingRemainder = (out.readerIndex() - setVlanStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction 2
int applyActionsLength2 = 24;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength2); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Set tp src action
int setTpSrcLength = 16;
int setTpSrcStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setTpSrcLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.UDP_SRC << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), TP_SRC_PORT.intValue());
paddingRemainder = (out.readerIndex() - setTpSrcStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction 3
int applyActionsLength3 = 24;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength3); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Set tp dst action
int setTpDstLength = 16;
int setTpDstStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setTpDstLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.UDP_DST << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), TP_DST_PORT.intValue());
paddingRemainder = (out.readerIndex() - setTpDstStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
}
private void testVlanTrue(final ByteBuf out) {
// VLAN_TRUE flow
// Header
assertEquals(out.readByte(), VERSION.shortValue());
assertEquals(out.readByte(), serializer.getMessageType());
assertEquals(out.readUnsignedShort(), 144);
assertEquals(out.readInt(), XID.intValue());
// Body
assertEquals(out.readLong(), COOKIE.getValue().longValue());
assertEquals(out.readLong(), COOKIE_MASK.getValue().longValue());
assertEquals(out.readUnsignedByte(), TABLE_ID.shortValue());
assertEquals(out.readUnsignedByte(), COMMAND.getIntValue());
assertEquals(out.readUnsignedShort(), IDLE_TIMEOUT.intValue());
assertEquals(out.readUnsignedShort(), HARD_TIMEOUT.intValue());
assertEquals(out.readUnsignedShort(), PRIORITY.intValue());
assertEquals(out.readUnsignedInt(), BUFFER_ID.longValue());
assertEquals(out.readUnsignedInt(), OUT_PORT.longValue());
assertEquals(out.readUnsignedInt(), OUT_GROUP.longValue());
assertEquals(out.readUnsignedShort(), ByteBufUtils.fillBitMask(0,
IS_SENDFLOWREM,
IS_CHECKOVERLAP,
IS_RESETCOUNTS,
IS_NOPKTCOUNTS,
IS_NOBYTCOUNTS));
out.skipBytes(PADDING_IN_FLOW_MOD_MESSAGE);
// Body match
int matchLength = 17;
assertEquals(out.readShort(), 1); // OXM match type
assertEquals(out.readUnsignedShort(), matchLength); // OXM match length
// Vlan false match
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.VLAN_VID << 1 | 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES * 2);
assertEquals(out.readUnsignedShort(), (1 << 12));
byte[] vlanMask = new byte[2];
out.readBytes(vlanMask);
assertArrayEquals(vlanMask, new byte[] { 16, 0 });
// Ip proto match
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.IP_PROTO << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
assertEquals(out.readUnsignedByte(), IP_PROTOCOL_MATCH.shortValue());
int paddingRemainder = matchLength % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction
int applyActionsLength = 24;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Set vlan id action
int setVlanIdLength = 16;
int setVlanStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setVlanIdLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.VLAN_VID << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), VLAN_ID | (1 << 12));
paddingRemainder = (out.readerIndex() - setVlanStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction 2
int applyActionsLength2 = 24;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength2); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Set tp src action
int setTpSrcLength = 16;
int setTpSrcStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setTpSrcLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.UDP_SRC << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), TP_SRC_PORT.intValue());
paddingRemainder = (out.readerIndex() - setTpSrcStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
// Apply actions instruction 3
int applyActionsLength3 = 24;
assertEquals(out.readUnsignedShort(), InstructionConstants.APPLY_ACTIONS_TYPE);
assertEquals(out.readUnsignedShort(), applyActionsLength3); // length of actions
out.skipBytes(InstructionConstants.PADDING_IN_ACTIONS_INSTRUCTION);
// Set tp dst action
int setTpDstLength = 16;
int setTpDstStartIndex = out.readerIndex();
assertEquals(out.readUnsignedShort(), ActionConstants.SET_FIELD_CODE);
assertEquals(out.readUnsignedShort(), setTpDstLength);
assertEquals(out.readUnsignedShort(), OxmMatchConstants.OPENFLOW_BASIC_CLASS);
assertEquals(out.readUnsignedByte(), OxmMatchConstants.UDP_DST << 1);
assertEquals(out.readUnsignedByte(), EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
assertEquals(out.readUnsignedShort(), TP_DST_PORT.intValue());
paddingRemainder = (out.readerIndex() - setTpDstStartIndex) % EncodeConstants.PADDING;
if (paddingRemainder != 0) {
out.skipBytes(EncodeConstants.PADDING - paddingRemainder);
}
}
}