def get_routes(self, family=AF_INET, **kwarg): ''' Get all routes. You can specify the table. There are 255 routing classes (tables), and the kernel returns all the routes on each request. So the routine filters routes from full output. Example:: ip.get_routes() # get all the routes for all families ip.get_routes(family=AF_INET6) # get only IPv6 routes ip.get_routes(table=254) # get routes from 254 table ''' msg_flags = NLM_F_DUMP | NLM_F_REQUEST msg = rtmsg() # you can specify the table here, but the kernel # will ignore this setting table = kwarg.get('table', DEFAULT_TABLE) msg['table'] = table if table <= 255 else 252 # explicitly look for IPv6 if any([ kwarg.get(x, '').find(':') >= 0 for x in ('dst', 'src', 'gateway', 'prefsrc') ]): family = AF_INET6 msg['family'] = family # get a particular route if kwarg.get('dst', None) is not None: dlen = 32 if family == AF_INET else \ 128 if family == AF_INET6 else 0 msg_flags = NLM_F_REQUEST msg['dst_len'] = kwarg.get('dst_len', dlen) for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) routes = self.nlm_request(msg, RTM_GETROUTE, msg_flags) return [ x for x in routes if x.get_attr('RTA_TABLE') == table or kwarg.get('table', None) is None ]
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith('ipdb_'): return # fix family if isinstance(value, basestring) and value.find(':') >= 0: self['family'] = AF_INET6 # work on the rest if key == 'dst': if isinstance(value, dict): dict.__setitem__(self, 'dst', value) elif value != 'default': value = value.split('/') if len(value) == 1: dst = value[0] mask = 0 elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError('wrong destination') dict.__setitem__(self, 'dst', dst) dict.__setitem__(self, 'dst_len', mask) elif key == 'metrics': ret = {'attrs': []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret['attrs'].append([rtax, value[name]]) if ret['attrs']: dict.__setitem__(self, 'metrics', ret) elif key == 'multipath': ret = [] for v in value: nh = {'attrs': []} for name in ('flag', 'hops', 'ifindex'): nh[name] = v.pop(name, 0) for name in v: rta = rtmsg.name2nla(name) nh['attrs'].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, 'multipath', ret) else: dict.__setitem__(self, key, value)
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith('ipdb_'): return # fix family if isinstance(value, basestring) and value.find(':') >= 0: self['family'] = AF_INET6 # work on the rest if key == 'dst': if isinstance(value, dict): dict.__setitem__(self, 'dst', value) elif value != 'default': value = value.split('/') if len(value) == 1: dst = value[0] mask = 0 elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError('wrong destination') dict.__setitem__(self, 'dst', dst) dict.__setitem__(self, 'dst_len', mask) elif key == 'metrics': ret = {'attrs': []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret['attrs'].append([rtax, value[name]]) if ret['attrs']: dict.__setitem__(self, 'metrics', ret) elif key == 'multipath': ret = [] for v in value: nh = {'attrs': []} for name in ('flag', 'hops', 'ifindex'): nh[name] = v.pop(name, 0) for name in v: rta = rtmsg.name2nla(name) nh['attrs'].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, 'multipath', ret) else: dict.__setitem__(self, key, value)
def get_routes(self, family=AF_INET, **kwarg): """ Get all routes. You can specify the table. There are 255 routing classes (tables), and the kernel returns all the routes on each request. So the routine filters routes from full output. Example:: ip.get_routes() # get all the routes for all families ip.get_routes(family=AF_INET6) # get only IPv6 routes ip.get_routes(table=254) # get routes from 254 table """ msg_flags = NLM_F_DUMP | NLM_F_REQUEST msg = rtmsg() # you can specify the table here, but the kernel # will ignore this setting table = kwarg.get("table", DEFAULT_TABLE) msg["table"] = table if table <= 255 else 252 # explicitly look for IPv6 if any([kwarg.get(x, "").find(":") >= 0 for x in ("dst", "src", "gateway", "prefsrc")]): family = AF_INET6 msg["family"] = family # get a particular route if kwarg.get("dst", None) is not None: dlen = 32 if family == AF_INET else 128 if family == AF_INET6 else 0 msg_flags = NLM_F_REQUEST msg["dst_len"] = kwarg.get("dst_len", dlen) for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg["attrs"].append([nla, kwarg[key]]) routes = self.nlm_request(msg, RTM_GETROUTE, msg_flags) return [x for x in routes if x.get_attr("RTA_TABLE") == table or kwarg.get("table", None) is None]
def get_routes(self, family=AF_UNSPEC, **kwarg): ''' Get all routes. You can specify the table. There are 255 routing classes (tables), and the kernel returns all the routes on each request. So the routine filters routes from full output. Example:: ip.get_routes() # get all the routes for all families ip.get_routes(family=AF_INET6) # get only IPv6 routes ip.get_routes(table=254) # get routes from 254 table ''' msg_flags = NLM_F_DUMP | NLM_F_REQUEST msg = rtmsg() msg['family'] = family # you can specify the table here, but the kernel # will ignore this setting table = kwarg.get('table', 0) msg['table'] = table if table <= 255 else 252 # get a particular route if kwarg.get('dst', None) is not None: dlen = 32 if family == AF_INET else \ 128 if family == AF_INET6 else 0 msg_flags = NLM_F_REQUEST msg['dst_len'] = kwarg.get('dst_len', dlen) for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) routes = self.nlm_request(msg, RTM_GETROUTE, msg_flags) return [x for x in routes if x.get_attr('RTA_TABLE') == table or kwarg.get('table', None) is None]
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith('ipdb_'): return # fix family if isinstance(value, basestring) and value.find(':') >= 0: self['family'] = AF_INET6 # work on the rest if key == 'family' and value == AF_MPLS: dict.__setitem__(self, 'family', value) dict.__setitem__(self, 'dst_len', 20) dict.__setitem__(self, 'table', 254) dict.__setitem__(self, 'type', 1) elif key == 'flags' and self.get('family', None) == AF_MPLS: return elif key in ('dst', 'src'): if isinstance(value, dict): dict.__setitem__(self, key, value) elif isinstance(value, int): dict.__setitem__(self, key, {'label': value, 'bos': 1}) elif value != 'default': value = value.split('/') mask = None if len(value) == 1: dst = value[0] if '%s_len' % key not in self: if self.get('family', 0) == AF_INET: mask = 32 elif self.get('family', 0) == AF_INET6: mask = 128 else: self._mask.append('%s_len' % key) elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError('wrong address spec') dict.__setitem__(self, key, dst) if mask is not None: dict.__setitem__(self, '%s_len' % key, mask) elif key == 'newdst': dict.__setitem__(self, 'newdst', self.mpls_rta(value)) elif key in self.resolve.keys(): if isinstance(value, basestring): value = self.resolve[key][value] dict.__setitem__(self, key, value) elif key == 'encap': if isinstance(value, dict): # human-friendly form: # # 'encap': {'type': 'mpls', # 'labels': '200/300'} # # 'type' is mandatory if 'type' in value and 'labels' in value: dict.__setitem__(self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) # human-friendly form: # # 'encap': {'type': 'seg6', # 'mode': 'encap' # 'segs': '2000::5,2000::6'} # # 'encap': {'type': 'seg6', # 'mode': 'inline' # 'segs': '2000::5,2000::6' # 'hmac': 1} # # 'encap': {'type': 'seg6', # 'mode': 'encap' # 'segs': '2000::5,2000::6' # 'hmac': 0xf} # # 'encap': {'type': 'seg6', # 'mode': 'inline' # 'segs': ['2000::5', '2000::6']} # # 'type', 'mode' and 'segs' are mandatory if 'type' in value and 'mode' in value and 'segs' in value: dict.__setitem__(self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) elif 'type' in value and ('in' in value or 'out' in value or 'xmit' in value): dict.__setitem__(self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) # human-friendly form: # # 'encap': {'type': 'seg6local', # 'action': 'End'} # # 'encap': {'type': 'seg6local', # 'action': 'End.DT6', # 'table': '10'} # # 'encap': {'type': 'seg6local', # 'action': 'End.DX6', # 'nh6': '2000::5'} # # 'encap': {'type': 'seg6local', # 'action': 'End.B6' # 'srh': {'segs': '2000::5,2000::6', # 'hmac': 0xf}} # # 'type' and 'action' are mandatory elif 'type' in value and 'action' in value: dict.__setitem__(self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) # assume it is a ready-to-use NLA elif 'attrs' in value: dict.__setitem__(self, 'encap', value) elif key == 'via': # ignore empty RTA_VIA if isinstance(value, dict) and \ set(value.keys()) == set(('addr', 'family')) and \ value['family'] in (AF_INET, AF_INET6) and \ isinstance(value['addr'], basestring): dict.__setitem__(self, 'via', value) elif key == 'metrics': if 'attrs' in value: ret = value else: ret = {'attrs': []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret['attrs'].append([rtax, value[name]]) if ret['attrs']: dict.__setitem__(self, 'metrics', ret) elif key == 'multipath': ret = [] for v in value: if 'attrs' in v: ret.append(v) continue nh = {'attrs': []} nh_fields = [x[0] for x in nh_header.fields] for name in nh_fields: nh[name] = v.get(name, 0) for name in v: if name in nh_fields or v[name] is None: continue if name == 'encap' and isinstance(v[name], dict): if v[name].get('type', None) is None or \ v[name].get('labels', None) is None: continue nh['attrs'].append(['RTA_ENCAP_TYPE', encap_types.get(v[name]['type'], v[name]['type'])]) nh['attrs'].append(['RTA_ENCAP', self.encap_header(v[name])]) elif name == 'newdst': nh['attrs'].append(['RTA_NEWDST', self.mpls_rta(v[name])]) else: rta = rtmsg.name2nla(name) nh['attrs'].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, 'multipath', ret) elif key == 'family': for d in self._mask: if d not in self: if value == AF_INET: dict.__setitem__(self, d, 32) elif value == AF_INET6: dict.__setitem__(self, d, 128) self._mask = [] dict.__setitem__(self, key, value) else: dict.__setitem__(self, key, value)
def route(self, command, **kwarg): ''' Route operations. * command -- add, delete, change, replace * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * family -- socket.AF_INET (default) or socket.AF_INET6 * mask -- route prefix mask `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address * dst -- the same as `prefix` * src -- source address * iif -- incoming traffic interface * oif -- outgoing traffic interface etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") Commands `change` and `replace` have the same meanings, as in ip-route(8): `change` modifies only existing route, while `replace` creates a new one, if there is no such route yet. ''' # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_change = flags_base | NLM_F_REPLACE flags_replace = flags_change | NLM_F_CREATE # 8<---------------------------------------------------- commands = {'add': (RTM_NEWROUTE, flags_make), 'set': (RTM_NEWROUTE, flags_replace), 'replace': (RTM_NEWROUTE, flags_replace), 'change': (RTM_NEWROUTE, flags_change), 'del': (RTM_DELROUTE, flags_make), 'remove': (RTM_DELROUTE, flags_make), 'delete': (RTM_DELROUTE, flags_make)} (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get('table', 254) msg['table'] = table if table <= 255 else 252 msg['family'] = kwarg.pop('family', AF_INET) msg['proto'] = rtprotos[kwarg.pop('rtproto', 'RTPROT_STATIC')] msg['type'] = rtypes[kwarg.pop('rtype', 'RTN_UNICAST')] msg['scope'] = rtscopes[kwarg.pop('rtscope', 'RT_SCOPE_UNIVERSE')] msg['dst_len'] = kwarg.pop('dst_len', None) or kwarg.pop('mask', 0) msg['attrs'] = [] # FIXME # deprecated "prefix" support: if 'prefix' in kwarg: logging.warning('`prefix` argument is deprecated, use `dst`') kwarg['dst'] = kwarg['prefix'] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) ret = self.nlm_request(msg, msg_type=command, msg_flags=flags) if 'match' in kwarg: return self._match(kwarg['match'], ret) else: return ret
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith('ipdb_'): return # fix family if isinstance(value, basestring) and value.find(':') >= 0: self['family'] = AF_INET6 # work on the rest if key == 'family' and value == AF_MPLS: dict.__setitem__(self, 'family', value) dict.__setitem__(self, 'dst_len', 20) dict.__setitem__(self, 'table', 254) dict.__setitem__(self, 'type', 1) elif key == 'flags': if self['family'] == AF_MPLS: return elif key == 'dst': if isinstance(value, dict): dict.__setitem__(self, 'dst', value) elif isinstance(value, int): dict.__setitem__(self, 'dst', {'label': value, 'bos': 1}) elif value != 'default': value = value.split('/') if len(value) == 1: dst = value[0] mask = 0 elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError('wrong destination') dict.__setitem__(self, 'dst', dst) if mask: dict.__setitem__(self, 'dst_len', mask) elif key == 'newdst': dict.__setitem__(self, 'newdst', self.mpls_rta(value)) elif key in self.resolve.keys(): if isinstance(value, basestring): value = self.resolve[key][value] dict.__setitem__(self, key, value) elif key == 'encap': if isinstance(value, dict): # human-friendly form: # # 'encap': {'type': 'mpls', # 'labels': '200/300'} # # 'type' is mandatory if 'type' in value and 'labels' in value: dict.__setitem__(self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) # assume it is a ready-to-use NLA elif 'attrs' in value: dict.__setitem__(self, 'encap', value) elif key == 'via': # ignore empty RTA_VIA if isinstance(value, dict) and \ set(value.keys()) == set(('addr', 'family')) and \ value['family'] in (AF_INET, AF_INET6) and \ isinstance(value['addr'], basestring): dict.__setitem__(self, 'via', value) elif key == 'metrics': if 'attrs' in value: ret = value else: ret = {'attrs': []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret['attrs'].append([rtax, value[name]]) if ret['attrs']: dict.__setitem__(self, 'metrics', ret) elif key == 'multipath': ret = [] for v in value: if 'attrs' in v: ret.append(v) continue nh = {'attrs': []} nh_fields = [x[0] for x in nh_header.fields] for name in nh_fields: nh[name] = v.get(name, 0) for name in v: if name in nh_fields or v[name] is None: continue if name == 'encap' and isinstance(v[name], dict): if v[name].get('type', None) is None or \ v[name].get('labels', None) is None: continue nh['attrs'].append(['RTA_ENCAP_TYPE', encap_types.get(v[name]['type'], v[name]['type'])]) nh['attrs'].append(['RTA_ENCAP', self.encap_header(v[name])]) elif name == 'newdst': nh['attrs'].append(['RTA_NEWDST', self.mpls_rta(v[name])]) else: rta = rtmsg.name2nla(name) nh['attrs'].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, 'multipath', ret) else: dict.__setitem__(self, key, value)
def route(self, command, rtype='RTN_UNICAST', rtproto='RTPROT_STATIC', rtscope='RT_SCOPE_UNIVERSE', **kwarg): ''' Route operations * command -- add, delete * prefix -- route prefix * mask -- route prefix mask * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * index -- via device index * family -- socket.AF_INET (default) or socket.AF_INET6 `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") ''' # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_replace = flags_base | NLM_F_REPLACE # 8<---------------------------------------------------- commands = {'add': (RTM_NEWROUTE, flags_make), 'set': (RTM_NEWROUTE, flags_replace), 'delete': (RTM_DELROUTE, flags_make)} (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get('table', 254) msg['table'] = table if table <= 255 else 252 msg['family'] = kwarg.get('family', AF_INET) msg['proto'] = rtprotos[rtproto] msg['type'] = rtypes[rtype] msg['scope'] = rtscopes[rtscope] msg['dst_len'] = kwarg.get('dst_len', None) or \ kwarg.get('mask', 0) msg['attrs'] = [] # FIXME # deprecated "prefix" support: if 'prefix' in kwarg: kwarg['dst'] = kwarg['prefix'] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith('ipdb_'): return # fix family if isinstance(value, basestring) and value.find(':') >= 0: self['family'] = AF_INET6 # work on the rest if key == 'family' and value == AF_MPLS: dict.__setitem__(self, 'family', value) dict.__setitem__(self, 'dst_len', 20) dict.__setitem__(self, 'table', 254) dict.__setitem__(self, 'type', 1) elif key == 'flags': if self['family'] == AF_MPLS: return elif key == 'dst': if isinstance(value, dict): dict.__setitem__(self, 'dst', value) elif isinstance(value, int): dict.__setitem__(self, 'dst', {'label': value, 'bos': 1}) elif value != 'default': value = value.split('/') if len(value) == 1: dst = value[0] mask = 0 elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError('wrong destination') dict.__setitem__(self, 'dst', dst) if mask: dict.__setitem__(self, 'dst_len', mask) elif key == 'newdst': dict.__setitem__(self, 'newdst', self.mpls_rta(value)) elif key in self.resolve.keys(): if isinstance(value, basestring): value = self.resolve[key][value] dict.__setitem__(self, key, value) elif key == 'encap': if isinstance(value, dict): # human-friendly form: # # 'encap': {'type': 'mpls', # 'labels': '200/300'} # # 'type' is mandatory if 'type' in value and 'labels' in value: dict.__setitem__( self, 'encap_type', encap_types.get(value['type'], value['type'])) dict.__setitem__(self, 'encap', self.encap_header(value)) # assume it is a ready-to-use NLA elif 'attrs' in value: dict.__setitem__(self, 'encap', value) elif key == 'via': # ignore empty RTA_VIA if isinstance(value, dict) and \ set(value.keys()) == set(('addr', 'family')) and \ value['family'] in (AF_INET, AF_INET6) and \ isinstance(value['addr'], basestring): dict.__setitem__(self, 'via', value) elif key == 'metrics': if 'attrs' in value: ret = value else: ret = {'attrs': []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret['attrs'].append([rtax, value[name]]) if ret['attrs']: dict.__setitem__(self, 'metrics', ret) elif key == 'multipath': ret = [] for v in value: if 'attrs' in v: ret.append(v) continue nh = {'attrs': []} nh_fields = [x[0] for x in nh_header.fields] for name in nh_fields: nh[name] = v.get(name, 0) for name in v: if name in nh_fields or v[name] is None: continue if name == 'encap' and isinstance(v[name], dict): if v[name].get('type', None) is None or \ v[name].get('labels', None) is None: continue nh['attrs'].append([ 'RTA_ENCAP_TYPE', encap_types.get(v[name]['type'], v[name]['type']) ]) nh['attrs'].append( ['RTA_ENCAP', self.encap_header(v[name])]) elif name == 'newdst': nh['attrs'].append( ['RTA_NEWDST', self.mpls_rta(v[name])]) else: rta = rtmsg.name2nla(name) nh['attrs'].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, 'multipath', ret) else: dict.__setitem__(self, key, value)
def route(self, command, **kwarg): ''' Route operations. * command -- add, delete, change, replace * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * family -- socket.AF_INET (default) or socket.AF_INET6 * mask -- route prefix mask `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address * dst -- the same as `prefix` * src -- source address * iif -- incoming traffic interface * oif -- outgoing traffic interface etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") Commands `change` and `replace` have the same meanings, as in ip-route(8): `change` modifies only existing route, while `replace` creates a new one, if there is no such route yet. It is possible to set also route metrics. There are two ways to do so. The first is to use 'raw' NLA notation:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1", metrics={"attrs": [["RTAX_MTU", 1400], ["RTAX_HOPLIMIT", 16]]}) The second way is to use `IPRouteRequest` helper:: from pyroute2.netlink.rtnl.req import IPRouteRequest ... ip.route("add", **IPRouteRequest({"dst": "10.0.0.0/24", "gateway": "192.168.0.1", "metrics": {"mtu": 1400, "hoplimit": 16}})) The `IPRouteRequest` helper is useful also to manage mulptipath routes:: from pyroute2.netlink.rtnl.req import IPRouteRequest ... request = {"dst": "10.0.0.0/24", "multipath": [{"gateway": "192.168.0.1", "hops": 2}, {"gateway": "192.168.0.2", "hops": 1}, {"gateway": "192.168.0.3"}]} ip.route("add", **IPRouteRequest(request)) ''' # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_change = flags_base | NLM_F_REPLACE flags_replace = flags_change | NLM_F_CREATE # 8<---------------------------------------------------- commands = { 'add': (RTM_NEWROUTE, flags_make), 'set': (RTM_NEWROUTE, flags_replace), 'replace': (RTM_NEWROUTE, flags_replace), 'change': (RTM_NEWROUTE, flags_change), 'del': (RTM_DELROUTE, flags_make), 'remove': (RTM_DELROUTE, flags_make), 'delete': (RTM_DELROUTE, flags_make) } (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get('table', 254) msg['table'] = table if table <= 255 else 252 msg['family'] = kwarg.pop('family', AF_INET) msg['proto'] = rtprotos[kwarg.pop('rtproto', 'RTPROT_STATIC')] msg['type'] = rtypes[kwarg.pop('rtype', 'RTN_UNICAST')] msg['scope'] = rtscopes[kwarg.pop('rtscope', 'RT_SCOPE_UNIVERSE')] msg['dst_len'] = kwarg.pop('dst_len', None) or kwarg.pop('mask', 0) msg['src_len'] = kwarg.pop('src_len', 0) msg['tos'] = kwarg.pop('tos', 0) msg['flags'] = kwarg.pop('flags', 0) msg['attrs'] = [] # FIXME # deprecated "prefix" support: if 'prefix' in kwarg: logging.warning('`prefix` argument is deprecated, use `dst`') kwarg['dst'] = kwarg['prefix'] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) # fix IP family, if needed if msg['family'] == AF_UNSPEC: if key in ('dst', 'src', 'gateway', 'prefsrc', 'newdst') \ and isinstance(kwarg[key], basestring): msg['family'] = AF_INET6 if kwarg[key].find(':') >= 0 \ else AF_INET elif key == 'multipath' and len(kwarg[key]) > 0: hop = kwarg[key][0] attrs = hop.get('attrs', []) for attr in attrs: if attr[0] == 'RTA_GATEWAY': msg['family'] = AF_INET6 if \ attr[1].find(':') >= 0 else AF_INET break ret = self.nlm_request(msg, msg_type=command, msg_flags=flags) if 'match' in kwarg: return self._match(kwarg['match'], ret) else: return ret
def route(self, command, rtype="RTN_UNICAST", rtproto="RTPROT_STATIC", rtscope="RT_SCOPE_UNIVERSE", **kwarg): """ Route operations * command -- add, delete, change, replace * prefix -- route prefix * mask -- route prefix mask * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * family -- socket.AF_INET (default) or socket.AF_INET6 `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address * dst -- the same as `prefix` * src -- source address * iif -- incoming traffic interface * oif -- outgoing traffic interface etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") Commands `change` and `replace` have the same meanings, as in ip-route(8): `change` modifies only existing route, while `replace` creates a new one, if there is no such route yet. """ # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_change = flags_base | NLM_F_REPLACE flags_replace = flags_change | NLM_F_CREATE # 8<---------------------------------------------------- commands = { "add": (RTM_NEWROUTE, flags_make), "set": (RTM_NEWROUTE, flags_replace), "replace": (RTM_NEWROUTE, flags_replace), "change": (RTM_NEWROUTE, flags_change), "del": (RTM_DELROUTE, flags_make), "remove": (RTM_DELROUTE, flags_make), "delete": (RTM_DELROUTE, flags_make), } (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get("table", 254) msg["table"] = table if table <= 255 else 252 msg["family"] = kwarg.get("family", AF_INET) msg["proto"] = rtprotos[rtproto] msg["type"] = rtypes[rtype] msg["scope"] = rtscopes[rtscope] msg["dst_len"] = kwarg.get("dst_len", None) or kwarg.get("mask", 0) msg["attrs"] = [] # FIXME # deprecated "prefix" support: if "prefix" in kwarg: kwarg["dst"] = kwarg["prefix"] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg["attrs"].append([nla, kwarg[key]]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def route(self, command, rtype='RTN_UNICAST', rtproto='RTPROT_STATIC', rtscope='RT_SCOPE_UNIVERSE', **kwarg): ''' Route operations * command -- add, delete, change, replace * prefix -- route prefix * mask -- route prefix mask * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * family -- socket.AF_INET (default) or socket.AF_INET6 `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address * dst -- the same as `prefix` * src -- source address * iif -- incoming traffic interface * oif -- outgoing traffic interface etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") Commands `change` and `replace` have the same meanings, as in ip-route(8): `change` modifies only existing route, while `replace` creates a new one, if there is no such route yet. ''' # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_change = flags_base | NLM_F_REPLACE flags_replace = flags_change | NLM_F_CREATE # 8<---------------------------------------------------- commands = { 'add': (RTM_NEWROUTE, flags_make), 'set': (RTM_NEWROUTE, flags_replace), 'replace': (RTM_NEWROUTE, flags_replace), 'change': (RTM_NEWROUTE, flags_change), 'del': (RTM_DELROUTE, flags_make), 'remove': (RTM_DELROUTE, flags_make), 'delete': (RTM_DELROUTE, flags_make) } (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get('table', 254) msg['table'] = table if table <= 255 else 252 msg['family'] = kwarg.get('family', AF_INET) msg['proto'] = rtprotos[rtproto] msg['type'] = rtypes[rtype] msg['scope'] = rtscopes[rtscope] msg['dst_len'] = kwarg.get('dst_len', None) or \ kwarg.get('mask', 0) msg['attrs'] = [] # FIXME # deprecated "prefix" support: if 'prefix' in kwarg: kwarg['dst'] = kwarg['prefix'] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def route(self, command, **kwarg): ''' Route operations. * command -- add, delete, change, replace * rtype -- route type (default: "RTN_UNICAST") * rtproto -- routing protocol (default: "RTPROT_STATIC") * rtscope -- routing scope (default: "RT_SCOPE_UNIVERSE") * family -- socket.AF_INET (default) or socket.AF_INET6 * mask -- route prefix mask `pyroute2/netlink/rtnl/rtmsg.py` rtmsg.nla_map: * table -- routing table to use (default: 254) * gateway -- via address * prefsrc -- preferred source IP address * dst -- the same as `prefix` * src -- source address * iif -- incoming traffic interface * oif -- outgoing traffic interface etc. Example:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1") Commands `change` and `replace` have the same meanings, as in ip-route(8): `change` modifies only existing route, while `replace` creates a new one, if there is no such route yet. It is possible to set also route metrics. There are two ways to do so. The first is to use 'raw' NLA notation:: ip.route("add", dst="10.0.0.0", mask=24, gateway="192.168.0.1", metrics={"attrs": [["RTAX_MTU", 1400], ["RTAX_HOPLIMIT", 16]]}) The second way is to use `IPRouteRequest` helper:: from pyroute2.netlink.rtnl.req import IPRouteRequest ... ip.route("add", **IPRouteRequest({"dst": "10.0.0.0/24", "gateway": "192.168.0.1", "metrics": {"mtu": 1400, "hoplimit": 16}})) The `IPRouteRequest` helper is useful also to manage mulptipath routes:: from pyroute2.netlink.rtnl.req import IPRouteRequest ... request = {"dst": "10.0.0.0/24", "multipath": [{"gateway": "192.168.0.1", "hops": 2}, {"gateway": "192.168.0.2", "hops": 1}, {"gateway": "192.168.0.3"}]} ip.route("add", **IPRouteRequest(request)) ''' # 8<---------------------------------------------------- # FIXME # flags should be moved to some more general place flags_base = NLM_F_REQUEST | NLM_F_ACK flags_make = flags_base | NLM_F_CREATE | NLM_F_EXCL flags_change = flags_base | NLM_F_REPLACE flags_replace = flags_change | NLM_F_CREATE # 8<---------------------------------------------------- commands = {'add': (RTM_NEWROUTE, flags_make), 'set': (RTM_NEWROUTE, flags_replace), 'replace': (RTM_NEWROUTE, flags_replace), 'change': (RTM_NEWROUTE, flags_change), 'del': (RTM_DELROUTE, flags_make), 'remove': (RTM_DELROUTE, flags_make), 'delete': (RTM_DELROUTE, flags_make)} (command, flags) = commands.get(command, command) msg = rtmsg() # table is mandatory; by default == 254 # if table is not defined in kwarg, save it there # also for nla_attr: table = kwarg.get('table', 254) msg['table'] = table if table <= 255 else 252 msg['family'] = kwarg.pop('family', AF_INET) msg['proto'] = rtprotos[kwarg.pop('rtproto', 'RTPROT_STATIC')] msg['type'] = rtypes[kwarg.pop('rtype', 'RTN_UNICAST')] msg['scope'] = rtscopes[kwarg.pop('rtscope', 'RT_SCOPE_UNIVERSE')] msg['dst_len'] = kwarg.pop('dst_len', None) or kwarg.pop('mask', 0) msg['src_len'] = kwarg.pop('src_len', 0) msg['tos'] = kwarg.pop('tos', 0) msg['flags'] = kwarg.pop('flags', 0) msg['attrs'] = [] # FIXME # deprecated "prefix" support: if 'prefix' in kwarg: logging.warning('`prefix` argument is deprecated, use `dst`') kwarg['dst'] = kwarg['prefix'] for key in kwarg: nla = rtmsg.name2nla(key) if kwarg[key] is not None: msg['attrs'].append([nla, kwarg[key]]) # fix IP family, if needed if msg['family'] == AF_UNSPEC: if key in ('dst', 'src', 'gateway', 'prefsrc', 'newdst') \ and isinstance(kwarg[key], basestring): msg['family'] = AF_INET6 if kwarg[key].find(':') >= 0 \ else AF_INET elif key == 'multipath' and len(kwarg[key]) > 0: hop = kwarg[key][0] attrs = hop.get('attrs', []) for attr in attrs: if attr[0] == 'RTA_GATEWAY': msg['family'] = AF_INET6 if \ attr[1].find(':') >= 0 else AF_INET break ret = self.nlm_request(msg, msg_type=command, msg_flags=flags) if 'match' in kwarg: return self._match(kwarg['match'], ret) else: return ret
def __setitem__(self, key, value): # skip virtual IPDB fields if key.startswith("ipdb_"): return # fix family if isinstance(value, basestring) and value.find(":") >= 0: self["family"] = AF_INET6 # work on the rest if key == "family" and value == AF_MPLS: dict.__setitem__(self, "family", value) dict.__setitem__(self, "dst_len", 20) dict.__setitem__(self, "table", 254) dict.__setitem__(self, "type", 1) elif key == "flags": if self["family"] == AF_MPLS: return elif key == "dst": if isinstance(value, dict): dict.__setitem__(self, "dst", value) elif isinstance(value, int): dict.__setitem__(self, "dst", {"label": value, "bos": 1}) elif value != "default": value = value.split("/") if len(value) == 1: dst = value[0] mask = 0 elif len(value) == 2: dst = value[0] mask = int(value[1]) else: raise ValueError("wrong destination") dict.__setitem__(self, "dst", dst) if mask: dict.__setitem__(self, "dst_len", mask) elif key == "newdst": dict.__setitem__(self, "newdst", self.mpls_rta(value)) elif key in self.resolve.keys(): if isinstance(value, basestring): value = self.resolve[key][value] dict.__setitem__(self, key, value) elif key == "encap": if isinstance(value, dict): # human-friendly form: # # 'encap': {'type': 'mpls', # 'labels': '200/300'} # # 'type' is mandatory if "type" in value and "labels" in value: dict.__setitem__(self, "encap_type", encap_types.get(value["type"], value["type"])) dict.__setitem__(self, "encap", self.encap_header(value)) # assume it is a ready-to-use NLA elif "attrs" in value: dict.__setitem__(self, "encap", value) elif key == "via": # ignore empty RTA_VIA if ( isinstance(value, dict) and set(value.keys()) == set(("addr", "family")) and value["family"] in (AF_INET, AF_INET6) and isinstance(value["addr"], basestring) ): dict.__setitem__(self, "via", value) elif key == "metrics": if "attrs" in value: ret = value else: ret = {"attrs": []} for name in value: rtax = rtmsg.metrics.name2nla(name) ret["attrs"].append([rtax, value[name]]) if ret["attrs"]: dict.__setitem__(self, "metrics", ret) elif key == "multipath": ret = [] for v in value: if "attrs" in v: ret.append(v) continue nh = {"attrs": []} nh_fields = [x[0] for x in nh_header.fields] for name in nh_fields: nh[name] = v.get(name, 0) for name in v: if name in nh_fields or v[name] is None: continue if name == "encap" and isinstance(v[name], dict): if v[name].get("type", None) is None or v[name].get("labels", None) is None: continue nh["attrs"].append(["RTA_ENCAP_TYPE", encap_types.get(v[name]["type"], v[name]["type"])]) nh["attrs"].append(["RTA_ENCAP", self.encap_header(v[name])]) elif name == "newdst": nh["attrs"].append(["RTA_NEWDST", self.mpls_rta(v[name])]) else: rta = rtmsg.name2nla(name) nh["attrs"].append([rta, v[name]]) ret.append(nh) if ret: dict.__setitem__(self, "multipath", ret) else: dict.__setitem__(self, key, value)