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 com.google.common.net.InetAddresses;
11 import io.netty.buffer.ByteBuf;
12 import java.net.InetAddress;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.openflowjava.nx.api.NiciraActionDeserializerKey;
16 import org.opendaylight.openflowjava.nx.api.NiciraActionSerializerKey;
17 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.ActionBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionConntrack;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionConntrackBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.NxActionConntrackBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActions;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.conntrack.grouping.nx.action.conntrack.CtActionsBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionCtMarkCaseBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.NxActionNatCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMark;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.ct.mark._case.NxActionCtMarkBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNat;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofpact.actions.ofpact.actions.nx.action.nat._case.NxActionNatBuilder;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * Action codec for conntrack.
42 * @author Aswin Suryanarayanan.
44 public class ConntrackCodec extends AbstractActionCodec {
45 private static final Logger LOG = LoggerFactory.getLogger(ConntrackCodec.class);
46 public static final int CT_LENGTH = 24;
47 public static final int NX_NAT_LENGTH = 16;
48 public static final int SHORT_LENGTH = 2;
49 public static final int INT_LENGTH = 4;
50 private static final int NXM_CT_MARK_FIELD_CODE = 107;
51 private static final int NXM_FIELD_CODE = 1;
52 private static final int SET_FIELD_LENGTH = 16;
53 private static final int SET_FIELD_CODE = 25;
55 public static final byte NXAST_CONNTRACK_SUBTYPE = 35;
56 public static final byte NXAST_NAT_SUBTYPE = 36;
57 public static final NiciraActionSerializerKey SERIALIZER_KEY =
58 new NiciraActionSerializerKey(EncodeConstants.OF13_VERSION_ID, ActionConntrack.class);
59 public static final NiciraActionDeserializerKey DESERIALIZER_KEY =
60 new NiciraActionDeserializerKey(EncodeConstants.OF13_VERSION_ID, NXAST_CONNTRACK_SUBTYPE);
63 public void serialize(final Action input, final ByteBuf outBuffer) {
64 LOG.trace("serialize :conntrack");
65 ActionConntrack action = (ActionConntrack) input.getActionChoice();
66 int length = getActionLength(action);
68 serializeHeader(length + pad + CT_LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer);
70 outBuffer.writeShort(action.getNxActionConntrack().getFlags().shortValue());
71 outBuffer.writeInt(action.getNxActionConntrack().getZoneSrc().intValue());
72 outBuffer.writeShort(action.getNxActionConntrack().getConntrackZone().shortValue());
73 outBuffer.writeByte(action.getNxActionConntrack().getRecircTable().byteValue());
74 outBuffer.writeZero(5);
75 serializeCtAction(outBuffer,action);
78 private static int getActionLength(final ActionConntrack action) {
80 List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
81 if (ctActionsList == null) {
84 for (CtActions ctActions : ctActionsList) {
85 if (ctActions.getOfpactActions() instanceof NxActionNatCase) {
86 NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions();
87 NxActionNat natAction = nxActionNatCase.getNxActionNat();
88 int natLength = getNatActionLength(natAction);
89 int pad = 8 - natLength % 8;
90 length += natLength + pad;
91 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
92 length += SET_FIELD_LENGTH;
95 LOG.trace("ActionLength :conntrack: length {}",length);
99 private static int getNatActionLength(final NxActionNat natAction) {
100 int natLength = NX_NAT_LENGTH;
101 short rangePresent = natAction.getRangePresent().shortValue();
102 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) {
103 natLength += INT_LENGTH;
105 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
106 natLength += INT_LENGTH;
108 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
109 natLength += SHORT_LENGTH;
111 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
112 natLength += SHORT_LENGTH;
117 private static void serializeCtAction(final ByteBuf outBuffer, final ActionConntrack action) {
118 List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
119 if (ctActionsList != null) {
120 for (CtActions ctActions : ctActionsList) {
121 if (ctActions.getOfpactActions() instanceof NxActionNatCase) {
122 NxActionNatCase nxActionNatCase = (NxActionNatCase)ctActions.getOfpactActions();
123 NxActionNat natAction = nxActionNatCase.getNxActionNat();
124 int natLength = getNatActionLength(natAction);
125 int pad = 8 - natLength % 8;
126 serializeHeader(natLength + pad, NXAST_NAT_SUBTYPE, outBuffer);
127 outBuffer.writeZero(2);
128 outBuffer.writeShort(natAction.getFlags().shortValue());
129 short rangePresent = natAction.getRangePresent().shortValue();
130 outBuffer.writeShort(rangePresent);
131 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) {
132 if (null != natAction.getIpAddressMin()) {
133 outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv4AddressBytes(natAction
134 .getIpAddressMin().getIpv4Address()));
137 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
138 if (null != natAction.getIpAddressMax()) {
139 outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv4AddressBytes(natAction
140 .getIpAddressMax().getIpv4Address()));
143 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
144 outBuffer.writeShort(natAction.getPortMin().toJava());
146 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
147 outBuffer.writeShort(natAction.getPortMax().toJava());
149 outBuffer.writeZero(pad);
150 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
151 NxActionCtMarkCase nxActionCtMarkCase = (NxActionCtMarkCase)ctActions.getOfpactActions();
152 NxActionCtMark ctMarkAction = nxActionCtMarkCase.getNxActionCtMark();
155 // 00 19 - set field code
156 // 00 10 - set field length
158 // xx xx xx xx FIELD VALUE (4 bytes)
159 // xx xx xx xx PADDING (4 bytes)
161 outBuffer.writeShort(SET_FIELD_CODE);
162 outBuffer.writeShort(SET_FIELD_LENGTH);
163 outBuffer.writeZero(1);
164 outBuffer.writeByte(NXM_FIELD_CODE);
165 outBuffer.writeByte(NXM_CT_MARK_FIELD_CODE << 1);
166 outBuffer.writeByte(INT_LENGTH);
167 outBuffer.writeInt(ctMarkAction.getCtMark().intValue());
168 outBuffer.writeZero(INT_LENGTH);
170 // TODO: ct_mark mask is not supported yet
177 public Action deserialize(final ByteBuf message) {
178 final short length = deserializeCtHeader(message);
179 NxActionConntrackBuilder nxActionConntrackBuilder = new NxActionConntrackBuilder();
180 nxActionConntrackBuilder.setFlags(message.readUnsignedShort());
181 nxActionConntrackBuilder.setZoneSrc(message.readUnsignedInt());
182 nxActionConntrackBuilder.setConntrackZone(message.readUnsignedShort());
183 nxActionConntrackBuilder.setRecircTable(message.readUnsignedByte());
184 message.skipBytes(5);
186 if (length > CT_LENGTH) {
187 deserializeCtAction(message,nxActionConntrackBuilder, length - CT_LENGTH);
189 ActionBuilder actionBuilder = new ActionBuilder();
190 actionBuilder.setExperimenterId(getExperimenterId());
191 ActionConntrackBuilder actionConntrackBuilder = new ActionConntrackBuilder();
192 actionConntrackBuilder.setNxActionConntrack(nxActionConntrackBuilder.build());
193 actionBuilder.setActionChoice(actionConntrackBuilder.build());
194 return actionBuilder.build();
197 private static void deserializeCtAction(final ByteBuf message,
198 final NxActionConntrackBuilder nxActionConntrackBuilder, final int ctActionsLength) {
199 List<CtActions> ctActionsList = new ArrayList<>();
200 int processedCtActionsLength = ctActionsLength;
202 while (processedCtActionsLength > 0) {
203 int startReaderIndex = message.readerIndex();
205 if (EncodeConstants.EXPERIMENTER_VALUE == message.readUnsignedShort()) {
208 message.setIndex(startReaderIndex, message.writerIndex());
210 final int startIndex = message.readerIndex();
211 int length = deserializeCtHeader(message);
213 processedCtActionsLength = processedCtActionsLength - length;
214 NxActionNatBuilder nxActionNatBuilder = new NxActionNatBuilder();
215 message.skipBytes(2);
216 nxActionNatBuilder.setFlags(message.readUnsignedShort());
218 int rangePresent = message.readUnsignedShort();
219 nxActionNatBuilder.setRangePresent(rangePresent);
220 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue())) {
221 InetAddress address = InetAddresses.fromInteger((int)message.readUnsignedInt());
222 nxActionNatBuilder.setIpAddressMin(IpAddressBuilder.getDefaultInstance(address.getHostAddress()));
224 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
225 InetAddress address = InetAddresses.fromInteger((int)message.readUnsignedInt());
226 nxActionNatBuilder.setIpAddressMax(IpAddressBuilder.getDefaultInstance(address.getHostAddress()));
228 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
229 nxActionNatBuilder.setPortMin(message.readUnsignedShort());
231 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
232 nxActionNatBuilder.setPortMax(message.readUnsignedShort());
235 NxActionNatCaseBuilder caseBuilder = new NxActionNatCaseBuilder();
236 caseBuilder.setNxActionNat(nxActionNatBuilder.build());
237 CtActionsBuilder ctActionsBuilder = new CtActionsBuilder();
238 ctActionsBuilder.setOfpactActions(caseBuilder.build());
239 ctActionsList.add(ctActionsBuilder.build());
240 int pad = length - (message.readerIndex() - startIndex);
241 message.skipBytes(pad);
243 // only other possible action here is currently ct_mark
245 message.setIndex(startReaderIndex, message.writerIndex());
246 processedCtActionsLength = processedCtActionsLength - SET_FIELD_LENGTH;
248 deserializeCtHeaderWithoutSubtype(message);
250 NxActionCtMarkBuilder nxActionCtMarkBuilder = new NxActionCtMarkBuilder();
251 nxActionCtMarkBuilder.setCtMark(message.readUnsignedInt());
253 NxActionCtMarkCaseBuilder caseBuilder = new NxActionCtMarkCaseBuilder();
254 caseBuilder.setNxActionCtMark(nxActionCtMarkBuilder.build());
255 CtActionsBuilder ctActionsBuilder = new CtActionsBuilder();
256 ctActionsBuilder.setOfpactActions(caseBuilder.build());
257 ctActionsList.add(ctActionsBuilder.build());
259 message.skipBytes(EncodeConstants.SIZE_OF_INT_IN_BYTES);
263 nxActionConntrackBuilder.setCtActions(ctActionsList);
266 private static short deserializeCtHeaderWithoutSubtype(final ByteBuf message) {
267 // size of experimenter type / size of set field code (in case of ct_mark)
268 message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
270 short length = message.readShort();
271 // vendor id / 00 01 d6 04 (in case of ct_mark)
272 message.skipBytes(EncodeConstants.SIZE_OF_INT_IN_BYTES);
276 private static short deserializeCtHeader(final ByteBuf message) {
277 short length = deserializeCtHeaderWithoutSubtype(message);
279 message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);