blob: f02552113bdba764a6417231e2fc414a570c0e90 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
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
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080018import java.util.HashMap;
19
alshabib7911a052014-10-16 17:49:37 -070020import com.google.common.collect.Lists;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080021import com.google.common.collect.Maps;
22
alshabib7911a052014-10-16 17:49:37 -070023import org.apache.commons.lang.ArrayUtils;
24
25import java.nio.ByteBuffer;
Ray Milkey241b96a2014-11-17 13:08:20 -080026import java.nio.charset.StandardCharsets;
alshabib7911a052014-10-16 17:49:37 -070027
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080028import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
29import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
30
alshabib7911a052014-10-16 17:49:37 -070031/**
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080032 * ONOS LLDP containing organizational TLV for ONOS device discovery.
alshabib7911a052014-10-16 17:49:37 -070033 */
34public class ONOSLLDP extends LLDP {
35
36 public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05};
37 public static final String DEFAULT_DEVICE = "INVALID";
38 public static final String DEFAULT_NAME = "ONOS Discovery";
39
40 public static final byte[] LLDP_NICIRA = {0x01, 0x23, 0x20, 0x00, 0x00,
41 0x01};
42 public static final byte[] LLDP_MULTICAST = {0x01, (byte) 0x80,
43 (byte) 0xc2, 0x00, 0x00, 0x0e};
44 public static final byte[] BDDP_MULTICAST = {(byte) 0xff, (byte) 0xff,
45 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
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;
50
51 private static final short NAME_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
52 private static final short DEVICE_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
53 private static final short DOMAIN_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
54
55 private final HashMap<Byte, LLDPOrganizationalTLV> opttlvs =
56 Maps.<Byte, LLDPOrganizationalTLV>newHashMap();
alshabib7911a052014-10-16 17:49:37 -070057
58 // TLV constants: type, size and subtype
59 // Organizationally specific TLV also have packet offset and contents of TLV
60 // header
61 private static final byte CHASSIS_TLV_TYPE = 1;
62 private static final byte CHASSIS_TLV_SIZE = 7;
63 private static final byte CHASSIS_TLV_SUBTYPE = 4;
64
65 private static final byte PORT_TLV_TYPE = 2;
66 private static final byte PORT_TLV_SIZE = 5;
67 private static final byte PORT_TLV_SUBTYPE = 2;
68
69 private static final byte TTL_TLV_TYPE = 3;
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 Milkeyb7f0f642016-01-22 16:08:14 -080074 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
85 setOptionalTLVList(Lists.<LLDPTLV>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);
103 nametlv.setOUI(ONLAB_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);
111 devicetlv.setOUI(ONLAB_OUI);
112 }
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);
123 domaintlv.setOUI(ONLAB_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) {
139 byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
140 ByteBuffer.allocate(4).putInt(portNumber).array());
141
142 LLDPTLV portTLV = new LLDPTLV();
143 portTLV.setLength(PORT_TLV_SIZE);
144 portTLV.setType(PORT_TLV_TYPE);
145 portTLV.setValue(port);
146 this.setPortId(portTLV);
147 }
148
149 public LLDPOrganizationalTLV getNameTLV() {
150 for (LLDPTLV tlv : this.getOptionalTLVList()) {
151 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
152 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
153 if (orgTLV.getSubType() == NAME_SUBTYPE) {
154 return orgTLV;
155 }
156 }
157 }
158 return null;
159 }
160
161 public LLDPOrganizationalTLV getDeviceTLV() {
162 for (LLDPTLV tlv : this.getOptionalTLVList()) {
163 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
164 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
165 if (orgTLV.getSubType() == DEVICE_SUBTYPE) {
166 return orgTLV;
167 }
168 }
169 }
170 return null;
171 }
172
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800173 /**
174 * Gets the TLV associated with remote probing. This TLV will be null if
175 * remote probing is disabled.
176 *
177 * @return A TLV containing domain ID, or null.
178 */
179 public LLDPOrganizationalTLV getDomainTLV() {
180 for (LLDPTLV tlv : this.getOptionalTLVList()) {
181 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
182 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
183 if (orgTLV.getSubType() == DOMAIN_SUBTYPE) {
184 return orgTLV;
185 }
186 }
187 }
188 return null;
189 }
190
alshabib7911a052014-10-16 17:49:37 -0700191 public String getNameString() {
192 LLDPOrganizationalTLV tlv = getNameTLV();
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
199 public String getDeviceString() {
200 LLDPOrganizationalTLV tlv = getDeviceTLV();
201 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800202 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700203 }
204 return null;
205 }
206
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800207 public String getDomainString() {
208 LLDPOrganizationalTLV tlv = getDomainTLV();
209 if (tlv != null) {
210 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
211 }
212 return null;
213 }
214
alshabib7911a052014-10-16 17:49:37 -0700215 public Integer getPort() {
216 ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
217 portBB.position(1);
218 return portBB.getInt();
219 }
220
221 /**
222 * Given an ethernet packet, determines if this is an LLDP from
223 * ONOS and returns the device the LLDP came from.
224 * @param eth an ethernet packet
225 * @return a the lldp packet or null
226 */
227 public static ONOSLLDP parseONOSLLDP(Ethernet eth) {
228 if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
229 eth.getEtherType() == Ethernet.TYPE_BSN) {
230 ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload()); //(ONOSLLDP) eth.getPayload();
231 if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) {
232 return onosLldp;
233 }
234 }
235 return null;
236 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800237
238 /**
239 * Creates a link probe for link discovery/verification.
240 *
241 * @param deviceId The device ID as a String
242 * @param chassisId The chassis ID of the device
243 * @param portNum Port number of port to send probe out of
244 * @return ONOSLLDP probe message
245 */
246 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum) {
247 ONOSLLDP probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE);
248 probe.setPortId(portNum);
249 probe.setDevice(deviceId);
250 probe.setChassisId(chassisId);
251 return probe;
252 }
253
254 /**
255 * Creates a link probe carrying a fingerprint unique to the ONOS cluster managing
256 * link discovery/verification.
257 *
258 * @param deviceId The device ID as a String
259 * @param chassisId The chassis ID of the device
260 * @param portNum Port number of port to send probe out of
261 * @param domainId The cluster's fingerprint
262 * @return ONOSLLDP probe message
263 */
264 public static ONOSLLDP fingerprintedLLDP(
265 String deviceId, ChassisId chassisId, int portNum, String domainId) {
266 ONOSLLDP probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE, DOMAIN_SUBTYPE);
267 probe.setPortId(portNum);
268 probe.setDevice(deviceId);
269 probe.setChassisId(chassisId);
270 probe.setDomainInfo(domainId);
271 return probe;
272 }
alshabib7911a052014-10-16 17:49:37 -0700273}