blob: 0124b7fdbc27ee07ae231858b83ef3ade0c1754e [file] [log] [blame]
Charles Chan64c2dfd2018-07-24 11:58:08 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onlab.packet.lacp;
18
19import com.google.common.collect.ImmutableMap;
20import org.onlab.packet.BasePacket;
21import org.onlab.packet.DeserializationException;
22import org.onlab.packet.Deserializer;
23
24import java.nio.ByteBuffer;
25import java.util.Map;
26import java.util.Objects;
27import java.util.Optional;
28import java.util.concurrent.ConcurrentHashMap;
29
30import static com.google.common.base.MoreObjects.toStringHelper;
31import static org.onlab.packet.PacketUtils.checkInput;
32
33public class Lacp extends BasePacket {
34 public static final int HEADER_LENGTH = 1;
35 public static final byte TYPE_ACTOR = 1;
36 public static final byte TYPE_PARTNER = 2;
37 public static final byte TYPE_COLLECTOR = 3;
38 public static final byte TYPE_TERMINATOR = 0;
39
40 private static final Map<Byte, Deserializer<? extends LacpTlv>> PROTOCOL_DESERIALIZER_MAP =
41 ImmutableMap.<Byte, Deserializer<? extends LacpTlv>>builder()
42 .put(TYPE_ACTOR, LacpBaseTlv.deserializer())
43 .put(TYPE_PARTNER, LacpBaseTlv.deserializer())
44 .put(TYPE_COLLECTOR, LacpCollectorTlv.deserializer())
45 .put(TYPE_TERMINATOR, LacpTerminatorTlv.deserializer())
46 .build();
47
48 private byte lacpVersion;
49 private Map<Byte, LacpTlv> tlv = new ConcurrentHashMap<>();
50
51 /**
52 * Gets LACP version.
53 *
54 * @return LACP version
55 */
56 public byte getLacpVersion() {
57 return this.lacpVersion;
58 }
59
60 /**
61 * Sets LACP version.
62 *
63 * @param lacpVersion LACP version
64 * @return this
65 */
66 public Lacp setLacpVersion(byte lacpVersion) {
67 this.lacpVersion = lacpVersion;
68 return this;
69 }
70
71 /**
72 * Gets LACP TLV.
73 *
74 * @return LACP TLV
75 */
76 public Map<Byte, LacpTlv> getTlv() {
77 return this.tlv;
78 }
79
80 /**
81 * Sets LACP TLV.
82 *
83 * @param tlv LACP TLV
84 * @return this
85 */
86 public Lacp setTlv(Map<Byte, LacpTlv> tlv) {
87 this.tlv = tlv;
88 return this;
89 }
90
91 /**
92 * Deserializer function for LACP packets.
93 *
94 * @return deserializer function
95 */
96 public static Deserializer<Lacp> deserializer() {
97 return (data, offset, length) -> {
98 checkInput(data, offset, length, HEADER_LENGTH);
99
100 Lacp lacp = new Lacp();
101 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
102 lacp.setLacpVersion(bb.get());
103
104 while (bb.limit() - bb.position() > 0) {
105 byte nextType = bb.get();
106 int nextLength = Byte.toUnsignedInt(bb.get());
107 int parseLength = nextLength == 0 ?
108 LacpTerminatorTlv.PADDING_LENGTH : // Special case for LacpTerminatorTlv
109 nextLength - 2;
110
111 Deserializer<? extends LacpTlv> deserializer;
112 if (Lacp.PROTOCOL_DESERIALIZER_MAP.containsKey(nextType)) {
113 deserializer = Lacp.PROTOCOL_DESERIALIZER_MAP.get(nextType);
114 } else {
115 throw new DeserializationException("Unsupported LACP subtype " + Byte.toString(nextType));
116 }
117
118 LacpTlv tlv = deserializer.deserialize(data, bb.position(), parseLength);
119 LacpTlv previousTlv = lacp.tlv.put(nextType, tlv);
120 if (previousTlv != null) {
121 throw new DeserializationException("Duplicated type " + Byte.toString(nextType)
122 + "in LACP TLV");
123 }
124
125 bb.position(bb.position() + parseLength);
126 }
127
128 return lacp;
129 };
130 }
131
132 @Override
133 public byte[] serialize() {
134 byte[] actorInfo = Optional.ofNullable(tlv.get(TYPE_ACTOR)).map(LacpTlv::serialize)
135 .orElse(new byte[0]);
136 byte[] partnerInfo = Optional.ofNullable(tlv.get(TYPE_PARTNER)).map(LacpTlv::serialize)
137 .orElse(new byte[0]);
138 byte[] collectorInfo = Optional.ofNullable(tlv.get(TYPE_COLLECTOR)).map(LacpTlv::serialize)
139 .orElse(new byte[0]);
140 byte[] terminatorInfo = Optional.ofNullable(tlv.get(TYPE_TERMINATOR)).map(LacpTlv::serialize)
141 .orElse(new byte[0]);
142
143 final byte[] data = new byte[HEADER_LENGTH
144 + LacpTlv.HEADER_LENGTH + actorInfo.length
145 + LacpTlv.HEADER_LENGTH + partnerInfo.length
146 + LacpTlv.HEADER_LENGTH + collectorInfo.length
147 + LacpTlv.HEADER_LENGTH + terminatorInfo.length];
148
149 final ByteBuffer bb = ByteBuffer.wrap(data);
150 bb.put(lacpVersion);
151 bb.put(TYPE_ACTOR);
152 bb.put(LacpBaseTlv.LENGTH);
153 bb.put(actorInfo);
154 bb.put(TYPE_PARTNER);
155 bb.put(LacpBaseTlv.LENGTH);
156 bb.put(partnerInfo);
157 bb.put(TYPE_COLLECTOR);
158 bb.put(LacpCollectorTlv.LENGTH);
159 bb.put(collectorInfo);
160 bb.put(TYPE_TERMINATOR);
161 bb.put(LacpTerminatorTlv.LENGTH);
162 bb.put(terminatorInfo);
163
164 return data;
165 }
166
167 @Override
168 public int hashCode() {
169 return Objects.hash(super.hashCode(), lacpVersion, tlv);
170 }
171
172 @Override
173 public boolean equals(final Object obj) {
174 if (this == obj) {
175 return true;
176 }
177 if (!super.equals(obj)) {
178 return false;
179 }
180 if (!(obj instanceof Lacp)) {
181 return false;
182 }
183 final Lacp other = (Lacp) obj;
184
185 return this.lacpVersion == other.lacpVersion &&
186 Objects.equals(this.tlv, other.tlv);
187 }
188
189 @Override
190 public String toString() {
191 return toStringHelper(getClass())
192 .add("lacpVersion", Byte.toString(lacpVersion))
193 .add("tlv", tlv)
194 .toString();
195 }
196}