X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=extension%2Fopenflowjava-extension-nicira%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowjava%2Fnx%2Fcodec%2Faction%2FConntrackCodec.java;h=a44a4c865493fb8d56d075dc4c02e7a4099098c9;hb=dc2befb3188ea11dfd0d74d375a8d3acf3619d38;hp=ca615eff2a3c9c670bfa130442ed9d9decd589c5;hpb=a30aafce9f8b747c573ba3172837edc3e9328253;p=openflowplugin.git diff --git a/extension/openflowjava-extension-nicira/src/main/java/org/opendaylight/openflowjava/nx/codec/action/ConntrackCodec.java b/extension/openflowjava-extension-nicira/src/main/java/org/opendaylight/openflowjava/nx/codec/action/ConntrackCodec.java index ca615eff2a..a44a4c8654 100644 --- a/extension/openflowjava-extension-nicira/src/main/java/org/opendaylight/openflowjava/nx/codec/action/ConntrackCodec.java +++ b/extension/openflowjava-extension-nicira/src/main/java/org/opendaylight/openflowjava/nx/codec/action/ConntrackCodec.java @@ -1,63 +1,289 @@ /* - * Copyright (c) 2015 Hewlett-Packard Enterprise and others. All rights reserved. + * Copyright (c) 2015, 2017 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 static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint16; +import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint32; +import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint8; + import io.netty.buffer.ByteBuf; +import java.util.ArrayList; +import java.util.List; import org.opendaylight.openflowjava.nx.api.NiciraActionDeserializerKey; import org.opendaylight.openflowjava.nx.api.NiciraActionSerializerKey; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.ActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionConntrack; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionConntrackBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.aug.nx.action.ActionConntrack; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.aug.nx.action.ActionConntrackBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.NxActionConntrackBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMark; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMarkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNat; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNatBuilder; +import org.opendaylight.yangtools.yang.common.Uint16; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** + * Action codec for conntrack. + * * @author Aswin Suryanarayanan. */ - public class ConntrackCodec extends AbstractActionCodec { - public static final int LENGTH = 24; + private static final Logger LOG = LoggerFactory.getLogger(ConntrackCodec.class); + public static final int CT_LENGTH = 24; + public static final int NX_NAT_LENGTH = 16; + public static final int SHORT_LENGTH = 2; + public static final int INT_LENGTH = 4; + private static final int NXM_CT_MARK_FIELD_CODE = 107; + private static final int NXM_FIELD_CODE = 1; + private static final int SET_FIELD_LENGTH = 16; + private static final int SET_FIELD_CODE = 25; + public static final byte NXAST_CONNTRACK_SUBTYPE = 35; + public static final byte NXAST_NAT_SUBTYPE = 36; public static final NiciraActionSerializerKey SERIALIZER_KEY = - new NiciraActionSerializerKey(EncodeConstants.OF13_VERSION_ID, ActionConntrack.class); + new NiciraActionSerializerKey(EncodeConstants.OF_VERSION_1_3, ActionConntrack.class); public static final NiciraActionDeserializerKey DESERIALIZER_KEY = - new NiciraActionDeserializerKey(EncodeConstants.OF13_VERSION_ID, NXAST_CONNTRACK_SUBTYPE); + new NiciraActionDeserializerKey(EncodeConstants.OF_VERSION_1_3, NXAST_CONNTRACK_SUBTYPE); @Override public void serialize(final Action input, final ByteBuf outBuffer) { - ActionConntrack action = ((ActionConntrack) input.getActionChoice()); - serializeHeader(LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer); + LOG.trace("serialize :conntrack"); + ActionConntrack action = (ActionConntrack) input.getActionChoice(); + int length = getActionLength(action); + int pad = length % 8; + serializeHeader(length + pad + CT_LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer); outBuffer.writeShort(action.getNxActionConntrack().getFlags().shortValue()); outBuffer.writeInt(action.getNxActionConntrack().getZoneSrc().intValue()); outBuffer.writeShort(action.getNxActionConntrack().getConntrackZone().shortValue()); outBuffer.writeByte(action.getNxActionConntrack().getRecircTable().byteValue()); outBuffer.writeZero(5); + serializeCtAction(outBuffer,action); + } + + private static int getActionLength(final ActionConntrack action) { + int length = 0; + List ctActionsList = action.getNxActionConntrack().getCtActions(); + if (ctActionsList == null) { + return length; + } + for (CtActions ctActions : ctActionsList) { + if (ctActions.getOfpactActions() instanceof NxActionNatCase) { + NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions(); + NxActionNat natAction = nxActionNatCase.getNxActionNat(); + int natLength = getNatActionLength(natAction); + int pad = 8 - natLength % 8; + length += natLength + pad; + } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) { + length += SET_FIELD_LENGTH; + } + } + LOG.trace("ActionLength :conntrack: length {}",length); + return length; + } + + private static int getNatActionLength(final NxActionNat natAction) { + int natLength = NX_NAT_LENGTH; + short rangePresent = natAction.getRangePresent().shortValue(); + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) { + natLength += INT_LENGTH; + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) { + natLength += INT_LENGTH; + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) { + natLength += SHORT_LENGTH; + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) { + natLength += SHORT_LENGTH; + } + return natLength; + } + + private static void serializeCtAction(final ByteBuf outBuffer, final ActionConntrack action) { + List ctActionsList = action.getNxActionConntrack().getCtActions(); + if (ctActionsList != null) { + for (CtActions ctActions : ctActionsList) { + if (ctActions.getOfpactActions() instanceof NxActionNatCase) { + NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions(); + NxActionNat natAction = nxActionNatCase.getNxActionNat(); + int natLength = getNatActionLength(natAction); + int pad = 8 - natLength % 8; + serializeHeader(natLength + pad, NXAST_NAT_SUBTYPE, outBuffer); + outBuffer.writeZero(2); + outBuffer.writeShort(natAction.getFlags().shortValue()); + short rangePresent = natAction.getRangePresent().shortValue(); + outBuffer.writeShort(rangePresent); + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) { + writeIpv4Address(outBuffer, natAction.getIpAddressMin()); + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) { + writeIpv4Address(outBuffer, natAction.getIpAddressMax()); + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) { + outBuffer.writeShort(natAction.getPortMin().toJava()); + } + if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) { + outBuffer.writeShort(natAction.getPortMax().toJava()); + } + outBuffer.writeZero(pad); + } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) { + NxActionCtMarkCase nxActionCtMarkCase = (NxActionCtMarkCase)ctActions.getOfpactActions(); + NxActionCtMark ctMarkAction = nxActionCtMarkCase.getNxActionCtMark(); + + // structure: + // 00 19 - set field code + // 00 10 - set field length + // 00 01 d6 04 + // xx xx xx xx FIELD VALUE (4 bytes) + // xx xx xx xx PADDING (4 bytes) + + outBuffer.writeShort(SET_FIELD_CODE); + outBuffer.writeShort(SET_FIELD_LENGTH); + outBuffer.writeZero(1); + outBuffer.writeByte(NXM_FIELD_CODE); + outBuffer.writeByte(NXM_CT_MARK_FIELD_CODE << 1); + outBuffer.writeByte(INT_LENGTH); + outBuffer.writeInt(ctMarkAction.getCtMark().intValue()); + outBuffer.writeZero(INT_LENGTH); + + // TODO: ct_mark mask is not supported yet + } + } + } } @Override public Action deserialize(final ByteBuf message) { - ActionBuilder actionBuilder = deserializeHeader(message); - ActionConntrackBuilder actionConntrackBuilder = new ActionConntrackBuilder(); - - NxActionConntrackBuilder nxActionConntrackBuilder = new NxActionConntrackBuilder(); - nxActionConntrackBuilder.setFlags(message.readUnsignedShort()); - nxActionConntrackBuilder.setZoneSrc(message.readUnsignedInt()); - nxActionConntrackBuilder.setConntrackZone(message.readUnsignedShort()); - nxActionConntrackBuilder.setRecircTable(message.readUnsignedByte()); + final short length = deserializeCtHeader(message); + final var nxActionConntrackBuilder = new NxActionConntrackBuilder() + .setFlags(readUint16(message)) + .setZoneSrc(readUint32(message)) + .setConntrackZone(readUint16(message)) + .setRecircTable(readUint8(message)); message.skipBytes(5); - actionConntrackBuilder.setNxActionConntrack(nxActionConntrackBuilder.build()); - actionBuilder.setActionChoice(actionConntrackBuilder.build()); - return actionBuilder.build(); + if (length > CT_LENGTH) { + deserializeCtAction(message, nxActionConntrackBuilder, length - CT_LENGTH); + } + return new ActionBuilder() + .setExperimenterId(getExperimenterId()) + .setActionChoice(new ActionConntrackBuilder() + .setNxActionConntrack(nxActionConntrackBuilder.build()) + .build()) + .build(); + } + + private static void deserializeCtAction(final ByteBuf message, + final NxActionConntrackBuilder nxActionConntrackBuilder, final int ctActionsLength) { + List ctActionsList = new ArrayList<>(); + int processedCtActionsLength = ctActionsLength; + + while (processedCtActionsLength > 0) { + final int startReaderIndex = message.readerIndex(); + + if (EncodeConstants.EXPERIMENTER_VALUE == message.readUnsignedShort()) { + // NAT action + // reset indices + message.setIndex(startReaderIndex, message.writerIndex()); + + final int startIndex = message.readerIndex(); + final int length = deserializeCtHeader(message); + + processedCtActionsLength = processedCtActionsLength - length; + message.skipBytes(2); + final var nxActionNatBuilder = new NxActionNatBuilder() + .setFlags(readUint16(message)); + + final Uint16 rangePresent = readUint16(message); + nxActionNatBuilder.setRangePresent(rangePresent); + + final int rangeBits = rangePresent.toJava(); + if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue()) != 0) { + nxActionNatBuilder.setIpAddressMin(readIpv4Address(message)); + } + if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue()) != 0) { + nxActionNatBuilder.setIpAddressMax(readIpv4Address(message)); + } + if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue()) != 0) { + nxActionNatBuilder.setPortMin(readUint16(message)); + } + if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue()) != 0) { + nxActionNatBuilder.setPortMax(readUint16(message)); + } + + ctActionsList.add(new CtActionsBuilder() + .setOfpactActions(new NxActionNatCaseBuilder() + .setNxActionNat(nxActionNatBuilder.build()).build()) + .build()); + + // Padding + message.skipBytes(length - (message.readerIndex() - startIndex)); + } else { + // only other possible action here is currently ct_mark + // reset indices + message.setIndex(startReaderIndex, message.writerIndex()); + processedCtActionsLength = processedCtActionsLength - SET_FIELD_LENGTH; + + deserializeCtHeaderWithoutSubtype(message); + + ctActionsList.add(new CtActionsBuilder() + .setOfpactActions(new NxActionCtMarkCaseBuilder() + .setNxActionCtMark(new NxActionCtMarkBuilder() + .setCtMark(readUint32(message)) + .build()) + .build()) + .build()); + + // Padding + message.skipBytes(Integer.BYTES); + } + } + + nxActionConntrackBuilder.setCtActions(ctActionsList); + } + + private static IpAddress readIpv4Address(final ByteBuf message) { + return new IpAddress(IetfInetUtil.ipv4AddressFor(message.readInt())); + } + + private static void writeIpv4Address(final ByteBuf outBuffer, final IpAddress ipAddress) { + if (ipAddress != null) { + outBuffer.writeBytes(IetfInetUtil.ipv4AddressBytes(ipAddress.getIpv4Address())); + } + } + + private static short deserializeCtHeaderWithoutSubtype(final ByteBuf message) { + // size of experimenter type / size of set field code (in case of ct_mark) + message.skipBytes(Short.BYTES); + // size of length + short length = message.readShort(); + // vendor id / 00 01 d6 04 (in case of ct_mark) + message.skipBytes(Integer.BYTES); + return length; + } + + private static short deserializeCtHeader(final ByteBuf message) { + short length = deserializeCtHeaderWithoutSubtype(message); + // subtype + message.skipBytes(Short.BYTES); + return length; } }