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