blob: f20de987408afdb255cf119ca06abcee92994908 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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
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;
Jonathan Hart7838c512016-06-07 15:18:22 -070024import java.util.HashMap;
alshabib7911a052014-10-16 17:49:37 -070025
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080026import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
27import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
28
alshabib7911a052014-10-16 17:49:37 -070029/**
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080030 * ONOS LLDP containing organizational TLV for ONOS device discovery.
alshabib7911a052014-10-16 17:49:37 -070031 */
32public class ONOSLLDP extends LLDP {
33
34 public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05};
35 public static final String DEFAULT_DEVICE = "INVALID";
36 public static final String DEFAULT_NAME = "ONOS Discovery";
37
Jonathan Hart7838c512016-06-07 15:18:22 -070038 // ON.Lab OUI (a42305) with multicast bit set
39 public static final byte[] LLDP_ONLAB = {(byte) 0xa5, 0x23, 0x05, 0x00, 0x00, 0x01};
alshabib7911a052014-10-16 17:49:37 -070040 public static final byte[] BDDP_MULTICAST = {(byte) 0xff, (byte) 0xff,
41 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
42
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080043 protected static final byte NAME_SUBTYPE = 1;
44 protected static final byte DEVICE_SUBTYPE = 2;
45 protected static final byte DOMAIN_SUBTYPE = 3;
46
47 private static final short NAME_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
48 private static final short DEVICE_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
49 private static final short DOMAIN_LENGTH = OUI_LENGTH + SUBTYPE_LENGTH;
50
Jonathan Hart7838c512016-06-07 15:18:22 -070051 private final HashMap<Byte, LLDPOrganizationalTLV> opttlvs = Maps.newHashMap();
alshabib7911a052014-10-16 17:49:37 -070052
53 // TLV constants: type, size and subtype
54 // Organizationally specific TLV also have packet offset and contents of TLV
55 // header
56 private static final byte CHASSIS_TLV_TYPE = 1;
57 private static final byte CHASSIS_TLV_SIZE = 7;
58 private static final byte CHASSIS_TLV_SUBTYPE = 4;
59
60 private static final byte PORT_TLV_TYPE = 2;
61 private static final byte PORT_TLV_SIZE = 5;
62 private static final byte PORT_TLV_SUBTYPE = 2;
63
64 private static final byte TTL_TLV_TYPE = 3;
65
alshabib7911a052014-10-16 17:49:37 -070066 private final byte[] ttlValue = new byte[] {0, 0x78};
67
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080068 // Only needs to be accessed from LinkProbeFactory.
Ray Milkeyb7f0f642016-01-22 16:08:14 -080069 public ONOSLLDP(byte ... subtype) {
alshabib7911a052014-10-16 17:49:37 -070070 super();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080071 for (byte st : subtype) {
72 opttlvs.put(st, new LLDPOrganizationalTLV());
73 }
74 // guarantee the following (name and device) TLVs exist
75 opttlvs.putIfAbsent(NAME_SUBTYPE, new LLDPOrganizationalTLV());
76 opttlvs.putIfAbsent(DEVICE_SUBTYPE, new LLDPOrganizationalTLV());
alshabib7911a052014-10-16 17:49:37 -070077 setName(DEFAULT_NAME);
78 setDevice(DEFAULT_DEVICE);
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080079
Jonathan Hart7838c512016-06-07 15:18:22 -070080 setOptionalTLVList(Lists.newArrayList(opttlvs.values()));
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080081 setTtl(new LLDPTLV().setType(TTL_TLV_TYPE)
alshabib7911a052014-10-16 17:49:37 -070082 .setLength((short) ttlValue.length)
83 .setValue(ttlValue));
alshabib7911a052014-10-16 17:49:37 -070084 }
85
86 private ONOSLLDP(LLDP lldp) {
87 this.portId = lldp.getPortId();
88 this.chassisId = lldp.getChassisId();
89 this.ttl = lldp.getTtl();
90 this.optionalTLVList = lldp.getOptionalTLVList();
91 }
92
93 public void setName(String name) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080094 LLDPOrganizationalTLV nametlv = opttlvs.get(NAME_SUBTYPE);
95 nametlv.setLength((short) (name.length() + NAME_LENGTH));
96 nametlv.setInfoString(name);
97 nametlv.setSubType(NAME_SUBTYPE);
98 nametlv.setOUI(ONLAB_OUI);
alshabib7911a052014-10-16 17:49:37 -070099 }
100
101 public void setDevice(String device) {
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800102 LLDPOrganizationalTLV devicetlv = opttlvs.get(DEVICE_SUBTYPE);
103 devicetlv.setInfoString(device);
104 devicetlv.setLength((short) (device.length() + DEVICE_LENGTH));
105 devicetlv.setSubType(DEVICE_SUBTYPE);
106 devicetlv.setOUI(ONLAB_OUI);
107 }
108
109 public void setDomainInfo(String domainId) {
110 LLDPOrganizationalTLV domaintlv = opttlvs.get(DOMAIN_SUBTYPE);
111 if (domaintlv == null) {
112 // maybe warn people not to set this if remote probes aren't.
113 return;
114 }
115 domaintlv.setInfoString(domainId);
116 domaintlv.setLength((short) (domainId.length() + DOMAIN_LENGTH));
117 domaintlv.setSubType(DOMAIN_SUBTYPE);
118 domaintlv.setOUI(ONLAB_OUI);
alshabib7911a052014-10-16 17:49:37 -0700119 }
120
121 public void setChassisId(final ChassisId chassisId) {
122 MacAddress chassisMac = MacAddress.valueOf(chassisId.value());
123 byte[] chassis = ArrayUtils.addAll(new byte[] {CHASSIS_TLV_SUBTYPE},
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800124 chassisMac.toBytes());
alshabib7911a052014-10-16 17:49:37 -0700125
126 LLDPTLV chassisTLV = new LLDPTLV();
127 chassisTLV.setLength(CHASSIS_TLV_SIZE);
128 chassisTLV.setType(CHASSIS_TLV_TYPE);
129 chassisTLV.setValue(chassis);
130 this.setChassisId(chassisTLV);
131 }
132
133 public void setPortId(final int portNumber) {
134 byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
135 ByteBuffer.allocate(4).putInt(portNumber).array());
136
137 LLDPTLV portTLV = new LLDPTLV();
138 portTLV.setLength(PORT_TLV_SIZE);
139 portTLV.setType(PORT_TLV_TYPE);
140 portTLV.setValue(port);
141 this.setPortId(portTLV);
142 }
143
144 public LLDPOrganizationalTLV getNameTLV() {
145 for (LLDPTLV tlv : this.getOptionalTLVList()) {
146 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
147 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
148 if (orgTLV.getSubType() == NAME_SUBTYPE) {
149 return orgTLV;
150 }
151 }
152 }
153 return null;
154 }
155
156 public LLDPOrganizationalTLV getDeviceTLV() {
157 for (LLDPTLV tlv : this.getOptionalTLVList()) {
158 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
159 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
160 if (orgTLV.getSubType() == DEVICE_SUBTYPE) {
161 return orgTLV;
162 }
163 }
164 }
165 return null;
166 }
167
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800168 /**
169 * Gets the TLV associated with remote probing. This TLV will be null if
170 * remote probing is disabled.
171 *
172 * @return A TLV containing domain ID, or null.
173 */
174 public LLDPOrganizationalTLV getDomainTLV() {
175 for (LLDPTLV tlv : this.getOptionalTLVList()) {
176 if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
177 LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
178 if (orgTLV.getSubType() == DOMAIN_SUBTYPE) {
179 return orgTLV;
180 }
181 }
182 }
183 return null;
184 }
185
alshabib7911a052014-10-16 17:49:37 -0700186 public String getNameString() {
187 LLDPOrganizationalTLV tlv = getNameTLV();
188 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800189 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700190 }
191 return null;
192 }
193
194 public String getDeviceString() {
195 LLDPOrganizationalTLV tlv = getDeviceTLV();
196 if (tlv != null) {
Ray Milkey241b96a2014-11-17 13:08:20 -0800197 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
alshabib7911a052014-10-16 17:49:37 -0700198 }
199 return null;
200 }
201
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800202 public String getDomainString() {
203 LLDPOrganizationalTLV tlv = getDomainTLV();
204 if (tlv != null) {
205 return new String(tlv.getInfoString(), StandardCharsets.UTF_8);
206 }
207 return null;
208 }
209
alshabib7911a052014-10-16 17:49:37 -0700210 public Integer getPort() {
211 ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
212 portBB.position(1);
213 return portBB.getInt();
214 }
215
216 /**
217 * Given an ethernet packet, determines if this is an LLDP from
218 * ONOS and returns the device the LLDP came from.
219 * @param eth an ethernet packet
220 * @return a the lldp packet or null
221 */
222 public static ONOSLLDP parseONOSLLDP(Ethernet eth) {
223 if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
224 eth.getEtherType() == Ethernet.TYPE_BSN) {
Jonathan Hart7838c512016-06-07 15:18:22 -0700225 ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload());
alshabib7911a052014-10-16 17:49:37 -0700226 if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) {
227 return onosLldp;
228 }
229 }
230 return null;
231 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800232
233 /**
234 * Creates a link probe for link discovery/verification.
235 *
236 * @param deviceId The device ID as a String
237 * @param chassisId The chassis ID of the device
238 * @param portNum Port number of port to send probe out of
239 * @return ONOSLLDP probe message
240 */
241 public static ONOSLLDP onosLLDP(String deviceId, ChassisId chassisId, int portNum) {
242 ONOSLLDP probe = new ONOSLLDP(NAME_SUBTYPE, DEVICE_SUBTYPE);
243 probe.setPortId(portNum);
244 probe.setDevice(deviceId);
245 probe.setChassisId(chassisId);
246 return probe;
247 }
alshabib7911a052014-10-16 17:49:37 -0700248}