backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / lldp.py
1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2012 Isaku Yamahata <yamahata at private email ne jp>
3 #
4 # 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
7 #
8 #    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
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 """
18 Link Layer Discovery Protocol(LLDP, IEEE 802.1AB)
19 http://standards.ieee.org/getieee802/download/802.1AB-2009.pdf
20
21
22 basic TLV format::
23
24     octets | 1          | 2             | 3 ...             n + 2 |
25            --------------------------------------------------------
26            | TLV type | TLV information | TLV information string  |
27            | (7bits)  | string length   | (0-507 octets)          |
28            |          | (9bits)         |                         |
29            --------------------------------------------------------
30     bits   |8        2|1|8             1|
31
32
33 Organizationally specific TLV format::
34
35     octets | 1          | 2        | 3 ...  5 | 6       | 7 ...    n + 6 |
36            ---------------------------------------------------------------
37            | TLV type | Length     | OUI      | Subtype | Infomation     |
38            | (7bits)  | (9bits)    | (24bits) | (8bits) | (0-507 octets) |
39            ---------------------------------------------------------------
40     bits   |8        2|1|8        1|
41
42
43 LLDPDU format::
44
45     ------------------------------------------------------------------------
46     | Chassis ID | Port ID | TTL | optional TLV | ... | optional TLV | End |
47     ------------------------------------------------------------------------
48
49 Chasis ID, Port ID, TTL, End are mandatory
50 optional TLV may be inserted in any order
51 """
52
53 import struct
54 from ryu.lib import stringify
55 from ryu.lib.packet import packet_base
56
57
58 # LLDP destination MAC address
59 LLDP_MAC_NEAREST_BRIDGE = '01:80:c2:00:00:0e'
60 LLDP_MAC_NEAREST_NON_TPMR_BRIDGE = '01:80:c2:00:00:03'
61 LLDP_MAC_NEAREST_CUSTOMER_BRIDGE = '01:80:c2:00:00:00'
62
63
64 LLDP_TLV_TYPELEN_STR = '!H'
65 LLDP_TLV_SIZE = 2
66 LLDP_TLV_TYPE_MASK = 0xfe00
67 LLDP_TLV_TYPE_SHIFT = 9
68 LLDP_TLV_LENGTH_MASK = 0x01ff
69
70
71 # LLDP TLV type
72 LLDP_TLV_END = 0                        # End of LLDPDU
73 LLDP_TLV_CHASSIS_ID = 1                 # Chassis ID
74 LLDP_TLV_PORT_ID = 2                    # Port ID
75 LLDP_TLV_TTL = 3                        # Time To Live
76 LLDP_TLV_PORT_DESCRIPTION = 4           # Port Description
77 LLDP_TLV_SYSTEM_NAME = 5                # System Name
78 LLDP_TLV_SYSTEM_DESCRIPTION = 6         # System Description
79 LLDP_TLV_SYSTEM_CAPABILITIES = 7        # System Capabilities
80 LLDP_TLV_MANAGEMENT_ADDRESS = 8         # Management Address
81 LLDP_TLV_ORGANIZATIONALLY_SPECIFIC = 127  # organizationally Specific TLVs
82
83
84 class LLDPBasicTLV(stringify.StringifyMixin):
85     _LEN_MIN = 0
86     _LEN_MAX = 511
87     tlv_type = None
88
89     def __init__(self, buf=None, *_args, **_kwargs):
90         super(LLDPBasicTLV, self).__init__()
91         if buf:
92             (self.typelen, ) = struct.unpack(
93                 LLDP_TLV_TYPELEN_STR, buf[:LLDP_TLV_SIZE])
94             tlv_type = \
95                 (self.typelen & LLDP_TLV_TYPE_MASK) >> LLDP_TLV_TYPE_SHIFT
96             assert self.tlv_type == tlv_type
97
98             self.len = self.typelen & LLDP_TLV_LENGTH_MASK
99             assert len(buf) >= self.len + LLDP_TLV_SIZE
100
101             self.tlv_info = buf[LLDP_TLV_SIZE:]
102             self.tlv_info = self.tlv_info[:self.len]
103
104     @staticmethod
105     def get_type(buf):
106         (typelen, ) = struct.unpack(LLDP_TLV_TYPELEN_STR, buf[:LLDP_TLV_SIZE])
107         return (typelen & LLDP_TLV_TYPE_MASK) >> LLDP_TLV_TYPE_SHIFT
108
109     @staticmethod
110     def set_tlv_type(subcls, tlv_type):
111         assert issubclass(subcls, LLDPBasicTLV)
112         subcls.tlv_type = tlv_type
113
114     def _len_valid(self):
115         return self._LEN_MIN <= self.len and self.len <= self._LEN_MAX
116
117
118 class lldp(packet_base.PacketBase):
119     """LLDPDU encoder/decoder class.
120
121     An instance has the following attributes at least.
122
123     ============== =====================================
124     Attribute      Description
125     ============== =====================================
126     tlvs           List of TLV instance.
127     ============== =====================================
128     """
129     _tlv_parsers = {}
130
131     def __init__(self, tlvs):
132         super(lldp, self).__init__()
133         self.tlvs = tlvs
134
135     # at least it must have chassis id, port id, ttl and end
136     def _tlvs_len_valid(self):
137         return len(self.tlvs) >= 4
138
139     # chassis id, port id, ttl and end
140     def _tlvs_valid(self):
141         return (self.tlvs[0].tlv_type == LLDP_TLV_CHASSIS_ID and
142                 self.tlvs[1].tlv_type == LLDP_TLV_PORT_ID and
143                 self.tlvs[2].tlv_type == LLDP_TLV_TTL and
144                 self.tlvs[-1].tlv_type == LLDP_TLV_END)
145
146     @classmethod
147     def _parser(cls, buf):
148         tlvs = []
149
150         while buf:
151             tlv_type = LLDPBasicTLV.get_type(buf)
152             tlv = cls._tlv_parsers[tlv_type](buf)
153             tlvs.append(tlv)
154             offset = LLDP_TLV_SIZE + tlv.len
155             buf = buf[offset:]
156             if tlv.tlv_type == LLDP_TLV_END:
157                 break
158             assert len(buf) > 0
159
160         lldp_pkt = cls(tlvs)
161
162         assert lldp_pkt._tlvs_len_valid()
163         assert lldp_pkt._tlvs_valid()
164
165         return lldp_pkt, None, buf
166
167     @classmethod
168     def parser(cls, buf):
169         try:
170             return cls._parser(buf)
171         except:
172             return None, None, buf
173
174     def serialize(self, payload, prev):
175         data = bytearray()
176         for tlv in self.tlvs:
177             data += tlv.serialize()
178
179         return data
180
181     @classmethod
182     def set_type(cls, tlv_cls):
183         cls._tlv_parsers[tlv_cls.tlv_type] = tlv_cls
184
185     @classmethod
186     def get_type(cls, tlv_type):
187         return cls._tlv_parsers[tlv_type]
188
189     @classmethod
190     def set_tlv_type(cls, tlv_type):
191         def _set_type(tlv_cls):
192             tlv_cls.set_tlv_type(tlv_cls, tlv_type)
193             cls.set_type(tlv_cls)
194             return tlv_cls
195         return _set_type
196
197     def __len__(self):
198         return sum(LLDP_TLV_SIZE + tlv.len for tlv in self.tlvs)
199
200
201 @lldp.set_tlv_type(LLDP_TLV_END)
202 class End(LLDPBasicTLV):
203     """End TLV encoder/decoder class
204
205     ============== =====================================
206     Attribute      Description
207     ============== =====================================
208     buf            Binary data to parse.
209     ============== =====================================
210     """
211
212     def __init__(self, buf=None, *args, **kwargs):
213         super(End, self).__init__(buf, *args, **kwargs)
214         if buf:
215             pass
216         else:
217             self.len = 0
218             self.typelen = 0
219
220     def serialize(self):
221         return struct.pack('!H', self.typelen)
222
223
224 @lldp.set_tlv_type(LLDP_TLV_CHASSIS_ID)
225 class ChassisID(LLDPBasicTLV):
226     """Chassis ID TLV encoder/decoder class
227
228     ============== =====================================
229     Attribute      Description
230     ============== =====================================
231     buf            Binary data to parse.
232     subtype        Subtype.
233     chassis_id     Chassis id corresponding to subtype.
234     ============== =====================================
235     """
236
237     _PACK_STR = '!B'
238     _PACK_SIZE = struct.calcsize(_PACK_STR)
239     # subtype id(1 octet) + chassis id length(1 - 255 octet)
240     _LEN_MIN = 2
241     _LEN_MAX = 256
242
243     # Chassis ID subtype
244     SUB_CHASSIS_COMPONENT = 1   # EntPhysicalAlias (IETF RFC 4133)
245     SUB_INTERFACE_ALIAS = 2     # IfAlias (IETF RFC 2863)
246     SUB_PORT_COMPONENT = 3      # EntPhysicalAlias (IETF RFC 4133)
247     SUB_MAC_ADDRESS = 4         # MAC address (IEEE std 802)
248     SUB_NETWORK_ADDRESS = 5     # networkAddress
249     SUB_INTERFACE_NAME = 6      # IfName (IETF RFC 2863)
250     SUB_LOCALLY_ASSIGNED = 7    # local
251
252     def __init__(self, buf=None, *args, **kwargs):
253         super(ChassisID, self).__init__(buf, *args, **kwargs)
254         if buf:
255             (self.subtype, ) = struct.unpack(
256                 self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
257             self.chassis_id = self.tlv_info[self._PACK_SIZE:]
258         else:
259             self.subtype = kwargs['subtype']
260             self.chassis_id = kwargs['chassis_id']
261             self.len = self._PACK_SIZE + len(self.chassis_id)
262             assert self._len_valid()
263             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
264
265     def serialize(self):
266         return struct.pack('!HB', self.typelen, self.subtype) + self.chassis_id
267
268
269 @lldp.set_tlv_type(LLDP_TLV_PORT_ID)
270 class PortID(LLDPBasicTLV):
271     """Port ID TLV encoder/decoder class
272
273     ============== =====================================
274     Attribute      Description
275     ============== =====================================
276     buf            Binary data to parse.
277     subtype        Subtype.
278     port_id        Port ID corresponding to subtype.
279     ============== =====================================
280     """
281     _PACK_STR = '!B'
282     _PACK_SIZE = struct.calcsize(_PACK_STR)
283
284     # subtype id(1 octet) + port id length(1 - 255 octet)
285     _LEN_MIN = 2
286     _LEN_MAX = 256
287
288     # Port ID subtype
289     SUB_INTERFACE_ALIAS = 1     # ifAlias (IETF RFC 2863)
290     SUB_PORT_COMPONENT = 2      # entPhysicalAlias (IETF RFC 4133)
291     SUB_MAC_ADDRESS = 3         # MAC address (IEEE Std 802)
292     SUB_NETWORK_ADDRESS = 4     # networkAddress
293     SUB_INTERFACE_NAME = 5      # ifName (IETF RFC 2863)
294     SUB_AGENT_CIRCUIT_ID = 6    # agent circuit ID(IETF RFC 3046)
295     SUB_LOCALLY_ASSIGNED = 7    # local
296
297     def __init__(self, buf=None, *args, **kwargs):
298         super(PortID, self).__init__(buf, *args, **kwargs)
299         if buf:
300             (self.subtype, ) = struct.unpack(
301                 self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
302             self.port_id = self.tlv_info[self._PACK_SIZE:]
303         else:
304             self.subtype = kwargs['subtype']
305             self.port_id = kwargs['port_id']
306             self.len = self._PACK_SIZE + len(self.port_id)
307             assert self._len_valid()
308             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
309
310     def serialize(self):
311         return struct.pack('!HB', self.typelen, self.subtype) + self.port_id
312
313
314 @lldp.set_tlv_type(LLDP_TLV_TTL)
315 class TTL(LLDPBasicTLV):
316     """Time To Live TLV encoder/decoder class
317
318     ============== =====================================
319     Attribute      Description
320     ============== =====================================
321     buf            Binary data to parse.
322     ttl            Time To Live.
323     ============== =====================================
324     """
325     _PACK_STR = '!H'
326     _PACK_SIZE = struct.calcsize(_PACK_STR)
327     _LEN_MIN = _PACK_SIZE
328     _LEN_MAX = _PACK_SIZE
329
330     def __init__(self, buf=None, *args, **kwargs):
331         super(TTL, self).__init__(buf, *args, **kwargs)
332         if buf:
333             (self.ttl, ) = struct.unpack(
334                 self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
335         else:
336             self.ttl = kwargs['ttl']
337             self.len = self._PACK_SIZE
338             assert self._len_valid()
339             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
340
341     def serialize(self):
342         return struct.pack('!HH', self.typelen, self.ttl)
343
344
345 @lldp.set_tlv_type(LLDP_TLV_PORT_DESCRIPTION)
346 class PortDescription(LLDPBasicTLV):
347     """Port description TLV encoder/decoder class
348
349     ================= =====================================
350     Attribute         Description
351     ================= =====================================
352     buf               Binary data to parse.
353     port_description  Port description.
354     ================= =====================================
355     """
356     _LEN_MAX = 255
357
358     def __init__(self, buf=None, *args, **kwargs):
359         super(PortDescription, self).__init__(buf, *args, **kwargs)
360         if buf:
361             pass
362         else:
363             self.port_description = kwargs['port_description']
364             self.len = len(self.port_description)
365             assert self._len_valid()
366             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
367
368     def serialize(self):
369         return struct.pack('!H', self.typelen) + self.port_description
370
371     @property
372     def port_description(self):
373         return self.tlv_info
374
375     @port_description.setter
376     def port_description(self, value):
377         self.tlv_info = value
378
379
380 @lldp.set_tlv_type(LLDP_TLV_SYSTEM_NAME)
381 class SystemName(LLDPBasicTLV):
382     """System name TLV encoder/decoder class
383
384     ================= =====================================
385     Attribute         Description
386     ================= =====================================
387     buf               Binary data to parse.
388     system_name       System name.
389     ================= =====================================
390     """
391     _LEN_MAX = 255
392
393     def __init__(self, buf=None, *args, **kwargs):
394         super(SystemName, self).__init__(buf, *args, **kwargs)
395         if buf:
396             pass
397         else:
398             self.system_name = kwargs['system_name']
399             self.len = len(self.system_name)
400             assert self._len_valid()
401             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
402
403     def serialize(self):
404         return struct.pack('!H', self.typelen) + self.tlv_info
405
406     @property
407     def system_name(self):
408         return self.tlv_info
409
410     @system_name.setter
411     def system_name(self, value):
412         self.tlv_info = value
413
414
415 @lldp.set_tlv_type(LLDP_TLV_SYSTEM_DESCRIPTION)
416 class SystemDescription(LLDPBasicTLV):
417     """System description TLV encoder/decoder class
418
419     =================== =====================================
420     Attribute           Description
421     =================== =====================================
422     buf                 Binary data to parse.
423     system_description  System description.
424     =================== =====================================
425     """
426     _LEN_MAX = 255
427
428     def __init__(self, buf=None, *args, **kwargs):
429         super(SystemDescription, self).__init__(buf, *args, **kwargs)
430         if buf:
431             pass
432         else:
433             self.system_description = kwargs['system_description']
434             self.len = len(self.system_description)
435             assert self._len_valid()
436             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
437
438     def serialize(self):
439         return struct.pack('!H', self.typelen) + self.tlv_info
440
441     @property
442     def system_description(self):
443         return self.tlv_info
444
445     @system_description.setter
446     def system_description(self, value):
447         self.tlv_info = value
448
449
450 @lldp.set_tlv_type(LLDP_TLV_SYSTEM_CAPABILITIES)
451 class SystemCapabilities(LLDPBasicTLV):
452     """System Capabilities TLV encoder/decoder class
453
454     ================= =====================================
455     Attribute         Description
456     ================= =====================================
457     buf               Binary data to parse.
458     system_cap        System Capabilities.
459     enabled_cap       Enabled Capabilities.
460     ================= =====================================
461     """
462     # system cap(2) + enabled cap(2)
463     _PACK_STR = '!HH'
464     _PACK_SIZE = struct.calcsize(_PACK_STR)
465     _LEN_MIN = _PACK_SIZE
466     _LEN_MAX = _PACK_SIZE
467
468     # System Capabilities
469     CAP_REPEATER = (1 << 1)             # IETF RFC 2108
470     CAP_MAC_BRIDGE = (1 << 2)           # IEEE Std 802.1D
471     CAP_WLAN_ACCESS_POINT = (1 << 3)    # IEEE Std 802.11 MIB
472     CAP_ROUTER = (1 << 4)               # IETF RFC 1812
473     CAP_TELEPHONE = (1 << 5)            # IETF RFC 4293
474     CAP_DOCSIS = (1 << 6)               # IETF RFC 4639 and IETF RFC 4546
475     CAP_STATION_ONLY = (1 << 7)         # IETF RFC 4293
476     CAP_CVLAN = (1 << 8)                # IEEE Std 802.1Q
477     CAP_SVLAN = (1 << 9)                # IEEE Std 802.1Q
478     CAP_TPMR = (1 << 10)                # IEEE Std 802.1Q
479
480     def __init__(self, buf=None, *args, **kwargs):
481         super(SystemCapabilities, self).__init__(buf, *args, **kwargs)
482         if buf:
483             (self.system_cap, self.enabled_cap) = struct.unpack(
484                 self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
485         else:
486             self.system_cap = kwargs['system_cap']
487             self.enabled_cap = kwargs['enabled_cap']
488             self.len = self._PACK_SIZE
489             assert self._len_valid()
490             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
491
492     def serialize(self):
493         return struct.pack('!HHH',
494                            self.typelen, self.system_cap, self.enabled_cap)
495
496
497 @lldp.set_tlv_type(LLDP_TLV_MANAGEMENT_ADDRESS)
498 class ManagementAddress(LLDPBasicTLV):
499     """Management Address TLV encoder/decoder class
500
501     ================= =====================================
502     Attribute         Description
503     ================= =====================================
504     buf               Binary data to parse.
505     addr_subtype      Address type.
506     addr              Device address.
507     intf_subtype      Interface type.
508     intf_num          Interface number.
509     oid               Object ID.
510     ================= =====================================
511     """
512     _LEN_MIN = 9
513     _LEN_MAX = 167
514
515     _ADDR_PACK_STR = '!BB'    # address string length, address subtype
516     _ADDR_PACK_SIZE = struct.calcsize(_ADDR_PACK_STR)
517     _ADDR_LEN_MIN = 1
518     _ADDR_LEN_MAX = 31
519
520     _INTF_PACK_STR = '!BIB'   # interface subtype, interface number, oid length
521     _INTF_PACK_SIZE = struct.calcsize(_INTF_PACK_STR)
522     _OID_LEN_MIN = 0
523     _OID_LEN_MAX = 128
524
525     def __init__(self, buf=None, *args, **kwargs):
526         super(ManagementAddress, self).__init__(buf, *args, **kwargs)
527         if buf:
528             (self.addr_len, self.addr_subtype) = struct.unpack(
529                 self._ADDR_PACK_STR, self.tlv_info[:self._ADDR_PACK_SIZE])
530             assert self._addr_len_valid()
531             offset = self._ADDR_PACK_SIZE + self.addr_len - 1
532             self.addr = self.tlv_info[self._ADDR_PACK_SIZE:offset]
533
534             (self.intf_subtype, self.intf_num, self.oid_len) = struct.unpack(
535                 self._INTF_PACK_STR,
536                 self.tlv_info[offset:offset + self._INTF_PACK_SIZE])
537             assert self._oid_len_valid()
538
539             offset = offset + self._INTF_PACK_SIZE
540             self.oid = self.tlv_info[offset:]
541         else:
542             self.addr_subtype = kwargs['addr_subtype']
543             self.addr = kwargs['addr']
544             self.addr_len = len(self.addr) + 1  # 1 octet subtype
545             assert self._addr_len_valid()
546
547             self.intf_subtype = kwargs['intf_subtype']
548             self.intf_num = kwargs['intf_num']
549
550             self.oid = kwargs['oid']
551             self.oid_len = len(self.oid)
552             assert self._oid_len_valid()
553
554             self.len = self._ADDR_PACK_SIZE + self.addr_len - 1 \
555                 + self._INTF_PACK_SIZE + self.oid_len
556             assert self._len_valid()
557             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
558
559     def serialize(self):
560         tlv_info = struct.pack(self._ADDR_PACK_STR,
561                                self.addr_len, self.addr_subtype)
562         tlv_info += self.addr
563         tlv_info += struct.pack(self._INTF_PACK_STR,
564                                 self.intf_subtype, self.intf_num, self.oid_len)
565         tlv_info += self.oid
566         return struct.pack('!H', self.typelen) + tlv_info
567
568     def _addr_len_valid(self):
569         return (self._ADDR_LEN_MIN <= self.addr_len or
570                 self.addr_len <= self._ADDR_LEN_MAX)
571
572     def _oid_len_valid(self):
573         return self._OID_LEN_MIN <= self.oid_len <= self._OID_LEN_MAX
574
575
576 @lldp.set_tlv_type(LLDP_TLV_ORGANIZATIONALLY_SPECIFIC)
577 class OrganizationallySpecific(LLDPBasicTLV):
578     """Organizationally Specific TLV encoder/decoder class
579
580     ================= =============================================
581     Attribute         Description
582     ================= =============================================
583     buf               Binary data to parse.
584     oui               Organizationally unique ID.
585     subtype           Organizationally defined subtype.
586     info              Organizationally defined information string.
587     ================= =============================================
588     """
589     _PACK_STR = '!3sB'
590     _PACK_SIZE = struct.calcsize(_PACK_STR)
591     _LEN_MIN = _PACK_SIZE
592     _LEN_MAX = 511
593
594     def __init__(self, buf=None, *args, **kwargs):
595         super(OrganizationallySpecific, self).__init__(buf, *args, **kwargs)
596         if buf:
597             (self.oui, self.subtype) = struct.unpack(
598                 self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
599             self.info = self.tlv_info[self._PACK_SIZE:]
600         else:
601             self.oui = kwargs['oui']
602             self.subtype = kwargs['subtype']
603             self.info = kwargs['info']
604             self.len = self._PACK_SIZE + len(self.info)
605             assert self._len_valid()
606             self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len
607
608     def serialize(self):
609         return struct.pack('!H3sB', self.typelen, self.oui,
610                            self.subtype) + self.info
611
612
613 lldp.set_classes(lldp._tlv_parsers)