blob: b1e44c5a690075030c704bb56e1e8e85e071ef81 [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;
21
22import java.nio.ByteBuffer;
Ray Milkey241b96a2014-11-17 13:08:20 -080023import java.nio.charset.StandardCharsets;
jaegonkim47b1b4a2017-12-04 14:08:26 +090024import java.util.Arrays;
Jonathan Hart7838c512016-06-07 15:18:22 -070025import java.util.HashMap;
alshabib7911a052014-10-16 17:49:37 -070026
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080027import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
28import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
29
alshabib7911a052014-10-16 17:49:37 -070030/**
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080031 * ONOS LLDP containing organizational TLV for ONOS device discovery.
alshabib7911a052014-10-16 17:49:37 -070032 */
33public class ONOSLLDP extends LLDP {
Charles Chan928ff8b2017-05-04 12:22:54 -070034
alshabib7911a052014-10-16 17:49:37 -070035 public static final String DEFAULT_DEVICE = "INVALID";
36 public static final String DEFAULT_NAME = "ONOS Discovery";
37
alshabib7911a052014-10-16 17:49:37 -070038
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080039 protected static final byte NAME_SUBTYPE = 1;
40 protected static final byte DEVICE_SUBTYPE = 2;
41 protected static final byte DOMAIN_SUBTYPE = 3;
42
43 private static final short NAME_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
44 private static final short DEVICE_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
45 private static final short DOMAIN_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
46
Jonathan Hart7838c512016-06-07 15:18:22 -070047 private final HashMap<Byte, LLDPOrganizationalTLV> opttlvs = Maps.newHashMap();
alshabib7911a052014-10-16 17:49:37 -070048
49 // TLV constants: type, size and subtype
50 // Organizationally specific TLV also have packet offset and contents of TLV
51 // header
52 private static final byte CHASSIS_TLV_TYPE = 1;
53 private static final byte CHASSIS_TLV_SIZE = 7;
54 private static final byte CHASSIS_TLV_SUBTYPE = 4;
55
56 private static final byte PORT_TLV_TYPE = 2;
alshabib7911a052014-10-16 17:49:37 -070057 private static final byte PORT_TLV_SUBTYPE = 2;
58
59 private static final byte TTL_TLV_TYPE = 3;
60
jaegonkim47b1b4a2017-12-04 14:08:26 +090061 private static final byte PORT_DESC_TLV_TYPE = 4;
62
alshabib7911a052014-10-16 17:49:37 -070063 private final byte[] ttlValue = new byte[] {0, 0x78};
64
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080065 // Only needs to be accessed from LinkProbeFactory.
Ray Milkey88cc3432017-03-30 17:19:08 -070066 public ONOSLLDP(byte... subtype) {
alshabib7911a052014-10-16 17:49:37 -070067 super();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080068 for (byte st : subtype) {
69 opttlvs.put(st, new LLDPOrganizationalTLV());
70 }
71 // guarantee the following (name and device) TLVs exist
72 opttlvs.putIfAbsent(NAME_SUBTYPE, new LLDPOrganizationalTLV());
73 opttlvs.putIfAbsent(DEVICE_SUBTYPE, new LLDPOrganizationalTLV());
alshabib7911a052014-10-16 17:49:37 -070074 setName(DEFAULT_NAME);
75 setDevice(DEFAULT_DEVICE);
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080076
Jonathan Hart7838c512016-06-07 15:18:22 -070077 setOptionalTLVList(Lists.newArrayList(opttlvs.values()));
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080078 setTtl(new LLDPTLV().setType(TTL_TLV_TYPE)
alshabib7911a052014-10-16 17:49:37 -070079 .setLength((short) ttlValue.length)
80 .setValue(ttlValue));
alshabib7911a052014-10-16 17:49:37 -070081 }
82
83 private ONOSLLDP(LLDP lldp) {
84 this.portId = lldp.getPortId();
85 this.chassisId = lldp.getChassisId();
86 this.ttl = lldp.getTtl();
87 this.optionalTLVList = lldp.getOptionalTLVList();
88 }
89
90 public void setName(String name) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080091 LLDPOrganizationalTLV nametlv = opttlvs.get(NAME_SUBTYPE);
92 nametlv.setLength((short) (name.length() + NAME_LENGTH));
93 nametlv.setInfoString(name);
94 nametlv.setSubType(NAME_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -070095 nametlv.setOUI(MacAddress.ONOS.oui());
alshabib7911a052014-10-16 17:49:37 -070096 }
97
98 public void setDevice(String device) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080099 LLDPOrganizationalTLV devicetlv = opttlvs.get(DEVICE_SUBTYPE);
100 devicetlv.setInfoString(device);
101 devicetlv.setLength((short) (device.length() + DEVICE_LENGTH));
102 devicetlv.setSubType(DEVICE_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -0700103 devicetlv.setOUI(MacAddress.ONOS.oui());
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800104 }
105
106 public void setDomainInfo(String domainId) {
107 LLDPOrganizationalTLV domaintlv = opttlvs.get(DOMAIN_SUBTYPE);
108 if (domaintlv == null) {
109 // maybe warn people not to set this if remote probes aren't.
110 return;
111 }
112 domaintlv.setInfoString(domainId);
113 domaintlv.setLength((short) (domainId.length() + DOMAIN_LENGTH));
114 domaintlv.setSubType(DOMAIN_SUBTYPE);
Charles Chan928ff8b2017-05-04 12:22:54 -0700115 domaintlv.setOUI(MacAddress.ONOS.oui());
alshabib7911a052014-10-16 17:49:37 -0700116 }
117
118 public void setChassisId(final ChassisId chassisId) {
119 MacAddress chassisMac = MacAddress.valueOf(chassisId.value());
120 byte[] chassis = ArrayUtils.addAll(new byte[] {CHASSIS_TLV_SUBTYPE},
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800121 chassisMac.toBytes());
alshabib7911a052014-10-16 17:49:37 -0700122
123 LLDPTLV chassisTLV = new LLDPTLV();
124 chassisTLV.setLength(CHASSIS_TLV_SIZE);
125 chassisTLV.setType(CHASSIS_TLV_TYPE);
126 chassisTLV.setValue(chassis);
127 this.setChassisId(chassisTLV);
128 }
129
130 public void setPortId(final int portNumber) {
131 byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900132 String.valueOf(portNumber).getBytes(StandardCharsets.UTF_8));
alshabib7911a052014-10-16 17:49:37 -0700133
134 LLDPTLV portTLV = new LLDPTLV();
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900135 portTLV.setLength((short) port.length);
alshabib7911a052014-10-16 17:49:37 -0700136 portTLV.setType(PORT_TLV_TYPE);
137 portTLV.setValue(port);
138 this.setPortId(portTLV);
139 }
140
141 public LLDPOrganizationalTLV getNameTLV() {
142 for (LLDPTLV tlv : this.getOptionalTLVList()) {
143 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
144 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
145 if (orgTLV.getSubType() == NAME_SUBTYPE) {
146 return orgTLV;
147 }
148 }
149 }
150 return null;
151 }
152
153 public LLDPOrganizationalTLV getDeviceTLV() {
154 for (LLDPTLV tlv : this.getOptionalTLVList()) {
155 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
156 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
157 if (orgTLV.getSubType() == DEVICE_SUBTYPE) {
158 return orgTLV;
159 }
160 }
161 }
162 return null;
163 }
164
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800165 /**
166 * Gets the TLV associated with remote probing. This TLV will be null if
167 * remote probing is disabled.
168 *
169 * @return A TLV containing domain ID, or null.
170 */
171 public LLDPOrganizationalTLV getDomainTLV() {
172 for (LLDPTLV tlv : this.getOptionalTLVList()) {
173 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
174 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
175 if (orgTLV.getSubType() == DOMAIN_SUBTYPE) {
176 return orgTLV;
177 }
178 }
179 }
180 return null;
181 }
182
alshabib7911a052014-10-16 17:49:37 -0700183 public String getNameString() {
184 LLDPOrganizationalTLV tlv = getNameTLV();
185 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800186 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700187 }
188 return null;
189 }
190
191 public String getDeviceString() {
192 LLDPOrganizationalTLV tlv = getDeviceTLV();
193 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800194 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700195 }
196 return null;
197 }
198
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800199 public String getDomainString() {
200 LLDPOrganizationalTLV tlv = getDomainTLV();
201 if (tlv != null) {
202 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
203 }
204 return null;
205 }
206
alshabib7911a052014-10-16 17:49:37 -0700207 public Integer getPort() {
208 ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
209 portBB.position(1);
DongRyeol Chae0c98db2018-07-12 16:17:21 +0900210
211 return Integer.parseInt(new String(portBB.array(),
212 portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
alshabib7911a052014-10-16 17:49:37 -0700213 }
214
215 /**
216 * Given an ethernet packet, determines if this is an LLDP from
217 * ONOS and returns the device the LLDP came from.
218 * @param eth an ethernet packet
219 * @return a the lldp packet or null
220 */
221 public static ONOSLLDP parseONOSLLDP(Ethernet eth) {
222 if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
223 eth.getEtherType() == Ethernet.TYPE_BSN) {
Jonathan Hart7838c512016-06-07 15:18:22 -0700224 ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload());
alshabib7911a052014-10-16 17:49:37 -0700225 if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) {
226 return onosLldp;
227 }
228 }
229 return null;
230 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800231
232 /**
233 * Creates a link probe for link discovery/verification.
234 *
235 * @param deviceId The device ID as a String
236 * @param chassisId The chassis ID of the device
237 * @param portNum Port number of port to send probe out of
238 * @return ONOSLLDP probe message
239 */
240 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum) {
241 ONOSLLDP probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE);
242 probe.setPortId(portNum);
243 probe.setDevice(deviceId);
244 probe.setChassisId(chassisId);
245 return probe;
246 }
jaegonkim47b1b4a2017-12-04 14:08:26 +0900247
248 /**
249 * Creates a link probe for link discovery/verification.
250 *
251 * @param deviceId The device ID as a String
252 * @param chassisId The chassis ID of the device
253 * @param portNum Port number of port to send probe out of
254 * @param portDesc Port description of port to send probe out of
255 * @return ONOSLLDP probe message
256 */
257 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum, String portDesc) {
258
259 ONOSLLDP probe = onosLLDP(deviceId, chassisId, portNum);
260
261 if (portDesc != null && !portDesc.isEmpty()) {
262 byte[] bPortDesc = portDesc.getBytes(StandardCharsets.UTF_8);
263
264 if (bPortDesc.length > LLDPTLV.MAX_LENGTH) {
265 bPortDesc = Arrays.copyOf(bPortDesc, LLDPTLV.MAX_LENGTH);
266 }
267 LLDPTLV portDescTlv = new LLDPTLV()
268 .setType(PORT_DESC_TLV_TYPE)
269 .setLength((short) bPortDesc.length)
270 .setValue(bPortDesc);
271 probe.addOptionalTLV(portDescTlv);
272 }
273 return probe;
274 }
275
alshabib7911a052014-10-16 17:49:37 -0700276}