Bump upstreams
[openflowplugin.git] / extension / openflowjava-extension-nicira / src / main / java / org / opendaylight / openflowjava / nx / codec / action / ConntrackCodec.java
1 /*
2  * Copyright (c) 2015, 2017 Hewlett-Packard Enterprise and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.openflowjava.nx.codec.action;
9
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;
13
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;
41
42 /**
43  * Action codec for conntrack.
44  *
45  * @author Aswin Suryanarayanan.
46  */
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;
57
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);
64
65     @Override
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);
70         int pad = length % 8;
71         serializeHeader(length + pad + CT_LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer);
72
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);
79     }
80
81     private static int getActionLength(final ActionConntrack action) {
82         int length = 0;
83         List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
84         if (ctActionsList == null) {
85             return length;
86         }
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;
96             }
97         }
98         LOG.trace("ActionLength :conntrack: length {}",length);
99         return length;
100     }
101
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;
107         }
108         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
109             natLength += INT_LENGTH;
110         }
111         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
112             natLength += SHORT_LENGTH;
113         }
114         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
115             natLength += SHORT_LENGTH;
116         }
117         return natLength;
118     }
119
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());
136                     }
137                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
138                         writeIpv4Address(outBuffer, natAction.getIpAddressMax());
139                     }
140                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
141                         outBuffer.writeShort(natAction.getPortMin().toJava());
142                     }
143                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
144                         outBuffer.writeShort(natAction.getPortMax().toJava());
145                     }
146                     outBuffer.writeZero(pad);
147                 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
148                     NxActionCtMarkCase nxActionCtMarkCase = (NxActionCtMarkCase)ctActions.getOfpactActions();
149                     NxActionCtMark ctMarkAction = nxActionCtMarkCase.getNxActionCtMark();
150
151                     // structure:
152                     // 00 19 - set field code
153                     // 00 10 - set field length
154                     // 00 01 d6 04
155                     // xx xx xx xx FIELD VALUE (4 bytes)
156                     // xx xx xx xx PADDING (4 bytes)
157
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);
166
167                     // TODO: ct_mark mask is not supported yet
168                 }
169             }
170         }
171     }
172
173     @Override
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);
182
183         if (length > CT_LENGTH) {
184             deserializeCtAction(message, nxActionConntrackBuilder, length - CT_LENGTH);
185         }
186         return new ActionBuilder()
187             .setExperimenterId(getExperimenterId())
188             .setActionChoice(new ActionConntrackBuilder()
189                 .setNxActionConntrack(nxActionConntrackBuilder.build())
190                 .build())
191             .build();
192     }
193
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;
198
199         while (processedCtActionsLength > 0) {
200             final int startReaderIndex = message.readerIndex();
201
202             if (EncodeConstants.EXPERIMENTER_VALUE == message.readUnsignedShort()) {
203                 // NAT action
204                 // reset indices
205                 message.setIndex(startReaderIndex, message.writerIndex());
206
207                 final int startIndex = message.readerIndex();
208                 final int length = deserializeCtHeader(message);
209
210                 processedCtActionsLength = processedCtActionsLength - length;
211                 message.skipBytes(2);
212                 final var nxActionNatBuilder = new NxActionNatBuilder()
213                     .setFlags(readUint16(message));
214
215                 final Uint16 rangePresent = readUint16(message);
216                 nxActionNatBuilder.setRangePresent(rangePresent);
217
218                 final int rangeBits = rangePresent.toJava();
219                 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue()) != 0) {
220                     nxActionNatBuilder.setIpAddressMin(readIpv4Address(message));
221                 }
222                 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue()) != 0) {
223                     nxActionNatBuilder.setIpAddressMax(readIpv4Address(message));
224                 }
225                 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue()) != 0) {
226                     nxActionNatBuilder.setPortMin(readUint16(message));
227                 }
228                 if ((rangeBits & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue()) != 0) {
229                     nxActionNatBuilder.setPortMax(readUint16(message));
230                 }
231
232                 ctActionsList.add(new CtActionsBuilder()
233                     .setOfpactActions(new NxActionNatCaseBuilder()
234                     .setNxActionNat(nxActionNatBuilder.build()).build())
235                     .build());
236
237                 // Padding
238                 message.skipBytes(length - (message.readerIndex() - startIndex));
239             } else {
240                 // only other possible action here is currently ct_mark
241                 // reset indices
242                 message.setIndex(startReaderIndex, message.writerIndex());
243                 processedCtActionsLength = processedCtActionsLength - SET_FIELD_LENGTH;
244
245                 deserializeCtHeaderWithoutSubtype(message);
246
247                 ctActionsList.add(new CtActionsBuilder()
248                     .setOfpactActions(new NxActionCtMarkCaseBuilder()
249                         .setNxActionCtMark(new NxActionCtMarkBuilder()
250                             .setCtMark(readUint32(message))
251                             .build())
252                         .build())
253                     .build());
254
255                 // Padding
256                 message.skipBytes(Integer.BYTES);
257             }
258         }
259
260         nxActionConntrackBuilder.setCtActions(ctActionsList);
261     }
262
263     private static IpAddress readIpv4Address(final ByteBuf message) {
264         return new IpAddress(IetfInetUtil.ipv4AddressFor(message.readInt()));
265     }
266
267     private static void writeIpv4Address(final ByteBuf outBuffer, final IpAddress ipAddress) {
268         if (ipAddress != null) {
269             outBuffer.writeBytes(IetfInetUtil.ipv4AddressBytes(ipAddress.getIpv4Address()));
270         }
271     }
272
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);
276         // size of length
277         short length = message.readShort();
278         // vendor id / 00 01 d6 04 (in case of ct_mark)
279         message.skipBytes(Integer.BYTES);
280         return length;
281     }
282
283     private static short deserializeCtHeader(final ByteBuf message) {
284         short length = deserializeCtHeaderWithoutSubtype(message);
285         // subtype
286         message.skipBytes(Short.BYTES);
287         return length;
288     }
289 }