blob: 9b379f65fac9a00576ce489cdffcafb4bb875b87 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
alshabib7911a052014-10-16 17:49:37 -070016package org.onlab.packet;
17
18import com.google.common.collect.Lists;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080019import com.google.common.collect.Maps;
alshabib7911a052014-10-16 17:49:37 -070020import org.apache.commons.lang.ArrayUtils;
DongRyeol Chace65cc02018-07-23 15:02:28 +090021import org.slf4j.Logger;
alshabib7911a052014-10-16 17:49:37 -070022
23import java.nio.ByteBuffer;
Ray Milkey241b96a2014-11-17 13:08:20 -080024import java.nio.charset.StandardCharsets;
Samuel Jero31e16f52018-09-21 10:34:28 -040025import java.security.InvalidKeyException;
26import java.security.NoSuchAlgorithmException;
jaegonkim47b1b4a2017-12-04 14:08:26 +090027import java.util.Arrays;
Jonathan Hart7838c512016-06-07 15:18:22 -070028import java.util.HashMap;
alshabib7911a052014-10-16 17:49:37 -070029
Samuel Jero31e16f52018-09-21 10:34:28 -040030import javax.crypto.Mac;
31import javax.crypto.spec.SecretKeySpec;
32
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080033import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
34import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
DongRyeol Chace65cc02018-07-23 15:02:28 +090035import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080036
alshabib7911a052014-10-16 17:49:37 -070037/**
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080038 * ONOS LLDP containing organizational TLV for ONOS device discovery.
alshabib7911a052014-10-16 17:49:37 -070039 */
40public class ONOSLLDP extends LLDP {
Charles Chan928ff8b2017-05-04 12:22:54 -070041
DongRyeol Chace65cc02018-07-23 15:02:28 +090042 private static final Logger log = getLogger(ONOSLLDP.class);
43
alshabib7911a052014-10-16 17:49:37 -070044 public static final String DEFAULT_DEVICE = "INVALID";
45 public static final String DEFAULT_NAME = "ONOS Discovery";
46
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080047 protected static final byte NAME_SUBTYPE = 1;
48 protected static final byte DEVICE_SUBTYPE = 2;
49 protected static final byte DOMAIN_SUBTYPE = 3;
Samuel Jero31e16f52018-09-21 10:34:28 -040050 protected static final byte TIMESTAMP_SUBTYPE = 4;
51 protected static final byte SIG_SUBTYPE = 5;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080052
53 private static final short NAME_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
54 private static final short DEVICE_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
55 private static final short DOMAIN_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
Samuel Jero31e16f52018-09-21 10:34:28 -040056 private static final short TIMESTAMP_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
57 private static final short SIG_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080058
Jonathan Hart7838c512016-06-07 15:18:22 -070059 private final HashMap<Byte, LLDPOrganizationalTLV> opttlvs = Maps.newHashMap();
alshabib7911a052014-10-16 17:49:37 -070060
61 // TLV constants: type, size and subtype
62 // Organizationally specific TLV also have packet offset and contents of TLV
63 // header
64 private static final byte CHASSIS_TLV_TYPE = 1;
65 private static final byte CHASSIS_TLV_SIZE = 7;
66 private static final byte CHASSIS_TLV_SUBTYPE = 4;
67
alshabib7911a052014-10-16 17:49:37 -070068 private static final byte TTL_TLV_TYPE = 3;
jaegonkim47b1b4a2017-12-04 14:08:26 +090069 private static final byte PORT_DESC_TLV_TYPE = 4;
70
alshabib7911a052014-10-16 17:49:37 -070071 private final byte[] ttlValue = new byte[] {0, 0x78};
72
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080073 // Only needs to be accessed from LinkProbeFactory.
Ray Milkey88cc3432017-03-30 17:19:08 -070074 public ONOSLLDP(byte... subtype) {
alshabib7911a052014-10-16 17:49:37 -070075 super();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080076 for (byte st : subtype) {
77 opttlvs.put(st, new LLDPOrganizationalTLV());
78 }
79 // guarantee the following (name and device) TLVs exist
80 opttlvs.putIfAbsent(NAME_SUBTYPE, new LLDPOrganizationalTLV());
81 opttlvs.putIfAbsent(DEVICE_SUBTYPE, new LLDPOrganizationalTLV());
alshabib7911a052014-10-16 17:49:37 -070082 setName(DEFAULT_NAME);
83 setDevice(DEFAULT_DEVICE);
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080084
Jonathan Hart7838c512016-06-07 15:18:22 -070085 setOptionalTLVList(Lists.newArrayList(opttlvs.values()));
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080086 setTtl(new LLDPTLV().setType(TTL_TLV_TYPE)
alshabib7911a052014-10-16 17:49:37 -070087 .setLength((short) ttlValue.length)
88 .setValue(ttlValue));
alshabib7911a052014-10-16 17:49:37 -070089 }
90
91 private ONOSLLDP(LLDP lldp) {
92 this.portId = lldp.getPortId();
93 this.chassisId = lldp.getChassisId();
94 this.ttl = lldp.getTtl();
95 this.optionalTLVList = lldp.getOptionalTLVList();
96 }
97
98 public void setName(String name) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080099 LLDPOrganizationalTLV nametlv = opttlvs.get(NAME_SUBTYPE);
100 nametlv.setLength((short) (name.length() + NAME_LENGTH));
101 nametlv.setInfoString(name);
102 nametlv.setSubType(NAME_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -0700103 nametlv.setOUI(MacAddress.ONOS.oui());
alshabib7911a052014-10-16 17:49:37 -0700104 }
105
106 public void setDevice(String device) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800107 LLDPOrganizationalTLV devicetlv = opttlvs.get(DEVICE_SUBTYPE);
108 devicetlv.setInfoString(device);
109 devicetlv.setLength((short) (device.length() + DEVICE_LENGTH));
110 devicetlv.setSubType(DEVICE_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -0700111 devicetlv.setOUI(MacAddress.ONOS.oui());
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800112 }
113
114 public void setDomainInfo(String domainId) {
115 LLDPOrganizationalTLV domaintlv = opttlvs.get(DOMAIN_SUBTYPE);
116 if (domaintlv == null) {
117 // maybe warn people not to set this if remote probes aren't.
118 return;
119 }
120 domaintlv.setInfoString(domainId);
121 domaintlv.setLength((short) (domainId.length() + DOMAIN_LENGTH));
122 domaintlv.setSubType(DOMAIN_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -0700123 domaintlv.setOUI(MacAddress.ONOS.oui());
alshabib7911a052014-10-16 17:49:37 -0700124 }
125
126 public void setChassisId(final ChassisId chassisId) {
127 MacAddress chassisMac = MacAddress.valueOf(chassisId.value());
128 byte[] chassis = ArrayUtils.addAll(new byte[] {CHASSIS_TLV_SUBTYPE},
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800129 chassisMac.toBytes());
alshabib7911a052014-10-16 17:49:37 -0700130
131 LLDPTLV chassisTLV = new LLDPTLV();
132 chassisTLV.setLength(CHASSIS_TLV_SIZE);
133 chassisTLV.setType(CHASSIS_TLV_TYPE);
134 chassisTLV.setValue(chassis);
135 this.setChassisId(chassisTLV);
136 }
137
138 public void setPortId(final int portNumber) {
DongRyeol Chace65cc02018-07-23 15:02:28 +0900139 byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_COMPONENT_SUBTYPE},
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900140 String.valueOf(portNumber).getBytes(StandardCharsets.UTF_8));
alshabib7911a052014-10-16 17:49:37 -0700141
142 LLDPTLV portTLV = new LLDPTLV();
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900143 portTLV.setLength((short) port.length);
alshabib7911a052014-10-16 17:49:37 -0700144 portTLV.setType(PORT_TLV_TYPE);
145 portTLV.setValue(port);
146 this.setPortId(portTLV);
147 }
148
DongRyeol Chace65cc02018-07-23 15:02:28 +0900149 public void setPortName(final String portName) {
150 byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_INTERFACE_NAME_SUBTYPE},
151 portName.getBytes(StandardCharsets.UTF_8));
152
153 LLDPTLV portTLV = new LLDPTLV();
154 portTLV.setLength((short) port.length);
155 portTLV.setType(PORT_TLV_TYPE);
156 portTLV.setValue(port);
157 this.setPortId(portTLV);
158 }
159
Samuel Jero31e16f52018-09-21 10:34:28 -0400160 public void setTimestamp(long timestamp) {
161 LLDPOrganizationalTLV tmtlv = opttlvs.get(TIMESTAMP_SUBTYPE);
162 if (tmtlv == null) {
163 return;
164 }
165 tmtlv.setInfoString(ByteBuffer.allocate(8).putLong(timestamp).array());
166 tmtlv.setLength((short) (8 + TIMESTAMP_LENGTH));
167 tmtlv.setSubType(TIMESTAMP_SUBTYPE);
168 tmtlv.setOUI(MacAddress.ONOS.oui());
169 }
170
171 public void setSig(byte[] sig) {
172 LLDPOrganizationalTLV sigtlv = opttlvs.get(SIG_SUBTYPE);
173 if (sigtlv == null) {
174 return;
175 }
176 sigtlv.setInfoString(sig);
177 sigtlv.setLength((short) (sig.length + SIG_LENGTH));
178 sigtlv.setSubType(SIG_SUBTYPE);
179 sigtlv.setOUI(MacAddress.ONOS.oui());
180 }
181
alshabib7911a052014-10-16 17:49:37 -0700182 public LLDPOrganizationalTLV getNameTLV() {
183 for (LLDPTLV tlv : this.getOptionalTLVList()) {
184 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
185 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
186 if (orgTLV.getSubType() == NAME_SUBTYPE) {
187 return orgTLV;
188 }
189 }
190 }
191 return null;
192 }
193
194 public LLDPOrganizationalTLV getDeviceTLV() {
195 for (LLDPTLV tlv : this.getOptionalTLVList()) {
196 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
Samuel Jero31e16f52018-09-21 10:34:28 -0400197 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
alshabib7911a052014-10-16 17:49:37 -0700198 if (orgTLV.getSubType() == DEVICE_SUBTYPE) {
199 return orgTLV;
200 }
201 }
202 }
203 return null;
204 }
205
Samuel Jero31e16f52018-09-21 10:34:28 -0400206 public LLDPOrganizationalTLV getTimestampTLV() {
207 for (LLDPTLV tlv : this.getOptionalTLVList()) {
208 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
209 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
210 if (orgTLV.getSubType() == TIMESTAMP_SUBTYPE) {
211 return orgTLV;
212 }
213 }
214 }
215 return null;
216 }
217
218 public LLDPOrganizationalTLV getSigTLV() {
219 for (LLDPTLV tlv : this.getOptionalTLVList()) {
220 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
221 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
222 if (orgTLV.getSubType() == SIG_SUBTYPE) {
223 return orgTLV;
224 }
225 }
226 }
227 return null;
228 }
229
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800230 /**
231 * Gets the TLV associated with remote probing. This TLV will be null if
232 * remote probing is disabled.
233 *
234 * @return A TLV containing domain ID, or null.
235 */
236 public LLDPOrganizationalTLV getDomainTLV() {
237 for (LLDPTLV tlv : this.getOptionalTLVList()) {
238 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
239 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
240 if (orgTLV.getSubType() == DOMAIN_SUBTYPE) {
241 return orgTLV;
242 }
243 }
244 }
245 return null;
246 }
247
DongRyeol Chace65cc02018-07-23 15:02:28 +0900248 public LLDPTLV getPortDescTLV() {
249 for (LLDPTLV tlv : this.getOptionalTLVList()) {
250 if (tlv.getType() == PORT_DESC_TLV_TYPE) {
251 return tlv;
252 }
253 }
254
255 log.error("Cannot find the port description tlv type.");
256 return null;
257 }
258
alshabib7911a052014-10-16 17:49:37 -0700259 public String getNameString() {
260 LLDPOrganizationalTLV tlv = getNameTLV();
261 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800262 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700263 }
264 return null;
265 }
266
267 public String getDeviceString() {
268 LLDPOrganizationalTLV tlv = getDeviceTLV();
269 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800270 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700271 }
272 return null;
273 }
274
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800275 public String getDomainString() {
276 LLDPOrganizationalTLV tlv = getDomainTLV();
277 if (tlv != null) {
278 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
279 }
280 return null;
281 }
282
DongRyeol Chace65cc02018-07-23 15:02:28 +0900283 public String getPortDescString() {
284 LLDPTLV tlv = getPortDescTLV();
285 if (tlv != null) {
286 return new String(tlv.getValue(), StandardCharsets.UTF_8);
287 }
288 return null;
289 }
290
alshabib7911a052014-10-16 17:49:37 -0700291 public Integer getPort() {
292 ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
DongRyeol Chace65cc02018-07-23 15:02:28 +0900293 byte type = portBB.get();
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900294
DongRyeol Chace65cc02018-07-23 15:02:28 +0900295 if (type == PORT_TLV_COMPONENT_SUBTYPE) {
296 return Integer.parseInt(new String(portBB.array(),
297 portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
298 } else {
299 return -1;
300 }
301 }
302
303 public String getPortNameString() {
304 ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
305 byte type = portBB.get();
306
307 if (type == PORT_TLV_INTERFACE_NAME_SUBTYPE) {
308 return new String(portBB.array(), portBB.position(), portBB.remaining(), StandardCharsets.UTF_8);
309 } else {
DongRyeol Chace65cc02018-07-23 15:02:28 +0900310 return null;
311 }
312 }
313
314 public MacAddress getChassisIdByMac() {
315 ByteBuffer portBB = ByteBuffer.wrap(this.getChassisId().getValue());
316 byte type = portBB.get();
317
318 if (type == CHASSIS_TLV_SUBTYPE) {
319 byte[] bytes = new byte[portBB.remaining()];
320
321 System.arraycopy(portBB.array(), portBB.position(), bytes, 0, MacAddress.MAC_ADDRESS_LENGTH);
322
323 return new MacAddress(bytes);
324 } else {
325 return MacAddress.NONE;
326 }
327 }
328
329 public short getTtlBySeconds() {
330 ByteBuffer portBB = ByteBuffer.wrap(this.getTtl().getValue());
331
332 return portBB.getShort();
alshabib7911a052014-10-16 17:49:37 -0700333 }
334
Samuel Jero31e16f52018-09-21 10:34:28 -0400335 public long getTimestamp() {
336 LLDPOrganizationalTLV tlv = getTimestampTLV();
337 if (tlv != null) {
338 ByteBuffer b = ByteBuffer.allocate(8).put(tlv.getInfoString());
339 b.flip();
340 return b.getLong();
341 }
342 return 0;
343 }
344
345 public byte[] getSig() {
346 LLDPOrganizationalTLV tlv = getSigTLV();
347 if (tlv != null) {
348 return tlv.getInfoString();
349 }
350 return null;
351 }
352
alshabib7911a052014-10-16 17:49:37 -0700353 /**
354 * Given an ethernet packet, determines if this is an LLDP from
355 * ONOS and returns the device the LLDP came from.
356 * @param eth an ethernet packet
357 * @return a the lldp packet or null
358 */
359 public static ONOSLLDP parseONOSLLDP(Ethernet eth) {
360 if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
361 eth.getEtherType() == Ethernet.TYPE_BSN) {
Jonathan Hart7838c512016-06-07 15:18:22 -0700362 ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload());
alshabib7911a052014-10-16 17:49:37 -0700363 if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) {
364 return onosLldp;
365 }
366 }
367 return null;
368 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800369
370 /**
DongRyeol Chace65cc02018-07-23 15:02:28 +0900371 * Given an ethernet packet, returns the device the LLDP came from.
372 * @param eth an ethernet packet
373 * @return a the lldp packet or null
374 */
375 public static ONOSLLDP parseLLDP(Ethernet eth) {
376 if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
377 eth.getEtherType() == Ethernet.TYPE_BSN) {
378
379 return new ONOSLLDP((LLDP) eth.getPayload());
380 }
381
382 log.error("Packet is not the LLDP or BSN.");
383 return null;
384 }
385
386 /**
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800387 * Creates a link probe for link discovery/verification.
Samuel Jero31e16f52018-09-21 10:34:28 -0400388 * @deprecated since 1.15. Insecure, do not use.
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800389 *
390 * @param deviceId The device ID as a String
391 * @param chassisId The chassis ID of the device
392 * @param portNum Port number of port to send probe out of
393 * @return ONOSLLDP probe message
394 */
Samuel Jero31e16f52018-09-21 10:34:28 -0400395 @Deprecated
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800396 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum) {
397 ONOSLLDP probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE);
398 probe.setPortId(portNum);
399 probe.setDevice(deviceId);
400 probe.setChassisId(chassisId);
401 return probe;
402 }
jaegonkim47b1b4a2017-12-04 14:08:26 +0900403
404 /**
405 * Creates a link probe for link discovery/verification.
406 *
407 * @param deviceId The device ID as a String
408 * @param chassisId The chassis ID of the device
409 * @param portNum Port number of port to send probe out of
Samuel Jero31e16f52018-09-21 10:34:28 -0400410 * @param secret LLDP secret
411 * @return ONOSLLDP probe message
412 */
413 public static ONOSLLDP onosSecureLLDP(String deviceId, ChassisId chassisId, int portNum, String secret) {
414 ONOSLLDP probe = null;
415 if (secret == null) {
416 probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE);
417 } else {
418 probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE, TIMESTAMP_SUBTYPE, SIG_SUBTYPE);
419 }
420 probe.setPortId(portNum);
421 probe.setDevice(deviceId);
422 probe.setChassisId(chassisId);
423
424 if (secret != null) {
425 /* Secure Mode */
426 long ts = System.currentTimeMillis();
427 probe.setTimestamp(ts);
428 byte[] sig = createSig(deviceId, portNum, ts, secret);
429 if (sig == null) {
430 return null;
431 }
432 probe.setSig(sig);
433 sig = null;
434 }
435 return probe;
436 }
437
438 /**
439 * Creates a link probe for link discovery/verification.
440 * @deprecated since 1.15. Insecure, do not use.
441 *
442 * @param deviceId The device ID as a String
443 * @param chassisId The chassis ID of the device
444 * @param portNum Port number of port to send probe out of
jaegonkim47b1b4a2017-12-04 14:08:26 +0900445 * @param portDesc Port description of port to send probe out of
446 * @return ONOSLLDP probe message
447 */
Samuel Jero31e16f52018-09-21 10:34:28 -0400448 @Deprecated
jaegonkim47b1b4a2017-12-04 14:08:26 +0900449 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum, String portDesc) {
jaegonkim47b1b4a2017-12-04 14:08:26 +0900450 ONOSLLDP probe = onosLLDP(deviceId, chassisId, portNum);
Samuel Jero31e16f52018-09-21 10:34:28 -0400451 addPortDesc(probe, portDesc);
452 return probe;
453 }
jaegonkim47b1b4a2017-12-04 14:08:26 +0900454
Samuel Jero31e16f52018-09-21 10:34:28 -0400455 /**
456 * Creates a link probe for link discovery/verification.
457 *
458 * @param deviceId The device ID as a String
459 * @param chassisId The chassis ID of the device
460 * @param portNum Port number of port to send probe out of
461 * @param portDesc Port description of port to send probe out of
462 * @param secret LLDP secret
463 * @return ONOSLLDP probe message
464 */
465 public static ONOSLLDP onosSecureLLDP(String deviceId, ChassisId chassisId, int portNum, String portDesc,
466 String secret) {
467 ONOSLLDP probe = onosSecureLLDP(deviceId, chassisId, portNum, secret);
468 addPortDesc(probe, portDesc);
469 return probe;
470 }
471
472 private static void addPortDesc(ONOSLLDP probe, String portDesc) {
jaegonkim47b1b4a2017-12-04 14:08:26 +0900473 if (portDesc != null && !portDesc.isEmpty()) {
474 byte[] bPortDesc = portDesc.getBytes(StandardCharsets.UTF_8);
475
476 if (bPortDesc.length > LLDPTLV.MAX_LENGTH) {
477 bPortDesc = Arrays.copyOf(bPortDesc, LLDPTLV.MAX_LENGTH);
478 }
479 LLDPTLV portDescTlv = new LLDPTLV()
480 .setType(PORT_DESC_TLV_TYPE)
481 .setLength((short) bPortDesc.length)
482 .setValue(bPortDesc);
483 probe.addOptionalTLV(portDescTlv);
484 }
Samuel Jero31e16f52018-09-21 10:34:28 -0400485 }
486
487 private static byte[] createSig(String deviceId, int portNum, long timestamp, String secret) {
488 byte[] pnb = ByteBuffer.allocate(8).putLong(portNum).array();
489 byte[] tmb = ByteBuffer.allocate(8).putLong(timestamp).array();
490
491 try {
492 SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
493 Mac mac = Mac.getInstance("HmacSHA256");
494 mac.init(signingKey);
495 mac.update(deviceId.getBytes());
496 mac.update(pnb);
497 mac.update(tmb);
498 byte[] sig = mac.doFinal();
499 return sig;
500 } catch (NoSuchAlgorithmException e) {
501 return null;
502 } catch (InvalidKeyException e) {
503 return null;
504 }
505 }
506
507 private static boolean verifySig(byte[] sig, String deviceId, int portNum, long timestamp, String secret) {
508 byte[] nsig = createSig(deviceId, portNum, timestamp, secret);
509 if (nsig == null) {
510 return false;
511 }
512
513 if (!ArrayUtils.isSameLength(nsig, sig)) {
514 return false;
515 }
516
517 boolean fail = false;
518 for (int i = 0; i < nsig.length; i++) {
519 if (sig[i] != nsig[i]) {
520 fail = true;
521 }
522 }
523 if (fail) {
524 return false;
525 }
526 return true;
527 }
528
529 public static boolean verify(ONOSLLDP probe, String secret, long maxDelay) {
530 if (secret == null) {
531 return true;
532 }
533
534 String deviceId = probe.getDeviceString();
535 int portNum = probe.getPort();
536 long timestamp = probe.getTimestamp();
537 byte[] sig = probe.getSig();
538
539 if (deviceId == null || sig == null) {
540 return false;
541 }
542
543 if (timestamp + maxDelay <= System.currentTimeMillis() ||
544 timestamp > System.currentTimeMillis()) {
545 return false;
546 }
547
548 return verifySig(sig, deviceId, portNum, timestamp, secret);
jaegonkim47b1b4a2017-12-04 14:08:26 +0900549 }
550
alshabib7911a052014-10-16 17:49:37 -0700551}