Merge "Make methods static"
[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 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;
38
39 /**
40  * Action codec for conntrack.
41  *
42  * @author Aswin Suryanarayanan.
43  */
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;
54
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);
61
62     @Override
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);
67         int pad = length % 8;
68         serializeHeader(length + pad + CT_LENGTH, NXAST_CONNTRACK_SUBTYPE, outBuffer);
69
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);
76     }
77
78     private static int getActionLength(final ActionConntrack action) {
79         int length = 0;
80         List<CtActions> ctActionsList = action.getNxActionConntrack().getCtActions();
81         if (ctActionsList == null) {
82             return length;
83         }
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;
93             }
94         }
95         LOG.trace("ActionLength :conntrack: length {}",length);
96         return length;
97     }
98
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;
104         }
105         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
106             natLength += INT_LENGTH;
107         }
108         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
109             natLength += SHORT_LENGTH;
110         }
111         if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
112             natLength += SHORT_LENGTH;
113         }
114         return natLength;
115     }
116
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()));
135                         }
136                     }
137                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
138                         if (null != natAction.getIpAddressMax()) {
139                             outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv4AddressBytes(natAction
140                                     .getIpAddressMax().getIpv4Address()));
141                         }
142                     }
143                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
144                         outBuffer.writeShort(natAction.getPortMin().toJava());
145                     }
146                     if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
147                         outBuffer.writeShort(natAction.getPortMax().toJava());
148                     }
149                     outBuffer.writeZero(pad);
150                 } else if (ctActions.getOfpactActions() instanceof NxActionCtMarkCase) {
151                     NxActionCtMarkCase nxActionCtMarkCase = (NxActionCtMarkCase)ctActions.getOfpactActions();
152                     NxActionCtMark ctMarkAction = nxActionCtMarkCase.getNxActionCtMark();
153
154                     // structure:
155                     // 00 19 - set field code
156                     // 00 10 - set field length
157                     // 00 01 d6 04
158                     // xx xx xx xx FIELD VALUE (4 bytes)
159                     // xx xx xx xx PADDING (4 bytes)
160
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);
169
170                     // TODO: ct_mark mask is not supported yet
171                 }
172             }
173         }
174     }
175
176     @Override
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);
185
186         if  (length > CT_LENGTH) {
187             deserializeCtAction(message,nxActionConntrackBuilder, length - CT_LENGTH);
188         }
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();
195     }
196
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;
201
202         while (processedCtActionsLength > 0) {
203             int startReaderIndex = message.readerIndex();
204
205             if (EncodeConstants.EXPERIMENTER_VALUE == message.readUnsignedShort()) {
206                 // NAT action
207                 // reset indices
208                 message.setIndex(startReaderIndex, message.writerIndex());
209
210                 final int startIndex = message.readerIndex();
211                 int length = deserializeCtHeader(message);
212
213                 processedCtActionsLength = processedCtActionsLength - length;
214                 NxActionNatBuilder nxActionNatBuilder = new NxActionNatBuilder();
215                 message.skipBytes(2);
216                 nxActionNatBuilder.setFlags(message.readUnsignedShort());
217
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()));
223                 }
224                 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEIPV4MAX.getIntValue())) {
225                     InetAddress address = InetAddresses.fromInteger((int)message.readUnsignedInt());
226                     nxActionNatBuilder.setIpAddressMax(IpAddressBuilder.getDefaultInstance(address.getHostAddress()));
227                 }
228                 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMIN.getIntValue())) {
229                     nxActionNatBuilder.setPortMin(message.readUnsignedShort());
230                 }
231                 if (0 != (rangePresent & NxActionNatRangePresent.NXNATRANGEPROTOMAX.getIntValue())) {
232                     nxActionNatBuilder.setPortMax(message.readUnsignedShort());
233                 }
234
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);
242             } else {
243                 // only other possible action here is currently ct_mark
244                 // reset indices
245                 message.setIndex(startReaderIndex, message.writerIndex());
246                 processedCtActionsLength = processedCtActionsLength - SET_FIELD_LENGTH;
247
248                 deserializeCtHeaderWithoutSubtype(message);
249
250                 NxActionCtMarkBuilder nxActionCtMarkBuilder = new NxActionCtMarkBuilder();
251                 nxActionCtMarkBuilder.setCtMark(message.readUnsignedInt());
252
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());
258                 // padding
259                 message.skipBytes(EncodeConstants.SIZE_OF_INT_IN_BYTES);
260             }
261         }
262
263         nxActionConntrackBuilder.setCtActions(ctActionsList);
264     }
265
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);
269         // size of length
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);
273         return length;
274     }
275
276     private static short deserializeCtHeader(final ByteBuf message) {
277         short length = deserializeCtHeaderWithoutSubtype(message);
278         // subtype
279         message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
280         return length;
281     }
282 }