summaryrefslogtreecommitdiff
path: root/python/netlink/route
diff options
context:
space:
mode:
Diffstat (limited to 'python/netlink/route')
-rw-r--r--python/netlink/route/__init__.py0
-rw-r--r--python/netlink/route/address.py398
-rw-r--r--python/netlink/route/capi.i338
-rw-r--r--python/netlink/route/link.py596
-rw-r--r--python/netlink/route/links/__init__.py0
-rw-r--r--python/netlink/route/links/dummy.py21
-rw-r--r--python/netlink/route/links/inet.py153
-rw-r--r--python/netlink/route/links/vlan.py62
-rw-r--r--python/netlink/route/qdisc.py185
-rw-r--r--python/netlink/route/tc.py357
10 files changed, 2110 insertions, 0 deletions
diff --git a/python/netlink/route/__init__.py b/python/netlink/route/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/netlink/route/__init__.py
diff --git a/python/netlink/route/address.py b/python/netlink/route/address.py
new file mode 100644
index 0000000..c0ce54f
--- /dev/null
+++ b/python/netlink/route/address.py
@@ -0,0 +1,398 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Module providing access to network addresses
+"""
+
+__version__ = "1.0"
+__all__ = [
+ 'AddressCache',
+ 'Address']
+
+import datetime
+import netlink.core as netlink
+import netlink.capi as core_capi
+import netlink.route.capi as capi
+import netlink.route.link as Link
+import netlink.util as util
+
+###########################################################################
+# Address Cache
+class AddressCache(netlink.Cache):
+ """Cache containing network addresses"""
+
+ def __init__(self, cache=None):
+ if not cache:
+ cache = self._alloc_cache_name("route/addr")
+
+ self._protocol = netlink.NETLINK_ROUTE
+ self._c_cache = cache
+
+ def __getitem__(self, key):
+ # Using ifindex=0 here implies that the local address itself
+ # is unique, otherwise the first occurence is returned.
+ return self.lookup(0, key)
+
+ def lookup(self, ifindex, local):
+ if type(local) is str:
+ local = netlink.AbstractAddress(local)
+
+ addr = capi.rtnl_addr_get(self._c_cache, ifindex,
+ local._nl_addr)
+ if addr is None:
+ raise KeyError()
+
+ return Address._from_capi(addr)
+
+ def _new_object(self, obj):
+ return Address(obj)
+
+ def _new_cache(self, cache):
+ return AddressCache(cache=cache)
+
+###########################################################################
+# Address Object
+class Address(netlink.Object):
+ """Network address"""
+
+ def __init__(self, obj=None):
+ netlink.Object.__init__(self, "route/addr", "address", obj)
+ self._rtnl_addr = self._obj2type(self._nl_object)
+
+ @classmethod
+ def _from_capi(cls, obj):
+ return cls(capi.addr2obj(obj))
+
+ def _obj2type(self, obj):
+ return capi.obj2addr(obj)
+
+ def __cmp__(self, other):
+ # sort by:
+ # 1. network link
+ # 2. address family
+ # 3. local address (including prefixlen)
+ diff = self.ifindex - other.ifindex
+
+ if diff == 0:
+ diff = self.family - other.family
+ if diff == 0:
+ diff = capi.nl_addr_cmp(self.local, other.local)
+
+ return diff
+
+ def _new_instance(self, obj):
+ return Address(obj)
+
+ #####################################################################
+ # ifindex
+ @netlink.nlattr('address.ifindex', type=int, immutable=True,
+ fmt=util.num)
+ @property
+ def ifindex(self):
+ """interface index"""
+ return capi.rtnl_addr_get_ifindex(self._rtnl_addr)
+
+ @ifindex.setter
+ def ifindex(self, value):
+ link = Link.resolve(value)
+ if not link:
+ raise ValueError()
+
+ self.link = link
+
+ #####################################################################
+ # link
+ @netlink.nlattr('address.link', type=str, fmt=util.string)
+ @property
+ def link(self):
+ link = capi.rtnl_addr_get_link(self._rtnl_addr)
+ if not link:
+ return None
+
+ return Link.Link.from_capi(link)
+
+ @link.setter
+ def link(self, value):
+ if type(value) is str:
+ try:
+ value = Link.resolve(value)
+ except KeyError:
+ raise ValueError()
+
+ capi.rtnl_addr_set_link(self._rtnl_addr, value._rtnl_link)
+
+ # ifindex is immutable but we assume that if _orig does not
+ # have an ifindex specified, it was meant to be given here
+ if capi.rtnl_addr_get_ifindex(self._orig) == 0:
+ capi.rtnl_addr_set_ifindex(self._orig, value.ifindex)
+
+ #####################################################################
+ # label
+ @netlink.nlattr('address.label', type=str, fmt=util.string)
+ @property
+ def label(self):
+ """address label"""
+ return capi.rtnl_addr_get_label(self._rtnl_addr)
+
+ @label.setter
+ def label(self, value):
+ capi.rtnl_addr_set_label(self._rtnl_addr, value)
+
+ #####################################################################
+ # flags
+ @netlink.nlattr('address.flags', type=str, fmt=util.string)
+ @property
+ def flags(self):
+ """Flags"""
+ flags = capi.rtnl_addr_get_flags(self._rtnl_addr)
+ return capi.rtnl_addr_flags2str(flags, 256)[0].split(',')
+
+ def _set_flag(self, flag):
+ if flag[0] == '-':
+ i = capi.rtnl_addr_str2flags(flag[1:])
+ capi.rtnl_addr_unset_flags(self._rtnl_addr, i)
+ else:
+ i = capi.rtnl_addr_str2flags(flag[1:])
+ capi.rtnl_addr_set_flags(self._rtnl_addr, i)
+
+ @flags.setter
+ def flags(self, value):
+ if type(value) is list:
+ for flag in value:
+ self._set_flag(flag)
+ else:
+ self._set_flag(value)
+
+ #####################################################################
+ # family
+ @netlink.nlattr('address.family', type=int, immutable=True,
+ fmt=util.num)
+ @property
+ def family(self):
+ """Address family"""
+ fam = capi.rtnl_addr_get_family(self._rtnl_addr)
+ return netlink.AddressFamily(fam)
+
+ @family.setter
+ def family(self, value):
+ if not isinstance(value, AddressFamily):
+ value = AddressFamily(value)
+
+ capi.rtnl_addr_set_family(self._rtnl_addr, int(value))
+
+ #####################################################################
+ # scope
+ @netlink.nlattr('address.scope', type=int, fmt=util.num)
+ @property
+ def scope(self):
+ """Address scope"""
+ scope = capi.rtnl_addr_get_scope(self._rtnl_addr)
+ return capi.rtnl_scope2str(scope, 32)[0]
+
+ @scope.setter
+ def scope(self, value):
+ if type(value) is str:
+ value = capi.rtnl_str2scope(value)
+ capi.rtnl_addr_set_scope(self._rtnl_addr, value)
+
+ #####################################################################
+ # local address
+ @netlink.nlattr('address.local', type=str, immutable=True,
+ fmt=util.addr)
+ @property
+ def local(self):
+ """Local address"""
+ a = capi.rtnl_addr_get_local(self._rtnl_addr)
+ return netlink.AbstractAddress(a)
+
+ @local.setter
+ def local(self, value):
+ a = netlink.AbstractAddress(value)
+ capi.rtnl_addr_set_local(self._rtnl_addr, a._nl_addr)
+
+ # local is immutable but we assume that if _orig does not
+ # have a local address specified, it was meant to be given here
+ if capi.rtnl_addr_get_local(self._orig) is None:
+ capi.rtnl_addr_set_local(self._orig, a._nl_addr)
+
+ #####################################################################
+ # Peer address
+ @netlink.nlattr('address.peer', type=str, fmt=util.addr)
+ @property
+ def peer(self):
+ """Peer address"""
+ a = capi.rtnl_addr_get_peer(self._rtnl_addr)
+ return netlink.AbstractAddress(a)
+
+ @peer.setter
+ def peer(self, value):
+ a = netlink.AbstractAddress(value)
+ capi.rtnl_addr_set_peer(self._rtnl_addr, a._nl_addr)
+
+ #####################################################################
+ # Broadcast address
+ @netlink.nlattr('address.broadcast', type=str, fmt=util.addr)
+ @property
+ def broadcast(self):
+ """Broadcast address"""
+ a = capi.rtnl_addr_get_broadcast(self._rtnl_addr)
+ return netlink.AbstractAddress(a)
+
+ @broadcast.setter
+ def broadcast(self, value):
+ a = netlink.AbstractAddress(value)
+ capi.rtnl_addr_set_broadcast(self._rtnl_addr, a._nl_addr)
+
+ #####################################################################
+ # Multicast address
+ @netlink.nlattr('address.multicast', type=str, fmt=util.addr)
+ @property
+ def multicast(self):
+ """multicast address"""
+ a = capi.rtnl_addr_get_multicast(self._rtnl_addr)
+ return netlink.AbstractAddress(a)
+
+ @multicast.setter
+ def multicast(self, value):
+ try:
+ a = netlink.AbstractAddress(value)
+ except ValueError as err:
+ raise AttributeError('multicast', err)
+
+ capi.rtnl_addr_set_multicast(self._rtnl_addr, a._nl_addr)
+
+ #####################################################################
+ # Anycast address
+ @netlink.nlattr('address.anycast', type=str, fmt=util.addr)
+ @property
+ def anycast(self):
+ """anycast address"""
+ a = capi.rtnl_addr_get_anycast(self._rtnl_addr)
+ return netlink.AbstractAddress(a)
+
+ @anycast.setter
+ def anycast(self, value):
+ a = netlink.AbstractAddress(value)
+ capi.rtnl_addr_set_anycast(self._rtnl_addr, a._nl_addr)
+
+ #####################################################################
+ # Valid lifetime
+ @netlink.nlattr('address.valid_lifetime', type=int, immutable=True,
+ fmt=util.num)
+ @property
+ def valid_lifetime(self):
+ """Valid lifetime"""
+ msecs = capi.rtnl_addr_get_valid_lifetime(self._rtnl_addr)
+ if msecs == 0xFFFFFFFF:
+ return None
+ else:
+ return datetime.timedelta(seconds=msecs)
+
+ @valid_lifetime.setter
+ def valid_lifetime(self, value):
+ capi.rtnl_addr_set_valid_lifetime(self._rtnl_addr, int(value))
+
+ #####################################################################
+ # Preferred lifetime
+ @netlink.nlattr('address.preferred_lifetime', type=int,
+ immutable=True, fmt=util.num)
+ @property
+ def preferred_lifetime(self):
+ """Preferred lifetime"""
+ msecs = capi.rtnl_addr_get_preferred_lifetime(self._rtnl_addr)
+ if msecs == 0xFFFFFFFF:
+ return None
+ else:
+ return datetime.timedelta(seconds=msecs)
+
+ @preferred_lifetime.setter
+ def preferred_lifetime(self, value):
+ capi.rtnl_addr_set_preferred_lifetime(self._rtnl_addr, int(value))
+
+ #####################################################################
+ # Creation Time
+ @netlink.nlattr('address.create_time', type=int, immutable=True,
+ fmt=util.num)
+ @property
+ def create_time(self):
+ """Creation time"""
+ hsec = capi.rtnl_addr_get_create_time(self._rtnl_addr)
+ return datetime.timedelta(milliseconds=10*hsec)
+
+ #####################################################################
+ # Last Update
+ @netlink.nlattr('address.last_update', type=int, immutable=True,
+ fmt=util.num)
+ @property
+ def last_update(self):
+ """Last update"""
+ hsec = capi.rtnl_addr_get_last_update_time(self._rtnl_addr)
+ return datetime.timedelta(milliseconds=10*hsec)
+
+ #####################################################################
+ # add()
+ def add(self, socket=None, flags=None):
+ if not socket:
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+ if not flags:
+ flags = netlink.NLM_F_CREATE
+
+ ret = capi.rtnl_addr_add(socket._sock, self._rtnl_addr, flags)
+ if ret < 0:
+ raise netlink.KernelError(ret)
+
+ #####################################################################
+ # delete()
+ def delete(self, socket):
+ """Attempt to delete this link in the kernel"""
+ ret = capi.rtnl_addr_delete(socket._sock, self._addr)
+ if ret < 0:
+ raise netlink.KernelError(ret)
+
+ ###################################################################
+ # private properties
+ #
+ # Used for formatting output. USE AT OWN RISK
+ @property
+ def _flags(self):
+ return ','.join(self.flags)
+
+ ###################################################################
+ #
+ # format(details=False, stats=False)
+ #
+ def format(self, details=False, stats=False, nodev=False, indent=''):
+ """Return address as formatted text"""
+ fmt = util.MyFormatter(self, indent)
+
+ buf = fmt.format('{a|local!b}')
+
+ if not nodev:
+ buf += fmt.format(' {a|ifindex}')
+
+ buf += fmt.format(' {a|scope}')
+
+ if self.label:
+ buf += fmt.format(' "{a|label}"')
+
+ buf += fmt.format(' <{a|_flags}>')
+
+ if details:
+ buf += fmt.nl('\t{t|broadcast} {t|multicast}') \
+ + fmt.nl('\t{t|peer} {t|anycast}')
+
+ if self.valid_lifetime:
+ buf += fmt.nl('\t{s|valid-lifetime!k} '\
+ '{a|valid_lifetime}')
+
+ if self.preferred_lifetime:
+ buf += fmt.nl('\t{s|preferred-lifetime!k} '\
+ '{a|preferred_lifetime}')
+
+ if stats and (self.create_time or self.last_update):
+ buf += self.nl('\t{s|created!k} {a|create_time}'\
+ ' {s|last-updated!k} {a|last_update}')
+
+ return buf
diff --git a/python/netlink/route/capi.i b/python/netlink/route/capi.i
new file mode 100644
index 0000000..abe3cc9
--- /dev/null
+++ b/python/netlink/route/capi.i
@@ -0,0 +1,338 @@
+%module capi
+%{
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+#include <netlink/route/link/inet.h>
+
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+
+#include <netlink/route/addr.h>
+%}
+
+%include <stdint.i>
+%include <cstring.i>
+
+%inline %{
+ struct nl_object *link2obj(struct rtnl_link *link)
+ {
+ return OBJ_CAST(link);
+ }
+
+ struct rtnl_link *obj2link(struct nl_object *obj)
+ {
+ return (struct rtnl_link *) obj;
+ }
+
+ struct rtnl_link *get_from_kernel(struct nl_sock *sk, int ifindex, const char *name)
+ {
+ struct rtnl_link *link;
+ if (rtnl_link_get_kernel(sk, ifindex, name, &link) < 0)
+ return NULL;
+ return link;
+ }
+
+ uint32_t inet_get_conf(struct rtnl_link *link, const unsigned int id)
+ {
+ uint32_t result;
+
+ if (rtnl_link_inet_get_conf(link, id, &result) < 0)
+ return 0;
+
+ return result;
+ }
+%};
+
+extern struct nl_object *link2obj(struct rtnl_link *);
+extern struct rtnl_link *obj2link(struct nl_object *);
+
+/* <netlink/route/rtnl.h> */
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char * rtnl_scope2str(int, char *buf, size_t len);
+extern int rtnl_str2scope(const char *);
+
+/* <netlink/route/link.h> */
+
+extern struct rtnl_link *rtnl_link_alloc(void);
+
+extern struct rtnl_link *rtnl_link_get(struct nl_cache *, int);
+extern struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *, const char *);
+
+extern int rtnl_link_build_add_request(struct rtnl_link *, int, struct nl_msg **);
+extern int rtnl_link_add(struct nl_sock *, struct rtnl_link *, int);
+extern int rtnl_link_build_change_request(struct rtnl_link *, struct rtnl_link *, int, struct nl_msg **);
+extern int rtnl_link_change(struct nl_sock *, struct rtnl_link *, struct rtnl_link *, int);
+
+extern int rtnl_link_build_delete_request(const struct rtnl_link *, struct nl_msg **);
+extern int rtnl_link_delete(struct nl_sock *, const struct rtnl_link *);
+extern int rtnl_link_build_get_request(int, const char *, struct nl_msg **);
+
+extern char *rtnl_link_stat2str(int, char *, size_t);
+extern int rtnl_link_str2stat(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_flags2str(int, char *buf, size_t len);
+extern int rtnl_link_str2flags(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_operstate2str(uint8_t, char *buf, size_t len);
+extern int rtnl_link_str2operstate(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_mode2str(uint8_t, char *buf, size_t len);
+extern int rtnl_link_str2mode(const char *);
+
+extern void rtnl_link_set_qdisc(struct rtnl_link *, const char *);
+extern char *rtnl_link_get_qdisc(struct rtnl_link *);
+
+extern void rtnl_link_set_name(struct rtnl_link *, const char *);
+extern char *rtnl_link_get_name(struct rtnl_link *);
+
+extern void rtnl_link_set_flags(struct rtnl_link *, unsigned int);
+extern void rtnl_link_unset_flags(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_flags(struct rtnl_link *);
+
+extern void rtnl_link_set_mtu(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_mtu(struct rtnl_link *);
+
+extern void rtnl_link_set_txqlen(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_txqlen(struct rtnl_link *);
+
+extern void rtnl_link_set_weight(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_weight(struct rtnl_link *);
+
+extern void rtnl_link_set_ifindex(struct rtnl_link *, int);
+extern int rtnl_link_get_ifindex(struct rtnl_link *);
+
+extern void rtnl_link_set_family(struct rtnl_link *, int);
+extern int rtnl_link_get_family(struct rtnl_link *);
+
+extern void rtnl_link_set_arptype(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_arptype(struct rtnl_link *);
+
+extern void rtnl_link_set_addr(struct rtnl_link *, struct nl_addr *);
+extern struct nl_addr *rtnl_link_get_addr(struct rtnl_link *);
+
+extern void rtnl_link_set_broadcast(struct rtnl_link *, struct nl_addr *);
+extern struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *);
+
+extern void rtnl_link_set_link(struct rtnl_link *, int);
+extern int rtnl_link_get_link(struct rtnl_link *);
+
+extern void rtnl_link_set_master(struct rtnl_link *, int);
+extern int rtnl_link_get_master(struct rtnl_link *);
+
+extern void rtnl_link_set_operstate(struct rtnl_link *, uint8_t);
+extern uint8_t rtnl_link_get_operstate(struct rtnl_link *);
+
+extern void rtnl_link_set_linkmode(struct rtnl_link *, uint8_t);
+extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *);
+
+extern const char *rtnl_link_get_ifalias(struct rtnl_link *);
+extern void rtnl_link_set_ifalias(struct rtnl_link *, const char *);
+
+extern int rtnl_link_get_num_vf(struct rtnl_link *, uint32_t *);
+
+extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int);
+extern int rtnl_link_set_stat(struct rtnl_link *, const unsigned int, const uint64_t);
+
+extern int rtnl_link_set_info_type(struct rtnl_link *, const char *);
+extern char *rtnl_link_get_info_type(struct rtnl_link *);
+
+/* <netlink/route/link/vlan.h> */
+
+struct vlan_map
+{
+ uint32_t vm_from;
+ uint32_t vm_to;
+};
+
+#define VLAN_PRIO_MAX 7
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_vlan_flags2str(int, char *buf, size_t len);
+extern int rtnl_link_vlan_str2flags(const char *);
+
+extern int rtnl_link_vlan_set_id(struct rtnl_link *, int);
+extern int rtnl_link_vlan_get_id(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_flags(struct rtnl_link *, unsigned int);
+extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, int, uint32_t);
+extern uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, uint32_t, int);
+extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, int *);
+
+/* <netlink/route/link/inet.h> */
+%cstring_output_maxsize(char *buf, size_t len)
+extern const char *rtnl_link_inet_devconf2str(int, char *buf, size_t len);
+extern unsigned int rtnl_link_inet_str2devconf(const char *);
+
+extern int rtnl_link_inet_set_conf(struct rtnl_link *, const unsigned int, uint32_t);
+
+/* <netlink/route/tc.h> */
+
+%inline %{
+ uint32_t tc_str2handle(const char *name)
+ {
+ uint32_t result;
+
+ if (rtnl_tc_str2handle(name, &result) < 0)
+ return 0;
+
+ return result;
+ }
+%};
+
+extern void rtnl_tc_set_ifindex(struct rtnl_tc *, int);
+extern int rtnl_tc_get_ifindex(struct rtnl_tc *);
+extern void rtnl_tc_set_link(struct rtnl_tc *, struct rtnl_link *);
+extern struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *);
+extern void rtnl_tc_set_mtu(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_mtu(struct rtnl_tc *);
+extern void rtnl_tc_set_mpu(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_mpu(struct rtnl_tc *);
+extern void rtnl_tc_set_overhead(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_overhead(struct rtnl_tc *);
+extern void rtnl_tc_set_linktype(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_linktype(struct rtnl_tc *);
+extern void rtnl_tc_set_handle(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_handle(struct rtnl_tc *);
+extern void rtnl_tc_set_parent(struct rtnl_tc *, uint32_t);
+extern uint32_t rtnl_tc_get_parent(struct rtnl_tc *);
+extern int rtnl_tc_set_kind(struct rtnl_tc *, const char *);
+extern char * rtnl_tc_get_kind(struct rtnl_tc *);
+extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat);
+
+extern int rtnl_tc_calc_txtime(int, int);
+extern int rtnl_tc_calc_bufsize(int, int);
+extern int rtnl_tc_calc_cell_log(int);
+
+extern int rtnl_tc_read_classid_file(void);
+%cstring_output_maxsize(char *buf, size_t len)
+extern char * rtnl_tc_handle2str(uint32_t, char *buf, size_t len);
+extern int rtnl_classid_generate(const char *, uint32_t *, uint32_t);
+
+/* <netlink/route/qdisc.h> */
+
+%inline %{
+ struct nl_object *qdisc2obj(struct rtnl_qdisc *qdisc)
+ {
+ return OBJ_CAST(qdisc);
+ }
+
+ struct rtnl_qdisc *obj2qdisc(struct nl_object *obj)
+ {
+ return (struct rtnl_qdisc *) obj;
+ }
+
+ struct rtnl_tc *obj2tc(struct nl_object *obj)
+ {
+ return TC_CAST(obj);
+ }
+%};
+extern struct rtnl_qdisc *
+ rtnl_qdisc_alloc(void);
+
+extern struct rtnl_qdisc *
+ rtnl_qdisc_get(struct nl_cache *, int, uint32_t);
+
+extern struct rtnl_qdisc *
+ rtnl_qdisc_get_by_parent(struct nl_cache *, int, uint32_t);
+
+extern int rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int,
+ struct nl_msg **);
+extern int rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int);
+
+extern int rtnl_qdisc_build_update_request(struct rtnl_qdisc *,
+ struct rtnl_qdisc *,
+ int, struct nl_msg **);
+
+extern int rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *,
+ struct rtnl_qdisc *, int);
+
+extern int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *,
+ struct nl_msg **);
+extern int rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *);
+
+/* <netlink/route/addr.h> */
+
+%inline %{
+ struct nl_object *addr2obj(struct rtnl_addr *addr)
+ {
+ return OBJ_CAST(addr);
+ }
+
+ struct rtnl_addr *obj2addr(struct nl_object *obj)
+ {
+ return (struct rtnl_addr *) obj;
+ }
+%};
+
+extern struct rtnl_addr *rtnl_addr_alloc(void);
+
+extern struct rtnl_addr *
+ rtnl_addr_get(struct nl_cache *, int, struct nl_addr *);
+
+extern int rtnl_addr_build_add_request(struct rtnl_addr *, int,
+ struct nl_msg **);
+extern int rtnl_addr_add(struct nl_sock *, struct rtnl_addr *, int);
+
+extern int rtnl_addr_build_delete_request(struct rtnl_addr *, int,
+ struct nl_msg **);
+extern int rtnl_addr_delete(struct nl_sock *,
+ struct rtnl_addr *, int);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char * rtnl_addr_flags2str(int, char *buf, size_t len);
+extern int rtnl_addr_str2flags(const char *);
+
+extern int rtnl_addr_set_label(struct rtnl_addr *, const char *);
+extern char * rtnl_addr_get_label(struct rtnl_addr *);
+
+extern void rtnl_addr_set_ifindex(struct rtnl_addr *, int);
+extern int rtnl_addr_get_ifindex(struct rtnl_addr *);
+
+extern void rtnl_addr_set_link(struct rtnl_addr *, struct rtnl_link *);
+extern struct rtnl_link *
+ rtnl_addr_get_link(struct rtnl_addr *);
+extern void rtnl_addr_set_family(struct rtnl_addr *, int);
+extern int rtnl_addr_get_family(struct rtnl_addr *);
+
+extern void rtnl_addr_set_prefixlen(struct rtnl_addr *, int);
+extern int rtnl_addr_get_prefixlen(struct rtnl_addr *);
+
+extern void rtnl_addr_set_scope(struct rtnl_addr *, int);
+extern int rtnl_addr_get_scope(struct rtnl_addr *);
+
+extern void rtnl_addr_set_flags(struct rtnl_addr *, unsigned int);
+extern void rtnl_addr_unset_flags(struct rtnl_addr *, unsigned int);
+extern unsigned int rtnl_addr_get_flags(struct rtnl_addr *);
+
+extern int rtnl_addr_set_local(struct rtnl_addr *,
+ struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *);
+
+extern int rtnl_addr_set_peer(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *);
+
+extern int rtnl_addr_set_broadcast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *);
+
+extern int rtnl_addr_set_multicast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *);
+
+extern int rtnl_addr_set_anycast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *);
+
+extern uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *);
+extern void rtnl_addr_set_valid_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *);
+extern void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_create_time(struct rtnl_addr *);
+extern uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *);
diff --git a/python/netlink/route/link.py b/python/netlink/route/link.py
new file mode 100644
index 0000000..b8e19fa
--- /dev/null
+++ b/python/netlink/route/link.py
@@ -0,0 +1,596 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Module providing access to network links
+
+This module provides an interface to view configured network links,
+modify them and to add and delete virtual network links.
+
+The following is a basic example:
+ import netlink.core as netlink
+ import netlink.route.link as link
+
+ sock = netlink.Socket()
+ sock.connect(netlink.NETLINK_ROUTE)
+
+ cache = link.LinkCache() # create new empty link cache
+ cache.refill(sock) # fill cache with all configured links
+ eth0 = cache['eth0'] # lookup link "eth0"
+ print eth0 # print basic configuration
+
+The module contains the following public classes:
+
+ - Link -- Represents a network link. Instances can be created directly
+ via the constructor (empty link objects) or via the refill()
+ method of a LinkCache.
+ - LinkCache -- Derived from netlink.Cache, holds any number of
+ network links (Link instances). Main purpose is to keep
+ a local list of all network links configured in the
+ kernel.
+
+The following public functions exist:
+ - get_from_kernel(socket, name)
+
+"""
+
+__version__ = "0.1"
+__all__ = [
+ 'LinkCache',
+ 'Link',
+ 'get_from_kernel']
+
+import socket
+import sys
+import netlink.core as netlink
+import netlink.capi as core_capi
+import netlink.route.capi as capi
+import netlink.route.links.inet as inet
+import netlink.util as util
+
+###########################################################################
+# Link statistics definitions
+RX_PACKETS = 0
+TX_PACKETS = 1
+RX_BYTES = 2
+TX_BYTES = 3
+RX_ERRORS = 4
+TX_ERRORS = 5
+RX_DROPPED = 6
+TX_DROPPED = 7
+RX_COMPRESSED = 8
+TX_COMPRESSED = 9
+RX_FIFO_ERR = 10
+TX_FIFO_ERR = 11
+RX_LEN_ERR = 12
+RX_OVER_ERR = 13
+RX_CRC_ERR = 14
+RX_FRAME_ERR = 15
+RX_MISSED_ERR = 16
+TX_ABORT_ERR = 17
+TX_CARRIER_ERR = 18
+TX_HBEAT_ERR = 19
+TX_WIN_ERR = 20
+COLLISIONS = 21
+MULTICAST = 22
+IP6_INPKTS = 23
+IP6_INHDRERRORS = 24
+IP6_INTOOBIGERRORS = 25
+IP6_INNOROUTES = 26
+IP6_INADDRERRORS = 27
+IP6_INUNKNOWNPROTOS = 28
+IP6_INTRUNCATEDPKTS = 29
+IP6_INDISCARDS = 30
+IP6_INDELIVERS = 31
+IP6_OUTFORWDATAGRAMS = 32
+IP6_OUTPKTS = 33
+IP6_OUTDISCARDS = 34
+IP6_OUTNOROUTES = 35
+IP6_REASMTIMEOUT = 36
+IP6_REASMREQDS = 37
+IP6_REASMOKS = 38
+IP6_REASMFAILS = 39
+IP6_FRAGOKS = 40
+IP6_FRAGFAILS = 41
+IP6_FRAGCREATES = 42
+IP6_INMCASTPKTS = 43
+IP6_OUTMCASTPKTS = 44
+IP6_INBCASTPKTS = 45
+IP6_OUTBCASTPKTS = 46
+IP6_INOCTETS = 47
+IP6_OUTOCTETS = 48
+IP6_INMCASTOCTETS = 49
+IP6_OUTMCASTOCTETS = 50
+IP6_INBCASTOCTETS = 51
+IP6_OUTBCASTOCTETS = 52
+ICMP6_INMSGS = 53
+ICMP6_INERRORS = 54
+ICMP6_OUTMSGS = 55
+ICMP6_OUTERRORS = 56
+
+###########################################################################
+# Link Cache
+class LinkCache(netlink.Cache):
+ """Cache of network links"""
+
+ def __init__(self, family=socket.AF_UNSPEC, cache=None):
+ if not cache:
+ cache = self._alloc_cache_name("route/link")
+
+ self._protocol = netlink.NETLINK_ROUTE
+ self._c_cache = cache
+ self._set_arg1(family)
+
+ def __getitem__(self, key):
+ if type(key) is int:
+ link = capi.rtnl_link_get(self._c_cache, key)
+ elif type(key) is str:
+ link = capi.rtnl_link_get_by_name(self._c_cache, key)
+
+ if link is None:
+ raise KeyError()
+ else:
+ return Link.from_capi(link)
+
+ def _new_object(self, obj):
+ return Link(obj)
+
+ def _new_cache(self, cache):
+ return LinkCache(family=self.arg1, cache=cache)
+
+###########################################################################
+# Link Object
+class Link(netlink.Object):
+ """Network link"""
+
+ def __init__(self, obj=None):
+ netlink.Object.__init__(self, "route/link", "link", obj)
+ self._rtnl_link = self._obj2type(self._nl_object)
+
+ self._type = None
+
+ if self.type:
+ self._type_lookup(self.type)
+
+ self.inet = inet.InetLink(self)
+ self.af = {'inet' : self.inet }
+
+ @classmethod
+ def from_capi(cls, obj):
+ return cls(capi.link2obj(obj))
+
+ def _obj2type(self, obj):
+ return capi.obj2link(obj)
+
+ def __cmp__(self, other):
+ return self.ifindex - other.ifindex
+
+ def _new_instance(self, obj):
+ if not obj:
+ raise ValueError()
+
+ return Link(obj)
+
+ def _type_lookup(self, name):
+ rname = 'netlink.route.links.' + name
+ tmp = __import__(rname)
+ mod = sys.modules[rname]
+
+ # this will create a type instance and assign it to
+ # link.<type>, e.g. link.vlan.id
+ self._type = mod.assign_type(self)
+
+ #####################################################################
+ # ifindex
+ @netlink.nlattr('link.ifindex', type=int, immutable=True, fmt=util.num)
+ @property
+ def ifindex(self):
+ """interface index"""
+ return capi.rtnl_link_get_ifindex(self._rtnl_link)
+
+ @ifindex.setter
+ def ifindex(self, value):
+ capi.rtnl_link_set_ifindex(self._rtnl_link, int(value))
+
+ # ifindex is immutable but we assume that if _orig does not
+ # have an ifindex specified, it was meant to be given here
+ if capi.rtnl_link_get_ifindex(self._orig) == 0:
+ capi.rtnl_link_set_ifindex(self._orig, int(value))
+
+ #####################################################################
+ # name
+ @netlink.nlattr('link.name', type=str, fmt=util.bold)
+ @property
+ def name(self):
+ """Name of link"""
+ return capi.rtnl_link_get_name(self._rtnl_link)
+
+ @name.setter
+ def name(self, value):
+ capi.rtnl_link_set_name(self._rtnl_link, value)
+
+ # name is the secondary identifier, if _orig does not have
+ # the name specified yet, assume it was meant to be specified
+ # here. ifindex will always take priority, therefore if ifindex
+ # is specified as well, this will be ignored automatically.
+ if capi.rtnl_link_get_name(self._orig) is None:
+ capi.rtnl_link_set_name(self._orig, value)
+
+ #####################################################################
+ # flags
+ @netlink.nlattr('link.flags', type=str, fmt=util.string)
+ @property
+ def flags(self):
+ """Flags"""
+ flags = capi.rtnl_link_get_flags(self._rtnl_link)
+ return capi.rtnl_link_flags2str(flags, 256)[0].split(',')
+
+ def _set_flag(self, flag):
+ if flag[0] == '-':
+ i = capi.rtnl_link_str2flags(flag[1:])
+ capi.rtnl_link_unset_flags(self._rtnl_link, i)
+ else:
+ i = capi.rtnl_link_str2flags(flag[1:])
+ capi.rtnl_link_set_flags(self._rtnl_link, i)
+
+ @flags.setter
+ def flags(self, value):
+ if type(value) is list:
+ for flag in value:
+ self._set_flag(flag)
+ else:
+ self._set_flag(value)
+
+ #####################################################################
+ # mtu
+ @netlink.nlattr('link.mtu', type=int, fmt=util.num)
+ @property
+ def mtu(self):
+ """Maximum Transmission Unit"""
+ return capi.rtnl_link_get_mtu(self._rtnl_link)
+
+ @mtu.setter
+ def mtu(self, value):
+ capi.rtnl_link_set_mtu(self._rtnl_link, int(value))
+
+ #####################################################################
+ # family
+ @netlink.nlattr('link.family', type=int, immutable=True, fmt=util.num)
+ @property
+ def family(self):
+ """Address family"""
+ return capi.rtnl_link_get_family(self._rtnl_link)
+
+ @family.setter
+ def family(self, value):
+ capi.rtnl_link_set_family(self._rtnl_link, value)
+
+ #####################################################################
+ # address
+ @netlink.nlattr('link.address', type=str, fmt=util.addr)
+ @property
+ def address(self):
+ """Hardware address (MAC address)"""
+ a = capi.rtnl_link_get_addr(self._rtnl_link)
+ return netlink.AbstractAddress(a)
+
+ @address.setter
+ def address(self, value):
+ capi.rtnl_link_set_addr(self._rtnl_link, value._addr)
+
+ #####################################################################
+ # broadcast
+ @netlink.nlattr('link.broadcast', type=str, fmt=util.addr)
+ @property
+ def broadcast(self):
+ """Hardware broadcast address"""
+ a = capi.rtnl_link_get_broadcast(self._rtnl_link)
+ return netlink.AbstractAddress(a)
+
+ @broadcast.setter
+ def broadcast(self, value):
+ capi.rtnl_link_set_broadcast(self._rtnl_link, value._addr)
+
+ #####################################################################
+ # qdisc
+ @netlink.nlattr('link.qdisc', type=str, immutable=True, fmt=util.string)
+ @property
+ def qdisc(self):
+ """Name of qdisc (cannot be changed)"""
+ return capi.rtnl_link_get_qdisc(self._rtnl_link)
+
+ @qdisc.setter
+ def qdisc(self, value):
+ capi.rtnl_link_set_qdisc(self._rtnl_link, value)
+
+ #####################################################################
+ # txqlen
+ @netlink.nlattr('link.txqlen', type=int, fmt=util.num)
+ @property
+ def txqlen(self):
+ """"Length of transmit queue"""
+ return capi.rtnl_link_get_txqlen(self._rtnl_link)
+
+ @txqlen.setter
+ def txqlen(self, value):
+ capi.rtnl_link_set_txqlen(self._rtnl_link, int(value))
+
+ #####################################################################
+ # weight
+ @netlink.nlattr('link.weight', type=str, fmt=util.string)
+ @property
+ def weight(self):
+ """Weight"""
+ v = capi.rtnl_link_get_weight(self._rtnl_link)
+ if v == 4294967295:
+ return 'max'
+ else:
+ return str(v)
+
+ @weight.setter
+ def weight(self, value):
+ if value == 'max':
+ v = 4294967295
+ else:
+ v = int(value)
+ capi.rtnl_link_set_weight(self._rtnl_link, v)
+
+ #####################################################################
+ # arptype
+ @netlink.nlattr('link.arptype', type=str, immutable=True, fmt=util.string)
+ @property
+ def arptype(self):
+ """Type of link (cannot be changed)"""
+ type = capi.rtnl_link_get_arptype(self._rtnl_link)
+ return core_capi.nl_llproto2str(type, 64)[0]
+
+ @arptype.setter
+ def arptype(self, value):
+ i = core_capi.nl_str2llproto(value)
+ capi.rtnl_link_set_arptype(self._rtnl_link, i)
+
+ #####################################################################
+ # operstate
+ @netlink.nlattr('link.operstate', type=str, immutable=True,
+ fmt=util.string, title='state')
+ @property
+ def operstate(self):
+ """Operational status"""
+ operstate = capi.rtnl_link_get_operstate(self._rtnl_link)
+ return capi.rtnl_link_operstate2str(operstate, 32)[0]
+
+ @operstate.setter
+ def operstate(self, value):
+ i = capi.rtnl_link_str2operstate(flag)
+ capi.rtnl_link_set_operstate(self._rtnl_link, i)
+
+ #####################################################################
+ # mode
+ @netlink.nlattr('link.mode', type=str, immutable=True, fmt=util.string)
+ @property
+ def mode(self):
+ """Link mode"""
+ mode = capi.rtnl_link_get_linkmode(self._rtnl_link)
+ return capi.rtnl_link_mode2str(mode, 32)[0]
+
+ @mode.setter
+ def mode(self, value):
+ i = capi.rtnl_link_str2mode(flag)
+ capi.rtnl_link_set_linkmode(self._rtnl_link, i)
+
+ #####################################################################
+ # alias
+ @netlink.nlattr('link.alias', type=str, fmt=util.string)
+ @property
+ def alias(self):
+ """Interface alias (SNMP)"""
+ return capi.rtnl_link_get_ifalias(self._rtnl_link)
+
+ @alias.setter
+ def alias(self, value):
+ capi.rtnl_link_set_ifalias(self._rtnl_link, value)
+
+ #####################################################################
+ # type
+ @netlink.nlattr('link.type', type=str, fmt=util.string)
+ @property
+ def type(self):
+ """Link type"""
+ return capi.rtnl_link_get_info_type(self._rtnl_link)
+
+ @type.setter
+ def type(self, value):
+ if capi.rtnl_link_set_info_type(self._rtnl_link, value) < 0:
+ raise NameError("unknown info type")
+
+ self._type_lookup(value)
+
+ #####################################################################
+ # get_stat()
+ def get_stat(self, stat):
+ """Retrieve statistical information"""
+ if type(stat) is str:
+ stat = capi.rtnl_link_str2stat(stat)
+ if stat < 0:
+ raise NameError("unknown name of statistic")
+
+ return capi.rtnl_link_get_stat(self._rtnl_link, stat)
+
+ #####################################################################
+ # add()
+ def add(self, socket=None, flags=None):
+ if not socket:
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+ if not flags:
+ flags = netlink.NLM_F_CREATE
+
+ ret = capi.rtnl_link_add(socket._sock, self._rtnl_link, flags)
+ if ret < 0:
+ raise netlink.KernelError(ret)
+
+ #####################################################################
+ # change()
+ def change(self, socket=None, flags=0):
+ """Commit changes made to the link object"""
+ if not socket:
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+ if not self._orig:
+ raise NetlinkError("Original link not available")
+ ret = capi.rtnl_link_change(socket._sock, self._orig, self._rtnl_link, flags)
+ if ret < 0:
+ raise netlink.KernelError(ret)
+
+ #####################################################################
+ # delete()
+ def delete(self, socket=None):
+ """Attempt to delete this link in the kernel"""
+ if not socket:
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+ ret = capi.rtnl_link_delete(socket._sock, self._rtnl_link)
+ if ret < 0:
+ raise netlink.KernelError(ret)
+
+ ###################################################################
+ # private properties
+ #
+ # Used for formatting output. USE AT OWN RISK
+ @property
+ def _state(self):
+ if 'up' in self.flags:
+ buf = util.good('up')
+ if 'lowerup' not in self.flags:
+ buf += ' ' + util.bad('no-carrier')
+ else:
+ buf = util.bad('down')
+ return buf
+
+ @property
+ def _brief(self):
+ buf = ''
+ if self.type:
+ if self._type and hasattr(self._type, 'brief'):
+ buf += self._type.brief()
+ else:
+ buf += util.yellow(self.type)
+
+ return buf + self._foreach_af('brief')
+
+ @property
+ def _flags(self):
+ ignore = ['up', 'running', 'lowerup']
+ return ','.join([flag for flag in self.flags if flag not in ignore])
+
+ def _foreach_af(self, name, args=None):
+ buf = ''
+ for af in self.af:
+ try:
+ func = getattr(self.af[af], name)
+ s = str(func(args))
+ if len(s) > 0:
+ buf += ' ' + s
+ except AttributeError:
+ pass
+ return buf
+
+ ###################################################################
+ #
+ # format(details=False, stats=False)
+ #
+ def format(self, details=False, stats=False, indent=''):
+ """Return link as formatted text"""
+ fmt = util.MyFormatter(self, indent)
+
+ buf = fmt.format('{a|ifindex} {a|name} {a|arptype} {a|address} '\
+ '{a|_state} <{a|_flags}> {a|_brief}')
+
+ if details:
+ buf += fmt.nl('\t{t|mtu} {t|txqlen} {t|weight} '\
+ '{t|qdisc} {t|operstate}')
+ buf += fmt.nl('\t{t|broadcast} {t|alias}')
+
+ buf += self._foreach_af('details', fmt)
+
+ 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)
+
+ buf += self._foreach_af('stats')
+
+ return buf
+
+def get(name, socket=None):
+ """Lookup Link object directly from kernel"""
+ if not name:
+ raise ValueError()
+
+ if not socket:
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+ link = capi.get_from_kernel(socket._sock, 0, name)
+ if not link:
+ return None
+
+ return Link.from_capi(link)
+
+link_cache = LinkCache()
+
+def resolve(name):
+ socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+ link_cache.refill()
+
+ return link_cache[name]
diff --git a/python/netlink/route/links/__init__.py b/python/netlink/route/links/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/netlink/route/links/__init__.py
diff --git a/python/netlink/route/links/dummy.py b/python/netlink/route/links/dummy.py
new file mode 100644
index 0000000..495be94
--- /dev/null
+++ b/python/netlink/route/links/dummy.py
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Dummy
+
+"""
+
+__version__ = "1.0"
+__all__ = ['assign_type']
+
+import netlink.core as netlink
+import netlink.route.capi as capi
+
+class DummyLink(object):
+ def __init__(self, link):
+ self._rtnl_link = link
+
+def assign_type(link):
+ link.dummy = DummyLink(link._rtnl_link)
+ return link.dummy
diff --git a/python/netlink/route/links/inet.py b/python/netlink/route/links/inet.py
new file mode 100644
index 0000000..63c234f
--- /dev/null
+++ b/python/netlink/route/links/inet.py
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""IPv4
+
+"""
+
+__all__ = ['']
+
+import netlink.core as netlink
+import netlink.route.capi as capi
+import netlink.util as util
+
+DEVCONF_FORWARDING = 1
+DEVCONF_MC_FORWARDING = 2
+DEVCONF_PROXY_ARP = 3
+DEVCONF_ACCEPT_REDIRECTS = 4
+DEVCONF_SECURE_REDIRECTS = 5
+DEVCONF_SEND_REDIRECTS = 6
+DEVCONF_SHARED_MEDIA = 7
+DEVCONF_RP_FILTER = 8
+DEVCONF_ACCEPT_SOURCE_ROUTE = 9
+DEVCONF_BOOTP_RELAY = 10
+DEVCONF_LOG_MARTIANS = 11
+DEVCONF_TAG = 12
+DEVCONF_ARPFILTER = 13
+DEVCONF_MEDIUM_ID = 14
+DEVCONF_NOXFRM = 15
+DEVCONF_NOPOLICY = 16
+DEVCONF_FORCE_IGMP_VERSION = 17
+DEVCONF_ARP_ANNOUNCE = 18
+DEVCONF_ARP_IGNORE = 19
+DEVCONF_PROMOTE_SECONDARIES = 20
+DEVCONF_ARP_ACCEPT = 21
+DEVCONF_ARP_NOTIFY = 22
+DEVCONF_ACCEPT_LOCAL = 23
+DEVCONF_SRC_VMARK = 24
+DEVCONF_PROXY_ARP_PVLAN = 25
+DEVCONF_MAX = DEVCONF_PROXY_ARP_PVLAN
+
+def _resolve(id):
+ if type(id) is str:
+ id = capi.rtnl_link_inet_str2devconf(id)[0]
+ if id < 0:
+ raise NameError("unknown configuration id")
+ return id
+
+class InetLink(object):
+ def __init__(self, link):
+ self._link = link
+
+ def details(self, fmt):
+ buf = '\n' + fmt.nl('\t%s\n\t' % util.title('Configuration:'))
+
+ for i in range(DEVCONF_FORWARDING,DEVCONF_MAX+1):
+ if i & 1 and i > 1:
+ buf += fmt.nl('\t')
+ txt = util.kw(capi.rtnl_link_inet_devconf2str(i, 32)[0])
+ buf += fmt.format('{0:28s} {1:12} ', txt,
+ self.get_conf(i))
+
+
+ return buf
+
+ def get_conf(self, id):
+ return capi.inet_get_conf(self._link._rtnl_link, _resolve(id))
+
+ def set_conf(self, id, value):
+ return capi.rtnl_link_inet_set_conf(self._link._rtnl_link,
+ _resolve(id), int(value))
+
+ @netlink.nlattr('link.inet.forwarding', type=bool, fmt=util.bool)
+ @property
+ def forwarding(self):
+ return bool(self.get_conf(DEVCONF_FORWARDING))
+
+ @forwarding.setter
+ def forwarding(self, value):
+ self.set_conf(DEVCONF_FORWARDING, int(value))
+
+ @netlink.nlattr('link.inet.mc_forwarding', type=bool, fmt=util.bool)
+ @property
+ def mc_forwarding(self):
+ return bool(self.get_conf(DEVCONF_MC_FORWARDING))
+
+ @mc_forwarding.setter
+ def mc_forwarding(self, value):
+ self.set_conf(DEVCONF_MC_FORWARDING, int(value))
+
+ @netlink.nlattr('link.inet.proxy_arp', type=bool, fmt=util.bool)
+ @property
+ def proxy_arp(self):
+ return bool(self.get_conf(DEVCONF_PROXY_ARP))
+
+ @proxy_arp.setter
+ def proxy_arp(self, value):
+ self.set_conf(DEVCONF_PROXY_ARP, int(value))
+
+ @netlink.nlattr('link.inet.accept_redirects', type=bool, fmt=util.bool)
+ @property
+ def accept_redirects(self):
+ return bool(self.get_conf(DEVCONF_ACCEPT_REDIRECTS))
+
+ @accept_redirects.setter
+ def accept_redirects(self, value):
+ self.set_conf(DEVCONF_ACCEPT_REDIRECTS, int(value))
+
+ @netlink.nlattr('link.inet.secure_redirects', type=bool, fmt=util.bool)
+ @property
+ def secure_redirects(self):
+ return bool(self.get_conf(DEVCONF_SECURE_REDIRECTS))
+
+ @secure_redirects.setter
+ def secure_redirects(self, value):
+ self.set_conf(DEVCONF_SECURE_REDIRECTS, int(value))
+
+ @netlink.nlattr('link.inet.send_redirects', type=bool, fmt=util.bool)
+ @property
+ def send_redirects(self):
+ return bool(self.get_conf(DEVCONF_SEND_REDIRECTS))
+
+ @send_redirects.setter
+ def send_redirects(self, value):
+ self.set_conf(DEVCONF_SEND_REDIRECTS, int(value))
+
+ @netlink.nlattr('link.inet.shared_media', type=bool, fmt=util.bool)
+ @property
+ def shared_media(self):
+ return bool(self.get_conf(DEVCONF_SHARED_MEDIA))
+
+ @shared_media.setter
+ def shared_media(self, value):
+ self.set_conf(DEVCONF_SHARED_MEDIA, int(value))
+
+# IPV4_DEVCONF_RP_FILTER,
+# IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
+# IPV4_DEVCONF_BOOTP_RELAY,
+# IPV4_DEVCONF_LOG_MARTIANS,
+# IPV4_DEVCONF_TAG,
+# IPV4_DEVCONF_ARPFILTER,
+# IPV4_DEVCONF_MEDIUM_ID,
+# IPV4_DEVCONF_NOXFRM,
+# IPV4_DEVCONF_NOPOLICY,
+# IPV4_DEVCONF_FORCE_IGMP_VERSION,
+# IPV4_DEVCONF_ARP_ANNOUNCE,
+# IPV4_DEVCONF_ARP_IGNORE,
+# IPV4_DEVCONF_PROMOTE_SECONDARIES,
+# IPV4_DEVCONF_ARP_ACCEPT,
+# IPV4_DEVCONF_ARP_NOTIFY,
+# IPV4_DEVCONF_ACCEPT_LOCAL,
+# IPV4_DEVCONF_SRC_VMARK,
+# IPV4_DEVCONF_PROXY_ARP_PVLAN,
diff --git a/python/netlink/route/links/vlan.py b/python/netlink/route/links/vlan.py
new file mode 100644
index 0000000..1d4e03d
--- /dev/null
+++ b/python/netlink/route/links/vlan.py
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""VLAN network link
+
+"""
+
+import netlink.core as netlink
+import netlink.route.capi as capi
+
+class VLANLink(object):
+ def __init__(self, link):
+ self._link = link
+
+ ###################################################################
+ # id
+ @netlink.nlattr('link.vlan.id', type=int)
+ @property
+ def id(self):
+ """vlan identifier"""
+ return capi.rtnl_link_vlan_get_id(self._link)
+
+ @id.setter
+ def id(self, value):
+ capi.rtnl_link_vlan_set_id(self._link, int(value))
+
+ ###################################################################
+ # flags
+ @netlink.nlattr('link.vlan.flags', type=str)
+ @property
+ def flags(self):
+ """vlan flags"""
+ flags = capi.rtnl_link_vlan_get_flags(self._link)
+ return capi.rtnl_link_vlan_flags2str(flags, 256)[0].split(',')
+
+ def _set_flag(self, flag):
+ i = capi.rtnl_link_vlan_str2flags(flag[1:])
+ if flag[0] == '-':
+ capi.rtnl_link_vlan_unset_flags(self._link, i)
+ else:
+ capi.rtnl_link_vlan_set_flags(self._link, i)
+
+ @flags.setter
+ def flags(self, value):
+ if type(value) is list:
+ for flag in value:
+ self._set_flag(flag)
+ else:
+ self._set_flag(value)
+
+ ###################################################################
+ # TODO:
+ # - ingress map
+ # - egress map
+
+ def brief(self):
+ return 'vlan-id ' + self.id
+
+def assign_type(link):
+ link.vlan = VLANLink(link._link)
+ return link.vlan
diff --git a/python/netlink/route/qdisc.py b/python/netlink/route/qdisc.py
new file mode 100644
index 0000000..c8a4c6f
--- /dev/null
+++ b/python/netlink/route/qdisc.py
@@ -0,0 +1,185 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+__all__ = [
+ 'QdiscCache',
+ 'Qdisc']
+
+import netlink.core as netlink
+import netlink.capi as core_capi
+import netlink.route.capi as capi
+import netlink.util as util
+import netlink.route.tc as tc
+
+###########################################################################
+# 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._protocol = netlink.NETLINK_ROUTE
+ 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.Tc):
+ """Network link"""
+
+ def __init__(self, obj=None):
+ self._name = "qdisc"
+ self._abbr = "qdisc"
+
+ netlink.Object.__init__(self, "route/qdisc", "qdisc", obj)
+ self._tc = capi.obj2tc(self._nl_object)
+ self._rtnl_qdisc = self._obj2type(self._nl_object)
+
+ netlink.attr('qdisc.handle', fmt=util.handle)
+ netlink.attr('qdisc.parent', fmt=util.handle)
+ netlink.attr('qdisc.kind', fmt=util.bold)
+
+ def _obj2type(self, obj):
+ return capi.obj2qdisc(obj)
+
+ 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.MyFormatter(self)
+
+ buf = fmt.format('qdisc {kind} {handle} {_dev} {_parent}')
+
+ if details:
+ fmt = util.MyFormatter(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
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