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