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/ifinfmsg/ |
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/ifinfmsg/compat.py |
import json import os import subprocess from pyroute2.common import map_enoent from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg from pyroute2.netlink.rtnl.ifinfmsg.sync import sync from pyroute2.netlink.rtnl.ifinfmsg.tuntap import manage_tuntap from pyroute2.netlink.rtnl.marshal import MarshalRtnl # it's simpler to double constants here, than to change all the # module layout; but it is a subject of the future refactoring RTM_NEWLINK = 16 RTM_DELLINK = 17 # _BONDING_MASTERS = '/sys/class/net/bonding_masters' _BONDING_SLAVES = '/sys/class/net/%s/bonding/slaves' _BRIDGE_MASTER = '/sys/class/net/%s/brport/bridge/ifindex' _BONDING_MASTER = '/sys/class/net/%s/master/ifindex' IFNAMSIZ = 16 def compat_fix_attrs(msg, nl): kind = None ifname = msg.get_attr('IFLA_IFNAME') # fix master if not nl.capabilities['provide_master']: master = compat_get_master(ifname) if master is not None: msg['attrs'].append(['IFLA_MASTER', master]) # fix linkinfo & kind li = msg.get_attr('IFLA_LINKINFO') if li is not None: kind = li.get_attr('IFLA_INFO_KIND') if kind is None: kind = get_interface_type(ifname) li['attrs'].append(['IFLA_INFO_KIND', kind]) elif 'attrs' in msg: kind = get_interface_type(ifname) msg['attrs'].append( ['IFLA_LINKINFO', {'attrs': [['IFLA_INFO_KIND', kind]]}] ) else: return li = msg.get_attr('IFLA_LINKINFO') # fetch specific interface data if (kind in ('bridge', 'bond')) and [ x for x in li['attrs'] if x[0] == 'IFLA_INFO_DATA' ]: if kind == 'bridge': t = '/sys/class/net/%s/bridge/%s' ifdata = ifinfmsg.ifinfo.bridge_data elif kind == 'bond': t = '/sys/class/net/%s/bonding/%s' ifdata = ifinfmsg.ifinfo.bond_data commands = [] for cmd, _ in ifdata.nla_map: try: with open(t % (ifname, ifdata.nla2name(cmd)), 'r') as f: value = f.read() if cmd == 'IFLA_BOND_MODE': value = value.split()[1] commands.append([cmd, int(value)]) except: pass if commands: li['attrs'].append(['IFLA_INFO_DATA', {'attrs': commands}]) def proxy_linkinfo(data, nl): marshal = MarshalRtnl() inbox = marshal.parse(data) data = b'' for msg in inbox: if msg['event'] == 'NLMSG_ERROR': data += msg.data continue # Sysfs operations can require root permissions, # but the script can be run under a normal user # Bug-Url: https://github.com/svinota/pyroute2/issues/113 try: compat_fix_attrs(msg, nl) except OSError: # We can safely ignore here any OSError. # In the worst case, we just return what we have got # from the kernel via netlink pass msg.reset() msg.encode() data += msg.data return {'verdict': 'forward', 'data': data} def proxy_setlink(imsg, nl): def get_interface(index): msg = nl.get_links(index)[0] try: kind = msg.get_attr('IFLA_LINKINFO').get_attr('IFLA_INFO_KIND') except AttributeError: kind = 'unknown' return { 'ifname': msg.get_attr('IFLA_IFNAME'), 'master': msg.get_attr('IFLA_MASTER'), 'kind': kind, } msg = ifinfmsg(imsg.data) msg.decode() forward = True kind = None infodata = None ifname = ( msg.get_attr('IFLA_IFNAME') or get_interface(msg['index'])['ifname'] ) linkinfo = msg.get_attr('IFLA_LINKINFO') if linkinfo: kind = linkinfo.get_attr('IFLA_INFO_KIND') infodata = linkinfo.get_attr('IFLA_INFO_DATA') if kind in ('bond', 'bridge') and infodata is not None: code = 0 # if kind == 'bond': func = compat_set_bond elif kind == 'bridge': func = compat_set_bridge # for cmd, value in infodata.get('attrs', []): cmd = infodata.nla2name(cmd) code = func(ifname, cmd, value) or code # if code: err = OSError() err.errno = code raise err # is it a port setup? master = msg.get_attr('IFLA_MASTER') if master is not None: if master == 0: # port delete # 1. get the current master iface = get_interface(msg['index']) master = get_interface(iface['master']) cmd = 'del' else: # port add # 1. get the master master = get_interface(master) cmd = 'add' # 2. manage the port forward_map = { 'team': manage_team_port, 'bridge': compat_bridge_port, 'bond': compat_bond_port, } if master['kind'] in forward_map: func = forward_map[master['kind']] forward = func(cmd, master['ifname'], ifname, nl) if forward is not None: return {'verdict': 'forward', 'data': imsg.data} def proxy_dellink(imsg, nl): orig_msg = ifinfmsg(imsg.data) orig_msg.decode() # get full interface description msg = nl.get_links(orig_msg['index'])[0] msg['header']['type'] = orig_msg['header']['type'] # get the interface kind kind = None li = msg.get_attr('IFLA_LINKINFO') if li is not None: kind = li.get_attr('IFLA_INFO_KIND') # team interfaces can be stopped by a normal RTM_DELLINK if kind == 'bond' and not nl.capabilities['create_bond']: return compat_del_bond(msg) elif kind == 'bridge' and not nl.capabilities['create_bridge']: return compat_del_bridge(msg) return {'verdict': 'forward', 'data': imsg.data} def proxy_newlink(imsg, nl): msg = ifinfmsg(imsg.data) msg.decode() kind = None # get the interface kind linkinfo = msg.get_attr('IFLA_LINKINFO') if linkinfo is not None: kind = [x[1] for x in linkinfo['attrs'] if x[0] == 'IFLA_INFO_KIND'] if kind: kind = kind[0] if kind == 'tuntap': return manage_tuntap(msg) elif kind == 'team': return manage_team(msg) elif kind == 'bond' and not nl.capabilities['create_bond']: return compat_create_bond(msg) elif kind == 'bridge' and not nl.capabilities['create_bridge']: return compat_create_bridge(msg) return {'verdict': 'forward', 'data': imsg.data} @map_enoent @sync def manage_team(msg): if msg['header']['type'] != RTM_NEWLINK: raise ValueError('wrong command type') config = { 'device': msg.get_attr('IFLA_IFNAME'), 'runner': {'name': 'activebackup'}, 'link_watch': {'name': 'ethtool'}, } with open(os.devnull, 'w') as fnull: subprocess.check_call( ['teamd', '-d', '-n', '-c', json.dumps(config)], stdout=fnull, stderr=fnull, ) @map_enoent def manage_team_port(cmd, master, ifname, nl): with open(os.devnull, 'w') as fnull: subprocess.check_call( [ 'teamdctl', master, 'port', 'remove' if cmd == 'del' else 'add', ifname, ], stdout=fnull, stderr=fnull, ) @sync def compat_create_bridge(msg): name = msg.get_attr('IFLA_IFNAME') with open(os.devnull, 'w') as fnull: subprocess.check_call( ['brctl', 'addbr', name], stdout=fnull, stderr=fnull ) @sync def compat_create_bond(msg): name = msg.get_attr('IFLA_IFNAME') with open(_BONDING_MASTERS, 'w') as f: f.write('+%s' % (name)) def compat_set_bond(name, cmd, value): # FIXME: join with bridge # FIXME: use internal IO, not bash t = 'echo %s >/sys/class/net/%s/bonding/%s' with open(os.devnull, 'w') as fnull: return subprocess.call( ['bash', '-c', t % (value, name, cmd)], stdout=fnull, stderr=fnull ) def compat_set_bridge(name, cmd, value): t = 'echo %s >/sys/class/net/%s/bridge/%s' with open(os.devnull, 'w') as fnull: return subprocess.call( ['bash', '-c', t % (value, name, cmd)], stdout=fnull, stderr=fnull ) @sync def compat_del_bridge(msg): name = msg.get_attr('IFLA_IFNAME') with open(os.devnull, 'w') as fnull: subprocess.check_call(['ip', 'link', 'set', 'dev', name, 'down']) subprocess.check_call( ['brctl', 'delbr', name], stdout=fnull, stderr=fnull ) @sync def compat_del_bond(msg): name = msg.get_attr('IFLA_IFNAME') subprocess.check_call(['ip', 'link', 'set', 'dev', name, 'down']) with open(_BONDING_MASTERS, 'w') as f: f.write('-%s' % (name)) def compat_bridge_port(cmd, master, port, nl): if nl.capabilities['create_bridge']: return True with open(os.devnull, 'w') as fnull: subprocess.check_call( ['brctl', '%sif' % (cmd), master, port], stdout=fnull, stderr=fnull ) def compat_bond_port(cmd, master, port, nl): if nl.capabilities['create_bond']: return True remap = {'add': '+', 'del': '-'} cmd = remap[cmd] with open(_BONDING_SLAVES % (master), 'w') as f: f.write('%s%s' % (cmd, port)) def compat_get_master(name): f = None for i in (_BRIDGE_MASTER, _BONDING_MASTER): try: try: f = open(i % (name)) except UnicodeEncodeError: # a special case with python3 on Ubuntu 14 f = open(i % (name.encode('utf-8'))) break except IOError: pass if f is not None: master = int(f.read()) f.close() return master def get_interface_type(name): ''' Utility function to get interface type. Unfortunately, we can not rely on RTNL or even ioctl(). RHEL doesn't support interface type in RTNL and doesn't provide extended (private) interface flags via ioctl(). Args: * name (str): interface name Returns: * False -- sysfs info unavailable * None -- type not known * str -- interface type: - 'bond' - 'bridge' ''' # FIXME: support all interface types? Right now it is # not needed try: ifattrs = os.listdir('/sys/class/net/%s/' % (name)) except OSError as e: if e.errno == 2: return 'unknown' else: raise if 'bonding' in ifattrs: return 'bond' elif 'bridge' in ifattrs: return 'bridge' else: return 'unknown'