1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # vim: tabstop=4 shiftwidth=4 softtabstop=4
23 from nose.tools import ok_, eq_, nottest
25 from ryu.ofproto import ether
26 from ryu.lib.packet import packet
27 from ryu.lib.packet import ethernet
28 from ryu.lib.packet import lldp
29 from ryu.lib import addrconv
31 LOG = logging.getLogger(__name__)
34 class TestLLDPMandatoryTLV(unittest.TestCase):
36 # sample data is based on:
37 # http://wiki.wireshark.org/LinkLayerDiscoveryProtocol
40 self.data = b'\x01\x80\xc2\x00\x00\x0e\x00\x04' \
41 + b'\x96\x1f\xa7\x26\x88\xcc\x02\x07' \
42 + b'\x04\x00\x04\x96\x1f\xa7\x26\x04' \
43 + b'\x04\x05\x31\x2f\x33\x06\x02\x00' \
49 def test_get_tlv_type(self):
50 buf = b'\x02\x07\x04\x00\x04\x96\x1f\xa7\x26'
51 eq_(lldp.LLDPBasicTLV.get_type(buf), lldp.LLDP_TLV_CHASSIS_ID)
53 def test_parse_without_ethernet(self):
54 buf = self.data[ethernet.ethernet._MIN_LEN:]
55 (lldp_pkt, cls, rest_buf) = lldp.lldp.parser(buf)
59 eq_(tlvs[0].tlv_type, lldp.LLDP_TLV_CHASSIS_ID)
61 eq_(tlvs[0].subtype, lldp.ChassisID.SUB_MAC_ADDRESS)
62 eq_(tlvs[0].chassis_id, b'\x00\x04\x96\x1f\xa7\x26')
63 eq_(tlvs[1].tlv_type, lldp.LLDP_TLV_PORT_ID)
65 eq_(tlvs[1].subtype, lldp.PortID.SUB_INTERFACE_NAME)
66 eq_(tlvs[1].port_id, b'1/3')
67 eq_(tlvs[2].tlv_type, lldp.LLDP_TLV_TTL)
70 eq_(tlvs[3].tlv_type, lldp.LLDP_TLV_END)
74 pkt = packet.Packet(buf)
77 eq_(type(next(i)), ethernet.ethernet)
78 eq_(type(next(i)), lldp.lldp)
81 tlv = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
82 chassis_id=b'\x00\x04\x96\x1f\xa7\x26')
83 eq_(tlv.tlv_type, lldp.LLDP_TLV_CHASSIS_ID)
85 (typelen, ) = struct.unpack('!H', b'\x02\x07')
86 eq_(tlv.typelen, typelen)
88 def test_serialize_without_ethernet(self):
89 tlv_chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
90 chassis_id=b'\x00\x04\x96\x1f\xa7\x26')
91 tlv_port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
93 tlv_ttl = lldp.TTL(ttl=120)
95 tlvs = (tlv_chassis_id, tlv_port_id, tlv_ttl, tlv_end)
96 lldp_pkt = lldp.lldp(tlvs)
98 eq_(lldp_pkt.serialize(None, None),
99 self.data[ethernet.ethernet._MIN_LEN:])
101 def test_serialize(self):
102 pkt = packet.Packet()
104 dst = lldp.LLDP_MAC_NEAREST_BRIDGE
105 src = '00:04:96:1f:a7:26'
106 ethertype = ether.ETH_TYPE_LLDP
107 eth_pkt = ethernet.ethernet(dst, src, ethertype)
108 pkt.add_protocol(eth_pkt)
110 tlv_chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
111 chassis_id=addrconv.mac.
113 tlv_port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
115 tlv_ttl = lldp.TTL(ttl=120)
117 tlvs = (tlv_chassis_id, tlv_port_id, tlv_ttl, tlv_end)
118 lldp_pkt = lldp.lldp(tlvs)
119 pkt.add_protocol(lldp_pkt)
121 eq_(len(pkt.protocols), 2)
125 # Note: If ethernet frame is less than 60 bytes length,
126 # ethernet.ethernet() appends padding to the payload.
127 # So, we splits the serialized data to compare.
128 data_len = len(self.data)
129 pkt_data_lldp = pkt.data[:data_len]
130 pkt_data_pad = pkt.data[data_len:]
131 eq_(b'\x00' * (60 - data_len), pkt_data_pad)
133 eq_(self.data, pkt_data_lldp)
135 def test_to_string(self):
136 chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
137 chassis_id=b'\x00\x04\x96\x1f\xa7\x26')
138 port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
140 ttl = lldp.TTL(ttl=120)
142 tlvs = (chassis_id, port_id, ttl, end)
143 lldp_pkt = lldp.lldp(tlvs)
145 chassis_id_values = {'subtype': lldp.ChassisID.SUB_MAC_ADDRESS,
146 'chassis_id': b'\x00\x04\x96\x1f\xa7\x26',
147 'len': chassis_id.len,
148 'typelen': chassis_id.typelen}
149 _ch_id_str = ','.join(['%s=%s' % (k, repr(chassis_id_values[k]))
150 for k, v in inspect.getmembers(chassis_id)
151 if k in chassis_id_values])
152 tlv_chassis_id_str = '%s(%s)' % (lldp.ChassisID.__name__, _ch_id_str)
154 port_id_values = {'subtype': port_id.subtype,
155 'port_id': port_id.port_id,
157 'typelen': port_id.typelen}
158 _port_id_str = ','.join(['%s=%s' % (k, repr(port_id_values[k]))
159 for k, v in inspect.getmembers(port_id)
160 if k in port_id_values])
161 tlv_port_id_str = '%s(%s)' % (lldp.PortID.__name__, _port_id_str)
163 ttl_values = {'ttl': ttl.ttl,
165 'typelen': ttl.typelen}
166 _ttl_str = ','.join(['%s=%s' % (k, repr(ttl_values[k]))
167 for k, v in inspect.getmembers(ttl)
169 tlv_ttl_str = '%s(%s)' % (lldp.TTL.__name__, _ttl_str)
171 end_values = {'len': end.len,
172 'typelen': end.typelen}
173 _end_str = ','.join(['%s=%s' % (k, repr(end_values[k]))
174 for k, v in inspect.getmembers(end)
176 tlv_end_str = '%s(%s)' % (lldp.End.__name__, _end_str)
178 _tlvs_str = '(%s, %s, %s, %s)'
179 tlvs_str = _tlvs_str % (tlv_chassis_id_str,
184 _lldp_str = '%s(tlvs=%s)'
185 lldp_str = _lldp_str % (lldp.lldp.__name__,
188 eq_(str(lldp_pkt), lldp_str)
189 eq_(repr(lldp_pkt), lldp_str)
192 chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
193 chassis_id=b'\x00\x04\x96\x1f\xa7\x26')
194 port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
196 ttl = lldp.TTL(ttl=120)
198 tlvs = (chassis_id, port_id, ttl, end)
199 lldp1 = lldp.lldp(tlvs)
200 jsondict = lldp1.to_jsondict()
201 lldp2 = lldp.lldp.from_jsondict(jsondict['lldp'])
202 eq_(str(lldp1), str(lldp2))
205 class TestLLDPOptionalTLV(unittest.TestCase):
207 # sample data is based on:
208 # http://wiki.wireshark.org/LinkLayerDiscoveryProtocol
210 # include optional TLV
211 self.data = b'\x01\x80\xc2\x00\x00\x0e\x00\x01' \
212 + b'\x30\xf9\xad\xa0\x88\xcc\x02\x07' \
213 + b'\x04\x00\x01\x30\xf9\xad\xa0\x04' \
214 + b'\x04\x05\x31\x2f\x31\x06\x02\x00' \
215 + b'\x78\x08\x17\x53\x75\x6d\x6d\x69' \
216 + b'\x74\x33\x30\x30\x2d\x34\x38\x2d' \
217 + b'\x50\x6f\x72\x74\x20\x31\x30\x30' \
218 + b'\x31\x00\x0a\x0d\x53\x75\x6d\x6d' \
219 + b'\x69\x74\x33\x30\x30\x2d\x34\x38' \
220 + b'\x00\x0c\x4c\x53\x75\x6d\x6d\x69' \
221 + b'\x74\x33\x30\x30\x2d\x34\x38\x20' \
222 + b'\x2d\x20\x56\x65\x72\x73\x69\x6f' \
223 + b'\x6e\x20\x37\x2e\x34\x65\x2e\x31' \
224 + b'\x20\x28\x42\x75\x69\x6c\x64\x20' \
225 + b'\x35\x29\x20\x62\x79\x20\x52\x65' \
226 + b'\x6c\x65\x61\x73\x65\x5f\x4d\x61' \
227 + b'\x73\x74\x65\x72\x20\x30\x35\x2f' \
228 + b'\x32\x37\x2f\x30\x35\x20\x30\x34' \
229 + b'\x3a\x35\x33\x3a\x31\x31\x00\x0e' \
230 + b'\x04\x00\x14\x00\x14\x10\x0e\x07' \
231 + b'\x06\x00\x01\x30\xf9\xad\xa0\x02' \
232 + b'\x00\x00\x03\xe9\x00\xfe\x07\x00' \
233 + b'\x12\x0f\x02\x07\x01\x00\xfe\x09' \
234 + b'\x00\x12\x0f\x01\x03\x6c\x00\x00' \
235 + b'\x10\xfe\x09\x00\x12\x0f\x03\x01' \
236 + b'\x00\x00\x00\x00\xfe\x06\x00\x12' \
237 + b'\x0f\x04\x05\xf2\xfe\x06\x00\x80' \
238 + b'\xc2\x01\x01\xe8\xfe\x07\x00\x80' \
239 + b'\xc2\x02\x01\x00\x00\xfe\x17\x00' \
240 + b'\x80\xc2\x03\x01\xe8\x10\x76\x32' \
241 + b'\x2d\x30\x34\x38\x38\x2d\x30\x33' \
242 + b'\x2d\x30\x35\x30\x35\x00\xfe\x05' \
243 + b'\x00\x80\xc2\x04\x00\x00\x00'
248 def test_parse(self):
250 pkt = packet.Packet(buf)
253 eq_(type(next(i)), ethernet.ethernet)
255 eq_(type(lldp_pkt), lldp.lldp)
260 eq_(tlvs[3].tlv_type, lldp.LLDP_TLV_PORT_DESCRIPTION)
261 eq_(tlvs[3].port_description, b'Summit300-48-Port 1001\x00')
264 eq_(tlvs[4].tlv_type, lldp.LLDP_TLV_SYSTEM_NAME)
265 eq_(tlvs[4].system_name, b'Summit300-48\x00')
269 eq_(tlvs[5].tlv_type, lldp.LLDP_TLV_SYSTEM_DESCRIPTION)
270 eq_(tlvs[5].system_description,
271 b'Summit300-48 - Version 7.4e.1 (Build 5) '
272 + b'by Release_Master 05/27/05 04:53:11\x00')
275 eq_(tlvs[6].tlv_type, lldp.LLDP_TLV_SYSTEM_CAPABILITIES)
276 eq_(tlvs[6].system_cap & lldp.SystemCapabilities.CAP_MAC_BRIDGE,
277 lldp.SystemCapabilities.CAP_MAC_BRIDGE)
278 eq_(tlvs[6].enabled_cap & lldp.SystemCapabilities.CAP_MAC_BRIDGE,
279 lldp.SystemCapabilities.CAP_MAC_BRIDGE)
280 eq_(tlvs[6].system_cap & lldp.SystemCapabilities.CAP_TELEPHONE, 0)
281 eq_(tlvs[6].enabled_cap & lldp.SystemCapabilities.CAP_TELEPHONE, 0)
284 eq_(tlvs[7].tlv_type, lldp.LLDP_TLV_MANAGEMENT_ADDRESS)
285 eq_(tlvs[7].addr_len, 7)
286 eq_(tlvs[7].addr, b'\x00\x01\x30\xf9\xad\xa0')
287 eq_(tlvs[7].intf_num, 1001)
289 # Organizationally Specific
290 eq_(tlvs[8].tlv_type, lldp.LLDP_TLV_ORGANIZATIONALLY_SPECIFIC)
291 eq_(tlvs[8].oui, b'\x00\x12\x0f') # IEEE 802.3
292 eq_(tlvs[8].subtype, 0x02) # Power Via MDI
295 eq_(tlvs[16].tlv_type, lldp.LLDP_TLV_END)
297 def test_parse_corrupted(self):
299 pkt = packet.Packet(buf[:128])
301 def test_serialize(self):
302 pkt = packet.Packet()
304 dst = lldp.LLDP_MAC_NEAREST_BRIDGE
305 src = '00:01:30:f9:ad:a0'
306 ethertype = ether.ETH_TYPE_LLDP
307 eth_pkt = ethernet.ethernet(dst, src, ethertype)
308 pkt.add_protocol(eth_pkt)
310 tlv_chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
311 chassis_id=addrconv.mac.
313 tlv_port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
315 tlv_ttl = lldp.TTL(ttl=120)
316 tlv_port_description = lldp.PortDescription(
317 port_description=b'Summit300-48-Port 1001\x00')
318 tlv_system_name = lldp.SystemName(system_name=b'Summit300-48\x00')
319 tlv_system_description = lldp.SystemDescription(
320 system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) '
321 + b'by Release_Master 05/27/05 04:53:11\x00')
322 tlv_system_capabilities = lldp.SystemCapabilities(
325 tlv_management_address = lldp.ManagementAddress(
326 addr_subtype=0x06, addr=b'\x00\x01\x30\xf9\xad\xa0',
327 intf_subtype=0x02, intf_num=1001,
329 tlv_organizationally_specific = lldp.OrganizationallySpecific(
330 oui=b'\x00\x12\x0f', subtype=0x02, info=b'\x07\x01\x00')
332 tlvs = (tlv_chassis_id, tlv_port_id, tlv_ttl, tlv_port_description,
333 tlv_system_name, tlv_system_description,
334 tlv_system_capabilities, tlv_management_address,
335 tlv_organizationally_specific, tlv_end)
336 lldp_pkt = lldp.lldp(tlvs)
337 pkt.add_protocol(lldp_pkt)
339 eq_(len(pkt.protocols), 2)
343 # self.data has many organizationally specific TLVs
344 data = six.binary_type(pkt.data[:-2])
345 eq_(data, self.data[:len(data)])
347 def test_to_string(self):
348 chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
349 chassis_id=b'\x00\x01\x30\xf9\xad\xa0')
350 port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
352 ttl = lldp.TTL(ttl=120)
353 port_desc = lldp.PortDescription(
354 port_description=b'Summit300-48-Port 1001\x00')
355 sys_name = lldp.SystemName(system_name=b'Summit300-48\x00')
356 sys_desc = lldp.SystemDescription(
357 system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) '
358 + b'by Release_Master 05/27/05 04:53:11\x00')
359 sys_cap = lldp.SystemCapabilities(
362 man_addr = lldp.ManagementAddress(
363 addr_subtype=0x06, addr=b'\x00\x01\x30\xf9\xad\xa0',
364 intf_subtype=0x02, intf_num=1001,
366 org_spec = lldp.OrganizationallySpecific(
367 oui=b'\x00\x12\x0f', subtype=0x02, info=b'\x07\x01\x00')
369 tlvs = (chassis_id, port_id, ttl, port_desc, sys_name,
370 sys_desc, sys_cap, man_addr, org_spec, end)
371 lldp_pkt = lldp.lldp(tlvs)
374 chassis_id_values = {'subtype': lldp.ChassisID.SUB_MAC_ADDRESS,
375 'chassis_id': b'\x00\x01\x30\xf9\xad\xa0',
376 'len': chassis_id.len,
377 'typelen': chassis_id.typelen}
378 _ch_id_str = ','.join(['%s=%s' % (k, repr(chassis_id_values[k]))
379 for k, v in inspect.getmembers(chassis_id)
380 if k in chassis_id_values])
381 tlv_chassis_id_str = '%s(%s)' % (lldp.ChassisID.__name__, _ch_id_str)
384 port_id_values = {'subtype': port_id.subtype,
385 'port_id': port_id.port_id,
387 'typelen': port_id.typelen}
388 _port_id_str = ','.join(['%s=%s' % (k, repr(port_id_values[k]))
389 for k, v in inspect.getmembers(port_id)
390 if k in port_id_values])
391 tlv_port_id_str = '%s(%s)' % (lldp.PortID.__name__, _port_id_str)
394 ttl_values = {'ttl': ttl.ttl,
396 'typelen': ttl.typelen}
397 _ttl_str = ','.join(['%s=%s' % (k, repr(ttl_values[k]))
398 for k, v in inspect.getmembers(ttl)
400 tlv_ttl_str = '%s(%s)' % (lldp.TTL.__name__, _ttl_str)
402 # PortDescription string
403 port_desc_values = {'tlv_info': port_desc.tlv_info,
404 'len': port_desc.len,
405 'typelen': port_desc.typelen}
406 _port_desc_str = ','.join(['%s=%s' % (k, repr(port_desc_values[k]))
407 for k, v in inspect.getmembers(port_desc)
408 if k in port_desc_values])
409 tlv_port_desc_str = '%s(%s)' % (lldp.PortDescription.__name__,
413 sys_name_values = {'tlv_info': sys_name.tlv_info,
415 'typelen': sys_name.typelen}
416 _system_name_str = ','.join(['%s=%s' % (k, repr(sys_name_values[k]))
417 for k, v in inspect.getmembers(sys_name)
418 if k in sys_name_values])
419 tlv_system_name_str = '%s(%s)' % (lldp.SystemName.__name__,
422 # SystemDescription string
423 sys_desc_values = {'tlv_info': sys_desc.tlv_info,
425 'typelen': sys_desc.typelen}
426 _sys_desc_str = ','.join(['%s=%s' % (k, repr(sys_desc_values[k]))
427 for k, v in inspect.getmembers(sys_desc)
428 if k in sys_desc_values])
429 tlv_sys_desc_str = '%s(%s)' % (lldp.SystemDescription.__name__,
432 # SystemCapabilities string
433 sys_cap_values = {'system_cap': 0x14,
436 'typelen': sys_cap.typelen}
437 _sys_cap_str = ','.join(['%s=%s' % (k, repr(sys_cap_values[k]))
438 for k, v in inspect.getmembers(sys_cap)
439 if k in sys_cap_values])
440 tlv_sys_cap_str = '%s(%s)' % (lldp.SystemCapabilities.__name__,
443 # ManagementAddress string
444 man_addr_values = {'addr_subtype': 0x06,
445 'addr': b'\x00\x01\x30\xf9\xad\xa0',
446 'addr_len': man_addr.addr_len,
447 'intf_subtype': 0x02,
450 'oid_len': man_addr.oid_len,
452 'typelen': man_addr.typelen}
453 _man_addr_str = ','.join(['%s=%s' % (k, repr(man_addr_values[k]))
454 for k, v in inspect.getmembers(man_addr)
455 if k in man_addr_values])
456 tlv_man_addr_str = '%s(%s)' % (lldp.ManagementAddress.__name__,
459 # OrganizationallySpecific string
460 org_spec_values = {'oui': b'\x00\x12\x0f',
462 'info': b'\x07\x01\x00',
464 'typelen': org_spec.typelen}
465 _org_spec_str = ','.join(['%s=%s' % (k, repr(org_spec_values[k]))
466 for k, v in inspect.getmembers(org_spec)
467 if k in org_spec_values])
468 tlv_org_spec_str = '%s(%s)' % (lldp.OrganizationallySpecific.__name__,
472 end_values = {'len': end.len,
473 'typelen': end.typelen}
474 _end_str = ','.join(['%s=%s' % (k, repr(end_values[k]))
475 for k, v in inspect.getmembers(end)
477 tlv_end_str = '%s(%s)' % (lldp.End.__name__, _end_str)
480 _tlvs_str = '(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'
481 tlvs_str = _tlvs_str % (tlv_chassis_id_str,
493 _lldp_str = '%s(tlvs=%s)'
494 lldp_str = _lldp_str % (lldp.lldp.__name__,
497 eq_(str(lldp_pkt), lldp_str)
498 eq_(repr(lldp_pkt), lldp_str)
501 chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
502 chassis_id=b'\x00\x01\x30\xf9\xad\xa0')
503 port_id = lldp.PortID(subtype=lldp.PortID.SUB_INTERFACE_NAME,
505 ttl = lldp.TTL(ttl=120)
506 port_desc = lldp.PortDescription(
507 port_description=b'Summit300-48-Port 1001\x00')
508 sys_name = lldp.SystemName(system_name=b'Summit300-48\x00')
509 sys_desc = lldp.SystemDescription(
510 system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) '
511 + b'by Release_Master 05/27/05 04:53:11\x00')
512 sys_cap = lldp.SystemCapabilities(
515 man_addr = lldp.ManagementAddress(
516 addr_subtype=0x06, addr=b'\x00\x01\x30\xf9\xad\xa0',
517 intf_subtype=0x02, intf_num=1001,
519 org_spec = lldp.OrganizationallySpecific(
520 oui=b'\x00\x12\x0f', subtype=0x02, info=b'\x07\x01\x00')
522 tlvs = (chassis_id, port_id, ttl, port_desc, sys_name,
523 sys_desc, sys_cap, man_addr, org_spec, end)
524 lldp1 = lldp.lldp(tlvs)
525 jsondict = lldp1.to_jsondict()
526 lldp2 = lldp.lldp.from_jsondict(jsondict['lldp'])
527 eq_(str(lldp1), str(lldp2))