/* * Copyright (c) 2016 Hewlett-Packard Enterprise 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.openflowjava.nx.codec.action; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import io.netty.buffer.ByteBuf; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionLearn; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromFieldCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromFieldCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromValueCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromValueCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyFieldIntoFieldCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyFieldIntoFieldCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyValueIntoFieldCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyValueIntoFieldCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModOutputToPortCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModOutputToPortCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.field._case.FlowModAddMatchFromField; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.field._case.FlowModAddMatchFromFieldBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.value._case.FlowModAddMatchFromValue; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.value._case.FlowModAddMatchFromValueBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.field.into.field._case.FlowModCopyFieldIntoField; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.field.into.field._case.FlowModCopyFieldIntoFieldBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.value.into.field._case.FlowModCopyValueIntoField; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.value.into.field._case.FlowModCopyValueIntoFieldBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.output.to.port._case.FlowModOutputToPort; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.output.to.port._case.FlowModOutputToPortBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.NxActionLearnBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.nx.action.learn.FlowMods; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.nx.action.learn.FlowModsBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LearnCodecUtil { private static final Logger logger = LoggerFactory.getLogger(LearnCodecUtil.class); public static final int HEADER_LENGTH = 32; private static final short SRC_MASK = 0x2000; private static final short DST_MASK = 0x1800; private static final short NUM_BITS_MASK = 0x07FF; private static final int SRC_POS = 13; private static final int DST_POS = 11; private static final int FROM_FIELD_LENGTH = 14; private static final int FROM_VALUE_LENGTH = 10; private static final int TO_PORT_LENGTH = 8; private static final int EMPTY_FLOW_MOD_LENGTH = 2; private static short length; static short deserializeHeader(ByteBuf message) { // size of experimenter type message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES); // size of length short length = message.readShort(); // vendor id message.skipBytes(EncodeConstants.SIZE_OF_INT_IN_BYTES); // subtype message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES); return length; } /* * SERIALIZATION */ static void serializeLearnHeader(final ByteBuf outBuffer, ActionLearn action) { outBuffer.writeShort(action.getNxActionLearn().getIdleTimeout().shortValue()); outBuffer.writeShort(action.getNxActionLearn().getHardTimeout().shortValue()); outBuffer.writeShort(action.getNxActionLearn().getPriority().shortValue()); outBuffer.writeLong(action.getNxActionLearn().getCookie().longValue()); outBuffer.writeShort(action.getNxActionLearn().getFlags().shortValue()); outBuffer.writeByte(action.getNxActionLearn().getTableId().byteValue()); outBuffer.writeZero(1); outBuffer.writeShort(action.getNxActionLearn().getFinIdleTimeout().shortValue()); outBuffer.writeShort(action.getNxActionLearn().getFinHardTimeout().shortValue()); } static void serializeFlowMods(final ByteBuf outBuffer, ActionLearn action) { if(action.getNxActionLearn().getFlowMods() != null){ for(FlowMods flowMod : action.getNxActionLearn().getFlowMods()){ if(flowMod.getFlowModSpec() instanceof FlowModAddMatchFromFieldCase){ FlowModAddMatchFromField flowModSpecFromField = ((FlowModAddMatchFromFieldCase)flowMod.getFlowModSpec()).getFlowModAddMatchFromField(); toFlowModSpecHeader(flowModSpecFromField, outBuffer); outBuffer.writeInt(flowModSpecFromField.getSrcField().intValue()); outBuffer.writeShort(flowModSpecFromField.getSrcOfs().shortValue()); outBuffer.writeInt(flowModSpecFromField.getDstField().intValue()); outBuffer.writeShort(flowModSpecFromField.getDstOfs().shortValue()); }else if( flowMod.getFlowModSpec() instanceof FlowModAddMatchFromValueCase){ FlowModAddMatchFromValue flowModSpec = ((FlowModAddMatchFromValueCase)flowMod.getFlowModSpec()).getFlowModAddMatchFromValue(); toFlowModSpecHeader(flowModSpec, outBuffer); outBuffer.writeShort(flowModSpec.getValue().shortValue()); outBuffer.writeInt(flowModSpec.getSrcField().intValue()); outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue()); }else if( flowMod.getFlowModSpec() instanceof FlowModCopyFieldIntoFieldCase){ FlowModCopyFieldIntoField flowModSpec = ((FlowModCopyFieldIntoFieldCase)flowMod.getFlowModSpec()).getFlowModCopyFieldIntoField(); toFlowModSpecHeader(flowModSpec, outBuffer); outBuffer.writeInt(flowModSpec.getSrcField().intValue()); outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue()); outBuffer.writeInt(flowModSpec.getDstField().intValue()); outBuffer.writeShort(flowModSpec.getDstOfs().shortValue()); }else if( flowMod.getFlowModSpec() instanceof FlowModCopyValueIntoFieldCase){ FlowModCopyValueIntoField flowModSpec = ((FlowModCopyValueIntoFieldCase)flowMod.getFlowModSpec()).getFlowModCopyValueIntoField(); toFlowModSpecHeader(flowModSpec, outBuffer); outBuffer.writeShort(flowModSpec.getValue().shortValue()); outBuffer.writeInt(flowModSpec.getDstField().intValue()); outBuffer.writeShort(flowModSpec.getDstOfs().shortValue()); }else if( flowMod.getFlowModSpec() instanceof FlowModOutputToPortCase){ FlowModOutputToPort flowModSpec = ((FlowModOutputToPortCase)flowMod.getFlowModSpec()).getFlowModOutputToPort(); toFlowModSpecHeader(flowModSpec, outBuffer); outBuffer.writeInt(flowModSpec.getSrcField().intValue()); outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue()); } } } } private static void toFlowModSpecHeader(FlowModOutputToPort flowModSpec, ByteBuf outBuffer) { serializeFlowModSpecHeader(0,2,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer); } private static void toFlowModSpecHeader(FlowModCopyValueIntoField flowModSpec, ByteBuf outBuffer) { serializeFlowModSpecHeader(1,1,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer); } private static void toFlowModSpecHeader(FlowModCopyFieldIntoField flowModSpec, ByteBuf outBuffer) { serializeFlowModSpecHeader(0,1,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer); } private static void toFlowModSpecHeader(FlowModAddMatchFromValue flowModSpec, ByteBuf outBuffer) { serializeFlowModSpecHeader(1,0,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer); } private static void toFlowModSpecHeader(FlowModAddMatchFromField flowModSpec, ByteBuf outBuffer) { serializeFlowModSpecHeader(0,0,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer); } private static void serializeFlowModSpecHeader(int src, int dst, short bitNum, ByteBuf outBuffer) { short s = 0; s |= (src << SRC_POS); s |= (dst << DST_POS); s |= bitNum; outBuffer.writeShort(s); } static int calcLength(ActionLearn action) { int length = HEADER_LENGTH; if(action.getNxActionLearn().getFlowMods() == null){ return length; } for(FlowMods flowMod : action.getNxActionLearn().getFlowMods()){ if(flowMod.getFlowModSpec() instanceof FlowModAddMatchFromFieldCase){ length += FROM_FIELD_LENGTH; } else if( flowMod.getFlowModSpec() instanceof FlowModAddMatchFromValueCase){ length += FROM_VALUE_LENGTH; } else if( flowMod.getFlowModSpec() instanceof FlowModCopyFieldIntoFieldCase){ length += FROM_FIELD_LENGTH; } else if( flowMod.getFlowModSpec() instanceof FlowModCopyValueIntoFieldCase){ length += FROM_VALUE_LENGTH; } else if( flowMod.getFlowModSpec() instanceof FlowModOutputToPortCase){ length += TO_PORT_LENGTH; } } return length; } /* * DESERIALIZATION */ static void deserializeLearnHeader(final ByteBuf message, NxActionLearnBuilder nxActionLearnBuilder) { nxActionLearnBuilder.setIdleTimeout(message.readUnsignedShort()); nxActionLearnBuilder.setHardTimeout(message.readUnsignedShort()); nxActionLearnBuilder.setPriority(message.readUnsignedShort()); nxActionLearnBuilder.setCookie(BigInteger.valueOf(message.readLong())); nxActionLearnBuilder.setFlags(message.readUnsignedShort()); nxActionLearnBuilder.setTableId(message.readUnsignedByte()); message.skipBytes(1); nxActionLearnBuilder.setFinIdleTimeout(message.readUnsignedShort()); nxActionLearnBuilder.setFinHardTimeout(message.readUnsignedShort()); } static synchronized void buildFlowModSpecs(NxActionLearnBuilder nxActionLearnBuilder, ByteBuf message, short length) { LearnCodecUtil.length = length; List<FlowMods> flowModeList = new ArrayList<FlowMods>(); while(LearnCodecUtil.length > 0){ FlowMods flowMod = readFlowMod(message); if(flowMod != null){ flowModeList.add(flowMod); }else{ logger.trace("skipping padding bytes"); } } if(LearnCodecUtil.length != 0){ logger.error("Learn Codec read " + Math.abs(length) + " bytes more than needed from stream. Packet might be corrupted"); } nxActionLearnBuilder.setFlowMods(flowModeList); } private static FlowMods readFlowMod(ByteBuf message) { short header = message.readShort(); length -= EncodeConstants.SIZE_OF_SHORT_IN_BYTES; if(header == 0){ return null; } short src = (short) ((header & SRC_MASK) >> SRC_POS); short dst = (short) ((header & DST_MASK) >> DST_POS); short numBits = (short) (header & NUM_BITS_MASK); if(src == 0 && dst == 0 && numBits != 0){ return readFlowModAddMatchFromField(message, numBits); } else if(src == 0 && dst == 0){ message.skipBytes(EMPTY_FLOW_MOD_LENGTH); length -= EMPTY_FLOW_MOD_LENGTH; } else if(src == 1 && dst == 0){ return readFlowModAddMatchFromValue(message, numBits); } else if(src == 0 && dst == 1){ return readFlowModCopyFromField(message, numBits); } else if(src == 1 && dst == 1){ return readFlowModCopyFromValue(message, numBits); } else if(src == 0 && dst == 2){ return readFlowToPort(message, numBits); } return null; } private static FlowMods readFlowModAddMatchFromField(ByteBuf message, short numBits) { FlowModAddMatchFromFieldBuilder builder = new FlowModAddMatchFromFieldBuilder(); builder.setSrcField((long) message.readInt()); builder.setSrcOfs((int) message.readShort()); builder.setDstField((long) message.readInt()); builder.setDstOfs((int) message.readShort()); builder.setFlowModNumBits((int) numBits); length -= FROM_FIELD_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES; FlowModsBuilder flowModsBuilder = new FlowModsBuilder(); FlowModAddMatchFromFieldCaseBuilder caseBuilder = new FlowModAddMatchFromFieldCaseBuilder(); caseBuilder.setFlowModAddMatchFromField(builder.build()); flowModsBuilder.setFlowModSpec(caseBuilder.build()); return flowModsBuilder.build(); } private static FlowMods readFlowModAddMatchFromValue(ByteBuf message, short numBits) { FlowModAddMatchFromValueBuilder builder = new FlowModAddMatchFromValueBuilder(); builder.setValue((int) message.readUnsignedShort()); builder.setSrcField((long) message.readInt()); builder.setSrcOfs((int) message.readShort()); builder.setFlowModNumBits((int) numBits); length -= FROM_VALUE_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES; FlowModsBuilder flowModsBuilder = new FlowModsBuilder(); FlowModAddMatchFromValueCaseBuilder caseBuilder = new FlowModAddMatchFromValueCaseBuilder(); caseBuilder.setFlowModAddMatchFromValue(builder.build()); flowModsBuilder.setFlowModSpec(caseBuilder.build()); return flowModsBuilder.build(); } private static FlowMods readFlowModCopyFromField(ByteBuf message, short numBits) { FlowModCopyFieldIntoFieldBuilder builder = new FlowModCopyFieldIntoFieldBuilder(); builder.setSrcField((long) message.readInt()); builder.setSrcOfs((int) message.readShort()); builder.setDstField((long) message.readInt()); builder.setDstOfs((int) message.readShort()); builder.setFlowModNumBits((int) numBits); length -= FROM_FIELD_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES; FlowModsBuilder flowModsBuilder = new FlowModsBuilder(); FlowModCopyFieldIntoFieldCaseBuilder caseBuilder = new FlowModCopyFieldIntoFieldCaseBuilder(); caseBuilder.setFlowModCopyFieldIntoField(builder.build()); flowModsBuilder.setFlowModSpec(caseBuilder.build()); return flowModsBuilder.build(); } private static FlowMods readFlowModCopyFromValue(ByteBuf message, short numBits) { FlowModCopyValueIntoFieldBuilder builder = new FlowModCopyValueIntoFieldBuilder(); builder.setValue((int) message.readUnsignedShort()); builder.setDstField((long) message.readInt()); builder.setDstOfs((int) message.readShort()); builder.setFlowModNumBits((int) numBits); length -= FROM_VALUE_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES; FlowModsBuilder flowModsBuilder = new FlowModsBuilder(); FlowModCopyValueIntoFieldCaseBuilder caseBuilder = new FlowModCopyValueIntoFieldCaseBuilder(); caseBuilder.setFlowModCopyValueIntoField(builder.build()); flowModsBuilder.setFlowModSpec(caseBuilder.build()); return flowModsBuilder.build(); } private static FlowMods readFlowToPort(ByteBuf message, short numBits) { FlowModOutputToPortBuilder builder = new FlowModOutputToPortBuilder(); builder.setSrcField((long) message.readInt()); builder.setSrcOfs((int) message.readShort()); builder.setFlowModNumBits((int) numBits); length -= TO_PORT_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES; FlowModsBuilder flowModsBuilder = new FlowModsBuilder(); FlowModOutputToPortCaseBuilder caseBuilder = new FlowModOutputToPortCaseBuilder(); caseBuilder.setFlowModOutputToPort(builder.build()); flowModsBuilder.setFlowModSpec(caseBuilder.build()); return flowModsBuilder.build(); } }