def get_classes(self, index=0): ''' Get classes for specified interface. ''' msg = tcmsg() msg['family'] = AF_UNSPEC msg['index'] = index return self.nlm_request(msg, RTM_GETTCLASS)
def get_classes(self, index=0): """ Get classes for specified interface. """ msg = tcmsg() msg["family"] = AF_UNSPEC msg["index"] = index return self.nlm_request(msg, RTM_GETTCLASS)
def get_filters(self, index=0, handle=0, parent=0): ''' Get filters for specified interface, handle and parent. ''' msg = tcmsg() msg['family'] = AF_UNSPEC msg['index'] = index msg['handle'] = handle msg['parent'] = parent return self.nlm_request(msg, RTM_GETTFILTER)
def get_filters(self, index=0, handle=0, parent=0): """ Get filters for specified interface, handle and parent. """ msg = tcmsg() msg["family"] = AF_UNSPEC msg["index"] = index msg["handle"] = handle msg["parent"] = parent return self.nlm_request(msg, RTM_GETTFILTER)
def get_qdiscs(self, index=None): ''' Get all queue disciplines for all interfaces or for specified one. ''' msg = tcmsg() msg['family'] = AF_UNSPEC ret = self.nlm_request(msg, RTM_GETQDISC) if index is None: return ret else: return [x for x in ret if x['index'] == index]
def del_filter_by_info(self, index=0, handle=0, info=0, parent=0): msg = tcmsg() msg['index'] = index msg['handle'] = handle msg['info'] = info if parent != 0: msg['parent'] = parent return tuple( ipr.nlm_request(msg, msg_type=RTM_DELTFILTER, msg_flags=NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL))
def _manage_plug_via_netlink(interface_name, action='unplug'): """ Manipulates the plug qdisc via netlink FIXME: Once we have a modern userpace, replace this with appropriate calls to nl-qdisc-add """ ip = IPRoute() index = ip.link_lookup(ifname=interface_name)[0] # See the linux source at include/uapi/linux/pkt_sched.h # #define TCQ_PLUG_BUFFER 0 # #define TCQ_PLUG_RELEASE_ONE 1 # #define TCQ_PLUG_RELEASE_INDEFINITE 2 # #define TCQ_PLUG_LIMIT 3 action = {'unplug': 2, 'plug': 0}[action] packet_limit = 10000 handle = transform_handle(PLUG_QDISC) parent = transform_handle(PLUG_CLASS) flags = NLM_F_REQUEST | NLM_F_ACK command = pyroute2.netlink.rtnl.RTM_NEWQDISC # This is a bit of magic sauce, inspired by xen's remus project opts = struct.pack('iI', action, packet_limit) msg = tcmsg() msg['index'] = index msg['handle'] = handle msg['parent'] = parent msg['attrs'] = [['TCA_KIND', 'plug']] msg['attrs'].append(['TCA_OPTIONS', opts]) try: nlm_response = ip.nlm_request(msg, msg_type=command, msg_flags=flags) except pyroute2.netlink.NetlinkError as nle: if nle.code == 22: # This is an old kernel and we're talking to a qfifo, chill log.warn('Detected a non plug qdisc, likely due to an old kernel. ' 'If you wish to have zero downtime haproxy restarts, ' 'upgrade your kernel. ' 'Doing nothing to the SYN traffic lane...') return else: raise # As per the netlink manpage (man 7 netlink), we expect an # acknowledgment as a NLMSG_ERROR packet with the error field being 0, # which it looks like pyroute2 treats as None. Really we want it to be # non negative. if not(len(nlm_response) > 0 and nlm_response[0]['event'] == 'NLMSG_ERROR' and nlm_response[0]['header']['error'] is None): raise RuntimeError( 'Had an error while communicating with netlink: {0}'.format( nlm_response))
def tc(self, command, kind, index, handle=0, **kwarg): """ "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() ip.tc(RTM_NEWQDISC, "sfq", 1) More complex example with htb qdisc, lets assume eth0 == 2:: # u32 --> +--> htb 1:10 --> sfq 10:0 # | | # | | # eth0 -- htb 1:0 -- htb 1:1 # | | # | | # u32 --> +--> htb 1:20 --> sfq 20:0 eth0 = 2 # add root queue 1:0 ip.tc("add", "htb", eth0, 0x10000, default=0x200000) # root class 1:1 ip.tc("add-class", "htb", eth0, 0x10001, parent=0x10000, rate="256kbit", burst=1024 * 6) # two branches: 1:10 and 1:20 ip.tc("add-class", "htb", eth0, 0x10010, parent=0x10001, rate="192kbit", burst=1024 * 6, prio=1) ip.tc("add-class", "htb", eht0, 0x10020, parent=0x10001, rate="128kbit", burst=1024 * 6, prio=2) # two leaves: 10:0 and 20:0 ip.tc("add", "sfq", eth0, 0x100000, parent=0x10010, perturb=10) ip.tc("add", "sfq", eth0, 0x200000, parent=0x10020, perturb=10) # two filters: one to load packets into 1:10 and the # second to 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0x0006/0x00ff+8", "0x0000/0xffc0+2"]) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0x5/0xf+0", "0x10/0xff+33"]) """ commands = { "add": RTM_NEWQDISC, "del": RTM_DELQDISC, "remove": RTM_DELQDISC, "delete": RTM_DELQDISC, "add-class": RTM_NEWTCLASS, "del-class": RTM_DELTCLASS, "add-filter": RTM_NEWTFILTER, "del-filter": RTM_DELTFILTER, } command = commands.get(command, command) flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ("parent", "target", "default"): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg["index"] = index msg["handle"] = handle opts = kwarg.get("opts", None) if kind == "ingress": msg["parent"] = TC_H_INGRESS msg["handle"] = 0xFFFF0000 elif kind == "tbf": msg["parent"] = TC_H_ROOT if kwarg: opts = get_tbf_parameters(kwarg) elif kind == "htb": msg["parent"] = kwarg.get("parent", TC_H_ROOT) if kwarg: if command in (RTM_NEWQDISC, RTM_DELQDISC): opts = get_htb_parameters(kwarg) elif command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = get_htb_class_parameters(kwarg) elif kind == "netem": msg["parent"] = kwarg.get("parent", TC_H_ROOT) if kwarg: opts = get_netem_parameters(kwarg) elif kind == "sfq": msg["parent"] = kwarg.get("parent", TC_H_ROOT) if kwarg: opts = get_sfq_parameters(kwarg) elif kind == "u32": msg["parent"] = kwarg.get("parent") msg["info"] = htons(kwarg.get("protocol", 0) & 0xFFFF) | ((kwarg.get("prio", 0) << 16) & 0xFFFF0000) if kwarg: opts = get_u32_parameters(kwarg) elif kind == "fw": msg["parent"] = kwarg.get("parent") msg["info"] = htons(kwarg.get("protocol", 0) & 0xFFFF) | ((kwarg.get("prio", 0) << 16) & 0xFFFF0000) if kwarg: opts = get_fw_parameters(kwarg) else: msg["parent"] = kwarg.get("parent", TC_H_ROOT) if kind is not None: msg["attrs"] = [["TCA_KIND", kind]] if opts is not None: msg["attrs"].append(["TCA_OPTIONS", opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def tc(self, command, kind, index, handle=0, **kwarg): ''' "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 Target notice: if your target is a class/qdisc that applies an algorithm that can only apply to upstream traffic profile, but your keys variable explicitly references a match that is only relevant for upstream traffic, the kernel will reject the filter. Unless you're dealing with devices like IMQs For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL ip.tc((RTM_NEWQDISC, flags), "sfq", 1) More complex example with htb qdisc, lets assume eth0 == 2:: # u32 --> +--> htb 1:10 --> sfq 10:0 # | | # | | # eth0 -- htb 1:0 -- htb 1:1 # | | # | | # u32 --> +--> htb 1:20 --> sfq 20:0 eth0 = 2 # add root queue 1:0 ip.tc("add", "htb", eth0, 0x10000, default=0x200000) # root class 1:1 ip.tc("add-class", "htb", eth0, 0x10001, parent=0x10000, rate="256kbit", burst=1024 * 6) # two branches: 1:10 and 1:20 ip.tc("add-class", "htb", eth0, 0x10010, parent=0x10001, rate="192kbit", burst=1024 * 6, prio=1) ip.tc("add-class", "htb", eht0, 0x10020, parent=0x10001, rate="128kbit", burst=1024 * 6, prio=2) # two leaves: 10:0 and 20:0 ip.tc("add", "sfq", eth0, 0x100000, parent=0x10010, perturb=10) ip.tc("add", "sfq", eth0, 0x200000, parent=0x10020, perturb=10) # two filters: one to load packets into 1:10 and the # second to 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0x0006/0x00ff+8", "0x0000/0xffc0+2"]) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0x5/0xf+0", "0x10/0xff+33"]) Filters can also take an `action` argument, which affects the packet behavior when the filter matches. Currently the gact, bpf, and police action types are supported, and can be attached to the u32 and bpf filter types:: # An action can be a simple string, which translates to a gact type action = "drop" # Or it can be an explicit type (these are equivalent) action = dict(kind="gact", action="drop") # There can also be a chain of actions, which depend on the return # value of the previous action. action = [ dict(kind="bpf", fd=fd, name=name, action="ok"), dict(kind="police", rate="10kbit", burst=10240, limit=0), dict(kind="gact", action="ok"), ] # Add the action to a u32 match-all filter ip.tc("add", "htb", eth0, 0x10000, default=0x200000) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=protocols.ETH_P_ALL, target=0x10020, keys=["0x0/0x0+0"], action=action) # Add two more filters: One to send packets with a src address of # 192.168.0.1/32 into 1:10 and the second to send packets with a # dst address of 192.168.0.0/24 into 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0xc0a80001/0xffffffff+12"]) # 0xc0a800010 = 192.168.0.1 # 0xffffffff = 255.255.255.255 (/32) # 12 = Source network field bit offset ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0xc0a80000/0xffffff00+16"]) # 0xc0a80000 = 192.168.0.0 # 0xffffff00 = 255.255.255.0 (/24) # 16 = Destination network field bit offset ''' 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 commands = { 'add': (RTM_NEWQDISC, flags_make), 'del': (RTM_DELQDISC, flags_make), 'remove': (RTM_DELQDISC, flags_make), 'delete': (RTM_DELQDISC, flags_make), 'add-class': (RTM_NEWTCLASS, flags_make), 'del-class': (RTM_DELTCLASS, flags_make), 'change-class': (RTM_NEWTCLASS, flags_change), 'replace-class': (RTM_NEWTCLASS, flags_replace), 'add-filter': (RTM_NEWTFILTER, flags_make), 'del-filter': (RTM_DELTFILTER, flags_make), 'change-class': (RTM_NEWTFILTER, flags_change), 'replace-filter': (RTM_NEWTFILTER, flags_replace) } if isinstance(command, int): command = (command, flags_make) command, flags = commands.get(command, command) msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ('parent', 'target', 'default'): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg['index'] = index msg['handle'] = handle opts = kwarg.get('opts', None) if kind == 'ingress': msg['parent'] = TC_H_INGRESS msg['handle'] = 0xffff0000 elif kind == 'tbf': msg['parent'] = TC_H_ROOT if kwarg: opts = get_tbf_parameters(kwarg) elif kind == 'htb': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: if command in (RTM_NEWQDISC, RTM_DELQDISC): opts = get_htb_parameters(kwarg) elif command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = get_htb_class_parameters(kwarg) elif kind == 'netem': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_netem_parameters(kwarg) elif kind == 'sfq': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_sfq_parameters(kwarg) elif kind == 'u32': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_u32_parameters(kwarg) elif kind == 'fw': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_fw_parameters(kwarg) elif kind == 'bpf': msg['parent'] = kwarg.get('parent', TC_H_ROOT) msg['info'] = htons(kwarg.get('protocol', ETH_P_ALL) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_bpf_parameters(kwarg) else: msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kind is not None: msg['attrs'] = [['TCA_KIND', kind]] if opts is not None: msg['attrs'].append(['TCA_OPTIONS', opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
from pprint import pprint from pyroute2.netlink.rtnl.tcmsg import tcmsg import io import sys f = open(sys.argv[1], 'r') b = io.BytesIO() for a in f.readlines(): if a[0] == '#': continue while True: try: b.write(chr(int(a[2:4], 16))) except: break a = a[4:] b.seek(0) t = tcmsg(b) t.decode() pprint(t)
def tc(self, command, kind, index, handle=0, **kwarg): ''' "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 Target notice: if your target is a class/qdisc that applies an algorithm that can only apply to upstream traffic profile, but your keys variable explicitly references a match that is only relevant for upstream traffic, the kernel will reject the filter. Unless you're dealing with devices like IMQs For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL ip.tc((RTM_NEWQDISC, flags), "sfq", 1) More complex example with htb qdisc, lets assume eth0 == 2:: # u32 --> +--> htb 1:10 --> sfq 10:0 # | | # | | # eth0 -- htb 1:0 -- htb 1:1 # | | # | | # u32 --> +--> htb 1:20 --> sfq 20:0 eth0 = 2 # add root queue 1:0 ip.tc("add", "htb", eth0, 0x10000, default=0x200000) # root class 1:1 ip.tc("add-class", "htb", eth0, 0x10001, parent=0x10000, rate="256kbit", burst=1024 * 6) # two branches: 1:10 and 1:20 ip.tc("add-class", "htb", eth0, 0x10010, parent=0x10001, rate="192kbit", burst=1024 * 6, prio=1) ip.tc("add-class", "htb", eht0, 0x10020, parent=0x10001, rate="128kbit", burst=1024 * 6, prio=2) # two leaves: 10:0 and 20:0 ip.tc("add", "sfq", eth0, 0x100000, parent=0x10010, perturb=10) ip.tc("add", "sfq", eth0, 0x200000, parent=0x10020, perturb=10) # two filters: one to load packets into 1:10 and the # second to 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0x0006/0x00ff+8", "0x0000/0xffc0+2"]) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0x5/0xf+0", "0x10/0xff+33"]) Filters can also take an `action` argument, which affects the packet behavior when the filter matches. Currently the gact, bpf, and police action types are supported, and can be attached to the u32 and bpf filter types:: # An action can be a simple string, which translates to a gact type action = "drop" # Or it can be an explicit type (these are equivalent) action = dict(kind="gact", action="drop") # There can also be a chain of actions, which depend on the return # value of the previous action. action = [ dict(kind="bpf", fd=fd, name=name, action="ok"), dict(kind="police", rate="10kbit", burst=10240, limit=0), dict(kind="gact", action="ok"), ] # Add the action to a u32 match-all filter ip.tc("add", "htb", eth0, 0x10000, default=0x200000) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=protocols.ETH_P_ALL, target=0x10020, keys=["0x0/0x0+0"], action=action) # Add two more filters: One to send packets with a src address of # 192.168.0.1/32 into 1:10 and the second to send packets with a # dst address of 192.168.0.0/24 into 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0xc0a80001/0xffffffff+12"]) # 0xc0a800010 = 192.168.0.1 # 0xffffffff = 255.255.255.255 (/32) # 12 = Source network field bit offset ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0xc0a80000/0xffffff00+16"]) # 0xc0a80000 = 192.168.0.0 # 0xffffff00 = 255.255.255.0 (/24) # 16 = Destination network field bit offset ''' 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 commands = {'add': (RTM_NEWQDISC, flags_make), 'del': (RTM_DELQDISC, flags_make), 'remove': (RTM_DELQDISC, flags_make), 'delete': (RTM_DELQDISC, flags_make), 'add-class': (RTM_NEWTCLASS, flags_make), 'del-class': (RTM_DELTCLASS, flags_make), 'change-class': (RTM_NEWTCLASS, flags_change), 'replace-class': (RTM_NEWTCLASS, flags_replace), 'add-filter': (RTM_NEWTFILTER, flags_make), 'del-filter': (RTM_DELTFILTER, flags_make), 'change-class': (RTM_NEWTFILTER, flags_change), 'replace-filter': (RTM_NEWTFILTER, flags_replace)} if isinstance(command, int): command = (command, flags_make) command, flags = commands.get(command, command) msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ('parent', 'target', 'default'): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg['index'] = index msg['handle'] = handle opts = kwarg.get('opts', None) if kind == 'ingress': msg['parent'] = TC_H_INGRESS msg['handle'] = 0xffff0000 elif kind == 'tbf': msg['parent'] = TC_H_ROOT if kwarg: opts = get_tbf_parameters(kwarg) elif kind == 'htb': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: if command in (RTM_NEWQDISC, RTM_DELQDISC): opts = get_htb_parameters(kwarg) elif command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = get_htb_class_parameters(kwarg) elif kind == 'netem': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_netem_parameters(kwarg) elif kind == 'sfq': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_sfq_parameters(kwarg) elif kind == 'u32': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_u32_parameters(kwarg) elif kind == 'fw': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_fw_parameters(kwarg) elif kind == 'bpf': msg['parent'] = kwarg.get('parent', TC_H_ROOT) msg['info'] = htons(kwarg.get('protocol', ETH_P_ALL) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_bpf_parameters(kwarg) else: msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kind is not None: msg['attrs'] = [['TCA_KIND', kind]] if opts is not None: msg['attrs'].append(['TCA_OPTIONS', opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def tc(self, command, kind, index, handle=0, **kwarg): ''' "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() ip.tc(RTM_NEWQDISC, "sfq", 1) More complex example with htb qdisc, lets assume eth0 == 2:: # u32 --> +--> htb 1:10 --> sfq 10:0 # | | # | | # eth0 -- htb 1:0 -- htb 1:1 # | | # | | # u32 --> +--> htb 1:20 --> sfq 20:0 eth0 = 2 # add root queue 1:0 ip.tc("add", "htb", eth0, 0x10000, default=0x200000) # root class 1:1 ip.tc("add-class", "htb", eth0, 0x10001, parent=0x10000, rate="256kbit", burst=1024 * 6) # two branches: 1:10 and 1:20 ip.tc("add-class", "htb", eth0, 0x10010, parent=0x10001, rate="192kbit", burst=1024 * 6, prio=1) ip.tc("add-class", "htb", eht0, 0x10020, parent=0x10001, rate="128kbit", burst=1024 * 6, prio=2) # two leaves: 10:0 and 20:0 ip.tc("add", "sfq", eth0, 0x100000, parent=0x10010, perturb=10) ip.tc("add", "sfq", eth0, 0x200000, parent=0x10020, perturb=10) # two filters: one to load packets into 1:10 and the # second to 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0x0006/0x00ff+8", "0x0000/0xffc0+2"]) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0x5/0xf+0", "0x10/0xff+33"]) ''' commands = { 'add': RTM_NEWQDISC, 'del': RTM_DELQDISC, 'remove': RTM_DELQDISC, 'delete': RTM_DELQDISC, 'add-class': RTM_NEWTCLASS, 'del-class': RTM_DELTCLASS, 'add-filter': RTM_NEWTFILTER, 'del-filter': RTM_DELTFILTER } command = commands.get(command, command) flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ('parent', 'target', 'default'): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg['index'] = index msg['handle'] = handle opts = kwarg.get('opts', None) if kind == 'ingress': msg['parent'] = TC_H_INGRESS msg['handle'] = 0xffff0000 elif kind == 'tbf': msg['parent'] = TC_H_ROOT if kwarg: opts = get_tbf_parameters(kwarg) elif kind == 'htb': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: if command in (RTM_NEWQDISC, RTM_DELQDISC): opts = get_htb_parameters(kwarg) elif command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = get_htb_class_parameters(kwarg) elif kind == 'netem': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_netem_parameters(kwarg) elif kind == 'sfq': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_sfq_parameters(kwarg) elif kind == 'u32': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_u32_parameters(kwarg) elif kind == 'fw': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_fw_parameters(kwarg) else: msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kind is not None: msg['attrs'] = [['TCA_KIND', kind]] if opts is not None: msg['attrs'].append(['TCA_OPTIONS', opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def tc(self, command, kind=None, index=0, handle=0, **kwarg): ''' "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 Target notice: if your target is a class/qdisc that applies an algorithm that can only apply to upstream traffic profile, but your keys variable explicitly references a match that is only relevant for upstream traffic, the kernel will reject the filter. Unless you're dealing with devices like IMQs For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL ip.tc((RTM_NEWQDISC, flags), "sfq", 1) Also available "modules" (returns tc plugins dict) and "help" commands:: help(ip.tc("modules")["htb"]) print(ip.tc("help", "htb")) ''' if command == 'modules': return tc_plugins if command == 'help': p = tc_plugins.get(kind) if p is not None and hasattr(p, '__doc__'): return p.__doc__ else: return 'No help available' 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 commands = {'add': (RTM_NEWQDISC, flags_make), 'del': (RTM_DELQDISC, flags_make), 'remove': (RTM_DELQDISC, flags_make), 'delete': (RTM_DELQDISC, flags_make), 'add-class': (RTM_NEWTCLASS, flags_make), 'del-class': (RTM_DELTCLASS, flags_make), 'change-class': (RTM_NEWTCLASS, flags_change), 'replace-class': (RTM_NEWTCLASS, flags_replace), 'add-filter': (RTM_NEWTFILTER, flags_make), 'del-filter': (RTM_DELTFILTER, flags_make), 'change-filter': (RTM_NEWTFILTER, flags_change), 'replace-filter': (RTM_NEWTFILTER, flags_replace)} if isinstance(command, int): command = (command, flags_make) command, flags = commands.get(command, command) msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ('parent', 'target', 'default'): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg['index'] = index msg['handle'] = handle opts = kwarg.get('opts', None) ## # # if kind in tc_plugins: p = tc_plugins[kind] msg['parent'] = kwarg.pop('parent', getattr(p, 'parent', 0)) if hasattr(p, 'fix_msg'): p.fix_msg(msg, kwarg) if kwarg: if command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = p.get_class_parameters(kwarg) else: opts = p.get_parameters(kwarg) else: msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kind is not None: msg['attrs'] = [['TCA_KIND', kind]] if opts is not None: msg['attrs'].append(['TCA_OPTIONS', opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)
def tc(self, command, kind, index, handle=0, **kwarg): ''' "Swiss knife" for traffic control. With the method you can add, delete or modify qdiscs, classes and filters. * command -- add or delete qdisc, class, filter. * kind -- a string identifier -- "sfq", "htb", "u32" and so on. * handle -- integer or string Command can be one of ("add", "del", "add-class", "del-class", "add-filter", "del-filter") (see `commands` dict in the code). Handle notice: traditional iproute2 notation, like "1:0", actually represents two parts in one four-bytes integer:: 1:0 -> 0x10000 1:1 -> 0x10001 ff:0 -> 0xff0000 ffff:1 -> 0xffff0001 For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like 'ffff:0000'. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000. So, to set up sfq queue on interface 1, the function call will be like that:: ip = IPRoute() ip.tc("add", "sfq", 1) Instead of string commands ("add", "del"...), you can use also module constants, `RTM_NEWQDISC`, `RTM_DELQDISC` and so on:: ip = IPRoute() ip.tc(RTM_NEWQDISC, "sfq", 1) More complex example with htb qdisc, lets assume eth0 == 2:: # u32 --> +--> htb 1:10 --> sfq 10:0 # | | # | | # eth0 -- htb 1:0 -- htb 1:1 # | | # | | # u32 --> +--> htb 1:20 --> sfq 20:0 eth0 = 2 # add root queue 1:0 ip.tc("add", "htb", eth0, 0x10000, default=0x200000) # root class 1:1 ip.tc("add-class", "htb", eth0, 0x10001, parent=0x10000, rate="256kbit", burst=1024 * 6) # two branches: 1:10 and 1:20 ip.tc("add-class", "htb", eth0, 0x10010, parent=0x10001, rate="192kbit", burst=1024 * 6, prio=1) ip.tc("add-class", "htb", eht0, 0x10020, parent=0x10001, rate="128kbit", burst=1024 * 6, prio=2) # two leaves: 10:0 and 20:0 ip.tc("add", "sfq", eth0, 0x100000, parent=0x10010, perturb=10) ip.tc("add", "sfq", eth0, 0x200000, parent=0x10020, perturb=10) # two filters: one to load packets into 1:10 and the # second to 1:20 ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10010, keys=["0x0006/0x00ff+8", "0x0000/0xffc0+2"]) ip.tc("add-filter", "u32", eth0, parent=0x10000, prio=10, protocol=socket.AF_INET, target=0x10020, keys=["0x5/0xf+0", "0x10/0xff+33"]) ''' 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 commands = {'add': (RTM_NEWQDISC, flags_make), 'del': (RTM_DELQDISC, flags_make), 'remove': (RTM_DELQDISC, flags_make), 'delete': (RTM_DELQDISC, flags_make), 'add-class': (RTM_NEWTCLASS, flags_make), 'del-class': (RTM_DELTCLASS, flags_make), 'change-class': (RTM_NEWTCLASS, flags_change), 'replace-class': (RTM_NEWTCLASS, flags_replace), 'add-filter': (RTM_NEWTFILTER, flags_make), 'del-filter': (RTM_DELTFILTER, flags_make), 'change-class': (RTM_NEWTFILTER, flags_change), 'replace-filter': (RTM_NEWTFILTER, flags_replace)} if isinstance(command, int): command = (command, flags_make) command, flags = commands.get(command, command) msg = tcmsg() # transform handle, parent and target, if needed: handle = transform_handle(handle) for item in ('parent', 'target', 'default'): if item in kwarg and kwarg[item] is not None: kwarg[item] = transform_handle(kwarg[item]) msg['index'] = index msg['handle'] = handle opts = kwarg.get('opts', None) if kind == 'ingress': msg['parent'] = TC_H_INGRESS msg['handle'] = 0xffff0000 elif kind == 'tbf': msg['parent'] = TC_H_ROOT if kwarg: opts = get_tbf_parameters(kwarg) elif kind == 'htb': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: if command in (RTM_NEWQDISC, RTM_DELQDISC): opts = get_htb_parameters(kwarg) elif command in (RTM_NEWTCLASS, RTM_DELTCLASS): opts = get_htb_class_parameters(kwarg) elif kind == 'netem': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_netem_parameters(kwarg) elif kind == 'sfq': msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kwarg: opts = get_sfq_parameters(kwarg) elif kind == 'u32': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_u32_parameters(kwarg) elif kind == 'fw': msg['parent'] = kwarg.get('parent') msg['info'] = htons(kwarg.get('protocol', 0) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_fw_parameters(kwarg) elif kind == 'bpf': msg['parent'] = kwarg.get('parent', TC_H_ROOT) msg['info'] = htons(kwarg.get('protocol', ETH_P_ALL) & 0xffff) |\ ((kwarg.get('prio', 0) << 16) & 0xffff0000) if kwarg: opts = get_bpf_parameters(kwarg) else: msg['parent'] = kwarg.get('parent', TC_H_ROOT) if kind is not None: msg['attrs'] = [['TCA_KIND', kind]] if opts is not None: msg['attrs'].append(['TCA_OPTIONS', opts]) return self.nlm_request(msg, msg_type=command, msg_flags=flags)