13452259deb9b7e4760b40e51511ec140dad3ee0
[openflowplugin.git] / extension / openflowjava-extension-nicira / src / main / java / org / opendaylight / openflowjava / nx / codec / match / NxmHeader.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.match;
9
10 import com.google.common.base.MoreObjects;
11 import java.math.BigInteger;
12 import java.util.Objects;
13 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
14 import org.opendaylight.yangtools.yang.common.Uint64;
15
16 /**
17  * Nxm header.
18  *
19  * @author msunal
20  */
21 public class NxmHeader {
22
23     // Full 4 or 8 byte header as big integer
24     private final Uint64 header;
25     // Full 4 or 8 byte header as long
26     private final long headerAsLong;
27     // 4 byte class, field, length as long
28     private final long shortHeader;
29     private final int oxmClass;
30     private final int nxmField;
31     private final boolean hasMask;
32     private final int length;
33     private final long experimenterId;
34
35     /**
36      * Builds a {@code NxmHeader} from a {@code BigInteger} representation,
37      * that is, one for which {@link BigInteger#longValue()} produces
38      * a valid long representation.
39      *
40      * @param header the header as {@code BigInteger}.
41      * @see NxmHeader#NxmHeader(long)
42      */
43     public NxmHeader(final Uint64 header) {
44         this.headerAsLong = header.longValue();
45         if (isExperimenter(header)) {
46             this.experimenterId = (int) this.headerAsLong;
47             this.shortHeader = this.headerAsLong >>> 32;
48         } else {
49             this.shortHeader = this.headerAsLong;
50             this.experimenterId = -1;
51         }
52
53         this.header = header;
54         try {
55             this.oxmClass = Math.toIntExact(extractSub(this.shortHeader, 16, 16));
56             this.nxmField = Math.toIntExact(extractSub(this.shortHeader, 7, 9));
57             this.hasMask = extractSub(this.shortHeader, 1, 8) == 1;
58             this.length = Math.toIntExact(extractSub(this.shortHeader, 8, 0));
59         } catch (ArithmeticException e) {
60             throw new IllegalArgumentException(e);
61         }
62     }
63
64     /**
65      * Builds a {@code NxmHeader} from a {@code long} representation.
66      * For non experimenter, the 4 byte header are the least
67      * significant of the long, being the other 4 most significant
68      * bytes 0. For experimenter, the full 8 byte constitute the header,
69      * being the 4 least significant the experimenter id.
70      *
71      * @param header the header as a {@code long}.
72      */
73     public NxmHeader(final long header) {
74         this(Uint64.fromLongBits(header));
75     }
76
77     /**
78      * Build a non experimenter header from it's constituent fields.
79      *
80      * @param oxmClass the OXM class.
81      * @param nxmField the NXM field.
82      * @param hasMask the hasMask field.
83      * @param length the length field.
84      */
85     public NxmHeader(final int oxmClass, final int nxmField, final boolean hasMask, final int length) {
86         this(oxmClass, nxmField, hasMask, length, -1);
87     }
88
89     /**
90      * Build a experimenter header from it's constituent fields.
91      * The OXM class will be set to 0xFFFF.
92      *
93      * @param nxmField the NXM field.
94      * @param hasMask the hasMask field.
95      * @param length the length field.
96      * @param experimenterId the esperimenter id field.
97      */
98     public NxmHeader(final int nxmField, final boolean hasMask, final int length, final long experimenterId) {
99         this(EncodeConstants.EXPERIMENTER_VALUE, nxmField, hasMask, length, experimenterId);
100     }
101
102     private NxmHeader(final int oxmClass, final int nxmField, final boolean hasMask, final int length,
103             final long experimenterId) {
104         this.oxmClass = oxmClass;
105         this.nxmField = nxmField;
106         this.hasMask = hasMask;
107         this.length = length;
108         this.shortHeader = (long) oxmClass << 16 | nxmField << 9 | (hasMask ? 1 : 0) << 8 | length;
109         this.experimenterId = experimenterId;
110         if (isExperimenter()) {
111             this.header = Uint64.fromLongBits((this.shortHeader << 32) + experimenterId);
112         } else {
113             this.header = Uint64.valueOf(this.shortHeader);
114         }
115         this.headerAsLong = this.header.longValue();
116     }
117
118     private static long extractSub(final long value, final int nrBits, final int offset) {
119         final long rightShifted = value >>> offset;
120         final long mask = (1L << nrBits) - 1L;
121         return rightShifted & mask;
122     }
123
124     /**
125      * Returns the {@code Uint64} representation of the header.
126      *
127      * @return the header.
128      * @see NxmHeader#NxmHeader(Uint64)
129      */
130     public Uint64 toUint64() {
131         return header;
132     }
133
134     /**
135      * Returns the {@code long} representation of the header.
136      *
137      * @return the header.
138      * @see NxmHeader#NxmHeader(long)
139      */
140     public long toLong() {
141         return headerAsLong;
142     }
143
144     public int getOxmClass() {
145         return oxmClass;
146     }
147
148     public int getNxmField() {
149         return nxmField;
150     }
151
152     public boolean isHasMask() {
153         return hasMask;
154     }
155
156     public int getLength() {
157         return length;
158     }
159
160     public long getExperimenterId() {
161         return experimenterId;
162     }
163
164     public boolean isExperimenter() {
165         return oxmClass == EncodeConstants.EXPERIMENTER_VALUE;
166     }
167
168     public static boolean isExperimenter(final Uint64 uint) {
169         return uint.longValue() >>> 48 == EncodeConstants.EXPERIMENTER_VALUE;
170     }
171
172     @Override
173     public int hashCode() {
174         return Objects.hash(shortHeader, experimenterId);
175     }
176
177     @Override
178     public boolean equals(final Object obj) {
179         if (this == obj) {
180             return true;
181         }
182         if (obj == null) {
183             return false;
184         }
185         if (getClass() != obj.getClass()) {
186             return false;
187         }
188         NxmHeader other = (NxmHeader) obj;
189         return shortHeader == other.shortHeader
190                 && experimenterId == other.experimenterId;
191     }
192
193     @Override
194     public String toString() {
195         return MoreObjects.toStringHelper(this)
196                 .add("header", header)
197                 .add("headerAsLong", headerAsLong)
198                 .add("shortHeader", shortHeader)
199                 .add("oxmClass", oxmClass)
200                 .add("oxmField", nxmField)
201                 .add("hasMask", hasMask)
202                 .add("length", length)
203                 .add("experimenterId", experimenterId)
204                 .toString();
205     }
206 }