1import struct
2from socket import inet_ntop
3from socket import inet_pton
4from socket import AF_UNSPEC
5from socket import AF_INET
6from socket import AF_INET6
7from pr2modules.common import AF_MPLS
8from pr2modules.common import hexdump
9from pr2modules.common import map_namespace
10from pr2modules.netlink import nlmsg
11from pr2modules.netlink import nla
12from pr2modules.netlink import nla_string
13
14RTNH_F_DEAD = 1
15RTNH_F_PERVASIVE = 2
16RTNH_F_ONLINK = 4
17RTNH_F_OFFLOAD = 8
18RTNH_F_LINKDOWN = 16
19(RTNH_F_NAMES, RTNH_F_VALUES) = map_namespace('RTNH_F', globals())
20
21LWTUNNEL_ENCAP_NONE = 0
22LWTUNNEL_ENCAP_MPLS = 1
23LWTUNNEL_ENCAP_IP = 2
24LWTUNNEL_ENCAP_ILA = 3
25LWTUNNEL_ENCAP_IP6 = 4
26LWTUNNEL_ENCAP_SEG6 = 5
27LWTUNNEL_ENCAP_BPF = 6
28LWTUNNEL_ENCAP_SEG6_LOCAL = 7
29
30
31class nlflags(object):
32
33    def encode(self):
34        if isinstance(self['flags'], (set, tuple, list)):
35            self['flags'] = self.names2flags(self['flags'])
36        return super(nlflags, self).encode()
37
38    def flags2names(self, flags=None):
39        ret = []
40        for flag in RTNH_F_VALUES:
41            if (flag & flags) == flag:
42                ret.append(RTNH_F_VALUES[flag].lower()[7:])
43        return ret
44
45    def names2flags(self, flags=None):
46        ret = 0
47        for flag in flags or self['flags']:
48            ret |= RTNH_F_NAMES['RTNH_F_' + flag.upper()]
49        return ret
50
51
52class rtmsg_base(nlflags):
53    '''
54    Route message
55
56    C structure::
57
58        struct rtmsg {
59            unsigned char rtm_family;   /* Address family of route */
60            unsigned char rtm_dst_len;  /* Length of destination */
61            unsigned char rtm_src_len;  /* Length of source */
62            unsigned char rtm_tos;      /* TOS filter */
63
64            unsigned char rtm_table;    /* Routing table ID */
65            unsigned char rtm_protocol; /* Routing protocol; see below */
66            unsigned char rtm_scope;    /* See below */
67            unsigned char rtm_type;     /* See below */
68
69            unsigned int  rtm_flags;
70        };
71    '''
72
73    __slots__ = ()
74
75    prefix = 'RTA_'
76    sql_constraints = {'RTA_TABLE': 'NOT NULL DEFAULT 0',
77                       'RTA_DST': "NOT NULL DEFAULT ''",
78                       'RTA_OIF': 'NOT NULL DEFAULT 0',
79                       'RTA_PRIORITY': 'NOT NULL DEFAULT 0',
80                       'RTA_VIA': "NOT NULL DEFAULT ''",
81                       'RTA_NEWDST': "NOT NULL DEFAULT ''"}
82
83    fields = (('family', 'B'),
84              ('dst_len', 'B'),
85              ('src_len', 'B'),
86              ('tos', 'B'),
87              ('table', 'B'),
88              ('proto', 'B'),
89              ('scope', 'B'),
90              ('type', 'B'),
91              ('flags', 'I'))
92
93    nla_map = (('RTA_UNSPEC', 'none'),
94               ('RTA_DST', 'target'),
95               ('RTA_SRC', 'target'),
96               ('RTA_IIF', 'uint32'),
97               ('RTA_OIF', 'uint32'),
98               ('RTA_GATEWAY', 'target'),
99               ('RTA_PRIORITY', 'uint32'),
100               ('RTA_PREFSRC', 'target'),
101               ('RTA_METRICS', 'metrics'),
102               ('RTA_MULTIPATH', '*get_nh'),
103               ('RTA_PROTOINFO', 'uint32'),
104               ('RTA_FLOW', 'uint32'),
105               ('RTA_CACHEINFO', 'cacheinfo'),
106               ('RTA_SESSION', 'hex'),
107               ('RTA_MP_ALGO', 'hex'),
108               ('RTA_TABLE', 'uint32'),
109               ('RTA_MARK', 'uint32'),
110               ('RTA_MFC_STATS', 'rta_mfc_stats'),
111               ('RTA_VIA', 'rtvia'),
112               ('RTA_NEWDST', 'target'),
113               ('RTA_PREF', 'uint8'),
114               ('RTA_ENCAP_TYPE', 'uint16'),
115               ('RTA_ENCAP', 'encap_info'),
116               ('RTA_EXPIRES', 'hex'))
117
118    @staticmethod
119    def encap_info(self, *argv, **kwarg):
120        encap_type = None
121
122        # Check, if RTA_ENCAP_TYPE is decoded already
123        #
124        for name, value in self['attrs']:
125            if name == 'RTA_ENCAP_TYPE':
126                encap_type = value
127                break
128        else:
129            # No RTA_ENCAP_TYPE met, so iterate all the chain.
130            # Ugly, but to do otherwise would be too complicated.
131            #
132            data = kwarg['data']
133            offset = kwarg['offset']
134            while offset < len(data):
135                # Shift offset to the next NLA
136                # NLA header:
137                #
138                # uint16 length
139                # uint16 type
140                #
141                try:
142                    offset += struct.unpack('H', data[offset:offset + 2])[0]
143                    # 21 == RTA_ENCAP_TYPE
144                    # FIXME: should not be hardcoded
145                    if struct.unpack('H', data[offset + 2:
146                                               offset + 4])[0] == 21:
147                        encap_type = struct.unpack('H', data[offset + 4:
148                                                             offset + 6])[0]
149                        break
150                except:
151                    # in the case of any decoding error return self.hex
152                    break
153
154        # return specific classes
155        #
156        return self.encaps.get(encap_type, self.hex)
157
158    class mpls_encap_info(nla):
159        prefix = 'MPLS_IPTUNNEL_'
160        __slots__ = ()
161
162        nla_map = (('MPLS_IPTUNNEL_UNSPEC', 'none'),
163                   ('MPLS_IPTUNNEL_DST', 'mpls_target'),
164                   ('MPLS_IPTUNNEL_TTL', 'uint8'))
165
166    class seg6_encap_info(nla):
167
168        __slots__ = ()
169
170        nla_map = (('SEG6_IPTUNNEL_UNSPEC', 'none'),
171                   ('SEG6_IPTUNNEL_SRH', 'ipv6_sr_hdr'))
172
173        class ipv6_sr_hdr(nla):
174
175            __slots__ = ()
176
177            fields = (('encapmode', 'I'),
178                      ('nexthdr', 'B'),
179                      ('hdrlen', 'B'),
180                      ('type', 'B'),
181                      ('segments_left', 'B'),
182                      ('first_segment', 'B'),
183                      ('flags', 'B'),
184                      ('reserved', 'H'),
185                      ('segs', 's'),
186                      # Potentially several type-length-value
187                      ('tlvs', 's'))
188
189            # Corresponding values for seg6 encap modes
190            SEG6_IPTUN_MODE_INLINE = 0
191            SEG6_IPTUN_MODE_ENCAP = 1
192
193            # Mapping string to nla value
194            encapmodes = {
195                "inline": SEG6_IPTUN_MODE_INLINE,
196                "encap": SEG6_IPTUN_MODE_ENCAP
197            }
198
199            # Reverse mapping: mapping nla value to string
200            r_encapmodes = {v: k for k, v in encapmodes.items()}
201
202            # Nla value for seg6 type
203            SEG6_TYPE = 4
204
205            # Flag value for hmac
206            SR6_FLAG1_HMAC = 1 << 3
207
208            # Tlv value for hmac
209            SR6_TLV_HMAC = 5
210
211            # Utility function to get the family from the msg
212            def get_family(self):
213                pointer = self
214                while pointer.parent is not None:
215                    pointer = pointer.parent
216                return pointer.get('family', AF_UNSPEC)
217
218            def encode(self):
219                # Retrieve the family
220                family = self.get_family()
221                # Seg6 can be applied only to IPv6 and IPv4
222                if family == AF_INET6 or family == AF_INET:
223                    # Get mode
224                    mode = self['mode']
225                    # Get segs
226                    segs = self['segs']
227                    # Get hmac
228                    hmac = self.get('hmac', None)
229                    # With "inline" mode there is not
230                    # encap into an outer IPv6 header
231                    if mode == "inline":
232                        # Add :: to segs
233                        segs.insert(0, "::")
234                    # Add mode to value
235                    self['encapmode'] = (self
236                                         .encapmodes
237                                         .get(mode,
238                                              self.SEG6_IPTUN_MODE_ENCAP))
239                    # Calculate srlen
240                    srhlen = 8 + 16 * len(segs)
241                    # If we are using hmac we have a tlv as trailer data
242                    if hmac:
243                        # Since we can use sha1 or sha256
244                        srhlen += 40
245                    # Calculate and set hdrlen
246                    self['hdrlen'] = (srhlen >> 3) - 1
247                    # Add seg6 type
248                    self['type'] = self.SEG6_TYPE
249                    # Add segments left
250                    self['segments_left'] = len(segs) - 1
251                    # Add fitst segment
252                    self['first_segment'] = len(segs) - 1
253                    # If hmac is used we have to set the flags
254                    if hmac:
255                        # Add SR6_FLAG1_HMAC
256                        self['flags'] |= self.SR6_FLAG1_HMAC
257                    # Init segs
258                    self['segs'] = b''
259                    # Iterate over segments
260                    for seg in segs:
261                        # Convert to network byte order and add to value
262                        self['segs'] += inet_pton(AF_INET6, seg)
263                    # Initialize tlvs
264                    self['tlvs'] = b''
265                    # If hmac is used we have to properly init tlvs
266                    if hmac:
267                        # Put type
268                        self['tlvs'] += struct.pack('B', self.SR6_TLV_HMAC)
269                        # Put length -> 40-2
270                        self['tlvs'] += struct.pack('B', 38)
271                        # Put reserved
272                        self['tlvs'] += struct.pack('H', 0)
273                        # Put hmac key
274                        self['tlvs'] += struct.pack('>I', hmac)
275                        # Put hmac
276                        self['tlvs'] += struct.pack('QQQQ', 0, 0, 0, 0)
277                else:
278                    raise TypeError('Family %s not supported for seg6 tunnel'
279                                    % family)
280                # Finally encode as nla
281                nla.encode(self)
282
283            # Utility function to verify if hmac is present
284            def has_hmac(self):
285                # Useful during the decoding
286                return self['flags'] & self.SR6_FLAG1_HMAC
287
288            def decode(self):
289                # Decode the data
290                nla.decode(self)
291                # Extract the encap mode
292                self['mode'] = (self.r_encapmodes
293                                .get(self['encapmode'], "encap"))
294                # Calculate offset of the segs
295                offset = self.offset + 16
296                # Point the addresses
297                addresses = self.data[offset:]
298                # Extract the number of segs
299                n_segs = self['segments_left'] + 1
300                # Init segs
301                segs = []
302                # Move 128 bit in each step
303                for i in range(n_segs):
304                    # Save the segment
305                    segs.append(inet_ntop(AF_INET6,
306                                          addresses[i * 16:i * 16 + 16]))
307                # Save segs
308                self['segs'] = segs
309                # Init tlvs
310                self['tlvs'] = ''
311                # If hmac is used
312                if self.has_hmac():
313                    # Point to the start of hmac
314                    hmac = addresses[n_segs * 16:n_segs * 16 + 40]
315                    # Save tlvs section
316                    self['tlvs'] = hexdump(hmac)
317                    # Show also the hmac key
318                    self['hmac'] = hexdump(hmac[4:8])
319
320    class bpf_encap_info(nla):
321
322        __slots__ = ()
323
324        nla_map = (('LWT_BPF_UNSPEC', 'none'),
325                   ('LWT_BPF_IN', 'bpf_obj'),
326                   ('LWT_BPF_OUT', 'bpf_obj'),
327                   ('LWT_BPF_XMIT', 'bpf_obj'),
328                   ('LWT_BPF_XMIT_HEADROOM', 'uint32'))
329
330        class bpf_obj(nla):
331
332            __slots__ = ()
333
334            nla_map = (('LWT_BPF_PROG_UNSPEC', 'none'),
335                       ('LWT_BPF_PROG_FD', 'uint32'),
336                       ('LWT_BPF_PROG_NAME', 'asciiz'))
337
338    class seg6local_encap_info(nla):
339
340        __slots__ = ()
341
342        nla_map = (('SEG6_LOCAL_UNSPEC', 'none'),
343                   ('SEG6_LOCAL_ACTION', 'action'),
344                   ('SEG6_LOCAL_SRH', 'ipv6_sr_hdr'),
345                   ('SEG6_LOCAL_TABLE', 'table'),
346                   ('SEG6_LOCAL_NH4', 'nh4'),
347                   ('SEG6_LOCAL_NH6', 'nh6'),
348                   ('SEG6_LOCAL_IIF', 'iif'),
349                   ('SEG6_LOCAL_OIF', 'oif'),
350                   ('SEG6_LOCAL_BPF', 'bpf_obj'))
351
352        class bpf_obj(nla):
353
354            __slots__ = ()
355
356            nla_map = (('LWT_BPF_PROG_UNSPEC', 'none'),
357                       ('LWT_BPF_PROG_FD', 'uint32'),
358                       ('LWT_BPF_PROG_NAME', 'asciiz'))
359
360        class ipv6_sr_hdr(nla):
361
362            __slots__ = ()
363
364            fields = (('nexthdr', 'B'),
365                      ('hdrlen', 'B'),
366                      ('type', 'B'),
367                      ('segments_left', 'B'),
368                      ('first_segment', 'B'),
369                      ('flags', 'B'),
370                      ('reserved', 'H'),
371                      ('segs', 's'),
372                      # Potentially several type-length-value
373                      ('tlvs', 's'))
374
375            # Corresponding values for seg6 encap modes
376            SEG6_IPTUN_MODE_INLINE = 0
377            SEG6_IPTUN_MODE_ENCAP = 1
378
379            # Mapping string to nla value
380            encapmodes = {
381                "inline": SEG6_IPTUN_MODE_INLINE,
382                "encap": SEG6_IPTUN_MODE_ENCAP
383            }
384
385            # Reverse mapping: mapping nla value to string
386            r_encapmodes = {v: k for k, v in encapmodes.items()}
387
388            # Nla value for seg6 type
389            SEG6_TYPE = 4
390
391            # Flag value for hmac
392            SR6_FLAG1_HMAC = 1 << 3
393
394            # Tlv value for hmac
395            SR6_TLV_HMAC = 5
396
397            # Utility function to get the family from the msg
398            def get_family(self):
399                pointer = self
400                while pointer.parent is not None:
401                    pointer = pointer.parent
402                return pointer.get('family', AF_UNSPEC)
403
404            def encode(self):
405                # Retrieve the family
406                family = self.get_family()
407                # Seg6 can be applied only to IPv6
408                if family == AF_INET6:
409                    # Get mode
410                    mode = self['mode']
411                    # Get segs
412                    segs = self['segs']
413                    # Get hmac
414                    hmac = self.get('hmac', None)
415                    # With "inline" mode there is not
416                    # encap into an outer IPv6 header
417                    if mode == "inline":
418                        # Add :: to segs
419                        segs.insert(0, "::")
420                    # Add mode to value
421                    self['encapmode'] = (self
422                                         .encapmodes
423                                         .get(mode,
424                                              self.SEG6_IPTUN_MODE_ENCAP))
425                    # Calculate srlen
426                    srhlen = 8 + 16 * len(segs)
427                    # If we are using hmac we have a tlv as trailer data
428                    if hmac:
429                        # Since we can use sha1 or sha256
430                        srhlen += 40
431                    # Calculate and set hdrlen
432                    self['hdrlen'] = (srhlen >> 3) - 1
433                    # Add seg6 type
434                    self['type'] = self.SEG6_TYPE
435                    # Add segments left
436                    self['segments_left'] = len(segs) - 1
437                    # Add fitst segment
438                    self['first_segment'] = len(segs) - 1
439                    # If hmac is used we have to set the flags
440                    if hmac:
441                        # Add SR6_FLAG1_HMAC
442                        self['flags'] |= self.SR6_FLAG1_HMAC
443                    # Init segs
444                    self['segs'] = b''
445                    # Iterate over segments
446                    for seg in segs:
447                        # Convert to network byte order and add to value
448                        self['segs'] += inet_pton(family, seg)
449                    # Initialize tlvs
450                    self['tlvs'] = b''
451                    # If hmac is used we have to properly init tlvs
452                    if hmac:
453                        # Put type
454                        self['tlvs'] += struct.pack('B', self.SR6_TLV_HMAC)
455                        # Put length -> 40-2
456                        self['tlvs'] += struct.pack('B', 38)
457                        # Put reserved
458                        self['tlvs'] += struct.pack('H', 0)
459                        # Put hmac key
460                        self['tlvs'] += struct.pack('>I', hmac)
461                        # Put hmac
462                        self['tlvs'] += struct.pack('QQQQ', 0, 0, 0, 0)
463                else:
464                    raise TypeError('Family %s not supported for seg6 tunnel'
465                                    % family)
466                # Finally encode as nla
467                nla.encode(self)
468
469            # Utility function to verify if hmac is present
470            def has_hmac(self):
471                # Useful during the decoding
472                return self['flags'] & self.SR6_FLAG1_HMAC
473
474            def decode(self):
475                # Decode the data
476                nla.decode(self)
477                # Extract the encap mode
478                self['mode'] = (self.r_encapmodes
479                                .get(self['encapmode'], "encap"))
480                # Calculate offset of the segs
481                offset = self.offset + 16
482                # Point the addresses
483                addresses = self.data[offset:]
484                # Extract the number of segs
485                n_segs = self['segments_left'] + 1
486                # Init segs
487                segs = []
488                # Move 128 bit in each step
489                for i in range(n_segs):
490                    # Save the segment
491                    segs.append(inet_ntop(AF_INET6,
492                                          addresses[i * 16:i * 16 + 16]))
493                # Save segs
494                self['segs'] = segs
495                # Init tlvs
496                self['tlvs'] = ''
497                # If hmac is used
498                if self.has_hmac():
499                    # Point to the start of hmac
500                    hmac = addresses[n_segs * 16:n_segs * 16 + 40]
501                    # Save tlvs section
502                    self['tlvs'] = hexdump(hmac)
503                    # Show also the hmac key
504                    self['hmac'] = hexdump(hmac[4:8])
505
506        class table(nla):
507            __slots__ = ()
508            # Table ID
509            fields = (('value', 'I'),)
510
511        class action(nla):
512            __slots__ = ()
513            # Action
514            fields = (('value', 'I'),)
515
516            SEG6_LOCAL_ACTION_UNSPEC = 0
517            SEG6_LOCAL_ACTION_END = 1
518            SEG6_LOCAL_ACTION_END_X = 2
519            SEG6_LOCAL_ACTION_END_T = 3
520            SEG6_LOCAL_ACTION_END_DX2 = 4
521            SEG6_LOCAL_ACTION_END_DX6 = 5
522            SEG6_LOCAL_ACTION_END_DX4 = 6
523            SEG6_LOCAL_ACTION_END_DT6 = 7
524            SEG6_LOCAL_ACTION_END_DT4 = 8
525            SEG6_LOCAL_ACTION_END_B6 = 9
526            SEG6_LOCAL_ACTION_END_B6_ENCAP = 10
527            SEG6_LOCAL_ACTION_END_BM = 11
528            SEG6_LOCAL_ACTION_END_S = 12
529            SEG6_LOCAL_ACTION_END_AS = 13
530            SEG6_LOCAL_ACTION_END_AM = 14
531            SEG6_LOCAL_ACTION_END_BPF = 15
532
533            actions = {'End': SEG6_LOCAL_ACTION_END,
534                       'End.X': SEG6_LOCAL_ACTION_END_X,
535                       'End.T': SEG6_LOCAL_ACTION_END_T,
536                       'End.DX2': SEG6_LOCAL_ACTION_END_DX2,
537                       'End.DX6': SEG6_LOCAL_ACTION_END_DX6,
538                       'End.DX4': SEG6_LOCAL_ACTION_END_DX4,
539                       'End.DT6': SEG6_LOCAL_ACTION_END_DT6,
540                       'End.DT4': SEG6_LOCAL_ACTION_END_DT4,
541                       'End.B6': SEG6_LOCAL_ACTION_END_B6,
542                       'End.B6.Encaps': SEG6_LOCAL_ACTION_END_B6_ENCAP,
543                       'End.BM': SEG6_LOCAL_ACTION_END_BM,
544                       'End.S': SEG6_LOCAL_ACTION_END_S,
545                       'End.AS': SEG6_LOCAL_ACTION_END_AS,
546                       'End.AM': SEG6_LOCAL_ACTION_END_AM,
547                       'End.BPF': SEG6_LOCAL_ACTION_END_BPF}
548
549            def encode(self):
550                # Get action type and convert string to value
551                action = self['value']
552                self['value'] = (self
553                                 .actions
554                                 .get(action,
555                                      self.SEG6_LOCAL_ACTION_UNSPEC))
556                # Convert action type to u32
557                self['value'] = self['value'] & 0xffffffff
558                # Finally encode as nla
559                nla.encode(self)
560
561        class iif(nla):
562
563            __slots__ = ()
564
565            # Index of the incoming interface
566            fields = (('value', 'I'),)
567
568        class oif(nla):
569
570            __slots__ = ()
571
572            # Index of the outcoming interface
573            fields = (('value', 'I'),)
574
575        class nh4(nla_string):
576
577            __slots__ = ()
578
579            # Nexthop of the IPv4 family
580
581            def encode(self):
582                # Convert to network byte order
583                self['value'] = inet_pton(AF_INET, self['value'])
584                # Finally encode as nla
585                nla_string.encode(self)
586
587            def decode(self):
588                # Decode the data
589                nla_string.decode(self)
590                # Convert the packed IP address to its string representation
591                self['value'] = inet_ntop(AF_INET,
592                                          self['value'])
593
594        class nh6(nla_string):
595
596            __slots__ = ()
597
598            # Nexthop of the IPv6 family
599
600            def encode(self):
601                # Convert to network byte order
602                self['value'] = inet_pton(AF_INET6, self['value'])
603                # Finally encode as nla
604                nla_string.encode(self)
605
606            def decode(self):
607                # Decode the data
608                nla_string.decode(self)
609                # Convert the packed IP address to its string representation
610                self['value'] = inet_ntop(AF_INET6, self['value'])
611
612    #
613    # TODO: add here other lwtunnel types
614    #
615    encaps = {LWTUNNEL_ENCAP_MPLS: mpls_encap_info,
616              LWTUNNEL_ENCAP_SEG6: seg6_encap_info,
617              LWTUNNEL_ENCAP_BPF: bpf_encap_info,
618              LWTUNNEL_ENCAP_SEG6_LOCAL: seg6local_encap_info}
619
620    class rta_mfc_stats(nla):
621
622        __slots__ = ()
623
624        fields = (('mfcs_packets', 'uint64'),
625                  ('mfcs_bytes', 'uint64'),
626                  ('mfcs_wrong_if', 'uint64'))
627
628    class metrics(nla):
629
630        __slots__ = ()
631
632        prefix = 'RTAX_'
633        nla_map = (('RTAX_UNSPEC', 'none'),
634                   ('RTAX_LOCK', 'uint32'),
635                   ('RTAX_MTU', 'uint32'),
636                   ('RTAX_WINDOW', 'uint32'),
637                   ('RTAX_RTT', 'uint32'),
638                   ('RTAX_RTTVAR', 'uint32'),
639                   ('RTAX_SSTHRESH', 'uint32'),
640                   ('RTAX_CWND', 'uint32'),
641                   ('RTAX_ADVMSS', 'uint32'),
642                   ('RTAX_REORDERING', 'uint32'),
643                   ('RTAX_HOPLIMIT', 'uint32'),
644                   ('RTAX_INITCWND', 'uint32'),
645                   ('RTAX_FEATURES', 'uint32'),
646                   ('RTAX_RTO_MIN', 'uint32'),
647                   ('RTAX_INITRWND', 'uint32'),
648                   ('RTAX_QUICKACK', 'uint32'))
649
650    @staticmethod
651    def get_nh(self, *argv, **kwarg):
652        return nh
653
654    class rtvia(nla_string):
655
656        __slots__ = ()
657        sql_type = 'TEXT'
658
659        def encode(self):
660            family = self.get('family', AF_UNSPEC)
661            if family in (AF_INET, AF_INET6):
662                addr = inet_pton(family, self['addr'])
663            else:
664                raise TypeError('Family %s not supported for RTA_VIA'
665                                % family)
666            self['value'] = struct.pack('H', family) + addr
667            nla_string.encode(self)
668
669        def decode(self):
670            nla_string.decode(self)
671            family = struct.unpack('H', self['value'][:2])[0]
672            addr = self['value'][2:]
673            if addr:
674                if (family == AF_INET and len(addr) == 4) or \
675                        (family == AF_INET6 and len(addr) == 16):
676                    addr = inet_ntop(family, addr)
677                else:
678                    addr = hexdump(addr)
679            self.value = {'family': family, 'addr': addr}
680
681    class cacheinfo(nla):
682
683        __slots__ = ()
684
685        fields = (('rta_clntref', 'I'),
686                  ('rta_lastuse', 'I'),
687                  ('rta_expires', 'i'),
688                  ('rta_error', 'I'),
689                  ('rta_used', 'I'),
690                  ('rta_id', 'I'),
691                  ('rta_ts', 'I'),
692                  ('rta_tsage', 'I'))
693
694
695class rtmsg(rtmsg_base, nlmsg):
696
697    __slots__ = ()
698
699    def encode(self):
700        if self.get('family') == AF_MPLS:
701            # force fields
702            self['dst_len'] = 20
703            self['table'] = 254
704            self['type'] = 1
705            # assert NLA types
706            for n in self.get('attrs', []):
707                if n[0] not in ('RTA_OIF',
708                                'RTA_DST',
709                                'RTA_VIA',
710                                'RTA_NEWDST',
711                                'RTA_MULTIPATH'):
712                    raise TypeError('Incorrect NLA type %s for AF_MPLS' % n[0])
713        super(rtmsg_base, self).encode()
714
715
716class nh(rtmsg_base, nla):
717
718    __slots__ = ()
719
720    is_nla = False
721
722    sql_constraints = {}
723    cell_header = (('length', 'H'), )
724    fields = (('flags', 'B'),
725              ('hops', 'B'),
726              ('oif', 'i'))
727