summaryrefslogtreecommitdiff
path: root/python/netlink/route/tc.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/netlink/route/tc.py')
-rw-r--r--python/netlink/route/tc.py357
1 files changed, 357 insertions, 0 deletions
diff --git a/python/netlink/route/tc.py b/python/netlink/route/tc.py
new file mode 100644
index 0000000..ebe25e1
--- /dev/null
+++ b/python/netlink/route/tc.py
@@ -0,0 +1,357 @@
+
+
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+__all__ = [
+ 'TcCache',
+ 'Tc',
+ 'QdiscCache',
+ 'Qdisc']
+
+import socket
+import sys
+import netlink.core as netlink
+import netlink.capi as core_capi
+import netlink.route.capi as capi
+import netlink.util as util
+
+from netlink.route.link import Link
+
+TC_PACKETS = 0
+TC_BYTES = 1
+TC_RATE_BPS = 2
+TC_RATE_PPS = 3
+TC_QLEN = 4
+TC_BACKLOG = 5
+TC_DROPS = 6
+TC_REQUEUES = 7
+TC_OVERLIMITS = 9
+
+TC_H_ROOT = 0xFFFFFFFF
+TC_H_INGRESS = 0xFFFFFFF1
+
+class Handle(object):
+ def __init__(self, val=None):
+ if type(val) is str:
+ val = capi.tc_str2handle(val)
+ elif not val:
+ val = 0
+
+ self._val = int(val)
+
+ def __int__(self):
+ return self._val
+
+ def __str__(self):
+ return capi.rtnl_tc_handle2str(self._val, 64)[0]
+
+ def isroot(self):
+ return self._val == TC_H_ROOT or self._val == TC_H_INGRESS
+
+###########################################################################
+# TC Cache
+class TcCache(netlink.Cache):
+ """Cache of traffic control object"""
+
+ def __getitem__(self, key):
+ raise NotImplementedError()
+
+###########################################################################
+# Tc Object
+class Tc(netlink.Object):
+ def __cmp__(self, other):
+ return self.ifindex - other.ifindex
+
+ def isroot(self):
+ return self.parent.isroot()
+
+ #####################################################################
+ # ifindex
+ @property
+ def ifindex(self):
+ """interface index"""
+ return capi.rtnl_tc_get_ifindex(self._tc)
+
+ @ifindex.setter
+ def ifindex(self, value):
+ capi.rtnl_tc_set_ifindex(self._tc, int(value))
+
+ #####################################################################
+ # link
+ @property
+ def link(self):
+ link = capi.rtnl_tc_get_link(self._tc)
+ if not link:
+ return None
+ else:
+ return Link._from_capi(link)
+
+ @link.setter
+ def link(self, value):
+ capi.rtnl_tc_set_link(self._tc, value._link)
+
+ #####################################################################
+ # mtu
+ @property
+ def mtu(self):
+ return capi.rtnl_tc_get_mtu(self._tc)
+
+ @mtu.setter
+ def mtu(self, value):
+ capi.rtnl_tc_set_mtu(self._tc, int(value))
+
+ #####################################################################
+ # mpu
+ @property
+ def mpu(self):
+ return capi.rtnl_tc_get_mpu(self._tc)
+
+ @mpu.setter
+ def mpu(self, value):
+ capi.rtnl_tc_set_mpu(self._tc, int(value))
+
+ #####################################################################
+ # overhead
+ @property
+ def overhead(self):
+ return capi.rtnl_tc_get_overhead(self._tc)
+
+ @overhead.setter
+ def overhead(self, value):
+ capi.rtnl_tc_set_overhead(self._tc, int(value))
+
+ #####################################################################
+ # linktype
+ @property
+ def linktype(self):
+ return capi.rtnl_tc_get_linktype(self._tc)
+
+ @linktype.setter
+ def linktype(self, value):
+ capi.rtnl_tc_set_linktype(self._tc, int(value))
+
+ #####################################################################
+ # handle
+ @property
+ def handle(self):
+ return Handle(capi.rtnl_tc_get_handle(self._tc))
+
+ @handle.setter
+ def handle(self, value):
+ capi.rtnl_tc_set_handle(self._tc, int(value))
+
+ #####################################################################
+ # parent
+ @property
+ def parent(self):
+ return Handle(capi.rtnl_tc_get_parent(self._tc))
+
+ @parent.setter
+ def parent(self, value):
+ capi.rtnl_tc_set_parent(self._tc, int(value))
+
+ #####################################################################
+ # kind
+ @property
+ def kind(self):
+ return capi.rtnl_tc_get_kind(self._tc)
+
+ @kind.setter
+ def kind(self, value):
+ capi.rtnl_tc_set_kind(self._tc, value)
+
+ def get_stat(self, id):
+ return capi.rtnl_tc_get_stat(self._tc, id)
+
+class TcTree(object):
+ def __init__(self, link, sock):
+ self._qdisc_cache = QdiscCache().refill(sock)
+
+ def __getitem__(self, key):
+ pass
+# if type(key) is int:
+# link = capi.rtnl_link_get(self._this, key)
+# elif type(key) is str:
+# link = capi.rtnl_link_get_by_name(self._this, key)
+#
+# if qdisc is None:
+# raise KeyError()
+# else:
+# return Qdisc._from_capi(capi.qdisc2obj(qdisc))
+
+
+
+
+###########################################################################
+# Link Cache
+class QdiscCache(netlink.Cache):
+ """Cache of qdiscs"""
+
+ def __init__(self, cache=None):
+ if not cache:
+ cache = self._alloc_cache_name("route/qdisc")
+
+ self._c_cache = cache
+
+# def __getitem__(self, key):
+# if type(key) is int:
+# link = capi.rtnl_link_get(self._this, key)
+# elif type(key) is str:
+# link = capi.rtnl_link_get_by_name(self._this, key)
+#
+# if qdisc is None:
+# raise KeyError()
+# else:
+# return Qdisc._from_capi(capi.qdisc2obj(qdisc))
+
+ def _new_object(self, obj):
+ return Qdisc(obj)
+
+ def _new_cache(self, cache):
+ return QdiscCache(cache=cache)
+
+###########################################################################
+# Qdisc Object
+class Qdisc(Tc):
+ """Network link"""
+
+ def __init__(self, obj=None):
+ self._name = "qdisc"
+ self._abbr = "qdisc"
+
+ if not obj:
+ self._qdisc = capi.rtnl_qdisc_alloc()
+ else:
+ self._qdisc = capi.obj2qdisc(obj)
+
+ self._obj = capi.qdisc2obj(self._qdisc)
+ self._orig = capi.obj2qdisc(core_capi.nl_object_clone(self._obj))
+
+ Tc.__init__(self)
+
+ netlink.attr('qdisc.handle', fmt=util.handle)
+ netlink.attr('qdisc.parent', fmt=util.handle)
+ netlink.attr('qdisc.kind', fmt=util.bold)
+
+ def __cmp__(self, other):
+ return self.handle - other.handle
+
+ def _new_instance(self, obj):
+ if not obj: raise ValueError()
+ return Qdisc(obj)
+
+# #####################################################################
+# # add()
+# def add(self, socket, flags=None):
+# if not flags:
+# flags = netlink.NLM_F_CREATE
+#
+# ret = capi.rtnl_link_add(socket._sock, self._link, flags)
+# if ret < 0:
+# raise netlink.KernelError(ret)
+#
+# #####################################################################
+# # change()
+# def change(self, socket, flags=0):
+# """Commit changes made to the link object"""
+# if not self._orig:
+# raise NetlinkError("Original link not available")
+# ret = capi.rtnl_link_change(socket._sock, self._orig, self._link, flags)
+# if ret < 0:
+# raise netlink.KernelError(ret)
+#
+# #####################################################################
+# # delete()
+# def delete(self, socket):
+# """Attempt to delete this link in the kernel"""
+# ret = capi.rtnl_link_delete(socket._sock, self._link)
+# if ret < 0:
+# raise netlink.KernelError(ret)
+
+ @property
+ def _dev(self):
+ buf = util.kw('dev') + ' '
+
+ if self.link:
+ return buf + util.string(self.link.name)
+ else:
+ return buf + util.num(self.ifindex)
+
+ @property
+ def _parent(self):
+ return util.kw('parent') + ' ' + str(self.parent)
+
+ ###################################################################
+ #
+ # format(details=False, stats=False)
+ #
+ def format(self, details=False, stats=False):
+ """Return qdisc as formatted text"""
+ fmt = util.BriefFormatter(self)
+
+ buf = fmt.format('qdisc {kind} {handle} {_dev} {_parent}')
+
+ if details:
+ fmt = util.DetailFormatter(self)
+ buf += fmt.format('\n'\
+ '\t{mtu} {mpu} {overhead}\n')
+
+# if stats:
+# l = [['Packets', RX_PACKETS, TX_PACKETS],
+# ['Bytes', RX_BYTES, TX_BYTES],
+# ['Errors', RX_ERRORS, TX_ERRORS],
+# ['Dropped', RX_DROPPED, TX_DROPPED],
+# ['Compressed', RX_COMPRESSED, TX_COMPRESSED],
+# ['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
+# ['Length Errors', RX_LEN_ERR, None],
+# ['Over Errors', RX_OVER_ERR, None],
+# ['CRC Errors', RX_CRC_ERR, None],
+# ['Frame Errors', RX_FRAME_ERR, None],
+# ['Missed Errors', RX_MISSED_ERR, None],
+# ['Abort Errors', None, TX_ABORT_ERR],
+# ['Carrier Errors', None, TX_CARRIER_ERR],
+# ['Heartbeat Errors', None, TX_HBEAT_ERR],
+# ['Window Errors', None, TX_WIN_ERR],
+# ['Collisions', None, COLLISIONS],
+# ['Multicast', None, MULTICAST],
+# ['', None, None],
+# ['Ipv6:', None, None],
+# ['Packets', IP6_INPKTS, IP6_OUTPKTS],
+# ['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
+# ['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
+# ['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
+# ['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
+# ['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
+# ['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
+# ['Delivers', IP6_INDELIVERS, None],
+# ['Forwarded', None, IP6_OUTFORWDATAGRAMS],
+# ['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
+# ['Header Errors', IP6_INHDRERRORS, None],
+# ['Too Big Errors', IP6_INTOOBIGERRORS, None],
+# ['Address Errors', IP6_INADDRERRORS, None],
+# ['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
+# ['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
+# ['Reasm Timeouts', IP6_REASMTIMEOUT, None],
+# ['Reasm Requests', IP6_REASMREQDS, None],
+# ['Reasm Failures', IP6_REASMFAILS, None],
+# ['Reasm OK', IP6_REASMOKS, None],
+# ['Frag Created', None, IP6_FRAGCREATES],
+# ['Frag Failures', None, IP6_FRAGFAILS],
+# ['Frag OK', None, IP6_FRAGOKS],
+# ['', None, None],
+# ['ICMPv6:', None, None],
+# ['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
+# ['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
+#
+# buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
+# 15 * ' ', util.title('TX'))
+#
+# for row in l:
+# row[0] = util.kw(row[0])
+# row[1] = self.get_stat(row[1]) if row[1] else ''
+# row[2] = self.get_stat(row[2]) if row[2] else ''
+# buf += '\t{0:27} {1:>16} {2:>16}\n'.format(*row)
+
+ return buf