PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/pyroute2/netlink/rtnl/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/pyroute2/netlink/rtnl/rtmsg.py |
import struct from socket import AF_INET, AF_INET6, AF_UNSPEC, inet_ntop, inet_pton from pyroute2.common import AF_MPLS, hexdump, map_namespace from pyroute2.netlink import nla, nla_string, nlmsg RTNH_F_DEAD = 1 RTNH_F_PERVASIVE = 2 RTNH_F_ONLINK = 4 RTNH_F_OFFLOAD = 8 RTNH_F_LINKDOWN = 16 (RTNH_F_NAMES, RTNH_F_VALUES) = map_namespace('RTNH_F_', globals()) RT_SCOPE_UNIVERSE = 0 RT_SCOPE_SITE = 200 RT_SCOPE_LINK = 253 RT_SCOPE_HOST = 254 RT_SCOPE_NOWHERE = 255 (RT_SCOPE_NAMES, RT_SCOPE_VALUES) = map_namespace('RT_SCOPE_', globals()) LWTUNNEL_ENCAP_NONE = 0 LWTUNNEL_ENCAP_MPLS = 1 LWTUNNEL_ENCAP_IP = 2 LWTUNNEL_ENCAP_ILA = 3 LWTUNNEL_ENCAP_IP6 = 4 LWTUNNEL_ENCAP_SEG6 = 5 LWTUNNEL_ENCAP_BPF = 6 LWTUNNEL_ENCAP_SEG6_LOCAL = 7 IP6_RT_PRIO_USER = 1024 class nlflags(object): def encode(self): if isinstance(self['flags'], str): self['flags'] = self['flags'].split(',') if isinstance(self['flags'], (set, tuple, list)): self['flags'] = self.names2flags(self['flags']) if isinstance(self.get('scope'), str): self['scope'] = self.name2scope(self['scope']) return super(nlflags, self).encode() @staticmethod def scope2name(scope): return RT_SCOPE_VALUES[scope].lower()[9:] @staticmethod def name2scope(scope): return RT_SCOPE_NAMES['RT_SCOPE_' + scope.upper()] @staticmethod def flags2names(flags): ret = [] for flag in RTNH_F_VALUES: if (flag & flags) == flag: ret.append(RTNH_F_VALUES[flag].lower()[7:]) return ret @staticmethod def names2flags(flags): ret = 0 if isinstance(flags, str): flags = [flags] for flag in flags: ret |= RTNH_F_NAMES['RTNH_F_' + flag.upper()] return ret class rtmsg_base(nlflags): ''' Route message C structure:: struct rtmsg { unsigned char rtm_family; /* Address family of route */ unsigned char rtm_dst_len; /* Length of destination */ unsigned char rtm_src_len; /* Length of source */ unsigned char rtm_tos; /* TOS filter */ unsigned char rtm_table; /* Routing table ID */ unsigned char rtm_protocol; /* Routing protocol; see below */ unsigned char rtm_scope; /* See below */ unsigned char rtm_type; /* See below */ unsigned int rtm_flags; }; ''' __slots__ = () prefix = 'RTA_' sql_constraints = { 'RTA_TABLE': 'NOT NULL DEFAULT 0', 'RTA_DST': "NOT NULL DEFAULT ''", 'RTA_OIF': 'NOT NULL DEFAULT 0', 'RTA_PRIORITY': 'NOT NULL DEFAULT 0', 'RTA_VIA': "NOT NULL DEFAULT ''", 'RTA_NEWDST': "NOT NULL DEFAULT ''", } fields = ( ('family', 'B'), ('dst_len', 'B'), ('src_len', 'B'), ('tos', 'B'), ('table', 'B'), ('proto', 'B'), ('scope', 'B'), ('type', 'B'), ('flags', 'I'), ) nla_map = ( ('RTA_UNSPEC', 'none'), ('RTA_DST', 'target'), ('RTA_SRC', 'target'), ('RTA_IIF', 'uint32'), ('RTA_OIF', 'uint32'), ('RTA_GATEWAY', 'target'), ('RTA_PRIORITY', 'uint32'), ('RTA_PREFSRC', 'target'), ('RTA_METRICS', 'metrics'), ('RTA_MULTIPATH', '*get_nh'), ('RTA_PROTOINFO', 'uint32'), ('RTA_FLOW', 'uint32'), ('RTA_CACHEINFO', 'cacheinfo'), ('RTA_SESSION', 'hex'), ('RTA_MP_ALGO', 'hex'), ('RTA_TABLE', 'uint32'), ('RTA_MARK', 'uint32'), ('RTA_MFC_STATS', 'rta_mfc_stats'), ('RTA_VIA', 'rtvia'), ('RTA_NEWDST', 'target'), ('RTA_PREF', 'uint8'), ('RTA_ENCAP_TYPE', 'uint16'), ('RTA_ENCAP', 'encap_info'), ('RTA_EXPIRES', 'hex'), ) @staticmethod def encap_info(self, *argv, **kwarg): encap_type = None # Check, if RTA_ENCAP_TYPE is decoded already # for name, value in self['attrs']: if name == 'RTA_ENCAP_TYPE': encap_type = value break else: # No RTA_ENCAP_TYPE met, so iterate all the chain. # Ugly, but to do otherwise would be too complicated. # data = kwarg['data'] offset = kwarg['offset'] while offset < len(data): # Shift offset to the next NLA # NLA header: # # uint16 length # uint16 type # try: offset += struct.unpack('H', data[offset : offset + 2])[0] # 21 == RTA_ENCAP_TYPE # FIXME: should not be hardcoded if ( struct.unpack('H', data[offset + 2 : offset + 4])[0] == 21 ): encap_type = struct.unpack( 'H', data[offset + 4 : offset + 6] )[0] break except: # in the case of any decoding error return self.hex break # return specific classes # return self.encaps.get(encap_type, self.hex) class mpls_encap_info(nla): prefix = 'MPLS_IPTUNNEL_' __slots__ = () nla_map = ( ('MPLS_IPTUNNEL_UNSPEC', 'none'), ('MPLS_IPTUNNEL_DST', 'mpls_target'), ('MPLS_IPTUNNEL_TTL', 'uint8'), ) class seg6_encap_info(nla): __slots__ = () nla_map = ( ('SEG6_IPTUNNEL_UNSPEC', 'none'), ('SEG6_IPTUNNEL_SRH', 'ipv6_sr_hdr'), ) class ipv6_sr_hdr(nla): __slots__ = () fields = ( ('encapmode', 'I'), ('nexthdr', 'B'), ('hdrlen', 'B'), ('type', 'B'), ('segments_left', 'B'), ('first_segment', 'B'), ('flags', 'B'), ('reserved', 'H'), ('segs', 's'), # Potentially several type-length-value ('tlvs', 's'), ) # Corresponding values for seg6 encap modes SEG6_IPTUN_MODE_INLINE = 0 SEG6_IPTUN_MODE_ENCAP = 1 # Mapping string to nla value encapmodes = { "inline": SEG6_IPTUN_MODE_INLINE, "encap": SEG6_IPTUN_MODE_ENCAP, } # Reverse mapping: mapping nla value to string r_encapmodes = {v: k for k, v in encapmodes.items()} # Nla value for seg6 type SEG6_TYPE = 4 # Flag value for hmac SR6_FLAG1_HMAC = 1 << 3 # Tlv value for hmac SR6_TLV_HMAC = 5 # Utility function to get the family from the msg def get_family(self): pointer = self while pointer.parent is not None: pointer = pointer.parent return pointer.get('family', AF_UNSPEC) def encode(self): # Retrieve the family family = self.get_family() # Seg6 can be applied only to IPv6 and IPv4 if family == AF_INET6 or family == AF_INET: # Get mode mode = self['mode'] # Get segs segs = self['segs'] # Get hmac hmac = self.get('hmac', None) # With "inline" mode there is not # encap into an outer IPv6 header if mode == "inline": # Add :: to segs segs.insert(0, "::") # Add mode to value self['encapmode'] = self.encapmodes.get( mode, self.SEG6_IPTUN_MODE_ENCAP ) # Calculate srlen srhlen = 8 + 16 * len(segs) # If we are using hmac we have a tlv as trailer data if hmac: # Since we can use sha1 or sha256 srhlen += 40 # Calculate and set hdrlen self['hdrlen'] = (srhlen >> 3) - 1 # Add seg6 type self['type'] = self.SEG6_TYPE # Add segments left self['segments_left'] = len(segs) - 1 # Add fitst segment self['first_segment'] = len(segs) - 1 # If hmac is used we have to set the flags if hmac: # Add SR6_FLAG1_HMAC self['flags'] |= self.SR6_FLAG1_HMAC # Init segs self['segs'] = b'' # Iterate over segments for seg in segs: # Convert to network byte order and add to value self['segs'] += inet_pton(AF_INET6, seg) # Initialize tlvs self['tlvs'] = b'' # If hmac is used we have to properly init tlvs if hmac: # Put type self['tlvs'] += struct.pack('B', self.SR6_TLV_HMAC) # Put length -> 40-2 self['tlvs'] += struct.pack('B', 38) # Put reserved self['tlvs'] += struct.pack('H', 0) # Put hmac key self['tlvs'] += struct.pack('>I', hmac) # Put hmac self['tlvs'] += struct.pack('QQQQ', 0, 0, 0, 0) else: raise TypeError( 'Family %s not supported for seg6 tunnel' % family ) # Finally encode as nla nla.encode(self) # Utility function to verify if hmac is present def has_hmac(self): # Useful during the decoding return self['flags'] & self.SR6_FLAG1_HMAC def decode(self): # Decode the data nla.decode(self) # Extract the encap mode self['mode'] = self.r_encapmodes.get( self['encapmode'], "encap" ) # Calculate offset of the segs offset = self.offset + 16 # Point the addresses addresses = self.data[offset:] # Extract the number of segs n_segs = self['segments_left'] + 1 # Init segs segs = [] # Move 128 bit in each step for i in range(n_segs): # Save the segment segs.append( inet_ntop(AF_INET6, addresses[i * 16 : i * 16 + 16]) ) # Save segs self['segs'] = segs # Init tlvs self['tlvs'] = '' # If hmac is used if self.has_hmac(): # Point to the start of hmac hmac = addresses[n_segs * 16 : n_segs * 16 + 40] # Save tlvs section self['tlvs'] = hexdump(hmac) # Show also the hmac key self['hmac'] = hexdump(hmac[4:8]) class bpf_encap_info(nla): __slots__ = () nla_map = ( ('LWT_BPF_UNSPEC', 'none'), ('LWT_BPF_IN', 'bpf_obj'), ('LWT_BPF_OUT', 'bpf_obj'), ('LWT_BPF_XMIT', 'bpf_obj'), ('LWT_BPF_XMIT_HEADROOM', 'uint32'), ) class bpf_obj(nla): __slots__ = () nla_map = ( ('LWT_BPF_PROG_UNSPEC', 'none'), ('LWT_BPF_PROG_FD', 'uint32'), ('LWT_BPF_PROG_NAME', 'asciiz'), ) class seg6local_encap_info(nla): __slots__ = () nla_map = ( ('SEG6_LOCAL_UNSPEC', 'none'), ('SEG6_LOCAL_ACTION', 'action'), ('SEG6_LOCAL_SRH', 'ipv6_sr_hdr'), ('SEG6_LOCAL_TABLE', 'table'), ('SEG6_LOCAL_NH4', 'nh4'), ('SEG6_LOCAL_NH6', 'nh6'), ('SEG6_LOCAL_IIF', 'iif'), ('SEG6_LOCAL_OIF', 'oif'), ('SEG6_LOCAL_BPF', 'bpf_obj'), ('SEG6_LOCAL_VRFTABLE', 'vrf_table'), ) class bpf_obj(nla): __slots__ = () nla_map = ( ('LWT_BPF_PROG_UNSPEC', 'none'), ('LWT_BPF_PROG_FD', 'uint32'), ('LWT_BPF_PROG_NAME', 'asciiz'), ) class ipv6_sr_hdr(nla): __slots__ = () fields = ( ('nexthdr', 'B'), ('hdrlen', 'B'), ('type', 'B'), ('segments_left', 'B'), ('first_segment', 'B'), ('flags', 'B'), ('reserved', 'H'), ('segs', 's'), # Potentially several type-length-value ('tlvs', 's'), ) # Corresponding values for seg6 encap modes SEG6_IPTUN_MODE_INLINE = 0 SEG6_IPTUN_MODE_ENCAP = 1 # Mapping string to nla value encapmodes = { "inline": SEG6_IPTUN_MODE_INLINE, "encap": SEG6_IPTUN_MODE_ENCAP, } # Reverse mapping: mapping nla value to string r_encapmodes = {v: k for k, v in encapmodes.items()} # Nla value for seg6 type SEG6_TYPE = 4 # Flag value for hmac SR6_FLAG1_HMAC = 1 << 3 # Tlv value for hmac SR6_TLV_HMAC = 5 # Utility function to get the family from the msg def get_family(self): pointer = self while pointer.parent is not None: pointer = pointer.parent return pointer.get('family', AF_UNSPEC) def encode(self): # Retrieve the family family = self.get_family() # Seg6 can be applied only to IPv6 if family == AF_INET6: # Get mode mode = self['mode'] # Get segs segs = self['segs'] # Get hmac hmac = self.get('hmac', None) # With "inline" mode there is not # encap into an outer IPv6 header if mode == "inline": # Add :: to segs segs.insert(0, "::") # Add mode to value self['encapmode'] = self.encapmodes.get( mode, self.SEG6_IPTUN_MODE_ENCAP ) # Calculate srlen srhlen = 8 + 16 * len(segs) # If we are using hmac we have a tlv as trailer data if hmac: # Since we can use sha1 or sha256 srhlen += 40 # Calculate and set hdrlen self['hdrlen'] = (srhlen >> 3) - 1 # Add seg6 type self['type'] = self.SEG6_TYPE # Add segments left self['segments_left'] = len(segs) - 1 # Add fitst segment self['first_segment'] = len(segs) - 1 # If hmac is used we have to set the flags if hmac: # Add SR6_FLAG1_HMAC self['flags'] |= self.SR6_FLAG1_HMAC # Init segs self['segs'] = b'' # Iterate over segments for seg in segs: # Convert to network byte order and add to value self['segs'] += inet_pton(family, seg) # Initialize tlvs self['tlvs'] = b'' # If hmac is used we have to properly init tlvs if hmac: # Put type self['tlvs'] += struct.pack('B', self.SR6_TLV_HMAC) # Put length -> 40-2 self['tlvs'] += struct.pack('B', 38) # Put reserved self['tlvs'] += struct.pack('H', 0) # Put hmac key self['tlvs'] += struct.pack('>I', hmac) # Put hmac self['tlvs'] += struct.pack('QQQQ', 0, 0, 0, 0) else: raise TypeError( 'Family %s not supported for seg6 tunnel' % family ) # Finally encode as nla nla.encode(self) # Utility function to verify if hmac is present def has_hmac(self): # Useful during the decoding return self['flags'] & self.SR6_FLAG1_HMAC def decode(self): # Decode the data nla.decode(self) # Extract the encap mode self['mode'] = self.r_encapmodes.get( self['encapmode'], "encap" ) # Calculate offset of the segs offset = self.offset + 16 # Point the addresses addresses = self.data[offset:] # Extract the number of segs n_segs = self['segments_left'] + 1 # Init segs segs = [] # Move 128 bit in each step for i in range(n_segs): # Save the segment segs.append( inet_ntop(AF_INET6, addresses[i * 16 : i * 16 + 16]) ) # Save segs self['segs'] = segs # Init tlvs self['tlvs'] = '' # If hmac is used if self.has_hmac(): # Point to the start of hmac hmac = addresses[n_segs * 16 : n_segs * 16 + 40] # Save tlvs section self['tlvs'] = hexdump(hmac) # Show also the hmac key self['hmac'] = hexdump(hmac[4:8]) class table(nla): __slots__ = () # Table ID fields = (('value', 'I'),) class action(nla): __slots__ = () # Action fields = (('value', 'I'),) SEG6_LOCAL_ACTION_UNSPEC = 0 SEG6_LOCAL_ACTION_END = 1 SEG6_LOCAL_ACTION_END_X = 2 SEG6_LOCAL_ACTION_END_T = 3 SEG6_LOCAL_ACTION_END_DX2 = 4 SEG6_LOCAL_ACTION_END_DX6 = 5 SEG6_LOCAL_ACTION_END_DX4 = 6 SEG6_LOCAL_ACTION_END_DT6 = 7 SEG6_LOCAL_ACTION_END_DT4 = 8 SEG6_LOCAL_ACTION_END_B6 = 9 SEG6_LOCAL_ACTION_END_B6_ENCAP = 10 SEG6_LOCAL_ACTION_END_BM = 11 SEG6_LOCAL_ACTION_END_S = 12 SEG6_LOCAL_ACTION_END_AS = 13 SEG6_LOCAL_ACTION_END_AM = 14 SEG6_LOCAL_ACTION_END_BPF = 15 SEG6_LOCAL_ACTION_END_DT46 = 16 actions = { 'End': SEG6_LOCAL_ACTION_END, 'End.X': SEG6_LOCAL_ACTION_END_X, 'End.T': SEG6_LOCAL_ACTION_END_T, 'End.DX2': SEG6_LOCAL_ACTION_END_DX2, 'End.DX6': SEG6_LOCAL_ACTION_END_DX6, 'End.DX4': SEG6_LOCAL_ACTION_END_DX4, 'End.DT6': SEG6_LOCAL_ACTION_END_DT6, 'End.DT4': SEG6_LOCAL_ACTION_END_DT4, 'End.B6': SEG6_LOCAL_ACTION_END_B6, 'End.B6.Encaps': SEG6_LOCAL_ACTION_END_B6_ENCAP, 'End.BM': SEG6_LOCAL_ACTION_END_BM, 'End.S': SEG6_LOCAL_ACTION_END_S, 'End.AS': SEG6_LOCAL_ACTION_END_AS, 'End.AM': SEG6_LOCAL_ACTION_END_AM, 'End.BPF': SEG6_LOCAL_ACTION_END_BPF, 'End.DT46': SEG6_LOCAL_ACTION_END_DT46, } def encode(self): # Get action type and convert string to value action = self['value'] self['value'] = self.actions.get( action, self.SEG6_LOCAL_ACTION_UNSPEC ) # Convert action type to u32 self['value'] = self['value'] & 0xFFFFFFFF # Finally encode as nla nla.encode(self) class iif(nla): __slots__ = () # Index of the incoming interface fields = (('value', 'I'),) class oif(nla): __slots__ = () # Index of the outcoming interface fields = (('value', 'I'),) class nh4(nla_string): __slots__ = () # Nexthop of the IPv4 family def encode(self): # Convert to network byte order self['value'] = inet_pton(AF_INET, self['value']) # Finally encode as nla nla_string.encode(self) def decode(self): # Decode the data nla_string.decode(self) # Convert the packed IP address to its string representation self['value'] = inet_ntop(AF_INET, self['value']) class nh6(nla_string): __slots__ = () # Nexthop of the IPv6 family def encode(self): # Convert to network byte order self['value'] = inet_pton(AF_INET6, self['value']) # Finally encode as nla nla_string.encode(self) def decode(self): # Decode the data nla_string.decode(self) # Convert the packed IP address to its string representation self['value'] = inet_ntop(AF_INET6, self['value']) class vrf_table(nla): __slots__ = () # VRF Table ID fields = (('value', 'I'),) # # TODO: add here other lwtunnel types # encaps = { LWTUNNEL_ENCAP_MPLS: mpls_encap_info, LWTUNNEL_ENCAP_SEG6: seg6_encap_info, LWTUNNEL_ENCAP_BPF: bpf_encap_info, LWTUNNEL_ENCAP_SEG6_LOCAL: seg6local_encap_info, } class rta_mfc_stats(nla): __slots__ = () fields = ( ('mfcs_packets', 'uint64'), ('mfcs_bytes', 'uint64'), ('mfcs_wrong_if', 'uint64'), ) class metrics(nla): __slots__ = () prefix = 'RTAX_' nla_map = ( ('RTAX_UNSPEC', 'none'), ('RTAX_LOCK', 'uint32'), ('RTAX_MTU', 'uint32'), ('RTAX_WINDOW', 'uint32'), ('RTAX_RTT', 'uint32'), ('RTAX_RTTVAR', 'uint32'), ('RTAX_SSTHRESH', 'uint32'), ('RTAX_CWND', 'uint32'), ('RTAX_ADVMSS', 'uint32'), ('RTAX_REORDERING', 'uint32'), ('RTAX_HOPLIMIT', 'uint32'), ('RTAX_INITCWND', 'uint32'), ('RTAX_FEATURES', 'uint32'), ('RTAX_RTO_MIN', 'uint32'), ('RTAX_INITRWND', 'uint32'), ('RTAX_QUICKACK', 'uint32'), ) @staticmethod def get_nh(self, *argv, **kwarg): return nh class rtvia(nla_string): __slots__ = () sql_type = 'TEXT' def encode(self): family = self.get('family', AF_UNSPEC) if family in (AF_INET, AF_INET6): addr = inet_pton(family, self['addr']) else: raise TypeError('Family %s not supported for RTA_VIA' % family) self['value'] = struct.pack('H', family) + addr nla_string.encode(self) def decode(self): nla_string.decode(self) family = struct.unpack('H', self['value'][:2])[0] addr = self['value'][2:] if addr: if (family == AF_INET and len(addr) == 4) or ( family == AF_INET6 and len(addr) == 16 ): addr = inet_ntop(family, addr) else: addr = hexdump(addr) self.value = {'family': family, 'addr': addr} class cacheinfo(nla): __slots__ = () fields = ( ('rta_clntref', 'I'), ('rta_lastuse', 'I'), ('rta_expires', 'i'), ('rta_error', 'I'), ('rta_used', 'I'), ('rta_id', 'I'), ('rta_ts', 'I'), ('rta_tsage', 'I'), ) class rtmsg(rtmsg_base, nlmsg): __slots__ = () def encode(self): if self.get('family') == AF_MPLS: # force fields self['dst_len'] = 20 self['table'] = 254 self['type'] = 1 # assert NLA types for n in self.get('attrs', []): if n[0] not in ( 'RTA_OIF', 'RTA_DST', 'RTA_VIA', 'RTA_NEWDST', 'RTA_MULTIPATH', ): raise TypeError('Incorrect NLA type %s for AF_MPLS' % n[0]) super(rtmsg_base, self).encode() class nh(rtmsg_base, nla): __slots__ = () is_nla = False sql_constraints = {} cell_header = (('length', 'H'),) fields = (('flags', 'B'), ('hops', 'B'), ('oif', 'i'))