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