2 * Copyright (c) 2015, 2017 Hewlett-Packard Enterprise and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.openflowjava.nx.codec.action;
10 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint16;
11 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint32;
12 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint8;
14 import io.netty.buffer.ByteBuf;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.opendaylight.openflowjava.nx.api.NiciraActionDeserializerKey;
18 import org.opendaylight.openflowjava.nx.api.NiciraActionSerializerKey;
19 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.ActionBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.aug.nx.action.ActionConntrack;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.aug.nx.action.ActionConntrackBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.NxActionConntrackBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActions;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActionsBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMark;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMarkBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNat;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNatBuilder;
38 import org.opendaylight.yangtools.yang.common.Uint16;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Action codec for conntrack.
45 * @author Aswin Suryanarayanan.
47 public class ConntrackCodec extends AbstractActionCodec {
48 private static final Logger LOG = LoggerFactory.getLogger(ConntrackCodec.class);
49 public static final int CT_LENGTH = 24;
50 public static final int NX_NAT_LENGTH = 16;
51 public static final int SHORT_LENGTH = 2;
52 public static final int INT_LENGTH = 4;
53 private static final int NXM_CT_MARK_FIELD_CODE = 107;
54 private static final int NXM_FIELD_CODE = 1;
55 private static final int SET_FIELD_LENGTH = 16;
56 private static final int SET_FIELD_CODE = 25;
58 public static final byte NXAST_CONNTRACK_SUBTYPE = 35;
59 public static final byte NXAST_NAT_SUBTYPE = 36;
60 public static final NiciraActionSerializerKey SERIALIZER_KEY =
61 new NiciraActionSerializerKey(EncodeConstants.OF_VERSION_1_3, ActionConntrack.class);
62 public static final NiciraActionDeserializerKey DESERIALIZER_KEY =
63 new NiciraActionDeserializerKey(EncodeConstants.OF_VERSION_1_3, NXAST_CONNTRACK_SUBTYPE);
66 public void serialize(final Action input, final ByteBuf outBuffer) {
67 LOG.trace("serialize :conntrack");
68 ActionConntrack action = (ActionConntrack) input.getActionChoice();
69 int length = getActionLength(action);
71 serializeHeader(length + pad + CT_LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer);
73 outBuffer.writeShort(action.getNxActionConntrack().getFlags().shortValue());
74 outBuffer.writeInt(action.getNxActionConntrack().getZoneSrc().intValue());
75 outBuffer.writeShort(action.getNxActionConntrack().getConntrackZone().shortValue());
76 outBuffer.writeByte(action.getNxActionConntrack().getRecircTable().byteValue());
77 outBuffer.writeZero(5);
78 serializeCtAction(outBuffer,action);
81 private static int getActionLength(final ActionConntrack action) {
83 List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
84 if (ctActionsList == null) {
87 for (CtActions ctActions : ctActionsList) {
88 if (ctActions.getOfpactActions() instanceof NxActionNatCase) {
89 NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions();
90 NxActionNat natAction = nxActionNatCase.getNxActionNat();
91 int natLength = getNatActionLength(natAction);
92 int pad = 8 - natLength % 8;
93 length += natLength + pad;
94 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
95 length += SET_FIELD_LENGTH;
98 LOG.trace("ActionLength :conntrack: length {}",length);
102 private static int getNatActionLength(final NxActionNat natAction) {
103 int natLength = NX_NAT_LENGTH;
104 short rangePresent = natAction.getRangePresent().shortValue();
105 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) {
106 natLength += INT_LENGTH;
108 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
109 natLength += INT_LENGTH;
111 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
112 natLength += SHORT_LENGTH;
114 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
115 natLength += SHORT_LENGTH;
120 private static void serializeCtAction(final ByteBuf outBuffer, final ActionConntrack action) {
121 List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
122 if (ctActionsList != null) {
123 for (CtActions ctActions : ctActionsList) {
124 if (ctActions.getOfpactActions() instanceof NxActionNatCase) {
125 NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions();
126 NxActionNat natAction = nxActionNatCase.getNxActionNat();
127 int natLength = getNatActionLength(natAction);
128 int pad = 8 - natLength % 8;
129 serializeHeader(natLength + pad, NXAST_NAT_SUBTYPE, outBuffer);
130 outBuffer.writeZero(2);
131 outBuffer.writeShort(natAction.getFlags().shortValue());
132 short rangePresent = natAction.getRangePresent().shortValue();
133 outBuffer.writeShort(rangePresent);
134 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) {
135 writeIpv4Address(outBuffer, natAction.getIpAddressMin());
137 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
138 writeIpv4Address(outBuffer, natAction.getIpAddressMax());
140 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
141 outBuffer.writeShort(natAction.getPortMin().toJava());
143 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
144 outBuffer.writeShort(natAction.getPortMax().toJava());
146 outBuffer.writeZero(pad);
147 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
148 NxActionCtMarkCase nxActionCtMarkCase = (NxActionCtMarkCase)ctActions.getOfpactActions();
149 NxActionCtMark ctMarkAction = nxActionCtMarkCase.getNxActionCtMark();
152 // 00 19 - set field code
153 // 00 10 - set field length
155 // xx xx xx xx FIELD VALUE (4 bytes)
156 // xx xx xx xx PADDING (4 bytes)
158 outBuffer.writeShort(SET_FIELD_CODE);
159 outBuffer.writeShort(SET_FIELD_LENGTH);
160 outBuffer.writeZero(1);
161 outBuffer.writeByte(NXM_FIELD_CODE);
162 outBuffer.writeByte(NXM_CT_MARK_FIELD_CODE << 1);
163 outBuffer.writeByte(INT_LENGTH);
164 outBuffer.writeInt(ctMarkAction.getCtMark().intValue());
165 outBuffer.writeZero(INT_LENGTH);
167 // TODO: ct_mark mask is not supported yet
174 public Action deserialize(final ByteBuf message) {
175 final short length = deserializeCtHeader(message);
176 final var nxActionConntrackBuilder = new NxActionConntrackBuilder()
177 .setFlags(readUint16(message))
178 .setZoneSrc(readUint32(message))
179 .setConntrackZone(readUint16(message))
180 .setRecircTable(readUint8(message));
181 message.skipBytes(5);
183 if (length > CT_LENGTH) {
184 deserializeCtAction(message, nxActionConntrackBuilder, length - CT_LENGTH);
186 return new ActionBuilder()
187 .setExperimenterId(getExperimenterId())
188 .setActionChoice(new ActionConntrackBuilder()
189 .setNxActionConntrack(nxActionConntrackBuilder.build())
194 private static void deserializeCtAction(final ByteBuf message,
195 final NxActionConntrackBuilder nxActionConntrackBuilder, final int ctActionsLength) {
196 List<CtActions> ctActionsList = new ArrayList<>();
197 int processedCtActionsLength = ctActionsLength;
199 while (processedCtActionsLength > 0) {
200 final int startReaderIndex = message.readerIndex();
202 if (EncodeConstants.EXPERIMENTER_VALUE == message.readUnsignedShort()) {
205 message.setIndex(startReaderIndex, message.writerIndex());
207 final int startIndex = message.readerIndex();
208 final int length = deserializeCtHeader(message);
210 processedCtActionsLength = processedCtActionsLength - length;
211 message.skipBytes(2);
212 final var nxActionNatBuilder = new NxActionNatBuilder()
213 .setFlags(readUint16(message));
215 final Uint16 rangePresent = readUint16(message);
216 nxActionNatBuilder.setRangePresent(rangePresent);
218 final int rangeBits = rangePresent.toJava();
219 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue()) != 0) {
220 nxActionNatBuilder.setIpAddressMin(readIpv4Address(message));
222 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue()) != 0) {
223 nxActionNatBuilder.setIpAddressMax(readIpv4Address(message));
225 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue()) != 0) {
226 nxActionNatBuilder.setPortMin(readUint16(message));
228 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue()) != 0) {
229 nxActionNatBuilder.setPortMax(readUint16(message));
232 ctActionsList.add(new CtActionsBuilder()
233 .setOfpactActions(new NxActionNatCaseBuilder()
234 .setNxActionNat(nxActionNatBuilder.build()).build())
238 message.skipBytes(length - (message.readerIndex() - startIndex));
240 // only other possible action here is currently ct_mark
242 message.setIndex(startReaderIndex, message.writerIndex());
243 processedCtActionsLength = processedCtActionsLength - SET_FIELD_LENGTH;
245 deserializeCtHeaderWithoutSubtype(message);
247 ctActionsList.add(new CtActionsBuilder()
248 .setOfpactActions(new NxActionCtMarkCaseBuilder()
249 .setNxActionCtMark(new NxActionCtMarkBuilder()
250 .setCtMark(readUint32(message))
256 message.skipBytes(Integer.BYTES);
260 nxActionConntrackBuilder.setCtActions(ctActionsList);
263 private static IpAddress readIpv4Address(final ByteBuf message) {
264 return new IpAddress(IetfInetUtil.INSTANCE.ipv4AddressFor(message.readInt()));
267 private static void writeIpv4Address(final ByteBuf outBuffer, final IpAddress ipAddress) {
268 if (ipAddress != null) {
269 outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv4AddressBytes(ipAddress.getIpv4Address()));
273 private static short deserializeCtHeaderWithoutSubtype(final ByteBuf message) {
274 // size of experimenter type / size of set field code (in case of ct_mark)
275 message.skipBytes(Short.BYTES);
277 short length = message.readShort();
278 // vendor id / 00 01 d6 04 (in case of ct_mark)
279 message.skipBytes(Integer.BYTES);
283 private static short deserializeCtHeader(final ByteBuf message) {
284 short length = deserializeCtHeaderWithoutSubtype(message);
286 message.skipBytes(Short.BYTES);