[Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3

Wayne Xia xiawenc at linux.vnet.ibm.com
Thu Jan 12 09:46:45 UTC 2012


    Libbridge comes from libbridge-util-1.5, which have no devel version
released. Libnl3 have packages released, but most programs today such
as libvirt still using libnl1.so, which conflict with libnl3 making runtime
errors if libnl1.so and libnl-3.so were both loaded. To avoid this, the lib
part of source code in libnl3 were directly moved here, and it would be
compiled and encapsulated into libnetwork.so resulting isolation with
libnl1.so. Source code version of libnl3 is libnl3.2.3.

Signed-off-by: Wayne Xia <xiawenc at linux.vnet.ibm.com>
---
 libnetwork/libbridge/.gitignore                    |    2 +
 libnetwork/libbridge/libbridge.h                   |  119 +
 libnetwork/libbridge/libbridge_devif.c             |  442 ++++
 libnetwork/libbridge/libbridge_if.c                |  117 +
 libnetwork/libbridge/libbridge_init.c              |  213 ++
 libnetwork/libbridge/libbridge_misc.c              |   51 +
 libnetwork/libbridge/libbridge_private.h           |   56 +
 libnetwork/libnl3/include/linux/fib_rules.h        |   69 +
 libnetwork/libnl3/include/linux/gen_stats.h        |   67 +
 libnetwork/libnl3/include/linux/genetlink.h        |   83 +
 libnetwork/libnl3/include/linux/if.h               |  140 ++
 libnetwork/libnl3/include/linux/if_addr.h          |   55 +
 libnetwork/libnl3/include/linux/if_arp.h           |  156 ++
 libnetwork/libnl3/include/linux/if_ether.h         |  125 ++
 libnetwork/libnl3/include/linux/if_link.h          |  377 ++++
 libnetwork/libnl3/include/linux/if_vlan.h          |   62 +
 libnetwork/libnl3/include/linux/inetdevice.h       |   36 +
 libnetwork/libnl3/include/linux/ip_mp_alg.h        |   22 +
 libnetwork/libnl3/include/linux/ipv6.h             |  146 ++
 libnetwork/libnl3/include/linux/neighbour.h        |  155 ++
 libnetwork/libnl3/include/linux/netfilter.h        |   57 +
 .../libnl3/include/linux/netfilter/nfnetlink.h     |   60 +
 .../include/linux/netfilter/nfnetlink_conntrack.h  |  140 ++
 .../libnl3/include/linux/netfilter/nfnetlink_log.h |   97 +
 .../include/linux/netfilter/nfnetlink_queue.h      |   94 +
 libnetwork/libnl3/include/linux/netlink.h          |  149 ++
 libnetwork/libnl3/include/linux/pkt_cls.h          |  467 ++++
 libnetwork/libnl3/include/linux/pkt_sched.h        |  606 +++++
 libnetwork/libnl3/include/linux/rtnetlink.h        |  605 +++++
 libnetwork/libnl3/include/linux/snmp.h             |  270 +++
 .../libnl3/include/linux/tc_ematch/tc_em_meta.h    |   89 +
 libnetwork/libnl3/include/netlink-generic.h        |   20 +
 libnetwork/libnl3/include/netlink-local.h          |  213 ++
 libnetwork/libnl3/include/netlink-tc.h             |   55 +
 libnetwork/libnl3/include/netlink-types.h          |  846 +++++++
 libnetwork/libnl3/include/netlink/addr.h           |   66 +
 libnetwork/libnl3/include/netlink/attr.h           |  283 +++
 libnetwork/libnl3/include/netlink/cache-api.h      |  230 ++
 libnetwork/libnl3/include/netlink/cache.h          |  134 ++
 libnetwork/libnl3/include/netlink/cli/addr.h       |   32 +
 libnetwork/libnl3/include/netlink/cli/class.h      |   21 +
 libnetwork/libnl3/include/netlink/cli/cls.h        |   24 +
 libnetwork/libnl3/include/netlink/cli/ct.h         |   34 +
 libnetwork/libnl3/include/netlink/cli/link.h       |   30 +
 libnetwork/libnl3/include/netlink/cli/neigh.h      |   27 +
 libnetwork/libnl3/include/netlink/cli/qdisc.h      |   23 +
 libnetwork/libnl3/include/netlink/cli/route.h      |   34 +
 libnetwork/libnl3/include/netlink/cli/rule.h       |   21 +
 libnetwork/libnl3/include/netlink/cli/tc.h         |   39 +
 libnetwork/libnl3/include/netlink/cli/utils.h      |   82 +
 libnetwork/libnl3/include/netlink/data.h           |   41 +
 libnetwork/libnl3/include/netlink/errno.h          |   64 +
 .../libnl3/include/netlink/fib_lookup/lookup.h     |   42 +
 .../libnl3/include/netlink/fib_lookup/request.h    |   51 +
 libnetwork/libnl3/include/netlink/genl/ctrl.h      |   40 +
 libnetwork/libnl3/include/netlink/genl/family.h    |   53 +
 libnetwork/libnl3/include/netlink/genl/genl.h      |   46 +
 libnetwork/libnl3/include/netlink/genl/mngt.h      |   87 +
 libnetwork/libnl3/include/netlink/handlers.h       |  146 ++
 libnetwork/libnl3/include/netlink/list.h           |   93 +
 libnetwork/libnl3/include/netlink/msg.h            |  147 ++
 libnetwork/libnl3/include/netlink/netfilter/ct.h   |  126 ++
 libnetwork/libnl3/include/netlink/netfilter/log.h  |  109 +
 .../libnl3/include/netlink/netfilter/log_msg.h     |   98 +
 .../libnl3/include/netlink/netfilter/netfilter.h   |   31 +
 libnetwork/libnl3/include/netlink/netfilter/nfnl.h |   44 +
 .../libnl3/include/netlink/netfilter/queue.h       |   90 +
 .../libnl3/include/netlink/netfilter/queue_msg.h   |  104 +
 libnetwork/libnl3/include/netlink/netlink-compat.h |   50 +
 libnetwork/libnl3/include/netlink/netlink-kernel.h |  293 +++
 libnetwork/libnl3/include/netlink/netlink.h        |   93 +
 libnetwork/libnl3/include/netlink/object-api.h     |  348 +++
 libnetwork/libnl3/include/netlink/object.h         |   70 +
 libnetwork/libnl3/include/netlink/route/addr.h     |   98 +
 libnetwork/libnl3/include/netlink/route/class.h    |   66 +
 .../libnl3/include/netlink/route/classifier.h      |   51 +
 .../libnl3/include/netlink/route/cls/basic.h       |   31 +
 .../libnl3/include/netlink/route/cls/cgroup.h      |   30 +
 .../libnl3/include/netlink/route/cls/ematch.h      |   95 +
 .../libnl3/include/netlink/route/cls/ematch/cmp.h  |   32 +
 .../libnl3/include/netlink/route/cls/ematch/meta.h |   41 +
 .../include/netlink/route/cls/ematch/nbyte.h       |   36 +
 .../libnl3/include/netlink/route/cls/ematch/text.h |   42 +
 libnetwork/libnl3/include/netlink/route/cls/fw.h   |   29 +
 .../libnl3/include/netlink/route/cls/police.h      |   29 +
 libnetwork/libnl3/include/netlink/route/cls/u32.h  |   43 +
 libnetwork/libnl3/include/netlink/route/link.h     |  217 ++
 libnetwork/libnl3/include/netlink/route/link/api.h |  134 ++
 .../libnl3/include/netlink/route/link/bonding.h    |   37 +
 .../libnl3/include/netlink/route/link/inet.h       |   29 +
 .../libnl3/include/netlink/route/link/info-api.h   |   20 +
 .../libnl3/include/netlink/route/link/vlan.h       |   57 +
 .../libnl3/include/netlink/route/neighbour.h       |   79 +
 libnetwork/libnl3/include/netlink/route/neightbl.h |   65 +
 libnetwork/libnl3/include/netlink/route/nexthop.h  |   65 +
 libnetwork/libnl3/include/netlink/route/pktloc.h   |   49 +
 libnetwork/libnl3/include/netlink/route/qdisc.h    |   73 +
 .../libnl3/include/netlink/route/qdisc/cbq.h       |   30 +
 .../libnl3/include/netlink/route/qdisc/dsmark.h    |   41 +
 .../libnl3/include/netlink/route/qdisc/fifo.h      |   28 +
 .../libnl3/include/netlink/route/qdisc/htb.h       |   47 +
 .../libnl3/include/netlink/route/qdisc/netem.h     |   75 +
 .../libnl3/include/netlink/route/qdisc/prio.h      |   53 +
 .../libnl3/include/netlink/route/qdisc/red.h       |   17 +
 .../libnl3/include/netlink/route/qdisc/sfq.h       |   36 +
 .../libnl3/include/netlink/route/qdisc/tbf.h       |   40 +
 libnetwork/libnl3/include/netlink/route/route.h    |  124 +
 libnetwork/libnl3/include/netlink/route/rtnl.h     |   69 +
 libnetwork/libnl3/include/netlink/route/rule.h     |   75 +
 libnetwork/libnl3/include/netlink/route/tc-api.h   |  143 ++
 libnetwork/libnl3/include/netlink/route/tc.h       |  105 +
 libnetwork/libnl3/include/netlink/socket.h         |   69 +
 libnetwork/libnl3/include/netlink/types.h          |  110 +
 libnetwork/libnl3/include/netlink/utils.h          |   85 +
 libnetwork/libnl3/include/netlink/version.h        |   28 +
 libnetwork/libnl3/include/netlink/version.h.in     |   28 +
 libnetwork/libnl3/lib/addr.c                       |  918 ++++++++
 libnetwork/libnl3/lib/attr.c                       | 1213 ++++++++++
 libnetwork/libnl3/lib/cache.c                      |  965 ++++++++
 libnetwork/libnl3/lib/cache_mngr.c                 |  391 ++++
 libnetwork/libnl3/lib/cache_mngt.c                 |  256 +++
 libnetwork/libnl3/lib/cli/cls/basic.c              |   93 +
 libnetwork/libnl3/lib/cli/cls/cgroup.c             |   75 +
 libnetwork/libnl3/lib/cli/qdisc/bfifo.c            |   83 +
 libnetwork/libnl3/lib/cli/qdisc/blackhole.c        |   64 +
 libnetwork/libnl3/lib/cli/qdisc/htb.c              |  203 ++
 libnetwork/libnl3/lib/cli/qdisc/pfifo.c            |   77 +
 libnetwork/libnl3/lib/data.c                       |  186 ++
 libnetwork/libnl3/lib/defs.h                       |   85 +
 libnetwork/libnl3/lib/defs.h.in                    |   84 +
 libnetwork/libnl3/lib/error.c                      |  116 +
 libnetwork/libnl3/lib/fib_lookup/lookup.c          |  348 +++
 libnetwork/libnl3/lib/fib_lookup/request.c         |  185 ++
 libnetwork/libnl3/lib/genl/ctrl.c                  |  380 ++++
 libnetwork/libnl3/lib/genl/family.c                |  316 +++
 libnetwork/libnl3/lib/genl/genl.c                  |  268 +++
 libnetwork/libnl3/lib/genl/mngt.c                  |  273 +++
 libnetwork/libnl3/lib/handlers.c                   |  395 ++++
 libnetwork/libnl3/lib/msg.c                        | 1050 +++++++++
 libnetwork/libnl3/lib/netfilter/ct.c               |  601 +++++
 libnetwork/libnl3/lib/netfilter/ct_obj.c           |  785 +++++++
 libnetwork/libnl3/lib/netfilter/log.c              |  251 +++
 libnetwork/libnl3/lib/netfilter/log_msg.c          |  209 ++
 libnetwork/libnl3/lib/netfilter/log_msg_obj.c      |  458 ++++
 libnetwork/libnl3/lib/netfilter/log_obj.c          |  287 +++
 libnetwork/libnl3/lib/netfilter/netfilter.c        |   53 +
 libnetwork/libnl3/lib/netfilter/nfnl.c             |  245 ++
 libnetwork/libnl3/lib/netfilter/queue.c            |  251 +++
 libnetwork/libnl3/lib/netfilter/queue_msg.c        |  284 +++
 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c    |  492 ++++
 libnetwork/libnl3/lib/netfilter/queue_obj.c        |  215 ++
 libnetwork/libnl3/lib/nl.c                         |  896 ++++++++
 libnetwork/libnl3/lib/object.c                     |  395 ++++
 libnetwork/libnl3/lib/route/addr.c                 | 1054 +++++++++
 libnetwork/libnl3/lib/route/class.c                |  473 ++++
 libnetwork/libnl3/lib/route/classid.c              |  441 ++++
 libnetwork/libnl3/lib/route/cls.c                  |  441 ++++
 libnetwork/libnl3/lib/route/cls/basic.c            |  229 ++
 libnetwork/libnl3/lib/route/cls/cgroup.c           |  189 ++
 libnetwork/libnl3/lib/route/cls/ematch.c           |  701 ++++++
 libnetwork/libnl3/lib/route/cls/ematch/cmp.c       |   93 +
 libnetwork/libnl3/lib/route/cls/ematch/container.c |   41 +
 libnetwork/libnl3/lib/route/cls/ematch/meta.c      |  334 +++
 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c     |  139 ++
 libnetwork/libnl3/lib/route/cls/ematch/text.c      |  183 ++
 libnetwork/libnl3/lib/route/cls/ematch_grammar.l   |  162 ++
 libnetwork/libnl3/lib/route/cls/ematch_syntax.y    |  497 +++++
 libnetwork/libnl3/lib/route/cls/fw.c               |  190 ++
 libnetwork/libnl3/lib/route/cls/police.c           |   66 +
 libnetwork/libnl3/lib/route/cls/u32.c              |  551 +++++
 libnetwork/libnl3/lib/route/link.c                 | 2342 ++++++++++++++++++++
 libnetwork/libnl3/lib/route/link/api.c             |  316 +++
 libnetwork/libnl3/lib/route/link/bonding.c         |  217 ++
 libnetwork/libnl3/lib/route/link/bridge.c          |   83 +
 libnetwork/libnl3/lib/route/link/dummy.c           |   40 +
 libnetwork/libnl3/lib/route/link/inet.c            |  280 +++
 libnetwork/libnl3/lib/route/link/inet6.c           |  377 ++++
 libnetwork/libnl3/lib/route/link/vlan.c            |  565 +++++
 libnetwork/libnl3/lib/route/neigh.c                |  846 +++++++
 libnetwork/libnl3/lib/route/neightbl.c             |  815 +++++++
 libnetwork/libnl3/lib/route/nexthop.c              |  290 +++
 libnetwork/libnl3/lib/route/pktloc.c               |  260 +++
 libnetwork/libnl3/lib/route/pktloc_grammar.l       |   51 +
 libnetwork/libnl3/lib/route/pktloc_syntax.y        |  103 +
 libnetwork/libnl3/lib/route/qdisc.c                |  575 +++++
 libnetwork/libnl3/lib/route/qdisc/blackhole.c      |   37 +
 libnetwork/libnl3/lib/route/qdisc/cbq.c            |  204 ++
 libnetwork/libnl3/lib/route/qdisc/dsmark.c         |  413 ++++
 libnetwork/libnl3/lib/route/qdisc/fifo.c           |  169 ++
 libnetwork/libnl3/lib/route/qdisc/htb.c            |  643 ++++++
 libnetwork/libnl3/lib/route/qdisc/netem.c          |  906 ++++++++
 libnetwork/libnl3/lib/route/qdisc/prio.c           |  294 +++
 libnetwork/libnl3/lib/route/qdisc/red.c            |  190 ++
 libnetwork/libnl3/lib/route/qdisc/sfq.c            |  256 +++
 libnetwork/libnl3/lib/route/qdisc/tbf.c            |  460 ++++
 libnetwork/libnl3/lib/route/route.c                |  202 ++
 libnetwork/libnl3/lib/route/route_obj.c            | 1148 ++++++++++
 libnetwork/libnl3/lib/route/route_utils.c          |  171 ++
 libnetwork/libnl3/lib/route/rtnl.c                 |  124 +
 libnetwork/libnl3/lib/route/rule.c                 |  753 +++++++
 libnetwork/libnl3/lib/route/tc.c                   | 1069 +++++++++
 libnetwork/libnl3/lib/socket.c                     |  628 ++++++
 libnetwork/libnl3/lib/stamp-h1                     |    1 +
 libnetwork/libnl3/lib/utils.c                      | 1040 +++++++++
 204 files changed, 47356 insertions(+), 0 deletions(-)
 create mode 100755 libnetwork/libbridge/.gitignore
 create mode 100644 libnetwork/libbridge/libbridge.h
 create mode 100644 libnetwork/libbridge/libbridge_devif.c
 create mode 100644 libnetwork/libbridge/libbridge_if.c
 create mode 100644 libnetwork/libbridge/libbridge_init.c
 create mode 100644 libnetwork/libbridge/libbridge_misc.c
 create mode 100644 libnetwork/libbridge/libbridge_private.h
 create mode 100644 libnetwork/libnl3/include/linux/fib_rules.h
 create mode 100644 libnetwork/libnl3/include/linux/gen_stats.h
 create mode 100644 libnetwork/libnl3/include/linux/genetlink.h
 create mode 100644 libnetwork/libnl3/include/linux/if.h
 create mode 100644 libnetwork/libnl3/include/linux/if_addr.h
 create mode 100644 libnetwork/libnl3/include/linux/if_arp.h
 create mode 100644 libnetwork/libnl3/include/linux/if_ether.h
 create mode 100644 libnetwork/libnl3/include/linux/if_link.h
 create mode 100644 libnetwork/libnl3/include/linux/if_vlan.h
 create mode 100644 libnetwork/libnl3/include/linux/inetdevice.h
 create mode 100644 libnetwork/libnl3/include/linux/ip_mp_alg.h
 create mode 100644 libnetwork/libnl3/include/linux/ipv6.h
 create mode 100644 libnetwork/libnl3/include/linux/neighbour.h
 create mode 100644 libnetwork/libnl3/include/linux/netfilter.h
 create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink.h
 create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h
 create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h
 create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h
 create mode 100644 libnetwork/libnl3/include/linux/netlink.h
 create mode 100644 libnetwork/libnl3/include/linux/pkt_cls.h
 create mode 100644 libnetwork/libnl3/include/linux/pkt_sched.h
 create mode 100644 libnetwork/libnl3/include/linux/rtnetlink.h
 create mode 100644 libnetwork/libnl3/include/linux/snmp.h
 create mode 100644 libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h
 create mode 100644 libnetwork/libnl3/include/netlink-generic.h
 create mode 100644 libnetwork/libnl3/include/netlink-local.h
 create mode 100644 libnetwork/libnl3/include/netlink-tc.h
 create mode 100644 libnetwork/libnl3/include/netlink-types.h
 create mode 100644 libnetwork/libnl3/include/netlink/addr.h
 create mode 100644 libnetwork/libnl3/include/netlink/attr.h
 create mode 100644 libnetwork/libnl3/include/netlink/cache-api.h
 create mode 100644 libnetwork/libnl3/include/netlink/cache.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/addr.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/class.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/cls.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/ct.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/link.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/neigh.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/qdisc.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/route.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/rule.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/tc.h
 create mode 100644 libnetwork/libnl3/include/netlink/cli/utils.h
 create mode 100644 libnetwork/libnl3/include/netlink/data.h
 create mode 100644 libnetwork/libnl3/include/netlink/errno.h
 create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/lookup.h
 create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/request.h
 create mode 100644 libnetwork/libnl3/include/netlink/genl/ctrl.h
 create mode 100644 libnetwork/libnl3/include/netlink/genl/family.h
 create mode 100644 libnetwork/libnl3/include/netlink/genl/genl.h
 create mode 100644 libnetwork/libnl3/include/netlink/genl/mngt.h
 create mode 100644 libnetwork/libnl3/include/netlink/handlers.h
 create mode 100644 libnetwork/libnl3/include/netlink/list.h
 create mode 100644 libnetwork/libnl3/include/netlink/msg.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/ct.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log_msg.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/netfilter.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/nfnl.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue.h
 create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue_msg.h
 create mode 100644 libnetwork/libnl3/include/netlink/netlink-compat.h
 create mode 100644 libnetwork/libnl3/include/netlink/netlink-kernel.h
 create mode 100644 libnetwork/libnl3/include/netlink/netlink.h
 create mode 100644 libnetwork/libnl3/include/netlink/object-api.h
 create mode 100644 libnetwork/libnl3/include/netlink/object.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/addr.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/class.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/classifier.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/basic.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/cgroup.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/text.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/fw.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/police.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/cls/u32.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link/api.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link/bonding.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link/inet.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link/info-api.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/link/vlan.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/neighbour.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/neightbl.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/nexthop.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/pktloc.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/cbq.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/fifo.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/htb.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/netem.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/prio.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/red.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/sfq.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/tbf.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/route.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/rtnl.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/rule.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/tc-api.h
 create mode 100644 libnetwork/libnl3/include/netlink/route/tc.h
 create mode 100644 libnetwork/libnl3/include/netlink/socket.h
 create mode 100644 libnetwork/libnl3/include/netlink/types.h
 create mode 100644 libnetwork/libnl3/include/netlink/utils.h
 create mode 100644 libnetwork/libnl3/include/netlink/version.h
 create mode 100644 libnetwork/libnl3/include/netlink/version.h.in
 create mode 100644 libnetwork/libnl3/lib/addr.c
 create mode 100644 libnetwork/libnl3/lib/attr.c
 create mode 100644 libnetwork/libnl3/lib/cache.c
 create mode 100644 libnetwork/libnl3/lib/cache_mngr.c
 create mode 100644 libnetwork/libnl3/lib/cache_mngt.c
 create mode 100644 libnetwork/libnl3/lib/cli/cls/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/cli/cls/basic.c
 create mode 100644 libnetwork/libnl3/lib/cli/cls/cgroup.c
 create mode 100644 libnetwork/libnl3/lib/cli/qdisc/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/cli/qdisc/bfifo.c
 create mode 100644 libnetwork/libnl3/lib/cli/qdisc/blackhole.c
 create mode 100644 libnetwork/libnl3/lib/cli/qdisc/htb.c
 create mode 100644 libnetwork/libnl3/lib/cli/qdisc/pfifo.c
 create mode 100644 libnetwork/libnl3/lib/data.c
 create mode 100644 libnetwork/libnl3/lib/defs.h
 create mode 100644 libnetwork/libnl3/lib/defs.h.in
 create mode 100644 libnetwork/libnl3/lib/error.c
 create mode 100644 libnetwork/libnl3/lib/fib_lookup/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/fib_lookup/lookup.c
 create mode 100644 libnetwork/libnl3/lib/fib_lookup/request.c
 create mode 100644 libnetwork/libnl3/lib/genl/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/genl/ctrl.c
 create mode 100644 libnetwork/libnl3/lib/genl/family.c
 create mode 100644 libnetwork/libnl3/lib/genl/genl.c
 create mode 100644 libnetwork/libnl3/lib/genl/mngt.c
 create mode 100644 libnetwork/libnl3/lib/handlers.c
 create mode 100644 libnetwork/libnl3/lib/msg.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/netfilter/ct.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/ct_obj.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/log.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg_obj.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/log_obj.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/netfilter.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/nfnl.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/queue.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c
 create mode 100644 libnetwork/libnl3/lib/netfilter/queue_obj.c
 create mode 100644 libnetwork/libnl3/lib/nl.c
 create mode 100644 libnetwork/libnl3/lib/object.c
 create mode 100644 libnetwork/libnl3/lib/route/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/route/addr.c
 create mode 100644 libnetwork/libnl3/lib/route/class.c
 create mode 100644 libnetwork/libnl3/lib/route/classid.c
 create mode 100644 libnetwork/libnl3/lib/route/cls.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/route/cls/basic.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/cgroup.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/cmp.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/container.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/meta.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/text.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_grammar.l
 create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_syntax.y
 create mode 100644 libnetwork/libnl3/lib/route/cls/fw.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/police.c
 create mode 100644 libnetwork/libnl3/lib/route/cls/u32.c
 create mode 100644 libnetwork/libnl3/lib/route/link.c
 create mode 100644 libnetwork/libnl3/lib/route/link/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/route/link/api.c
 create mode 100644 libnetwork/libnl3/lib/route/link/bonding.c
 create mode 100644 libnetwork/libnl3/lib/route/link/bridge.c
 create mode 100644 libnetwork/libnl3/lib/route/link/dummy.c
 create mode 100644 libnetwork/libnl3/lib/route/link/inet.c
 create mode 100644 libnetwork/libnl3/lib/route/link/inet6.c
 create mode 100644 libnetwork/libnl3/lib/route/link/vlan.c
 create mode 100644 libnetwork/libnl3/lib/route/neigh.c
 create mode 100644 libnetwork/libnl3/lib/route/neightbl.c
 create mode 100644 libnetwork/libnl3/lib/route/nexthop.c
 create mode 100644 libnetwork/libnl3/lib/route/pktloc.c
 create mode 100644 libnetwork/libnl3/lib/route/pktloc_grammar.l
 create mode 100644 libnetwork/libnl3/lib/route/pktloc_syntax.y
 create mode 100644 libnetwork/libnl3/lib/route/qdisc.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/.dirstamp
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/blackhole.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/cbq.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/dsmark.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/fifo.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/htb.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/netem.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/prio.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/red.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/sfq.c
 create mode 100644 libnetwork/libnl3/lib/route/qdisc/tbf.c
 create mode 100644 libnetwork/libnl3/lib/route/route.c
 create mode 100644 libnetwork/libnl3/lib/route/route_obj.c
 create mode 100644 libnetwork/libnl3/lib/route/route_utils.c
 create mode 100644 libnetwork/libnl3/lib/route/rtnl.c
 create mode 100644 libnetwork/libnl3/lib/route/rule.c
 create mode 100644 libnetwork/libnl3/lib/route/tc.c
 create mode 100644 libnetwork/libnl3/lib/socket.c
 create mode 100644 libnetwork/libnl3/lib/stamp-h1
 create mode 100644 libnetwork/libnl3/lib/utils.c

diff --git a/libnetwork/libbridge/.gitignore b/libnetwork/libbridge/.gitignore
new file mode 100755
index 0000000..f611548
--- /dev/null
+++ b/libnetwork/libbridge/.gitignore
@@ -0,0 +1,2 @@
+config.h
+stamp-h1
diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/libbridge/libbridge.h
new file mode 100644
index 0000000..39964f2
--- /dev/null
+++ b/libnetwork/libbridge/libbridge.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_H
+#define _LIBBRIDGE_H
+
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_bridge.h>
+
+/* defined in net/if.h but that conflicts with linux/if.h... */
+extern unsigned int if_nametoindex (const char *__ifname);
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
+
+struct bridge_id
+{
+	unsigned char prio[2];
+	unsigned char addr[6];
+};
+
+struct bridge_info
+{
+	struct bridge_id designated_root;
+	struct bridge_id bridge_id;
+	unsigned root_path_cost;
+	struct timeval max_age;
+	struct timeval hello_time;
+	struct timeval forward_delay;
+	struct timeval bridge_max_age;
+	struct timeval bridge_hello_time;
+	struct timeval bridge_forward_delay;
+	u_int16_t root_port;
+	unsigned char stp_enabled;
+	unsigned char topology_change;
+	unsigned char topology_change_detected;
+	struct timeval ageing_time;
+	struct timeval hello_timer_value;
+	struct timeval tcn_timer_value;
+	struct timeval topology_change_timer_value;
+	struct timeval gc_timer_value;
+};
+
+struct fdb_entry
+{
+	u_int8_t mac_addr[6];
+	u_int16_t port_no;
+	unsigned char is_local;
+	struct timeval ageing_timer_value;
+};
+
+struct port_info
+{
+	unsigned port_no;
+	struct bridge_id designated_root;
+	struct bridge_id designated_bridge;
+	u_int16_t port_id;
+	u_int16_t designated_port;
+	u_int8_t priority;
+	unsigned char top_change_ack;
+	unsigned char config_pending;
+	unsigned char state;
+	unsigned path_cost;
+	unsigned designated_cost;
+	struct timeval message_age_timer_value;
+	struct timeval forward_delay_timer_value;
+	struct timeval hold_timer_value;
+	unsigned char hairpin_mode;
+};
+
+extern int br_init(void);
+extern int br_refresh(void);
+extern void br_shutdown(void);
+
+extern int br_foreach_bridge(int (*iterator)(const char *brname, void *),
+			     void *arg);
+extern int br_foreach_port(const char *brname,
+			   int (*iterator)(const char *brname, const char *port,
+					   void *arg ),
+			   void *arg);
+extern const char *br_get_state_name(int state);
+
+extern int br_get_bridge_info(const char *br, struct bridge_info *info);
+extern int br_get_port_info(const char *brname, const char *port, 
+			    struct port_info *info);
+extern int br_add_bridge(const char *brname);
+extern int br_del_bridge(const char *brname);
+extern int br_add_interface(const char *br, const char *dev);
+extern int br_del_interface(const char *br, const char *dev);
+extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv);
+extern int br_set_bridge_hello_time(const char *br, struct timeval *tv);
+extern int br_set_bridge_max_age(const char *br, struct timeval *tv);
+extern int br_set_ageing_time(const char *br, struct timeval *tv);
+extern int br_set_stp_state(const char *br, int stp_state);
+extern int br_set_bridge_priority(const char *br, int bridge_priority);
+extern int br_set_port_priority(const char *br, const char *p, 
+				int port_priority);
+extern int br_set_path_cost(const char *br, const char *p, 
+			    int path_cost);
+extern int br_read_fdb(const char *br, struct fdb_entry *fdbs, 
+		       unsigned long skip, int num);
+extern int br_set_hairpin_mode(const char *bridge, const char *dev,
+			       int hairpin_mode);
+#endif
diff --git a/libnetwork/libbridge/libbridge_devif.c b/libnetwork/libbridge/libbridge_devif.c
new file mode 100644
index 0000000..9d106f4
--- /dev/null
+++ b/libnetwork/libbridge/libbridge_devif.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/fcntl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+static FILE *fpopen(const char *dir, const char *name)
+{
+	char path[SYSFS_PATH_MAX];
+
+	snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name);
+	return fopen(path, "r");
+}
+
+static void fetch_id(const char *dev, const char *name, struct bridge_id *id)
+{
+	FILE *f = fpopen(dev, name);
+        int unused;
+
+	if (!f)
+		fprintf(stderr, "%s: %s\n", dev, strerror(errno));
+	else {
+		unused = fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+		       &id->prio[0], &id->prio[1],
+		       &id->addr[0], &id->addr[1], &id->addr[2],
+		       &id->addr[3], &id->addr[4], &id->addr[5]);
+		fclose(f);
+	}
+}
+
+/* Fetch an integer attribute out of sysfs. */
+static int fetch_int(const char *dev, const char *name)
+{
+	FILE *f = fpopen(dev, name);
+	int value = -1;
+        int unused;
+
+	if (!f) 
+		return 0;
+
+	unused = fscanf(f, "%i", &value);
+	fclose(f);
+	return value;
+}
+
+/* Get a time value out of sysfs */
+static void fetch_tv(const char *dev, const char *name, 
+		    struct timeval *tv)
+{
+	__jiffies_to_tv(tv, fetch_int(dev, name));
+}
+
+/*
+ * Convert device name to an index in the list of ports in bridge.
+ *
+ * Old API does bridge operations as if ports were an array
+ * inside bridge structure.
+ */
+static int get_portno(const char *brname, const char *ifname)
+{
+	int i;
+	int ifindex = if_nametoindex(ifname);
+	int ifindices[MAX_PORTS];
+	unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+				  (unsigned long)ifindices, MAX_PORTS, 0 };
+	struct ifreq ifr;
+
+	if (ifindex <= 0)
+		goto error;
+
+	memset(ifindices, 0, sizeof(ifindices));
+	strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+	ifr.ifr_data = (char *) &args;
+
+	if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		dprintf("get_portno: get ports of %s failed: %s\n", 
+			brname, strerror(errno));
+		goto error;
+	}
+
+	for (i = 0; i < MAX_PORTS; i++) {
+		if (ifindices[i] == ifindex)
+			return i;
+	}
+
+	dprintf("%s is not a in bridge %s\n", ifname, brname);
+ error:
+	return -1;
+}
+
+/* get information via ioctl */
+static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+	struct ifreq ifr;
+	struct __bridge_info i;
+	unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
+				  (unsigned long) &i, 0, 0 };
+
+	memset(info, 0, sizeof(*info));
+	strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+	ifr.ifr_data = (char *) &args;
+
+	if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		dprintf("%s: can't get info %s\n",
+			bridge, strerror(errno));
+		return errno;
+	}
+
+	memcpy(&info->designated_root, &i.designated_root, 8);
+	memcpy(&info->bridge_id, &i.bridge_id, 8);
+	info->root_path_cost = i.root_path_cost;
+	info->root_port = i.root_port;
+	info->topology_change = i.topology_change;
+	info->topology_change_detected = i.topology_change_detected;
+	info->stp_enabled = i.stp_enabled;
+	__jiffies_to_tv(&info->max_age, i.max_age);
+	__jiffies_to_tv(&info->hello_time, i.hello_time);
+	__jiffies_to_tv(&info->forward_delay, i.forward_delay);
+	__jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age);
+	__jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time);
+	__jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay);
+	__jiffies_to_tv(&info->ageing_time, i.ageing_time);
+	__jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value);
+	__jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value);
+	__jiffies_to_tv(&info->topology_change_timer_value, 
+			i.topology_change_timer_value);
+	__jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value);
+
+	return 0;
+}
+
+/*
+ * Get bridge parameters using either sysfs or old
+ * ioctl.
+ */
+int br_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+	DIR *dir;
+	char path[SYSFS_PATH_MAX];
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
+	dir = opendir(path);
+	if (dir == NULL) {
+		dprintf("path '%s' is not a directory\n", path);
+		goto fallback;
+	}
+
+	memset(info, 0, sizeof(*info));
+	fetch_id(path, "root_id", &info->designated_root);
+	fetch_id(path, "bridge_id", &info->bridge_id);
+	info->root_path_cost = fetch_int(path, "root_path_cost");
+	fetch_tv(path, "max_age", &info->max_age);
+	fetch_tv(path, "hello_time", &info->hello_time);
+	fetch_tv(path, "forward_delay", &info->forward_delay);
+	fetch_tv(path, "max_age", &info->bridge_max_age);
+	fetch_tv(path, "hello_time", &info->bridge_hello_time);
+	fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
+	fetch_tv(path, "ageing_time", &info->ageing_time);
+	fetch_tv(path, "hello_timer", &info->hello_timer_value);
+	fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
+	fetch_tv(path, "topology_change_timer", 
+		 &info->topology_change_timer_value);;
+	fetch_tv(path, "gc_timer", &info->gc_timer_value);
+
+	info->root_port = fetch_int(path, "root_port");
+	info->stp_enabled = fetch_int(path, "stp_state");
+	info->topology_change = fetch_int(path, "topology_change");
+	info->topology_change_detected = fetch_int(path, "topology_change_detected");
+
+	closedir(dir);
+	return 0;
+
+fallback:
+	return old_get_bridge_info(bridge, info);
+}
+
+static int old_get_port_info(const char *brname, const char *port,
+			     struct port_info *info)
+{
+	struct __port_info i;
+	int index;
+
+	memset(info, 0, sizeof(*info));
+
+	index = get_portno(brname, port);
+	if (index < 0)
+		return errno;
+	
+	else {
+		struct ifreq ifr;
+		unsigned long args[4] = { BRCTL_GET_PORT_INFO,
+					   (unsigned long) &i, index, 0 };
+	
+		strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+		ifr.ifr_data = (char *) &args;
+		
+		if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+			dprintf("old can't get port %s(%d) info %s\n",
+				brname, index, strerror(errno));
+			return errno;
+		}
+	}
+
+	info->port_no = index;
+	memcpy(&info->designated_root, &i.designated_root, 8);
+	memcpy(&info->designated_bridge, &i.designated_bridge, 8);
+	info->port_id = i.port_id;
+	info->designated_port = i.designated_port;
+	info->path_cost = i.path_cost;
+	info->designated_cost = i.designated_cost;
+	info->state = i.state;
+	info->top_change_ack = i.top_change_ack;
+	info->config_pending = i.config_pending;
+	__jiffies_to_tv(&info->message_age_timer_value, 
+			i.message_age_timer_value);
+	__jiffies_to_tv(&info->forward_delay_timer_value, 
+			i.forward_delay_timer_value);
+	__jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value);
+	info->hairpin_mode = 0;
+	return 0;
+}
+
+/*
+ * Get information about port on bridge.
+ */
+int br_get_port_info(const char *brname, const char *port, 
+		     struct port_info *info)
+{
+	DIR *d;
+	char path[SYSFS_PATH_MAX];
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port);
+	d = opendir(path);
+	if (!d)
+		goto fallback;
+
+	memset(info, 0, sizeof(*info));
+
+	fetch_id(path, "designated_root", &info->designated_root);
+	fetch_id(path, "designated_bridge", &info->designated_bridge);
+	info->port_no = fetch_int(path, "port_no");
+	info->port_id = fetch_int(path, "port_id");
+	info->designated_port = fetch_int(path, "designated_port");
+	info->path_cost = fetch_int(path, "path_cost");
+	info->designated_cost = fetch_int(path, "designated_cost");
+	info->state = fetch_int(path, "state");
+	info->top_change_ack = fetch_int(path, "change_ack");
+	info->config_pending = fetch_int(path, "config_pending");
+	fetch_tv(path, "message_age_timer", &info->message_age_timer_value);
+	fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value);
+	fetch_tv(path, "hold_timer", &info->hold_timer_value);
+	info->hairpin_mode = fetch_int(path, "hairpin_mode");
+
+	closedir(d);
+
+	return 0;
+fallback:
+	return old_get_port_info(brname, port, info);
+}
+
+
+static int br_set(const char *bridge, const char *name,
+		  unsigned long value, unsigned long oldcode)
+{
+	int ret;
+	char path[SYSFS_PATH_MAX];
+	FILE *f;
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/%s", bridge, name);
+
+	f = fopen(path, "w");
+	if (f) {
+		ret = fprintf(f, "%ld\n", value);
+		fclose(f);
+	} else {
+		/* fallback to old ioctl */
+		struct ifreq ifr;
+		unsigned long args[4] = { oldcode, value, 0, 0 };
+		
+		strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+		ifr.ifr_data = (char *) &args;
+		ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+	}
+
+	return ret < 0 ? errno : 0;
+}
+
+int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
+{
+	return br_set(br, "forward_delay", __tv_to_jiffies(tv),
+		      BRCTL_SET_BRIDGE_FORWARD_DELAY);
+}
+
+int br_set_bridge_hello_time(const char *br, struct timeval *tv)
+{
+	return br_set(br, "hello_time", __tv_to_jiffies(tv),
+		      BRCTL_SET_BRIDGE_HELLO_TIME);
+}
+
+int br_set_bridge_max_age(const char *br, struct timeval *tv)
+{
+	return br_set(br, "max_age", __tv_to_jiffies(tv),
+		      BRCTL_SET_BRIDGE_MAX_AGE);
+}
+
+int br_set_ageing_time(const char *br, struct timeval *tv)
+{
+	return br_set(br, "ageing_time", __tv_to_jiffies(tv),
+		      BRCTL_SET_AGEING_TIME);
+}
+
+int br_set_stp_state(const char *br, int stp_state)
+{
+	return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
+}
+
+int br_set_bridge_priority(const char *br, int bridge_priority)
+{
+	return br_set(br, "priority", bridge_priority, 
+		      BRCTL_SET_BRIDGE_PRIORITY);
+}
+
+static int port_set(const char *bridge, const char *ifname, 
+		    const char *name, unsigned long value, 
+		    unsigned long oldcode)
+{
+	int ret;
+	char path[SYSFS_PATH_MAX];
+	FILE *f;
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name);
+	f = fopen(path, "w");
+	if (f) {
+		ret = fprintf(f, "%ld\n", value);
+		fclose(f);
+	} else {
+		int index = get_portno(bridge, ifname);
+
+		if (index < 0)
+			ret = index;
+		else {
+			struct ifreq ifr;
+			unsigned long args[4] = { oldcode, index, value, 0 };
+			
+			strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+			ifr.ifr_data = (char *) &args;
+			ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+		}
+	}
+
+	return ret < 0 ? errno : 0;
+}
+
+int br_set_port_priority(const char *bridge, const char *port, int priority)
+{
+	return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
+}
+
+int br_set_path_cost(const char *bridge, const char *port, int cost)
+{
+	return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
+}
+
+int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
+{
+	return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
+}
+
+static inline void __copy_fdb(struct fdb_entry *ent, 
+			      const struct __fdb_entry *f)
+{
+	memcpy(ent->mac_addr, f->mac_addr, 6);
+	ent->port_no = f->port_no;
+	ent->is_local = f->is_local;
+	__jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
+}
+
+int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, 
+		unsigned long offset, int num)
+{
+	FILE *f;
+	int i, n;
+	struct __fdb_entry fe[num];
+	char path[SYSFS_PATH_MAX];
+	
+	/* open /sys/class/net/brXXX/brforward */
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge);
+	f = fopen(path, "r");
+	if (f) {
+		fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
+		n = fread(fe, sizeof(struct __fdb_entry), num, f);
+		fclose(f);
+	} else {
+		/* old kernel, use ioctl */
+		unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
+					  (unsigned long) fe,
+					  num, offset };
+		struct ifreq ifr;
+		int retries = 0;
+
+		strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+		ifr.ifr_data = (char *) args;
+
+	retry:
+		n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+
+		/* table can change during ioctl processing */
+		if (n < 0 && errno == EAGAIN && ++retries < 10) {
+			sleep(0);
+			goto retry;
+		}
+	}
+
+	for (i = 0; i < n; i++) 
+		__copy_fdb(fdbs+i, fe+i);
+
+	return n;
+}
diff --git a/libnetwork/libbridge/libbridge_if.c b/libnetwork/libbridge/libbridge_if.c
new file mode 100644
index 0000000..77d3f8a
--- /dev/null
+++ b/libnetwork/libbridge/libbridge_if.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+int br_add_bridge(const char *brname)
+{
+	int ret;
+
+#ifdef SIOCBRADDBR
+	ret = ioctl(br_socket_fd, SIOCBRADDBR, brname);
+	if (ret < 0)
+#endif
+	{
+		char _br[IFNAMSIZ];
+		unsigned long arg[3] 
+			= { BRCTL_ADD_BRIDGE, (unsigned long) _br };
+
+		strncpy(_br, brname, IFNAMSIZ);
+		ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+	} 
+
+	return ret < 0 ? errno : 0;
+}
+
+int br_del_bridge(const char *brname)
+{
+	int ret;
+
+#ifdef SIOCBRDELBR	
+	ret = ioctl(br_socket_fd, SIOCBRDELBR, brname);
+	if (ret < 0)
+#endif
+	{
+		char _br[IFNAMSIZ];
+		unsigned long arg[3] 
+			= { BRCTL_DEL_BRIDGE, (unsigned long) _br };
+
+		strncpy(_br, brname, IFNAMSIZ);
+		ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+	} 
+	return  ret < 0 ? errno : 0;
+}
+
+int br_add_interface(const char *bridge, const char *dev)
+{
+	struct ifreq ifr;
+	int err;
+	int ifindex = if_nametoindex(dev);
+
+	if (ifindex == 0) 
+		return ENODEV;
+	
+	strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRADDIF
+	ifr.ifr_ifindex = ifindex;
+	err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr);
+	if (err < 0)
+#endif
+	{
+		unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
+					  
+		ifr.ifr_data = (char *) args;
+		err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+	}
+
+	return err < 0 ? errno : 0;
+}
+
+int br_del_interface(const char *bridge, const char *dev)
+{
+	struct ifreq ifr;
+	int err;
+	int ifindex = if_nametoindex(dev);
+
+	if (ifindex == 0) 
+		return ENODEV;
+	
+	strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRDELIF
+	ifr.ifr_ifindex = ifindex;
+	err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr);
+	if (err < 0)
+#endif		
+	{
+		unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 };
+					  
+		ifr.ifr_data = (char *) args;
+		err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+	}
+
+	return err < 0 ? errno : 0;
+}
diff --git a/libnetwork/libbridge/libbridge_init.c b/libnetwork/libbridge/libbridge_init.c
new file mode 100644
index 0000000..1c1acbd
--- /dev/null
+++ b/libnetwork/libbridge/libbridge_init.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+int br_socket_fd = -1;
+
+int br_init(void)
+{
+	if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+		return errno;
+	return 0;
+}
+
+void br_shutdown(void)
+{
+	close(br_socket_fd);
+	br_socket_fd = -1;
+}
+
+/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
+static int isbridge(const struct dirent *entry)
+{
+	char path[SYSFS_PATH_MAX];
+	struct stat st;
+
+	if (entry->d_name[0] == '.')
+		return 0;
+	
+	snprintf(path, SYSFS_PATH_MAX, 
+		 SYSFS_CLASS_NET "%s/bridge", entry->d_name);
+	return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+/*
+ * New interface uses sysfs to find bridges
+ */
+static int new_foreach_bridge(int (*iterator)(const char *name, void *),
+			      void *arg)
+{
+	struct dirent **namelist;
+	int i, count = 0;
+
+	count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
+	if (count < 0)
+		return -1;
+
+	for (i = 0; i < count; i++) {
+		if (iterator(namelist[i]->d_name, arg))
+			break;
+	}
+
+	for (i = 0; i < count; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return count;
+}
+
+/*
+ * Old interface uses ioctl
+ */
+static int old_foreach_bridge(int (*iterator)(const char *, void *), 
+			      void *iarg)
+{
+	int i, ret=0, num;
+	char ifname[IFNAMSIZ];
+	int ifindices[MAX_BRIDGES];
+	unsigned long args[3] = { BRCTL_GET_BRIDGES, 
+				 (unsigned long)ifindices, MAX_BRIDGES };
+
+	num = ioctl(br_socket_fd, SIOCGIFBR, args);
+	if (num < 0) {
+		dprintf("Get bridge indices failed: %s\n",
+			strerror(errno));
+		return -errno;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (!if_indextoname(ifindices[i], ifname)) {
+			dprintf("get find name for ifindex %d\n",
+				ifindices[i]);
+			return -errno;
+		}
+
+		++ret;
+		if(iterator(ifname, iarg)) 
+			break;
+		
+	}
+
+	return ret;
+
+}
+
+/*
+ * Go over all bridges and call iterator function.
+ * if iterator returns non-zero then stop.
+ */
+int br_foreach_bridge(int (*iterator)(const char *, void *), 
+		     void *arg)
+{
+	int ret;
+
+	ret = new_foreach_bridge(iterator, arg);
+	if (ret <= 0)
+		ret = old_foreach_bridge(iterator, arg);
+
+	return ret;
+}
+
+/* 
+ * Only used if sysfs is not available.
+ */
+static int old_foreach_port(const char *brname,
+			    int (*iterator)(const char *br, const char *port, 
+					    void *arg),
+			    void *arg)
+{
+	int i, err, count;
+	struct ifreq ifr;
+	char ifname[IFNAMSIZ];
+	int ifindices[MAX_PORTS];
+	unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+				  (unsigned long)ifindices, MAX_PORTS, 0 };
+
+	memset(ifindices, 0, sizeof(ifindices));
+	strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+	ifr.ifr_data = (char *) &args;
+
+	err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+	if (err < 0) {
+		dprintf("list ports for bridge:'%s' failed: %s\n",
+			brname, strerror(errno));
+		return -errno;
+	}
+
+	count = 0;
+	for (i = 0; i < MAX_PORTS; i++) {
+		if (!ifindices[i])
+			continue;
+
+		if (!if_indextoname(ifindices[i], ifname)) {
+			dprintf("can't find name for ifindex:%d\n",
+				ifindices[i]);
+			continue;
+		}
+
+		++count;
+		if (iterator(brname, ifname, arg))
+			break;
+	}
+
+	return count;
+}
+	
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+int br_foreach_port(const char *brname,
+		    int (*iterator)(const char *br, const char *port, void *arg),
+		    void *arg)
+{
+	int i, count;
+	struct dirent **namelist;
+	char path[SYSFS_PATH_MAX];
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
+	count = scandir(path, &namelist, 0, alphasort);
+	if (count < 0)
+		return old_foreach_port(brname, iterator, arg);
+
+	for (i = 0; i < count; i++) {
+		if (namelist[i]->d_name[0] == '.'
+		    && (namelist[i]->d_name[1] == '\0'
+			|| (namelist[i]->d_name[1] == '.'
+			    && namelist[i]->d_name[2] == '\0')))
+			continue;
+
+		if (iterator(brname, namelist[i]->d_name, arg))
+			break;
+	}
+	for (i = 0; i < count; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return count;
+}
diff --git a/libnetwork/libbridge/libbridge_misc.c b/libnetwork/libbridge/libbridge_misc.c
new file mode 100644
index 0000000..3420359
--- /dev/null
+++ b/libnetwork/libbridge/libbridge_misc.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <asm/param.h>
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+static const char *state_names[5] = {
+	[BR_STATE_DISABLED] = "disabled", 
+	[BR_STATE_LISTENING] = "listening", 
+	[BR_STATE_LEARNING] = "learning", 
+	[BR_STATE_FORWARDING] = "forwarding", 
+	[BR_STATE_BLOCKING] = "blocking",
+};
+
+const char *br_get_state_name(int state)
+{
+	if (state >= 0 && state <= 4)
+		return state_names[state];
+
+	return "<INVALID STATE>";
+}
+
+int __br_hz_internal;
+
+int __get_hz(void);
+int __get_hz(void)
+{
+	const char * s = getenv("HZ");
+	return s ? atoi(s) : HZ;
+}
diff --git a/libnetwork/libbridge/libbridge_private.h b/libnetwork/libbridge/libbridge_private.h
new file mode 100644
index 0000000..c5c4ce8
--- /dev/null
+++ b/libnetwork/libbridge/libbridge_private.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_PRIVATE_H
+#define _LIBBRIDGE_PRIVATE_H
+
+//#include "config.h"
+
+#include <linux/sockios.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/if_bridge.h>
+
+#define MAX_BRIDGES	1024
+#define MAX_PORTS	1024
+
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_PATH_MAX	256
+
+#define dprintf(fmt,arg...)
+
+extern int br_socket_fd;
+
+static inline unsigned long __tv_to_jiffies(const struct timeval *tv)
+{
+	unsigned long long jif;
+
+	jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
+
+	return jif/10000;
+}
+
+static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
+{
+	unsigned long long tvusec;
+
+	tvusec = 10000ULL*jiffies;
+	tv->tv_sec = tvusec/1000000;
+	tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
+}
+#endif
diff --git a/libnetwork/libnl3/include/linux/fib_rules.h b/libnetwork/libnl3/include/linux/fib_rules.h
new file mode 100644
index 0000000..ed4504a
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/fib_rules.h
@@ -0,0 +1,69 @@
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+/* rule is permanent, and cannot be deleted */
+#define FIB_RULE_PERMANENT	0x00000001
+#define FIB_RULE_INVERT		0x00000002
+#define FIB_RULE_UNRESOLVED	0x00000004
+#define FIB_RULE_IIF_DETACHED	0x00000008
+#define FIB_RULE_DEV_DETACHED	FIB_RULE_IIF_DETACHED
+#define FIB_RULE_OIF_DETACHED	0x00000010
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR	0x00010000
+
+struct fib_rule_hdr {
+	__u8		family;
+	__u8		dst_len;
+	__u8		src_len;
+	__u8		tos;
+
+	__u8		table;
+	__u8		res1;	/* reserved */
+	__u8		res2;	/* reserved */
+	__u8		action;
+
+	__u32		flags;
+};
+
+enum {
+	FRA_UNSPEC,
+	FRA_DST,	/* destination address */
+	FRA_SRC,	/* source address */
+	FRA_IIFNAME,	/* interface name */
+#define FRA_IFNAME	FRA_IIFNAME
+	FRA_GOTO,	/* target to jump to (FR_ACT_GOTO) */
+	FRA_UNUSED2,
+	FRA_PRIORITY,	/* priority/preference */
+	FRA_UNUSED3,
+	FRA_UNUSED4,
+	FRA_UNUSED5,
+	FRA_FWMARK,	/* mark */
+	FRA_FLOW,	/* flow/class id */
+	FRA_UNUSED6,
+	FRA_UNUSED7,
+	FRA_UNUSED8,
+	FRA_TABLE,	/* Extended table id */
+	FRA_FWMASK,	/* mask for netfilter mark */
+	FRA_OIFNAME,
+	__FRA_MAX
+};
+
+#define FRA_MAX (__FRA_MAX - 1)
+
+enum {
+	FR_ACT_UNSPEC,
+	FR_ACT_TO_TBL,		/* Pass to fixed table */
+	FR_ACT_GOTO,		/* Jump to another rule */
+	FR_ACT_NOP,		/* No operation */
+	FR_ACT_RES3,
+	FR_ACT_RES4,
+	FR_ACT_BLACKHOLE,	/* Drop without notification */
+	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+	FR_ACT_PROHIBIT,	/* Drop with EACCES */
+	__FR_ACT_MAX,
+};
+
+#define FR_ACT_MAX (__FR_ACT_MAX - 1)
+
+#endif
diff --git a/libnetwork/libnl3/include/linux/gen_stats.h b/libnetwork/libnl3/include/linux/gen_stats.h
new file mode 100644
index 0000000..552c8a0
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/gen_stats.h
@@ -0,0 +1,67 @@
+#ifndef __LINUX_GEN_STATS_H
+#define __LINUX_GEN_STATS_H
+
+#include <linux/types.h>
+
+enum {
+	TCA_STATS_UNSPEC,
+	TCA_STATS_BASIC,
+	TCA_STATS_RATE_EST,
+	TCA_STATS_QUEUE,
+	TCA_STATS_APP,
+	__TCA_STATS_MAX,
+};
+#define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
+
+/**
+ * struct gnet_stats_basic - byte/packet throughput statistics
+ * @bytes: number of seen bytes
+ * @packets: number of seen packets
+ */
+struct gnet_stats_basic {
+	__u64	bytes;
+	__u32	packets;
+};
+struct gnet_stats_basic_packed {
+	__u64	bytes;
+	__u32	packets;
+} __attribute__ ((packed));
+
+/**
+ * struct gnet_stats_rate_est - rate estimator
+ * @bps: current byte rate
+ * @pps: current packet rate
+ */
+struct gnet_stats_rate_est {
+	__u32	bps;
+	__u32	pps;
+};
+
+/**
+ * struct gnet_stats_queue - queuing statistics
+ * @qlen: queue length
+ * @backlog: backlog size of queue
+ * @drops: number of dropped packets
+ * @requeues: number of requeues
+ * @overlimits: number of enqueues over the limit
+ */
+struct gnet_stats_queue {
+	__u32	qlen;
+	__u32	backlog;
+	__u32	drops;
+	__u32	requeues;
+	__u32	overlimits;
+};
+
+/**
+ * struct gnet_estimator - rate estimator configuration
+ * @interval: sampling period
+ * @ewma_log: the log of measurement window weight
+ */
+struct gnet_estimator {
+	signed char	interval;
+	unsigned char	ewma_log;
+};
+
+
+#endif /* __LINUX_GEN_STATS_H */
diff --git a/libnetwork/libnl3/include/linux/genetlink.h b/libnetwork/libnl3/include/linux/genetlink.h
new file mode 100644
index 0000000..b834ef6
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/genetlink.h
@@ -0,0 +1,83 @@
+#ifndef __LINUX_GENERIC_NETLINK_H
+#define __LINUX_GENERIC_NETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+#define GENL_NAMSIZ	16	/* length of family name */
+
+#define GENL_MIN_ID	NLMSG_MIN_TYPE
+#define GENL_MAX_ID	1023
+
+struct genlmsghdr {
+	__u8	cmd;
+	__u8	version;
+	__u16	reserved;
+};
+
+#define GENL_HDRLEN	NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
+#define GENL_ADMIN_PERM		0x01
+#define GENL_CMD_CAP_DO		0x02
+#define GENL_CMD_CAP_DUMP	0x04
+#define GENL_CMD_CAP_HASPOL	0x08
+
+/*
+ * List of reserved static generic netlink identifiers:
+ */
+#define GENL_ID_GENERATE	0
+#define GENL_ID_CTRL		NLMSG_MIN_TYPE
+
+/**************************************************************************
+ * Controller
+ **************************************************************************/
+
+enum {
+	CTRL_CMD_UNSPEC,
+	CTRL_CMD_NEWFAMILY,
+	CTRL_CMD_DELFAMILY,
+	CTRL_CMD_GETFAMILY,
+	CTRL_CMD_NEWOPS,
+	CTRL_CMD_DELOPS,
+	CTRL_CMD_GETOPS,
+	CTRL_CMD_NEWMCAST_GRP,
+	CTRL_CMD_DELMCAST_GRP,
+	CTRL_CMD_GETMCAST_GRP, /* unused */
+	__CTRL_CMD_MAX,
+};
+
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+	CTRL_ATTR_UNSPEC,
+	CTRL_ATTR_FAMILY_ID,
+	CTRL_ATTR_FAMILY_NAME,
+	CTRL_ATTR_VERSION,
+	CTRL_ATTR_HDRSIZE,
+	CTRL_ATTR_MAXATTR,
+	CTRL_ATTR_OPS,
+	CTRL_ATTR_MCAST_GROUPS,
+	__CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+enum {
+	CTRL_ATTR_OP_UNSPEC,
+	CTRL_ATTR_OP_ID,
+	CTRL_ATTR_OP_FLAGS,
+	__CTRL_ATTR_OP_MAX,
+};
+
+#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
+
+enum {
+	CTRL_ATTR_MCAST_GRP_UNSPEC,
+	CTRL_ATTR_MCAST_GRP_NAME,
+	CTRL_ATTR_MCAST_GRP_ID,
+	__CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
+#endif	/* __LINUX_GENERIC_NETLINK_H */
diff --git a/libnetwork/libnl3/include/linux/if.h b/libnetwork/libnl3/include/linux/if.h
new file mode 100644
index 0000000..32f910f
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if.h
@@ -0,0 +1,140 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Global definitions for the INET interface module.
+ *
+ * Version:	@(#)if.h	1.0.2	04/18/93
+ *
+ * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ *		Ross Biro
+ *		Fred N. van Kempen, <waltje at uWalt.NL.Mugnet.ORG>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#define	IFNAMSIZ	16
+#define	IFALIASZ	256
+
+/* Standard interface flags (netdevice->flags). */
+#define	IFF_UP		0x1		/* interface is up		*/
+#define	IFF_BROADCAST	0x2		/* broadcast address valid	*/
+#define	IFF_DEBUG	0x4		/* turn on debugging		*/
+#define	IFF_LOOPBACK	0x8		/* is a loopback net		*/
+#define	IFF_POINTOPOINT	0x10		/* interface is has p-p link	*/
+#define	IFF_NOTRAILERS	0x20		/* avoid use of trailers	*/
+#define	IFF_RUNNING	0x40		/* interface RFC2863 OPER_UP	*/
+#define	IFF_NOARP	0x80		/* no ARP protocol		*/
+#define	IFF_PROMISC	0x100		/* receive all packets		*/
+#define	IFF_ALLMULTI	0x200		/* receive all multicast packets*/
+
+#define IFF_MASTER	0x400		/* master of a load balancer 	*/
+#define IFF_SLAVE	0x800		/* slave of a load balancer	*/
+
+#define IFF_MULTICAST	0x1000		/* Supports multicast		*/
+
+#define IFF_PORTSEL	0x2000          /* can set media type		*/
+#define IFF_AUTOMEDIA	0x4000		/* auto media select active	*/
+#define IFF_DYNAMIC	0x8000		/* dialup device with changing addresses*/
+
+#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
+#define IFF_DORMANT	0x20000		/* driver signals dormant	*/
+
+#define IFF_ECHO	0x40000		/* echo sent packets		*/
+
+#define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
+/* Private (from user) interface flags (netdevice->priv_flags). */
+#define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
+#define IFF_EBRIDGE	0x2		/* Ethernet bridging device.	*/
+#define IFF_SLAVE_INACTIVE	0x4	/* bonding slave not the curr. active */
+#define IFF_MASTER_8023AD	0x8	/* bonding master, 802.3ad. 	*/
+#define IFF_MASTER_ALB	0x10		/* bonding master, balance-alb.	*/
+#define IFF_BONDING	0x20		/* bonding master or slave	*/
+#define IFF_SLAVE_NEEDARP 0x40		/* need ARPs for validation	*/
+#define IFF_ISATAP	0x80		/* ISATAP interface (RFC4214)	*/
+#define IFF_MASTER_ARPMON 0x100		/* bonding master, ARP mon in use */
+#define IFF_WAN_HDLC	0x200		/* WAN HDLC device		*/
+#define IFF_XMIT_DST_RELEASE 0x400	/* dev_hard_start_xmit() is allowed to
+					 * release skb->dst
+					 */
+#define IFF_DONT_BRIDGE 0x800		/* disallow bridging this ether dev */
+#define IFF_IN_NETPOLL	0x1000		/* whether we are processing netpoll */
+#define IFF_DISABLE_NETPOLL	0x2000	/* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT	0x4000	/* device used as macvlan port */
+#define IFF_BRIDGE_PORT	0x8000		/* device used as bridge port */
+#define IFF_OVS_DATAPATH	0x10000	/* device used as Open vSwitch
+					 * datapath port */
+
+#define IF_GET_IFACE	0x0001		/* for querying only */
+#define IF_GET_PROTO	0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35	0x1000		/* V.35 serial interface	*/
+#define IF_IFACE_V24	0x1001		/* V.24 serial interface	*/
+#define IF_IFACE_X21	0x1002		/* X.21 serial interface	*/
+#define IF_IFACE_T1	0x1003		/* T1 telco serial interface	*/
+#define IF_IFACE_E1	0x1004		/* E1 telco serial interface	*/
+#define IF_IFACE_SYNC_SERIAL 0x1005	/* can't be set by software	*/
+#define IF_IFACE_X21D   0x1006          /* X.21 Dual Clocking (FarSite) */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC	0x2000		/* raw HDLC protocol		*/
+#define IF_PROTO_PPP	0x2001		/* PPP protocol			*/
+#define IF_PROTO_CISCO	0x2002		/* Cisco HDLC protocol		*/
+#define IF_PROTO_FR	0x2003		/* Frame Relay protocol		*/
+#define IF_PROTO_FR_ADD_PVC 0x2004	/*    Create FR PVC		*/
+#define IF_PROTO_FR_DEL_PVC 0x2005	/*    Delete FR PVC		*/
+#define IF_PROTO_X25	0x2006		/* X.25				*/
+#define IF_PROTO_HDLC_ETH 0x2007	/* raw HDLC, Ethernet emulation	*/
+#define IF_PROTO_FR_ADD_ETH_PVC 0x2008	/*  Create FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_DEL_ETH_PVC 0x2009	/*  Delete FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_PVC	0x200A		/* for reading PVC status	*/
+#define IF_PROTO_FR_ETH_PVC 0x200B
+#define IF_PROTO_RAW    0x200C          /* RAW Socket                   */
+
+/* RFC 2863 operational status */
+enum {
+	IF_OPER_UNKNOWN,
+	IF_OPER_NOTPRESENT,
+	IF_OPER_DOWN,
+	IF_OPER_LOWERLAYERDOWN,
+	IF_OPER_TESTING,
+	IF_OPER_DORMANT,
+	IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+	IF_LINK_MODE_DEFAULT,
+	IF_LINK_MODE_DORMANT,	/* limit upward transition to dormant */
+};
+
+/*
+ *	Device mapping structure. I'd just gone off and designed a 
+ *	beautiful scheme using only loadable modules with arguments
+ *	for driver options and along come the PCMCIA people 8)
+ *
+ *	Ah well. The get() side of this is good for WDSETUP, and it'll
+ *	be handy for debugging things. The set side is fine for now and
+ *	being very small might be worth keeping for clean configuration.
+ */
+
+struct ifmap {
+	unsigned long mem_start;
+	unsigned long mem_end;
+	unsigned short base_addr; 
+	unsigned char irq;
+	unsigned char dma;
+	unsigned char port;
+	/* 3 bytes spare */
+};
+
+#endif /* _LINUX_IF_H */
diff --git a/libnetwork/libnl3/include/linux/if_addr.h b/libnetwork/libnl3/include/linux/if_addr.h
new file mode 100644
index 0000000..c355522
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if_addr.h
@@ -0,0 +1,55 @@
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg {
+	__u8		ifa_family;
+	__u8		ifa_prefixlen;	/* The prefix length		*/
+	__u8		ifa_flags;	/* Flags			*/
+	__u8		ifa_scope;	/* Address scope		*/
+	__u32		ifa_index;	/* Link index			*/
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ */
+enum {
+	IFA_UNSPEC,
+	IFA_ADDRESS,
+	IFA_LOCAL,
+	IFA_LABEL,
+	IFA_BROADCAST,
+	IFA_ANYCAST,
+	IFA_CACHEINFO,
+	IFA_MULTICAST,
+	__IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY		0x01
+#define IFA_F_TEMPORARY		IFA_F_SECONDARY
+
+#define	IFA_F_NODAD		0x02
+#define IFA_F_OPTIMISTIC	0x04
+#define IFA_F_DADFAILED		0x08
+#define	IFA_F_HOMEADDRESS	0x10
+#define IFA_F_DEPRECATED	0x20
+#define IFA_F_TENTATIVE		0x40
+#define IFA_F_PERMANENT		0x80
+
+struct ifa_cacheinfo {
+	__u32	ifa_prefered;
+	__u32	ifa_valid;
+	__u32	cstamp; /* created timestamp, hundredths of seconds */
+	__u32	tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/linux/if_arp.h b/libnetwork/libnl3/include/linux/if_arp.h
new file mode 100644
index 0000000..e04cd2c
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if_arp.h
@@ -0,0 +1,156 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Global definitions for the ARP (RFC 826) protocol.
+ *
+ * Version:	@(#)if_arp.h	1.0.1	04/16/93
+ *
+ * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ *		Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
+ *		Ross Biro
+ *		Fred N. van Kempen, <waltje at uWalt.NL.Mugnet.ORG>
+ *		Florian La Roche,
+ *		Jonathan Layes <layes at loran.com>
+ *		Arnaldo Carvalho de Melo <acme at conectiva.com.br> ARPHRD_HWX25
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_ARP_H
+#define _LINUX_IF_ARP_H
+
+#include <linux/netdevice.h>
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/
+#define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/
+#define	ARPHRD_EETHER	2		/* Experimental Ethernet	*/
+#define	ARPHRD_AX25	3		/* AX.25 Level 2		*/
+#define	ARPHRD_PRONET	4		/* PROnet token ring		*/
+#define	ARPHRD_CHAOS	5		/* Chaosnet			*/
+#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
+#define	ARPHRD_ARCNET	7		/* ARCnet			*/
+#define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/
+#define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/
+#define ARPHRD_ATM	19		/* ATM 				*/
+#define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
+#define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
+#define ARPHRD_EUI64	27		/* EUI-64                       */
+#define ARPHRD_INFINIBAND 32		/* InfiniBand			*/
+
+/* Dummy types for non ARP hardware */
+#define ARPHRD_SLIP	256
+#define ARPHRD_CSLIP	257
+#define ARPHRD_SLIP6	258
+#define ARPHRD_CSLIP6	259
+#define ARPHRD_RSRVD	260		/* Notional KISS type 		*/
+#define ARPHRD_ADAPT	264
+#define ARPHRD_ROSE	270
+#define ARPHRD_X25	271		/* CCITT X.25			*/
+#define ARPHRD_HWX25	272		/* Boards with X.25 in firmware	*/
+#define ARPHRD_CAN	280		/* Controller Area Network      */
+#define ARPHRD_PPP	512
+#define ARPHRD_CISCO	513		/* Cisco HDLC	 		*/
+#define ARPHRD_HDLC	ARPHRD_CISCO
+#define ARPHRD_LAPB	516		/* LAPB				*/
+#define ARPHRD_DDCMP    517		/* Digital's DDCMP protocol     */
+#define ARPHRD_RAWHDLC	518		/* Raw HDLC			*/
+
+#define ARPHRD_TUNNEL	768		/* IPIP tunnel			*/
+#define ARPHRD_TUNNEL6	769		/* IP6IP6 tunnel       		*/
+#define ARPHRD_FRAD	770             /* Frame Relay Access Device    */
+#define ARPHRD_SKIP	771		/* SKIP vif			*/
+#define ARPHRD_LOOPBACK	772		/* Loopback device		*/
+#define ARPHRD_LOCALTLK 773		/* Localtalk device		*/
+#define ARPHRD_FDDI	774		/* Fiber Distributed Data Interface */
+#define ARPHRD_BIF      775             /* AP1000 BIF                   */
+#define ARPHRD_SIT	776		/* sit0 device - IPv6-in-IPv4	*/
+#define ARPHRD_IPDDP	777		/* IP over DDP tunneller	*/
+#define ARPHRD_IPGRE	778		/* GRE over IP			*/
+#define ARPHRD_PIMREG	779		/* PIMSM register interface	*/
+#define ARPHRD_HIPPI	780		/* High Performance Parallel Interface */
+#define ARPHRD_ASH	781		/* Nexus 64Mbps Ash		*/
+#define ARPHRD_ECONET	782		/* Acorn Econet			*/
+#define ARPHRD_IRDA 	783		/* Linux-IrDA			*/
+/* ARP works differently on different FC media .. so  */
+#define ARPHRD_FCPP	784		/* Point to point fibrechannel	*/
+#define ARPHRD_FCAL	785		/* Fibrechannel arbitrated loop */
+#define ARPHRD_FCPL	786		/* Fibrechannel public loop	*/
+#define ARPHRD_FCFABRIC	787		/* Fibrechannel fabric		*/
+	/* 787->799 reserved for fibrechannel media types */
+#define ARPHRD_IEEE802_TR 800		/* Magic type ident for TR	*/
+#define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/
+#define ARPHRD_IEEE80211_PRISM 802	/* IEEE 802.11 + Prism2 header  */
+#define ARPHRD_IEEE80211_RADIOTAP 803	/* IEEE 802.11 + radiotap header */
+#define ARPHRD_IEEE802154	  804
+
+#define ARPHRD_PHONET	820		/* PhoNet media type		*/
+#define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
+#define ARPHRD_CAIF	822		/* CAIF media type		*/
+
+#define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
+#define ARPHRD_NONE	  0xFFFE	/* zero header length */
+
+/* ARP protocol opcodes. */
+#define	ARPOP_REQUEST	1		/* ARP request			*/
+#define	ARPOP_REPLY	2		/* ARP reply			*/
+#define	ARPOP_RREQUEST	3		/* RARP request			*/
+#define	ARPOP_RREPLY	4		/* RARP reply			*/
+#define	ARPOP_InREQUEST	8		/* InARP request		*/
+#define	ARPOP_InREPLY	9		/* InARP reply			*/
+#define	ARPOP_NAK	10		/* (ATM)ARP NAK			*/
+
+
+/* ARP ioctl request. */
+struct arpreq {
+  struct sockaddr	arp_pa;		/* protocol address		*/
+  struct sockaddr	arp_ha;		/* hardware address		*/
+  int			arp_flags;	/* flags			*/
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+  char			arp_dev[16];
+};
+
+struct arpreq_old {
+  struct sockaddr	arp_pa;		/* protocol address		*/
+  struct sockaddr	arp_ha;		/* hardware address		*/
+  int			arp_flags;	/* flags			*/
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+};
+
+/* ARP Flag values. */
+#define ATF_COM		0x02		/* completed entry (ha valid)	*/
+#define	ATF_PERM	0x04		/* permanent entry		*/
+#define	ATF_PUBL	0x08		/* publish entry		*/
+#define	ATF_USETRAILERS	0x10		/* has requested trailers	*/
+#define ATF_NETMASK     0x20            /* want to use a netmask (only
+					   for proxy entries) */
+#define ATF_DONTPUB	0x40		/* don't answer this addresses	*/
+
+/*
+ *	This structure defines an ethernet arp header.
+ */
+
+struct arphdr {
+	__be16		ar_hrd;		/* format of hardware address	*/
+	__be16		ar_pro;		/* format of protocol address	*/
+	unsigned char	ar_hln;		/* length of hardware address	*/
+	unsigned char	ar_pln;		/* length of protocol address	*/
+	__be16		ar_op;		/* ARP opcode (command)		*/
+
+#if 0
+	 /*
+	  *	 Ethernet looks like this : This bit is variable sized however...
+	  */
+	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
+	unsigned char		ar_sip[4];		/* sender IP address		*/
+	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
+	unsigned char		ar_tip[4];		/* target IP address		*/
+#endif
+
+};
+
+#endif	/* _LINUX_IF_ARP_H */
diff --git a/libnetwork/libnl3/include/linux/if_ether.h b/libnetwork/libnl3/include/linux/if_ether.h
new file mode 100644
index 0000000..a6af32d
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if_ether.h
@@ -0,0 +1,125 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version:	@(#)if_ether.h	1.0.1a	02/08/94
+ *
+ * Author:	Fred N. van Kempen, <waltje at uWalt.NL.Mugnet.ORG>
+ *		Donald Becker, <becker at super.org>
+ *		Alan Cox, <alan at lxorguk.ukuu.org.uk>
+ *		Steve Whitehouse, <gw7rrm at eeshack3.swan.ac.uk>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+#include <linux/types.h>
+
+/*
+ *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+ *	and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#define ETH_HLEN	14		/* Total octets in header.	 */
+#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
+#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN	4		/* Octets in the FCS		 */
+
+/*
+ *	These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
+#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
+#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_X25	0x0805		/* CCITT X.25			*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet	[ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_TEB	0x6558		/* Trans Ether Bridging		*/
+#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
+#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
+#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
+#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
+#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
+#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+#define ETH_P_PAUSE	0x8808		/* IEEE Pause frames. See 802.3 31B */
+#define ETH_P_SLOW	0x8809		/* Slow Protocol. See 802.3ad 43B */
+#define ETH_P_WCCP	0x883E		/* Web-cache coordination protocol
+					 * defined in draft-wilson-wrec-wccp-v2-00.txt */
+#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
+#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic		*/
+#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic	*/
+#define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
+#define ETH_P_LINK_CTL	0x886c		/* HPNA, wlan link local tunnel */
+#define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
+					 * over Ethernet
+					 */
+#define ETH_P_PAE	0x888E		/* Port Access Entity (IEEE 802.1X) */
+#define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
+#define ETH_P_TIPC	0x88CA		/* TIPC 			*/
+#define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
+#define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
+#define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
+#define ETH_P_EDSA	0xDADA		/* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+
+/*
+ *	Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
+#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
+#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
+#define ETH_P_802_2	0x0004		/* 802.2 frames 		*/
+#define ETH_P_SNAP	0x0005		/* Internal only		*/
+#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
+#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
+#define ETH_P_CAN	0x000C		/* Controller Area Network      */
+#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
+#define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz at cafe.net)	*/
+#define ETH_P_CONTROL	0x0016		/* Card specific control frames */
+#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
+#define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
+#define ETH_P_HDLC	0x0019		/* HDLC frames			*/
+#define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
+#define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
+#define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
+#define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
+#define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
+#define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
+
+/*
+ *	This is an Ethernet frame header.
+ */
+
+struct ethhdr {
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	__be16		h_proto;		/* packet type ID field	*/
+} __attribute__((packed));
+
+#endif	/* _LINUX_IF_ETHER_H */
diff --git a/libnetwork/libnl3/include/linux/if_link.h b/libnetwork/libnl3/include/linux/if_link.h
new file mode 100644
index 0000000..8a27d5a
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if_link.h
@@ -0,0 +1,377 @@
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+/* This struct should be in sync with struct rtnl_link_stats64 */
+struct rtnl_link_stats {
+	__u32	rx_packets;		/* total packets received	*/
+	__u32	tx_packets;		/* total packets transmitted	*/
+	__u32	rx_bytes;		/* total bytes received 	*/
+	__u32	tx_bytes;		/* total bytes transmitted	*/
+	__u32	rx_errors;		/* bad packets received		*/
+	__u32	tx_errors;		/* packet transmit problems	*/
+	__u32	rx_dropped;		/* no space in linux buffers	*/
+	__u32	tx_dropped;		/* no space available in linux	*/
+	__u32	multicast;		/* multicast packets received	*/
+	__u32	collisions;
+
+	/* detailed rx_errors: */
+	__u32	rx_length_errors;
+	__u32	rx_over_errors;		/* receiver ring buff overflow	*/
+	__u32	rx_crc_errors;		/* recved pkt with crc error	*/
+	__u32	rx_frame_errors;	/* recv'd frame alignment error */
+	__u32	rx_fifo_errors;		/* recv'r fifo overrun		*/
+	__u32	rx_missed_errors;	/* receiver missed packet	*/
+
+	/* detailed tx_errors */
+	__u32	tx_aborted_errors;
+	__u32	tx_carrier_errors;
+	__u32	tx_fifo_errors;
+	__u32	tx_heartbeat_errors;
+	__u32	tx_window_errors;
+
+	/* for cslip etc */
+	__u32	rx_compressed;
+	__u32	tx_compressed;
+};
+
+/* The main device statistics structure */
+struct rtnl_link_stats64 {
+	__u64	rx_packets;		/* total packets received	*/
+	__u64	tx_packets;		/* total packets transmitted	*/
+	__u64	rx_bytes;		/* total bytes received 	*/
+	__u64	tx_bytes;		/* total bytes transmitted	*/
+	__u64	rx_errors;		/* bad packets received		*/
+	__u64	tx_errors;		/* packet transmit problems	*/
+	__u64	rx_dropped;		/* no space in linux buffers	*/
+	__u64	tx_dropped;		/* no space available in linux	*/
+	__u64	multicast;		/* multicast packets received	*/
+	__u64	collisions;
+
+	/* detailed rx_errors: */
+	__u64	rx_length_errors;
+	__u64	rx_over_errors;		/* receiver ring buff overflow	*/
+	__u64	rx_crc_errors;		/* recved pkt with crc error	*/
+	__u64	rx_frame_errors;	/* recv'd frame alignment error */
+	__u64	rx_fifo_errors;		/* recv'r fifo overrun		*/
+	__u64	rx_missed_errors;	/* receiver missed packet	*/
+
+	/* detailed tx_errors */
+	__u64	tx_aborted_errors;
+	__u64	tx_carrier_errors;
+	__u64	tx_fifo_errors;
+	__u64	tx_heartbeat_errors;
+	__u64	tx_window_errors;
+
+	/* for cslip etc */
+	__u64	rx_compressed;
+	__u64	tx_compressed;
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap {
+	__u64	mem_start;
+	__u64	mem_end;
+	__u64	base_addr;
+	__u16	irq;
+	__u8	dma;
+	__u8	port;
+};
+
+/*
+ * IFLA_AF_SPEC
+ *   Contains nested attributes for address family specific attributes.
+ *   Each address family may create a attribute with the address family
+ *   number as type and create its own attribute structure in it.
+ *
+ *   Example:
+ *   [IFLA_AF_SPEC] = {
+ *       [AF_INET] = {
+ *           [IFLA_INET_CONF] = ...,
+ *       },
+ *       [AF_INET6] = {
+ *           [IFLA_INET6_FLAGS] = ...,
+ *           [IFLA_INET6_CONF] = ...,
+ *       }
+ *   }
+ */
+
+enum {
+	IFLA_UNSPEC,
+	IFLA_ADDRESS,
+	IFLA_BROADCAST,
+	IFLA_IFNAME,
+	IFLA_MTU,
+	IFLA_LINK,
+	IFLA_QDISC,
+	IFLA_STATS,
+	IFLA_COST,
+#define IFLA_COST IFLA_COST
+	IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+	IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+	IFLA_PROTINFO,		/* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+	IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+	IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+	IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+	IFLA_OPERSTATE,
+	IFLA_LINKMODE,
+	IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+	IFLA_NET_NS_PID,
+	IFLA_IFALIAS,
+	IFLA_NUM_VF,		/* Number of VFs if device is SR-IOV PF */
+	IFLA_VFINFO_LIST,
+	IFLA_STATS64,
+	IFLA_VF_PORTS,
+	IFLA_PORT_SELF,
+	IFLA_AF_SPEC,
+	IFLA_GROUP,		/* Group the device belongs to */
+	IFLA_NET_NS_FD,
+	__IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+enum {
+	IFLA_INET_UNSPEC,
+	IFLA_INET_CONF,
+	__IFLA_INET_MAX,
+};
+
+#define IFLA_INET_MAX (__IFLA_INET_MAX - 1)
+
+/* ifi_flags.
+
+   IFF_* flags.
+
+   The only change is:
+   IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+   more not changeable by user. They describe link media
+   characteristics and set by device driver.
+
+   Comments:
+   - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+   - If neither of these three flags are set;
+     the interface is NBMA.
+
+   - IFF_MULTICAST does not mean anything special:
+   multicasts can be used on all not-NBMA links.
+   IFF_MULTICAST means that this media uses special encapsulation
+   for multicast frames. Apparently, all IFF_POINTOPOINT and
+   IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+   For usual devices it is equal ifi_index.
+   If it is a "virtual interface" (f.e. tunnel), ifi_link
+   can point to real physical interface (f.e. for bandwidth calculations),
+   or maybe 0, what means, that real media is unknown (usual
+   for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum {
+	IFLA_INET6_UNSPEC,
+	IFLA_INET6_FLAGS,	/* link flags			*/
+	IFLA_INET6_CONF,	/* sysctl parameters		*/
+	IFLA_INET6_STATS,	/* statistics			*/
+	IFLA_INET6_MCAST,	/* MC things. What of them?	*/
+	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
+	IFLA_INET6_ICMP6STATS,	/* statistics (icmpv6)		*/
+	__IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX	(__IFLA_INET6_MAX - 1)
+
+struct ifla_cacheinfo {
+	__u32	max_reasm_len;
+	__u32	tstamp;		/* ipv6InterfaceTable updated timestamp */
+	__u32	reachable_time;
+	__u32	retrans_time;
+};
+
+enum {
+	IFLA_INFO_UNSPEC,
+	IFLA_INFO_KIND,
+	IFLA_INFO_DATA,
+	IFLA_INFO_XSTATS,
+	__IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX	(__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum {
+	IFLA_VLAN_UNSPEC,
+	IFLA_VLAN_ID,
+	IFLA_VLAN_FLAGS,
+	IFLA_VLAN_EGRESS_QOS,
+	IFLA_VLAN_INGRESS_QOS,
+	__IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX	(__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+	__u32	flags;
+	__u32	mask;
+};
+
+enum {
+	IFLA_VLAN_QOS_UNSPEC,
+	IFLA_VLAN_QOS_MAPPING,
+	__IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX	(__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping {
+	__u32 from;
+	__u32 to;
+};
+
+/* MACVLAN section */
+enum {
+	IFLA_MACVLAN_UNSPEC,
+	IFLA_MACVLAN_MODE,
+	__IFLA_MACVLAN_MAX,
+};
+
+#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
+
+enum macvlan_mode {
+	MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
+	MACVLAN_MODE_VEPA    = 2, /* talk to other ports through ext bridge */
+	MACVLAN_MODE_BRIDGE  = 4, /* talk to bridge ports directly */
+	MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
+};
+
+/* SR-IOV virtual function management section */
+
+enum {
+	IFLA_VF_INFO_UNSPEC,
+	IFLA_VF_INFO,
+	__IFLA_VF_INFO_MAX,
+};
+
+#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1)
+
+enum {
+	IFLA_VF_UNSPEC,
+	IFLA_VF_MAC,		/* Hardware queue specific attributes */
+	IFLA_VF_VLAN,
+	IFLA_VF_TX_RATE,	/* TX Bandwidth Allocation */
+	__IFLA_VF_MAX,
+};
+
+#define IFLA_VF_MAX (__IFLA_VF_MAX - 1)
+
+struct ifla_vf_mac {
+	__u32 vf;
+	__u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_vlan {
+	__u32 vf;
+	__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+	__u32 qos;
+};
+
+struct ifla_vf_tx_rate {
+	__u32 vf;
+	__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_info {
+	__u32 vf;
+	__u8 mac[32];
+	__u32 vlan;
+	__u32 qos;
+	__u32 tx_rate;
+};
+
+/* VF ports management section
+ *
+ *	Nested layout of set/get msg is:
+ *
+ *		[IFLA_NUM_VF]
+ *		[IFLA_VF_PORTS]
+ *			[IFLA_VF_PORT]
+ *				[IFLA_PORT_*], ...
+ *			[IFLA_VF_PORT]
+ *				[IFLA_PORT_*], ...
+ *			...
+ *		[IFLA_PORT_SELF]
+ *			[IFLA_PORT_*], ...
+ */
+
+enum {
+	IFLA_VF_PORT_UNSPEC,
+	IFLA_VF_PORT,			/* nest */
+	__IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+	IFLA_PORT_UNSPEC,
+	IFLA_PORT_VF,			/* __u32 */
+	IFLA_PORT_PROFILE,		/* string */
+	IFLA_PORT_VSI_TYPE,		/* 802.1Qbg (pre-)standard VDP */
+	IFLA_PORT_INSTANCE_UUID,	/* binary UUID */
+	IFLA_PORT_HOST_UUID,		/* binary UUID */
+	IFLA_PORT_REQUEST,		/* __u8 */
+	IFLA_PORT_RESPONSE,		/* __u16, output only */
+	__IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX	40
+#define PORT_UUID_MAX		16
+#define PORT_SELF_VF		-1
+
+enum {
+	PORT_REQUEST_PREASSOCIATE = 0,
+	PORT_REQUEST_PREASSOCIATE_RR,
+	PORT_REQUEST_ASSOCIATE,
+	PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+	PORT_VDP_RESPONSE_SUCCESS = 0,
+	PORT_VDP_RESPONSE_INVALID_FORMAT,
+	PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+	PORT_VDP_RESPONSE_UNUSED_VTID,
+	PORT_VDP_RESPONSE_VTID_VIOLATION,
+	PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+	PORT_VDP_RESPONSE_OUT_OF_SYNC,
+	/* 0x08-0xFF reserved for future VDP use */
+	PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+	PORT_PROFILE_RESPONSE_INPROGRESS,
+	PORT_PROFILE_RESPONSE_INVALID,
+	PORT_PROFILE_RESPONSE_BADSTATE,
+	PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+	PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+	__u8 vsi_mgr_id;
+	__u8 vsi_type_id[3];
+	__u8 vsi_type_version;
+	__u8 pad[3];
+};
+
+#endif /* _LINUX_IF_LINK_H */
diff --git a/libnetwork/libnl3/include/linux/if_vlan.h b/libnetwork/libnl3/include/linux/if_vlan.h
new file mode 100644
index 0000000..67affd1
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/if_vlan.h
@@ -0,0 +1,62 @@
+/*
+ * VLAN		An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:	Ben Greear <greearb at candelatech.com>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+/* VLAN IOCTLs are found in sockios.h */
+
+/* Passed in vlan_ioctl_args structure to determine behaviour. */
+enum vlan_ioctl_cmds {
+	ADD_VLAN_CMD,
+	DEL_VLAN_CMD,
+	SET_VLAN_INGRESS_PRIORITY_CMD,
+	SET_VLAN_EGRESS_PRIORITY_CMD,
+	GET_VLAN_INGRESS_PRIORITY_CMD,
+	GET_VLAN_EGRESS_PRIORITY_CMD,
+	SET_VLAN_NAME_TYPE_CMD,
+	SET_VLAN_FLAG_CMD,
+	GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+	GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
+};
+
+enum vlan_flags {
+	VLAN_FLAG_REORDER_HDR	= 0x1,
+	VLAN_FLAG_GVRP		= 0x2,
+	VLAN_FLAG_LOOSE_BINDING	= 0x4,
+};
+
+enum vlan_name_types {
+	VLAN_NAME_TYPE_PLUS_VID, /* Name will look like:  vlan0005 */
+	VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like:  eth1.0005 */
+	VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like:  vlan5 */
+	VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like:  eth0.5 */
+	VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+	int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+	char device1[24];
+
+        union {
+		char device2[24];
+		int VID;
+		unsigned int skb_priority;
+		unsigned int name_type;
+		unsigned int bind_type;
+		unsigned int flag; /* Matches vlan_dev_info flags */
+        } u;
+
+	short vlan_qos;   
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/libnetwork/libnl3/include/linux/inetdevice.h b/libnetwork/libnl3/include/linux/inetdevice.h
new file mode 100644
index 0000000..fd4d2df
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/inetdevice.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_INETDEVICE_H
+#define _LINUX_INETDEVICE_H
+
+enum
+{
+	IPV4_DEVCONF_FORWARDING=1,
+	IPV4_DEVCONF_MC_FORWARDING,
+	IPV4_DEVCONF_PROXY_ARP,
+	IPV4_DEVCONF_ACCEPT_REDIRECTS,
+	IPV4_DEVCONF_SECURE_REDIRECTS,
+	IPV4_DEVCONF_SEND_REDIRECTS,
+	IPV4_DEVCONF_SHARED_MEDIA,
+	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,
+	__IPV4_DEVCONF_MAX
+};
+
+#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
+
+#endif /* _LINUX_INETDEVICE_H */
diff --git a/libnetwork/libnl3/include/linux/ip_mp_alg.h b/libnetwork/libnl3/include/linux/ip_mp_alg.h
new file mode 100644
index 0000000..e234e20
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/ip_mp_alg.h
@@ -0,0 +1,22 @@
+/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck at de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem at davemloft.net>
+ */
+
+#ifndef _LINUX_IP_MP_ALG_H
+#define _LINUX_IP_MP_ALG_H
+
+enum ip_mp_alg {
+	IP_MP_ALG_NONE,
+	IP_MP_ALG_RR,
+	IP_MP_ALG_DRR,
+	IP_MP_ALG_RANDOM,
+	IP_MP_ALG_WRANDOM,
+	__IP_MP_ALG_MAX
+};
+
+#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
+
+#endif /* _LINUX_IP_MP_ALG_H */
+
diff --git a/libnetwork/libnl3/include/linux/ipv6.h b/libnetwork/libnl3/include/linux/ipv6.h
new file mode 100644
index 0000000..f16349d
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/ipv6.h
@@ -0,0 +1,146 @@
+#ifndef _IPV6_H
+#define _IPV6_H
+
+#include <asm/byteorder.h>
+
+/* The latest drafts declared increase in minimal mtu up to 1280. */
+
+#define IPV6_MIN_MTU	1280
+
+/*
+ *	Advanced API
+ *	source interface/address selection, source routing, etc...
+ *	*under construction*
+ */
+
+
+#define IPV6_SRCRT_STRICT	0x01	/* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_0	0	/* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_2	2	/* IPv6 type 2 Routing Header	*/
+
+/*
+ *	routing header
+ */
+struct ipv6_rt_hdr {
+	__u8		nexthdr;
+	__u8		hdrlen;
+	__u8		type;
+	__u8		segments_left;
+
+	/*
+	 *	type specific data
+	 *	variable length field
+	 */
+};
+
+
+struct ipv6_opt_hdr {
+	__u8 		nexthdr;
+	__u8 		hdrlen;
+	/* 
+	 * TLV encoded option data follows.
+	 */
+} __attribute__((packed));	/* required for some archs */
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr  ipv6_opt_hdr
+
+
+/*
+ *	routing header type 0 (used in cmsghdr struct)
+ */
+
+struct rt0_hdr {
+	struct ipv6_rt_hdr	rt_hdr;
+	__u32			reserved;
+	struct in6_addr		addr[0];
+
+#define rt0_type		rt_hdr.type
+};
+
+/*
+ *	routing header type 2
+ */
+
+struct rt2_hdr {
+	struct ipv6_rt_hdr	rt_hdr;
+	__u32			reserved;
+	struct in6_addr		addr;
+
+#define rt2_type		rt_hdr.type
+};
+
+/*
+ *	home address option in destination options header
+ */
+
+struct ipv6_destopt_hao {
+	__u8			type;
+	__u8			length;
+	struct in6_addr		addr;
+} __attribute__((packed));
+
+/*
+ *	IPv6 fixed header
+ *
+ *	BEWARE, it is incorrect. The first 4 bits of flow_lbl
+ *	are glued to priority now, forming "class".
+ */
+
+struct ipv6hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8			priority:4,
+				version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u8			version:4,
+				priority:4;
+#else
+#error	"Please fix <asm/byteorder.h>"
+#endif
+	__u8			flow_lbl[3];
+
+	__be16			payload_len;
+	__u8			nexthdr;
+	__u8			hop_limit;
+
+	struct	in6_addr	saddr;
+	struct	in6_addr	daddr;
+};
+
+
+/* index values for the variables in ipv6_devconf */
+enum {
+	DEVCONF_FORWARDING = 0,
+	DEVCONF_HOPLIMIT,
+	DEVCONF_MTU6,
+	DEVCONF_ACCEPT_RA,
+	DEVCONF_ACCEPT_REDIRECTS,
+	DEVCONF_AUTOCONF,
+	DEVCONF_DAD_TRANSMITS,
+	DEVCONF_RTR_SOLICITS,
+	DEVCONF_RTR_SOLICIT_INTERVAL,
+	DEVCONF_RTR_SOLICIT_DELAY,
+	DEVCONF_USE_TEMPADDR,
+	DEVCONF_TEMP_VALID_LFT,
+	DEVCONF_TEMP_PREFERED_LFT,
+	DEVCONF_REGEN_MAX_RETRY,
+	DEVCONF_MAX_DESYNC_FACTOR,
+	DEVCONF_MAX_ADDRESSES,
+	DEVCONF_FORCE_MLD_VERSION,
+	DEVCONF_ACCEPT_RA_DEFRTR,
+	DEVCONF_ACCEPT_RA_PINFO,
+	DEVCONF_ACCEPT_RA_RTR_PREF,
+	DEVCONF_RTR_PROBE_INTERVAL,
+	DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
+	DEVCONF_PROXY_NDP,
+	DEVCONF_OPTIMISTIC_DAD,
+	DEVCONF_ACCEPT_SOURCE_ROUTE,
+	DEVCONF_MC_FORWARDING,
+	DEVCONF_DISABLE_IPV6,
+	DEVCONF_ACCEPT_DAD,
+	DEVCONF_FORCE_TLLAO,
+	DEVCONF_MAX
+};
+
+
+#endif /* _IPV6_H */
diff --git a/libnetwork/libnl3/include/linux/neighbour.h b/libnetwork/libnl3/include/linux/neighbour.h
new file mode 100644
index 0000000..a7003b7
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/neighbour.h
@@ -0,0 +1,155 @@
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ndmsg {
+	__u8		ndm_family;
+	__u8		ndm_pad1;
+	__u16		ndm_pad2;
+	__s32		ndm_ifindex;
+	__u16		ndm_state;
+	__u8		ndm_flags;
+	__u8		ndm_type;
+};
+
+enum {
+	NDA_UNSPEC,
+	NDA_DST,
+	NDA_LLADDR,
+	NDA_CACHEINFO,
+	NDA_PROBES,
+	__NDA_MAX
+};
+
+#define NDA_MAX (__NDA_MAX - 1)
+
+/*
+ *	Neighbor Cache Entry Flags
+ */
+
+#define NTF_USE		0x01
+#define NTF_PROXY	0x08	/* == ATF_PUBL */
+#define NTF_ROUTER	0x80
+
+/*
+ *	Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE	0x01
+#define NUD_REACHABLE	0x02
+#define NUD_STALE	0x04
+#define NUD_DELAY	0x08
+#define NUD_PROBE	0x10
+#define NUD_FAILED	0x20
+
+/* Dummy states */
+#define NUD_NOARP	0x40
+#define NUD_PERMANENT	0x80
+#define NUD_NONE	0x00
+
+/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+   and make no address resolution or NUD.
+   NUD_PERMANENT is also cannot be deleted by garbage collectors.
+ */
+
+struct nda_cacheinfo {
+	__u32		ndm_confirmed;
+	__u32		ndm_used;
+	__u32		ndm_updated;
+	__u32		ndm_refcnt;
+};
+
+/*****************************************************************
+ *		Neighbour tables specific messages.
+ *
+ * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
+ * NLM_F_DUMP flag set. Every neighbour table configuration is
+ * spread over multiple messages to avoid running into message
+ * size limits on systems with many interfaces. The first message
+ * in the sequence transports all not device specific data such as
+ * statistics, configuration, and the default parameter set.
+ * This message is followed by 0..n messages carrying device
+ * specific parameter sets.
+ * Although the ordering should be sufficient, NDTA_NAME can be
+ * used to identify sequences. The initial message can be identified
+ * by checking for NDTA_CONFIG. The device specific messages do
+ * not contain this TLV but have NDTPA_IFINDEX set to the
+ * corresponding interface index.
+ *
+ * To change neighbour table attributes, send RTM_SETNEIGHTBL
+ * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
+ * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
+ * otherwise. Device specific parameter sets can be changed by
+ * setting NDTPA_IFINDEX to the interface index of the corresponding
+ * device.
+ ****/
+
+struct ndt_stats {
+	__u64		ndts_allocs;
+	__u64		ndts_destroys;
+	__u64		ndts_hash_grows;
+	__u64		ndts_res_failed;
+	__u64		ndts_lookups;
+	__u64		ndts_hits;
+	__u64		ndts_rcv_probes_mcast;
+	__u64		ndts_rcv_probes_ucast;
+	__u64		ndts_periodic_gc_runs;
+	__u64		ndts_forced_gc_runs;
+};
+
+enum {
+	NDTPA_UNSPEC,
+	NDTPA_IFINDEX,			/* u32, unchangeable */
+	NDTPA_REFCNT,			/* u32, read-only */
+	NDTPA_REACHABLE_TIME,		/* u64, read-only, msecs */
+	NDTPA_BASE_REACHABLE_TIME,	/* u64, msecs */
+	NDTPA_RETRANS_TIME,		/* u64, msecs */
+	NDTPA_GC_STALETIME,		/* u64, msecs */
+	NDTPA_DELAY_PROBE_TIME,		/* u64, msecs */
+	NDTPA_QUEUE_LEN,		/* u32 */
+	NDTPA_APP_PROBES,		/* u32 */
+	NDTPA_UCAST_PROBES,		/* u32 */
+	NDTPA_MCAST_PROBES,		/* u32 */
+	NDTPA_ANYCAST_DELAY,		/* u64, msecs */
+	NDTPA_PROXY_DELAY,		/* u64, msecs */
+	NDTPA_PROXY_QLEN,		/* u32 */
+	NDTPA_LOCKTIME,			/* u64, msecs */
+	__NDTPA_MAX
+};
+#define NDTPA_MAX (__NDTPA_MAX - 1)
+
+struct ndtmsg {
+	__u8		ndtm_family;
+	__u8		ndtm_pad1;
+	__u16		ndtm_pad2;
+};
+
+struct ndt_config {
+	__u16		ndtc_key_len;
+	__u16		ndtc_entry_size;
+	__u32		ndtc_entries;
+	__u32		ndtc_last_flush;	/* delta to now in msecs */
+	__u32		ndtc_last_rand;		/* delta to now in msecs */
+	__u32		ndtc_hash_rnd;
+	__u32		ndtc_hash_mask;
+	__u32		ndtc_hash_chain_gc;
+	__u32		ndtc_proxy_qlen;
+};
+
+enum {
+	NDTA_UNSPEC,
+	NDTA_NAME,			/* char *, unchangeable */
+	NDTA_THRESH1,			/* u32 */
+	NDTA_THRESH2,			/* u32 */
+	NDTA_THRESH3,			/* u32 */
+	NDTA_CONFIG,			/* struct ndt_config, read-only */
+	NDTA_PARMS,			/* nested TLV NDTPA_* */
+	NDTA_STATS,			/* struct ndt_stats, read-only */
+	NDTA_GC_INTERVAL,		/* u64, msecs */
+	__NDTA_MAX
+};
+#define NDTA_MAX (__NDTA_MAX - 1)
+
+#endif
diff --git a/libnetwork/libnl3/include/linux/netfilter.h b/libnetwork/libnl3/include/linux/netfilter.h
new file mode 100644
index 0000000..7999885
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netfilter.h
@@ -0,0 +1,57 @@
+#ifndef __LINUX_NETFILTER_H
+#define __LINUX_NETFILTER_H
+
+#include <linux/types.h>
+
+/* Responses from hook functions. */
+#define NF_DROP 0
+#define NF_ACCEPT 1
+#define NF_STOLEN 2
+#define NF_QUEUE 3
+#define NF_REPEAT 4
+#define NF_STOP 5
+#define NF_MAX_VERDICT NF_STOP
+
+/* we overload the higher bits for encoding auxiliary data such as the queue
+ * number. Not nice, but better than additional function arguments. */
+#define NF_VERDICT_MASK 0x0000ffff
+#define NF_VERDICT_BITS 16
+
+#define NF_VERDICT_QMASK 0xffff0000
+#define NF_VERDICT_QBITS 16
+
+#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+/* Generic cache responses from hook functions.
+   <= 0x2000 is used for protocol-flags. */
+#define NFC_UNKNOWN 0x4000
+#define NFC_ALTERED 0x8000
+
+enum nf_inet_hooks {
+	NF_INET_PRE_ROUTING,
+	NF_INET_LOCAL_IN,
+	NF_INET_FORWARD,
+	NF_INET_LOCAL_OUT,
+	NF_INET_POST_ROUTING,
+	NF_INET_NUMHOOKS
+};
+
+enum {
+	NFPROTO_UNSPEC =  0,
+	NFPROTO_IPV4   =  2,
+	NFPROTO_ARP    =  3,
+	NFPROTO_BRIDGE =  7,
+	NFPROTO_IPV6   = 10,
+	NFPROTO_DECNET = 12,
+	NFPROTO_NUMPROTO,
+};
+
+union nf_inet_addr {
+	__u32		all[4];
+	__be32		ip;
+	__be32		ip6[4];
+	struct in_addr	in;
+	struct in6_addr	in6;
+};
+
+#endif /*__LINUX_NETFILTER_H*/
diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h
new file mode 100644
index 0000000..1e59984
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h
@@ -0,0 +1,60 @@
+#ifndef _NFNETLINK_H
+#define _NFNETLINK_H
+#include <linux/types.h>
+
+#ifndef __KERNEL__
+/* nfnetlink groups: Up to 32 maximum - backwards compatibility for userspace */
+#define NF_NETLINK_CONNTRACK_NEW 		0x00000001
+#define NF_NETLINK_CONNTRACK_UPDATE		0x00000002
+#define NF_NETLINK_CONNTRACK_DESTROY		0x00000004
+#define NF_NETLINK_CONNTRACK_EXP_NEW		0x00000008
+#define NF_NETLINK_CONNTRACK_EXP_UPDATE		0x00000010
+#define NF_NETLINK_CONNTRACK_EXP_DESTROY	0x00000020
+#endif
+
+enum nfnetlink_groups {
+	NFNLGRP_NONE,
+#define NFNLGRP_NONE			NFNLGRP_NONE
+	NFNLGRP_CONNTRACK_NEW,
+#define NFNLGRP_CONNTRACK_NEW		NFNLGRP_CONNTRACK_NEW
+	NFNLGRP_CONNTRACK_UPDATE,
+#define NFNLGRP_CONNTRACK_UPDATE	NFNLGRP_CONNTRACK_UPDATE
+	NFNLGRP_CONNTRACK_DESTROY,
+#define NFNLGRP_CONNTRACK_DESTROY	NFNLGRP_CONNTRACK_DESTROY
+	NFNLGRP_CONNTRACK_EXP_NEW,
+#define	NFNLGRP_CONNTRACK_EXP_NEW	NFNLGRP_CONNTRACK_EXP_NEW
+	NFNLGRP_CONNTRACK_EXP_UPDATE,
+#define NFNLGRP_CONNTRACK_EXP_UPDATE	NFNLGRP_CONNTRACK_EXP_UPDATE
+	NFNLGRP_CONNTRACK_EXP_DESTROY,
+#define NFNLGRP_CONNTRACK_EXP_DESTROY	NFNLGRP_CONNTRACK_EXP_DESTROY
+	__NFNLGRP_MAX,
+};
+#define NFNLGRP_MAX	(__NFNLGRP_MAX - 1)
+
+/* General form of address family dependent message.
+ */
+struct nfgenmsg {
+	u_int8_t  nfgen_family;		/* AF_xxx */
+	u_int8_t  version;		/* nfnetlink version */
+	__be16    res_id;		/* resource id */
+};
+
+#define NFNETLINK_V0	0
+
+/* netfilter netlink message types are split in two pieces:
+ * 8 bit subsystem, 8bit operation.
+ */
+
+#define NFNL_SUBSYS_ID(x)	((x & 0xff00) >> 8)
+#define NFNL_MSG_TYPE(x)	(x & 0x00ff)
+
+/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
+ * won't work anymore */
+#define NFNL_SUBSYS_NONE 		0
+#define NFNL_SUBSYS_CTNETLINK		1
+#define NFNL_SUBSYS_CTNETLINK_EXP	2
+#define NFNL_SUBSYS_QUEUE		3
+#define NFNL_SUBSYS_ULOG		4
+#define NFNL_SUBSYS_COUNT		5
+
+#endif	/* _NFNETLINK_H */
diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h
new file mode 100644
index 0000000..d7c3503
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h
@@ -0,0 +1,140 @@
+#ifndef _IPCONNTRACK_NETLINK_H
+#define _IPCONNTRACK_NETLINK_H
+#include <linux/netfilter/nfnetlink.h>
+
+enum cntl_msg_types {
+	IPCTNL_MSG_CT_NEW,
+	IPCTNL_MSG_CT_GET,
+	IPCTNL_MSG_CT_DELETE,
+	IPCTNL_MSG_CT_GET_CTRZERO,
+
+	IPCTNL_MSG_MAX
+};
+
+enum ctnl_exp_msg_types {
+	IPCTNL_MSG_EXP_NEW,
+	IPCTNL_MSG_EXP_GET,
+	IPCTNL_MSG_EXP_DELETE,
+
+	IPCTNL_MSG_EXP_MAX
+};
+
+
+enum ctattr_type {
+	CTA_UNSPEC,
+	CTA_TUPLE_ORIG,
+	CTA_TUPLE_REPLY,
+	CTA_STATUS,
+	CTA_PROTOINFO,
+	CTA_HELP,
+	CTA_NAT_SRC,
+#define CTA_NAT	CTA_NAT_SRC	/* backwards compatibility */
+	CTA_TIMEOUT,
+	CTA_MARK,
+	CTA_COUNTERS_ORIG,
+	CTA_COUNTERS_REPLY,
+	CTA_USE,
+	CTA_ID,
+	CTA_NAT_DST,
+	__CTA_MAX
+};
+#define CTA_MAX (__CTA_MAX - 1)
+
+enum ctattr_tuple {
+	CTA_TUPLE_UNSPEC,
+	CTA_TUPLE_IP,
+	CTA_TUPLE_PROTO,
+	__CTA_TUPLE_MAX
+};
+#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
+
+enum ctattr_ip {
+	CTA_IP_UNSPEC,
+	CTA_IP_V4_SRC,
+	CTA_IP_V4_DST,
+	CTA_IP_V6_SRC,
+	CTA_IP_V6_DST,
+	__CTA_IP_MAX
+};
+#define CTA_IP_MAX (__CTA_IP_MAX - 1)
+
+enum ctattr_l4proto {
+	CTA_PROTO_UNSPEC,
+	CTA_PROTO_NUM,
+	CTA_PROTO_SRC_PORT,
+	CTA_PROTO_DST_PORT,
+	CTA_PROTO_ICMP_ID,
+	CTA_PROTO_ICMP_TYPE,
+	CTA_PROTO_ICMP_CODE,
+	CTA_PROTO_ICMPV6_ID,
+	CTA_PROTO_ICMPV6_TYPE,
+	CTA_PROTO_ICMPV6_CODE,
+	__CTA_PROTO_MAX
+};
+#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
+
+enum ctattr_protoinfo {
+	CTA_PROTOINFO_UNSPEC,
+	CTA_PROTOINFO_TCP,
+	__CTA_PROTOINFO_MAX
+};
+#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
+
+enum ctattr_protoinfo_tcp {
+	CTA_PROTOINFO_TCP_UNSPEC,
+	CTA_PROTOINFO_TCP_STATE,
+	CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+	CTA_PROTOINFO_TCP_WSCALE_REPLY,
+	CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+	CTA_PROTOINFO_TCP_FLAGS_REPLY,
+	__CTA_PROTOINFO_TCP_MAX
+};
+#define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1)
+
+enum ctattr_counters {
+	CTA_COUNTERS_UNSPEC,
+	CTA_COUNTERS_PACKETS,		/* old 64bit counters */
+	CTA_COUNTERS_BYTES,		/* old 64bit counters */
+	CTA_COUNTERS32_PACKETS,
+	CTA_COUNTERS32_BYTES,
+	__CTA_COUNTERS_MAX
+};
+#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
+
+enum ctattr_nat {
+	CTA_NAT_UNSPEC,
+	CTA_NAT_MINIP,
+	CTA_NAT_MAXIP,
+	CTA_NAT_PROTO,
+	__CTA_NAT_MAX
+};
+#define CTA_NAT_MAX (__CTA_NAT_MAX - 1)
+
+enum ctattr_protonat {
+	CTA_PROTONAT_UNSPEC,
+	CTA_PROTONAT_PORT_MIN,
+	CTA_PROTONAT_PORT_MAX,
+	__CTA_PROTONAT_MAX
+};
+#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1)
+
+enum ctattr_expect {
+	CTA_EXPECT_UNSPEC,
+	CTA_EXPECT_MASTER,
+	CTA_EXPECT_TUPLE,
+	CTA_EXPECT_MASK,
+	CTA_EXPECT_TIMEOUT,
+	CTA_EXPECT_ID,
+	CTA_EXPECT_HELP_NAME,
+	__CTA_EXPECT_MAX
+};
+#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
+
+enum ctattr_help {
+	CTA_HELP_UNSPEC,
+	CTA_HELP_NAME,
+	__CTA_HELP_MAX
+};
+#define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
+
+#endif /* _IPCONNTRACK_NETLINK_H */
diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h
new file mode 100644
index 0000000..38fafc1
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h
@@ -0,0 +1,97 @@
+#ifndef _NFNETLINK_LOG_H
+#define _NFNETLINK_LOG_H
+
+/* This file describes the netlink messages (i.e. 'protocol packets'),
+ * and not any kind of function definitions.  It is shared between kernel and
+ * userspace.  Don't put kernel specific stuff in here */
+
+#ifndef aligned_be64
+#define aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+enum nfulnl_msg_types {
+	NFULNL_MSG_PACKET,		/* packet from kernel to userspace */
+	NFULNL_MSG_CONFIG,		/* connect to a particular queue */
+
+	NFULNL_MSG_MAX
+};
+
+struct nfulnl_msg_packet_hdr {
+	__be16		hw_protocol;	/* hw protocol (network order) */
+	u_int8_t	hook;		/* netfilter hook */
+	u_int8_t	_pad;
+};
+
+struct nfulnl_msg_packet_hw {
+	__be16		hw_addrlen;
+	u_int16_t	_pad;
+	u_int8_t	hw_addr[8];
+};
+
+struct nfulnl_msg_packet_timestamp {
+	aligned_be64	sec;
+	aligned_be64	usec;
+};
+
+enum nfulnl_attr_type {
+	NFULA_UNSPEC,
+	NFULA_PACKET_HDR,
+	NFULA_MARK,			/* u_int32_t nfmark */
+	NFULA_TIMESTAMP,		/* nfulnl_msg_packet_timestamp */
+	NFULA_IFINDEX_INDEV,		/* u_int32_t ifindex */
+	NFULA_IFINDEX_OUTDEV,		/* u_int32_t ifindex */
+	NFULA_IFINDEX_PHYSINDEV,	/* u_int32_t ifindex */
+	NFULA_IFINDEX_PHYSOUTDEV,	/* u_int32_t ifindex */
+	NFULA_HWADDR,			/* nfulnl_msg_packet_hw */
+	NFULA_PAYLOAD,			/* opaque data payload */
+	NFULA_PREFIX,			/* string prefix */
+	NFULA_UID,			/* user id of socket */
+	NFULA_SEQ,			/* instance-local sequence number */
+	NFULA_SEQ_GLOBAL,		/* global sequence number */
+	NFULA_GID,			/* group id of socket */
+
+	__NFULA_MAX
+};
+#define NFULA_MAX (__NFULA_MAX - 1)
+
+enum nfulnl_msg_config_cmds {
+	NFULNL_CFG_CMD_NONE,
+	NFULNL_CFG_CMD_BIND,
+	NFULNL_CFG_CMD_UNBIND,
+	NFULNL_CFG_CMD_PF_BIND,
+	NFULNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfulnl_msg_config_cmd {
+	u_int8_t	command;	/* nfulnl_msg_config_cmds */
+} __attribute__ ((packed));
+
+struct nfulnl_msg_config_mode {
+	__be32		copy_range;
+	u_int8_t	copy_mode;
+	u_int8_t	_pad;
+} __attribute__ ((packed));
+
+enum nfulnl_attr_config {
+	NFULA_CFG_UNSPEC,
+	NFULA_CFG_CMD,			/* nfulnl_msg_config_cmd */
+	NFULA_CFG_MODE,			/* nfulnl_msg_config_mode */
+	NFULA_CFG_NLBUFSIZ,		/* u_int32_t buffer size */
+	NFULA_CFG_TIMEOUT,		/* u_int32_t in 1/100 s */
+	NFULA_CFG_QTHRESH,		/* u_int32_t */
+	NFULA_CFG_FLAGS,		/* u_int16_t */
+	__NFULA_CFG_MAX
+};
+#define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
+
+#define NFULNL_COPY_NONE	0x00
+#define NFULNL_COPY_META	0x01
+#define NFULNL_COPY_PACKET	0x02
+
+#define NFULNL_CFG_F_SEQ	0x0001
+#define NFULNL_CFG_F_SEQ_GLOBAL	0x0002
+
+#endif /* _NFNETLINK_LOG_H */
diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h
new file mode 100644
index 0000000..bf7cfb6
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h
@@ -0,0 +1,94 @@
+#ifndef _NFNETLINK_QUEUE_H
+#define _NFNETLINK_QUEUE_H
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+#ifndef aligned_be64
+#define aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+enum nfqnl_msg_types {
+	NFQNL_MSG_PACKET,		/* packet from kernel to userspace */
+	NFQNL_MSG_VERDICT,		/* verdict from userspace to kernel */
+	NFQNL_MSG_CONFIG,		/* connect to a particular queue */
+
+	NFQNL_MSG_MAX
+};
+
+struct nfqnl_msg_packet_hdr {
+	__be32		packet_id;	/* unique ID of packet in queue */
+	__be16		hw_protocol;	/* hw protocol (network order) */
+	u_int8_t	hook;		/* netfilter hook */
+} __attribute__ ((packed));
+
+struct nfqnl_msg_packet_hw {
+	__be16		hw_addrlen;
+	u_int16_t	_pad;
+	u_int8_t	hw_addr[8];
+};
+
+struct nfqnl_msg_packet_timestamp {
+	aligned_be64	sec;
+	aligned_be64	usec;
+};
+
+enum nfqnl_attr_type {
+	NFQA_UNSPEC,
+	NFQA_PACKET_HDR,
+	NFQA_VERDICT_HDR,		/* nfqnl_msg_verdict_hrd */
+	NFQA_MARK,			/* u_int32_t nfmark */
+	NFQA_TIMESTAMP,			/* nfqnl_msg_packet_timestamp */
+	NFQA_IFINDEX_INDEV,		/* u_int32_t ifindex */
+	NFQA_IFINDEX_OUTDEV,		/* u_int32_t ifindex */
+	NFQA_IFINDEX_PHYSINDEV,		/* u_int32_t ifindex */
+	NFQA_IFINDEX_PHYSOUTDEV,	/* u_int32_t ifindex */
+	NFQA_HWADDR,			/* nfqnl_msg_packet_hw */
+	NFQA_PAYLOAD,			/* opaque data payload */
+
+	__NFQA_MAX
+};
+#define NFQA_MAX (__NFQA_MAX - 1)
+
+struct nfqnl_msg_verdict_hdr {
+	__be32 verdict;
+	__be32 id;
+};
+
+
+enum nfqnl_msg_config_cmds {
+	NFQNL_CFG_CMD_NONE,
+	NFQNL_CFG_CMD_BIND,
+	NFQNL_CFG_CMD_UNBIND,
+	NFQNL_CFG_CMD_PF_BIND,
+	NFQNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfqnl_msg_config_cmd {
+	u_int8_t	command;	/* nfqnl_msg_config_cmds */
+	u_int8_t	_pad;
+	__be16		pf;		/* AF_xxx for PF_[UN]BIND */
+};
+
+enum nfqnl_config_mode {
+	NFQNL_COPY_NONE,
+	NFQNL_COPY_META,
+	NFQNL_COPY_PACKET,
+};
+
+struct nfqnl_msg_config_params {
+	__be32		copy_range;
+	u_int8_t	copy_mode;	/* enum nfqnl_config_mode */
+} __attribute__ ((packed));
+
+
+enum nfqnl_attr_config {
+	NFQA_CFG_UNSPEC,
+	NFQA_CFG_CMD,			/* nfqnl_msg_config_cmd */
+	NFQA_CFG_PARAMS,		/* nfqnl_msg_config_params */
+	NFQA_CFG_QUEUE_MAXLEN,		/* u_int32_t */
+	__NFQA_CFG_MAX
+};
+#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
+
+#endif /* _NFNETLINK_QUEUE_H */
diff --git a/libnetwork/libnl3/include/linux/netlink.h b/libnetwork/libnl3/include/linux/netlink.h
new file mode 100644
index 0000000..3925254
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/netlink.h
@@ -0,0 +1,149 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/socket.h> /* for sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE		0	/* Routing/device hook				*/
+#define NETLINK_UNUSED		1	/* Unused number				*/
+#define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
+#define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
+#define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
+#define NETLINK_XFRM		6	/* ipsec */
+#define NETLINK_SELINUX		7	/* SELinux event notifications */
+#define NETLINK_ISCSI		8	/* Open-iSCSI */
+#define NETLINK_AUDIT		9	/* auditing */
+#define NETLINK_FIB_LOOKUP	10	
+#define NETLINK_CONNECTOR	11
+#define NETLINK_NETFILTER	12	/* netfilter subsystem */
+#define NETLINK_IP6_FW		13
+#define NETLINK_DNRTMSG		14	/* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
+#define NETLINK_GENERIC		16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
+#define NETLINK_ECRYPTFS	19
+#define NETLINK_RDMA		20
+
+#define MAX_LINKS 32		
+
+struct sockaddr_nl {
+	sa_family_t	nl_family;	/* AF_NETLINK	*/
+	unsigned short	nl_pad;		/* zero		*/
+	__u32		nl_pid;		/* port ID	*/
+       	__u32		nl_groups;	/* multicast groups mask */
+};
+
+struct nlmsghdr {
+	__u32		nlmsg_len;	/* Length of message including header */
+	__u16		nlmsg_type;	/* Message content */
+	__u16		nlmsg_flags;	/* Additional flags */
+	__u32		nlmsg_seq;	/* Sequence number */
+	__u32		nlmsg_pid;	/* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST		1	/* It is request message. 	*/
+#define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK		4	/* Reply with ack, with zero or error code */
+#define NLM_F_ECHO		8	/* Echo this request 		*/
+#define NLM_F_DUMP_INTR		16	/* Dump was inconsistent due to sequence change */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT	0x100	/* specify tree	root	*/
+#define NLM_F_MATCH	0x200	/* return all matching	*/
+#define NLM_F_ATOMIC	0x400	/* atomic GET		*/
+#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE	0x100	/* Override existing		*/
+#define NLM_F_EXCL	0x200	/* Do not touch, if it exists	*/
+#define NLM_F_CREATE	0x400	/* Create, if it does not exist	*/
+#define NLM_F_APPEND	0x800	/* Add to end of list		*/
+
+/*
+   4.4BSD ADD		NLM_F_CREATE|NLM_F_EXCL
+   4.4BSD CHANGE	NLM_F_REPLACE
+
+   True CHANGE		NLM_F_CREATE|NLM_F_REPLACE
+   Append		NLM_F_CREATE
+   Check		NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO	4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+				  (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+			   (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP		0x1	/* Nothing.		*/
+#define NLMSG_ERROR		0x2	/* Error		*/
+#define NLMSG_DONE		0x3	/* End of a dump	*/
+#define NLMSG_OVERRUN		0x4	/* Data lost		*/
+
+#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+	int		error;
+	struct nlmsghdr msg;
+};
+
+#define NETLINK_ADD_MEMBERSHIP	1
+#define NETLINK_DROP_MEMBERSHIP	2
+#define NETLINK_PKTINFO		3
+#define NETLINK_BROADCAST_ERROR	4
+#define NETLINK_NO_ENOBUFS	5
+
+struct nl_pktinfo {
+	__u32	group;
+};
+
+#define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
+
+enum {
+	NETLINK_UNCONNECTED = 0,
+	NETLINK_CONNECTED,
+};
+
+/*
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+	__u16           nla_len;
+	__u16           nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED		(1 << 15)
+#define NLA_F_NET_BYTEORDER	(1 << 14)
+#define NLA_TYPE_MASK		~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO		4
+#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+#endif	/* __LINUX_NETLINK_H */
diff --git a/libnetwork/libnl3/include/linux/pkt_cls.h b/libnetwork/libnl3/include/linux/pkt_cls.h
new file mode 100644
index 0000000..defbde2
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/pkt_cls.h
@@ -0,0 +1,467 @@
+#ifndef __LINUX_PKT_CLS_H
+#define __LINUX_PKT_CLS_H
+
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+/* I think i could have done better macros ; for now this is stolen from
+ * some arch/mips code - jhs
+*/
+#define _TC_MAKE32(x) ((x))
+
+#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
+#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n))
+#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n))
+#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n))
+
+/* verdict bit breakdown 
+ *
+bit 0: when set -> this packet has been munged already
+
+bit 1: when set -> It is ok to munge this packet
+
+bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded
+assume loop
+
+bit 6,7: Where this packet was last seen 
+0: Above the transmit example at the socket level
+1: on the Ingress
+2: on the Egress
+
+bit 8: when set --> Request not to classify on ingress. 
+
+bits 9,10,11: redirect counter -  redirect TTL. Loop avoidance
+
+ *
+ * */
+
+#define TC_MUNGED          _TC_MAKEMASK1(0)
+#define SET_TC_MUNGED(v)   ( TC_MUNGED | (v & ~TC_MUNGED))
+#define CLR_TC_MUNGED(v)   ( v & ~TC_MUNGED)
+
+#define TC_OK2MUNGE        _TC_MAKEMASK1(1)
+#define SET_TC_OK2MUNGE(v)   ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
+#define CLR_TC_OK2MUNGE(v)   ( v & ~TC_OK2MUNGE)
+
+#define S_TC_VERD          _TC_MAKE32(2)
+#define M_TC_VERD          _TC_MAKEMASK(4,S_TC_VERD)
+#define G_TC_VERD(x)       _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
+#define V_TC_VERD(x)       _TC_MAKEVALUE(x,S_TC_VERD)
+#define SET_TC_VERD(v,n)   ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
+
+#define S_TC_FROM          _TC_MAKE32(6)
+#define M_TC_FROM          _TC_MAKEMASK(2,S_TC_FROM)
+#define G_TC_FROM(x)       _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM)
+#define V_TC_FROM(x)       _TC_MAKEVALUE(x,S_TC_FROM)
+#define SET_TC_FROM(v,n)   ((V_TC_FROM(n)) | (v & ~M_TC_FROM))
+#define AT_STACK	0x0
+#define AT_INGRESS	0x1
+#define AT_EGRESS	0x2
+
+#define TC_NCLS          _TC_MAKEMASK1(8)
+#define SET_TC_NCLS(v)   ( TC_NCLS | (v & ~TC_NCLS))
+#define CLR_TC_NCLS(v)   ( v & ~TC_NCLS)
+
+#define S_TC_RTTL          _TC_MAKE32(9)
+#define M_TC_RTTL          _TC_MAKEMASK(3,S_TC_RTTL)
+#define G_TC_RTTL(x)       _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL)
+#define V_TC_RTTL(x)       _TC_MAKEVALUE(x,S_TC_RTTL)
+#define SET_TC_RTTL(v,n)   ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL))
+
+#define S_TC_AT          _TC_MAKE32(12)
+#define M_TC_AT          _TC_MAKEMASK(2,S_TC_AT)
+#define G_TC_AT(x)       _TC_GETVALUE(x,S_TC_AT,M_TC_AT)
+#define V_TC_AT(x)       _TC_MAKEVALUE(x,S_TC_AT)
+#define SET_TC_AT(v,n)   ((V_TC_AT(n)) | (v & ~M_TC_AT))
+
+/* Action attributes */
+enum {
+	TCA_ACT_UNSPEC,
+	TCA_ACT_KIND,
+	TCA_ACT_OPTIONS,
+	TCA_ACT_INDEX,
+	TCA_ACT_STATS,
+	__TCA_ACT_MAX
+};
+
+#define TCA_ACT_MAX __TCA_ACT_MAX
+#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
+#define TCA_ACT_MAX_PRIO 32
+#define TCA_ACT_BIND	1
+#define TCA_ACT_NOBIND	0
+#define TCA_ACT_UNBIND	1
+#define TCA_ACT_NOUNBIND	0
+#define TCA_ACT_REPLACE		1
+#define TCA_ACT_NOREPLACE	0
+#define MAX_REC_LOOP 4
+#define MAX_RED_LOOP 4
+
+#define TC_ACT_UNSPEC	(-1)
+#define TC_ACT_OK		0
+#define TC_ACT_RECLASSIFY	1
+#define TC_ACT_SHOT		2
+#define TC_ACT_PIPE		3
+#define TC_ACT_STOLEN		4
+#define TC_ACT_QUEUED		5
+#define TC_ACT_REPEAT		6
+#define TC_ACT_JUMP		0x10000000
+
+/* Action type identifiers*/
+enum {
+	TCA_ID_UNSPEC=0,
+	TCA_ID_POLICE=1,
+	/* other actions go here */
+	__TCA_ID_MAX=255
+};
+
+#define TCA_ID_MAX __TCA_ID_MAX
+
+struct tc_police {
+	__u32			index;
+	int			action;
+#define TC_POLICE_UNSPEC	TC_ACT_UNSPEC
+#define TC_POLICE_OK		TC_ACT_OK
+#define TC_POLICE_RECLASSIFY	TC_ACT_RECLASSIFY
+#define TC_POLICE_SHOT		TC_ACT_SHOT
+#define TC_POLICE_PIPE		TC_ACT_PIPE
+
+	__u32			limit;
+	__u32			burst;
+	__u32			mtu;
+	struct tc_ratespec	rate;
+	struct tc_ratespec	peakrate;
+	int 			refcnt;
+	int 			bindcnt;
+	__u32			capab;
+};
+
+struct tcf_t {
+	__u64   install;
+	__u64   lastuse;
+	__u64   expires;
+};
+
+struct tc_cnt {
+	int                   refcnt; 
+	int                   bindcnt;
+};
+
+#define tc_gen \
+	__u32                 index; \
+	__u32                 capab; \
+	int                   action; \
+	int                   refcnt; \
+	int                   bindcnt
+
+enum {
+	TCA_POLICE_UNSPEC,
+	TCA_POLICE_TBF,
+	TCA_POLICE_RATE,
+	TCA_POLICE_PEAKRATE,
+	TCA_POLICE_AVRATE,
+	TCA_POLICE_RESULT,
+	__TCA_POLICE_MAX
+#define TCA_POLICE_RESULT TCA_POLICE_RESULT
+};
+
+#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
+
+/* U32 filters */
+
+#define TC_U32_HTID(h) ((h)&0xFFF00000)
+#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
+#define TC_U32_HASH(h) (((h)>>12)&0xFF)
+#define TC_U32_NODE(h) ((h)&0xFFF)
+#define TC_U32_KEY(h) ((h)&0xFFFFF)
+#define TC_U32_UNSPEC	0
+#define TC_U32_ROOT	(0xFFF00000)
+
+enum {
+	TCA_U32_UNSPEC,
+	TCA_U32_CLASSID,
+	TCA_U32_HASH,
+	TCA_U32_LINK,
+	TCA_U32_DIVISOR,
+	TCA_U32_SEL,
+	TCA_U32_POLICE,
+	TCA_U32_ACT,   
+	TCA_U32_INDEV,
+	TCA_U32_PCNT,
+	TCA_U32_MARK,
+	__TCA_U32_MAX
+};
+
+#define TCA_U32_MAX (__TCA_U32_MAX - 1)
+
+struct tc_u32_key {
+	__be32		mask;
+	__be32		val;
+	int		off;
+	int		offmask;
+};
+
+struct tc_u32_sel {
+	unsigned char		flags;
+	unsigned char		offshift;
+	unsigned char		nkeys;
+
+	__be16			offmask;
+	__u16			off;
+	short			offoff;
+
+	short			hoff;
+	__be32			hmask;
+	struct tc_u32_key	keys[0];
+};
+
+struct tc_u32_mark {
+	__u32		val;
+	__u32		mask;
+	__u32		success;
+};
+
+struct tc_u32_pcnt {
+	__u64 rcnt;
+	__u64 rhit;
+	__u64 kcnts[0];
+};
+
+/* Flags */
+
+#define TC_U32_TERMINAL		1
+#define TC_U32_OFFSET		2
+#define TC_U32_VAROFFSET	4
+#define TC_U32_EAT		8
+
+#define TC_U32_MAXDEPTH 8
+
+
+/* RSVP filter */
+
+enum {
+	TCA_RSVP_UNSPEC,
+	TCA_RSVP_CLASSID,
+	TCA_RSVP_DST,
+	TCA_RSVP_SRC,
+	TCA_RSVP_PINFO,
+	TCA_RSVP_POLICE,
+	TCA_RSVP_ACT,
+	__TCA_RSVP_MAX
+};
+
+#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
+
+struct tc_rsvp_gpi {
+	__u32	key;
+	__u32	mask;
+	int	offset;
+};
+
+struct tc_rsvp_pinfo {
+	struct tc_rsvp_gpi dpi;
+	struct tc_rsvp_gpi spi;
+	__u8	protocol;
+	__u8	tunnelid;
+	__u8	tunnelhdr;
+	__u8	pad;
+};
+
+/* ROUTE filter */
+
+enum {
+	TCA_ROUTE4_UNSPEC,
+	TCA_ROUTE4_CLASSID,
+	TCA_ROUTE4_TO,
+	TCA_ROUTE4_FROM,
+	TCA_ROUTE4_IIF,
+	TCA_ROUTE4_POLICE,
+	TCA_ROUTE4_ACT,
+	__TCA_ROUTE4_MAX
+};
+
+#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1)
+
+
+/* FW filter */
+
+enum {
+	TCA_FW_UNSPEC,
+	TCA_FW_CLASSID,
+	TCA_FW_POLICE,
+	TCA_FW_INDEV, /*  used by CONFIG_NET_CLS_IND */
+	TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
+	TCA_FW_MASK,
+	__TCA_FW_MAX
+};
+
+#define TCA_FW_MAX (__TCA_FW_MAX - 1)
+
+/* TC index filter */
+
+enum {
+	TCA_TCINDEX_UNSPEC,
+	TCA_TCINDEX_HASH,
+	TCA_TCINDEX_MASK,
+	TCA_TCINDEX_SHIFT,
+	TCA_TCINDEX_FALL_THROUGH,
+	TCA_TCINDEX_CLASSID,
+	TCA_TCINDEX_POLICE,
+	TCA_TCINDEX_ACT,
+	__TCA_TCINDEX_MAX
+};
+
+#define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
+
+/* Flow filter */
+
+enum {
+	FLOW_KEY_SRC,
+	FLOW_KEY_DST,
+	FLOW_KEY_PROTO,
+	FLOW_KEY_PROTO_SRC,
+	FLOW_KEY_PROTO_DST,
+	FLOW_KEY_IIF,
+	FLOW_KEY_PRIORITY,
+	FLOW_KEY_MARK,
+	FLOW_KEY_NFCT,
+	FLOW_KEY_NFCT_SRC,
+	FLOW_KEY_NFCT_DST,
+	FLOW_KEY_NFCT_PROTO_SRC,
+	FLOW_KEY_NFCT_PROTO_DST,
+	FLOW_KEY_RTCLASSID,
+	FLOW_KEY_SKUID,
+	FLOW_KEY_SKGID,
+	FLOW_KEY_VLAN_TAG,
+	FLOW_KEY_RXHASH,
+	__FLOW_KEY_MAX,
+};
+
+#define FLOW_KEY_MAX	(__FLOW_KEY_MAX - 1)
+
+enum {
+	FLOW_MODE_MAP,
+	FLOW_MODE_HASH,
+};
+
+enum {
+	TCA_FLOW_UNSPEC,
+	TCA_FLOW_KEYS,
+	TCA_FLOW_MODE,
+	TCA_FLOW_BASECLASS,
+	TCA_FLOW_RSHIFT,
+	TCA_FLOW_ADDEND,
+	TCA_FLOW_MASK,
+	TCA_FLOW_XOR,
+	TCA_FLOW_DIVISOR,
+	TCA_FLOW_ACT,
+	TCA_FLOW_POLICE,
+	TCA_FLOW_EMATCHES,
+	TCA_FLOW_PERTURB,
+	__TCA_FLOW_MAX
+};
+
+#define TCA_FLOW_MAX	(__TCA_FLOW_MAX - 1)
+
+/* Basic filter */
+
+enum {
+	TCA_BASIC_UNSPEC,
+	TCA_BASIC_CLASSID,
+	TCA_BASIC_EMATCHES,
+	TCA_BASIC_ACT,
+	TCA_BASIC_POLICE,
+	__TCA_BASIC_MAX
+};
+
+#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
+
+
+/* Cgroup classifier */
+
+enum {
+	TCA_CGROUP_UNSPEC,
+	TCA_CGROUP_ACT,
+	TCA_CGROUP_POLICE,
+	TCA_CGROUP_EMATCHES,
+	__TCA_CGROUP_MAX,
+};
+
+#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+
+/* Extended Matches */
+
+struct tcf_ematch_tree_hdr {
+	__u16		nmatches;
+	__u16		progid;
+};
+
+enum {
+	TCA_EMATCH_TREE_UNSPEC,
+	TCA_EMATCH_TREE_HDR,
+	TCA_EMATCH_TREE_LIST,
+	__TCA_EMATCH_TREE_MAX
+};
+#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1)
+
+struct tcf_ematch_hdr {
+	__u16		matchid;
+	__u16		kind;
+	__u16		flags;
+	__u16		pad; /* currently unused */
+};
+
+/*  0                   1
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+ * +-----------------------+-+-+---+
+ * |         Unused        |S|I| R |
+ * +-----------------------+-+-+---+
+ *
+ * R(2) ::= relation to next ematch
+ *          where: 0 0 END (last ematch)
+ *                 0 1 AND
+ *                 1 0 OR
+ *                 1 1 Unused (invalid)
+ * I(1) ::= invert result
+ * S(1) ::= simple payload
+ */
+#define TCF_EM_REL_END	0
+#define TCF_EM_REL_AND	(1<<0)
+#define TCF_EM_REL_OR	(1<<1)
+#define TCF_EM_INVERT	(1<<2)
+#define TCF_EM_SIMPLE	(1<<3)
+
+#define TCF_EM_REL_MASK	3
+#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK)
+
+enum {
+	TCF_LAYER_LINK,
+	TCF_LAYER_NETWORK,
+	TCF_LAYER_TRANSPORT,
+	__TCF_LAYER_MAX
+};
+#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
+
+/* Ematch type assignments
+ *   1..32767		Reserved for ematches inside kernel tree
+ *   32768..65535	Free to use, not reliable
+ */
+#define	TCF_EM_CONTAINER	0
+#define	TCF_EM_CMP		1
+#define	TCF_EM_NBYTE		2
+#define	TCF_EM_U32		3
+#define	TCF_EM_META		4
+#define	TCF_EM_TEXT		5
+#define        TCF_EM_VLAN		6
+#define	TCF_EM_MAX		6
+
+enum {
+	TCF_EM_PROG_TC
+};
+
+enum {
+	TCF_EM_OPND_EQ,
+	TCF_EM_OPND_GT,
+	TCF_EM_OPND_LT
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/linux/pkt_sched.h b/libnetwork/libnl3/include/linux/pkt_sched.h
new file mode 100644
index 0000000..c533670
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/pkt_sched.h
@@ -0,0 +1,606 @@
+#ifndef __LINUX_PKT_SCHED_H
+#define __LINUX_PKT_SCHED_H
+
+#include <linux/types.h>
+
+/* Logical priority bands not depending on specific packet scheduler.
+   Every scheduler will map them to real traffic classes, if it has
+   no more precise mechanism to classify packets.
+
+   These numbers have no special meaning, though their coincidence
+   with obsolete IPv6 values is not occasional :-). New IPv6 drafts
+   preferred full anarchy inspired by diffserv group.
+
+   Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy
+   class, actually, as rule it will be handled with more care than
+   filler or even bulk.
+ */
+
+#define TC_PRIO_BESTEFFORT		0
+#define TC_PRIO_FILLER			1
+#define TC_PRIO_BULK			2
+#define TC_PRIO_INTERACTIVE_BULK	4
+#define TC_PRIO_INTERACTIVE		6
+#define TC_PRIO_CONTROL			7
+
+#define TC_PRIO_MAX			15
+
+/* Generic queue statistics, available for all the elements.
+   Particular schedulers may have also their private records.
+ */
+
+struct tc_stats {
+	__u64	bytes;			/* NUmber of enqueues bytes */
+	__u32	packets;		/* Number of enqueued packets	*/
+	__u32	drops;			/* Packets dropped because of lack of resources */
+	__u32	overlimits;		/* Number of throttle events when this
+					 * flow goes out of allocated bandwidth */
+	__u32	bps;			/* Current flow byte rate */
+	__u32	pps;			/* Current flow packet rate */
+	__u32	qlen;
+	__u32	backlog;
+};
+
+struct tc_estimator {
+	signed char	interval;
+	unsigned char	ewma_log;
+};
+
+/* "Handles"
+   ---------
+
+    All the traffic control objects have 32bit identifiers, or "handles".
+
+    They can be considered as opaque numbers from user API viewpoint,
+    but actually they always consist of two fields: major and
+    minor numbers, which are interpreted by kernel specially,
+    that may be used by applications, though not recommended.
+
+    F.e. qdisc handles always have minor number equal to zero,
+    classes (or flows) have major equal to parent qdisc major, and
+    minor uniquely identifying class inside qdisc.
+
+    Macros to manipulate handles:
+ */
+
+#define TC_H_MAJ_MASK (0xFFFF0000U)
+#define TC_H_MIN_MASK (0x0000FFFFU)
+#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK)
+#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK)
+#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
+
+#define TC_H_UNSPEC	(0U)
+#define TC_H_ROOT	(0xFFFFFFFFU)
+#define TC_H_INGRESS    (0xFFFFFFF1U)
+
+struct tc_ratespec {
+	unsigned char	cell_log;
+	unsigned char	__reserved;
+	unsigned short	overhead;
+	short		cell_align;
+	unsigned short	mpu;
+	__u32		rate;
+};
+
+#define TC_RTAB_SIZE	1024
+
+struct tc_sizespec {
+	unsigned char	cell_log;
+	unsigned char	size_log;
+	short		cell_align;
+	int		overhead;
+	unsigned int	linklayer;
+	unsigned int	mpu;
+	unsigned int	mtu;
+	unsigned int	tsize;
+};
+
+enum {
+	TCA_STAB_UNSPEC,
+	TCA_STAB_BASE,
+	TCA_STAB_DATA,
+	__TCA_STAB_MAX
+};
+
+#define TCA_STAB_MAX (__TCA_STAB_MAX - 1)
+
+/* FIFO section */
+
+struct tc_fifo_qopt {
+	__u32	limit;	/* Queue length: bytes for bfifo, packets for pfifo */
+};
+
+/* PRIO section */
+
+#define TCQ_PRIO_BANDS	16
+#define TCQ_MIN_PRIO_BANDS 2
+
+struct tc_prio_qopt {
+	int	bands;			/* Number of bands */
+	__u8	priomap[TC_PRIO_MAX+1];	/* Map: logical priority -> PRIO band */
+};
+
+/* MULTIQ section */
+
+struct tc_multiq_qopt {
+	__u16	bands;			/* Number of bands */
+	__u16	max_bands;		/* Maximum number of queues */
+};
+
+/* TBF section */
+
+struct tc_tbf_qopt {
+	struct tc_ratespec rate;
+	struct tc_ratespec peakrate;
+	__u32		limit;
+	__u32		buffer;
+	__u32		mtu;
+};
+
+enum {
+	TCA_TBF_UNSPEC,
+	TCA_TBF_PARMS,
+	TCA_TBF_RTAB,
+	TCA_TBF_PTAB,
+	__TCA_TBF_MAX,
+};
+
+#define TCA_TBF_MAX (__TCA_TBF_MAX - 1)
+
+
+/* TEQL section */
+
+/* TEQL does not require any parameters */
+
+/* SFQ section */
+
+struct tc_sfq_qopt {
+	unsigned	quantum;	/* Bytes per round allocated to flow */
+	int		perturb_period;	/* Period of hash perturbation */
+	__u32		limit;		/* Maximal packets in queue */
+	unsigned	divisor;	/* Hash divisor  */
+	unsigned	flows;		/* Maximal number of flows  */
+};
+
+struct tc_sfq_xstats {
+	__s32		allot;
+};
+
+/*
+ *  NOTE: limit, divisor and flows are hardwired to code at the moment.
+ *
+ *	limit=flows=128, divisor=1024;
+ *
+ *	The only reason for this is efficiency, it is possible
+ *	to change these parameters in compile time.
+ */
+
+/* RED section */
+
+enum {
+	TCA_RED_UNSPEC,
+	TCA_RED_PARMS,
+	TCA_RED_STAB,
+	__TCA_RED_MAX,
+};
+
+#define TCA_RED_MAX (__TCA_RED_MAX - 1)
+
+struct tc_red_qopt {
+	__u32		limit;		/* HARD maximal queue length (bytes)	*/
+	__u32		qth_min;	/* Min average length threshold (bytes) */
+	__u32		qth_max;	/* Max average length threshold (bytes) */
+	unsigned char   Wlog;		/* log(W)		*/
+	unsigned char   Plog;		/* log(P_max/(qth_max-qth_min))	*/
+	unsigned char   Scell_log;	/* cell size for idle damping */
+	unsigned char	flags;
+#define TC_RED_ECN	1
+#define TC_RED_HARDDROP	2
+};
+
+struct tc_red_xstats {
+	__u32           early;          /* Early drops */
+	__u32           pdrop;          /* Drops due to queue limits */
+	__u32           other;          /* Drops due to drop() calls */
+	__u32           marked;         /* Marked packets */
+};
+
+/* GRED section */
+
+#define MAX_DPs 16
+
+enum {
+       TCA_GRED_UNSPEC,
+       TCA_GRED_PARMS,
+       TCA_GRED_STAB,
+       TCA_GRED_DPS,
+	   __TCA_GRED_MAX,
+};
+
+#define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
+
+struct tc_gred_qopt {
+	__u32		limit;        /* HARD maximal queue length (bytes)    */
+	__u32		qth_min;      /* Min average length threshold (bytes) */
+	__u32		qth_max;      /* Max average length threshold (bytes) */
+	__u32		DP;           /* up to 2^32 DPs */
+	__u32		backlog;
+	__u32		qave;
+	__u32		forced;
+	__u32		early;
+	__u32		other;
+	__u32		pdrop;
+	__u8		Wlog;         /* log(W)               */
+	__u8		Plog;         /* log(P_max/(qth_max-qth_min)) */
+	__u8		Scell_log;    /* cell size for idle damping */
+	__u8		prio;         /* prio of this VQ */
+	__u32		packets;
+	__u32		bytesin;
+};
+
+/* gred setup */
+struct tc_gred_sopt {
+	__u32		DPs;
+	__u32		def_DP;
+	__u8		grio;
+	__u8		flags;
+	__u16		pad1;
+};
+
+/* CHOKe section */
+
+enum {
+	TCA_CHOKE_UNSPEC,
+	TCA_CHOKE_PARMS,
+	TCA_CHOKE_STAB,
+	__TCA_CHOKE_MAX,
+};
+
+#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1)
+
+struct tc_choke_qopt {
+	__u32		limit;		/* Hard queue length (packets)	*/
+	__u32		qth_min;	/* Min average threshold (packets) */
+	__u32		qth_max;	/* Max average threshold (packets) */
+	unsigned char   Wlog;		/* log(W)		*/
+	unsigned char   Plog;		/* log(P_max/(qth_max-qth_min))	*/
+	unsigned char   Scell_log;	/* cell size for idle damping */
+	unsigned char	flags;		/* see RED flags */
+};
+
+struct tc_choke_xstats {
+	__u32		early;          /* Early drops */
+	__u32		pdrop;          /* Drops due to queue limits */
+	__u32		other;          /* Drops due to drop() calls */
+	__u32		marked;         /* Marked packets */
+	__u32		matched;	/* Drops due to flow match */
+};
+
+/* HTB section */
+#define TC_HTB_NUMPRIO		8
+#define TC_HTB_MAXDEPTH		8
+#define TC_HTB_PROTOVER		3 /* the same as HTB and TC's major */
+
+struct tc_htb_opt {
+	struct tc_ratespec 	rate;
+	struct tc_ratespec 	ceil;
+	__u32	buffer;
+	__u32	cbuffer;
+	__u32	quantum;
+	__u32	level;		/* out only */
+	__u32	prio;
+};
+struct tc_htb_glob {
+	__u32 version;		/* to match HTB/TC */
+    	__u32 rate2quantum;	/* bps->quantum divisor */
+    	__u32 defcls;		/* default class number */
+	__u32 debug;		/* debug flags */
+
+	/* stats */
+	__u32 direct_pkts; /* count of non shapped packets */
+};
+enum {
+	TCA_HTB_UNSPEC,
+	TCA_HTB_PARMS,
+	TCA_HTB_INIT,
+	TCA_HTB_CTAB,
+	TCA_HTB_RTAB,
+	__TCA_HTB_MAX,
+};
+
+#define TCA_HTB_MAX (__TCA_HTB_MAX - 1)
+
+struct tc_htb_xstats {
+	__u32 lends;
+	__u32 borrows;
+	__u32 giants;	/* too big packets (rate will not be accurate) */
+	__u32 tokens;
+	__u32 ctokens;
+};
+
+/* HFSC section */
+
+struct tc_hfsc_qopt {
+	__u16	defcls;		/* default class */
+};
+
+struct tc_service_curve {
+	__u32	m1;		/* slope of the first segment in bps */
+	__u32	d;		/* x-projection of the first segment in us */
+	__u32	m2;		/* slope of the second segment in bps */
+};
+
+struct tc_hfsc_stats {
+	__u64	work;		/* total work done */
+	__u64	rtwork;		/* work done by real-time criteria */
+	__u32	period;		/* current period */
+	__u32	level;		/* class level in hierarchy */
+};
+
+enum {
+	TCA_HFSC_UNSPEC,
+	TCA_HFSC_RSC,
+	TCA_HFSC_FSC,
+	TCA_HFSC_USC,
+	__TCA_HFSC_MAX,
+};
+
+#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1)
+
+
+/* CBQ section */
+
+#define TC_CBQ_MAXPRIO		8
+#define TC_CBQ_MAXLEVEL		8
+#define TC_CBQ_DEF_EWMA		5
+
+struct tc_cbq_lssopt {
+	unsigned char	change;
+	unsigned char	flags;
+#define TCF_CBQ_LSS_BOUNDED	1
+#define TCF_CBQ_LSS_ISOLATED	2
+	unsigned char  	ewma_log;
+	unsigned char  	level;
+#define TCF_CBQ_LSS_FLAGS	1
+#define TCF_CBQ_LSS_EWMA	2
+#define TCF_CBQ_LSS_MAXIDLE	4
+#define TCF_CBQ_LSS_MINIDLE	8
+#define TCF_CBQ_LSS_OFFTIME	0x10
+#define TCF_CBQ_LSS_AVPKT	0x20
+	__u32		maxidle;
+	__u32		minidle;
+	__u32		offtime;
+	__u32		avpkt;
+};
+
+struct tc_cbq_wrropt {
+	unsigned char	flags;
+	unsigned char	priority;
+	unsigned char	cpriority;
+	unsigned char	__reserved;
+	__u32		allot;
+	__u32		weight;
+};
+
+struct tc_cbq_ovl {
+	unsigned char	strategy;
+#define	TC_CBQ_OVL_CLASSIC	0
+#define	TC_CBQ_OVL_DELAY	1
+#define	TC_CBQ_OVL_LOWPRIO	2
+#define	TC_CBQ_OVL_DROP		3
+#define	TC_CBQ_OVL_RCLASSIC	4
+	unsigned char	priority2;
+	__u16		pad;
+	__u32		penalty;
+};
+
+struct tc_cbq_police {
+	unsigned char	police;
+	unsigned char	__res1;
+	unsigned short	__res2;
+};
+
+struct tc_cbq_fopt {
+	__u32		split;
+	__u32		defmap;
+	__u32		defchange;
+};
+
+struct tc_cbq_xstats {
+	__u32		borrows;
+	__u32		overactions;
+	__s32		avgidle;
+	__s32		undertime;
+};
+
+enum {
+	TCA_CBQ_UNSPEC,
+	TCA_CBQ_LSSOPT,
+	TCA_CBQ_WRROPT,
+	TCA_CBQ_FOPT,
+	TCA_CBQ_OVL_STRATEGY,
+	TCA_CBQ_RATE,
+	TCA_CBQ_RTAB,
+	TCA_CBQ_POLICE,
+	__TCA_CBQ_MAX,
+};
+
+#define TCA_CBQ_MAX	(__TCA_CBQ_MAX - 1)
+
+/* dsmark section */
+
+enum {
+	TCA_DSMARK_UNSPEC,
+	TCA_DSMARK_INDICES,
+	TCA_DSMARK_DEFAULT_INDEX,
+	TCA_DSMARK_SET_TC_INDEX,
+	TCA_DSMARK_MASK,
+	TCA_DSMARK_VALUE,
+	__TCA_DSMARK_MAX,
+};
+
+#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1)
+
+/* ATM  section */
+
+enum {
+	TCA_ATM_UNSPEC,
+	TCA_ATM_FD,		/* file/socket descriptor */
+	TCA_ATM_PTR,		/* pointer to descriptor - later */
+	TCA_ATM_HDR,		/* LL header */
+	TCA_ATM_EXCESS,		/* excess traffic class (0 for CLP)  */
+	TCA_ATM_ADDR,		/* PVC address (for output only) */
+	TCA_ATM_STATE,		/* VC state (ATM_VS_*; for output only) */
+	__TCA_ATM_MAX,
+};
+
+#define TCA_ATM_MAX	(__TCA_ATM_MAX - 1)
+
+/* Network emulator */
+
+enum {
+	TCA_NETEM_UNSPEC,
+	TCA_NETEM_CORR,
+	TCA_NETEM_DELAY_DIST,
+	TCA_NETEM_REORDER,
+	TCA_NETEM_CORRUPT,
+	TCA_NETEM_LOSS,
+	__TCA_NETEM_MAX,
+};
+
+#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1)
+
+struct tc_netem_qopt {
+	__u32	latency;	/* added delay (us) */
+	__u32   limit;		/* fifo limit (packets) */
+	__u32	loss;		/* random packet loss (0=none ~0=100%) */
+	__u32	gap;		/* re-ordering gap (0 for none) */
+	__u32   duplicate;	/* random packet dup  (0=none ~0=100%) */
+	__u32	jitter;		/* random jitter in latency (us) */
+};
+
+struct tc_netem_corr {
+	__u32	delay_corr;	/* delay correlation */
+	__u32	loss_corr;	/* packet loss correlation */
+	__u32	dup_corr;	/* duplicate correlation  */
+};
+
+struct tc_netem_reorder {
+	__u32	probability;
+	__u32	correlation;
+};
+
+struct tc_netem_corrupt {
+	__u32	probability;
+	__u32	correlation;
+};
+
+enum {
+	NETEM_LOSS_UNSPEC,
+	NETEM_LOSS_GI,		/* General Intuitive - 4 state model */
+	NETEM_LOSS_GE,		/* Gilbert Elliot models */
+	__NETEM_LOSS_MAX
+};
+#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1)
+
+/* State transition probablities for 4 state model */
+struct tc_netem_gimodel {
+	__u32	p13;
+	__u32	p31;
+	__u32	p32;
+	__u32	p14;
+	__u32	p23;
+};
+
+/* Gilbert-Elliot models */
+struct tc_netem_gemodel {
+	__u32 p;
+	__u32 r;
+	__u32 h;
+	__u32 k1;
+};
+
+#define NETEM_DIST_SCALE	8192
+#define NETEM_DIST_MAX		16384
+
+/* DRR */
+
+enum {
+	TCA_DRR_UNSPEC,
+	TCA_DRR_QUANTUM,
+	__TCA_DRR_MAX
+};
+
+#define TCA_DRR_MAX	(__TCA_DRR_MAX - 1)
+
+struct tc_drr_stats {
+	__u32	deficit;
+};
+
+/* MQPRIO */
+#define TC_QOPT_BITMASK 15
+#define TC_QOPT_MAX_QUEUE 16
+
+struct tc_mqprio_qopt {
+	__u8	num_tc;
+	__u8	prio_tc_map[TC_QOPT_BITMASK + 1];
+	__u8	hw;
+	__u16	count[TC_QOPT_MAX_QUEUE];
+	__u16	offset[TC_QOPT_MAX_QUEUE];
+};
+
+/* SFB */
+
+enum {
+	TCA_SFB_UNSPEC,
+	TCA_SFB_PARMS,
+	__TCA_SFB_MAX,
+};
+
+#define TCA_SFB_MAX (__TCA_SFB_MAX - 1)
+
+/*
+ * Note: increment, decrement are Q0.16 fixed-point values.
+ */
+struct tc_sfb_qopt {
+	__u32 rehash_interval;	/* delay between hash move, in ms */
+	__u32 warmup_time;	/* double buffering warmup time in ms (warmup_time < rehash_interval) */
+	__u32 max;		/* max len of qlen_min */
+	__u32 bin_size;		/* maximum queue length per bin */
+	__u32 increment;	/* probability increment, (d1 in Blue) */
+	__u32 decrement;	/* probability decrement, (d2 in Blue) */
+	__u32 limit;		/* max SFB queue length */
+	__u32 penalty_rate;	/* inelastic flows are rate limited to 'rate' pps */
+	__u32 penalty_burst;
+};
+
+struct tc_sfb_xstats {
+	__u32 earlydrop;
+	__u32 penaltydrop;
+	__u32 bucketdrop;
+	__u32 queuedrop;
+	__u32 childdrop; /* drops in child qdisc */
+	__u32 marked;
+	__u32 maxqlen;
+	__u32 maxprob;
+	__u32 avgprob;
+};
+
+#define SFB_MAX_PROB 0xFFFF
+
+/* QFQ */
+enum {
+	TCA_QFQ_UNSPEC,
+	TCA_QFQ_WEIGHT,
+	TCA_QFQ_LMAX,
+	__TCA_QFQ_MAX
+};
+
+#define TCA_QFQ_MAX	(__TCA_QFQ_MAX - 1)
+
+struct tc_qfq_stats {
+	__u32 weight;
+	__u32 lmax;
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/linux/rtnetlink.h b/libnetwork/libnl3/include/linux/rtnetlink.h
new file mode 100644
index 0000000..2363c18
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/rtnetlink.h
@@ -0,0 +1,605 @@
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+
+/* rtnetlink families. Values up to 127 are reserved for real address
+ * families, values above 128 may be used arbitrarily.
+ */
+#define RTNL_FAMILY_IPMR		128
+#define RTNL_FAMILY_IP6MR		129
+#define RTNL_FAMILY_MAX			129
+
+/****
+ *		Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+enum {
+	RTM_BASE	= 16,
+#define RTM_BASE	RTM_BASE
+
+	RTM_NEWLINK	= 16,
+#define RTM_NEWLINK	RTM_NEWLINK
+	RTM_DELLINK,
+#define RTM_DELLINK	RTM_DELLINK
+	RTM_GETLINK,
+#define RTM_GETLINK	RTM_GETLINK
+	RTM_SETLINK,
+#define RTM_SETLINK	RTM_SETLINK
+
+	RTM_NEWADDR	= 20,
+#define RTM_NEWADDR	RTM_NEWADDR
+	RTM_DELADDR,
+#define RTM_DELADDR	RTM_DELADDR
+	RTM_GETADDR,
+#define RTM_GETADDR	RTM_GETADDR
+
+	RTM_NEWROUTE	= 24,
+#define RTM_NEWROUTE	RTM_NEWROUTE
+	RTM_DELROUTE,
+#define RTM_DELROUTE	RTM_DELROUTE
+	RTM_GETROUTE,
+#define RTM_GETROUTE	RTM_GETROUTE
+
+	RTM_NEWNEIGH	= 28,
+#define RTM_NEWNEIGH	RTM_NEWNEIGH
+	RTM_DELNEIGH,
+#define RTM_DELNEIGH	RTM_DELNEIGH
+	RTM_GETNEIGH,
+#define RTM_GETNEIGH	RTM_GETNEIGH
+
+	RTM_NEWRULE	= 32,
+#define RTM_NEWRULE	RTM_NEWRULE
+	RTM_DELRULE,
+#define RTM_DELRULE	RTM_DELRULE
+	RTM_GETRULE,
+#define RTM_GETRULE	RTM_GETRULE
+
+	RTM_NEWQDISC	= 36,
+#define RTM_NEWQDISC	RTM_NEWQDISC
+	RTM_DELQDISC,
+#define RTM_DELQDISC	RTM_DELQDISC
+	RTM_GETQDISC,
+#define RTM_GETQDISC	RTM_GETQDISC
+
+	RTM_NEWTCLASS	= 40,
+#define RTM_NEWTCLASS	RTM_NEWTCLASS
+	RTM_DELTCLASS,
+#define RTM_DELTCLASS	RTM_DELTCLASS
+	RTM_GETTCLASS,
+#define RTM_GETTCLASS	RTM_GETTCLASS
+
+	RTM_NEWTFILTER	= 44,
+#define RTM_NEWTFILTER	RTM_NEWTFILTER
+	RTM_DELTFILTER,
+#define RTM_DELTFILTER	RTM_DELTFILTER
+	RTM_GETTFILTER,
+#define RTM_GETTFILTER	RTM_GETTFILTER
+
+	RTM_NEWACTION	= 48,
+#define RTM_NEWACTION   RTM_NEWACTION
+	RTM_DELACTION,
+#define RTM_DELACTION   RTM_DELACTION
+	RTM_GETACTION,
+#define RTM_GETACTION   RTM_GETACTION
+
+	RTM_NEWPREFIX	= 52,
+#define RTM_NEWPREFIX	RTM_NEWPREFIX
+
+	RTM_GETMULTICAST = 58,
+#define RTM_GETMULTICAST RTM_GETMULTICAST
+
+	RTM_GETANYCAST	= 62,
+#define RTM_GETANYCAST	RTM_GETANYCAST
+
+	RTM_NEWNEIGHTBL	= 64,
+#define RTM_NEWNEIGHTBL	RTM_NEWNEIGHTBL
+	RTM_GETNEIGHTBL	= 66,
+#define RTM_GETNEIGHTBL	RTM_GETNEIGHTBL
+	RTM_SETNEIGHTBL,
+#define RTM_SETNEIGHTBL	RTM_SETNEIGHTBL
+
+	RTM_NEWNDUSEROPT = 68,
+#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT
+
+	RTM_NEWADDRLABEL = 72,
+#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL
+	RTM_DELADDRLABEL,
+#define RTM_DELADDRLABEL RTM_DELADDRLABEL
+	RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
+	RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+	RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
+	__RTM_MAX,
+#define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
+};
+
+#define RTM_NR_MSGTYPES	(RTM_MAX + 1 - RTM_BASE)
+#define RTM_NR_FAMILIES	(RTM_NR_MSGTYPES >> 2)
+#define RTM_FAM(cmd)	(((cmd) - RTM_BASE) >> 2)
+
+/* 
+   Generic structure for encapsulation of optional route information.
+   It is reminiscent of sockaddr, but with sa_family replaced
+   with attribute type.
+ */
+
+struct rtattr {
+	unsigned short	rta_len;
+	unsigned short	rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO	4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
+			 (rta)->rta_len >= sizeof(struct rtattr) && \
+			 (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen)	((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+				 (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len)	(RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len)	RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta)   ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ *		Definitions used in routing table administration.
+ ****/
+
+struct rtmsg {
+	unsigned char		rtm_family;
+	unsigned char		rtm_dst_len;
+	unsigned char		rtm_src_len;
+	unsigned char		rtm_tos;
+
+	unsigned char		rtm_table;	/* Routing table id */
+	unsigned char		rtm_protocol;	/* Routing protocol; see below	*/
+	unsigned char		rtm_scope;	/* See below */	
+	unsigned char		rtm_type;	/* See below	*/
+
+	unsigned		rtm_flags;
+};
+
+/* rtm_type */
+
+enum {
+	RTN_UNSPEC,
+	RTN_UNICAST,		/* Gateway or direct route	*/
+	RTN_LOCAL,		/* Accept locally		*/
+	RTN_BROADCAST,		/* Accept locally as broadcast,
+				   send as broadcast */
+	RTN_ANYCAST,		/* Accept locally as broadcast,
+				   but send as unicast */
+	RTN_MULTICAST,		/* Multicast route		*/
+	RTN_BLACKHOLE,		/* Drop				*/
+	RTN_UNREACHABLE,	/* Destination is unreachable   */
+	RTN_PROHIBIT,		/* Administratively prohibited	*/
+	RTN_THROW,		/* Not in this table		*/
+	RTN_NAT,		/* Translate this address	*/
+	RTN_XRESOLVE,		/* Use external resolver	*/
+	__RTN_MAX
+};
+
+#define RTN_MAX (__RTN_MAX - 1)
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC	0
+#define RTPROT_REDIRECT	1	/* Route installed by ICMP redirects;
+				   not used by current IPv4 */
+#define RTPROT_KERNEL	2	/* Route installed by kernel		*/
+#define RTPROT_BOOT	3	/* Route installed during boot		*/
+#define RTPROT_STATIC	4	/* Route installed by administrator	*/
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+   they are just passed from user and back as is.
+   It will be used by hypothetical multiple routing daemons.
+   Note that protocol values should be standardized in order to
+   avoid conflicts.
+ */
+
+#define RTPROT_GATED	8	/* Apparently, GateD */
+#define RTPROT_RA	9	/* RDISC/ND router advertisements */
+#define RTPROT_MRT	10	/* Merit MRT */
+#define RTPROT_ZEBRA	11	/* Zebra */
+#define RTPROT_BIRD	12	/* BIRD */
+#define RTPROT_DNROUTED	13	/* DECnet routing daemon */
+#define RTPROT_XORP	14	/* XORP */
+#define RTPROT_NTK	15	/* Netsukuku */
+#define RTPROT_DHCP	16      /* DHCP client */
+
+/* rtm_scope
+
+   Really it is not scope, but sort of distance to the destination.
+   NOWHERE are reserved for not existing destinations, HOST is our
+   local addresses, LINK are destinations, located on directly attached
+   link and UNIVERSE is everywhere in the Universe.
+
+   Intermediate values are also possible f.e. interior routes
+   could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t {
+	RT_SCOPE_UNIVERSE=0,
+/* User defined values  */
+	RT_SCOPE_SITE=200,
+	RT_SCOPE_LINK=253,
+	RT_SCOPE_HOST=254,
+	RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY		0x100	/* Notify user of route change	*/
+#define RTM_F_CLONED		0x200	/* This route is cloned		*/
+#define RTM_F_EQUALIZE		0x400	/* Multipath equalizer: NI	*/
+#define RTM_F_PREFIX		0x800	/* Prefix addresses		*/
+
+/* Reserved table identifiers */
+
+enum rt_class_t {
+	RT_TABLE_UNSPEC=0,
+/* User defined values */
+	RT_TABLE_COMPAT=252,
+	RT_TABLE_DEFAULT=253,
+	RT_TABLE_MAIN=254,
+	RT_TABLE_LOCAL=255,
+	RT_TABLE_MAX=0xFFFFFFFF
+};
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t {
+	RTA_UNSPEC,
+	RTA_DST,
+	RTA_SRC,
+	RTA_IIF,
+	RTA_OIF,
+	RTA_GATEWAY,
+	RTA_PRIORITY,
+	RTA_PREFSRC,
+	RTA_METRICS,
+	RTA_MULTIPATH,
+	RTA_PROTOINFO, /* no longer used */
+	RTA_FLOW,
+	RTA_CACHEINFO,
+	RTA_SESSION, /* no longer used */
+	RTA_MP_ALGO, /* no longer used */
+	RTA_TABLE,
+	RTA_MARK,
+	__RTA_MAX
+};
+
+#define RTA_MAX (__RTA_MAX - 1)
+
+#define RTM_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describes all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nexthop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop {
+	unsigned short		rtnh_len;
+	unsigned char		rtnh_flags;
+	unsigned char		rtnh_hops;
+	int			rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD		1	/* Nexthop is dead (used by multipath)	*/
+#define RTNH_F_PERVASIVE	2	/* Do recursive gateway lookup	*/
+#define RTNH_F_ONLINK		4	/* Gateway is forced on link	*/
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO	4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+			   ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh)	((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len)	RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh)   ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo {
+	__u32	rta_clntref;
+	__u32	rta_lastuse;
+	__s32	rta_expires;
+	__u32	rta_error;
+	__u32	rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+	__u32	rta_id;
+	__u32	rta_ts;
+	__u32	rta_tsage;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum {
+	RTAX_UNSPEC,
+#define RTAX_UNSPEC RTAX_UNSPEC
+	RTAX_LOCK,
+#define RTAX_LOCK RTAX_LOCK
+	RTAX_MTU,
+#define RTAX_MTU RTAX_MTU
+	RTAX_WINDOW,
+#define RTAX_WINDOW RTAX_WINDOW
+	RTAX_RTT,
+#define RTAX_RTT RTAX_RTT
+	RTAX_RTTVAR,
+#define RTAX_RTTVAR RTAX_RTTVAR
+	RTAX_SSTHRESH,
+#define RTAX_SSTHRESH RTAX_SSTHRESH
+	RTAX_CWND,
+#define RTAX_CWND RTAX_CWND
+	RTAX_ADVMSS,
+#define RTAX_ADVMSS RTAX_ADVMSS
+	RTAX_REORDERING,
+#define RTAX_REORDERING RTAX_REORDERING
+	RTAX_HOPLIMIT,
+#define RTAX_HOPLIMIT RTAX_HOPLIMIT
+	RTAX_INITCWND,
+#define RTAX_INITCWND RTAX_INITCWND
+	RTAX_FEATURES,
+#define RTAX_FEATURES RTAX_FEATURES
+	RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
+	RTAX_INITRWND,
+#define RTAX_INITRWND RTAX_INITRWND
+	__RTAX_MAX
+};
+
+#define RTAX_MAX (__RTAX_MAX - 1)
+
+#define RTAX_FEATURE_ECN	0x00000001
+#define RTAX_FEATURE_SACK	0x00000002
+#define RTAX_FEATURE_TIMESTAMP	0x00000004
+#define RTAX_FEATURE_ALLFRAG	0x00000008
+
+struct rta_session {
+	__u8	proto;
+	__u8	pad1;
+	__u16	pad2;
+
+	union {
+		struct {
+			__u16	sport;
+			__u16	dport;
+		} ports;
+
+		struct {
+			__u8	type;
+			__u8	code;
+			__u16	ident;
+		} icmpt;
+
+		__u32		spi;
+	} u;
+};
+
+/****
+ *		General form of address family dependent message.
+ ****/
+
+struct rtgenmsg {
+	unsigned char		rtgen_family;
+};
+
+/*****************************************************************
+ *		Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg {
+	unsigned char	ifi_family;
+	unsigned char	__ifi_pad;
+	unsigned short	ifi_type;		/* ARPHRD_* */
+	int		ifi_index;		/* Link index	*/
+	unsigned	ifi_flags;		/* IFF_* flags	*/
+	unsigned	ifi_change;		/* IFF_* change mask */
+};
+
+/********************************************************************
+ *		prefix information 
+ ****/
+
+struct prefixmsg {
+	unsigned char	prefix_family;
+	unsigned char	prefix_pad1;
+	unsigned short	prefix_pad2;
+	int		prefix_ifindex;
+	unsigned char	prefix_type;
+	unsigned char	prefix_len;
+	unsigned char	prefix_flags;
+	unsigned char	prefix_pad3;
+};
+
+enum 
+{
+	PREFIX_UNSPEC,
+	PREFIX_ADDRESS,
+	PREFIX_CACHEINFO,
+	__PREFIX_MAX
+};
+
+#define PREFIX_MAX	(__PREFIX_MAX - 1)
+
+struct prefix_cacheinfo {
+	__u32	preferred_time;
+	__u32	valid_time;
+};
+
+
+/*****************************************************************
+ *		Traffic control messages.
+ ****/
+
+struct tcmsg {
+	unsigned char	tcm_family;
+	unsigned char	tcm__pad1;
+	unsigned short	tcm__pad2;
+	int		tcm_ifindex;
+	__u32		tcm_handle;
+	__u32		tcm_parent;
+	__u32		tcm_info;
+};
+
+enum {
+	TCA_UNSPEC,
+	TCA_KIND,
+	TCA_OPTIONS,
+	TCA_STATS,
+	TCA_XSTATS,
+	TCA_RATE,
+	TCA_FCNT,
+	TCA_STATS2,
+	TCA_STAB,
+	__TCA_MAX
+};
+
+#define TCA_MAX (__TCA_MAX - 1)
+
+#define TCA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+/********************************************************************
+ *		Neighbor Discovery userland options
+ ****/
+
+struct nduseroptmsg {
+	unsigned char	nduseropt_family;
+	unsigned char	nduseropt_pad1;
+	unsigned short	nduseropt_opts_len;	/* Total length of options */
+	int		nduseropt_ifindex;
+	__u8		nduseropt_icmp_type;
+	__u8		nduseropt_icmp_code;
+	unsigned short	nduseropt_pad2;
+	unsigned int	nduseropt_pad3;
+	/* Followed by one or more ND options */
+};
+
+enum {
+	NDUSEROPT_UNSPEC,
+	NDUSEROPT_SRCADDR,
+	__NDUSEROPT_MAX
+};
+
+#define NDUSEROPT_MAX	(__NDUSEROPT_MAX - 1)
+
+#ifndef __KERNEL__
+/* RTnetlink multicast groups - backwards compatibility for userspace */
+#define RTMGRP_LINK		1
+#define RTMGRP_NOTIFY		2
+#define RTMGRP_NEIGH		4
+#define RTMGRP_TC		8
+
+#define RTMGRP_IPV4_IFADDR	0x10
+#define RTMGRP_IPV4_MROUTE	0x20
+#define RTMGRP_IPV4_ROUTE	0x40
+#define RTMGRP_IPV4_RULE	0x80
+
+#define RTMGRP_IPV6_IFADDR	0x100
+#define RTMGRP_IPV6_MROUTE	0x200
+#define RTMGRP_IPV6_ROUTE	0x400
+#define RTMGRP_IPV6_IFINFO	0x800
+
+#define RTMGRP_DECnet_IFADDR    0x1000
+#define RTMGRP_DECnet_ROUTE     0x4000
+
+#define RTMGRP_IPV6_PREFIX	0x20000
+#endif
+
+/* RTnetlink multicast groups */
+enum rtnetlink_groups {
+	RTNLGRP_NONE,
+#define RTNLGRP_NONE		RTNLGRP_NONE
+	RTNLGRP_LINK,
+#define RTNLGRP_LINK		RTNLGRP_LINK
+	RTNLGRP_NOTIFY,
+#define RTNLGRP_NOTIFY		RTNLGRP_NOTIFY
+	RTNLGRP_NEIGH,
+#define RTNLGRP_NEIGH		RTNLGRP_NEIGH
+	RTNLGRP_TC,
+#define RTNLGRP_TC		RTNLGRP_TC
+	RTNLGRP_IPV4_IFADDR,
+#define RTNLGRP_IPV4_IFADDR	RTNLGRP_IPV4_IFADDR
+	RTNLGRP_IPV4_MROUTE,
+#define	RTNLGRP_IPV4_MROUTE	RTNLGRP_IPV4_MROUTE
+	RTNLGRP_IPV4_ROUTE,
+#define RTNLGRP_IPV4_ROUTE	RTNLGRP_IPV4_ROUTE
+	RTNLGRP_IPV4_RULE,
+#define RTNLGRP_IPV4_RULE	RTNLGRP_IPV4_RULE
+	RTNLGRP_IPV6_IFADDR,
+#define RTNLGRP_IPV6_IFADDR	RTNLGRP_IPV6_IFADDR
+	RTNLGRP_IPV6_MROUTE,
+#define RTNLGRP_IPV6_MROUTE	RTNLGRP_IPV6_MROUTE
+	RTNLGRP_IPV6_ROUTE,
+#define RTNLGRP_IPV6_ROUTE	RTNLGRP_IPV6_ROUTE
+	RTNLGRP_IPV6_IFINFO,
+#define RTNLGRP_IPV6_IFINFO	RTNLGRP_IPV6_IFINFO
+	RTNLGRP_DECnet_IFADDR,
+#define RTNLGRP_DECnet_IFADDR	RTNLGRP_DECnet_IFADDR
+	RTNLGRP_NOP2,
+	RTNLGRP_DECnet_ROUTE,
+#define RTNLGRP_DECnet_ROUTE	RTNLGRP_DECnet_ROUTE
+	RTNLGRP_DECnet_RULE,
+#define RTNLGRP_DECnet_RULE	RTNLGRP_DECnet_RULE
+	RTNLGRP_NOP4,
+	RTNLGRP_IPV6_PREFIX,
+#define RTNLGRP_IPV6_PREFIX	RTNLGRP_IPV6_PREFIX
+	RTNLGRP_IPV6_RULE,
+#define RTNLGRP_IPV6_RULE	RTNLGRP_IPV6_RULE
+	RTNLGRP_ND_USEROPT,
+#define RTNLGRP_ND_USEROPT	RTNLGRP_ND_USEROPT
+	RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR	RTNLGRP_PHONET_IFADDR
+	RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE	RTNLGRP_PHONET_ROUTE
+	__RTNLGRP_MAX
+};
+#define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
+
+/* TC action piece */
+struct tcamsg {
+	unsigned char	tca_family;
+	unsigned char	tca__pad1;
+	unsigned short	tca__pad2;
+};
+#define TA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
+#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
+#define TCA_ACT_TAB 1 /* attr type must be >=1 */	
+#define TCAA_MAX 1
+
+/* End of information exported to user level */
+
+#endif	/* __LINUX_RTNETLINK_H */
diff --git a/libnetwork/libnl3/include/linux/snmp.h b/libnetwork/libnl3/include/linux/snmp.h
new file mode 100644
index 0000000..12b2b18
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/snmp.h
@@ -0,0 +1,270 @@
+/*
+ * Definitions for MIBs
+ *
+ * Author: Hideaki YOSHIFUJI <yoshfuji at linux-ipv6.org>
+ */
+
+#ifndef _LINUX_SNMP_H
+#define _LINUX_SNMP_H
+
+/* ipstats mib definitions */
+/*
+ * RFC 1213:  MIB-II
+ * RFC 2011 (updates 1213):  SNMPv2-MIB-IP
+ * RFC 2863:  Interfaces Group MIB
+ * RFC 2465:  IPv6 MIB: General Group
+ * draft-ietf-ipv6-rfc2011-update-10.txt: MIB for IP: IP Statistics Tables
+ */
+enum
+{
+	IPSTATS_MIB_NUM = 0,
+	IPSTATS_MIB_INPKTS,			/* InReceives */
+	IPSTATS_MIB_INHDRERRORS,		/* InHdrErrors */
+	IPSTATS_MIB_INTOOBIGERRORS,		/* InTooBigErrors */
+	IPSTATS_MIB_INNOROUTES,			/* InNoRoutes */
+	IPSTATS_MIB_INADDRERRORS,		/* InAddrErrors */
+	IPSTATS_MIB_INUNKNOWNPROTOS,		/* InUnknownProtos */
+	IPSTATS_MIB_INTRUNCATEDPKTS,		/* InTruncatedPkts */
+	IPSTATS_MIB_INDISCARDS,			/* InDiscards */
+	IPSTATS_MIB_INDELIVERS,			/* InDelivers */
+	IPSTATS_MIB_OUTFORWDATAGRAMS,		/* OutForwDatagrams */
+	IPSTATS_MIB_OUTPKTS,			/* OutRequests */
+	IPSTATS_MIB_OUTDISCARDS,		/* OutDiscards */
+	IPSTATS_MIB_OUTNOROUTES,		/* OutNoRoutes */
+	IPSTATS_MIB_REASMTIMEOUT,		/* ReasmTimeout */
+	IPSTATS_MIB_REASMREQDS,			/* ReasmReqds */
+	IPSTATS_MIB_REASMOKS,			/* ReasmOKs */
+	IPSTATS_MIB_REASMFAILS,			/* ReasmFails */
+	IPSTATS_MIB_FRAGOKS,			/* FragOKs */
+	IPSTATS_MIB_FRAGFAILS,			/* FragFails */
+	IPSTATS_MIB_FRAGCREATES,		/* FragCreates */
+	IPSTATS_MIB_INMCASTPKTS,		/* InMcastPkts */
+	IPSTATS_MIB_OUTMCASTPKTS,		/* OutMcastPkts */
+	IPSTATS_MIB_INBCASTPKTS,		/* InBcastPkts */
+	IPSTATS_MIB_OUTBCASTPKTS,		/* OutBcastPkts */
+	IPSTATS_MIB_INOCTETS,			/* InOctets */
+	IPSTATS_MIB_OUTOCTETS,			/* OutOctets */
+	IPSTATS_MIB_INMCASTOCTETS,		/* InMcastOctets */
+	IPSTATS_MIB_OUTMCASTOCTETS,		/* OutMcastOctets */
+	IPSTATS_MIB_INBCASTOCTETS,		/* InBcastOctets */
+	IPSTATS_MIB_OUTBCASTOCTETS,		/* OutBcastOctets */
+	__IPSTATS_MIB_MAX
+};
+
+/* icmp mib definitions */
+/*
+ * RFC 1213:  MIB-II ICMP Group
+ * RFC 2011 (updates 1213):  SNMPv2 MIB for IP: ICMP group
+ */
+enum
+{
+	ICMP_MIB_NUM = 0,
+	ICMP_MIB_INMSGS,			/* InMsgs */
+	ICMP_MIB_INERRORS,			/* InErrors */
+	ICMP_MIB_INDESTUNREACHS,		/* InDestUnreachs */
+	ICMP_MIB_INTIMEEXCDS,			/* InTimeExcds */
+	ICMP_MIB_INPARMPROBS,			/* InParmProbs */
+	ICMP_MIB_INSRCQUENCHS,			/* InSrcQuenchs */
+	ICMP_MIB_INREDIRECTS,			/* InRedirects */
+	ICMP_MIB_INECHOS,			/* InEchos */
+	ICMP_MIB_INECHOREPS,			/* InEchoReps */
+	ICMP_MIB_INTIMESTAMPS,			/* InTimestamps */
+	ICMP_MIB_INTIMESTAMPREPS,		/* InTimestampReps */
+	ICMP_MIB_INADDRMASKS,			/* InAddrMasks */
+	ICMP_MIB_INADDRMASKREPS,		/* InAddrMaskReps */
+	ICMP_MIB_OUTMSGS,			/* OutMsgs */
+	ICMP_MIB_OUTERRORS,			/* OutErrors */
+	ICMP_MIB_OUTDESTUNREACHS,		/* OutDestUnreachs */
+	ICMP_MIB_OUTTIMEEXCDS,			/* OutTimeExcds */
+	ICMP_MIB_OUTPARMPROBS,			/* OutParmProbs */
+	ICMP_MIB_OUTSRCQUENCHS,			/* OutSrcQuenchs */
+	ICMP_MIB_OUTREDIRECTS,			/* OutRedirects */
+	ICMP_MIB_OUTECHOS,			/* OutEchos */
+	ICMP_MIB_OUTECHOREPS,			/* OutEchoReps */
+	ICMP_MIB_OUTTIMESTAMPS,			/* OutTimestamps */
+	ICMP_MIB_OUTTIMESTAMPREPS,		/* OutTimestampReps */
+	ICMP_MIB_OUTADDRMASKS,			/* OutAddrMasks */
+	ICMP_MIB_OUTADDRMASKREPS,		/* OutAddrMaskReps */
+	__ICMP_MIB_MAX
+};
+
+#define __ICMPMSG_MIB_MAX 512	/* Out+In for all 8-bit ICMP types */
+
+/* icmp6 mib definitions */
+/*
+ * RFC 2466:  ICMPv6-MIB
+ */
+enum
+{
+	ICMP6_MIB_NUM = 0,
+	ICMP6_MIB_INMSGS,			/* InMsgs */
+	ICMP6_MIB_INERRORS,			/* InErrors */
+	ICMP6_MIB_OUTMSGS,			/* OutMsgs */
+	ICMP6_MIB_OUTERRORS,			/* OutErrors */
+	__ICMP6_MIB_MAX
+};
+
+#define __ICMP6MSG_MIB_MAX 512 /* Out+In for all 8-bit ICMPv6 types */
+
+/* tcp mib definitions */
+/*
+ * RFC 1213:  MIB-II TCP group
+ * RFC 2012 (updates 1213):  SNMPv2-MIB-TCP
+ */
+enum
+{
+	TCP_MIB_NUM = 0,
+	TCP_MIB_RTOALGORITHM,			/* RtoAlgorithm */
+	TCP_MIB_RTOMIN,				/* RtoMin */
+	TCP_MIB_RTOMAX,				/* RtoMax */
+	TCP_MIB_MAXCONN,			/* MaxConn */
+	TCP_MIB_ACTIVEOPENS,			/* ActiveOpens */
+	TCP_MIB_PASSIVEOPENS,			/* PassiveOpens */
+	TCP_MIB_ATTEMPTFAILS,			/* AttemptFails */
+	TCP_MIB_ESTABRESETS,			/* EstabResets */
+	TCP_MIB_CURRESTAB,			/* CurrEstab */
+	TCP_MIB_INSEGS,				/* InSegs */
+	TCP_MIB_OUTSEGS,			/* OutSegs */
+	TCP_MIB_RETRANSSEGS,			/* RetransSegs */
+	TCP_MIB_INERRS,				/* InErrs */
+	TCP_MIB_OUTRSTS,			/* OutRsts */
+	__TCP_MIB_MAX
+};
+
+/* udp mib definitions */
+/*
+ * RFC 1213:  MIB-II UDP group
+ * RFC 2013 (updates 1213):  SNMPv2-MIB-UDP
+ */
+enum
+{
+	UDP_MIB_NUM = 0,
+	UDP_MIB_INDATAGRAMS,			/* InDatagrams */
+	UDP_MIB_NOPORTS,			/* NoPorts */
+	UDP_MIB_INERRORS,			/* InErrors */
+	UDP_MIB_OUTDATAGRAMS,			/* OutDatagrams */
+	UDP_MIB_RCVBUFERRORS,			/* RcvbufErrors */
+	UDP_MIB_SNDBUFERRORS,			/* SndbufErrors */
+	__UDP_MIB_MAX
+};
+
+/* linux mib definitions */
+enum
+{
+	LINUX_MIB_NUM = 0,
+	LINUX_MIB_SYNCOOKIESSENT,		/* SyncookiesSent */
+	LINUX_MIB_SYNCOOKIESRECV,		/* SyncookiesRecv */
+	LINUX_MIB_SYNCOOKIESFAILED,		/* SyncookiesFailed */
+	LINUX_MIB_EMBRYONICRSTS,		/* EmbryonicRsts */
+	LINUX_MIB_PRUNECALLED,			/* PruneCalled */
+	LINUX_MIB_RCVPRUNED,			/* RcvPruned */
+	LINUX_MIB_OFOPRUNED,			/* OfoPruned */
+	LINUX_MIB_OUTOFWINDOWICMPS,		/* OutOfWindowIcmps */
+	LINUX_MIB_LOCKDROPPEDICMPS,		/* LockDroppedIcmps */
+	LINUX_MIB_ARPFILTER,			/* ArpFilter */
+	LINUX_MIB_TIMEWAITED,			/* TimeWaited */
+	LINUX_MIB_TIMEWAITRECYCLED,		/* TimeWaitRecycled */
+	LINUX_MIB_TIMEWAITKILLED,		/* TimeWaitKilled */
+	LINUX_MIB_PAWSPASSIVEREJECTED,		/* PAWSPassiveRejected */
+	LINUX_MIB_PAWSACTIVEREJECTED,		/* PAWSActiveRejected */
+	LINUX_MIB_PAWSESTABREJECTED,		/* PAWSEstabRejected */
+	LINUX_MIB_DELAYEDACKS,			/* DelayedACKs */
+	LINUX_MIB_DELAYEDACKLOCKED,		/* DelayedACKLocked */
+	LINUX_MIB_DELAYEDACKLOST,		/* DelayedACKLost */
+	LINUX_MIB_LISTENOVERFLOWS,		/* ListenOverflows */
+	LINUX_MIB_LISTENDROPS,			/* ListenDrops */
+	LINUX_MIB_TCPPREQUEUED,			/* TCPPrequeued */
+	LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG,	/* TCPDirectCopyFromBacklog */
+	LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE,	/* TCPDirectCopyFromPrequeue */
+	LINUX_MIB_TCPPREQUEUEDROPPED,		/* TCPPrequeueDropped */
+	LINUX_MIB_TCPHPHITS,			/* TCPHPHits */
+	LINUX_MIB_TCPHPHITSTOUSER,		/* TCPHPHitsToUser */
+	LINUX_MIB_TCPPUREACKS,			/* TCPPureAcks */
+	LINUX_MIB_TCPHPACKS,			/* TCPHPAcks */
+	LINUX_MIB_TCPRENORECOVERY,		/* TCPRenoRecovery */
+	LINUX_MIB_TCPSACKRECOVERY,		/* TCPSackRecovery */
+	LINUX_MIB_TCPSACKRENEGING,		/* TCPSACKReneging */
+	LINUX_MIB_TCPFACKREORDER,		/* TCPFACKReorder */
+	LINUX_MIB_TCPSACKREORDER,		/* TCPSACKReorder */
+	LINUX_MIB_TCPRENOREORDER,		/* TCPRenoReorder */
+	LINUX_MIB_TCPTSREORDER,			/* TCPTSReorder */
+	LINUX_MIB_TCPFULLUNDO,			/* TCPFullUndo */
+	LINUX_MIB_TCPPARTIALUNDO,		/* TCPPartialUndo */
+	LINUX_MIB_TCPDSACKUNDO,			/* TCPDSACKUndo */
+	LINUX_MIB_TCPLOSSUNDO,			/* TCPLossUndo */
+	LINUX_MIB_TCPLOSS,			/* TCPLoss */
+	LINUX_MIB_TCPLOSTRETRANSMIT,		/* TCPLostRetransmit */
+	LINUX_MIB_TCPRENOFAILURES,		/* TCPRenoFailures */
+	LINUX_MIB_TCPSACKFAILURES,		/* TCPSackFailures */
+	LINUX_MIB_TCPLOSSFAILURES,		/* TCPLossFailures */
+	LINUX_MIB_TCPFASTRETRANS,		/* TCPFastRetrans */
+	LINUX_MIB_TCPFORWARDRETRANS,		/* TCPForwardRetrans */
+	LINUX_MIB_TCPSLOWSTARTRETRANS,		/* TCPSlowStartRetrans */
+	LINUX_MIB_TCPTIMEOUTS,			/* TCPTimeouts */
+	LINUX_MIB_TCPRENORECOVERYFAIL,		/* TCPRenoRecoveryFail */
+	LINUX_MIB_TCPSACKRECOVERYFAIL,		/* TCPSackRecoveryFail */
+	LINUX_MIB_TCPSCHEDULERFAILED,		/* TCPSchedulerFailed */
+	LINUX_MIB_TCPRCVCOLLAPSED,		/* TCPRcvCollapsed */
+	LINUX_MIB_TCPDSACKOLDSENT,		/* TCPDSACKOldSent */
+	LINUX_MIB_TCPDSACKOFOSENT,		/* TCPDSACKOfoSent */
+	LINUX_MIB_TCPDSACKRECV,			/* TCPDSACKRecv */
+	LINUX_MIB_TCPDSACKOFORECV,		/* TCPDSACKOfoRecv */
+	LINUX_MIB_TCPABORTONSYN,		/* TCPAbortOnSyn */
+	LINUX_MIB_TCPABORTONDATA,		/* TCPAbortOnData */
+	LINUX_MIB_TCPABORTONCLOSE,		/* TCPAbortOnClose */
+	LINUX_MIB_TCPABORTONMEMORY,		/* TCPAbortOnMemory */
+	LINUX_MIB_TCPABORTONTIMEOUT,		/* TCPAbortOnTimeout */
+	LINUX_MIB_TCPABORTONLINGER,		/* TCPAbortOnLinger */
+	LINUX_MIB_TCPABORTFAILED,		/* TCPAbortFailed */
+	LINUX_MIB_TCPMEMORYPRESSURES,		/* TCPMemoryPressures */
+	LINUX_MIB_TCPSACKDISCARD,		/* TCPSACKDiscard */
+	LINUX_MIB_TCPDSACKIGNOREDOLD,		/* TCPSACKIgnoredOld */
+	LINUX_MIB_TCPDSACKIGNOREDNOUNDO,	/* TCPSACKIgnoredNoUndo */
+	LINUX_MIB_TCPSPURIOUSRTOS,		/* TCPSpuriousRTOs */
+	LINUX_MIB_TCPMD5NOTFOUND,		/* TCPMD5NotFound */
+	LINUX_MIB_TCPMD5UNEXPECTED,		/* TCPMD5Unexpected */
+	LINUX_MIB_SACKSHIFTED,
+	LINUX_MIB_SACKMERGED,
+	LINUX_MIB_SACKSHIFTFALLBACK,
+	LINUX_MIB_TCPBACKLOGDROP,
+	LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
+	LINUX_MIB_TCPDEFERACCEPTDROP,
+	LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
+	LINUX_MIB_TCPTIMEWAITOVERFLOW,		/* TCPTimeWaitOverflow */
+	__LINUX_MIB_MAX
+};
+
+/* linux Xfrm mib definitions */
+enum
+{
+	LINUX_MIB_XFRMNUM = 0,
+	LINUX_MIB_XFRMINERROR,			/* XfrmInError */
+	LINUX_MIB_XFRMINBUFFERERROR,		/* XfrmInBufferError */
+	LINUX_MIB_XFRMINHDRERROR,		/* XfrmInHdrError */
+	LINUX_MIB_XFRMINNOSTATES,		/* XfrmInNoStates */
+	LINUX_MIB_XFRMINSTATEPROTOERROR,	/* XfrmInStateProtoError */
+	LINUX_MIB_XFRMINSTATEMODEERROR,		/* XfrmInStateModeError */
+	LINUX_MIB_XFRMINSTATESEQERROR,		/* XfrmInStateSeqError */
+	LINUX_MIB_XFRMINSTATEEXPIRED,		/* XfrmInStateExpired */
+	LINUX_MIB_XFRMINSTATEMISMATCH,		/* XfrmInStateMismatch */
+	LINUX_MIB_XFRMINSTATEINVALID,		/* XfrmInStateInvalid */
+	LINUX_MIB_XFRMINTMPLMISMATCH,		/* XfrmInTmplMismatch */
+	LINUX_MIB_XFRMINNOPOLS,			/* XfrmInNoPols */
+	LINUX_MIB_XFRMINPOLBLOCK,		/* XfrmInPolBlock */
+	LINUX_MIB_XFRMINPOLERROR,		/* XfrmInPolError */
+	LINUX_MIB_XFRMOUTERROR,			/* XfrmOutError */
+	LINUX_MIB_XFRMOUTBUNDLEGENERROR,	/* XfrmOutBundleGenError */
+	LINUX_MIB_XFRMOUTBUNDLECHECKERROR,	/* XfrmOutBundleCheckError */
+	LINUX_MIB_XFRMOUTNOSTATES,		/* XfrmOutNoStates */
+	LINUX_MIB_XFRMOUTSTATEPROTOERROR,	/* XfrmOutStateProtoError */
+	LINUX_MIB_XFRMOUTSTATEMODEERROR,	/* XfrmOutStateModeError */
+	LINUX_MIB_XFRMOUTSTATESEQERROR,		/* XfrmOutStateSeqError */
+	LINUX_MIB_XFRMOUTSTATEEXPIRED,		/* XfrmOutStateExpired */
+	LINUX_MIB_XFRMOUTPOLBLOCK,		/* XfrmOutPolBlock */
+	LINUX_MIB_XFRMOUTPOLDEAD,		/* XfrmOutPolDead */
+	LINUX_MIB_XFRMOUTPOLERROR,		/* XfrmOutPolError */
+	LINUX_MIB_XFRMFWDHDRERROR,		/* XfrmFwdHdrError*/
+	__LINUX_MIB_XFRMMAX
+};
+
+#endif	/* _LINUX_SNMP_H */
diff --git a/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h b/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h
new file mode 100644
index 0000000..fe815e2
--- /dev/null
+++ b/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h
@@ -0,0 +1,89 @@
+#ifndef __LINUX_TC_EM_META_H
+#define __LINUX_TC_EM_META_H
+
+enum {
+	TCA_EM_META_UNSPEC,
+	TCA_EM_META_HDR,
+	TCA_EM_META_LVALUE,
+	TCA_EM_META_RVALUE,
+	__TCA_EM_META_MAX
+};
+#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1)
+
+struct tcf_meta_val {
+	__u16			kind;
+	__u8			shift;
+	__u8			op;
+};
+
+#define TCF_META_TYPE_MASK	(0xf << 12)
+#define TCF_META_TYPE(kind)	(((kind) & TCF_META_TYPE_MASK) >> 12)
+#define TCF_META_ID_MASK	0x7ff
+#define TCF_META_ID(kind)	((kind) & TCF_META_ID_MASK)
+
+enum {
+	TCF_META_TYPE_VAR,
+	TCF_META_TYPE_INT,
+	__TCF_META_TYPE_MAX
+};
+#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1)
+
+enum {
+	TCF_META_ID_VALUE,
+	TCF_META_ID_RANDOM,
+	TCF_META_ID_LOADAVG_0,
+	TCF_META_ID_LOADAVG_1,
+	TCF_META_ID_LOADAVG_2,
+	TCF_META_ID_DEV,
+	TCF_META_ID_PRIORITY,
+	TCF_META_ID_PROTOCOL,
+	TCF_META_ID_PKTTYPE,
+	TCF_META_ID_PKTLEN,
+	TCF_META_ID_DATALEN,
+	TCF_META_ID_MACLEN,
+	TCF_META_ID_NFMARK,
+	TCF_META_ID_TCINDEX,
+	TCF_META_ID_RTCLASSID,
+	TCF_META_ID_RTIIF,
+	TCF_META_ID_SK_FAMILY,
+	TCF_META_ID_SK_STATE,
+	TCF_META_ID_SK_REUSE,
+	TCF_META_ID_SK_BOUND_IF,
+	TCF_META_ID_SK_REFCNT,
+	TCF_META_ID_SK_SHUTDOWN,
+	TCF_META_ID_SK_PROTO,
+	TCF_META_ID_SK_TYPE,
+	TCF_META_ID_SK_RCVBUF,
+	TCF_META_ID_SK_RMEM_ALLOC,
+	TCF_META_ID_SK_WMEM_ALLOC,
+	TCF_META_ID_SK_OMEM_ALLOC,
+	TCF_META_ID_SK_WMEM_QUEUED,
+	TCF_META_ID_SK_RCV_QLEN,
+	TCF_META_ID_SK_SND_QLEN,
+ 	TCF_META_ID_SK_ERR_QLEN,
+	TCF_META_ID_SK_FORWARD_ALLOCS,
+	TCF_META_ID_SK_SNDBUF,
+ 	TCF_META_ID_SK_ALLOCS,
+ 	TCF_META_ID_SK_ROUTE_CAPS,
+ 	TCF_META_ID_SK_HASH,
+ 	TCF_META_ID_SK_LINGERTIME,
+ 	TCF_META_ID_SK_ACK_BACKLOG,
+ 	TCF_META_ID_SK_MAX_ACK_BACKLOG,
+ 	TCF_META_ID_SK_PRIO,
+ 	TCF_META_ID_SK_RCVLOWAT,
+ 	TCF_META_ID_SK_RCVTIMEO,
+ 	TCF_META_ID_SK_SNDTIMEO,
+ 	TCF_META_ID_SK_SENDMSG_OFF,
+ 	TCF_META_ID_SK_WRITE_PENDING,
+	TCF_META_ID_VLAN_TAG,
+	TCF_META_ID_RXHASH,
+	__TCF_META_ID_MAX
+};
+#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
+
+struct tcf_meta_hdr {
+	struct tcf_meta_val	left;
+	struct tcf_meta_val	right;
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink-generic.h b/libnetwork/libnl3/include/netlink-generic.h
new file mode 100644
index 0000000..10aa2f0
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink-generic.h
@@ -0,0 +1,20 @@
+/*
+ * netlink-generic.h	Local Generic Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_GENL_PRIV_H_
+#define NETLINK_GENL_PRIV_H_
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+
+#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen))
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink-local.h b/libnetwork/libnl3/include/netlink-local.h
new file mode 100644
index 0000000..01c611a
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink-local.h
@@ -0,0 +1,213 @@
+/*
+ * netlink-local.h		Local Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_H_
+#define NETLINK_LOCAL_H_
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <limits.h>
+#include <search.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#include <linux/types.h>
+
+/* local header copies */
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ethtool.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+#include <linux/gen_stats.h>
+#include <linux/ip_mp_alg.h>
+#include <linux/atm.h>
+#include <linux/inetdevice.h>
+#include <linux/ipv6.h>
+#include <linux/snmp.h>
+
+#include <netlink/netlink.h>
+#include <netlink/handlers.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+#include <netlink/object-api.h>
+#include <netlink/cache-api.h>
+#include <netlink-types.h>
+
+struct trans_tbl {
+	int i;
+	const char *a;
+};
+
+#define __ADD(id, name) { .i = id, .a = #name },
+
+struct trans_list {
+	int i;
+	char *a;
+	struct nl_list_head list;
+};
+
+#define NL_DEBUG	1
+
+#define NL_DBG(LVL,FMT,ARG...) \
+	do {	\
+		if (LVL <= nl_debug) \
+			fprintf(stderr, "DBG<" #LVL ">: " FMT, ##ARG); \
+	} while (0)
+
+#define BUG()                            \
+	do {                                 \
+		fprintf(stderr, "BUG: %s:%d\n",  \
+			__FILE__, __LINE__);         \
+		assert(0);	\
+	} while (0)
+
+#define APPBUG(msg)							\
+	do {								\
+		fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n",	\
+			__FILE__, __LINE__, __PRETTY_FUNCTION__, msg);	\
+		assert(0);						\
+	} while(0)
+
+extern int __nl_read_num_str_file(const char *path,
+				  int (*cb)(long, const char *));
+
+extern int __trans_list_add(int, const char *, struct nl_list_head *);
+extern void __trans_list_clear(struct nl_list_head *);
+
+extern char *__type2str(int, char *, size_t, const struct trans_tbl *, size_t);
+extern int __str2type(const char *, const struct trans_tbl *, size_t);
+
+extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
+extern int __list_str2type(const char *, struct nl_list_head *);
+
+extern char *__flags2str(int, char *, size_t, const struct trans_tbl *, size_t);
+extern int __str2flags(const char *, const struct trans_tbl *, size_t);
+
+extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
+
+static inline struct nl_cache *dp_cache(struct nl_object *obj)
+{
+	if (obj->ce_cache == NULL)
+		return nl_cache_mngt_require(obj->ce_ops->oo_name);
+
+	return obj->ce_cache;
+}
+
+static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
+{
+	return cb->cb_set[type](msg, cb->cb_args[type]);
+}
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+
+/* This is also defined in stddef.h */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define __init __attribute__ ((constructor))
+#define __exit __attribute__ ((destructor))
+#undef __deprecated
+#define __deprecated __attribute__ ((deprecated))
+
+#define min(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x > _y ? _x : _y; })
+
+#define min_t(type,x,y) \
+	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
+			  struct nlmsghdr *, struct nl_parser_param *);
+
+
+static inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst,
+				      struct tc_ratespec *src)
+{
+	dst->rs_cell_log = src->cell_log;
+	dst->rs_overhead = src->overhead;
+	dst->rs_cell_align = src->cell_align;
+	dst->rs_mpu = src->mpu;
+	dst->rs_rate = src->rate;
+}
+
+static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
+				       struct rtnl_ratespec *src)
+{
+	dst->cell_log = src->rs_cell_log;
+	dst->overhead = src->rs_overhead;
+	dst->cell_align = src->rs_cell_align;
+	dst->mpu = src->rs_mpu;
+	dst->rate = src->rs_rate;
+}
+
+static inline char *nl_cache_name(struct nl_cache *cache)
+{
+	return cache->c_ops ? cache->c_ops->co_name : "unknown";
+}
+
+#define GENL_FAMILY(id, name) \
+	{ \
+		{ id, NL_ACT_UNSPEC, name }, \
+		END_OF_MSGTYPES_LIST, \
+	}
+
+static inline int wait_for_ack(struct nl_sock *sk)
+{
+	if (sk->s_flags & NL_NO_AUTO_ACK)
+		return 0;
+	else
+		return nl_wait_for_ack(sk);
+}
+
+static inline int build_sysconf_path(char **strp, const char *filename)
+{
+	char *sysconfdir;
+
+	sysconfdir = getenv("NLSYSCONFDIR");
+
+	if (!sysconfdir)
+		sysconfdir = SYSCONFDIR;
+
+	return asprintf(strp, "%s/%s", sysconfdir, filename);
+}
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink-tc.h b/libnetwork/libnl3/include/netlink-tc.h
new file mode 100644
index 0000000..3e44642
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink-tc.h
@@ -0,0 +1,55 @@
+/*
+ * netlink-tc.h		Local Traffic Control Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_TC_PRIV_H_
+#define NETLINK_TC_PRIV_H_
+
+#include <netlink-local.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TCA_ATTR_HANDLE		0x0001
+#define TCA_ATTR_PARENT		0x0002
+#define TCA_ATTR_IFINDEX	0x0004
+#define TCA_ATTR_KIND		0x0008
+#define TCA_ATTR_FAMILY		0x0010
+#define TCA_ATTR_INFO		0x0020
+#define TCA_ATTR_OPTS		0x0040
+#define TCA_ATTR_STATS		0x0080
+#define TCA_ATTR_XSTATS		0x0100
+#define TCA_ATTR_LINK		0x0200
+#define TCA_ATTR_MTU		0x0400
+#define TCA_ATTR_MPU		0x0800
+#define TCA_ATTR_OVERHEAD	0x1000
+#define TCA_ATTR_LINKTYPE	0x2000
+#define TCA_ATTR_MAX		TCA_ATTR_LINKTYPE
+
+extern int tca_parse(struct nlattr **, int, struct rtnl_tc *,
+		     struct nla_policy *);
+
+#define RTNL_TC_RTABLE_SIZE	256
+
+extern int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *,
+				    uint32_t *);
+
+
+static inline void *tca_xstats(struct rtnl_tc *tca)
+{
+	return tca->tc_xstats->d_data;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink-types.h b/libnetwork/libnl3/include/netlink-types.h
new file mode 100644
index 0000000..750c897
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink-types.h
@@ -0,0 +1,846 @@
+/*
+ * netlink-types.h	Netlink Types (Private)
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_TYPES_H_
+#define NETLINK_LOCAL_TYPES_H_
+
+#include <netlink/list.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/tc-api.h>
+
+#define NL_SOCK_BUFSIZE_SET	(1<<0)
+#define NL_SOCK_PASSCRED	(1<<1)
+#define NL_OWN_PORT		(1<<2)
+#define NL_MSG_PEEK		(1<<3)
+#define NL_NO_AUTO_ACK		(1<<4)
+
+#define NL_MSG_CRED_PRESENT 1
+
+struct nl_cache_ops;
+struct nl_sock;
+struct nl_object;
+
+struct nl_cb
+{
+	nl_recvmsg_msg_cb_t	cb_set[NL_CB_TYPE_MAX+1];
+	void *			cb_args[NL_CB_TYPE_MAX+1];
+	
+	nl_recvmsg_err_cb_t	cb_err;
+	void *			cb_err_arg;
+
+	/** May be used to replace nl_recvmsgs with your own implementation
+	 * in all internal calls to nl_recvmsgs. */
+	int			(*cb_recvmsgs_ow)(struct nl_sock *,
+						  struct nl_cb *);
+
+	/** Overwrite internal calls to nl_recv, must return the number of
+	 * octets read and allocate a buffer for the received data. */
+	int			(*cb_recv_ow)(struct nl_sock *,
+					      struct sockaddr_nl *,
+					      unsigned char **,
+					      struct ucred **);
+
+	/** Overwrites internal calls to nl_send, must send the netlink
+	 * message. */
+	int			(*cb_send_ow)(struct nl_sock *,
+					      struct nl_msg *);
+
+	int			cb_refcnt;
+};
+
+struct nl_sock
+{
+	struct sockaddr_nl	s_local;
+	struct sockaddr_nl	s_peer;
+	int			s_fd;
+	int			s_proto;
+	unsigned int		s_seq_next;
+	unsigned int		s_seq_expect;
+	int			s_flags;
+	struct nl_cb *		s_cb;
+};
+
+struct nl_cache
+{
+	struct nl_list_head	c_items;
+	int			c_nitems;
+	int                     c_iarg1;
+	int                     c_iarg2;
+	struct nl_cache_ops *   c_ops;
+};
+
+struct nl_cache_assoc
+{
+	struct nl_cache *	ca_cache;
+	change_func_t		ca_change;
+	void *			ca_change_data;
+};
+
+struct nl_cache_mngr
+{
+	int			cm_protocol;
+	int			cm_flags;
+	int			cm_nassocs;
+	struct nl_sock *	cm_handle;
+	struct nl_cache_assoc *	cm_assocs;
+};
+
+struct nl_parser_param;
+
+#define LOOSE_COMPARISON	1
+
+#define NL_OBJ_MARK		1
+
+struct nl_data
+{
+	size_t			d_size;
+	void *			d_data;
+};
+
+struct nl_addr
+{
+	int			a_family;
+	unsigned int		a_maxsize;
+	unsigned int		a_len;
+	int			a_prefixlen;
+	int			a_refcnt;
+	char			a_addr[0];
+};
+
+struct nl_msg
+{
+	int			nm_protocol;
+	int			nm_flags;
+	struct sockaddr_nl	nm_src;
+	struct sockaddr_nl	nm_dst;
+	struct ucred		nm_creds;
+	struct nlmsghdr *	nm_nlh;
+	size_t			nm_size;
+	int			nm_refcnt;
+};
+
+struct rtnl_link_map
+{
+	uint64_t lm_mem_start;
+	uint64_t lm_mem_end;
+	uint64_t lm_base_addr;
+	uint16_t lm_irq;
+	uint8_t  lm_dma;
+	uint8_t  lm_port;
+};
+
+#define IFQDISCSIZ	32
+
+struct rtnl_link
+{
+	NLHDR_COMMON
+
+	char				l_name[IFNAMSIZ];
+	uint32_t			l_family;
+	uint32_t			l_arptype;
+	uint32_t			l_index;
+	uint32_t			l_flags;
+	uint32_t			l_change;
+	uint32_t 			l_mtu;
+	uint32_t			l_link;
+	uint32_t			l_txqlen;
+	uint32_t			l_weight;
+	uint32_t			l_master;
+	struct nl_addr *		l_addr;	
+	struct nl_addr *		l_bcast;
+	char				l_qdisc[IFQDISCSIZ];
+	struct rtnl_link_map		l_map;
+	uint64_t			l_stats[RTNL_LINK_STATS_MAX+1];
+	uint32_t			l_flag_mask;
+	uint32_t			l_num_vf;
+	uint8_t				l_operstate;
+	uint8_t				l_linkmode;
+	/* 2 byte hole */
+	struct rtnl_link_info_ops *	l_info_ops;
+	void *				l_af_data[AF_MAX];
+	void *				l_info;
+	char *				l_ifalias;
+};
+
+struct rtnl_ncacheinfo
+{
+	uint32_t nci_confirmed;	/**< Time since neighbour validty was last confirmed */
+	uint32_t nci_used;	/**< Time since neighbour entry was last ued */
+	uint32_t nci_updated;	/**< Time since last update */
+	uint32_t nci_refcnt;	/**< Reference counter */
+};
+
+
+struct rtnl_neigh
+{
+	NLHDR_COMMON
+	uint32_t	n_family;
+	uint32_t	n_ifindex;
+	uint16_t	n_state;
+	uint8_t		n_flags;
+	uint8_t		n_type;	
+	struct nl_addr *n_lladdr;
+	struct nl_addr *n_dst;	
+	uint32_t	n_probes;
+	struct rtnl_ncacheinfo n_cacheinfo;
+	uint32_t                n_state_mask;
+	uint32_t                n_flag_mask;
+};
+
+
+struct rtnl_addr_cacheinfo
+{
+	/* Preferred lifetime in seconds */
+	uint32_t aci_prefered;
+
+	/* Valid lifetime in seconds */
+	uint32_t aci_valid;
+
+	/* Timestamp of creation in 1/100s seince boottime */
+	uint32_t aci_cstamp;
+
+	/* Timestamp of last update in 1/100s since boottime */
+	uint32_t aci_tstamp;
+};
+
+struct rtnl_addr
+{
+	NLHDR_COMMON
+
+	uint8_t		a_family;
+	uint8_t		a_prefixlen;
+	uint8_t		a_flags;
+	uint8_t		a_scope;
+	uint32_t	a_ifindex;
+
+	struct nl_addr *a_peer;	
+	struct nl_addr *a_local;
+	struct nl_addr *a_bcast;
+	struct nl_addr *a_anycast;
+	struct nl_addr *a_multicast;
+
+	struct rtnl_addr_cacheinfo a_cacheinfo;
+	
+	char a_label[IFNAMSIZ];
+	uint32_t a_flag_mask;
+	struct rtnl_link *a_link;
+};
+
+struct rtnl_nexthop
+{
+	uint8_t			rtnh_flags;
+	uint8_t			rtnh_flag_mask;
+	uint8_t			rtnh_weight;
+	/* 1 byte spare */
+	uint32_t		rtnh_ifindex;
+	struct nl_addr *	rtnh_gateway;
+	uint32_t		ce_mask; /* HACK to support attr macros */
+	struct nl_list_head	rtnh_list;
+	uint32_t		rtnh_realms;
+};
+
+struct rtnl_route
+{
+	NLHDR_COMMON
+
+	uint8_t			rt_family;
+	uint8_t			rt_dst_len;
+	uint8_t			rt_src_len;
+	uint8_t			rt_tos;
+	uint8_t			rt_protocol;
+	uint8_t			rt_scope;
+	uint8_t			rt_type;
+	uint8_t			rt_nmetrics;
+	uint32_t		rt_flags;
+	struct nl_addr *	rt_dst;
+	struct nl_addr *	rt_src;
+	uint32_t		rt_table;
+	uint32_t		rt_iif;
+	uint32_t		rt_prio;
+	uint32_t		rt_metrics[RTAX_MAX];
+	uint32_t		rt_metrics_mask;
+	uint32_t		rt_nr_nh;
+	struct nl_addr *	rt_pref_src;
+	struct nl_list_head	rt_nexthops;
+	struct rtnl_rtcacheinfo	rt_cacheinfo;
+	uint32_t		rt_flag_mask;
+};
+
+struct rtnl_rule
+{
+	NLHDR_COMMON
+	uint8_t		r_family;
+	uint8_t		r_action;
+	uint8_t		r_dsfield; /* ipv4 only */
+	uint8_t		r_unused;
+	uint32_t	r_table;
+	uint32_t	r_flags;
+	uint32_t	r_prio;
+	uint32_t	r_mark;
+	uint32_t	r_mask;
+	uint32_t	r_goto;
+	uint32_t	r_flow; /* ipv4 only */
+	struct nl_addr *r_src;
+	struct nl_addr *r_dst;
+	char		r_iifname[IFNAMSIZ];
+	char		r_oifname[IFNAMSIZ];
+};
+
+struct rtnl_neightbl_parms
+{
+	/**
+	 * Interface index of the device this parameter set is assigned
+	 * to or 0 for the default set.
+	 */
+	uint32_t		ntp_ifindex;
+
+	/**
+	 * Number of references to this parameter set.
+	 */
+	uint32_t		ntp_refcnt;
+
+	/**
+	 * Queue length for pending arp requests, i.e. the number of
+	 * packets which are accepted from other layers while the
+	 * neighbour address is still being resolved
+	 */
+	uint32_t		ntp_queue_len;
+
+	/**
+	 * Number of requests to send to the user level ARP daemon.
+	 * Specify 0 to disable.
+	 */
+	uint32_t		ntp_app_probes;
+
+	/**
+	 * Maximum number of retries for unicast solicitation.
+	 */
+	uint32_t		ntp_ucast_probes;
+
+	/**
+	 * Maximum number of retries for multicast solicitation.
+	 */
+	uint32_t		ntp_mcast_probes;
+
+	/**
+	 * Base value in milliseconds to ompute reachable time, see RFC2461.
+	 */
+	uint64_t		ntp_base_reachable_time;
+
+	/**
+	 * Actual reachable time (read-only)
+	 */
+	uint64_t		ntp_reachable_time;	/* secs */
+
+	/**
+	 * The time in milliseconds between retransmitted Neighbor
+	 * Solicitation messages.
+	 */
+	uint64_t		ntp_retrans_time;
+
+	/**
+	 * Interval in milliseconds to check for stale neighbour
+	 * entries.
+	 */
+	uint64_t		ntp_gc_stale_time;	/* secs */
+
+	/**
+	 * Delay in milliseconds for the first time probe if
+	 * the neighbour is reachable.
+	 */
+	uint64_t		ntp_probe_delay;	/* secs */
+
+	/**
+	 * Maximum delay in milliseconds of an answer to a neighbour
+	 * solicitation message.
+	 */
+	uint64_t		ntp_anycast_delay;
+
+	/**
+	 * Minimum age in milliseconds before a neighbour entry
+	 * may be replaced.
+	 */
+	uint64_t		ntp_locktime;
+
+	/**
+	 * Delay in milliseconds before answering to an ARP request
+	 * for which a proxy ARP entry exists.
+	 */
+	uint64_t		ntp_proxy_delay;
+
+	/**
+	 * Queue length for the delayed proxy arp requests.
+	 */
+	uint32_t		ntp_proxy_qlen;
+	
+	/**
+	 * Mask of available parameter attributes
+	 */
+	uint32_t		ntp_mask;
+};
+
+#define NTBLNAMSIZ	32
+
+/**
+ * Neighbour table
+ * @ingroup neightbl
+ */
+struct rtnl_neightbl
+{
+	NLHDR_COMMON
+
+	char			nt_name[NTBLNAMSIZ];
+	uint32_t		nt_family;
+	uint32_t		nt_gc_thresh1;
+	uint32_t		nt_gc_thresh2;
+	uint32_t		nt_gc_thresh3;
+	uint64_t		nt_gc_interval;
+	struct ndt_config	nt_config;
+	struct rtnl_neightbl_parms nt_parms;
+	struct ndt_stats	nt_stats;
+};
+
+struct rtnl_ratespec
+{
+	uint8_t			rs_cell_log;
+	uint16_t		rs_overhead;
+	int16_t			rs_cell_align;
+	uint16_t		rs_mpu;
+	uint32_t		rs_rate;
+};
+
+struct rtnl_tstats
+{
+	struct {
+		uint64_t            bytes;
+		uint64_t            packets;
+	} tcs_basic;
+
+	struct {
+		uint32_t            bps;
+		uint32_t            pps;
+	} tcs_rate_est;
+
+	struct {
+		uint32_t            qlen;
+		uint32_t            backlog;
+		uint32_t            drops;
+		uint32_t            requeues;
+		uint32_t            overlimits;
+	} tcs_queue;
+};
+
+#define TCKINDSIZ	32
+
+#define NL_TC_GENERIC(pre)				\
+	NLHDR_COMMON					\
+	uint32_t		pre ##_family;		\
+	uint32_t		pre ##_ifindex;		\
+	uint32_t		pre ##_handle;		\
+	uint32_t		pre ##_parent;		\
+	uint32_t		pre ##_info;		\
+	uint32_t		pre ##_mtu;		\
+	uint32_t		pre ##_mpu;		\
+	uint32_t		pre ##_overhead;	\
+	uint32_t		pre ##_linktype;	\
+	char			pre ##_kind[TCKINDSIZ];	\
+	struct nl_data *	pre ##_opts;		\
+	uint64_t		pre ##_stats[RTNL_TC_STATS_MAX+1]; \
+	struct nl_data *	pre ##_xstats;		\
+	struct nl_data *	pre ##_subdata;		\
+	struct rtnl_link *	pre ##_link;		\
+	struct rtnl_tc_ops *	pre ##_ops;		\
+	enum rtnl_tc_type	pre ##_type
+
+struct rtnl_tc
+{
+	NL_TC_GENERIC(tc);
+};
+
+struct rtnl_qdisc
+{
+	NL_TC_GENERIC(q);
+};
+
+struct rtnl_class
+{
+	NL_TC_GENERIC(c);
+};
+
+struct rtnl_cls
+{
+	NL_TC_GENERIC(c);
+	uint16_t		c_prio;
+	uint16_t		c_protocol;
+};
+
+struct rtnl_u32
+{
+	uint32_t		cu_divisor;
+	uint32_t		cu_hash;
+	uint32_t		cu_classid;
+	uint32_t		cu_link;
+	struct nl_data *	cu_pcnt;
+	struct nl_data *	cu_selector;
+	struct nl_data *	cu_act;
+	struct nl_data *	cu_police;
+	char			cu_indev[IFNAMSIZ];
+	int			cu_mask;
+};
+
+struct rtnl_cgroup
+{
+	struct rtnl_ematch_tree *cg_ematch;
+	int			cg_mask;
+};
+
+struct rtnl_fw
+{
+	uint32_t		cf_classid;
+	struct nl_data *	cf_act;
+	struct nl_data *	cf_police;
+	char			cf_indev[IFNAMSIZ];
+	int			cf_mask;
+};
+
+struct rtnl_ematch
+{
+	uint16_t		e_id;
+	uint16_t		e_kind;
+	uint16_t		e_flags;
+	uint16_t		e_index;
+	size_t			e_datalen;
+
+	struct nl_list_head	e_childs;
+	struct nl_list_head	e_list;
+	struct rtnl_ematch_ops *e_ops;
+
+	void *			e_data;
+};
+
+struct rtnl_ematch_tree
+{
+	uint16_t		et_progid;
+	struct nl_list_head	et_list;
+
+};
+
+struct rtnl_dsmark_qdisc
+{
+	uint16_t	qdm_indices;
+	uint16_t	qdm_default_index;
+	uint32_t	qdm_set_tc_index;
+	uint32_t	qdm_mask;
+};
+
+struct rtnl_dsmark_class
+{
+	uint8_t		cdm_bmask;
+	uint8_t		cdm_value;
+	uint32_t	cdm_mask;
+};
+
+struct rtnl_fifo
+{
+	uint32_t	qf_limit;
+	uint32_t	qf_mask;
+};
+
+struct rtnl_prio
+{
+	uint32_t	qp_bands;
+	uint8_t		qp_priomap[TC_PRIO_MAX+1];
+	uint32_t	qp_mask;
+};
+
+struct rtnl_tbf
+{
+	uint32_t		qt_limit;
+	struct rtnl_ratespec	qt_rate;
+	uint32_t		qt_rate_bucket;
+	uint32_t		qt_rate_txtime;
+	struct rtnl_ratespec	qt_peakrate;
+	uint32_t		qt_peakrate_bucket;
+	uint32_t		qt_peakrate_txtime;
+	uint32_t		qt_mask;
+};
+
+struct rtnl_sfq
+{
+	uint32_t	qs_quantum;
+	uint32_t	qs_perturb;
+	uint32_t	qs_limit;
+	uint32_t	qs_divisor;
+	uint32_t	qs_flows;
+	uint32_t	qs_mask;
+};
+
+struct rtnl_netem_corr
+{
+	uint32_t	nmc_delay;
+	uint32_t	nmc_loss;
+	uint32_t	nmc_duplicate;
+};
+
+struct rtnl_netem_reo
+{
+	uint32_t	nmro_probability;
+	uint32_t	nmro_correlation;
+};
+
+struct rtnl_netem_crpt
+{
+	uint32_t	nmcr_probability;
+	uint32_t	nmcr_correlation;
+};
+
+struct rtnl_netem_dist
+{
+	int16_t	*	dist_data;
+	size_t		dist_size;
+};
+
+struct rtnl_netem
+{
+	uint32_t		qnm_latency;
+	uint32_t		qnm_limit;
+	uint32_t		qnm_loss;
+	uint32_t		qnm_gap;
+	uint32_t		qnm_duplicate;
+	uint32_t		qnm_jitter;
+	uint32_t		qnm_mask;
+	struct rtnl_netem_corr	qnm_corr;
+	struct rtnl_netem_reo	qnm_ro;
+	struct rtnl_netem_crpt	qnm_crpt;
+	struct rtnl_netem_dist  qnm_dist;
+};
+
+struct rtnl_htb_qdisc
+{
+	uint32_t		qh_rate2quantum;
+	uint32_t		qh_defcls;
+	uint32_t		qh_mask;
+	uint32_t		qh_direct_pkts;
+};
+
+struct rtnl_htb_class
+{
+	uint32_t		ch_prio;
+	struct rtnl_ratespec	ch_rate;
+	struct rtnl_ratespec	ch_ceil;
+	uint32_t		ch_rbuffer;
+	uint32_t		ch_cbuffer;
+	uint32_t		ch_quantum;
+	uint32_t		ch_mask;
+	uint32_t		ch_level;
+};
+
+struct rtnl_cbq
+{
+	struct tc_cbq_lssopt    cbq_lss;
+	struct tc_ratespec      cbq_rate;
+	struct tc_cbq_wrropt    cbq_wrr;
+	struct tc_cbq_ovl       cbq_ovl;
+	struct tc_cbq_fopt      cbq_fopt;
+	struct tc_cbq_police    cbq_police;
+};
+
+struct rtnl_red
+{
+	uint32_t	qr_limit;
+	uint32_t	qr_qth_min;
+	uint32_t	qr_qth_max;
+	uint8_t		qr_flags;
+	uint8_t		qr_wlog;
+	uint8_t		qr_plog;
+	uint8_t		qr_scell_log;
+	uint32_t	qr_mask;
+};
+
+struct flnl_request
+{
+	NLHDR_COMMON
+
+	struct nl_addr *	lr_addr;
+	uint32_t		lr_fwmark;
+	uint8_t			lr_tos;
+	uint8_t			lr_scope;
+	uint8_t			lr_table;
+};
+
+
+struct flnl_result
+{
+	NLHDR_COMMON
+
+	struct flnl_request *	fr_req;
+	uint8_t			fr_table_id;
+	uint8_t			fr_prefixlen;
+	uint8_t			fr_nh_sel;
+	uint8_t			fr_type;
+	uint8_t			fr_scope;
+	uint32_t		fr_error;
+};
+
+#define GENL_OP_HAS_POLICY	1
+#define GENL_OP_HAS_DOIT	2
+#define GENL_OP_HAS_DUMPIT	4
+
+struct genl_family_op
+{
+	uint32_t		o_id;
+	uint32_t		o_flags;
+
+	struct nl_list_head	o_list;
+};
+
+struct genl_family_grp {
+        struct genl_family      *family;        /* private */
+        struct nl_list_head     list;           /* private */
+        char                    name[GENL_NAMSIZ];
+        u_int32_t               id;
+};
+
+struct genl_family
+{
+	NLHDR_COMMON
+
+	uint16_t		gf_id;
+	char 			gf_name[GENL_NAMSIZ];
+	uint32_t		gf_version;
+	uint32_t		gf_hdrsize;
+	uint32_t		gf_maxattr;
+
+	struct nl_list_head	gf_ops;
+	struct nl_list_head	gf_mc_grps;
+};
+
+union nfnl_ct_proto
+{
+	struct {
+		uint16_t	src;
+		uint16_t	dst;
+	} port;
+	struct {
+		uint16_t	id;
+		uint8_t		type;
+		uint8_t		code;
+	} icmp;
+};
+
+struct nfnl_ct_dir {
+	struct nl_addr *	src;
+	struct nl_addr *	dst;
+	union nfnl_ct_proto	proto;
+	uint64_t		packets;
+	uint64_t		bytes;
+};
+
+union nfnl_ct_protoinfo {
+	struct {
+		uint8_t		state;
+	} tcp;
+};
+
+struct nfnl_ct {
+	NLHDR_COMMON
+
+	uint8_t			ct_family;
+	uint8_t			ct_proto;
+	union nfnl_ct_protoinfo	ct_protoinfo;
+
+	uint32_t		ct_status;
+	uint32_t		ct_status_mask;
+	uint32_t		ct_timeout;
+	uint32_t		ct_mark;
+	uint32_t		ct_use;
+	uint32_t		ct_id;
+
+	struct nfnl_ct_dir	ct_orig;
+	struct nfnl_ct_dir	ct_repl;
+};
+
+struct nfnl_log {
+	NLHDR_COMMON
+
+	uint16_t		log_group;
+	uint8_t			log_copy_mode;
+	uint32_t		log_copy_range;
+	uint32_t		log_flush_timeout;
+	uint32_t		log_alloc_size;
+	uint32_t		log_queue_threshold;
+	uint32_t		log_flags;
+	uint32_t		log_flag_mask;
+};
+
+struct nfnl_log_msg {
+	NLHDR_COMMON
+
+	uint8_t			log_msg_family;
+	uint8_t			log_msg_hook;
+	uint16_t		log_msg_hwproto;
+	uint32_t		log_msg_mark;
+	struct timeval		log_msg_timestamp;
+	uint32_t		log_msg_indev;
+	uint32_t		log_msg_outdev;
+	uint32_t		log_msg_physindev;
+	uint32_t		log_msg_physoutdev;
+	uint8_t			log_msg_hwaddr[8];
+	int			log_msg_hwaddr_len;
+	void *			log_msg_payload;
+	int			log_msg_payload_len;
+	char *			log_msg_prefix;
+	uint32_t		log_msg_uid;
+	uint32_t		log_msg_gid;
+	uint32_t		log_msg_seq;
+	uint32_t		log_msg_seq_global;
+};
+
+struct nfnl_queue {
+	NLHDR_COMMON
+
+	uint16_t		queue_group;
+	uint32_t		queue_maxlen;
+	uint32_t		queue_copy_range;
+	uint8_t			queue_copy_mode;
+};
+
+struct nfnl_queue_msg {
+	NLHDR_COMMON
+
+	uint16_t		queue_msg_group;
+	uint8_t			queue_msg_family;
+	uint8_t			queue_msg_hook;
+	uint16_t		queue_msg_hwproto;
+	uint32_t		queue_msg_packetid;
+	uint32_t		queue_msg_mark;
+	struct timeval		queue_msg_timestamp;
+	uint32_t		queue_msg_indev;
+	uint32_t		queue_msg_outdev;
+	uint32_t		queue_msg_physindev;
+	uint32_t		queue_msg_physoutdev;
+	uint8_t			queue_msg_hwaddr[8];
+	int			queue_msg_hwaddr_len;
+	void *			queue_msg_payload;
+	int			queue_msg_payload_len;
+	uint32_t		queue_msg_verdict;
+};
+
+struct ematch_quoted {
+	char *	data;
+	size_t	len;
+	int	index;
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/addr.h b/libnetwork/libnl3/include/netlink/addr.h
new file mode 100644
index 0000000..794c4ff
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/addr.h
@@ -0,0 +1,66 @@
+/*
+ * netlink/addr.h		Abstract Address
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_ADDR_H_
+#define NETLINK_ADDR_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_addr;
+
+/* Creation */
+extern struct nl_addr *	nl_addr_alloc(size_t);
+extern struct nl_addr *	nl_addr_alloc_attr(struct nlattr *, int);
+extern struct nl_addr *	nl_addr_build(int, void *, size_t);
+extern int		nl_addr_parse(const char *, int, struct nl_addr **);
+extern struct nl_addr *	nl_addr_clone(struct nl_addr *);
+
+/* Usage Management */
+extern struct nl_addr *	nl_addr_get(struct nl_addr *);
+extern void		nl_addr_put(struct nl_addr *);
+extern int		nl_addr_shared(struct nl_addr *);
+
+extern int		nl_addr_cmp(struct nl_addr *, struct nl_addr *);
+extern int		nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
+extern int		nl_addr_iszero(struct nl_addr *);
+extern int		nl_addr_valid(char *, int);
+extern int      	nl_addr_guess_family(struct nl_addr *);
+extern int		nl_addr_fill_sockaddr(struct nl_addr *,
+					      struct sockaddr *, socklen_t *);
+extern int		nl_addr_info(struct nl_addr *, struct addrinfo **);
+extern int		nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
+
+/* Access Functions */
+extern void		nl_addr_set_family(struct nl_addr *, int);
+extern int		nl_addr_get_family(struct nl_addr *);
+extern int		nl_addr_set_binary_addr(struct nl_addr *, void *,
+						size_t);
+extern void *		nl_addr_get_binary_addr(struct nl_addr *);
+extern unsigned int	nl_addr_get_len(struct nl_addr *);
+extern void		nl_addr_set_prefixlen(struct nl_addr *, int);
+extern unsigned int	nl_addr_get_prefixlen(struct nl_addr *);
+
+/* Address Family Translations */
+extern char *		nl_af2str(int, char *, size_t);
+extern int		nl_str2af(const char *);
+
+/* Translations to Strings */
+extern char *		nl_addr2str(struct nl_addr *, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/attr.h b/libnetwork/libnl3/include/netlink/attr.h
new file mode 100644
index 0000000..8479c23
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/attr.h
@@ -0,0 +1,283 @@
+/*
+ * netlink/attr.h		Netlink Attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_ATTR_H_
+#define NETLINK_ATTR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/addr.h>
+#include <netlink/data.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_msg;
+
+/**
+ * @name Basic Attribute Data Types
+ * @{
+ */
+
+ /**
+  * @ingroup attr
+  * Basic attribute data types
+  *
+  * See \ref attr_datatypes for more details.
+  */
+enum {
+	NLA_UNSPEC,	/**< Unspecified type, binary data chunk */
+	NLA_U8,		/**< 8 bit integer */
+	NLA_U16,	/**< 16 bit integer */
+	NLA_U32,	/**< 32 bit integer */
+	NLA_U64,	/**< 64 bit integer */
+	NLA_STRING,	/**< NUL terminated character string */
+	NLA_FLAG,	/**< Flag */
+	NLA_MSECS,	/**< Micro seconds (64bit) */
+	NLA_NESTED,	/**< Nested attributes */
+	__NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/** @} */
+
+/**
+ * @ingroup attr
+ * Attribute validation policy.
+ *
+ * See \ref attr_datatypes for more details.
+ */
+struct nla_policy {
+	/** Type of attribute or NLA_UNSPEC */
+	uint16_t	type;
+
+	/** Minimal length of payload required */
+	uint16_t	minlen;
+
+	/** Maximal length of payload allowed */
+	uint16_t	maxlen;
+};
+
+/* Size calculations */
+extern int		nla_attr_size(int payload);
+extern int		nla_total_size(int payload);
+extern int		nla_padlen(int payload);
+
+/* Attribute parsing */
+extern int		nla_type(const struct nlattr *);
+extern void *		nla_data(const struct nlattr *);
+extern int		nla_len(const struct nlattr *);
+extern int		nla_ok(const struct nlattr *, int);
+extern struct nlattr *	nla_next(const struct nlattr *, int *);
+extern int		nla_parse(struct nlattr **, int, struct nlattr *,
+				  int, struct nla_policy *);
+extern int		nla_validate(struct nlattr *, int, int,
+				     struct nla_policy *);
+extern struct nlattr *	nla_find(struct nlattr *, int, int);
+
+/* Helper Functions */
+extern int		nla_memcpy(void *, struct nlattr *, int);
+extern size_t		nla_strlcpy(char *, const struct nlattr *, size_t);
+extern int		nla_memcmp(const struct nlattr *, const void *, size_t);
+extern int		nla_strcmp(const struct nlattr *, const char *);
+
+/* Unspecific attribute */
+extern struct nlattr *	nla_reserve(struct nl_msg *, int, int);
+extern int		nla_put(struct nl_msg *, int, int, const void *);
+extern int		nla_put_data(struct nl_msg *, int, struct nl_data *);
+extern int		nla_put_addr(struct nl_msg *, int, struct nl_addr *);
+
+/* Integer attribute */
+extern uint8_t		nla_get_u8(struct nlattr *);
+extern int		nla_put_u8(struct nl_msg *, int, uint8_t);
+extern uint16_t		nla_get_u16(struct nlattr *);
+extern int		nla_put_u16(struct nl_msg *, int, uint16_t);
+extern uint32_t		nla_get_u32(struct nlattr *);
+extern int		nla_put_u32(struct nl_msg *, int, uint32_t);
+extern uint64_t		nla_get_u64(struct nlattr *);
+extern int		nla_put_u64(struct nl_msg *, int, uint64_t);
+
+/* String attribute */
+extern char *		nla_get_string(struct nlattr *);
+extern char *		nla_strdup(struct nlattr *);
+extern int		nla_put_string(struct nl_msg *, int, const char *);
+
+/* Flag attribute */
+extern int		nla_get_flag(struct nlattr *);
+extern int		nla_put_flag(struct nl_msg *, int);
+
+/* Msec attribute */
+extern unsigned long	nla_get_msecs(struct nlattr *);
+extern int		nla_put_msecs(struct nl_msg *, int, unsigned long);
+
+/* Attribute nesting */
+extern int		nla_put_nested(struct nl_msg *, int, struct nl_msg *);
+extern struct nlattr *	nla_nest_start(struct nl_msg *, int);
+extern int		nla_nest_end(struct nl_msg *, struct nlattr *);
+extern int		nla_parse_nested(struct nlattr **, int, struct nlattr *,
+					 struct nla_policy *);
+
+/**
+ * @name Attribute Construction (Exception Based)
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Add unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg attrlen		Length of attribute payload.
+ * @arg data		Head of attribute payload.
+ */
+#define NLA_PUT(msg, attrtype, attrlen, data) \
+	do { \
+		if (nla_put(msg, attrtype, attrlen, data) < 0) \
+			goto nla_put_failure; \
+	} while(0)
+
+/**
+ * @ingroup attr
+ * Add atomic type attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg type		Atomic type.
+ * @arg attrtype	Attribute type.
+ * @arg value		Head of attribute payload.
+ */
+#define NLA_PUT_TYPE(msg, type, attrtype, value) \
+	do { \
+		type __tmp = value; \
+		NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
+	} while(0)
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U8(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U16(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U32(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U64(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		NUL terminated character string.
+ */
+#define NLA_PUT_STRING(msg, attrtype, value) \
+	NLA_PUT(msg, attrtype, strlen(value) + 1, value)
+
+/**
+ * Add flag attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ */
+#define NLA_PUT_FLAG(msg, attrtype) \
+	NLA_PUT(msg, attrtype, 0, NULL)
+
+/**
+ * Add msecs attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg msecs		Numeric value in micro seconds.
+ */
+#define NLA_PUT_MSECS(msg, attrtype, msecs) \
+	NLA_PUT_U64(msg, attrtype, msecs)
+
+/**
+ * Add address attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg addr		Abstract address object.
+ */
+#define NLA_PUT_ADDR(msg, attrtype, addr) \
+	NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \
+		nl_addr_get_binary_addr(addr))
+
+/**
+ * Add abstract data attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg data		Abstract data object.
+ */
+#define NLA_PUT_DATA(msg, attrtype, data) \
+	NLA_PUT(msg, attrtype, nl_data_get_size(data), \
+		nl_data_get(data))
+
+/** @} */
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of attributes
+ * @arg pos	loop counter, set to current attribute
+ * @arg head	head of attribute stream
+ * @arg len	length of attribute stream
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of nested attributes
+ * @arg pos	loop counter, set to current attribute
+ * @arg nla	attribute containing the nested attributes
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_nested(pos, nla, rem) \
+	for (pos = nla_data(nla), rem = nla_len(nla); \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cache-api.h b/libnetwork/libnl3/include/netlink/cache-api.h
new file mode 100644
index 0000000..1b3d099
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cache-api.h
@@ -0,0 +1,230 @@
+/*
+ * netlink/cache-api.h		Caching API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_API_H_
+#define NETLINK_CACHE_API_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup cache
+ * @defgroup cache_api Cache Implementation
+ * @brief
+ *
+ * @par 1) Cache Definition
+ * @code
+ * struct nl_cache_ops my_cache_ops = {
+ * 	.co_name		= "route/link",
+ * 	.co_protocol		= NETLINK_ROUTE,
+ * 	.co_hdrsize		= sizeof(struct ifinfomsg),
+ * 	.co_obj_ops		= &my_obj_ops,
+ * };
+ * @endcode
+ *
+ * @par 2) 
+ * @code
+ * // The simplest way to fill a cache is by providing a request-update
+ * // function which must trigger a complete dump on the kernel-side of
+ * // whatever the cache covers.
+ * static int my_request_update(struct nl_cache *cache,
+ * 				struct nl_sock *socket)
+ * {
+ * 	// In this example, we request a full dump of the interface table
+ * 	return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+ * }
+ *
+ * // The resulting netlink messages sent back will be fed into a message
+ * // parser one at a time. The message parser has to extract all relevant
+ * // information from the message and create an object reflecting the
+ * // contents of the message and pass it on to the parser callback function
+ * // provide which will add the object to the cache.
+ * static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ * 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
+ * {
+ * 	struct my_obj *obj;
+ *
+ * 	obj = my_obj_alloc();
+ * 	obj->ce_msgtype = nlh->nlmsg_type;
+ *
+ * 	// Parse the netlink message and continue creating the object.
+ *
+ * 	err = pp->pp_cb((struct nl_object *) obj, pp);
+ * 	if (err < 0)
+ * 		goto errout;
+ * }
+ *
+ * struct nl_cache_ops my_cache_ops = {
+ * 	...
+ * 	.co_request_update	= my_request_update,
+ * 	.co_msg_parser		= my_msg_parser,
+ * };
+ * @endcode
+ *
+ * @par 3) Notification based Updates
+ * @code
+ * // Caches can be kept up-to-date based on notifications if the kernel
+ * // sends out notifications whenever an object is added/removed/changed.
+ * //
+ * // It is trivial to support this, first a list of groups needs to be
+ * // defined which are required to join in order to receive all necessary
+ * // notifications. The groups are separated by address family to support
+ * // the common situation where a separate group is used for each address
+ * // family. If there is only one group, simply specify AF_UNSPEC.
+ * static struct nl_af_group addr_groups[] = {
+ * 	{ AF_INET,	RTNLGRP_IPV4_IFADDR },
+ * 	{ AF_INET6,	RTNLGRP_IPV6_IFADDR },
+ * 	{ END_OF_GROUP_LIST },
+ * };
+ *
+ * // In order for the caching system to know the meaning of each message
+ * // type it requires a table which maps each supported message type to
+ * // a cache action, e.g. RTM_NEWADDR means address has been added or
+ * // updated, RTM_DELADDR means address has been removed.
+ * static struct nl_cache_ops rtnl_addr_ops = {
+ * 	...
+ * 	.co_msgtypes		= {
+ * 					{ RTM_NEWADDR, NL_ACT_NEW, "new" },
+ * 					{ RTM_DELADDR, NL_ACT_DEL, "del" },
+ * 					{ RTM_GETADDR, NL_ACT_GET, "get" },
+ * 					END_OF_MSGTYPES_LIST,
+ * 				},
+ * 	.co_groups		= addr_groups,
+ * };
+ *
+ * // It is now possible to keep the cache up-to-date using the cache manager.
+ * @endcode
+ * @{
+ */
+
+enum {
+	NL_ACT_UNSPEC,
+	NL_ACT_NEW,
+	NL_ACT_DEL,
+	NL_ACT_GET,
+	NL_ACT_SET,
+	NL_ACT_CHANGE,
+	__NL_ACT_MAX,
+};
+
+#define NL_ACT_MAX (__NL_ACT_MAX - 1)
+
+#define END_OF_MSGTYPES_LIST	{ -1, -1, NULL }
+
+/**
+ * Message type to cache action association
+ */
+struct nl_msgtype
+{
+	/** Netlink message type */
+	int			mt_id;
+
+	/** Cache action to take */
+	int			mt_act;
+
+	/** Name of operation for human-readable printing */
+	char *			mt_name;
+};
+
+/**
+ * Address family to netlink group association
+ */
+struct nl_af_group
+{
+	/** Address family */
+	int			ag_family;
+
+	/** Netlink group identifier */
+	int			ag_group;
+};
+
+#define END_OF_GROUP_LIST AF_UNSPEC, 0
+
+/**
+ * Parser parameters
+ *
+ * This structure is used to configure what kind of parser to use
+ * when parsing netlink messages to create objects.
+ */
+struct nl_parser_param
+{
+	/** Function to parse netlink messages into objects */
+	int             (*pp_cb)(struct nl_object *, struct nl_parser_param *);
+
+	/** Arbitary argument to be passed to the parser */
+	void *            pp_arg;
+};
+
+/**
+ * Cache Operations
+ *
+ * This structure defines the characterstics of a cache type. It contains
+ * pointers to functions which implement the specifics of the object type
+ * the cache can hold.
+ */
+struct nl_cache_ops
+{
+	/** Name of cache type (must be unique) */
+	char  *			co_name;
+
+	/** Size of family specific netlink header */
+	int			co_hdrsize;
+
+	/** Netlink protocol */
+	int			co_protocol;
+
+	/** Group definition */
+	struct nl_af_group *	co_groups;
+	
+	/**
+	 * Called whenever an update of the cache is required. Must send
+	 * a request message to the kernel requesting a complete dump.
+	 */
+	int   (*co_request_update)(struct nl_cache *, struct nl_sock *);
+
+	/**
+	 * Called whenever a message was received that needs to be parsed.
+	 * Must parse the message and call the paser callback function
+	 * (nl_parser_param) provided via the argument.
+	 */
+	int   (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+			       struct nlmsghdr *, struct nl_parser_param *);
+
+	/**
+	 * Called whenever a notification has been parsed into an object and
+	 * is considered for inclusion into a cache. Must return NL_SKIP if
+	 * the object should not be included in the cache.
+	 */
+	int   (*co_event_filter)(struct nl_cache *, struct nl_object *obj);
+
+	/** Object operations */
+	struct nl_object_ops *	co_obj_ops;
+
+	/** Internal, do not touch! */
+	struct nl_cache_ops *co_next;
+
+	struct nl_cache *co_major_cache;
+	struct genl_ops *	co_genl;
+
+	/* Message type definition */
+	struct nl_msgtype	co_msgtypes[];
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cache.h b/libnetwork/libnl3/include/netlink/cache.h
new file mode 100644
index 0000000..f8073f0
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cache.h
@@ -0,0 +1,134 @@
+/*
+ * netlink/cache.h		Caching Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_H_
+#define NETLINK_CACHE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/cache-api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache;
+
+typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
+
+/* Access Functions */
+extern int			nl_cache_nitems(struct nl_cache *);
+extern int			nl_cache_nitems_filter(struct nl_cache *,
+						       struct nl_object *);
+extern struct nl_cache_ops *	nl_cache_get_ops(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_first(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_last(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_next(struct nl_object *);
+extern struct nl_object *	nl_cache_get_prev(struct nl_object *);
+
+extern struct nl_cache *	nl_cache_alloc(struct nl_cache_ops *);
+extern int			nl_cache_alloc_and_fill(struct nl_cache_ops *,
+							struct nl_sock *,
+							struct nl_cache **);
+extern int			nl_cache_alloc_name(const char *,
+						    struct nl_cache **);
+extern struct nl_cache *	nl_cache_subset(struct nl_cache *,
+						struct nl_object *);
+extern void			nl_cache_clear(struct nl_cache *);
+extern void			nl_cache_free(struct nl_cache *);
+
+/* Cache modification */
+extern int			nl_cache_add(struct nl_cache *,
+					     struct nl_object *);
+extern int			nl_cache_parse_and_add(struct nl_cache *,
+						       struct nl_msg *);
+extern void			nl_cache_remove(struct nl_object *);
+extern int			nl_cache_refill(struct nl_sock *,
+						struct nl_cache *);
+extern int			nl_cache_pickup(struct nl_sock *,
+						struct nl_cache *);
+extern int			nl_cache_resync(struct nl_sock *,
+						struct nl_cache *,
+						change_func_t,
+						void *);
+extern int			nl_cache_include(struct nl_cache *,
+						 struct nl_object *,
+						 change_func_t,
+						 void *);
+extern void			nl_cache_set_arg1(struct nl_cache *, int);
+extern void			nl_cache_set_arg2(struct nl_cache *, int);
+
+/* General */
+extern int			nl_cache_is_empty(struct nl_cache *);
+extern struct nl_object *	nl_cache_search(struct nl_cache *,
+						struct nl_object *);
+extern void			nl_cache_mark_all(struct nl_cache *);
+
+/* Dumping */
+extern void			nl_cache_dump(struct nl_cache *,
+					      struct nl_dump_params *);
+extern void			nl_cache_dump_filter(struct nl_cache *,
+						     struct nl_dump_params *,
+						     struct nl_object *);
+
+/* Iterators */
+extern void			nl_cache_foreach(struct nl_cache *,
+						 void (*cb)(struct nl_object *,
+							    void *),
+						 void *arg);
+extern void			nl_cache_foreach_filter(struct nl_cache *,
+							struct nl_object *,
+							void (*cb)(struct
+								   nl_object *,
+								   void *),
+							void *arg);
+
+/* --- cache management --- */
+
+/* Cache type management */
+extern struct nl_cache_ops *	nl_cache_ops_lookup(const char *);
+extern struct nl_cache_ops *	nl_cache_ops_associate(int, int);
+extern struct nl_msgtype *	nl_msgtype_lookup(struct nl_cache_ops *, int);
+extern void			nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
+extern int			nl_cache_mngt_register(struct nl_cache_ops *);
+extern int			nl_cache_mngt_unregister(struct nl_cache_ops *);
+
+/* Global cache provisioning/requiring */
+extern void			nl_cache_mngt_provide(struct nl_cache *);
+extern void			nl_cache_mngt_unprovide(struct nl_cache *);
+extern struct nl_cache *	nl_cache_mngt_require(const char *);
+extern struct nl_cache *	__nl_cache_mngt_require(const char *);
+
+struct nl_cache_mngr;
+
+#define NL_AUTO_PROVIDE		1
+
+extern int			nl_cache_mngr_alloc(struct nl_sock *,
+						    int, int,
+						    struct nl_cache_mngr **);
+extern int			nl_cache_mngr_add(struct nl_cache_mngr *,
+						  const char *,
+						  change_func_t,
+						  void *,
+						  struct nl_cache **);
+extern int			nl_cache_mngr_get_fd(struct nl_cache_mngr *);
+extern int			nl_cache_mngr_poll(struct nl_cache_mngr *,
+						   int);
+extern int			nl_cache_mngr_data_ready(struct nl_cache_mngr *);
+extern void			nl_cache_mngr_free(struct nl_cache_mngr *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/addr.h b/libnetwork/libnl3/include/netlink/cli/addr.h
new file mode 100644
index 0000000..d0fd055
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/addr.h
@@ -0,0 +1,32 @@
+/*
+ * netlink/cli/addr.h    CLI Address Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_ADDR_H_
+#define __NETLINK_CLI_ADDR_H_
+
+#include <netlink/route/addr.h>
+
+#define nl_cli_addr_alloc_cache(sk) \
+		nl_cli_alloc_cache((sk), "address", rtnl_addr_alloc_cache)
+
+extern struct rtnl_addr *nl_cli_addr_alloc(void);
+
+extern void nl_cli_addr_parse_family(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_local(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_dev(struct rtnl_addr *, struct nl_cache *,char *);
+extern void nl_cli_addr_parse_label(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_peer(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_scope(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_broadcast(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_preferred(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_valid(struct rtnl_addr *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/class.h b/libnetwork/libnl3/include/netlink/cli/class.h
new file mode 100644
index 0000000..5001e42
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/class.h
@@ -0,0 +1,21 @@
+/*
+ * netlink/cli/class.h     CLI Class Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CLASS_H_
+#define __NETLINK_CLI_CLASS_H_
+
+#include <netlink/route/class.h>
+#include <netlink/cli/tc.h>
+
+extern struct rtnl_class *nl_cli_class_alloc(void);
+extern struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *, int);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/cls.h b/libnetwork/libnl3/include/netlink/cli/cls.h
new file mode 100644
index 0000000..a2707b8
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/cls.h
@@ -0,0 +1,24 @@
+/*
+ * netlink/cli/cls.h		CLI Classifier Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CLS_H_
+#define __NETLINK_CLI_CLS_H_
+
+#include <netlink/route/classifier.h>
+#include <netlink/cli/tc.h>
+
+extern struct rtnl_cls *	nl_cli_cls_alloc(void);
+extern struct nl_cache *	nl_cli_cls_alloc_cache(struct nl_sock *,
+						       int, uint32_t);
+extern void			nl_cli_cls_parse_proto(struct rtnl_cls *, char *);
+extern struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/ct.h b/libnetwork/libnl3/include/netlink/cli/ct.h
new file mode 100644
index 0000000..bed776b
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/ct.h
@@ -0,0 +1,34 @@
+/*
+ * netlink/cli/ct.h	CLI Conntrack Helper
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CT_H_
+#define __NETLINK_CLI_CT_H_
+
+#include <netlink/netfilter/ct.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+
+extern struct nfnl_ct *nl_cli_ct_alloc(void);
+extern struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *);
+
+extern void nl_cli_ct_parse_family(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_protocol(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_mark(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_timeout(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_id(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_use(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_src(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_dst(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_src_port(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_dst_port(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_tcp_state(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_status(struct nfnl_ct *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/link.h b/libnetwork/libnl3/include/netlink/cli/link.h
new file mode 100644
index 0000000..3f37948
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/link.h
@@ -0,0 +1,30 @@
+/*
+ * netlink/cli/link.h     CLI Link Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_LINK_H_
+#define __NETLINK_CLI_LINK_H_
+
+#include <netlink/route/link.h>
+#include <netlink/cli/utils.h>
+
+extern struct rtnl_link *nl_cli_link_alloc(void);
+extern struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *, int);
+extern struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *);
+
+extern void nl_cli_link_parse_family(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_name(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_mtu(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_ifindex(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_txqlen(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_weight(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_ifalias(struct rtnl_link *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/neigh.h b/libnetwork/libnl3/include/netlink/cli/neigh.h
new file mode 100644
index 0000000..5440012
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/neigh.h
@@ -0,0 +1,27 @@
+/*
+ * netlink/cli/neighbour.h     CLI Neighbour Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_NEIGH_H_
+#define __NETLINK_CLI_NEIGH_H_
+
+#include <netlink/route/neighbour.h>
+
+#define nl_cli_neigh_alloc_cache(sk) \
+		nl_cli_alloc_cache((sk), "neighbour", rtnl_neigh_alloc_cache)
+
+extern struct rtnl_neigh *nl_cli_neigh_alloc(void);
+extern void nl_cli_neigh_parse_dst(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_dev(struct rtnl_neigh *, struct nl_cache *, char *);
+extern void nl_cli_neigh_parse_family(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_state(struct rtnl_neigh *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/qdisc.h b/libnetwork/libnl3/include/netlink/cli/qdisc.h
new file mode 100644
index 0000000..b102da4
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/qdisc.h
@@ -0,0 +1,23 @@
+/*
+ * netlink/cli/qdisc.h     CLI QDisc Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_QDISC_H_
+#define __NETLINK_CLI_QDISC_H_
+
+#include <netlink/route/qdisc.h>
+
+#define nl_cli_qdisc_alloc_cache(sk) \
+		nl_cli_alloc_cache((sk), "queueing disciplines", \
+				   rtnl_qdisc_alloc_cache)
+
+extern struct rtnl_qdisc *nl_cli_qdisc_alloc(void);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/route.h b/libnetwork/libnl3/include/netlink/cli/route.h
new file mode 100644
index 0000000..089c658
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/route.h
@@ -0,0 +1,34 @@
+/*
+ * netlink/cli//route.h     CLI Route Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_ROUTE_H_
+#define __NETLINK_CLI_ROUTE_H_
+
+#include <netlink/route/route.h>
+
+extern struct rtnl_route *nl_cli_route_alloc(void);
+
+extern struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *, int);
+
+extern void	nl_cli_route_parse_family(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_dst(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_src(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_pref_src(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_metric(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_nexthop(struct rtnl_route *, char *, struct nl_cache *);
+extern void	nl_cli_route_parse_table(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_prio(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_scope(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_protocol(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_type(struct rtnl_route *, char *);
+extern void	nl_cli_route_parse_iif(struct rtnl_route *, char *, struct nl_cache *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/rule.h b/libnetwork/libnl3/include/netlink/cli/rule.h
new file mode 100644
index 0000000..61cd63e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/rule.h
@@ -0,0 +1,21 @@
+/*
+ * netlink/cli/rule.h     CLI Routing Rule Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_RULE_H_
+#define __NETLINK_CLI_RULE_H_
+
+#include <netlink/route/rule.h>
+
+extern struct rtnl_rule *nl_cli_rule_alloc(void);
+extern struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *);
+extern void nl_cli_rule_parse_family(struct rtnl_rule *, char *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/tc.h b/libnetwork/libnl3/include/netlink/cli/tc.h
new file mode 100644
index 0000000..85d2e30
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/tc.h
@@ -0,0 +1,39 @@
+/*
+ * netlink/cli/tc.h     CLI Traffic Control Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_TC_H_
+#define __NETLINK_CLI_TC_H_
+
+#include <netlink/route/tc-api.h>
+
+extern void nl_cli_tc_parse_dev(struct rtnl_tc *, struct nl_cache *, char *);
+extern void nl_cli_tc_parse_parent(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_handle(struct rtnl_tc *, char *, int);
+extern void nl_cli_tc_parse_mtu(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_mpu(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_overhead(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_linktype(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_kind(struct rtnl_tc *, char *);
+
+struct nl_cli_tc_module
+{
+	const char *		tm_name;
+	enum rtnl_tc_type	tm_type;
+	struct rtnl_tc_ops *	tm_ops;
+	void		      (*tm_parse_argv)(struct rtnl_tc *, int, char **);
+	struct nl_list_head	tm_list;
+};
+
+extern struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *);
+extern void nl_cli_tc_register(struct nl_cli_tc_module *);
+extern void nl_cli_tc_unregister(struct nl_cli_tc_module *);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/cli/utils.h b/libnetwork/libnl3/include/netlink/cli/utils.h
new file mode 100644
index 0000000..da41c10
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/cli/utils.h
@@ -0,0 +1,82 @@
+/*
+ * src/utils.h		Utilities
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2009 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_UTILS_H_
+#define __NETLINK_CLI_UTILS_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <netlink/list.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/neighbour.h>
+#include <netlink/route/neightbl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/rule.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/fib_lookup/lookup.h>
+#include <netlink/fib_lookup/request.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/netfilter/ct.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __init
+#define __init __attribute__((constructor))
+#endif
+
+#ifndef __exit
+#define __exit __attribute__((destructor))
+#endif
+
+extern uint32_t		nl_cli_parse_u32(const char *);
+extern void		nl_cli_print_version(void);
+extern void		nl_cli_fatal(int, const char *, ...);
+extern struct nl_addr *	nl_cli_addr_parse(const char *, int);
+extern int		nl_cli_connect(struct nl_sock *, int);
+extern struct nl_sock *	nl_cli_alloc_socket(void);
+extern int		nl_cli_parse_dumptype(const char *);
+extern int		nl_cli_confirm(struct nl_object *,
+				       struct nl_dump_params *, int);
+
+extern struct nl_cache *nl_cli_alloc_cache(struct nl_sock *, const char *,
+			     int (*ac)(struct nl_sock *, struct nl_cache **));
+
+extern void		nl_cli_load_module(const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/data.h b/libnetwork/libnl3/include/netlink/data.h
new file mode 100644
index 0000000..071159e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/data.h
@@ -0,0 +1,41 @@
+/*
+ * netlink/data.h	Abstract Data
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_DATA_H_
+#define NETLINK_DATA_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_data;
+
+/* General */
+extern struct nl_data *	nl_data_alloc(void *, size_t);
+extern struct nl_data * nl_data_alloc_attr(struct nlattr *);
+extern struct nl_data *	nl_data_clone(struct nl_data *);
+extern int		nl_data_append(struct nl_data *, void *, size_t);
+extern void		nl_data_free(struct nl_data *);
+
+/* Access Functions */
+extern void *		nl_data_get(struct nl_data *);
+extern size_t		nl_data_get_size(struct nl_data *);
+
+/* Misc */
+extern int		nl_data_cmp(struct nl_data *, struct nl_data *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/errno.h b/libnetwork/libnl3/include/netlink/errno.h
new file mode 100644
index 0000000..f8b5130
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/errno.h
@@ -0,0 +1,64 @@
+/*
+ * netlink/errno.h		Error Numbers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_ERRNO_H_
+#define NETLINK_ERRNO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NLE_SUCCESS		0
+#define NLE_FAILURE		1
+#define NLE_INTR		2
+#define NLE_BAD_SOCK		3
+#define NLE_AGAIN		4
+#define NLE_NOMEM		5
+#define NLE_EXIST		6
+#define NLE_INVAL		7
+#define NLE_RANGE		8
+#define NLE_MSGSIZE		9
+#define NLE_OPNOTSUPP		10
+#define NLE_AF_NOSUPPORT	11
+#define NLE_OBJ_NOTFOUND	12
+#define NLE_NOATTR		13
+#define NLE_MISSING_ATTR	14
+#define NLE_AF_MISMATCH		15
+#define NLE_SEQ_MISMATCH	16
+#define NLE_MSG_OVERFLOW	17
+#define NLE_MSG_TRUNC		18
+#define NLE_NOADDR		19
+#define NLE_SRCRT_NOSUPPORT	20
+#define NLE_MSG_TOOSHORT	21
+#define NLE_MSGTYPE_NOSUPPORT	22
+#define NLE_OBJ_MISMATCH	23
+#define NLE_NOCACHE		24
+#define NLE_BUSY		25
+#define NLE_PROTO_MISMATCH	26
+#define NLE_NOACCESS		27
+#define NLE_PERM		28
+#define NLE_PKTLOC_FILE		29
+#define NLE_PARSE_ERR		30
+#define NLE_NODEV		31
+#define NLE_IMMUTABLE		32
+#define NLE_DUMP_INTR		33
+
+#define NLE_MAX			NLE_DUMP_INTR
+
+extern const char *	nl_geterror(int);
+extern void		nl_perror(int, const char *);
+extern int		nl_syserr2nlerr(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h b/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h
new file mode 100644
index 0000000..8bf27b8
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h
@@ -0,0 +1,42 @@
+/*
+ * netlink/fib_lookup/fib_lookup.h	FIB Lookup
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_FIB_LOOKUP_H_
+#define NETLINK_FIB_LOOKUP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/fib_lookup/request.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct flnl_result;
+
+extern struct flnl_result *	flnl_result_alloc(void);
+extern void			flnl_result_put(struct flnl_result *);
+
+extern struct nl_cache *	flnl_result_alloc_cache(void);
+
+extern int			flnl_lookup_build_request(struct flnl_request *,
+							  int,
+							  struct nl_msg **);
+extern int			flnl_lookup(struct nl_sock *,
+					    struct flnl_request *,
+					    struct nl_cache *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/fib_lookup/request.h b/libnetwork/libnl3/include/netlink/fib_lookup/request.h
new file mode 100644
index 0000000..60e8820
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/fib_lookup/request.h
@@ -0,0 +1,51 @@
+/*
+ * netlink/fib_lookup/request.h		FIB Lookup Request	
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_FIB_LOOKUP_REQUEST_H_
+#define NETLINK_FIB_LOOKUP_REQUEST_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct flnl_request;
+
+#define REQUEST_CAST(ptr)	((struct flnl_request *) (ptr))
+
+extern struct flnl_request *	flnl_request_alloc(void);
+
+extern void			flnl_request_set_fwmark(struct flnl_request *,
+							uint64_t);
+extern uint64_t			flnl_request_get_fwmark(struct flnl_request *);
+extern void			flnl_request_set_tos(struct flnl_request *,
+						     int);
+extern int			flnl_request_get_tos(struct flnl_request *);
+extern void			flnl_request_set_scope(struct flnl_request *,
+						       int);
+extern int			flnl_request_get_scope(struct flnl_request *);
+extern void			flnl_request_set_table(struct flnl_request *,
+						       int);
+extern int			flnl_request_get_table(struct flnl_request *);
+extern int			flnl_request_set_addr(struct flnl_request *,
+						      struct nl_addr *);
+extern struct nl_addr *		flnl_request_get_addr(struct flnl_request *);
+
+extern int			flnl_request_cmp(struct flnl_request *,
+						 struct flnl_request *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/genl/ctrl.h b/libnetwork/libnl3/include/netlink/genl/ctrl.h
new file mode 100644
index 0000000..26a0a99
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/genl/ctrl.h
@@ -0,0 +1,40 @@
+/*
+ * netlink/genl/ctrl.h		Generic Netlink Controller
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_GENL_CTRL_H_
+#define NETLINK_GENL_CTRL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct genl_family;
+
+extern int			genl_ctrl_alloc_cache(struct nl_sock *,
+						      struct nl_cache **);
+extern struct genl_family *	genl_ctrl_search(struct nl_cache *, int);
+extern struct genl_family *	genl_ctrl_search_by_name(struct nl_cache *,
+							 const char *);
+extern int			genl_ctrl_resolve(struct nl_sock *,
+						  const char *);
+extern int 			genl_ctrl_resolve_grp(struct nl_sock *sk,
+						      const char *family,
+						      const char *grp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/genl/family.h b/libnetwork/libnl3/include/netlink/genl/family.h
new file mode 100644
index 0000000..721dc13
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/genl/family.h
@@ -0,0 +1,53 @@
+/*
+ * netlink/genl/family.h	Generic Netlink Family
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_GENL_FAMILY_H_
+#define NETLINK_GENL_FAMILY_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct genl_family;
+
+extern struct genl_family *	genl_family_alloc(void);
+extern void			genl_family_put(struct genl_family *);
+
+extern unsigned int		genl_family_get_id(struct genl_family *);
+extern void			genl_family_set_id(struct genl_family *,
+						   unsigned int);
+extern char *			genl_family_get_name(struct genl_family *);
+extern void			genl_family_set_name(struct genl_family *,
+						     const char *name);
+extern uint8_t			genl_family_get_version(struct genl_family *);
+extern void			genl_family_set_version(struct genl_family *,
+							uint8_t);
+extern uint32_t			genl_family_get_hdrsize(struct genl_family *);
+extern void			genl_family_set_hdrsize(struct genl_family *,
+							uint32_t);
+extern uint32_t			genl_family_get_maxattr(struct genl_family *);
+extern void			genl_family_set_maxattr(struct genl_family *,
+							uint32_t);
+
+extern int			genl_family_add_op(struct genl_family *,
+						   int, int);
+extern int 			genl_family_add_grp(struct genl_family *,
+					uint32_t , const char *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/genl/genl.h b/libnetwork/libnl3/include/netlink/genl/genl.h
new file mode 100644
index 0000000..364a471
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/genl/genl.h
@@ -0,0 +1,46 @@
+/*
+ * netlink/genl/genl.h		Generic Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_GENL_H_
+#define NETLINK_GENL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int		genl_connect(struct nl_sock *);
+extern int		genl_send_simple(struct nl_sock *, int, int,
+					 int, int);
+
+extern void *		genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+				    int, int, int, uint8_t, uint8_t);
+
+extern int		genlmsg_valid_hdr(struct nlmsghdr *, int);
+extern int		genlmsg_validate(struct nlmsghdr *, int, int,
+					 struct nla_policy *);
+extern int		genlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+				      int, struct nla_policy *);
+extern void *		genlmsg_data(const struct genlmsghdr *);
+extern int		genlmsg_len(const struct genlmsghdr *);
+extern struct nlattr *	genlmsg_attrdata(const struct genlmsghdr *, int);
+extern int		genlmsg_attrlen(const struct genlmsghdr *, int);
+
+extern char *		genl_op2name(int, int, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/genl/mngt.h b/libnetwork/libnl3/include/netlink/genl/mngt.h
new file mode 100644
index 0000000..8b0244f
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/genl/mngt.h
@@ -0,0 +1,87 @@
+/*
+ * netlink/genl/mngt.h		Generic Netlink Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_GENL_MNGT_H_
+#define NETLINK_GENL_MNGT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache_ops;
+
+struct genl_info
+{
+	struct sockaddr_nl *    who;
+	struct nlmsghdr *       nlh;
+	struct genlmsghdr *     genlhdr;
+	void *                  userhdr;
+	struct nlattr **        attrs;
+};
+
+/**
+ * @ingroup genl_mngt
+ * Generic Netlink Command
+ */
+struct genl_cmd
+{
+	/** Unique command identifier */
+	int			c_id;
+
+	/** Name/description of command */
+	char *			c_name;
+
+	/**
+	 * Maximum attribute identifier, must be provided if
+	 * a message parser is available.
+	 */
+	int			c_maxattr;
+
+	int		      (*c_msg_parser)(struct nl_cache_ops *,
+					      struct genl_cmd *,
+					      struct genl_info *, void *);
+
+	/**
+	 * Attribute validation policy (optional)
+	 */
+	struct nla_policy *	c_attr_policy;
+};
+
+/**
+ * @ingroup genl_mngt
+ * Generic Netlink Operations
+ */
+struct genl_ops
+{
+	int			o_family;
+	int			o_id;
+	char *			o_name;
+	struct nl_cache_ops *	o_cache_ops;
+	struct genl_cmd	*	o_cmds;
+	int			o_ncmds;
+
+	/* linked list of all genl cache operations */
+	struct nl_list_head	o_list;
+};
+
+
+extern int		genl_register(struct nl_cache_ops *);
+extern void		genl_unregister(struct nl_cache_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/handlers.h b/libnetwork/libnl3/include/netlink/handlers.h
new file mode 100644
index 0000000..dfa2809
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/handlers.h
@@ -0,0 +1,146 @@
+/*
+ * netlink/handlers.c	default netlink message handlers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_HANDLERS_H_
+#define NETLINK_HANDLERS_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netlink/netlink-compat.h>
+#include <netlink/netlink-kernel.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cb;
+struct nl_sock;
+struct nl_msg;
+struct ucred;
+
+/**
+ * @name Callback Typedefs
+ * @{
+ */
+
+/**
+ * nl_recvmsgs() callback for message processing customization
+ * @ingroup cb
+ * @arg msg		netlink message being processed
+ * @arg arg		argument passwd on through caller
+ */
+typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
+
+/**
+ * nl_recvmsgs() callback for error message processing customization
+ * @ingroup cb
+ * @arg nla		netlink address of the peer
+ * @arg nlerr		netlink error message being processed
+ * @arg arg		argument passed on through caller
+ */
+typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla,
+				   struct nlmsgerr *nlerr, void *arg);
+
+/** @} */
+
+/**
+ * Callback actions
+ * @ingroup cb
+ */
+enum nl_cb_action {
+	/** Proceed with wathever would come next */
+	NL_OK,
+	/** Skip this message */
+	NL_SKIP,
+	/** Stop parsing altogether and discard remaining messages */
+	NL_STOP,
+};
+
+/**
+ * Callback kinds
+ * @ingroup cb
+ */
+enum nl_cb_kind {
+	/** Default handlers (quiet) */
+	NL_CB_DEFAULT,
+	/** Verbose default handlers (error messages printed) */
+	NL_CB_VERBOSE,
+	/** Debug handlers for debugging */
+	NL_CB_DEBUG,
+	/** Customized handler specified by the user */
+	NL_CB_CUSTOM,
+	__NL_CB_KIND_MAX,
+};
+
+#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
+
+/**
+ * Callback types
+ * @ingroup cb
+ */
+enum nl_cb_type {
+	/** Message is valid */
+	NL_CB_VALID,
+	/** Last message in a series of multi part messages received */
+	NL_CB_FINISH,
+	/** Report received that data was lost */
+	NL_CB_OVERRUN,
+	/** Message wants to be skipped */
+	NL_CB_SKIPPED,
+	/** Message is an acknowledge */
+	NL_CB_ACK,
+	/** Called for every message received */
+	NL_CB_MSG_IN,
+	/** Called for every message sent out except for nl_sendto() */
+	NL_CB_MSG_OUT,
+	/** Message is malformed and invalid */
+	NL_CB_INVALID,
+	/** Called instead of internal sequence number checking */
+	NL_CB_SEQ_CHECK,
+	/** Sending of an acknowledge message has been requested */
+	NL_CB_SEND_ACK,
+	/** Flag NLM_F_DUMP_INTR is set in message */
+	NL_CB_DUMP_INTR,
+	__NL_CB_TYPE_MAX,
+};
+
+#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
+
+extern struct nl_cb *	nl_cb_alloc(enum nl_cb_kind);
+extern struct nl_cb *	nl_cb_clone(struct nl_cb *);
+extern struct nl_cb *	nl_cb_get(struct nl_cb *);
+extern void		nl_cb_put(struct nl_cb *);
+
+extern int  nl_cb_set(struct nl_cb *, enum nl_cb_type, enum nl_cb_kind,
+		      nl_recvmsg_msg_cb_t, void *);
+extern int  nl_cb_set_all(struct nl_cb *, enum nl_cb_kind,
+			  nl_recvmsg_msg_cb_t, void *);
+extern int  nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t,
+		      void *);
+
+extern void nl_cb_overwrite_recvmsgs(struct nl_cb *,
+				     int (*func)(struct nl_sock *,
+						 struct nl_cb *));
+extern void nl_cb_overwrite_recv(struct nl_cb *,
+				 int (*func)(struct nl_sock *,
+					     struct sockaddr_nl *,
+					     unsigned char **,
+					     struct ucred **));
+extern void nl_cb_overwrite_send(struct nl_cb *,
+				 int (*func)(struct nl_sock *,
+					     struct nl_msg *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/list.h b/libnetwork/libnl3/include/netlink/list.h
new file mode 100644
index 0000000..28712ed
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/list.h
@@ -0,0 +1,93 @@
+/*
+ * netlink/list.h	Netlink List Utilities
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LIST_H_
+#define NETLINK_LIST_H_
+
+struct nl_list_head
+{
+	struct nl_list_head *	next;
+	struct nl_list_head *	prev;
+};
+
+static inline void NL_INIT_LIST_HEAD(struct nl_list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static inline void __nl_list_add(struct nl_list_head *obj,
+				 struct nl_list_head *prev,
+				 struct nl_list_head *next)
+{
+	prev->next = obj;
+	obj->prev = prev;
+	next->prev = obj;
+	obj->next = next;
+}
+
+static inline void nl_list_add_tail(struct nl_list_head *obj,
+				    struct nl_list_head *head)
+{
+	__nl_list_add(obj, head->prev, head);
+}
+
+static inline void nl_list_add_head(struct nl_list_head *obj,
+				    struct nl_list_head *head)
+{
+	__nl_list_add(obj, head, head->next);
+}
+
+static inline void nl_list_del(struct nl_list_head *obj)
+{
+	obj->next->prev = obj->prev;
+	obj->prev->next = obj->next;
+}
+
+static inline int nl_list_empty(struct nl_list_head *head)
+{
+	return head->next == head;
+}
+
+#define nl_container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
+
+#define nl_list_entry(ptr, type, member) \
+	nl_container_of(ptr, type, member)
+
+#define nl_list_at_tail(pos, head, member) \
+	((pos)->member.next == (head))
+
+#define nl_list_at_head(pos, head, member) \
+	((pos)->member.prev == (head))
+
+#define NL_LIST_HEAD(name) \
+	struct nl_list_head name = { &(name), &(name) }
+
+#define nl_list_first_entry(head, type, member)			\
+	nl_list_entry((head)->next, type, member)
+
+#define nl_list_for_each_entry(pos, head, member)				\
+	for (pos = nl_list_entry((head)->next, typeof(*pos), member);	\
+	     &(pos)->member != (head); 	\
+	     (pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member))
+
+#define nl_list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = nl_list_entry((head)->next, typeof(*pos), member),	\
+		n = nl_list_entry(pos->member.next, typeof(*pos), member);	\
+	     &(pos)->member != (head); 					\
+	     pos = n, n = nl_list_entry(n->member.next, typeof(*n), member))
+
+#define nl_init_list_head(head) \
+	do { (head)->next = (head); (head)->prev = (head); } while (0)
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/msg.h b/libnetwork/libnl3/include/netlink/msg.h
new file mode 100644
index 0000000..f3d50ae
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/msg.h
@@ -0,0 +1,147 @@
+/*
+ * netlink/msg.c		Netlink Messages Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_MSG_H_
+#define NETLINK_MSG_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NL_DONTPAD	0
+
+/**
+ * @ingroup msg
+ * @brief
+ * Will cause the netlink port to be set to the port assigned to
+ * the netlink icoket ust before sending the message off.
+ *
+ * @note Requires the use of nl_send_auto()!
+ */
+#define NL_AUTO_PORT	0
+#define NL_AUTO_PID	NL_AUTO_PORT
+
+/**
+ * @ingroup msg
+ * @brief
+ * May be used to refer to a sequence number which should be
+ * automatically set just before sending the message off.
+ *
+ * @note Requires the use of nl_send_auto()!
+ */
+#define NL_AUTO_SEQ	0
+
+struct nl_msg;
+struct nl_tree;
+struct ucred;
+
+extern int			nlmsg_size(int);
+extern int			nlmsg_total_size(int);
+extern int			nlmsg_padlen(int);
+
+extern void *			nlmsg_data(const struct nlmsghdr *);
+extern int			nlmsg_datalen(const struct nlmsghdr *);
+extern void *			nlmsg_tail(const struct nlmsghdr *);
+
+/* attribute access */
+extern struct nlattr *	  nlmsg_attrdata(const struct nlmsghdr *, int);
+extern int		  nlmsg_attrlen(const struct nlmsghdr *, int);
+
+/* message parsing */
+extern int		  nlmsg_valid_hdr(const struct nlmsghdr *, int);
+extern int		  nlmsg_ok(const struct nlmsghdr *, int);
+extern struct nlmsghdr *  nlmsg_next(struct nlmsghdr *, int *);
+extern int		  nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+				      int, struct nla_policy *);
+extern struct nlattr *	  nlmsg_find_attr(struct nlmsghdr *, int, int);
+extern int		  nlmsg_validate(struct nlmsghdr *, int, int,
+					 struct nla_policy *);
+
+extern struct nl_msg *	  nlmsg_alloc(void);
+extern struct nl_msg *	  nlmsg_alloc_size(size_t);
+extern struct nl_msg *	  nlmsg_alloc_simple(int, int);
+extern void		  nlmsg_set_default_size(size_t);
+extern struct nl_msg *	  nlmsg_inherit(struct nlmsghdr *);
+extern struct nl_msg *	  nlmsg_convert(struct nlmsghdr *);
+extern void *		  nlmsg_reserve(struct nl_msg *, size_t, int);
+extern int		  nlmsg_append(struct nl_msg *, void *, size_t, int);
+extern int		  nlmsg_expand(struct nl_msg *, size_t);
+
+extern struct nlmsghdr *  nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+				    int, int, int);
+extern struct nlmsghdr *  nlmsg_hdr(struct nl_msg *);
+extern void		  nlmsg_get(struct nl_msg *);
+extern void		  nlmsg_free(struct nl_msg *);
+
+/* attribute modification */
+extern void		  nlmsg_set_proto(struct nl_msg *, int);
+extern int		  nlmsg_get_proto(struct nl_msg *);
+extern size_t		  nlmsg_get_max_size(struct nl_msg *);
+extern void		  nlmsg_set_src(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_src(struct nl_msg *);
+extern void		  nlmsg_set_dst(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *);
+extern void		  nlmsg_set_creds(struct nl_msg *, struct ucred *);
+extern struct ucred *	  nlmsg_get_creds(struct nl_msg *);
+
+extern char *		  nl_nlmsgtype2str(int, char *, size_t);
+extern int		  nl_str2nlmsgtype(const char *);
+
+extern char *		  nl_nlmsg_flags2str(int, char *, size_t);
+
+extern int		  nl_msg_parse(struct nl_msg *,
+				       void (*cb)(struct nl_object *, void *),
+				       void *);
+
+extern void		nl_msg_dump(struct nl_msg *, FILE *);
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup msg
+ * Iterate over a stream of attributes in a message
+ * @arg pos	loop counter, set to current attribute
+ * @arg nlh	netlink message header
+ * @arg hdrlen	length of family header
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
+	nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
+			  nlmsg_attrlen(nlh, hdrlen), rem)
+
+/**
+ * Iterate over a stream of messages
+ * @arg pos	loop counter, set to current message
+ * @arg head	head of message stream
+ * @arg len	length of message stream
+ */
+#define nlmsg_for_each(pos, head, len) \
+	for (int rem = len, pos = head; \
+		nlmsg_ok(pos, rem); \
+		pos = nlmsg_next(pos, &rem))
+
+#define nlmsg_for_each_msg(pos, head, len, rem) \
+		nlmsg_for_each(pos, head, len)
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/netfilter/ct.h b/libnetwork/libnl3/include/netlink/netfilter/ct.h
new file mode 100644
index 0000000..57fbe53
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/ct.h
@@ -0,0 +1,126 @@
+/*
+ * netlink/netfilter/ct.h	Conntrack
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#ifndef NETLINK_CT_H_
+#define NETLINK_CT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+#include <netlink/cache.h>
+#include <netlink/msg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nfnl_ct;
+
+extern struct nl_object_ops ct_obj_ops;
+
+extern struct nfnl_ct *	nfnl_ct_alloc(void);
+extern int	nfnl_ct_alloc_cache(struct nl_sock *, struct nl_cache **);
+
+extern int	nfnlmsg_ct_group(struct nlmsghdr *);
+extern int	nfnlmsg_ct_parse(struct nlmsghdr *, struct nfnl_ct **);
+
+extern void	nfnl_ct_get(struct nfnl_ct *);
+extern void	nfnl_ct_put(struct nfnl_ct *);
+
+extern int	nfnl_ct_dump_request(struct nl_sock *);
+
+extern int	nfnl_ct_build_add_request(const struct nfnl_ct *, int,
+					  struct nl_msg **);
+extern int	nfnl_ct_add(struct nl_sock *, const struct nfnl_ct *, int);
+
+extern int	nfnl_ct_build_delete_request(const struct nfnl_ct *, int,
+					     struct nl_msg **);
+extern int	nfnl_ct_del(struct nl_sock *, const struct nfnl_ct *, int);
+
+extern int	nfnl_ct_build_query_request(const struct nfnl_ct *, int,
+					    struct nl_msg **);
+extern int	nfnl_ct_query(struct nl_sock *, const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_family(struct nfnl_ct *, uint8_t);
+extern uint8_t	nfnl_ct_get_family(const struct nfnl_ct *);
+
+extern void	nfnl_ct_set_proto(struct nfnl_ct *, uint8_t);
+extern int	nfnl_ct_test_proto(const struct nfnl_ct *);
+extern uint8_t	nfnl_ct_get_proto(const struct nfnl_ct *);
+
+extern void	nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t);
+extern int	nfnl_ct_test_tcp_state(const struct nfnl_ct *);
+extern uint8_t	nfnl_ct_get_tcp_state(const struct nfnl_ct *);
+extern char *	nfnl_ct_tcp_state2str(uint8_t, char *, size_t);
+extern int	nfnl_ct_str2tcp_state(const char *name);
+
+extern void	nfnl_ct_set_status(struct nfnl_ct *, uint32_t);
+extern void	nfnl_ct_unset_status(struct nfnl_ct *, uint32_t);
+extern uint32_t	nfnl_ct_get_status(const struct nfnl_ct *);
+extern char *	nfnl_ct_status2str(int, char *, size_t);
+extern int	nfnl_ct_str2status(const char *);
+
+extern void	nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_timeout(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_timeout(const struct nfnl_ct *);
+
+extern void	nfnl_ct_set_mark(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_mark(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_mark(const struct nfnl_ct *);
+
+extern void	nfnl_ct_set_use(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_use(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_use(const struct nfnl_ct *);
+
+extern void	nfnl_ct_set_id(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_id(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_id(const struct nfnl_ct *);
+
+extern int	nfnl_ct_set_src(struct nfnl_ct *, int, struct nl_addr *);
+extern struct nl_addr *	nfnl_ct_get_src(const struct nfnl_ct *, int);
+
+extern int	nfnl_ct_set_dst(struct nfnl_ct *, int, struct nl_addr *);
+extern struct nl_addr *	nfnl_ct_get_dst(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_src_port(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_src_port(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_dst_port(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_dst_port(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_icmp_id(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_icmp_id(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t);
+extern int	nfnl_ct_test_icmp_type(const struct nfnl_ct *, int);
+extern uint8_t	nfnl_ct_get_icmp_type(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t);
+extern int	nfnl_ct_test_icmp_code(const struct nfnl_ct *, int);
+extern uint8_t	nfnl_ct_get_icmp_code(const struct nfnl_ct *, int);
+
+extern void	nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t);
+extern int	nfnl_ct_test_packets(const struct nfnl_ct *, int);
+extern uint64_t	nfnl_ct_get_packets(const struct nfnl_ct *,int);
+
+extern void	nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t);
+extern int	nfnl_ct_test_bytes(const struct nfnl_ct *, int);
+extern uint64_t	nfnl_ct_get_bytes(const struct nfnl_ct *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/netfilter/log.h b/libnetwork/libnl3/include/netlink/netfilter/log.h
new file mode 100644
index 0000000..2002fa8
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/log.h
@@ -0,0 +1,109 @@
+/*
+ * netlink/netfilter/log.h	Netfilter Log
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#ifndef NETLINK_LOG_H_
+#define NETLINK_LOG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_log;
+
+extern struct nl_object_ops log_obj_ops;
+
+enum nfnl_log_copy_mode {
+	NFNL_LOG_COPY_NONE,
+	NFNL_LOG_COPY_META,
+	NFNL_LOG_COPY_PACKET,
+};
+
+enum nfnl_log_flags {
+	NFNL_LOG_FLAG_SEQ		= 0x1,
+	NFNL_LOG_FLAG_SEQ_GLOBAL	= 0x2,
+};
+
+/* General */
+extern struct nfnl_log *	nfnl_log_alloc(void);
+extern int			nfnlmsg_log_parse(struct nlmsghdr *,
+						  struct nfnl_log **);
+
+extern void			nfnl_log_get(struct nfnl_log *);
+extern void			nfnl_log_put(struct nfnl_log *);
+
+/* Attributes */
+extern void			nfnl_log_set_group(struct nfnl_log *, uint16_t);
+extern int			nfnl_log_test_group(const struct nfnl_log *);
+extern uint16_t			nfnl_log_get_group(const struct nfnl_log *);
+
+extern void			nfnl_log_set_copy_mode(struct nfnl_log *,
+						       enum nfnl_log_copy_mode);
+extern int			nfnl_log_test_copy_mode(const struct nfnl_log *);
+extern enum nfnl_log_copy_mode	nfnl_log_get_copy_mode(const struct nfnl_log *);
+
+extern char *			nfnl_log_copy_mode2str(enum nfnl_log_copy_mode,
+						       char *, size_t);
+extern enum nfnl_log_copy_mode	nfnl_log_str2copy_mode(const char *);
+
+extern void			nfnl_log_set_copy_range(struct nfnl_log *, uint32_t);
+extern int			nfnl_log_test_copy_range(const struct nfnl_log *);
+extern uint32_t			nfnl_log_get_copy_range(const struct nfnl_log *);
+
+extern void			nfnl_log_set_flush_timeout(struct nfnl_log *, uint32_t);
+extern int			nfnl_log_test_flush_timeout(const struct nfnl_log *);
+extern uint32_t			nfnl_log_get_flush_timeout(const struct nfnl_log *);
+
+extern void			nfnl_log_set_alloc_size(struct nfnl_log *, uint32_t);
+extern int			nfnl_log_test_alloc_size(const struct nfnl_log *);
+extern uint32_t			nfnl_log_get_alloc_size(const struct nfnl_log *);
+
+extern void			nfnl_log_set_queue_threshold(struct nfnl_log *, uint32_t);
+extern int			nfnl_log_test_queue_threshold(const struct nfnl_log *);
+extern uint32_t			nfnl_log_get_queue_threshold(const struct nfnl_log *);
+
+extern void			nfnl_log_set_flags(struct nfnl_log *, unsigned int);
+extern void			nfnl_log_unset_flags(struct nfnl_log *, unsigned int);
+extern unsigned int		nfnl_log_get_flags(const struct nfnl_log *);
+
+extern char *			nfnl_log_flags2str(unsigned int, char *, size_t);
+extern unsigned int		nfnl_log_str2flags(const char *);
+
+extern int	nfnl_log_build_pf_bind(uint8_t, struct nl_msg **);
+extern int	nfnl_log_pf_bind(struct nl_sock *, uint8_t);
+
+extern int	nfnl_log_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int	nfnl_log_pf_unbind(struct nl_sock *, uint8_t);
+
+extern int	nfnl_log_build_create_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_create(struct nl_sock *, const struct nfnl_log *);
+
+extern int	nfnl_log_build_change_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_change(struct nl_sock *, const struct nfnl_log *);
+
+extern int	nfnl_log_build_delete_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_delete(struct nl_sock *, const struct nfnl_log *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnetwork/libnl3/include/netlink/netfilter/log_msg.h b/libnetwork/libnl3/include/netlink/netfilter/log_msg.h
new file mode 100644
index 0000000..63b0f64
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/log_msg.h
@@ -0,0 +1,98 @@
+/*
+ * netlink/netfilter/log_msg.h	Netfilter Log Message
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#ifndef NETLINK_LOG_MSG_H_
+#define NETLINK_LOG_MSG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nlmsghdr;
+struct nfnl_log_msg;
+
+extern struct nl_object_ops log_msg_obj_ops;
+
+/* General */
+extern struct nfnl_log_msg *nfnl_log_msg_alloc(void);
+extern int		nfnlmsg_log_msg_parse(struct nlmsghdr *,
+					      struct nfnl_log_msg **);
+
+extern void		nfnl_log_msg_get(struct nfnl_log_msg *);
+extern void		nfnl_log_msg_put(struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_family(struct nfnl_log_msg *, uint8_t);
+extern uint8_t		nfnl_log_msg_get_family(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_hwproto(struct nfnl_log_msg *, uint16_t);
+extern int		nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *);
+extern uint16_t		nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_hook(struct nfnl_log_msg *, uint8_t);
+extern int		nfnl_log_msg_test_hook(const struct nfnl_log_msg *);
+extern uint8_t		nfnl_log_msg_get_hook(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_mark(struct nfnl_log_msg *, uint32_t);
+extern int		nfnl_log_msg_test_mark(const struct nfnl_log_msg *);
+extern uint32_t		nfnl_log_msg_get_mark(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_timestamp(struct nfnl_log_msg *,
+					       struct timeval *);
+extern const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_indev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t		nfnl_log_msg_get_indev(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_outdev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t		nfnl_log_msg_get_outdev(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_physindev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t		nfnl_log_msg_get_physindev(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t		nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *, uint8_t *, int);
+extern const uint8_t *	nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *, int *);
+
+extern int		nfnl_log_msg_set_payload(struct nfnl_log_msg *, uint8_t *, int);
+extern const void *	nfnl_log_msg_get_payload(const struct nfnl_log_msg *, int *);
+
+extern int		nfnl_log_msg_set_prefix(struct nfnl_log_msg *, void *);
+extern const char *	nfnl_log_msg_get_prefix(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_uid(struct nfnl_log_msg *, uint32_t);
+extern int		nfnl_log_msg_test_uid(const struct nfnl_log_msg *);
+extern uint32_t		nfnl_log_msg_get_uid(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_gid(struct nfnl_log_msg *, uint32_t);
+extern int		nfnl_log_msg_test_gid(const struct nfnl_log_msg *);
+extern uint32_t		nfnl_log_msg_get_gid(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_seq(struct nfnl_log_msg *, uint32_t);
+extern int		nfnl_log_msg_test_seq(const struct nfnl_log_msg *);
+extern uint32_t		nfnl_log_msg_get_seq(const struct nfnl_log_msg *);
+
+extern void		nfnl_log_msg_set_seq_global(struct nfnl_log_msg *, uint32_t);
+extern int		nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *);
+extern uint32_t		nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnetwork/libnl3/include/netlink/netfilter/netfilter.h b/libnetwork/libnl3/include/netlink/netfilter/netfilter.h
new file mode 100644
index 0000000..dd3589c
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/netfilter.h
@@ -0,0 +1,31 @@
+/*
+ * netlink/netfilter/netfilter.h	Netfilter generic functions
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#ifndef NETLINK_NETFILTER_H_
+#define NETLINK_NETFILTER_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *			nfnl_verdict2str(unsigned int, char *, size_t);
+extern unsigned int		nfnl_str2verdict(const char *);
+
+extern char *			nfnl_inet_hook2str(unsigned int, char *, size_t);
+extern unsigned int		nfnl_str2inet_hook(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/netfilter/nfnl.h b/libnetwork/libnl3/include/netlink/netfilter/nfnl.h
new file mode 100644
index 0000000..8da4ba1
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/nfnl.h
@@ -0,0 +1,44 @@
+/*
+ * netlink/nfnl/nfnl.h		Netfilter Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#ifndef NETLINK_NFNL_H_
+#define NETLINK_NFNL_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NFNL_HDRLEN NLMSG_ALIGN(sizeof(struct nfgenmsg))
+#define NFNLMSG_TYPE(subsys, subtype) (((subsys) << 8) | (subtype))
+
+extern int		nfnl_connect(struct nl_sock *);
+
+extern uint8_t		nfnlmsg_subsys(struct nlmsghdr *);
+extern uint8_t		nfnlmsg_subtype(struct nlmsghdr *);
+extern uint8_t		nfnlmsg_family(struct nlmsghdr *);
+extern uint16_t		nfnlmsg_res_id(struct nlmsghdr *);
+
+extern int		nfnl_send_simple(struct nl_sock *, uint8_t, uint8_t,
+					 int, uint8_t, uint16_t);
+extern struct nl_msg *	nfnlmsg_alloc_simple(uint8_t, uint8_t, int,
+					     uint8_t, uint16_t);
+extern int		nfnlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+				    uint8_t, uint8_t, int, uint8_t, uint16_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/netfilter/queue.h b/libnetwork/libnl3/include/netlink/netfilter/queue.h
new file mode 100644
index 0000000..664610d
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/queue.h
@@ -0,0 +1,90 @@
+/*
+ * netlink/netfilter/queue.h	Netfilter Queue
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#ifndef NETLINK_QUEUE_H_
+#define NETLINK_QUEUE_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_queue;
+
+extern struct nl_object_ops queue_obj_ops;
+
+enum nfnl_queue_copy_mode {
+	NFNL_QUEUE_COPY_NONE,
+	NFNL_QUEUE_COPY_META,
+	NFNL_QUEUE_COPY_PACKET,
+};
+
+/* General */
+extern struct nl_sock *		nfnl_queue_socket_alloc(void);
+
+extern struct nfnl_queue *	nfnl_queue_alloc(void);
+
+extern void			nfnl_queue_get(struct nfnl_queue *);
+extern void			nfnl_queue_put(struct nfnl_queue *);
+
+/* Attributes */
+extern void			nfnl_queue_set_group(struct nfnl_queue *, uint16_t);
+extern int			nfnl_queue_test_group(const struct nfnl_queue *);
+extern uint16_t			nfnl_queue_get_group(const struct nfnl_queue *);
+
+extern void			nfnl_queue_set_maxlen(struct nfnl_queue *, uint32_t);
+extern int			nfnl_queue_test_maxlen(const struct nfnl_queue *);
+extern uint32_t			nfnl_queue_get_maxlen(const struct nfnl_queue *);
+
+extern void			nfnl_queue_set_copy_mode(struct nfnl_queue *,
+							 enum nfnl_queue_copy_mode);
+extern int			nfnl_queue_test_copy_mode(const struct nfnl_queue *);
+extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *);
+
+extern char *			nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode,
+							 char *, size_t);
+extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *);
+
+extern void			nfnl_queue_set_copy_range(struct nfnl_queue *,
+							  uint32_t);
+extern int			nfnl_queue_test_copy_range(const struct nfnl_queue *);
+extern uint32_t			nfnl_queue_get_copy_range(const struct nfnl_queue *);
+
+extern int	nfnl_queue_build_pf_bind(uint8_t, struct nl_msg **);
+extern int	nfnl_queue_pf_bind(struct nl_sock *, uint8_t);
+
+extern int	nfnl_queue_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int	nfnl_queue_pf_unbind(struct nl_sock *, uint8_t);
+
+extern int	nfnl_queue_build_create_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_create(struct nl_sock *,
+				  const struct nfnl_queue *);
+
+extern int	nfnl_queue_build_change_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_change(struct nl_sock *,
+				  const struct nfnl_queue *);
+
+extern int	nfnl_queue_build_delete_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_delete(struct nl_sock *,
+				  const struct nfnl_queue *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h b/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h
new file mode 100644
index 0000000..24ed081
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h
@@ -0,0 +1,104 @@
+/*
+ * netlink/netfilter/queue_msg.h	Netfilter Queue Messages
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#ifndef NETLINK_QUEUE_MSG_H_
+#define NETLINK_QUEUE_MSG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_queue_msg;
+
+extern struct nl_object_ops queue_msg_obj_ops;
+
+/* General */
+extern struct nfnl_queue_msg *	nfnl_queue_msg_alloc(void);
+extern int			nfnlmsg_queue_msg_parse(struct nlmsghdr *,
+						struct nfnl_queue_msg **);
+
+extern void			nfnl_queue_msg_get(struct nfnl_queue_msg *);
+extern void			nfnl_queue_msg_put(struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_group(struct nfnl_queue_msg *, uint16_t);
+extern int			nfnl_queue_msg_test_group(const struct nfnl_queue_msg *);
+extern uint16_t			nfnl_queue_msg_get_group(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_family(struct nfnl_queue_msg *, uint8_t);
+extern int			nfnl_queue_msg_test_family(const struct nfnl_queue_msg *);
+extern uint8_t			nfnl_queue_msg_get_family(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *, uint16_t);
+extern int			nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *);
+extern uint16_t			nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_hook(struct nfnl_queue_msg *, uint8_t);
+extern int			nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *);
+extern uint8_t			nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_mark(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *,
+							      struct timeval *);
+extern int			nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *);
+extern const struct timeval *	nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_indev(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *, uint32_t);
+extern int			nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *);
+extern uint32_t			nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *);
+
+extern void			nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *, uint8_t *, int);
+extern int			nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *);
+extern const uint8_t *		nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *, int *);
+
+extern int			nfnl_queue_msg_set_payload(struct nfnl_queue_msg *, uint8_t *, int);
+extern int			nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *);
+extern const void *		nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *, int *);
+
+extern void			nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *,
+							   unsigned int);
+extern int			nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *);
+extern unsigned int		nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *);
+
+extern struct nl_msg *		nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *);
+extern int			nfnl_queue_msg_send_verdict(struct nl_sock *,
+							    const struct nfnl_queue_msg *);
+extern int			nfnl_queue_msg_send_verdict_payload(struct nl_sock *,
+						const struct nfnl_queue_msg *,
+						const void *, unsigned );
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnetwork/libnl3/include/netlink/netlink-compat.h b/libnetwork/libnl3/include/netlink/netlink-compat.h
new file mode 100644
index 0000000..17ec9fc
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netlink-compat.h
@@ -0,0 +1,50 @@
+/*
+ * netlink/netlink-compat.h	Netlink Compatability
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_COMPAT_H_
+#define NETLINK_COMPAT_H_
+
+#if !defined _LINUX_SOCKET_H && !defined _BITS_SOCKADDR_H
+typedef unsigned short  sa_family_t;
+#endif
+
+#ifndef IFNAMSIZ 
+/** Maximum length of a interface name */
+#define IFNAMSIZ 16
+#endif
+
+/* patch 2.4.x if_arp */
+#ifndef ARPHRD_INFINIBAND
+#define ARPHRD_INFINIBAND 32
+#endif
+
+/* patch 2.4.x eth header file */
+#ifndef ETH_P_MPLS_UC
+#define ETH_P_MPLS_UC  0x8847 
+#endif
+
+#ifndef ETH_P_MPLS_MC
+#define ETH_P_MPLS_MC   0x8848
+#endif
+
+#ifndef  ETH_P_EDP2
+#define ETH_P_EDP2      0x88A2
+#endif
+
+#ifndef ETH_P_HDLC
+#define ETH_P_HDLC      0x0019 
+#endif
+
+#ifndef AF_LLC
+#define AF_LLC		26
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/netlink-kernel.h b/libnetwork/libnl3/include/netlink/netlink-kernel.h
new file mode 100644
index 0000000..f09051d
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netlink-kernel.h
@@ -0,0 +1,293 @@
+#ifndef __NETLINK_KERNEL_H_
+#define __NETLINK_KERNEL_H_
+
+#if 0
+
+/*
+ * FIXME: Goal is to preseve the documentation but make it simple
+ * to keep linux/netlink.h in sync. Maybe use named documentation
+ * sections.
+ */
+
+/**
+ * Netlink socket address
+ * @ingroup nl
+ */
+struct sockaddr_nl
+{
+	/** socket family (AF_NETLINK) */
+	sa_family_t     nl_family;
+
+	/** Padding (unused) */
+	unsigned short  nl_pad;
+
+	/** Unique process ID  */
+	uint32_t        nl_pid;
+
+	/** Multicast group subscriptions */
+	uint32_t        nl_groups;
+};
+
+/**
+ * @addtogroup msg
+ * @{
+ */
+
+
+/**
+ * Netlink message header
+ */
+struct nlmsghdr
+{
+	/** Length of message including header and padding. */
+	uint32_t	nlmsg_len;
+
+	/** Message type (content type) */
+	uint16_t	nlmsg_type;
+
+	/** Message flags */
+	uint16_t	nlmsg_flags;
+
+	/** Sequence number of message \see core_sk_seq_num. */
+	uint32_t	nlmsg_seq;
+
+	/** Netlink port */
+	uint32_t	nlmsg_pid;
+};
+
+/**
+ * @name Standard message flags
+ * @{
+ */
+
+/**
+ * Must be set on all request messages (typically from user space to
+ * kernel space).
+ */
+#define NLM_F_REQUEST		1
+
+/**
+ * Indicates the message is part of a multipart message terminated
+ * by NLMSG_DONE.
+ */
+#define NLM_F_MULTI		2
+
+/**
+ * Request for an acknowledgment on success.
+ */
+#define NLM_F_ACK		4
+
+/**
+ * Echo this request
+ */
+#define NLM_F_ECHO		8
+
+/** @} */
+
+/**
+ * @name Additional message flags for GET requests
+ * @{
+ */
+
+/**
+ * Return the complete table instead of a single entry.
+ */
+#define NLM_F_ROOT	0x100
+
+/**
+ * Return all entries matching criteria passed in message content.
+ */
+#define NLM_F_MATCH	0x200
+
+/**
+ * Return an atomic snapshot of the table being referenced. This
+ * may require special privileges because it has the potential to
+ * interrupt service in the FE for a longer time.
+ */
+#define NLM_F_ATOMIC	0x400
+
+/**
+ * Dump all entries
+ */
+#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+
+/** @} */
+
+/**
+ * @name Additional messsage flags for NEW requests
+ * @{
+ */
+
+/**
+ * Replace existing matching config object with this request.
+ */
+#define NLM_F_REPLACE	0x100
+
+/**
+ * Don't replace the config object if it already exists.
+ */
+#define NLM_F_EXCL	0x200
+
+/**
+ * Create config object if it doesn't already exist.
+ */
+#define NLM_F_CREATE	0x400
+
+/**
+ * Add to the end of the object list.
+ */
+#define NLM_F_APPEND	0x800
+
+/** @} */
+
+/**
+ * @name Standard Message types
+ * @{
+ */
+
+/**
+ * No operation, message must be ignored
+ */
+#define NLMSG_NOOP		0x1
+
+/**
+ * The message signals an error and the payload contains a nlmsgerr
+ * structure. This can be looked at as a NACK and typically it is
+ * from FEC to CPC.
+ */
+#define NLMSG_ERROR		0x2
+
+/**
+ * Message terminates a multipart message.
+ */
+#define NLMSG_DONE		0x3
+
+/**
+ * The message signals that data got lost
+ */
+#define NLMSG_OVERRUN		0x4
+
+/**
+ * Lower limit of reserved message types
+ */
+#define NLMSG_MIN_TYPE		0x10
+
+/** @} */
+
+/**
+ * Netlink error message header
+ */
+struct nlmsgerr
+{
+	/** Error code (errno number) */
+	int		error;
+
+	/** Original netlink message causing the error */
+	struct nlmsghdr	msg;
+};
+
+struct nl_pktinfo
+{
+	__u32	group;
+};
+
+/**
+ * Netlink alignment constant, all boundries within messages must be align to this.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_ALIGNTO	4
+
+/**
+ * Returns \p len properly aligned to NLMSG_ALIGNTO.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+
+/**
+ * Length of a netlink message header including padding.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+
+/** @} */
+
+/**
+ * @addtogroup attr
+ * @{
+ */
+
+/*
+ */
+
+/**
+ * Netlink attribute structure
+ *
+ * @code
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ * @endcode
+ */
+struct nlattr {
+	/**
+	 * Attribute length in bytes including header
+	 */
+	__u16           nla_len;
+
+	/**
+	 * Netlink attribute type
+	 */
+	__u16           nla_type;
+};
+
+/**
+ * @name Attribute Type Flags
+ *
+ * @code
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ * @endcode
+ *
+ * @note The N and O flag are mutually exclusive.
+ *
+ * @{
+ */
+
+/*
+ */
+#define NLA_F_NESTED		(1 << 15)
+#define NLA_F_NET_BYTEORDER	(1 << 14)
+#define NLA_TYPE_MASK		~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+/** @} */
+
+#define NLA_ALIGNTO		4
+
+/**
+ * Returns \p len properly aligned to NLA_ALIGNTO.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+
+/**
+ * Length of a netlink attribute header including padding.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/** @} */
+
+#endif
+#endif	/* __LINUX_NETLINK_H */
diff --git a/libnetwork/libnl3/include/netlink/netlink.h b/libnetwork/libnl3/include/netlink/netlink.h
new file mode 100644
index 0000000..0768708
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/netlink.h
@@ -0,0 +1,93 @@
+/*
+ * netlink/netlink.h		Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_NETLINK_H_
+#define NETLINK_NETLINK_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <netlink/netlink-compat.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/genetlink.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <netlink/version.h>
+#include <netlink/errno.h>
+#include <netlink/types.h>
+#include <netlink/handlers.h>
+#include <netlink/socket.h>
+#include <netlink/object.h>
+#include <netlink/cache-api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ucred;
+
+extern int nl_debug;
+extern struct nl_dump_params nl_debug_dp;
+
+/* Connection Management */
+extern int			nl_connect(struct nl_sock *, int);
+extern void			nl_close(struct nl_sock *);
+
+/* Send */
+extern int			nl_sendto(struct nl_sock *, void *, size_t);
+extern int			nl_sendmsg(struct nl_sock *, struct nl_msg *,
+					   struct msghdr *);
+extern int			nl_send(struct nl_sock *, struct nl_msg *);
+extern int			nl_send_iovec(struct nl_sock *, struct nl_msg *,
+					      struct iovec *, unsigned);
+extern void			nl_complete_msg(struct nl_sock *,
+						struct nl_msg *);
+extern void			nl_auto_complete(struct nl_sock *,
+						 struct nl_msg *);
+extern int			nl_send_auto(struct nl_sock *, struct nl_msg *);
+extern int			nl_send_auto_complete(struct nl_sock *,
+						      struct nl_msg *);
+extern int			nl_send_sync(struct nl_sock *, struct nl_msg *);
+extern int			nl_send_simple(struct nl_sock *, int, int,
+					       void *, size_t);
+
+/* Receive */
+extern int			nl_recv(struct nl_sock *,
+					struct sockaddr_nl *, unsigned char **,
+					struct ucred **);
+
+extern int			nl_recvmsgs(struct nl_sock *, struct nl_cb *);
+
+extern int			nl_recvmsgs_default(struct nl_sock *);
+
+extern int			nl_wait_for_ack(struct nl_sock *);
+
+extern int			nl_pickup(struct nl_sock *,
+					  int (*parser)(struct nl_cache_ops *,
+						struct sockaddr_nl *,
+						struct nlmsghdr *,
+						struct nl_parser_param *),
+					  struct nl_object **);
+/* Netlink Family Translations */
+extern char *			nl_nlfamily2str(int, char *, size_t);
+extern int			nl_str2nlfamily(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/object-api.h b/libnetwork/libnl3/include/netlink/object-api.h
new file mode 100644
index 0000000..70a4ddd
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/object-api.h
@@ -0,0 +1,348 @@
+/*
+ * netlink/object-api.c		Object API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2007 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_API_H_
+#define NETLINK_OBJECT_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup object
+ * @defgroup object_api Object API
+ * @brief
+ *
+ * @par 1) Object Definition
+ * @code
+ * // Define your object starting with the common object header
+ * struct my_obj {
+ * 	NLHDR_COMMON
+ * 	int		my_data;
+ * };
+ *
+ * // Fill out the object operations structure
+ * struct nl_object_ops my_ops = {
+ * 	.oo_name	= "my_obj",
+ * 	.oo_size	= sizeof(struct my_obj),
+ * };
+ *
+ * // At this point the object can be allocated, you may want to provide a
+ * // separate _alloc() function to ease allocting objects of this kind.
+ * struct nl_object *obj = nl_object_alloc(&my_ops);
+ *
+ * // And release it again...
+ * nl_object_put(obj);
+ * @endcode
+ *
+ * @par 2) Allocating additional data
+ * @code
+ * // You may require to allocate additional data and store it inside
+ * // object, f.e. assuming there is a field `ptr'.
+ * struct my_obj {
+ * 	NLHDR_COMMON
+ * 	void *		ptr;
+ * };
+ *
+ * // And at some point you may assign allocated data to this field:
+ * my_obj->ptr = calloc(1, ...);
+ *
+ * // In order to not introduce any memory leaks you have to release
+ * // this data again when the last reference is given back.
+ * static void my_obj_free_data(struct nl_object *obj)
+ * {
+ * 	struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ * 	free(my_obj->ptr);
+ * }
+ *
+ * // Also when the object is cloned, you must ensure for your pointer
+ * // stay valid even if one of the clones is freed by either making
+ * // a clone as well or increase the reference count.
+ * static int my_obj_clone(struct nl_object *src, struct nl_object *dst)
+ * {
+ * 	struct my_obj *my_src = nl_object_priv(src);
+ * 	struct my_obj *my_dst = nl_object_priv(dst);
+ *
+ * 	if (src->ptr) {
+ * 		dst->ptr = calloc(1, ...);
+ * 		memcpy(dst->ptr, src->ptr, ...);
+ * 	}
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_free_data	= my_obj_free_data,
+ * 	.oo_clone	= my_obj_clone,
+ * };
+ * @endcode
+ *
+ * @par 3) Object Dumping
+ * @code
+ * static int my_obj_dump_detailed(struct nl_object *obj,
+ * 				   struct nl_dump_params *params)
+ * {
+ * 	struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ * 	// It is absolutely essential to use nl_dump() when printing
+ *	// any text to make sure the dumping parameters are respected.
+ * 	nl_dump(params, "Obj Integer: %d\n", my_obj->my_int);
+ *
+ * 	// Before we can dump the next line, make sure to prefix
+ *	// this line correctly.
+ * 	nl_new_line(params);
+ *
+ * 	// You may also split a line into multiple nl_dump() calls.
+ * 	nl_dump(params, "String: %s ", my_obj->my_string);
+ * 	nl_dump(params, "String-2: %s\n", my_obj->another_string);
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_dump[NL_DUMP_FULL]	= my_obj_dump_detailed,
+ * };
+ * @endcode
+ *
+ * @par 4) Object Attributes
+ * @code
+ * // The concept of object attributes is optional but can ease the typical
+ * // case of objects that have optional attributes, e.g. a route may have a
+ * // nexthop assigned but it is not required to.
+ *
+ * // The first step to define your object specific bitmask listing all
+ * // attributes
+ * #define MY_ATTR_FOO		(1<<0)
+ * #define MY_ATTR_BAR		(1<<1)
+ *
+ * // When assigning an optional attribute to the object, make sure
+ * // to mark its availability.
+ * my_obj->foo = 123123;
+ * my_obj->ce_mask |= MY_ATTR_FOO;
+ *
+ * // At any time you may use this mask to check for the availability
+ * // of the attribute, e.g. while dumping
+ * if (my_obj->ce_mask & MY_ATTR_FOO)
+ * 	nl_dump(params, "foo %d ", my_obj->foo);
+ *
+ * // One of the big advantages of this concept is that it allows for
+ * // standardized comparisons which make it trivial for caches to
+ * // identify unique objects by use of unified comparison functions.
+ * // In order for it to work, your object implementation must provide
+ * // a comparison function and define a list of attributes which
+ * // combined together make an object unique.
+ *
+ * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b,
+ * 			     uint32_t attrs, int flags)
+ * {
+ * 	struct my_obj *a = nl_object_priv(_a):
+ * 	struct my_obj *b = nl_object_priv(_b):
+ * 	int diff = 0;
+ *
+ * 	// We help ourselves in defining our own DIFF macro which will
+ *	// call ATTR_DIFF() on both objects which will make sure to only
+ *	// compare the attributes if required.
+ * 	#define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR)
+ *
+ * 	// Call our own diff macro for each attribute to build a bitmask
+ *	// representing the attributes which mismatch.
+ * 	diff |= MY_DIFF(FOO, a->foo != b->foo)
+ * 	diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar))
+ *
+ * 	return diff;
+ * }
+ *
+ * // In order to identify identical objects with differing attributes
+ * // you must specify the attributes required to uniquely identify
+ * // your object. Make sure to not include too many attributes, this
+ * // list is used when caches look for an old version of an object.
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_id_attrs		= MY_ATTR_FOO,
+ * 	.oo_compare		= my_obj_compare,
+ * };
+ * @endcode
+ * @{
+ */
+
+/**
+ * Common Object Header
+ *
+ * This macro must be included as first member in every object
+ * definition to allow objects to be cached.
+ */
+#define NLHDR_COMMON				\
+	int			ce_refcnt;	\
+	struct nl_object_ops *	ce_ops;		\
+	struct nl_cache *	ce_cache;	\
+	struct nl_list_head	ce_list;	\
+	int			ce_msgtype;	\
+	int			ce_flags;	\
+	uint32_t		ce_mask;
+
+struct nl_object
+{
+	NLHDR_COMMON
+};
+
+
+/**
+ * Return true if attribute is available in both objects
+ * @arg A		an object
+ * @arg B		another object
+ * @arg ATTR		attribute bit
+ *
+ * @return True if the attribute is available, otherwise false is returned.
+ */
+#define AVAILABLE(A, B, ATTR)		(((A)->ce_mask & (B)->ce_mask) & (ATTR))
+
+/**
+ * Return true if attribute is available in only one of both objects
+ * @arg A		an object
+ * @arg B		another object
+ * @arg ATTR		attribute bit
+ *
+ * @return True if the attribute is available in only one of both objects,
+ * otherwise false is returned.
+ */
+#define AVAILABLE_MISMATCH(A, B, ATTR)	(((A)->ce_mask ^ (B)->ce_mask) & (ATTR))
+
+/**
+ * Return true if attributes mismatch
+ * @arg A		an object
+ * @arg B		another object
+ * @arg ATTR		attribute bit
+ * @arg EXPR		Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * @return True if the attribute mismatch, or false if they match.
+ */
+#define ATTR_MISMATCH(A, B, ATTR, EXPR)	(AVAILABLE_MISMATCH(A, B, ATTR) || \
+					 (AVAILABLE(A, B, ATTR) && (EXPR)))
+
+/**
+ * Return attribute bit if attribute does not match
+ * @arg LIST		list of attributes to be compared
+ * @arg ATTR		attribute bit
+ * @arg A		an object
+ * @arg B		another object
+ * @arg EXPR		Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * In case the attributes mismatch, the attribute is returned, otherwise
+ * 0 is returned.
+ *
+ * @code
+ * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo);
+ * @endcode
+ */
+#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
+({	int diff = 0; \
+	if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \
+		diff = ATTR; \
+	diff; })
+
+/**
+ * Object Operations
+ */
+struct nl_object_ops
+{
+	/**
+	 * Unique name of object type
+	 *
+	 * Must be in the form family/name, e.g. "route/addr"
+	 */
+	char *		oo_name;
+
+	/** Size of object including its header */
+	size_t		oo_size;
+
+	/* List of attributes needed to uniquely identify the object */
+	uint32_t	oo_id_attrs;
+
+	/**
+	 * Constructor function
+	 *
+	 * Will be called when a new object of this type is allocated.
+	 * Can be used to initialize members such as lists etc.
+	 */
+	void  (*oo_constructor)(struct nl_object *);
+
+	/**
+	 * Destructor function
+	 *
+	 * Will be called when an object is freed. Must free all
+	 * resources which may have been allocated as part of this
+	 * object.
+	 */
+	void  (*oo_free_data)(struct nl_object *);
+
+	/**
+	 * Cloning function
+	 *
+	 * Will be called when an object needs to be cloned. Please
+	 * note that the generic object code will make an exact
+	 * copy of the object first, therefore you only need to take
+	 * care of members which require reference counting etc.
+	 *
+	 * May return a negative error code to abort cloning.
+	 */
+	int  (*oo_clone)(struct nl_object *, struct nl_object *);
+
+	/**
+	 * Dumping functions
+	 *
+	 * Will be called when an object is dumped. The implementations
+	 * have to use nl_dump(), nl_dump_line(), and nl_new_line() to
+	 * dump objects.
+	 *
+	 * The functions must return the number of lines printed.
+	 */
+	void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *,
+				       struct nl_dump_params *);
+
+	/**
+	 * Comparison function
+	 *
+	 * Will be called when two objects of the same type are
+	 * compared. It takes the two objects in question, an object
+	 * specific bitmask defining which attributes should be
+	 * compared and flags to control the behaviour.
+	 *
+	 * The function must return a bitmask with the relevant bit
+	 * set for each attribute that mismatches.
+	 */
+	int   (*oo_compare)(struct nl_object *, struct nl_object *,
+			    uint32_t, int);
+
+
+	char *(*oo_attrs2str)(int, char *, size_t);
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/object.h b/libnetwork/libnl3/include/netlink/object.h
new file mode 100644
index 0000000..7dc62ac
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/object.h
@@ -0,0 +1,70 @@
+/*
+ * netlink/object.c	Generic Cacheable Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_H_
+#define NETLINK_OBJECT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache;
+struct nl_object;
+struct nl_object_ops;
+
+#define OBJ_CAST(ptr)		((struct nl_object *) (ptr))
+
+/* General */
+extern struct nl_object *	nl_object_alloc(struct nl_object_ops *);
+extern int			nl_object_alloc_name(const char *,
+						     struct nl_object **);
+extern void			nl_object_free(struct nl_object *);
+extern struct nl_object *	nl_object_clone(struct nl_object *obj);
+extern void			nl_object_get(struct nl_object *);
+extern void			nl_object_put(struct nl_object *);
+extern int			nl_object_shared(struct nl_object *);
+extern void			nl_object_dump(struct nl_object *,
+					       struct nl_dump_params *);
+extern void			nl_object_dump_buf(struct nl_object *, char *, size_t);
+extern int			nl_object_identical(struct nl_object *,
+						    struct nl_object *);
+extern uint32_t			nl_object_diff(struct nl_object *,
+					       struct nl_object *);
+extern int			nl_object_match_filter(struct nl_object *,
+						       struct nl_object *);
+extern char *			nl_object_attrs2str(struct nl_object *,
+						    uint32_t attrs, char *buf,
+						    size_t);
+extern char *			nl_object_attr_list(struct nl_object *,
+						    char *, size_t);
+
+/* Marks */
+extern void			nl_object_mark(struct nl_object *);
+extern void			nl_object_unmark(struct nl_object *);
+extern int			nl_object_is_marked(struct nl_object *);
+
+/* Access Functions */
+extern int			nl_object_get_refcnt(struct nl_object *);
+extern struct nl_cache *	nl_object_get_cache(struct nl_object *);
+static inline void *		nl_object_priv(struct nl_object *obj)
+{
+	return obj;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/addr.h b/libnetwork/libnl3/include/netlink/route/addr.h
new file mode 100644
index 0000000..56c12e7
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/addr.h
@@ -0,0 +1,98 @@
+/*
+ * netlink/route/addr.c		rtnetlink addr layer
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch at ev-en.org>,
+ *                         Mediatrix Telecom, inc. <ericb at mediatrix.com>
+ */
+
+#ifndef NETADDR_ADDR_H_
+#define NETADDR_ADDR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_addr;
+
+/* General */
+extern struct rtnl_addr *rtnl_addr_alloc(void);
+extern void	rtnl_addr_put(struct rtnl_addr *);
+
+extern int	rtnl_addr_alloc_cache(struct nl_sock *, struct nl_cache **);
+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);
+
+extern char *	rtnl_addr_flags2str(int, char *, size_t);
+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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/class.h b/libnetwork/libnl3/include/netlink/route/class.h
new file mode 100644
index 0000000..e73b60a
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/class.h
@@ -0,0 +1,66 @@
+/*
+ * netlink/route/class.h       Traffic Classes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLASS_H_
+#define NETLINK_CLASS_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_class;
+
+extern struct rtnl_class *
+			rtnl_class_alloc(void);
+extern void		rtnl_class_put(struct rtnl_class *);
+
+extern int		rtnl_class_alloc_cache(struct nl_sock *, int,
+					       struct nl_cache **);
+extern struct rtnl_class *
+			rtnl_class_get(struct nl_cache *, int, uint32_t);
+
+extern struct rtnl_qdisc *
+			rtnl_class_leaf_qdisc(struct rtnl_class *,
+						      struct nl_cache *);
+
+extern int		rtnl_class_build_add_request(struct rtnl_class *, int,
+						     struct nl_msg **);
+extern int		rtnl_class_add(struct nl_sock *, struct rtnl_class *,
+				       int);
+
+extern int		rtnl_class_build_delete_request(struct rtnl_class *,
+							struct nl_msg **);
+extern int		rtnl_class_delete(struct nl_sock *,
+					  struct rtnl_class *);
+
+/* deprecated functions */
+extern void		rtnl_class_foreach_child(struct rtnl_class *,
+						 struct nl_cache *,
+						 void (*cb)(struct nl_object *,
+						 	    void *),
+						 void *)
+						 __attribute__((deprecated));
+extern void		rtnl_class_foreach_cls(struct rtnl_class *,
+					       struct nl_cache *,
+					       void (*cb)(struct nl_object *,
+							  void *),
+					       void *)
+					       __attribute__((deprecated));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/classifier.h b/libnetwork/libnl3/include/netlink/route/classifier.h
new file mode 100644
index 0000000..647bf1e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/classifier.h
@@ -0,0 +1,51 @@
+/*
+ * netlink/route/classifier.h       Classifiers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLASSIFIER_H_
+#define NETLINK_CLASSIFIER_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_cls *rtnl_cls_alloc(void);
+extern void		rtnl_cls_put(struct rtnl_cls *);
+
+extern int		rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t,
+					     struct nl_cache **);
+
+extern int		rtnl_cls_build_add_request(struct rtnl_cls *, int,
+						   struct nl_msg **);
+extern int		rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int);
+
+extern int		rtnl_cls_build_change_request(struct rtnl_cls *, int,
+						      struct nl_msg **);
+extern int		rtnl_cls_build_delete_request(struct rtnl_cls *, int,
+						      struct nl_msg **);
+extern int		rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *,
+					int);
+
+extern void		rtnl_cls_set_prio(struct rtnl_cls *, uint16_t);
+extern uint16_t		rtnl_cls_get_prio(struct rtnl_cls *);
+
+extern void		rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
+extern uint16_t		rtnl_cls_get_protocol(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/basic.h b/libnetwork/libnl3/include/netlink/route/cls/basic.h
new file mode 100644
index 0000000..8b58c1e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/basic.h
@@ -0,0 +1,31 @@
+/*
+ * netlink/route/cls/basic.h	Basic Classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_BASIC_H_
+#define NETLINK_BASIC_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void			rtnl_basic_set_target(struct rtnl_cls *, uint32_t);
+extern uint32_t			rtnl_basic_get_target(struct rtnl_cls *);
+extern void			rtnl_basic_set_ematch(struct rtnl_cls *,
+						      struct rtnl_ematch_tree *);
+extern struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/cgroup.h b/libnetwork/libnl3/include/netlink/route/cls/cgroup.h
new file mode 100644
index 0000000..20346ff
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/cgroup.h
@@ -0,0 +1,30 @@
+/*
+ * netlink/route/cls/cgroup.h	Control Groups Classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2009-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_CGROUP_H_
+#define NETLINK_CLS_CGROUP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void			rtnl_cgroup_set_ematch(struct rtnl_cls *,
+						struct rtnl_ematch_tree *);
+struct rtnl_ematch_tree *	rtnl_cgroup_get_ematch(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch.h b/libnetwork/libnl3/include/netlink/route/cls/ematch.h
new file mode 100644
index 0000000..13f9c32
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/ematch.h
@@ -0,0 +1,95 @@
+/*
+ * netlink/route/cls/ematch.h		Extended Matches
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_H_
+#define NETLINK_CLS_EMATCH_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/route/classifier.h>
+#include <linux/pkt_cls.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* FIXME: Should be moved to the kernel header at some point */
+#define RTNL_EMATCH_PROGID	2
+
+struct rtnl_ematch;
+struct rtnl_ematch_tree;
+
+/**
+ * Extended Match Operations
+ */
+struct rtnl_ematch_ops
+{
+	int			eo_kind;
+	const char *		eo_name;
+	size_t			eo_minlen;
+	size_t			eo_datalen;
+
+	int		      (*eo_parse)(struct rtnl_ematch *, void *, size_t);
+	void		      (*eo_dump)(struct rtnl_ematch *,
+					 struct nl_dump_params *);
+	int		      (*eo_fill)(struct rtnl_ematch *, struct nl_msg *);
+	void		      (*eo_free)(struct rtnl_ematch *);
+	struct nl_list_head	eo_list;
+};
+
+extern int			rtnl_ematch_register(struct rtnl_ematch_ops *);
+extern struct rtnl_ematch_ops *	rtnl_ematch_lookup_ops(int);
+extern struct rtnl_ematch_ops *	rtnl_ematch_lookup_ops_by_name(const char *);
+
+extern struct rtnl_ematch *	rtnl_ematch_alloc(void);
+extern int			rtnl_ematch_add_child(struct rtnl_ematch *,
+						      struct rtnl_ematch *);
+extern void			rtnl_ematch_unlink(struct rtnl_ematch *);
+extern void			rtnl_ematch_free(struct rtnl_ematch *);
+
+extern void *			rtnl_ematch_data(struct rtnl_ematch *);
+extern void			rtnl_ematch_set_flags(struct rtnl_ematch *,
+						      uint16_t);
+extern void			rtnl_ematch_unset_flags(struct rtnl_ematch *,
+							uint16_t);
+extern uint16_t			rtnl_ematch_get_flags(struct rtnl_ematch *);
+extern int			rtnl_ematch_set_ops(struct rtnl_ematch *,
+						    struct rtnl_ematch_ops *);
+extern int			rtnl_ematch_set_kind(struct rtnl_ematch *,
+						     uint16_t);
+extern int			rtnl_ematch_set_name(struct rtnl_ematch *,
+						     const char *);
+
+extern struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t);
+extern void			rtnl_ematch_tree_free(struct rtnl_ematch_tree *);
+extern void			rtnl_ematch_tree_add(struct rtnl_ematch_tree *,
+						     struct rtnl_ematch *);
+
+extern int			rtnl_ematch_parse_attr(struct nlattr *,
+						       struct rtnl_ematch_tree **);
+extern int			rtnl_ematch_fill_attr(struct nl_msg *, int,
+						      struct rtnl_ematch_tree *);
+extern void			rtnl_ematch_tree_dump(struct rtnl_ematch_tree *,
+						      struct nl_dump_params *);
+
+
+extern int			rtnl_ematch_parse_expr(const char *, char **,
+						       struct rtnl_ematch_tree **);
+
+extern char *			rtnl_ematch_offset2txt(uint8_t, uint16_t,
+						       char *, size_t);
+extern char *			rtnl_ematch_opnd2txt(uint8_t, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h
new file mode 100644
index 0000000..308113e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h
@@ -0,0 +1,32 @@
+/*
+ * netlink/route/cls/ematch/cmp.h	Simple Comparison
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_CMP_H_
+#define NETLINK_CLS_EMATCH_CMP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void	rtnl_ematch_cmp_set(struct rtnl_ematch *,
+				    struct tcf_em_cmp *);
+extern struct tcf_em_cmp *
+		rtnl_ematch_cmp_get(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h
new file mode 100644
index 0000000..2fe5899
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h
@@ -0,0 +1,41 @@
+/*
+ * netlink/route/cls/ematch/meta.h	Metadata Match
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_META_H_
+#define NETLINK_CLS_EMATCH_META_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_meta.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_meta_value;
+
+extern struct rtnl_meta_value *	rtnl_meta_value_alloc_int(uint64_t);
+extern struct rtnl_meta_value *	rtnl_meta_value_alloc_var(void *, size_t);
+extern struct rtnl_meta_value *	rtnl_meta_value_alloc_id(uint8_t, uint16_t,
+							  uint8_t, uint64_t);
+extern void	rtnl_meta_value_put(struct rtnl_meta_value *);
+
+extern void	rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *,
+					    struct rtnl_meta_value *);
+void		rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *,
+					    struct rtnl_meta_value *);
+extern void	rtnl_ematch_meta_set_operand(struct rtnl_ematch *, uint8_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h
new file mode 100644
index 0000000..014c719
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h
@@ -0,0 +1,36 @@
+/*
+ * netlink/route/cls/ematch/nbyte.h	N-Byte Comparison
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_NBYTE_H_
+#define NETLINK_CLS_EMATCH_NBYTE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_nbyte.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void		rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *,
+						     uint8_t, uint16_t);
+extern uint16_t		rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *);
+extern uint8_t		rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *);
+extern void		rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *,
+						      uint8_t *, size_t);
+extern uint8_t *	rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *);
+extern size_t		rtnl_ematch_nbyte_get_len(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h
new file mode 100644
index 0000000..e599abf
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h
@@ -0,0 +1,42 @@
+/*
+ * netlink/route/cls/ematch/text.h	Text Search
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_TEXT_H_
+#define NETLINK_CLS_EMATCH_TEXT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_text.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void	rtnl_ematch_text_set_from(struct rtnl_ematch *,
+					  uint8_t, uint16_t);
+extern uint16_t	rtnl_ematch_text_get_from_offset(struct rtnl_ematch *);
+extern uint8_t	rtnl_ematch_text_get_from_layer(struct rtnl_ematch *);
+extern void	rtnl_ematch_text_set_to(struct rtnl_ematch *,
+					uint8_t, uint16_t);
+extern uint16_t	rtnl_ematch_text_get_to_offset(struct rtnl_ematch *);
+extern uint8_t	rtnl_ematch_text_get_to_layer(struct rtnl_ematch *);
+extern void	rtnl_ematch_text_set_pattern(struct rtnl_ematch *,
+					     char *, size_t);
+extern char *	rtnl_ematch_text_get_pattern(struct rtnl_ematch *);
+extern size_t	rtnl_ematch_text_get_len(struct rtnl_ematch *);
+extern void	rtnl_ematch_text_set_algo(struct rtnl_ematch *, const char *);
+extern char *	rtnl_ematch_text_get_algo(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/fw.h b/libnetwork/libnl3/include/netlink/route/cls/fw.h
new file mode 100644
index 0000000..39878de
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/fw.h
@@ -0,0 +1,29 @@
+/*
+ * netlink/route/cls/fw.h	fw classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2006 Petr Gotthard <petr.gotthard at siemens.com>
+ * Copyright (c) 2006 Siemens AG Oesterreich
+ */
+
+#ifndef NETLINK_FW_H_
+#define NETLINK_FW_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	rtnl_fw_set_classid(struct rtnl_cls *, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/police.h b/libnetwork/libnl3/include/netlink/route/cls/police.h
new file mode 100644
index 0000000..cd1efb0
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/police.h
@@ -0,0 +1,29 @@
+/*
+ * netlink/route/cls/police.h	Policer
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CLS_POLICE_H_
+#define NETLINK_CLS_POLICE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *	nl_police2str(int, char *, size_t);
+extern int	nl_str2police(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/cls/u32.h b/libnetwork/libnl3/include/netlink/route/cls/u32.h
new file mode 100644
index 0000000..cf35e26
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/cls/u32.h
@@ -0,0 +1,43 @@
+/*
+ * netlink/route/cls/u32.h	u32 classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_U32_H_
+#define NETLINK_U32_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void	rtnl_u32_set_handle(struct rtnl_cls *, int, int, int);
+extern int	rtnl_u32_set_classid(struct rtnl_cls *, uint32_t);
+
+extern int	rtnl_u32_set_flags(struct rtnl_cls *, int);
+extern int	rtnl_u32_add_key(struct rtnl_cls *, uint32_t, uint32_t,
+				 int, int);
+extern int	rtnl_u32_add_key_uint8(struct rtnl_cls *, uint8_t, uint8_t,
+				       int, int);
+extern int	rtnl_u32_add_key_uint16(struct rtnl_cls *, uint16_t, uint16_t,
+					int, int);
+extern int	rtnl_u32_add_key_uint32(struct rtnl_cls *, uint32_t, uint32_t,
+					int, int);
+extern int	rtnl_u32_add_key_in_addr(struct rtnl_cls *, struct in_addr *,
+					 uint8_t, int, int);
+extern int	rtnl_u32_add_key_in6_addr(struct rtnl_cls *, struct in6_addr *,
+					  uint8_t, int, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/link.h b/libnetwork/libnl3/include/netlink/route/link.h
new file mode 100644
index 0000000..42ef7c8
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link.h
@@ -0,0 +1,217 @@
+/*
+ * netlink/route/link.h		Links (Interfaces)
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_H_
+#define NETLINK_LINK_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/if.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @struct rtnl_link link.h "netlink/route/link.h"
+ * @brief Link object
+ * @implements nl_object
+ * @ingroup link
+ *
+ * @copydoc private_struct
+ */
+struct rtnl_link;
+
+/**
+ * @ingroup link
+ */
+typedef enum {
+	RTNL_LINK_RX_PACKETS,		/*!< Packets received */
+	RTNL_LINK_TX_PACKETS,		/*!< Packets sent */
+	RTNL_LINK_RX_BYTES,		/*!< Bytes received */
+	RTNL_LINK_TX_BYTES,		/*!< Bytes sent */
+	RTNL_LINK_RX_ERRORS,		/*!< Receive errors */
+	RTNL_LINK_TX_ERRORS,		/*!< Send errors */
+	RTNL_LINK_RX_DROPPED,		/*!< Received packets dropped */
+	RTNL_LINK_TX_DROPPED,		/*!< Packets dropped during transmit */
+	RTNL_LINK_RX_COMPRESSED,	/*!< Compressed packets received */
+	RTNL_LINK_TX_COMPRESSED,	/*!< Compressed packets sent */
+	RTNL_LINK_RX_FIFO_ERR,		/*!< Receive FIFO errors */
+	RTNL_LINK_TX_FIFO_ERR,		/*!< Send FIFO errors */
+	RTNL_LINK_RX_LEN_ERR,		/*!< Length errors */
+	RTNL_LINK_RX_OVER_ERR,		/*!< Over errors */
+	RTNL_LINK_RX_CRC_ERR,		/*!< CRC errors */
+	RTNL_LINK_RX_FRAME_ERR,		/*!< Frame errors */
+	RTNL_LINK_RX_MISSED_ERR,	/*!< Missed errors */
+	RTNL_LINK_TX_ABORT_ERR,		/*!< Aborted errors */
+	RTNL_LINK_TX_CARRIER_ERR,	/*!< Carrier errors */
+	RTNL_LINK_TX_HBEAT_ERR,		/*!< Heartbeat errors */
+	RTNL_LINK_TX_WIN_ERR,		/*!< Window errors */
+	RTNL_LINK_COLLISIONS,		/*!< Send collisions */
+	RTNL_LINK_MULTICAST,		/*!< Multicast */
+	RTNL_LINK_IP6_INPKTS,		/*!< IPv6 SNMP InReceives */
+	RTNL_LINK_IP6_INHDRERRORS,	/*!< IPv6 SNMP InHdrErrors */
+	RTNL_LINK_IP6_INTOOBIGERRORS,	/*!< IPv6 SNMP InTooBigErrors */
+	RTNL_LINK_IP6_INNOROUTES,	/*!< IPv6 SNMP InNoRoutes */
+	RTNL_LINK_IP6_INADDRERRORS,	/*!< IPv6 SNMP InAddrErrors */
+	RTNL_LINK_IP6_INUNKNOWNPROTOS,	/*!< IPv6 SNMP InUnknownProtos */
+	RTNL_LINK_IP6_INTRUNCATEDPKTS,	/*!< IPv6 SNMP InTruncatedPkts */
+	RTNL_LINK_IP6_INDISCARDS,	/*!< IPv6 SNMP InDiscards */
+	RTNL_LINK_IP6_INDELIVERS,	/*!< IPv6 SNMP InDelivers */
+	RTNL_LINK_IP6_OUTFORWDATAGRAMS,	/*!< IPv6 SNMP OutForwDatagrams */
+	RTNL_LINK_IP6_OUTPKTS,		/*!< IPv6 SNMP OutRequests */
+	RTNL_LINK_IP6_OUTDISCARDS,	/*!< IPv6 SNMP OutDiscards */
+	RTNL_LINK_IP6_OUTNOROUTES,	/*!< IPv6 SNMP OutNoRoutes */
+	RTNL_LINK_IP6_REASMTIMEOUT,	/*!< IPv6 SNMP ReasmTimeout */
+	RTNL_LINK_IP6_REASMREQDS,	/*!< IPv6 SNMP ReasmReqds */
+	RTNL_LINK_IP6_REASMOKS,		/*!< IPv6 SNMP ReasmOKs */
+	RTNL_LINK_IP6_REASMFAILS,	/*!< IPv6 SNMP ReasmFails */
+	RTNL_LINK_IP6_FRAGOKS,		/*!< IPv6 SNMP FragOKs */
+	RTNL_LINK_IP6_FRAGFAILS,	/*!< IPv6 SNMP FragFails */
+	RTNL_LINK_IP6_FRAGCREATES,	/*!< IPv6 SNMP FragCreates */
+	RTNL_LINK_IP6_INMCASTPKTS,	/*!< IPv6 SNMP InMcastPkts */
+	RTNL_LINK_IP6_OUTMCASTPKTS,	/*!< IPv6 SNMP OutMcastPkts */
+	RTNL_LINK_IP6_INBCASTPKTS,	/*!< IPv6 SNMP InBcastPkts */
+	RTNL_LINK_IP6_OUTBCASTPKTS,	/*!< IPv6 SNMP OutBcastPkts */
+	RTNL_LINK_IP6_INOCTETS,		/*!< IPv6 SNMP InOctets */
+	RTNL_LINK_IP6_OUTOCTETS,	/*!< IPv6 SNMP OutOctets */
+	RTNL_LINK_IP6_INMCASTOCTETS,	/*!< IPv6 SNMP InMcastOctets */
+	RTNL_LINK_IP6_OUTMCASTOCTETS,	/*!< IPv6 SNMP OutMcastOctets */
+	RTNL_LINK_IP6_INBCASTOCTETS,	/*!< IPv6 SNMP InBcastOctets */
+	RTNL_LINK_IP6_OUTBCASTOCTETS,	/*!< IPv6 SNMP OutBcastOctets */
+	RTNL_LINK_ICMP6_INMSGS,		/*!< ICMPv6 SNMP InMsgs */
+	RTNL_LINK_ICMP6_INERRORS,	/*!< ICMPv6 SNMP InErrors */
+	RTNL_LINK_ICMP6_OUTMSGS,	/*!< ICMPv6 SNMP OutMsgs */
+	RTNL_LINK_ICMP6_OUTERRORS,	/*!< ICMPv6 SNMP OutErrors */
+	__RTNL_LINK_STATS_MAX,
+} rtnl_link_stat_id_t;
+
+#define RTNL_LINK_STATS_MAX (__RTNL_LINK_STATS_MAX - 1)
+
+extern struct rtnl_link *rtnl_link_alloc(void);
+extern void	rtnl_link_put(struct rtnl_link *);
+extern void	rtnl_link_free(struct rtnl_link *);
+
+extern int	rtnl_link_alloc_cache(struct nl_sock *, int, struct nl_cache **);
+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 int	rtnl_link_get_kernel(struct nl_sock *, int, const char *,
+				     struct rtnl_link **);
+
+/* Name <-> Index Translations */
+extern char * 	rtnl_link_i2name(struct nl_cache *, int, char *, size_t);
+extern int	rtnl_link_name2i(struct nl_cache *, const char *);
+
+/* Name <-> Statistic Translations */
+extern char *	rtnl_link_stat2str(int, char *, size_t);
+extern int	rtnl_link_str2stat(const char *);
+
+/* Link Flags Translations */
+extern char *	rtnl_link_flags2str(int, char *, size_t);
+extern int	rtnl_link_str2flags(const char *);
+
+extern char *	rtnl_link_operstate2str(uint8_t, char *, size_t);
+extern int	rtnl_link_str2operstate(const char *);
+
+extern char *	rtnl_link_mode2str(uint8_t, char *, size_t);
+extern int	rtnl_link_str2mode(const char *);
+
+/* Access Functions */
+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_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 *, rtnl_link_stat_id_t);
+extern int	rtnl_link_set_stat(struct rtnl_link *, rtnl_link_stat_id_t,
+				   const uint64_t);
+
+extern int	rtnl_link_set_type(struct rtnl_link *, const char *);
+extern char *	rtnl_link_get_type(struct rtnl_link *);
+
+extern int	rtnl_link_enslave_ifindex(struct nl_sock *, int, int);
+extern int	rtnl_link_enslave(struct nl_sock *, struct rtnl_link *,
+				  struct rtnl_link *);
+extern int	rtnl_link_release_ifindex(struct nl_sock *, int);
+extern int	rtnl_link_release(struct nl_sock *, struct rtnl_link *);
+
+/* deprecated */
+extern int	rtnl_link_set_info_type(struct rtnl_link *, const char *) __attribute__((deprecated));
+extern char *	rtnl_link_get_info_type(struct rtnl_link *) __attribute__((deprecated));
+extern void	rtnl_link_set_weight(struct rtnl_link *, unsigned int) __attribute__((deprecated));
+extern unsigned int rtnl_link_get_weight(struct rtnl_link *) __attribute__((deprecated));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/link/api.h b/libnetwork/libnl3/include/netlink/route/link/api.h
new file mode 100644
index 0000000..960d3f1
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link/api.h
@@ -0,0 +1,134 @@
+/*
+ * netlink/route/link/api.h	Link Modules API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_API_H_
+#define NETLINK_LINK_API_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup link_api
+ *
+ * Available operations to modules implementing a link info type.
+ */
+struct rtnl_link_info_ops
+{
+	/** Name of link info type, must match name on kernel side */
+	char *		io_name;
+
+	/** Reference count, DO NOT MODIFY */
+	int		io_refcnt;
+
+	/** Called to assign an info type to a link.
+	 * Has to allocate enough resources to hold attributes. Can
+	 * use link->l_info to store a pointer. */
+	int	      (*io_alloc)(struct rtnl_link *);
+
+	/** Called to parse the link info attribute.
+	 * Must parse the attribute and assign all values to the link.
+	 */
+	int	      (*io_parse)(struct rtnl_link *,
+				  struct nlattr *,
+				  struct nlattr *);
+
+	/** Called when the link object is dumped.
+	 * Must dump the info type specific attributes. */
+	void	      (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+						struct nl_dump_params *);
+
+	/** Called when a link object is cloned.
+	 * Must clone all info type specific attributes. */
+	int	      (*io_clone)(struct rtnl_link *, struct rtnl_link *);
+
+	/** Called when construction a link netlink message.
+	 * Must append all info type specific attributes to the message. */
+	int	      (*io_put_attrs)(struct nl_msg *, struct rtnl_link *);
+
+	/** Called to release all resources previously allocated
+	 * in either io_alloc() or io_parse(). */
+	void	      (*io_free)(struct rtnl_link *);
+
+	struct nl_list_head		io_list;
+};
+
+extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *);
+extern void			rtnl_link_info_ops_put(struct rtnl_link_info_ops *);
+extern int			rtnl_link_register_info(struct rtnl_link_info_ops *);
+extern int			rtnl_link_unregister_info(struct rtnl_link_info_ops *);
+
+
+/**
+ * @ingroup link_api
+ *
+ * Available operations to modules implementing a link address family.
+ */
+struct rtnl_link_af_ops
+{
+	/** The address family this operations set implements */
+	const unsigned int	ao_family;
+
+	/** Number of users of this operations, DO NOT MODIFY. */
+	int			ao_refcnt;
+
+	/** Validation policy for IFLA_PROTINFO attribute. This pointer
+	 * can be set to a nla_policy structure describing the minimal
+	 * requirements the attribute must meet. Failure of meeting these
+	 * requirements will result in a parsing error. */
+	const struct nla_policy *ao_protinfo_policy;
+
+	/** Called after address family has been assigned to link. Must
+	 * allocate data buffer to hold address family specific data and
+	 * store it in link->l_af_data. */
+	void *		      (*ao_alloc)(struct rtnl_link *);
+
+	/** Called when the link is cloned, must allocate a clone of the
+	 * address family specific buffer and return it. */
+	void *		      (*ao_clone)(struct rtnl_link *, void *);
+
+	/** Called when the link gets freed. Must free all allocated data */
+	void		      (*ao_free)(struct rtnl_link *, void *);
+
+	/** Called if a IFLA_PROTINFO attribute needs to be parsed. Typically
+	 * stores the parsed data in the address family specific buffer. */
+	int		      (*ao_parse_protinfo)(struct rtnl_link *,
+						   struct nlattr *, void *);
+
+	/** Called if a IFLA_AF_SPEC attribute needs to be parsed. Typically
+	 * stores the parsed data in the address family specific buffer. */
+	int		      (*ao_parse_af)(struct rtnl_link *,
+					     struct nlattr *, void *);
+
+	/** Called if a link message is sent to the kernel. Must append the
+	 * link address family specific attributes to the message. */
+	int		      (*ao_fill_af)(struct rtnl_link *,
+					    struct nl_msg *msg, void *);
+
+	/** Dump address family specific link attributes */
+	void		      (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+							struct nl_dump_params *,
+							void *);
+};
+
+extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int);
+extern void			rtnl_link_af_ops_put(struct rtnl_link_af_ops *);
+extern void *			rtnl_link_af_alloc(struct rtnl_link *,
+						const struct rtnl_link_af_ops *);
+extern void *			rtnl_link_af_data(const struct rtnl_link *,
+						const struct rtnl_link_af_ops *);
+extern int			rtnl_link_af_register(struct rtnl_link_af_ops *);
+extern int			rtnl_link_af_unregister(struct rtnl_link_af_ops *);
+
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/link/bonding.h b/libnetwork/libnl3/include/netlink/route/link/bonding.h
new file mode 100644
index 0000000..78ee6bd
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link/bonding.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/bonding.h		Bonding Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_BONDING_H_
+#define NETLINK_LINK_BONDING_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	rtnl_link_bond_add(struct nl_sock *, const char *,
+				   struct rtnl_link *);
+
+extern int	rtnl_link_bond_enslave_ifindex(struct nl_sock *, int, int);
+extern int	rtnl_link_bond_enslave(struct nl_sock *, struct rtnl_link *,
+				       struct rtnl_link *);
+
+extern int	rtnl_link_bond_release_ifindex(struct nl_sock *, int);
+extern int	rtnl_link_bond_release(struct nl_sock *, struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnetwork/libnl3/include/netlink/route/link/inet.h b/libnetwork/libnl3/include/netlink/route/link/inet.h
new file mode 100644
index 0000000..66419e3
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link/inet.h
@@ -0,0 +1,29 @@
+/*
+ * netlink/route/link/inet.h	INET Link Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_INET_H_
+#define NETLINK_LINK_INET_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *	rtnl_link_inet_devconf2str(int, char *, size_t);
+extern int		rtnl_link_inet_str2devconf(const char *);
+
+extern int		rtnl_link_inet_get_conf(struct rtnl_link *,
+						const unsigned int, uint32_t *);
+extern int		rtnl_link_inet_set_conf(struct rtnl_link *,
+						const unsigned int, uint32_t);
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/link/info-api.h b/libnetwork/libnl3/include/netlink/route/link/info-api.h
new file mode 100644
index 0000000..4750e18
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link/info-api.h
@@ -0,0 +1,20 @@
+/*
+ * netlink/route/link/info-api.h	Link Info API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_INFO_API_H_
+#define NETLINK_LINK_INFO_API_H_
+
+#warning "<netlink/route/link/info-api.h> is obsolete and may be removed in the future."
+#warning "include <netlink/route/link/api.h> instead.
+
+#include <netlink/route/link/api.h>
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/link/vlan.h b/libnetwork/libnl3/include/netlink/route/link/vlan.h
new file mode 100644
index 0000000..42768b6
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/link/vlan.h
@@ -0,0 +1,57 @@
+/*
+ * netlink/route/link/vlan.h		VLAN interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_LINK_VLAN_H_
+#define NETLINK_LINK_VLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct vlan_map
+{
+	uint32_t		vm_from;
+	uint32_t		vm_to;
+};
+
+#define VLAN_PRIO_MAX 7
+
+extern int		rtnl_link_is_vlan(struct rtnl_link *);
+
+extern char *		rtnl_link_vlan_flags2str(int, char *, size_t);
+extern int		rtnl_link_vlan_str2flags(const char *);
+
+extern int		rtnl_link_vlan_set_id(struct rtnl_link *, uint16_t);
+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 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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/neighbour.h b/libnetwork/libnl3/include/netlink/route/neighbour.h
new file mode 100644
index 0000000..698539a
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/neighbour.h
@@ -0,0 +1,79 @@
+/*
+ * netlink/route/neighbour.h	Neighbours
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_NEIGHBOUR_H_
+#define NETLINK_NEIGHBOUR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_neigh;
+
+extern struct rtnl_neigh *rtnl_neigh_alloc(void);
+extern void	rtnl_neigh_put(struct rtnl_neigh *);
+
+extern int	rtnl_neigh_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int,
+					       struct nl_addr *);
+
+extern char *	rtnl_neigh_state2str(int, char *, size_t);
+extern int	rtnl_neigh_str2state(const char *);
+
+extern char *	rtnl_neigh_flags2str(int, char *, size_t);
+extern int	rtnl_neigh_str2flag(const char *);
+
+extern int	rtnl_neigh_add(struct nl_sock *, struct rtnl_neigh *, int);
+extern int	rtnl_neigh_build_add_request(struct rtnl_neigh *, int,
+					     struct nl_msg **);
+
+extern int	rtnl_neigh_delete(struct nl_sock *, struct rtnl_neigh *, int);
+extern int	rtnl_neigh_build_delete_request(struct rtnl_neigh *, int,
+						struct nl_msg **);
+
+extern void			rtnl_neigh_set_state(struct rtnl_neigh *, int);
+extern int			rtnl_neigh_get_state(struct rtnl_neigh *);
+extern void			rtnl_neigh_unset_state(struct rtnl_neigh *,
+						       int);
+
+extern void			rtnl_neigh_set_flags(struct rtnl_neigh *,
+						     unsigned int);
+extern void			rtnl_neigh_unset_flags(struct rtnl_neigh *,
+						       unsigned int);
+extern unsigned int		rtnl_neigh_get_flags(struct rtnl_neigh *);
+
+extern void			rtnl_neigh_set_ifindex(struct rtnl_neigh *,
+						       int);
+extern int			rtnl_neigh_get_ifindex(struct rtnl_neigh *);
+
+extern void			rtnl_neigh_set_lladdr(struct rtnl_neigh *,
+						      struct nl_addr *);
+extern struct nl_addr *		rtnl_neigh_get_lladdr(struct rtnl_neigh *);
+
+extern int			rtnl_neigh_set_dst(struct rtnl_neigh *,
+						   struct nl_addr *);
+extern struct nl_addr *		rtnl_neigh_get_dst(struct rtnl_neigh *);
+
+extern void			rtnl_neigh_set_type(struct rtnl_neigh *, int);
+extern int			rtnl_neigh_get_type(struct rtnl_neigh *);
+
+extern void			rtnl_neigh_set_family(struct rtnl_neigh *, int);
+extern int			rtnl_neigh_get_family(struct rtnl_neigh *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/neightbl.h b/libnetwork/libnl3/include/netlink/route/neightbl.h
new file mode 100644
index 0000000..412c3e9
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/neightbl.h
@@ -0,0 +1,65 @@
+/*
+ * netlink/route/neightbl.h	Neighbour Tables
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_NEIGHTBL_H_
+#define NETLINK_NEIGHTBL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_neightbl;
+
+extern struct rtnl_neightbl *rtnl_neightbl_alloc(void);
+extern void rtnl_neightbl_put(struct rtnl_neightbl *);
+extern void rtnl_neightbl_free(struct rtnl_neightbl *);
+extern int rtnl_neightbl_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *,
+					       const char *, int);
+extern void rtnl_neightbl_dump(struct rtnl_neightbl *, FILE *,
+			       struct nl_dump_params *);
+
+extern int rtnl_neightbl_build_change_request(struct rtnl_neightbl *,
+					      struct rtnl_neightbl *,
+					      struct nl_msg **);
+extern int rtnl_neightbl_change(struct nl_sock *, struct rtnl_neightbl *,
+				struct rtnl_neightbl *);
+
+extern void rtnl_neightbl_set_family(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_name(struct rtnl_neightbl *, const char *);
+extern void rtnl_neightbl_set_dev(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *,
+						  uint64_t);
+extern void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *,
+					       uint64_t);
+extern void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_locktime(struct rtnl_neightbl *, uint64_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/nexthop.h b/libnetwork/libnl3/include/netlink/route/nexthop.h
new file mode 100644
index 0000000..2aa44dc
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/nexthop.h
@@ -0,0 +1,65 @@
+/*
+ * netlink/route/nexthop.h	Routing Nexthop
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_ROUTE_NEXTHOP_H_
+#define NETLINK_ROUTE_NEXTHOP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_nexthop;
+
+enum {
+	NH_DUMP_FROM_ONELINE = -2,
+	NH_DUMP_FROM_DETAILS = -1,
+	NH_DUMP_FROM_ENV = 0,
+	/* > 0 reserved for nexthop index */
+};
+
+extern struct rtnl_nexthop * rtnl_route_nh_alloc(void);
+extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *);
+extern void		rtnl_route_nh_free(struct rtnl_nexthop *);
+
+extern int		rtnl_route_nh_compare(struct rtnl_nexthop *,
+					      struct rtnl_nexthop *,
+					      uint32_t, int);
+
+extern void		rtnl_route_nh_dump(struct rtnl_nexthop *,
+					   struct nl_dump_params *);
+
+extern void		rtnl_route_nh_set_weight(struct rtnl_nexthop *, uint8_t);
+extern uint8_t		rtnl_route_nh_get_weight(struct rtnl_nexthop *);
+extern void		rtnl_route_nh_set_ifindex(struct rtnl_nexthop *, int);
+extern int		rtnl_route_nh_get_ifindex(struct rtnl_nexthop *);
+extern void		rtnl_route_nh_set_gateway(struct rtnl_nexthop *,
+						  struct nl_addr *);
+extern struct nl_addr *	rtnl_route_nh_get_gateway(struct rtnl_nexthop *);
+extern void		rtnl_route_nh_set_flags(struct rtnl_nexthop *,
+						unsigned int);
+extern void		rtnl_route_nh_unset_flags(struct rtnl_nexthop *,
+						  unsigned int);
+extern unsigned int	rtnl_route_nh_get_flags(struct rtnl_nexthop *);
+extern void		rtnl_route_nh_set_realms(struct rtnl_nexthop *,
+						 uint32_t);
+extern uint32_t		rtnl_route_nh_get_realms(struct rtnl_nexthop *);
+
+extern char *		rtnl_route_nh_flags2str(int, char *, size_t);
+extern int		rtnl_route_nh_str2flags(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/pktloc.h b/libnetwork/libnl3/include/netlink/route/pktloc.h
new file mode 100644
index 0000000..c3768ce
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/pktloc.h
@@ -0,0 +1,49 @@
+/*
+ * netlink/route/pktloc.h         Packet Location Aliasing
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_PKTLOC_H_
+#define NETLINK_PKTLOC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_pktloc
+{
+	char *			name;
+	uint8_t			layer;
+	uint8_t			shift;
+	uint16_t		offset;
+	uint16_t		align;
+	uint32_t		mask;
+	uint32_t		refcnt;
+
+	struct nl_list_head	list;
+};
+
+extern int	rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **);
+extern struct rtnl_pktloc *rtnl_pktloc_alloc(void);
+extern void	rtnl_pktloc_put(struct rtnl_pktloc *);
+extern int	rtnl_pktloc_add(struct rtnl_pktloc *);
+extern void	rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *),
+				    void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc.h b/libnetwork/libnl3/include/netlink/route/qdisc.h
new file mode 100644
index 0000000..10b85c5
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc.h
@@ -0,0 +1,73 @@
+/*
+ * netlink/route/qdisc.h         Queueing Disciplines
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_QDISC_H_
+#define NETLINK_QDISC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_qdisc;
+
+extern struct rtnl_qdisc *
+		rtnl_qdisc_alloc(void);
+extern void	rtnl_qdisc_put(struct rtnl_qdisc *);
+
+extern int	rtnl_qdisc_alloc_cache(struct nl_sock *, struct nl_cache **);
+
+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 *);
+
+/* Deprecated functions */
+extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *,
+				     void (*cb)(struct nl_object *, void *),
+				     void *) __attribute__ ((deprecated));
+
+extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *,
+				   void (*cb)(struct nl_object *, void *),
+				   void *) __attribute__ ((deprecated));
+
+extern int rtnl_qdisc_build_change_request(struct rtnl_qdisc *,
+					   struct rtnl_qdisc *,
+					   struct nl_msg **)
+					   __attribute__ ((deprecated));
+
+extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *,
+			     struct rtnl_qdisc *) __attribute__ ((deprecated));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h b/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h
new file mode 100644
index 0000000..3dbdd2d
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h
@@ -0,0 +1,30 @@
+/*
+ * netlink/route/sch/cbq.h	Class Based Queueing
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_CBQ_H_
+#define NETLINK_CBQ_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char * nl_ovl_strategy2str(int, char *, size_t);
+extern int    nl_str2ovl_strategy(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h b/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h
new file mode 100644
index 0000000..de65496
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h
@@ -0,0 +1,41 @@
+/*
+ * netlink/route/sch/dsmark.h	DSMARK
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_DSMARK_H_
+#define NETLINK_DSMARK_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	rtnl_class_dsmark_set_bmask(struct rtnl_class *, uint8_t);
+extern int	rtnl_class_dsmark_get_bmask(struct rtnl_class *);
+
+extern int	rtnl_class_dsmark_set_value(struct rtnl_class *, uint8_t);
+extern int	rtnl_class_dsmark_get_value(struct rtnl_class *);
+
+extern int	rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *, uint16_t);
+extern int	rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *);
+
+extern int	rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *,
+						    uint16_t);
+extern int	rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *);
+
+extern int	rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *, int);
+extern int	rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h b/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h
new file mode 100644
index 0000000..c18dd79
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h
@@ -0,0 +1,28 @@
+/*
+ * netlink/route/sch/fifo.c	FIFO Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_FIFO_H_
+#define NETLINK_FIFO_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *, int);
+extern int	rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/htb.h b/libnetwork/libnl3/include/netlink/route/qdisc/htb.h
new file mode 100644
index 0000000..af0287d
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/htb.h
@@ -0,0 +1,47 @@
+/*
+ * netlink/route/sch/htb.h	HTB Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2005 Petr Gotthard <petr.gotthard at siemens.com>
+ * Copyright (c) 2005 Siemens AG Oesterreich
+ */
+
+#ifndef NETLINK_HTB_H_
+#define NETLINK_HTB_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint32_t	rtnl_htb_get_rate2quantum(struct rtnl_qdisc *);
+extern int	rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t);
+extern uint32_t	rtnl_htb_get_defcls(struct rtnl_qdisc *);
+extern int	rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t);
+
+extern uint32_t	rtnl_htb_get_prio(struct rtnl_class *);
+extern int	rtnl_htb_set_prio(struct rtnl_class *, uint32_t);
+extern uint32_t	rtnl_htb_get_rate(struct rtnl_class *);
+extern int	rtnl_htb_set_rate(struct rtnl_class *, uint32_t);
+extern uint32_t	rtnl_htb_get_ceil(struct rtnl_class *);
+extern int	rtnl_htb_set_ceil(struct rtnl_class *, uint32_t);
+extern uint32_t	rtnl_htb_get_rbuffer(struct rtnl_class *);
+extern int	rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t	rtnl_htb_get_cbuffer(struct rtnl_class *);
+extern int	rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t	rtnl_htb_get_quantum(struct rtnl_class *);
+extern int	rtnl_htb_set_quantum(struct rtnl_class *, uint32_t);
+extern int	rtnl_htb_get_level(struct rtnl_class *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/netem.h b/libnetwork/libnl3/include/netlink/route/qdisc/netem.h
new file mode 100644
index 0000000..ce56ee7
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/netem.h
@@ -0,0 +1,75 @@
+/*
+ * netlink/route/sch/netem.h		Network Emulator Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_NETEM_H_
+#define NETLINK_NETEM_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_limit(struct rtnl_qdisc *);
+
+/* Packet Re-ordering */
+extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_gap(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *);
+
+/* Corruption */
+extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *);
+
+/* Packet Loss */
+extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_loss(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *);
+
+/* Packet Duplication */
+extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *);
+
+/* Packet Delay */
+extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_delay(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_jitter(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *);
+
+/* Delay Distribution */
+#define MAXDIST 65536
+extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *);
+extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *);
+extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/prio.h b/libnetwork/libnl3/include/netlink/route/qdisc/prio.h
new file mode 100644
index 0000000..f6fdc86
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/prio.h
@@ -0,0 +1,53 @@
+/*
+ * netlink/route/sch/prio.c	PRIO Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_PRIO_H_
+#define NETLINK_PRIO_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Default Values
+ * @{
+ */
+
+/**
+ * Default number of bands.
+ * @ingroup prio
+ */
+#define QDISC_PRIO_DEFAULT_BANDS 3
+
+/**
+ * Default priority mapping.
+ * @ingroup prio
+ */
+#define QDISC_PRIO_DEFAULT_PRIOMAP \
+		{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }
+
+/** @} */
+
+extern void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *, int);
+extern int  rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *);
+extern int  rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *, uint8_t[], int);
+extern uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *);
+
+extern char *	rtnl_prio2str(int, char *, size_t);
+extern int	rtnl_str2prio(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/red.h b/libnetwork/libnl3/include/netlink/route/qdisc/red.h
new file mode 100644
index 0000000..a4e8642
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/red.h
@@ -0,0 +1,17 @@
+/*
+ * netlink/route/sch/red.h	RED Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_RED_H_
+#define NETLINK_RED_H_
+
+#include <netlink/netlink.h>
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h b/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h
new file mode 100644
index 0000000..7cc0b3e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h
@@ -0,0 +1,36 @@
+/*
+ * netlink/route/sch/sfq.c	SFQ Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_SFQ_H_
+#define NETLINK_SFQ_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void	rtnl_sfq_set_quantum(struct rtnl_qdisc *, int);
+extern int	rtnl_sfq_get_quantum(struct rtnl_qdisc *);
+
+extern void	rtnl_sfq_set_limit(struct rtnl_qdisc *, int);
+extern int	rtnl_sfq_get_limit(struct rtnl_qdisc *);
+
+extern void	rtnl_sfq_set_perturb(struct rtnl_qdisc *, int);
+extern int	rtnl_sfq_get_perturb(struct rtnl_qdisc *);
+
+extern int	rtnl_sfq_get_divisor(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h b/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h
new file mode 100644
index 0000000..8a2144a
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h
@@ -0,0 +1,40 @@
+/*
+ * netlink/route/sch/tbf.h	TBF Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_TBF_H_
+#define NETLINK_TBF_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *, int);
+extern int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *, int);
+extern int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *);
+
+extern void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *, int, int, int);
+extern int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *);
+
+extern int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *, int, int, int);
+extern int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/route.h b/libnetwork/libnl3/include/netlink/route/route.h
new file mode 100644
index 0000000..5729cd7
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/route.h
@@ -0,0 +1,124 @@
+/*
+ * netlink/route/route.h	Routes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_ROUTE_H_
+#define NETLINK_ROUTE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/data.h>
+#include <netlink/route/nexthop.h>
+#include <netlink/route/rtnl.h>
+#include <linux/in_route.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* flags */
+#define ROUTE_CACHE_CONTENT	1
+
+struct rtnl_route;
+
+struct rtnl_rtcacheinfo
+{
+	uint32_t	rtci_clntref;
+	uint32_t	rtci_last_use;
+	uint32_t	rtci_expires;
+	int32_t		rtci_error;
+	uint32_t	rtci_used;
+	uint32_t	rtci_id;
+	uint32_t	rtci_ts;
+	uint32_t	rtci_tsage;
+};
+
+extern struct nl_object_ops route_obj_ops;
+
+extern struct rtnl_route *	rtnl_route_alloc(void);
+extern void	rtnl_route_put(struct rtnl_route *);
+extern int	rtnl_route_alloc_cache(struct nl_sock *, int, int,
+				       struct nl_cache **);
+
+extern void	rtnl_route_get(struct rtnl_route *);
+extern void	rtnl_route_put(struct rtnl_route *);
+
+extern int	rtnl_route_parse(struct nlmsghdr *, struct rtnl_route **);
+extern int	rtnl_route_build_msg(struct nl_msg *, struct rtnl_route *);
+
+extern int	rtnl_route_build_add_request(struct rtnl_route *, int,
+					     struct nl_msg **);
+extern int	rtnl_route_add(struct nl_sock *, struct rtnl_route *, int);
+extern int	rtnl_route_build_del_request(struct rtnl_route *, int,
+					     struct nl_msg **);
+extern int	rtnl_route_delete(struct nl_sock *, struct rtnl_route *, int);
+
+extern void	rtnl_route_set_table(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_table(struct rtnl_route *);
+extern void	rtnl_route_set_scope(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_scope(struct rtnl_route *);
+extern void	rtnl_route_set_tos(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_tos(struct rtnl_route *);
+extern void	rtnl_route_set_protocol(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_protocol(struct rtnl_route *);
+extern void	rtnl_route_set_priority(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_priority(struct rtnl_route *);
+extern int	rtnl_route_set_family(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_family(struct rtnl_route *);
+extern int	rtnl_route_set_type(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_type(struct rtnl_route *);
+extern void	rtnl_route_set_flags(struct rtnl_route *, uint32_t);
+extern void	rtnl_route_unset_flags(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_flags(struct rtnl_route *);
+extern int	rtnl_route_set_metric(struct rtnl_route *, int, unsigned int);
+extern int	rtnl_route_unset_metric(struct rtnl_route *, int);
+extern int	rtnl_route_get_metric(struct rtnl_route *, int, uint32_t *);
+extern int	rtnl_route_set_dst(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_dst(struct rtnl_route *);
+extern int	rtnl_route_set_src(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_src(struct rtnl_route *);
+extern int	rtnl_route_set_pref_src(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *);
+extern void	rtnl_route_set_iif(struct rtnl_route *, int);
+extern int	rtnl_route_get_iif(struct rtnl_route *);
+extern int	rtnl_route_get_src_len(struct rtnl_route *);
+
+extern void	rtnl_route_add_nexthop(struct rtnl_route *,
+				       struct rtnl_nexthop *);
+extern void	rtnl_route_remove_nexthop(struct rtnl_route *,
+					  struct rtnl_nexthop *);
+extern struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *);
+extern int	rtnl_route_get_nnexthops(struct rtnl_route *);
+
+extern void	rtnl_route_foreach_nexthop(struct rtnl_route *r,
+                                 void (*cb)(struct rtnl_nexthop *, void *),
+                                 void *arg);
+
+extern struct rtnl_nexthop * rtnl_route_nexthop_n(struct rtnl_route *r, int n);
+
+extern int	rtnl_route_guess_scope(struct rtnl_route *);
+
+extern char *	rtnl_route_table2str(int, char *, size_t);
+extern int	rtnl_route_str2table(const char *);
+extern int	rtnl_route_read_table_names(const char *);
+
+extern char *	rtnl_route_proto2str(int, char *, size_t);
+extern int	rtnl_route_str2proto(const char *);
+extern int	rtnl_route_read_protocol_names(const char *);
+
+extern char *	rtnl_route_metric2str(int, char *, size_t);
+extern int	rtnl_route_str2metric(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/rtnl.h b/libnetwork/libnl3/include/netlink/route/rtnl.h
new file mode 100644
index 0000000..f551a5d
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/rtnl.h
@@ -0,0 +1,69 @@
+/*
+ * netlink/route/rtnl.h		Routing Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_RTNL_H_
+#define NETLINK_RTNL_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Realms
+ * @{
+ */
+
+/**
+ * Mask specying the size of each realm part
+ * @ingroup rtnl
+ */
+#define RTNL_REALM_MASK (0xFFFF)
+
+/**
+ * Extract FROM realm from a realms field
+ */
+#define RTNL_REALM_FROM(realm) ((realm) >> 16)
+
+/**
+ * Extract TO realm from a realms field
+ */
+#define RTNL_REALM_TO(realm) ((realm) & RTNL_REALM_MASK)
+
+/**
+ * Build a realms field
+ */
+#define RTNL_MAKE_REALM(from, to) \
+	((RTNL_REALM_TO(from) << 16) & RTNL_REALM_TO(to))
+
+/** @} */
+
+
+/* General */
+extern int		nl_rtgen_request(struct nl_sock *, int, int, int);
+
+/* Routing Type Translations */
+extern char *		nl_rtntype2str(int, char *, size_t);
+extern int		nl_str2rtntype(const char *);
+
+/* Scope Translations */
+extern char *		rtnl_scope2str(int, char *, size_t);
+extern int		rtnl_str2scope(const char *);
+
+/* Realms Translations */
+extern char *		rtnl_realms2str(uint32_t, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/rule.h b/libnetwork/libnl3/include/netlink/route/rule.h
new file mode 100644
index 0000000..760b782
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/rule.h
@@ -0,0 +1,75 @@
+/*
+ * netlink/route/rule.h		Rules
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_RULE_H_
+#define NETLINK_RULE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/route/route.h>
+#include <linux/fib_rules.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_rule;
+
+/* General */
+extern struct rtnl_rule *	rtnl_rule_alloc(void);
+extern void			rtnl_rule_put(struct rtnl_rule *);
+
+extern int	rtnl_rule_alloc_cache(struct nl_sock *, int,
+				      struct nl_cache **);
+extern void rtnl_rule_dump(struct rtnl_rule *, FILE *, struct nl_dump_params *);
+
+extern int	rtnl_rule_build_add_request(struct rtnl_rule *, int,
+					    struct nl_msg **);
+extern int rtnl_rule_add(struct nl_sock *, struct rtnl_rule *, int);
+extern int	rtnl_rule_build_delete_request(struct rtnl_rule *, int,
+					       struct nl_msg **);
+extern int rtnl_rule_delete(struct nl_sock *, struct rtnl_rule *, int);
+
+
+/* attribute modification */
+extern void		rtnl_rule_set_family(struct rtnl_rule *, int);
+extern int		rtnl_rule_get_family(struct rtnl_rule *);
+extern void		rtnl_rule_set_prio(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_prio(struct rtnl_rule *);
+extern void		rtnl_rule_set_mark(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_mark(struct rtnl_rule *);
+extern void		rtnl_rule_set_mask(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_mask(struct rtnl_rule *);
+extern void		rtnl_rule_set_table(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_table(struct rtnl_rule *);
+extern void		rtnl_rule_set_dsfield(struct rtnl_rule *, uint8_t);
+extern uint8_t		rtnl_rule_get_dsfield(struct rtnl_rule *);
+extern int		rtnl_rule_set_src(struct rtnl_rule *, struct nl_addr *);
+extern struct nl_addr *	rtnl_rule_get_src(struct rtnl_rule *);
+extern int		rtnl_rule_set_dst(struct rtnl_rule *, struct nl_addr *);
+extern struct nl_addr *	rtnl_rule_get_dst(struct rtnl_rule *);
+extern void		rtnl_rule_set_action(struct rtnl_rule *, uint8_t);
+extern uint8_t		rtnl_rule_get_action(struct rtnl_rule *);
+extern int		rtnl_rule_set_iif(struct rtnl_rule *, const char *);
+extern char *		rtnl_rule_get_iif(struct rtnl_rule *);
+extern int		rtnl_rule_set_oif(struct rtnl_rule *, const char *);
+extern char *		rtnl_rule_get_oif(struct rtnl_rule *);
+extern void		rtnl_rule_set_realms(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_realms(struct rtnl_rule *);
+extern void		rtnl_rule_set_goto(struct rtnl_rule *, uint32_t);
+extern uint32_t		rtnl_rule_get_goto(struct rtnl_rule *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/tc-api.h b/libnetwork/libnl3/include/netlink/route/tc-api.h
new file mode 100644
index 0000000..d89408f
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/tc-api.h
@@ -0,0 +1,143 @@
+/*
+ * netlink/route/tc-api.h	Traffic Control API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_TC_API_H_
+#define NETLINK_TC_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum rtnl_tc_type {
+	RTNL_TC_TYPE_QDISC,
+	RTNL_TC_TYPE_CLASS,
+	RTNL_TC_TYPE_CLS,
+	__RTNL_TC_TYPE_MAX,
+};
+
+#define RTNL_TC_TYPE_MAX (__RTNL_TC_TYPE_MAX - 1)
+
+/**
+ * Traffic control object operations
+ * @ingroup tc
+ *
+ * This structure holds function pointers and settings implementing
+ * the features of each traffic control object implementation.
+ */
+struct rtnl_tc_ops
+{
+	/**
+	 * Name of traffic control module
+	 */
+	char *to_kind;
+
+	/**
+	 * Type of traffic control object
+	 */
+	enum rtnl_tc_type to_type;
+
+
+	/**
+	 * Size of private data
+	 */
+	size_t to_size;
+
+	/**
+	 * Dump callbacks
+	 */
+	void (*to_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, void *,
+				       struct nl_dump_params *);
+	/**
+	 * Used to fill the contents of TCA_OPTIONS
+	 */
+	int (*to_msg_fill)(struct rtnl_tc *, void *, struct nl_msg *);
+
+	/**
+	 * Uesd to to fill tc related messages, unlike with to_msg_fill,
+	 * the contents is not encapsulated with a TCA_OPTIONS nested
+	 * attribute.
+	 */
+	int (*to_msg_fill_raw)(struct rtnl_tc *, void *, struct nl_msg *);
+
+	/**
+	 * TCA_OPTIONS message parser
+	 */
+	int (*to_msg_parser)(struct rtnl_tc *, void *);
+
+	/**
+	 * Called before a tc object is destroyed
+	 */
+	void (*to_free_data)(struct rtnl_tc *, void *);
+
+	/**
+	 * Called whenever a classifier object needs to be cloned
+	 */
+	int (*to_clone)(void *, void *);
+
+	/**
+	 * Internal, don't touch
+	 */
+	struct nl_list_head to_list;
+};
+
+struct rtnl_tc_type_ops
+{
+	enum rtnl_tc_type tt_type;
+
+	char *tt_dump_prefix;
+
+	/**
+	 * Dump callbacks
+	 */
+	void (*tt_dump[NL_DUMP_MAX+1])(struct rtnl_tc *,
+				        struct nl_dump_params *);
+};
+
+extern int			rtnl_tc_msg_parse(struct nlmsghdr *,
+						  struct rtnl_tc *);
+extern int			rtnl_tc_msg_build(struct rtnl_tc *, int,
+						  int, struct nl_msg **);
+
+extern void			rtnl_tc_free_data(struct nl_object *);
+extern int			rtnl_tc_clone(struct nl_object *,
+					      struct nl_object *);
+extern void			rtnl_tc_dump_line(struct nl_object *,
+						  struct nl_dump_params *);
+extern void			rtnl_tc_dump_details(struct nl_object *,
+						     struct nl_dump_params *);
+extern void			rtnl_tc_dump_stats(struct nl_object *,
+						   struct nl_dump_params *);
+extern int			rtnl_tc_compare(struct nl_object *,
+						struct nl_object *,
+						uint32_t, int);
+
+extern void *			rtnl_tc_data(struct rtnl_tc *);
+extern void *			rtnl_tc_data_check(struct rtnl_tc *,
+						   struct rtnl_tc_ops *);
+
+extern struct rtnl_tc_ops *	rtnl_tc_lookup_ops(enum rtnl_tc_type,
+						   const char *);
+extern struct rtnl_tc_ops *	rtnl_tc_get_ops(struct rtnl_tc *);
+extern int 			rtnl_tc_register(struct rtnl_tc_ops *);
+extern void 			rtnl_tc_unregister(struct rtnl_tc_ops *);
+
+extern void			rtnl_tc_type_register(struct rtnl_tc_type_ops *);
+extern void			rtnl_tc_type_unregister(struct rtnl_tc_type_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/route/tc.h b/libnetwork/libnl3/include/netlink/route/tc.h
new file mode 100644
index 0000000..50ca6de
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/route/tc.h
@@ -0,0 +1,105 @@
+/*
+ * netlink/route/tc.h		Traffic Control
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_TC_H_
+#define NETLINK_TC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/data.h>
+#include <netlink/route/link.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Compute tc handle based on major and minor parts
+ * @ingroup tc
+ */
+#define TC_HANDLE(maj, min)	(TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
+
+/**
+ * Traffic control object
+ * @ingroup tc
+ */
+struct rtnl_tc;
+
+/**
+ * Macro to cast qdisc/class/classifier to tc object
+ * @ingroup tc
+ *
+ * @code
+ * rtnl_tc_set_mpu(TC_CAST(qdisc), 40);
+ * @endcode
+ */
+#define TC_CAST(ptr)		((struct rtnl_tc *) (ptr))
+
+/**
+ * Traffic control statistical identifier
+ * @ingroup tc
+ *
+ * @code
+ * uint64_t n = rtnl_tc_get_stat(TC_CAST(class), RTNL_TC_PACKETS);
+ * @endcode
+ */
+enum rtnl_tc_stat {
+	RTNL_TC_PACKETS,	/**< Number of packets seen */
+	RTNL_TC_BYTES,		/**< Total bytes seen */
+	RTNL_TC_RATE_BPS,	/**< Current bits/s (rate estimator) */
+	RTNL_TC_RATE_PPS,	/**< Current packet/s (rate estimator) */
+	RTNL_TC_QLEN,		/**< Current queue length */
+	RTNL_TC_BACKLOG,	/**< Current backlog length */
+	RTNL_TC_DROPS,		/**< Total number of packets dropped */
+	RTNL_TC_REQUEUES,	/**< Total number of requeues */
+	RTNL_TC_OVERLIMITS,	/**< Total number of overlimits */
+	__RTNL_TC_STATS_MAX,
+};
+
+#define RTNL_TC_STATS_MAX (__RTNL_TC_STATS_MAX - 1)
+
+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);
+extern char *		rtnl_tc_handle2str(uint32_t, char *, size_t);
+extern int		rtnl_tc_str2handle(const char *, uint32_t *);
+extern int		rtnl_classid_generate(const char *, uint32_t *,
+					      uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/socket.h b/libnetwork/libnl3/include/netlink/socket.h
new file mode 100644
index 0000000..d0f5a6a
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/socket.h
@@ -0,0 +1,69 @@
+/*
+ * netlink/socket.h		Netlink Socket
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_SOCKET_H_
+#define NETLINK_SOCKET_H_
+
+#include <netlink/types.h>
+#include <netlink/handlers.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct nl_sock *	nl_socket_alloc(void);
+extern struct nl_sock *	nl_socket_alloc_cb(struct nl_cb *);
+extern void		nl_socket_free(struct nl_sock *);
+
+extern uint32_t		nl_socket_get_local_port(const struct nl_sock *);
+extern void		nl_socket_set_local_port(struct nl_sock *, uint32_t);
+
+extern int		nl_socket_add_memberships(struct nl_sock *, int, ...);
+extern int		nl_socket_add_membership(struct nl_sock *, int);
+extern int		nl_socket_drop_memberships(struct nl_sock *, int, ...);
+extern int		nl_socket_drop_membership(struct nl_sock *,
+							  int);
+extern void		nl_join_groups(struct nl_sock *, int);
+
+
+extern uint32_t		nl_socket_get_peer_port(const struct nl_sock *);
+extern void		nl_socket_set_peer_port(struct nl_sock *,
+							uint32_t);
+extern uint32_t 	nl_socket_get_peer_groups(const struct nl_sock *sk);
+extern void 		nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
+extern struct nl_cb *	nl_socket_get_cb(const struct nl_sock *);
+extern void		nl_socket_set_cb(struct nl_sock *,
+						 struct nl_cb *);
+extern int		nl_socket_modify_cb(struct nl_sock *, enum nl_cb_type,
+					    enum nl_cb_kind,
+					    nl_recvmsg_msg_cb_t, void *);
+extern int nl_socket_modify_err_cb(struct nl_sock *, enum nl_cb_kind,
+				   nl_recvmsg_err_cb_t, void *);
+
+extern int		nl_socket_set_buffer_size(struct nl_sock *, int, int);
+extern int		nl_socket_set_passcred(struct nl_sock *, int);
+extern int		nl_socket_recv_pktinfo(struct nl_sock *, int);
+
+extern void		nl_socket_disable_seq_check(struct nl_sock *);
+extern unsigned int	nl_socket_use_seq(struct nl_sock *);
+extern void		nl_socket_disable_auto_ack(struct nl_sock *);
+extern void		nl_socket_enable_auto_ack(struct nl_sock *);
+
+extern int		nl_socket_get_fd(const struct nl_sock *);
+extern int		nl_socket_set_nonblocking(const struct nl_sock *);
+extern void		nl_socket_enable_msg_peek(struct nl_sock *);
+extern void		nl_socket_disable_msg_peek(struct nl_sock *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/types.h b/libnetwork/libnl3/include/netlink/types.h
new file mode 100644
index 0000000..f6dade3
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/types.h
@@ -0,0 +1,110 @@
+/*
+ * netlink/netlink-types.h	Netlink Types
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef __NETLINK_TYPES_H_
+#define __NETLINK_TYPES_H_
+
+#include <stdio.h>
+
+/**
+ * Dumping types (dp_type)
+ * @ingroup utils
+ */
+enum nl_dump_type {
+	NL_DUMP_LINE,		/**< Dump object briefly on one line */
+	NL_DUMP_DETAILS,	/**< Dump all attributes but no statistics */
+	NL_DUMP_STATS,		/**< Dump all attributes including statistics */
+	__NL_DUMP_MAX,
+};
+#define NL_DUMP_MAX (__NL_DUMP_MAX - 1)
+
+/**
+ * Dumping parameters
+ * @ingroup utils
+ */
+struct nl_dump_params
+{
+	/**
+	 * Specifies the type of dump that is requested.
+	 */
+	enum nl_dump_type	dp_type;
+
+	/**
+	 * Specifies the number of whitespaces to be put in front
+	 * of every new line (indentation).
+	 */
+	int			dp_prefix;
+
+	/**
+	 * Causes the cache index to be printed for each element.
+	 */
+	int			dp_print_index;
+
+	/**
+	 * Causes each element to be prefixed with the message type.
+	 */
+	int			dp_dump_msgtype;
+
+	/**
+	 * A callback invoked for output
+	 *
+	 * Passed arguments are:
+	 *  - dumping parameters
+	 *  - string to append to the output
+	 */
+	void			(*dp_cb)(struct nl_dump_params *, char *);
+
+	/**
+	 * A callback invoked for every new line, can be used to
+	 * customize the indentation.
+	 *
+	 * Passed arguments are:
+	 *  - dumping parameters
+	 *  - line number starting from 0
+	 */
+	void			(*dp_nl_cb)(struct nl_dump_params *, int);
+
+	/**
+	 * User data pointer, can be used to pass data to callbacks.
+	 */
+	void			*dp_data;
+
+	/**
+	 * File descriptor the dumping output should go to
+	 */
+	FILE *			dp_fd;
+
+	/**
+	 * Alternatively the output may be redirected into a buffer
+	 */
+	char *			dp_buf;
+
+	/**
+	 * Length of the buffer dp_buf
+	 */
+	size_t			dp_buflen;
+
+	/**
+	 * PRIVATE
+	 * Set if a dump was performed prior to the actual dump handler.
+	 */
+	int			dp_pre_dump;
+
+	/**
+	 * PRIVATE
+	 * Owned by the current caller
+	 */
+	int			dp_ivar;
+
+	unsigned int		dp_line;
+};
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/utils.h b/libnetwork/libnl3/include/netlink/utils.h
new file mode 100644
index 0000000..a1ef82e
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/utils.h
@@ -0,0 +1,85 @@
+/*
+ * netlink/utils.h		Utility Functions
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_UTILS_H_
+#define NETLINK_UTILS_H_
+
+#include <netlink/netlink.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Probability Constants
+ * @{
+ */
+
+/**
+ * Lower probability limit
+ * @ingroup utils
+ */
+#define NL_PROB_MIN 0x0
+
+/**
+ * Upper probability limit
+ * @ingroup utils
+ */
+#define NL_PROB_MAX 0xffffffff
+
+/** @} */
+
+enum {
+	NL_BYTE_RATE,
+	NL_BIT_RATE,
+};
+
+/* unit pretty-printing */
+extern double	nl_cancel_down_bytes(unsigned long long, char **);
+extern double	nl_cancel_down_bits(unsigned long long, char **);
+extern int	nl_rate2str(unsigned long long, int, char *, size_t);
+extern double	nl_cancel_down_us(uint32_t, char **);
+
+/* generic unit translations */
+extern long	nl_size2int(const char *);
+extern char *	nl_size2str(const size_t, char *, const size_t);
+extern long	nl_prob2int(const char *);
+
+/* time translations */
+extern int	nl_get_user_hz(void);
+extern uint32_t	nl_us2ticks(uint32_t);
+extern uint32_t	nl_ticks2us(uint32_t);
+extern int	nl_str2msec(const char *, uint64_t *);
+extern char *	nl_msec2str(uint64_t, char *, size_t);
+
+/* link layer protocol translations */
+extern char *	nl_llproto2str(int, char *, size_t);
+extern int	nl_str2llproto(const char *);
+
+/* ethernet protocol translations */
+extern char *	nl_ether_proto2str(int, char *, size_t);
+extern int	nl_str2ether_proto(const char *);
+
+/* IP protocol translations */
+extern char *	nl_ip_proto2str(int, char *, size_t);
+extern int	nl_str2ip_proto(const char *);
+
+/* Dumping helpers */
+extern void	nl_new_line(struct nl_dump_params *);
+extern void	nl_dump(struct nl_dump_params *, const char *, ...);
+extern void	nl_dump_line(struct nl_dump_params *, const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/version.h b/libnetwork/libnl3/include/netlink/version.h
new file mode 100644
index 0000000..85d1831
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/version.h
@@ -0,0 +1,28 @@
+/*
+ * netlink/version.h	Compile Time Versioning Information
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_VERSION_H_
+#define NETLINK_VERSION_H_
+
+#define LIBNL_STRING "libnl 3.2.3"
+#define LIBNL_VERSION "3.2.3"
+
+#define LIBNL_VER_MAJ		3
+#define LIBNL_VER_MIN		2
+#define LIBNL_VER_MIC		3
+#define LIBNL_VER(maj,min)	((maj) << 8 | (min))
+#define LIBNL_VER_NUM		LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN)
+
+#define LIBNL_CURRENT		203
+#define LIBNL_REVISION		0
+#define LIBNL_AGE		3
+
+#endif
diff --git a/libnetwork/libnl3/include/netlink/version.h.in b/libnetwork/libnl3/include/netlink/version.h.in
new file mode 100644
index 0000000..ac56799
--- /dev/null
+++ b/libnetwork/libnl3/include/netlink/version.h.in
@@ -0,0 +1,28 @@
+/*
+ * netlink/version.h	Compile Time Versioning Information
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#ifndef NETLINK_VERSION_H_
+#define NETLINK_VERSION_H_
+
+#define LIBNL_STRING "@PACKAGE_STRING@"
+#define LIBNL_VERSION "@PACKAGE_VERSION@"
+
+#define LIBNL_VER_MAJ		@MAJ_VERSION@
+#define LIBNL_VER_MIN		@MIN_VERSION@
+#define LIBNL_VER_MIC		@MIC_VERSION@
+#define LIBNL_VER(maj,min)	((maj) << 8 | (min))
+#define LIBNL_VER_NUM		LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN)
+
+#define LIBNL_CURRENT		@LT_CURRENT@
+#define LIBNL_REVISION		@LT_REVISION@
+#define LIBNL_AGE		@LT_AGE@
+
+#endif
diff --git a/libnetwork/libnl3/lib/addr.c b/libnetwork/libnl3/lib/addr.c
new file mode 100644
index 0000000..c8c4ca4
--- /dev/null
+++ b/libnetwork/libnl3/lib/addr.c
@@ -0,0 +1,918 @@
+/*
+ * lib/addr.c		Abstract Address
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup addr Abstract Address
+ *
+ * @par 1) Transform character string to abstract address
+ * @code
+ * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC);
+ * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
+ * nl_addr_put(a);
+ * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC);
+ * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
+ * nl_addr_put(a);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <linux/socket.h>
+
+/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
+ * this, probably Alexey. */
+static inline uint16_t dn_ntohs(uint16_t addr)
+{
+	union {
+		uint8_t byte[2];
+		uint16_t word;
+	} u = {
+		.word = addr,
+	};
+
+	return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
+}
+
+static inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
+			   size_t *pos, size_t len, int *started)
+{
+	uint16_t tmp = *addr / scale;
+
+	if (*pos == len)
+		return 1;
+
+	if (((tmp) > 0) || *started || (scale == 1)) {
+		*str = tmp + '0';
+		*started = 1;
+		(*pos)++;
+		*addr -= (tmp * scale);
+	}
+
+	return 0;
+}
+
+static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
+			     size_t len)
+{
+	uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
+	uint16_t area = addr >> 10;
+	size_t pos = 0;
+	int started = 0;
+
+	if (addrlen != 2)
+		return NULL;
+
+	addr &= 0x03ff;
+
+	if (len == 0)
+		return str;
+
+	if (do_digit(str + pos, &area, 10, &pos, len, &started))
+		return str;
+
+	if (do_digit(str + pos, &area, 1, &pos, len, &started))
+		return str;
+
+	if (pos == len)
+		return str;
+
+	*(str + pos) = '.';
+	pos++;
+	started = 0;
+
+	if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
+		return str;
+
+	if (do_digit(str + pos, &addr, 100, &pos, len, &started))
+		return str;
+
+	if (do_digit(str + pos, &addr, 10, &pos, len, &started))
+		return str;
+
+	if (do_digit(str + pos, &addr, 1, &pos, len, &started))
+		return str;
+
+	if (pos == len)
+		return str;
+
+	*(str + pos) = 0;
+
+	return str;
+}
+
+static int dnet_num(const char *src, uint16_t * dst)
+{
+	int rv = 0;
+	int tmp;
+	*dst = 0;
+
+	while ((tmp = *src++) != 0) {
+		tmp -= '0';
+		if ((tmp < 0) || (tmp > 9))
+			return rv;
+
+		rv++;
+		(*dst) *= 10;
+		(*dst) += tmp;
+	}
+
+	return rv;
+}
+
+static inline int dnet_pton(const char *src, char *addrbuf)
+{
+	uint16_t area = 0;
+	uint16_t node = 0;
+	int pos;
+
+	pos = dnet_num(src, &area);
+	if ((pos == 0) || (area > 63) ||
+	    ((*(src + pos) != '.') && (*(src + pos) != ',')))
+		return -NLE_INVAL;
+
+	pos = dnet_num(src + pos + 1, &node);
+	if ((pos == 0) || (node > 1023))
+		return -NLE_INVAL;
+
+	*(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
+
+	return 1;
+}
+
+static void addr_destroy(struct nl_addr *addr)
+{
+	if (!addr)
+		return;
+
+	if (addr->a_refcnt != 1)
+		BUG();
+
+	free(addr);
+}
+
+/**
+ * @name Creating Abstract Addresses
+ * @{
+ */
+
+/**
+ * Allocate new abstract address object.
+ * @arg maxsize		Maximum size of the binary address.
+ * @return Newly allocated address object or NULL
+ */
+struct nl_addr *nl_addr_alloc(size_t maxsize)
+{
+	struct nl_addr *addr;
+	
+	addr = calloc(1, sizeof(*addr) + maxsize);
+	if (!addr)
+		return NULL;
+
+	addr->a_refcnt = 1;
+	addr->a_maxsize = maxsize;
+
+	return addr;
+}
+
+/**
+ * Allocate new abstract address object based on a binary address.
+ * @arg family		Address family.
+ * @arg buf		Buffer containing the binary address.
+ * @arg size		Length of binary address buffer.
+ * @return Newly allocated address handle or NULL
+ */
+struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
+{
+	struct nl_addr *addr;
+
+	addr = nl_addr_alloc(size);
+	if (!addr)
+		return NULL;
+
+	addr->a_family = family;
+	addr->a_len = size;
+	addr->a_prefixlen = size*8;
+
+	if (size)
+		memcpy(addr->a_addr, buf, size);
+
+	return addr;
+}
+
+/**
+ * Allocate abstract address based on netlink attribute.
+ * @arg nla		Netlink attribute of unspecific type.
+ * @arg family		Address family.
+ *
+ * Considers the netlink attribute payload a address of the specified
+ * family and allocates a new abstract address based on it.
+ *
+ * @return Newly allocated address handle or NULL.
+ */
+struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
+{
+	return nl_addr_build(family, nla_data(nla), nla_len(nla));
+}
+
+/**
+ * Allocate abstract address object based on a character string
+ * @arg addrstr		Address represented as character string.
+ * @arg hint		Address family hint or AF_UNSPEC.
+ * @arg result		Pointer to store resulting address.
+ *
+ * Regognizes the following address formats:
+ *@code
+ *  Format                      Len                Family
+ *  ----------------------------------------------------------------
+ *  IPv6 address format         16                 AF_INET6
+ *  ddd.ddd.ddd.ddd             4                  AF_INET
+ *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
+ *  AA{.|,}NNNN                 2                  AF_DECnet
+ *  HH:HH:HH:...                variable           AF_UNSPEC
+ * @endcode
+ *
+ *  Special values:
+ *    - none: All bits and length set to 0.
+ *    - {default|all|any}: All bits set to 0, length based on hint or
+ *                         AF_INET if no hint is given.
+ *
+ * The prefix length may be appened at the end prefixed with a
+ * slash, e.g. 10.0.0.0/8.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
+{
+	int err, copy = 0, len = 0, family = AF_UNSPEC;
+	char *str, *prefix, buf[32];
+	struct nl_addr *addr = NULL; /* gcc ain't that smart */
+
+	str = strdup(addrstr);
+	if (!str) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	prefix = strchr(str, '/');
+	if (prefix)
+		*prefix = '\0';
+
+	if (!strcasecmp(str, "none")) {
+		family = hint;
+		goto prefix;
+	}
+
+	if (!strcasecmp(str, "default") ||
+	    !strcasecmp(str, "all") ||
+	    !strcasecmp(str, "any")) {
+			
+		switch (hint) {
+			case AF_INET:
+			case AF_UNSPEC:
+				/* Kind of a hack, we assume that if there is
+				 * no hint given the user wants to have a IPv4
+				 * address given back. */
+				family = AF_INET;
+				len = 4;
+				goto prefix;
+
+			case AF_INET6:
+				family = AF_INET6;
+				len = 16;
+				goto prefix;
+
+			case AF_LLC:
+				family = AF_LLC;
+				len = 6;
+				goto prefix;
+
+			default:
+				err = -NLE_AF_NOSUPPORT;
+				goto errout;
+		}
+	}
+
+	copy = 1;
+
+	if (hint == AF_INET || hint == AF_UNSPEC) {
+		if (inet_pton(AF_INET, str, buf) > 0) {
+			family = AF_INET;
+			len = 4;
+			goto prefix;
+		}
+		if (hint == AF_INET) {
+			err = -NLE_NOADDR;
+			goto errout;
+		}
+	}
+
+	if (hint == AF_INET6 || hint == AF_UNSPEC) {
+		if (inet_pton(AF_INET6, str, buf) > 0) {
+			family = AF_INET6;
+			len = 16;
+			goto prefix;
+		}
+		if (hint == AF_INET6) {
+			err = -NLE_NOADDR;
+			goto errout;
+		}
+	}
+
+	if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
+		unsigned int a, b, c, d, e, f;
+
+		if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+		    &a, &b, &c, &d, &e, &f) == 6) {
+			family = AF_LLC;
+			len = 6;
+			buf[0] = (unsigned char) a;
+			buf[1] = (unsigned char) b;
+			buf[2] = (unsigned char) c;
+			buf[3] = (unsigned char) d;
+			buf[4] = (unsigned char) e;
+			buf[5] = (unsigned char) f;
+			goto prefix;
+		}
+
+		if (hint == AF_LLC) {
+			err = -NLE_NOADDR;
+			goto errout;
+		}
+	}
+
+	if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
+	    (strchr(str, '.') || strchr(str, ','))) {
+		if (dnet_pton(str, buf) > 0) {
+			family = AF_DECnet;
+			len = 2;
+			goto prefix;
+		}
+		if (hint == AF_DECnet) {
+			err = -NLE_NOADDR;
+			goto errout;
+		}
+	}
+
+	if (hint == AF_UNSPEC && strchr(str, ':')) {
+		int i = 0;
+		char *s = str, *p;
+		for (;;) {
+			long l = strtol(s, &p, 16);
+
+			if (s == p || l > 0xff || i >= sizeof(buf)) {
+				err = -NLE_INVAL;
+				goto errout;
+			}
+
+			buf[i++] = (unsigned char) l;
+			if (*p == '\0')
+				break;
+			s = ++p;
+		}
+
+		len = i;
+		family = AF_UNSPEC;
+		goto prefix;
+	}
+
+	err = -NLE_NOADDR;
+	goto errout;
+
+prefix:
+	addr = nl_addr_alloc(len);
+	if (!addr) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	nl_addr_set_family(addr, family);
+
+	if (copy)
+		nl_addr_set_binary_addr(addr, buf, len);
+
+	if (prefix) {
+		char *p;
+		long pl = strtol(++prefix, &p, 0);
+		if (p == prefix) {
+			addr_destroy(addr);
+			err = -NLE_INVAL;
+			goto errout;
+		}
+		nl_addr_set_prefixlen(addr, pl);
+	} else
+		nl_addr_set_prefixlen(addr, len * 8);
+
+	*result = addr;
+	err = 0;
+errout:
+	free(str);
+
+	return err;
+}
+
+/**
+ * Clone existing abstract address object.
+ * @arg addr		Abstract address object.
+ * @return Newly allocated abstract address object being a duplicate of the
+ *         specified address object or NULL if a failure occured.
+ */
+struct nl_addr *nl_addr_clone(struct nl_addr *addr)
+{
+	struct nl_addr *new;
+
+	new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
+	if (new)
+		new->a_prefixlen = addr->a_prefixlen;
+
+	return new;
+}
+
+/** @} */
+
+/**
+ * @name Managing Usage References
+ * @{
+ */
+
+struct nl_addr *nl_addr_get(struct nl_addr *addr)
+{
+	addr->a_refcnt++;
+
+	return addr;
+}
+
+void nl_addr_put(struct nl_addr *addr)
+{
+	if (!addr)
+		return;
+
+	if (addr->a_refcnt == 1)
+		addr_destroy(addr);
+	else
+		addr->a_refcnt--;
+}
+
+/**
+ * Check whether an abstract address object is shared.
+ * @arg addr		Abstract address object.
+ * @return Non-zero if the abstract address object is shared, otherwise 0.
+ */
+int nl_addr_shared(struct nl_addr *addr)
+{
+	return addr->a_refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Miscellaneous
+ * @{
+ */
+
+/**
+ * Compares two abstract address objects.
+ * @arg a		A abstract address object.
+ * @arg b		Another abstract address object.
+ *
+ * @return Integer less than, equal to or greather than zero if \c is found,
+ *         respectively to be less than, to, or be greater than \c b.
+ */
+int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
+{
+	int d = a->a_family - b->a_family;
+
+	if (d == 0) {
+		d = a->a_len - b->a_len;
+
+		if (a->a_len && d == 0)
+			return memcmp(a->a_addr, b->a_addr, a->a_len);
+	}
+
+	return d;
+}
+
+/**
+ * Compares the prefix of two abstract address objects.
+ * @arg a		A abstract address object.
+ * @arg b		Another abstract address object.
+ *
+ * @return Integer less than, equal to or greather than zero if \c is found,
+ *         respectively to be less than, to, or be greater than \c b.
+ */
+int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
+{
+	int d = a->a_family - b->a_family;
+
+	if (d == 0) {
+		int len = min(a->a_prefixlen, b->a_prefixlen);
+		int bytes = len / 8;
+
+		d = memcmp(a->a_addr, b->a_addr, bytes);
+		if (d == 0) {
+			int mask = (1UL << (len % 8)) - 1UL;
+
+			d = (a->a_addr[bytes] & mask) -
+			    (b->a_addr[bytes] & mask);
+		}
+	}
+
+	return d;
+}
+
+/**
+ * Returns true if the address consists of all zeros
+ * @arg addr		Address to look at.
+ */
+int nl_addr_iszero(struct nl_addr *addr)
+{
+	int i;
+
+	for (i = 0; i < addr->a_len; i++)
+		if (addr->a_addr[i])
+			return 0;
+
+	return 1;
+}
+
+/**
+ * Check if an address matches a certain family.
+ * @arg addr		Address represented as character string.
+ * @arg family		Desired address family.
+ *
+ * @return 1 if the address is of the desired address family,
+ *         otherwise 0 is returned.
+ */
+int nl_addr_valid(char *addr, int family)
+{
+	int ret;
+	char buf[32];
+
+	switch (family) {
+	case AF_INET:
+	case AF_INET6:
+		ret = inet_pton(family, addr, buf);
+		if (ret <= 0)
+			return 0;
+		break;
+
+	case AF_DECnet:
+		ret = dnet_pton(addr, buf);
+		if (ret <= 0)
+			return 0;
+		break;
+
+	case AF_LLC:
+		if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
+			return 0;
+		break;
+	}
+
+	return 1;
+}
+
+/**
+ * Guess address family of an abstract address object based on address size.
+ * @arg addr		Abstract address object.
+ * @return Address family or AF_UNSPEC if guessing wasn't successful.
+ */
+int nl_addr_guess_family(struct nl_addr *addr)
+{
+	switch (addr->a_len) {
+		case 4:
+			return AF_INET;
+		case 6:
+			return AF_LLC;
+		case 16:
+			return AF_INET6;
+		default:
+			return AF_UNSPEC;
+	}
+}
+
+/**
+ * Fill out sockaddr structure with values from abstract address object.
+ * @arg addr		Abstract address object.
+ * @arg sa		Destination sockaddr structure buffer.
+ * @arg salen		Length of sockaddr structure buffer.
+ *
+ * Fills out the specified sockaddr structure with the data found in the
+ * specified abstract address. The salen argument needs to be set to the
+ * size of sa but will be modified to the actual size used during before
+ * the function exits.
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
+			  socklen_t *salen)
+{
+	switch (addr->a_family) {
+	case AF_INET: {
+		struct sockaddr_in *sai = (struct sockaddr_in *) sa;
+
+		if (*salen < sizeof(*sai))
+			return -NLE_INVAL;
+
+		sai->sin_family = addr->a_family;
+		memcpy(&sai->sin_addr, addr->a_addr, 4);
+		*salen = sizeof(*sai);
+	}
+		break;
+
+	case AF_INET6: {
+		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
+
+		if (*salen < sizeof(*sa6))
+			return -NLE_INVAL;
+
+		sa6->sin6_family = addr->a_family;
+		memcpy(&sa6->sin6_addr, addr->a_addr, 16);
+		*salen = sizeof(*sa6);
+	}
+		break;
+
+	default:
+		return -NLE_INVAL;
+	}
+
+	return 0;
+}
+
+
+/** @} */
+
+/**
+ * @name Getting Information About Addresses
+ * @{
+ */
+
+/**
+ * Call getaddrinfo() for an abstract address object.
+ * @arg addr		Abstract address object.
+ * @arg result		Pointer to store resulting address list.
+ * 
+ * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
+ * mode.
+ *
+ * @note The caller is responsible for freeing the linked list using the
+ *       interface provided by getaddrinfo(3).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
+{
+	int err;
+	char buf[INET6_ADDRSTRLEN+5];
+	struct addrinfo hint = {
+		.ai_flags = AI_NUMERICHOST,
+		.ai_family = addr->a_family,
+	};
+
+	nl_addr2str(addr, buf, sizeof(buf));
+
+	err = getaddrinfo(buf, NULL, &hint, result);
+	if (err != 0) {
+		switch (err) {
+		case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT;
+		case EAI_AGAIN: return -NLE_AGAIN;
+		case EAI_BADFLAGS: return -NLE_INVAL;
+		case EAI_FAIL: return -NLE_NOADDR;
+		case EAI_FAMILY: return -NLE_AF_NOSUPPORT;
+		case EAI_MEMORY: return -NLE_NOMEM;
+		case EAI_NODATA: return -NLE_NOADDR;
+		case EAI_NONAME: return -NLE_OBJ_NOTFOUND;
+		case EAI_SERVICE: return -NLE_OPNOTSUPP;
+		case EAI_SOCKTYPE: return -NLE_BAD_SOCK;
+		default: return -NLE_FAILURE;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Resolve abstract address object to a name using getnameinfo().
+ * @arg addr		Abstract address object.
+ * @arg host		Destination buffer for host name.
+ * @arg hostlen		Length of destination buffer.
+ *
+ * Resolves the abstract address to a name and writes the looked up result
+ * into the host buffer. getnameinfo() is used to perform the lookup and
+ * is put into NI_NAMEREQD mode so the function will fail if the lookup
+ * couldn't be performed.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
+{
+	int err;
+	struct sockaddr_in6 buf;
+	socklen_t salen = sizeof(buf);
+
+	err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
+	if (err < 0)
+		return err;
+
+	err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen,
+			  NULL, 0, NI_NAMEREQD);
+	if (err < 0)
+		return nl_syserr2nlerr(err);
+
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nl_addr_set_family(struct nl_addr *addr, int family)
+{
+	addr->a_family = family;
+}
+
+int nl_addr_get_family(struct nl_addr *addr)
+{
+	return addr->a_family;
+}
+
+/**
+ * Set binary address of abstract address object.
+ * @arg addr		Abstract address object.
+ * @arg buf		Buffer containing binary address.
+ * @arg len		Length of buffer containing binary address.
+ */
+int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
+{
+	if (len > addr->a_maxsize)
+		return -NLE_RANGE;
+
+	addr->a_len = len;
+	memcpy(addr->a_addr, buf, len);
+
+	return 0;
+}
+
+/**
+ * Get binary address of abstract address object.
+ * @arg addr		Abstract address object.
+ */
+void *nl_addr_get_binary_addr(struct nl_addr *addr)
+{
+	return addr->a_addr;
+}
+
+/**
+ * Get length of binary address of abstract address object.
+ * @arg addr		Abstract address object.
+ */
+unsigned int nl_addr_get_len(struct nl_addr *addr)
+{
+	return addr->a_len;
+}
+
+void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
+{
+	addr->a_prefixlen = prefixlen;
+}
+
+/**
+ * Get prefix length of abstract address object.
+ * @arg addr		Abstract address object.
+ */
+unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
+{
+	return addr->a_prefixlen;
+}
+
+/** @} */
+
+/**
+ * @name Translations to Strings
+ * @{
+ */
+
+/**
+ * Convert abstract address object to character string.
+ * @arg addr		Abstract address object.
+ * @arg buf		Destination buffer.
+ * @arg size		Size of destination buffer.
+ *
+ * Converts an abstract address to a character string and stores
+ * the result in the specified destination buffer.
+ *
+ * @return Address represented in ASCII stored in destination buffer.
+ */
+char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
+{
+	int i;
+	char tmp[16];
+
+	if (!addr || !addr->a_len) {
+		snprintf(buf, size, "none");
+		if (addr)
+			goto prefix;
+		else
+			return buf;
+	}
+
+	switch (addr->a_family) {
+		case AF_INET:
+			inet_ntop(AF_INET, addr->a_addr, buf, size);
+			break;
+
+		case AF_INET6:
+			inet_ntop(AF_INET6, addr->a_addr, buf, size);
+			break;
+
+		case AF_DECnet:
+			dnet_ntop(addr->a_addr, addr->a_len, buf, size);
+			break;
+
+		case AF_LLC:
+		default:
+			snprintf(buf, size, "%02x",
+				 (unsigned char) addr->a_addr[0]);
+			for (i = 1; i < addr->a_len; i++) {
+				snprintf(tmp, sizeof(tmp), ":%02x",
+					 (unsigned char) addr->a_addr[i]);
+				strncat(buf, tmp, size - strlen(buf) - 1);
+			}
+			break;
+	}
+
+prefix:
+	if (addr->a_prefixlen != (8 * addr->a_len)) {
+		snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
+		strncat(buf, tmp, size - strlen(buf) - 1);
+	}
+
+	return buf;
+}
+
+/** @} */
+
+/**
+ * @name Address Family Transformations
+ * @{
+ */
+
+static const struct trans_tbl afs[] = {
+	__ADD(AF_UNSPEC,unspec)
+	__ADD(AF_UNIX,unix)
+	__ADD(AF_LOCAL,local)
+	__ADD(AF_INET,inet)
+	__ADD(AF_AX25,ax25)
+	__ADD(AF_IPX,ipx)
+	__ADD(AF_APPLETALK,appletalk)
+	__ADD(AF_NETROM,netrom)
+	__ADD(AF_BRIDGE,bridge)
+	__ADD(AF_ATMPVC,atmpvc)
+	__ADD(AF_X25,x25)
+	__ADD(AF_INET6,inet6)
+	__ADD(AF_ROSE,rose)
+	__ADD(AF_DECnet,decnet)
+	__ADD(AF_NETBEUI,netbeui)
+	__ADD(AF_SECURITY,security)
+	__ADD(AF_KEY,key)
+	__ADD(AF_NETLINK,netlink)
+	__ADD(AF_ROUTE,route)
+	__ADD(AF_PACKET,packet)
+	__ADD(AF_ASH,ash)
+	__ADD(AF_ECONET,econet)
+	__ADD(AF_ATMSVC,atmsvc)
+	__ADD(AF_SNA,sna)
+	__ADD(AF_IRDA,irda)
+	__ADD(AF_PPPOX,pppox)
+	__ADD(AF_WANPIPE,wanpipe)
+	__ADD(AF_LLC,llc)
+	__ADD(AF_BLUETOOTH,bluetooth)
+};
+
+char *nl_af2str(int family, char *buf, size_t size)
+{
+	return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
+}
+
+int nl_str2af(const char *name)
+{
+	int fam = __str2type(name, afs, ARRAY_SIZE(afs));
+	return fam >= 0 ? fam : -EINVAL;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/attr.c b/libnetwork/libnl3/lib/attr.c
new file mode 100644
index 0000000..a045351
--- /dev/null
+++ b/libnetwork/libnl3/lib/attr.c
@@ -0,0 +1,1213 @@
+/*
+ * lib/attr.c		Netlink Attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <netlink/attr.h>
+#include <netlink/msg.h>
+#include <linux/socket.h>
+
+/**
+ * @ingroup msg
+ * @defgroup attr Attributes
+ * Netlink Attributes Construction/Parsing Interface
+ *
+ * \section attr_sec Netlink Attributes
+ * Netlink attributes allow for data chunks of arbitary length to be
+ * attached to a netlink message. Each attribute is encoded with a
+ * type and length field, both 16 bits, stored in the attribute header
+ * preceding the attribute data. The main advantage of using attributes
+ * over packing everything into the family header is that the interface
+ * stays extendable as new attributes can supersede old attributes while
+ * remaining backwards compatible. Also attributes can be defined optional
+ * thus avoiding the transmission of unnecessary empty data blocks.
+ * Special nested attributes allow for more complex data structures to
+ * be transmitted, e.g. trees, lists, etc.
+ *
+ * While not required, netlink attributes typically follow the family
+ * header of a netlink message and must be properly aligned to NLA_ALIGNTO:
+ * @code
+ *   +----------------+- - -+---------------+- - -+------------+- - -+
+ *   | Netlink Header | Pad | Family Header | Pad | Attributes | Pad |
+ *   +----------------+- - -+---------------+- - -+------------+- - -+
+ * @endcode
+ *
+ * The actual attributes are chained together each separately aligned to
+ * NLA_ALIGNTO. The position of an attribute is defined based on the
+ * length field of the preceding attributes:
+ * @code
+ *   +-------------+- - -+-------------+- - -+------
+ *   | Attribute 1 | Pad | Attribute 2 | Pad | ...
+ *   +-------------+- - -+-------------+- - -+------
+ *   nla_next(attr1)------^
+ * @endcode
+ *
+ * The attribute itself consists of the attribute header followed by
+ * the actual payload also aligned to NLA_ALIGNTO. The function nla_data()
+ * returns a pointer to the start of the payload while nla_len() returns
+ * the length of the payload in bytes.
+ *
+ * \b Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not
+ * safe to dereference any 64 bit data types directly.
+ *
+ * @code
+ *    <----------- nla_total_size(payload) ----------->
+ *    <-------- nla_attr_size(payload) --------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   nla_data(nla)-------------^
+ *                             <- nla_len(nla) ->
+ * @endcode
+ *
+ * @subsection attr_datatypes Attribute Data Types
+ * A number of basic data types are supported to simplify access and
+ * validation of netlink attributes. This data type information is
+ * not encoded in the attribute, both the kernel and userspace part
+ * are required to share this information on their own.
+ *
+ * One of the major advantages of these basic types is the automatic
+ * validation of each attribute based on an attribute policy. The
+ * validation covers most of the checks required to safely use
+ * attributes and thus keeps the individual sanity check to a minimum.
+ *
+ * Never access attribute payload without ensuring basic validation
+ * first, attributes may:
+ * - not be present even though required
+ * - contain less actual payload than expected
+ * - fake a attribute length which exceeds the end of the message
+ * - contain unterminated character strings
+ *
+ * Policies are defined as array of the struct nla_policy. The array is
+ * indexed with the attribute type, therefore the array must be sized
+ * accordingly.
+ * @code
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ * 	[ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... },
+ * };
+ *
+ * err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy);
+ * @endcode
+ *
+ * Some basic validations are performed on every attribute, regardless of type.
+ * - If the attribute type exceeds the maximum attribute type specified or
+ *   the attribute type is lesser-or-equal than zero, the attribute will
+ *   be silently ignored.
+ * - If the payload length falls below the \a minlen value the attribute
+ *   will be rejected.
+ * - If \a maxlen is non-zero and the payload length exceeds the \a maxlen
+ *   value the attribute will be rejected.
+ *
+ *
+ * @par Unspecific Attribute (NLA_UNSPEC)
+ * This is the standard type if no type is specified. It is used for
+ * binary data of arbitary length. Typically this attribute carries
+ * a binary structure or a stream of bytes.
+ * @par
+ * @code
+ * // In this example, we will assume a binary structure requires to
+ * // be transmitted. The definition of the structure will typically
+ * // go into a header file available to both the kernel and userspace
+ * // side.
+ * //
+ * // Note: Be careful when putting 64 bit data types into a structure.
+ * // The attribute payload is only aligned to 4 bytes, dereferencing
+ * // the member may fail.
+ * struct my_struct {
+ *     int a;
+ *     int b;
+ * };
+ *
+ * // The validation function will not enforce an exact length match to
+ * // allow structures to grow as required. Note: While it is allowed
+ * // to add members to the end of the structure, changing the order or
+ * // inserting members in the middle of the structure will break your
+ * // binary interface.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_MY_STRICT] = { .type = NLA_UNSPEC,
+ *                          .minlen = sizeof(struct my_struct) },
+ *
+ * // The binary structure is appened to the message using nla_put()
+ * struct my_struct foo = { .a = 1, .b = 2 };
+ * nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo);
+ *
+ * // On the receiving side, a pointer to the structure pointing inside
+ * // the message payload is returned by nla_get().
+ * if (attrs[ATTR_MY_STRUCT])
+ *     struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]);
+ * @endcode
+ *
+ * @par Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64)
+ * Integers come in different sizes from 8 bit to 64 bit. However, since the
+ * payload length is aligned to 4 bytes, integers smaller than 32 bit are
+ * only useful to enforce the maximum range of values.
+ * @par
+ * \b Note: There is no difference made between signed and unsigned integers.
+ * The validation only enforces the minimal payload length required to store
+ * an integer of specified type.
+ * @par
+ * @code
+ * // Even though possible, it does not make sense to specify .minlen or
+ * // .maxlen for integer types. The data types implies the corresponding
+ * // minimal payload length.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_FOO] = { .type = NLA_U32 },
+ *
+ * // Numeric values can be appended directly using the respective
+ * // nla_put_uxxx() function
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ *
+ * // Same for the receiving side.
+ * if (attrs[ATTR_FOO])
+ *     uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
+ * @endcode
+ *
+ * @par Character string (NLA_STRING)
+ * This data type represents a NUL terminated character string of variable
+ * length. For binary data streams the type NLA_UNSPEC is recommended.
+ * @par
+ * @code
+ * // Enforce a NUL terminated character string of at most 4 characters
+ * // including the NUL termination.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 },
+ *
+ * // nla_put_string() creates a string attribute of the necessary length
+ * // and appends it to the message including the NUL termination.
+ * nla_put_string(msg, ATTR_BAR, "some text");
+ *
+ * // It is safe to use the returned character string directly if the
+ * // attribute has been validated as the validation enforces the proper
+ * // termination of the string.
+ * if (attrs[ATTR_BAR])
+ *     char *text = nla_get_string(attrs[ATTR_BAR]);
+ * @endcode
+ *
+ * @par Flag (NLA_FLAG)
+ * This attribute type may be used to indicate the presence of a flag. The
+ * attribute is only valid if the payload length is zero. The presence of
+ * the attribute header indicates the presence of the flag.
+ * @par
+ * @code
+ * // This attribute type is special as .minlen and .maxlen have no effect.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_FLAG] = { .type = NLA_FLAG },
+ *
+ * // nla_put_flag() appends a zero sized attribute to the message.
+ * nla_put_flag(msg, ATTR_FLAG);
+ *
+ * // There is no need for a receival function, the presence is the value.
+ * if (attrs[ATTR_FLAG])
+ *     // flag is present
+ * @endcode
+ *
+ * @par Micro Seconds (NLA_MSECS)
+ *
+ * @par Nested Attribute (NLA_NESTED)
+ * Attributes can be nested and put into a container to create groups, lists
+ * or to construct trees of attributes. Nested attributes are often used to
+ * pass attributes to a subsystem where the top layer has no knowledge of the
+ * configuration possibilities of each subsystem.
+ * @par
+ * \b Note: When validating the attributes using nlmsg_validate() or
+ * nlmsg_parse() it will only affect the top level attributes. Each
+ * level of nested attributes must be validated seperately using
+ * nla_parse_nested() or nla_validate().
+ * @par
+ * @code
+ * // The minimal length policy may be used to enforce the presence of at
+ * // least one attribute.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN },
+ *
+ * // Nested attributes are constructed by enclosing the attributes
+ * // to be nested with calls to nla_nest_start() respetively nla_nest_end().
+ * struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS);
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ * nla_put_string(msg, ATTR_BAR, "some text");
+ * nla_nest_end(msg, opts);
+ *
+ * // Various methods exist to parse nested attributes, the easiest being
+ * // nla_parse_nested() which also allows validation in the same step.
+ * if (attrs[ATTR_OPTS]) {
+ *     struct nlattr *nested[ATTR_MAX+1];
+ *
+ *     nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy);
+ *
+ *     if (nested[ATTR_FOO])
+ *         uint32_t foo = nla_get_u32(nested[ATTR_FOO]);
+ * }
+ * @endcode
+ *
+ * @subsection attr_exceptions Exception Based Attribute Construction
+ * Often a large number of attributes are added to a message in a single
+ * function. In order to simplify error handling, a second set of
+ * construction functions exist which jump to a error label when they
+ * fail instead of returning an error code. This second set consists
+ * of macros which are named after their error code based counterpart
+ * except that the name is written all uppercase.
+ *
+ * All of the macros jump to the target \c nla_put_failure if they fail.
+ * @code
+ * void my_func(struct nl_msg *msg)
+ * {
+ *     NLA_PUT_U32(msg, ATTR_FOO, 10);
+ *     NLA_PUT_STRING(msg, ATTR_BAR, "bar");
+ *
+ *     return 0;
+ *
+ * nla_put_failure:
+ *     return -NLE_NOMEM;
+ * }
+ * @endcode
+ *
+ * @subsection attr_examples Examples
+ * @par Example 1.1 Constructing a netlink message with attributes.
+ * @code
+ * struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu)
+ * {
+ *     struct nl_msg *msg;
+ *     struct nlattr *info, *vlan;
+ *     struct ifinfomsg ifi = {
+ *         .ifi_family = AF_INET,
+ *         .ifi_index = ifindex,
+ *     };
+ *
+ *     // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO
+ *     if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO)))
+ *         return NULL;
+ *
+ *     // Append the family specific header (struct ifinfomsg)
+ *     if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+ *         goto nla_put_failure
+ *
+ *     // Append a 32 bit integer attribute to carry the MTU
+ *     NLA_PUT_U32(msg, IFLA_MTU, mtu);
+ *
+ *     // Append a unspecific attribute to carry the link layer address
+ *     NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr);
+ *
+ *     // Append a container for nested attributes to carry link information
+ *     if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
+ *         goto nla_put_failure;
+ *
+ *     // Put a string attribute into the container
+ *     NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan");
+ *
+ *     // Append another container inside the open container to carry
+ *     // vlan specific attributes
+ *     if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA)))
+ *         goto nla_put_failure;
+ *
+ *     // add vlan specific info attributes here...
+ *
+ *     // Finish nesting the vlan attributes and close the second container.
+ *     nla_nest_end(msg, vlan);
+ *
+ *     // Finish nesting the link info attribute and close the first container.
+ *     nla_nest_end(msg, info);
+ *
+ *     return msg;
+ *
+ * // If any of the construction macros fails, we end up here.
+ * nla_put_failure:
+ *     nlmsg_free(msg);
+ *     return NULL;
+ * }
+ * @endcode
+ *
+ * @par Example 2.1 Parsing a netlink message with attributes.
+ * @code
+ * int parse_message(struct nl_msg *msg)
+ * {
+ *     // The policy defines two attributes: a 32 bit integer and a container
+ *     // for nested attributes.
+ *     struct nla_policy attr_policy[ATTR_MAX+1] = {
+ *         [ATTR_FOO] = { .type = NLA_U32 },
+ *         [ATTR_BAR] = { .type = NLA_NESTED },
+ *     };
+ *     struct nlattr *attrs[ATTR_MAX+1];
+ *     int err;
+ *
+ *     // The nlmsg_parse() function will make sure that the message contains
+ *     // enough payload to hold the header (struct my_hdr), validates any
+ *     // attributes attached to the messages and stores a pointer to each
+ *     // attribute in the attrs[] array accessable by attribute type.
+ *     if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
+ *                            ATTR_MAX, attr_policy)) < 0)
+ *         goto errout;
+ *
+ *     if (attrs[ATTR_FOO]) {
+ *         // It is safe to directly access the attribute payload without
+ *         // any further checks since nlmsg_parse() enforced the policy.
+ *         uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
+ *     }
+ *
+ *     if (attrs[ATTR_BAR]) {
+ *         struct nlattr *nested[NESTED_MAX+1];
+ *
+ *         // Attributes nested in a container can be parsed the same way
+ *         // as top level attributes.
+ *         if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR],
+ *                                     nested_policy)) < 0)
+ *             goto errout;
+ *
+ *         // Process nested attributes here.
+ *     }
+ *
+ *     err = 0;
+ * errout:
+ *     return err;
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * @name Attribute Size Calculation
+ * @{
+ */
+
+/**
+ * Return size of attribute whithout padding.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *    <-------- nla_attr_size(payload) --------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes without padding.
+ */
+int nla_attr_size(int payload)
+{
+	return NLA_HDRLEN + payload;
+}
+
+/**
+ * Return size of attribute including padding.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *    <----------- nla_total_size(payload) ----------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes.
+ */
+int nla_total_size(int payload)
+{
+	return NLA_ALIGN(nla_attr_size(payload));
+}
+
+/**
+ * Return length of padding at the tail of the attribute.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *                                                <--->  
+ * @endcode
+ *
+ * @return Length of padding in bytes.
+ */
+int nla_padlen(int payload)
+{
+	return nla_total_size(payload) - nla_attr_size(payload);
+}
+
+/** @} */
+
+/**
+ * @name Parsing Attributes
+ * @{
+ */
+
+/**
+ * Return type of the attribute.
+ * @arg nla		Attribute.
+ *
+ * @return Type of attribute.
+ */
+int nla_type(const struct nlattr *nla)
+{
+	return nla->nla_type & NLA_TYPE_MASK;
+}
+
+/**
+ * Return pointer to the payload section.
+ * @arg nla		Attribute.
+ *
+ * @return Pointer to start of payload section.
+ */
+void *nla_data(const struct nlattr *nla)
+{
+	return (char *) nla + NLA_HDRLEN;
+}
+
+/**
+ * Return length of the payload .
+ * @arg nla		Attribute
+ *
+ * @return Length of payload in bytes.
+ */
+int nla_len(const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
+
+/**
+ * Check if the attribute header and payload can be accessed safely.
+ * @arg nla		Attribute of any kind.
+ * @arg remaining	Number of bytes remaining in attribute stream.
+ *
+ * Verifies that the header and payload do not exceed the number of
+ * bytes left in the attribute stream. This function must be called
+ * before access the attribute header or payload when iterating over
+ * the attribute stream using nla_next().
+ *
+ * @return True if the attribute can be accessed safely, false otherwise.
+ */
+int nla_ok(const struct nlattr *nla, int remaining)
+{
+	return remaining >= sizeof(*nla) &&
+	       nla->nla_len >= sizeof(*nla) &&
+	       nla->nla_len <= remaining;
+}
+
+/**
+ * Return next attribute in a stream of attributes.
+ * @arg nla		Attribute of any kind.
+ * @arg remaining	Variable to count remaining bytes in stream.
+ *
+ * Calculates the offset to the next attribute based on the attribute
+ * given. The attribute provided is assumed to be accessible, the
+ * caller is responsible to use nla_ok() beforehand. The offset (length
+ * of specified attribute including padding) is then subtracted from
+ * the remaining bytes variable and a pointer to the next attribute is
+ * returned.
+ *
+ * nla_next() can be called as long as remainig is >0.
+ *
+ * @return Pointer to next attribute.
+ */
+struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+	int totlen = NLA_ALIGN(nla->nla_len);
+
+	*remaining -= totlen;
+	return (struct nlattr *) ((char *) nla + totlen);
+}
+
+static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
+	[NLA_U8]	= sizeof(uint8_t),
+	[NLA_U16]	= sizeof(uint16_t),
+	[NLA_U32]	= sizeof(uint32_t),
+	[NLA_U64]	= sizeof(uint64_t),
+	[NLA_STRING]	= 1,
+};
+
+static int validate_nla(struct nlattr *nla, int maxtype,
+			struct nla_policy *policy)
+{
+	struct nla_policy *pt;
+	int minlen = 0, type = nla_type(nla);
+
+	if (type <= 0 || type > maxtype)
+		return 0;
+
+	pt = &policy[type];
+
+	if (pt->type > NLA_TYPE_MAX)
+		BUG();
+
+	if (pt->minlen)
+		minlen = pt->minlen;
+	else if (pt->type != NLA_UNSPEC)
+		minlen = nla_attr_minlen[pt->type];
+
+	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
+		return -NLE_RANGE;
+
+	if (nla_len(nla) < minlen)
+		return -NLE_RANGE;
+
+	if (pt->maxlen && nla_len(nla) > pt->maxlen)
+		return -NLE_RANGE;
+
+	if (pt->type == NLA_STRING) {
+		char *data = nla_data(nla);
+		if (data[nla_len(nla) - 1] != '\0')
+			return -NLE_INVAL;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Create attribute index based on a stream of attributes.
+ * @arg tb		Index array to be filled (maxtype+1 elements).
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg head		Head of attribute stream.
+ * @arg len		Length of attribute stream.
+ * @arg policy		Attribute validation policy.
+ *
+ * Iterates over the stream of attributes and stores a pointer to each
+ * attribute in the index array using the attribute type as index to
+ * the array. Attribute with a type greater than the maximum type
+ * specified will be silently ignored in order to maintain backwards
+ * compatibility. If \a policy is not NULL, the attribute will be
+ * validated using the specified policy.
+ *
+ * @see nla_validate
+ * @return 0 on success or a negative error code.
+ */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+	      struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+	nla_for_each_attr(nla, head, len, rem) {
+		int type = nla_type(nla);
+
+		if (type == 0) {
+			fprintf(stderr, "Illegal nla->nla_type == 0\n");
+			continue;
+		}
+
+		if (type <= maxtype) {
+			if (policy) {
+				err = validate_nla(nla, maxtype, policy);
+				if (err < 0)
+					goto errout;
+			}
+
+			tb[type] = nla;
+		}
+	}
+
+	if (rem > 0)
+		fprintf(stderr, "netlink: %d bytes leftover after parsing "
+		       "attributes.\n", rem);
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * Validate a stream of attributes.
+ * @arg head		Head of attributes stream.
+ * @arg len		Length of attributes stream.
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg policy		Validation policy.
+ *
+ * Iterates over the stream of attributes and validates each attribute
+ * one by one using the specified policy. Attributes with a type greater
+ * than the maximum type specified will be silently ignored in order to
+ * maintain backwards compatibility.
+ *
+ * See \ref attr_datatypes for more details on what kind of validation
+ * checks are performed on each attribute data type.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nla_validate(struct nlattr *head, int len, int maxtype,
+		 struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	nla_for_each_attr(nla, head, len, rem) {
+		err = validate_nla(nla, maxtype, policy);
+		if (err < 0)
+			goto errout;
+	}
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * Find a single attribute in a stream of attributes.
+ * @arg head		Head of attributes stream.
+ * @arg len		Length of attributes stream.
+ * @arg attrtype	Attribute type to look for.
+ *
+ * Iterates over the stream of attributes and compares each type with
+ * the type specified. Returns the first attribute which matches the
+ * type.
+ *
+ * @return Pointer to attribute found or NULL.
+ */
+struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
+{
+	struct nlattr *nla;
+	int rem;
+
+	nla_for_each_attr(nla, head, len, rem)
+		if (nla_type(nla) == attrtype)
+			return nla;
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Helper Functions
+ * @{
+ */
+
+/**
+ * Copy attribute payload to another memory area.
+ * @arg dest		Pointer to destination memory area.
+ * @arg src		Attribute
+ * @arg count		Number of bytes to copy at most.
+ *
+ * Note: The number of bytes copied is limited by the length of
+ *       the attribute payload.
+ *
+ * @return The number of bytes copied to dest.
+ */
+int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+	int minlen;
+
+	if (!src)
+		return 0;
+	
+	minlen = min_t(int, count, nla_len(src));
+	memcpy(dest, nla_data(src), minlen);
+
+	return minlen;
+}
+
+/**
+ * Copy string attribute payload to a buffer.
+ * @arg dst		Pointer to destination buffer.
+ * @arg nla		Attribute of type NLA_STRING.
+ * @arg dstsize		Size of destination buffer in bytes.
+ *
+ * Copies at most dstsize - 1 bytes to the destination buffer.
+ * The result is always a valid NUL terminated string. Unlike
+ * strlcpy the destination buffer is always padded out.
+ *
+ * @return The length of string attribute without the terminating NUL.
+ */
+size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
+{
+	size_t srclen = nla_len(nla);
+	char *src = nla_data(nla);
+
+	if (srclen > 0 && src[srclen - 1] == '\0')
+		srclen--;
+
+	if (dstsize > 0) {
+		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
+
+		memset(dst, 0, dstsize);
+		memcpy(dst, src, len);
+	}
+
+	return srclen;
+}
+
+/**
+ * Compare attribute payload with memory area.
+ * @arg nla		Attribute.
+ * @arg data		Memory area to compare to.
+ * @arg size		Number of bytes to compare.
+ *
+ * @see memcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+int nla_memcmp(const struct nlattr *nla, const void *data, size_t size)
+{
+	int d = nla_len(nla) - size;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), data, size);
+
+	return d;
+}
+
+/**
+ * Compare string attribute payload with string
+ * @arg nla		Attribute of type NLA_STRING.
+ * @arg str		NUL terminated string.
+ *
+ * @see strcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+int nla_strcmp(const struct nlattr *nla, const char *str)
+{
+	int len = strlen(str) + 1;
+	int d = nla_len(nla) - len;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), str, len);
+
+	return d;
+}
+
+/** @} */
+
+/**
+ * @name Unspecific Attribute
+ * @{
+ */
+
+/**
+ * Reserve space for a attribute.
+ * @arg msg		Netlink Message.
+ * @arg attrtype	Attribute Type.
+ * @arg attrlen		Length of payload.
+ *
+ * Reserves room for a attribute in the specified netlink message and
+ * fills in the attribute header (type, length). Returns NULL if there
+ * is unsuficient space for the attribute.
+ *
+ * Any padding between payload and the start of the next attribute is
+ * zeroed out.
+ *
+ * @return Pointer to start of attribute or NULL on failure.
+ */
+struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
+{
+	struct nlattr *nla;
+	int tlen;
+	
+	tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
+
+	if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size)
+		return NULL;
+
+	nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+	nla->nla_type = attrtype;
+	nla->nla_len = nla_attr_size(attrlen);
+
+	if (attrlen)
+		memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+	msg->nm_nlh->nlmsg_len = tlen;
+
+	NL_DBG(2, "msg %p: attr <%p> %d: Reserved %d (%d) bytes at offset +%td "
+		  "nlmsg_len=%d\n", msg, nla, nla->nla_type,
+		  nla_total_size(attrlen), attrlen,
+		  (void *) nla - nlmsg_data(msg->nm_nlh),
+		  msg->nm_nlh->nlmsg_len);
+
+	return nla;
+}
+
+/**
+ * Add a unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg datalen		Length of data to be used as payload.
+ * @arg data		Pointer to data to be used as attribute payload.
+ *
+ * Reserves room for a unspecific attribute and copies the provided data
+ * into the message as payload of the attribute. Returns an error if there
+ * is insufficient space for the attribute.
+ *
+ * @see nla_reserve
+ * @return 0 on success or a negative error code.
+ */
+int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
+{
+	struct nlattr *nla;
+
+	nla = nla_reserve(msg, attrtype, datalen);
+	if (!nla)
+		return -NLE_NOMEM;
+
+	if (datalen > 0) {
+		memcpy(nla_data(nla), data, datalen);
+		NL_DBG(2, "msg %p: attr <%p> %d: Wrote %d bytes at offset +%td\n",
+		       msg, nla, nla->nla_type, datalen,
+		       (void *) nla - nlmsg_data(msg->nm_nlh));
+	}
+
+	return 0;
+}
+
+/**
+ * Add abstract data as unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg data		Abstract data object.
+ *
+ * Equivalent to nla_put() except that the length of the payload is
+ * derived from the abstract data object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data)
+{
+	return nla_put(msg, attrtype, nl_data_get_size(data),
+		       nl_data_get(data));
+}
+
+/**
+ * Add abstract address as unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg addr		Abstract address object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr)
+{
+	return nla_put(msg, attrtype, nl_addr_get_len(addr),
+		       nl_addr_get_binary_addr(addr));
+}
+
+/** @} */
+
+/**
+ * @name Integer Attributes
+ */
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/**
+ * Return value of 8 bit integer attribute.
+ * @arg nla		8 bit integer attribute
+ *
+ * @return Payload as 8 bit integer.
+ */
+uint8_t nla_get_u8(struct nlattr *nla)
+{
+	return *(uint8_t *) nla_data(nla);
+}
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/**
+ * Return payload of 16 bit integer attribute.
+ * @arg nla		16 bit integer attribute
+ *
+ * @return Payload as 16 bit integer.
+ */
+uint16_t nla_get_u16(struct nlattr *nla)
+{
+	return *(uint16_t *) nla_data(nla);
+}
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/**
+ * Return payload of 32 bit integer attribute.
+ * @arg nla		32 bit integer attribute.
+ *
+ * @return Payload as 32 bit integer.
+ */
+uint32_t nla_get_u32(struct nlattr *nla)
+{
+	return *(uint32_t *) nla_data(nla);
+}
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
+
+/**
+ * Return payload of u64 attribute
+ * @arg nla		u64 netlink attribute
+ *
+ * @return Payload as 64 bit integer.
+ */
+uint64_t nla_get_u64(struct nlattr *nla)
+{
+	uint64_t tmp;
+
+	nla_memcpy(&tmp, nla, sizeof(tmp));
+
+	return tmp;
+}
+
+/** @} */
+
+/**
+ * @name String Attribute
+ */
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg str		NUL terminated string.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
+{
+	return nla_put(msg, attrtype, strlen(str) + 1, str);
+}
+
+/**
+ * Return payload of string attribute.
+ * @arg nla		String attribute.
+ *
+ * @return Pointer to attribute payload.
+ */
+char *nla_get_string(struct nlattr *nla)
+{
+	return (char *) nla_data(nla);
+}
+
+char *nla_strdup(struct nlattr *nla)
+{
+	return strdup(nla_get_string(nla));
+}
+
+/** @} */
+
+/**
+ * @name Flag Attribute
+ */
+
+/**
+ * Add flag netlink attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_flag(struct nl_msg *msg, int attrtype)
+{
+	return nla_put(msg, attrtype, 0, NULL);
+}
+
+/**
+ * Return true if flag attribute is set.
+ * @arg nla		Flag netlink attribute.
+ *
+ * @return True if flag is set, otherwise false.
+ */
+int nla_get_flag(struct nlattr *nla)
+{
+	return !!nla;
+}
+
+/** @} */
+
+/**
+ * @name Microseconds Attribute
+ */
+
+/**
+ * Add a msecs netlink attribute to a netlink message
+ * @arg n		netlink message
+ * @arg attrtype	attribute type
+ * @arg msecs 		number of msecs
+ */
+int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
+{
+	return nla_put_u64(n, attrtype, msecs);
+}
+
+/**
+ * Return payload of msecs attribute
+ * @arg nla		msecs netlink attribute
+ *
+ * @return the number of milliseconds.
+ */
+unsigned long nla_get_msecs(struct nlattr *nla)
+{
+	return nla_get_u64(nla);
+}
+
+/** @} */
+
+/**
+ * @name Nested Attribute
+ */
+
+/**
+ * Add nested attributes to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg nested		Message containing attributes to be nested.
+ *
+ * Takes the attributes found in the \a nested message and appends them
+ * to the message \a msg nested in a container of the type \a attrtype.
+ * The \a nested message may not have a family specific header.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+{
+	NL_DBG(2, "msg %p: attr <> %d: adding msg %p as nested attribute\n",
+		msg, attrtype, nested);
+
+	return nla_put(msg, attrtype, nlmsg_datalen(nested->nm_nlh),
+		       nlmsg_data(nested->nm_nlh));
+}
+
+
+/**
+ * Start a new level of nested attributes.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type of container.
+ *
+ * @return Pointer to container attribute.
+ */
+struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
+{
+	struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+
+	if (nla_put(msg, attrtype, 0, NULL) < 0)
+		return NULL;
+
+	NL_DBG(2, "msg %p: attr <%p> %d: starting nesting\n",
+		msg, start, start->nla_type);
+
+	return start;
+}
+
+/**
+ * Finalize nesting of attributes.
+ * @arg msg		Netlink message.
+ * @arg start		Container attribute as returned from nla_nest_start().
+ *
+ * Corrects the container attribute header to include the appeneded attributes.
+ *
+ * @return 0
+ */
+int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+	size_t pad, len;
+
+	len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start;
+
+	if (len == NLA_HDRLEN) {
+		/*
+		 * Kernel can't handle empty nested attributes, trim the
+		 * attribute header again
+		 */
+		msg->nm_nlh->nlmsg_len -= NLA_HDRLEN;
+		memset(nlmsg_tail(msg->nm_nlh), 0, NLA_HDRLEN);
+
+		return 0;
+	}
+
+	start->nla_len = len;
+
+	pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
+	if (pad > 0) {
+		/*
+		 * Data inside attribute does not end at a alignment boundry.
+		 * Pad accordingly and accoun for the additional space in
+		 * the message. nlmsg_reserve() may never fail in this situation,
+		 * the allocate message buffer must be a multiple of NLMSG_ALIGNTO.
+		 */
+		if (!nlmsg_reserve(msg, pad, 0))
+			BUG();
+
+		NL_DBG(2, "msg %p: attr <%p> %d: added %zu bytes of padding\n",
+			msg, start, start->nla_type, pad);
+	}
+
+	NL_DBG(2, "msg %p: attr <%p> %d: closing nesting, len=%u\n",
+		msg, start, start->nla_type, start->nla_len);
+
+	return 0;
+}
+
+/**
+ * Create attribute index based on nested attribute
+ * @arg tb		Index array to be filled (maxtype+1 elements).
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg nla		Nested Attribute.
+ * @arg policy		Attribute validation policy.
+ *
+ * Feeds the stream of attributes nested into the specified attribute
+ * to nla_parse().
+ *
+ * @see nla_parse
+ * @return 0 on success or a negative error code.
+ */
+int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
+		     struct nla_policy *policy)
+{
+	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/cache.c b/libnetwork/libnl3/lib/cache.c
new file mode 100644
index 0000000..a1c8eae
--- /dev/null
+++ b/libnetwork/libnl3/lib/cache.c
@@ -0,0 +1,965 @@
+/*
+ * lib/cache.c		Caching Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cache_mngt
+ * @defgroup cache Cache
+ *
+ * @code
+ *   Cache Management             |    | Type Specific Cache Operations
+ *                                      
+ *                                |    | +----------------+ +------------+
+ *                                       | request update | | msg_parser |
+ *                                |    | +----------------+ +------------+
+ *                                     +- - - - -^- - - - - - - -^- -|- - - -
+ *    nl_cache_update:            |              |               |   |
+ *          1) --------- co_request_update ------+               |   |
+ *                                |                              |   |
+ *          2) destroy old cache     +----------- pp_cb ---------|---+
+ *                                |  |                           |
+ *          3) ---------- nl_recvmsgs ----------+   +- cb_valid -+
+ *             +--------------+   |  |          |   |
+ *             | nl_cache_add |<-----+   + - - -v- -|- - - - - - - - - - -
+ *             +--------------+   |      | +-------------+
+ *                                         | nl_recvmsgs |
+ *                                |      | +-----|-^-----+
+ *                                           +---v-|---+
+ *                                |      |   | nl_recv |
+ *                                           +---------+
+ *                                |      |                 Core Netlink
+ * @endcode
+ * 
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Access Functions
+ * @{
+ */
+
+/**
+ * Return the number of items in the cache
+ * @arg cache		cache handle
+ */
+int nl_cache_nitems(struct nl_cache *cache)
+{
+	return cache->c_nitems;
+}
+
+/**
+ * Return the number of items matching a filter in the cache
+ * @arg cache		Cache object.
+ * @arg filter		Filter object.
+ */
+int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
+{
+	struct nl_object *obj;
+	int nitems = 0;
+
+	if (cache->c_ops == NULL)
+		BUG();
+
+	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+		if (filter && !nl_object_match_filter(obj, filter))
+			continue;
+
+		nitems++;
+	}
+
+	return nitems;
+}
+
+/**
+ * Returns \b true if the cache is empty.
+ * @arg cache		Cache to check
+ * @return \a true if the cache is empty, otherwise \b false is returned.
+ */
+int nl_cache_is_empty(struct nl_cache *cache)
+{
+	return nl_list_empty(&cache->c_items);
+}
+
+/**
+ * Return the operations set of the cache
+ * @arg cache		cache handle
+ */
+struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
+{
+	return cache->c_ops;
+}
+
+/**
+ * Return the first element in the cache
+ * @arg cache		cache handle
+ */
+struct nl_object *nl_cache_get_first(struct nl_cache *cache)
+{
+	if (nl_list_empty(&cache->c_items))
+		return NULL;
+
+	return nl_list_entry(cache->c_items.next,
+			     struct nl_object, ce_list);
+}
+
+/**
+ * Return the last element in the cache
+ * @arg cache		cache handle
+ */
+struct nl_object *nl_cache_get_last(struct nl_cache *cache)
+{
+	if (nl_list_empty(&cache->c_items))
+		return NULL;
+
+	return nl_list_entry(cache->c_items.prev,
+			     struct nl_object, ce_list);
+}
+
+/**
+ * Return the next element in the cache
+ * @arg obj		current object
+ */
+struct nl_object *nl_cache_get_next(struct nl_object *obj)
+{
+	if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
+		return NULL;
+	else
+		return nl_list_entry(obj->ce_list.next,
+				     struct nl_object, ce_list);
+}
+
+/**
+ * Return the previous element in the cache
+ * @arg obj		current object
+ */
+struct nl_object *nl_cache_get_prev(struct nl_object *obj)
+{
+	if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
+		return NULL;
+	else
+		return nl_list_entry(obj->ce_list.prev,
+				     struct nl_object, ce_list);
+}
+
+/** @} */
+
+/**
+ * @name Cache Allocation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate new cache
+ * @arg ops		Cache operations
+ *
+ * Allocate and initialize a new cache based on the cache operations
+ * provided.
+ *
+ * @return Allocated cache or NULL if allocation failed.
+ */
+struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
+{
+	struct nl_cache *cache;
+
+	cache = calloc(1, sizeof(*cache));
+	if (!cache)
+		return NULL;
+
+	nl_init_list_head(&cache->c_items);
+	cache->c_ops = ops;
+
+	NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
+
+	return cache;
+}
+
+/**
+ * Allocate new cache and fill it
+ * @arg ops		Cache operations
+ * @arg sock		Netlink socket
+ * @arg result		Result pointer
+ *
+ * Allocate new cache and fill it. Equivalent to calling:
+ * @code
+ * cache = nl_cache_alloc(ops);
+ * nl_cache_refill(sock, cache);
+ * @endcode
+ *
+ * @see nl_cache_alloc
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
+			    struct nl_cache **result)
+{
+	struct nl_cache *cache;
+	int err;
+	
+	if (!(cache = nl_cache_alloc(ops)))
+		return -NLE_NOMEM;
+
+	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/**
+ * Allocate new cache based on type name
+ * @arg kind		Name of cache type
+ * @arg result		Result pointer
+ *
+ * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache
+ * by calling nl_cache_alloc(). Stores the allocated cache in the
+ * result pointer provided.
+ *
+ * @see nl_cache_alloc
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_alloc_name(const char *kind, struct nl_cache **result)
+{
+	struct nl_cache_ops *ops;
+	struct nl_cache *cache;
+
+	ops = nl_cache_ops_lookup(kind);
+	if (!ops)
+		return -NLE_NOCACHE;
+
+	if (!(cache = nl_cache_alloc(ops)))
+		return -NLE_NOMEM;
+
+	*result = cache;
+	return 0;
+}
+
+/**
+ * Allocate new cache containing a subset of an existing cache
+ * @arg orig		Original cache to base new cache on
+ * @arg filter		Filter defining the subset to be filled into the new cache
+ *
+ * Allocates a new cache matching the type of the cache specified by
+ * \p orig. Iterates over the \p orig cache applying the specified
+ * \p filter and copies all objects that match to the new cache.
+ *
+ * The copied objects are clones but do not contain a reference to each
+ * other. Later modifications to objects in the original cache will
+ * not affect objects in the new cache.
+ *
+ * @return A newly allocated cache or NULL.
+ */
+struct nl_cache *nl_cache_subset(struct nl_cache *orig,
+				 struct nl_object *filter)
+{
+	struct nl_cache *cache;
+	struct nl_object *obj;
+
+	if (!filter)
+		BUG();
+
+	cache = nl_cache_alloc(orig->c_ops);
+	if (!cache)
+		return NULL;
+
+	nl_list_for_each_entry(obj, &orig->c_items, ce_list) {
+		if (!nl_object_match_filter(obj, filter))
+			continue;
+
+		nl_cache_add(cache, obj);
+	}
+
+	return cache;
+}
+
+/**
+ * Remove all objects of a cache.
+ * @arg cache		Cache to clear
+ *
+ * The objects are unliked/removed from the cache by calling
+ * nl_cache_remove() on each object in the cache. If any of the objects
+ * to not contain any further references to them, those objects will
+ * be freed.
+ *
+ * Unlike with nl_cache_free(), the cache is not freed just emptied.
+ */
+void nl_cache_clear(struct nl_cache *cache)
+{
+	struct nl_object *obj, *tmp;
+
+	NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
+
+	nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
+		nl_cache_remove(obj);
+}
+
+/**
+ * Free a cache.
+ * @arg cache		Cache to free.
+ *
+ * Calls nl_cache_clear() to remove all objects associated with the
+ * cache and frees the cache afterwards.
+ *
+ * @see nl_cache_clear()
+ */
+void nl_cache_free(struct nl_cache *cache)
+{
+	if (!cache)
+		return;
+
+	nl_cache_clear(cache);
+	NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
+	free(cache);
+}
+
+/** @} */
+
+/**
+ * @name Cache Modifications
+ * @{
+ */
+
+static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+	obj->ce_cache = cache;
+
+	nl_list_add_tail(&obj->ce_list, &cache->c_items);
+	cache->c_nitems++;
+
+	NL_DBG(1, "Added %p to cache %p <%s>.\n",
+	       obj, cache, nl_cache_name(cache));
+
+	return 0;
+}
+
+/**
+ * Add object to cache.
+ * @arg cache		Cache
+ * @arg obj		Object to be added to the cache
+ *
+ * Adds the object \p obj to the specified \p cache. In case the object
+ * is already associated with another cache, the object is cloned before
+ * adding it to the cache. In this case, the sole reference to the object
+ * will be the one of the cache. Therefore clearing/freeing the cache
+ * will result in the object being freed again.
+ *
+ * If the object has not been associated with a cache yet, the reference
+ * counter of the object is incremented to account for the additional
+ * reference.
+ *
+ * The type of the object and cache must match, otherwise an error is
+ * returned (-NLE_OBJ_MISMATCH).
+ *
+ * @see nl_cache_move()
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+	struct nl_object *new;
+
+	if (cache->c_ops->co_obj_ops != obj->ce_ops)
+		return -NLE_OBJ_MISMATCH;
+
+	if (!nl_list_empty(&obj->ce_list)) {
+		new = nl_object_clone(obj);
+		if (!new)
+			return -NLE_NOMEM;
+	} else {
+		nl_object_get(obj);
+		new = obj;
+	}
+
+	return __cache_add(cache, new);
+}
+
+/**
+ * Move object from one cache to another
+ * @arg cache		Cache to move object to.
+ * @arg obj		Object subject to be moved
+ *
+ * Removes the the specified object \p obj from its associated cache
+ * and moves it to another cache.
+ *
+ * If the object is not associated with a cache, the function behaves
+ * just like nl_cache_add().
+ *
+ * The type of the object and cache must match, otherwise an error is
+ * returned (-NLE_OBJ_MISMATCH).
+ *
+ * @see nl_cache_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
+{
+	if (cache->c_ops->co_obj_ops != obj->ce_ops)
+		return -NLE_OBJ_MISMATCH;
+
+	NL_DBG(3, "Moving object %p to cache %p\n", obj, cache);
+	
+	/* Acquire reference, if already in a cache this will be
+	 * reverted during removal */
+	nl_object_get(obj);
+
+	if (!nl_list_empty(&obj->ce_list))
+		nl_cache_remove(obj);
+
+	return __cache_add(cache, obj);
+}
+
+/**
+ * Remove object from cache.
+ * @arg obj		Object to remove from cache
+ *
+ * Removes the object \c obj from the cache it is associated with. The
+ * reference counter of the object will be decremented. If the reference
+ * to the object was the only one remaining, the object will be freed.
+ *
+ * If no cache is associated with the object, this function is a NOP.
+ */
+void nl_cache_remove(struct nl_object *obj)
+{
+	struct nl_cache *cache = obj->ce_cache;
+
+	if (cache == NULL)
+		return;
+
+	nl_list_del(&obj->ce_list);
+	obj->ce_cache = NULL;
+	nl_object_put(obj);
+	cache->c_nitems--;
+
+	NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
+	       obj, cache, nl_cache_name(cache));
+}
+
+/** @} */
+
+/**
+ * @name Synchronization
+ * @{
+ */
+
+/**
+ * Set synchronization arg1 of cache
+ * @arg cache		Cache
+ * @arg arg		argument
+ *
+ * Synchronization arguments are used to specify filters when
+ * requesting dumps from the kernel.
+ */
+void nl_cache_set_arg1(struct nl_cache *cache, int arg)
+{
+        cache->c_iarg1 = arg;
+}
+
+/**
+ * Set synchronization arg2 of cache
+ * @arg cache		Cache
+ * @arg arg		argument
+ *
+ * Synchronization arguments are used to specify filters when
+ * requesting dumps from the kernel.
+ */
+void nl_cache_set_arg2(struct nl_cache *cache, int arg)
+{
+        cache->c_iarg2 = arg;
+}
+
+/**
+ * Invoke the request-update operation
+ * @arg sk		Netlink socket.
+ * @arg cache		Cache
+ *
+ * This function causes the \e request-update function of the cache
+ * operations to be invoked. This usually causes a dump request to
+ * be sent over the netlink socket which triggers the kernel to dump
+ * all objects of a specific type to be dumped onto the netlink
+ * socket for pickup.
+ *
+ * The behaviour of this function depends on the implemenation of
+ * the \e request_update function of each individual type of cache.
+ *
+ * This function will not have any effects on the cache (unless the
+ * request_update implementation of the cache operations does so).
+ *
+ * Use nl_cache_pickup() to pick-up (read) the objects from the socket
+ * and fill them into the cache.
+ *
+ * @see nl_cache_pickup(), nl_cache_resync()
+ *
+ * @return 0 on success or a negative error code.
+ */
+static int nl_cache_request_full_dump(struct nl_sock *sk,
+				      struct nl_cache *cache)
+{
+	NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
+	          cache, nl_cache_name(cache));
+
+	if (cache->c_ops->co_request_update == NULL)
+		return -NLE_OPNOTSUPP;
+
+	return cache->c_ops->co_request_update(cache, sk);
+}
+
+/** @cond SKIP */
+struct update_xdata {
+	struct nl_cache_ops *ops;
+	struct nl_parser_param *params;
+};
+
+static int update_msg_parser(struct nl_msg *msg, void *arg)
+{
+	struct update_xdata *x = arg;
+	
+	return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
+}
+/** @endcond */
+
+/**
+ * Pick-up a netlink request-update with your own parser
+ * @arg sk		Netlink socket
+ * @arg cache		Cache
+ * @arg param		Parser parameters
+ */
+static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
+			  struct nl_parser_param *param)
+{
+	int err;
+	struct nl_cb *cb;
+	struct update_xdata x = {
+		.ops = cache->c_ops,
+		.params = param,
+	};
+
+	NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
+		  cache, nl_cache_name(cache));
+
+	cb = nl_cb_clone(sk->s_cb);
+	if (cb == NULL)
+		return -NLE_NOMEM;
+
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
+
+	err = nl_recvmsgs(sk, cb);
+	if (err < 0)
+		NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
+		       "%d: %s", cache, nl_cache_name(cache),
+		       err, nl_geterror(err));
+
+	nl_cb_put(cb);
+
+	return err;
+}
+
+static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+	return nl_cache_add((struct nl_cache *) p->pp_arg, c);
+}
+
+/**
+ * Pickup a netlink dump response and put it into a cache.
+ * @arg sk		Netlink socket.
+ * @arg cache		Cache to put items into.
+ *
+ * Waits for netlink messages to arrive, parses them and puts them into
+ * the specified cache.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
+{
+	struct nl_parser_param p = {
+		.pp_cb = pickup_cb,
+		.pp_arg = cache,
+	};
+
+	return __cache_pickup(sk, cache, &p);
+}
+
+static int cache_include(struct nl_cache *cache, struct nl_object *obj,
+			 struct nl_msgtype *type, change_func_t cb, void *data)
+{
+	struct nl_object *old;
+
+	switch (type->mt_act) {
+	case NL_ACT_NEW:
+	case NL_ACT_DEL:
+		old = nl_cache_search(cache, obj);
+		if (old) {
+			nl_cache_remove(old);
+			if (type->mt_act == NL_ACT_DEL) {
+				if (cb)
+					cb(cache, old, NL_ACT_DEL, data);
+				nl_object_put(old);
+			}
+		}
+
+		if (type->mt_act == NL_ACT_NEW) {
+			nl_cache_move(cache, obj);
+			if (old == NULL && cb)
+				cb(cache, obj, NL_ACT_NEW, data);
+			else if (old) {
+				if (nl_object_diff(old, obj) && cb)
+					cb(cache, obj, NL_ACT_CHANGE, data);
+
+				nl_object_put(old);
+			}
+		}
+		break;
+	default:
+		NL_DBG(2, "Unknown action associated to object %p\n", obj);
+		return 0;
+	}
+
+	return 0;
+}
+
+int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
+		     change_func_t change_cb, void *data)
+{
+	struct nl_cache_ops *ops = cache->c_ops;
+	int i;
+
+	if (ops->co_obj_ops != obj->ce_ops)
+		return -NLE_OBJ_MISMATCH;
+
+	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+		if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
+			return cache_include(cache, obj, &ops->co_msgtypes[i],
+					     change_cb, data);
+
+	return -NLE_MSGTYPE_NOSUPPORT;
+}
+
+static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+	struct nl_cache_assoc *ca = p->pp_arg;
+
+	return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data);
+}
+
+int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
+		    change_func_t change_cb, void *data)
+{
+	struct nl_object *obj, *next;
+	struct nl_cache_assoc ca = {
+		.ca_cache = cache,
+		.ca_change = change_cb,
+		.ca_change_data = data,
+	};
+	struct nl_parser_param p = {
+		.pp_cb = resync_cb,
+		.pp_arg = &ca,
+	};
+	int err;
+
+	NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache));
+
+restart:
+	/* Mark all objects so we can see if some of them are obsolete */
+	nl_cache_mark_all(cache);
+
+	err = nl_cache_request_full_dump(sk, cache);
+	if (err < 0)
+		goto errout;
+
+	err = __cache_pickup(sk, cache, &p);
+	if (err == -NLE_DUMP_INTR)
+		goto restart;
+	else if (err < 0)
+		goto errout;
+
+	nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) {
+		if (nl_object_is_marked(obj)) {
+			nl_object_get(obj);
+			nl_cache_remove(obj);
+			if (change_cb)
+				change_cb(cache, obj, NL_ACT_DEL, data);
+			nl_object_put(obj);
+		}
+	}
+
+	NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache));
+
+	err = 0;
+errout:
+	return err;
+}
+
+/** @} */
+
+/**
+ * @name Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+		   struct nlmsghdr *nlh, struct nl_parser_param *params)
+{
+	int i, err;
+
+	if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
+		return -NLE_MSG_TOOSHORT;
+
+	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
+		if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
+			err = ops->co_msg_parser(ops, who, nlh, params);
+			if (err != -NLE_OPNOTSUPP)
+				goto errout;
+		}
+	}
+
+
+	err = -NLE_MSGTYPE_NOSUPPORT;
+errout:
+	return err;
+}
+/** @endcond */
+
+/**
+ * Parse a netlink message and add it to the cache.
+ * @arg cache		cache to add element to
+ * @arg msg		netlink message
+ *
+ * Parses a netlink message by calling the cache specific message parser
+ * and adds the new element to the cache.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
+{
+	struct nl_parser_param p = {
+		.pp_cb = pickup_cb,
+		.pp_arg = cache,
+	};
+
+	return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/**
+ * (Re)fill a cache with the contents in the kernel.
+ * @arg sk		Netlink socket.
+ * @arg cache		cache to update
+ *
+ * Clears the specified cache and fills it with the current state in
+ * the kernel.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
+{
+	int err;
+
+restart:
+	err = nl_cache_request_full_dump(sk, cache);
+	if (err < 0)
+		return err;
+
+	NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
+	       cache, nl_cache_name(cache));
+	nl_cache_clear(cache);
+
+	err = nl_cache_pickup(sk, cache);
+	if (err == -NLE_DUMP_INTR) {
+		fprintf(stderr, "dump interrupted, restarting!\n");
+		goto restart;
+	}
+	
+	return err;
+}
+
+/** @} */
+
+/**
+ * @name Utillities
+ * @{
+ */
+
+/**
+ * Search object in cache
+ * @arg cache		Cache
+ * @arg needle		Object to look for.
+ *
+ * Searches the cache for an object which matches the object \p needle.
+ * The function nl_object_identical() is used to determine if the
+ * objects match. If a matching object is found, the reference counter
+ * is incremented and the object is returned.
+ * 
+ * Therefore, if an object is returned, the reference to the object
+ * must be returned by calling nl_object_put() after usage.
+ *
+ * @return Reference to object or NULL if not found.
+ */
+struct nl_object *nl_cache_search(struct nl_cache *cache,
+				  struct nl_object *needle)
+{
+	struct nl_object *obj;
+
+	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+		if (nl_object_identical(obj, needle)) {
+			nl_object_get(obj);
+			return obj;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Mark all objects of a cache
+ * @arg cache		Cache
+ *
+ * Marks all objects of a cache by calling nl_object_mark() on each
+ * object associated with the cache.
+ */
+void nl_cache_mark_all(struct nl_cache *cache)
+{
+	struct nl_object *obj;
+
+	NL_DBG(2, "Marking all objects in cache %p <%s>...\n",
+	          cache, nl_cache_name(cache));
+
+	nl_list_for_each_entry(obj, &cache->c_items, ce_list)
+		nl_object_mark(obj);
+}
+
+/** @} */
+
+/**
+ * @name Dumping
+ * @{
+ */
+
+/**
+ * Dump all elements of a cache.
+ * @arg cache		cache to dump
+ * @arg params		dumping parameters
+ *
+ * Dumps all elements of the \a cache to the file descriptor \a fd.
+ */
+void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
+{
+	nl_cache_dump_filter(cache, params, NULL);
+}
+
+/**
+ * Dump all elements of a cache (filtered).
+ * @arg cache		cache to dump
+ * @arg params		dumping parameters (optional)
+ * @arg filter		filter object
+ *
+ * Dumps all elements of the \a cache to the file descriptor \a fd
+ * given they match the given filter \a filter.
+ */
+void nl_cache_dump_filter(struct nl_cache *cache,
+			  struct nl_dump_params *params,
+			  struct nl_object *filter)
+{
+	int type = params ? params->dp_type : NL_DUMP_DETAILS;
+	struct nl_object_ops *ops;
+	struct nl_object *obj;
+
+	NL_DBG(2, "Dumping cache %p <%s> filter %p\n",
+	       cache, nl_cache_name(cache), filter);
+
+	if (type > NL_DUMP_MAX || type < 0)
+		BUG();
+
+	if (cache->c_ops == NULL)
+		BUG();
+
+	ops = cache->c_ops->co_obj_ops;
+	if (!ops->oo_dump[type])
+		return;
+
+	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+		if (filter && !nl_object_match_filter(obj, filter))
+			continue;
+
+		NL_DBG(4, "Dumping object %p...\n", obj);
+		dump_from_ops(obj, params);
+	}
+}
+
+/** @} */
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * Call a callback on each element of the cache.
+ * @arg cache		cache to iterate on
+ * @arg cb		callback function
+ * @arg arg		argument passed to callback function
+ *
+ * Calls a callback function \a cb on each element of the \a cache.
+ * The argument \a arg is passed on the callback function.
+ */
+void nl_cache_foreach(struct nl_cache *cache,
+		      void (*cb)(struct nl_object *, void *), void *arg)
+{
+	nl_cache_foreach_filter(cache, NULL, cb, arg);
+}
+
+/**
+ * Call a callback on each element of the cache (filtered).
+ * @arg cache		cache to iterate on
+ * @arg filter		filter object
+ * @arg cb		callback function
+ * @arg arg		argument passed to callback function
+ *
+ * Calls a callback function \a cb on each element of the \a cache
+ * that matches the \a filter. The argument \a arg is passed on
+ * to the callback function.
+ */
+void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
+			     void (*cb)(struct nl_object *, void *), void *arg)
+{
+	struct nl_object *obj, *tmp;
+
+	if (cache->c_ops == NULL)
+		BUG();
+
+	nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
+		if (filter) {
+			int diff = nl_object_match_filter(obj, filter);
+
+			NL_DBG(3, "%p<->%p object difference: %x\n",
+				obj, filter, diff);
+
+			if (!diff)
+				continue;
+		}
+
+		/* Caller may hold obj for a long time */
+		nl_object_get(obj);
+
+		cb(obj, arg);
+
+		nl_object_put(obj);
+	}
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/cache_mngr.c b/libnetwork/libnl3/lib/cache_mngr.c
new file mode 100644
index 0000000..cf5a951
--- /dev/null
+++ b/libnetwork/libnl3/lib/cache_mngr.c
@@ -0,0 +1,391 @@
+/*
+ * lib/cache_mngr.c	Cache Manager
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cache_mngt
+ * @defgroup cache_mngr Manager
+ * @brief Helps keeping caches up to date.
+ *
+ * The purpose of a cache manager is to keep track of caches and
+ * automatically receive event notifications to keep the caches
+ * up to date with the kernel state. Each manager has exactly one
+ * netlink socket assigned which limits the scope of each manager
+ * to exactly one netlink family. Therefore all caches committed
+ * to a manager must be part of the same netlink family. Due to the
+ * nature of a manager, it is not possible to have a cache maintain
+ * two instances of the same cache type. The socket is subscribed
+ * to the event notification group of each cache and also put into
+ * non-blocking mode. Functions exist to poll() on the socket to
+ * wait for new events to be received.
+ *
+ * @code
+ * App       libnl                        Kernel
+ *        |                            |
+ *            +-----------------+        [ notification, link change ]
+ *        |   |  Cache Manager  |      | [   (IFF_UP | IFF_RUNNING)  ]
+ *            |                 |                |
+ *        |   |   +------------+|      |         |  [ notification, new addr ]
+ *    <-------|---| route/link |<-------(async)--+  [  10.0.1.1/32 dev eth1  ]
+ *        |   |   +------------+|      |                      |
+ *            |   +------------+|                             |
+ *    <---|---|---| route/addr |<------|-(async)--------------+
+ *            |   +------------+|
+ *        |   |   +------------+|      |
+ *    <-------|---| ...        ||
+ *        |   |   +------------+|      |
+ *            +-----------------+
+ *        |                            |
+ * @endcode
+ *
+ * @par 1) Creating a new cache manager
+ * @code
+ * struct nl_cache_mngr *mngr;
+ *
+ * // Allocate a new cache manager for RTNETLINK and automatically
+ * // provide the caches added to the manager.
+ * mngr = nl_cache_mngr_alloc(NETLINK_ROUTE, NL_AUTO_PROVIDE);
+ * @endcode
+ *
+ * @par 2) Keep track of a cache
+ * @code
+ * struct nl_cache *cache;
+ *
+ * // Create a new cache for links/interfaces and ask the manager to
+ * // keep it up to date for us. This will trigger a full dump request
+ * // to initially fill the cache.
+ * cache = nl_cache_mngr_add(mngr, "route/link");
+ * @endcode
+ *
+ * @par 3) Make the manager receive updates
+ * @code
+ * // Give the manager the ability to receive updates, will call poll()
+ * // with a timeout of 5 seconds.
+ * if (nl_cache_mngr_poll(mngr, 5000) > 0) {
+ *         // Manager received at least one update, dump cache?
+ *         nl_cache_dump(cache, ...);
+ * }
+ * @endcode
+ *
+ * @par 4) Release cache manager
+ * @code
+ * nl_cache_mngr_free(mngr);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+
+static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
+{
+	struct nl_cache_assoc *ca = p->pp_arg;
+	struct nl_cache_ops *ops = ca->ca_cache->c_ops;
+
+	NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
+#ifdef NL_DEBUG
+	if (nl_debug >= 4)
+		nl_object_dump(obj, &nl_debug_dp);
+#endif
+
+	if (ops->co_event_filter)
+		if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK)
+			return 0;
+
+	return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+	struct nl_cache_mngr *mngr = arg;
+	int protocol = nlmsg_get_proto(msg);
+	int type = nlmsg_hdr(msg)->nlmsg_type;
+	struct nl_cache_ops *ops;
+	int i, n;
+	struct nl_parser_param p = {
+		.pp_cb = include_cb,
+	};
+
+	NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
+	       mngr, msg);
+#ifdef NL_DEBUG
+	if (nl_debug >= 4)
+		nl_msg_dump(msg, stderr);
+#endif
+
+	if (mngr->cm_protocol != protocol)
+		BUG();
+
+	for (i = 0; i < mngr->cm_nassocs; i++) {
+		if (mngr->cm_assocs[i].ca_cache) {
+			ops = mngr->cm_assocs[i].ca_cache->c_ops;
+			for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++)
+				if (ops->co_msgtypes[n].mt_id == type)
+					goto found;
+		}
+	}
+
+	return NL_SKIP;
+
+found:
+	NL_DBG(2, "Associated message %p to cache %p\n",
+	       msg, mngr->cm_assocs[i].ca_cache);
+	p.pp_arg = &mngr->cm_assocs[i];
+
+	return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/**
+ * Allocate new cache manager
+ * @arg sk		Netlink socket.
+ * @arg protocol	Netlink Protocol this manager is used for
+ * @arg flags		Flags
+ * @arg result		Result pointer
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngr_alloc(struct nl_sock *sk, int protocol, int flags,
+			struct nl_cache_mngr **result)
+{
+	struct nl_cache_mngr *mngr;
+	int err = -NLE_NOMEM;
+
+	if (sk == NULL)
+		BUG();
+
+	mngr = calloc(1, sizeof(*mngr));
+	if (!mngr)
+		goto errout;
+
+	mngr->cm_handle = sk;
+	mngr->cm_nassocs = 32;
+	mngr->cm_protocol = protocol;
+	mngr->cm_flags = flags;
+	mngr->cm_assocs = calloc(mngr->cm_nassocs,
+				 sizeof(struct nl_cache_assoc));
+	if (!mngr->cm_assocs)
+		goto errout;
+
+	nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
+			    event_input, mngr);
+
+	/* Required to receive async event notifications */
+	nl_socket_disable_seq_check(mngr->cm_handle);
+
+	if ((err = nl_connect(mngr->cm_handle, protocol) < 0))
+		goto errout;
+
+	if ((err = nl_socket_set_nonblocking(mngr->cm_handle) < 0))
+		goto errout;
+
+	NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
+	       mngr, protocol, mngr->cm_nassocs);
+
+	*result = mngr;
+	return 0;
+
+errout:
+	nl_cache_mngr_free(mngr);
+	return err;
+}
+
+/**
+ * Add cache responsibility to cache manager
+ * @arg mngr		Cache manager.
+ * @arg name		Name of cache to keep track of
+ * @arg cb		Function to be called upon changes.
+ * @arg data		Argument passed on to change callback
+ * @arg result		Pointer to store added cache.
+ *
+ * Allocates a new cache of the specified type and adds it to the manager.
+ * The operation will trigger a full dump request from the kernel to
+ * initially fill the contents of the cache. The manager will subscribe
+ * to the notification group of the cache to keep track of any further
+ * changes.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
+		      change_func_t cb, void *data, struct nl_cache **result)
+{
+	struct nl_cache_ops *ops;
+	struct nl_cache *cache;
+	struct nl_af_group *grp;
+	int err, i;
+
+	ops = nl_cache_ops_lookup(name);
+	if (!ops)
+		return -NLE_NOCACHE;
+
+	if (ops->co_protocol != mngr->cm_protocol)
+		return -NLE_PROTO_MISMATCH;
+
+	if (ops->co_groups == NULL)
+		return -NLE_OPNOTSUPP;
+
+	for (i = 0; i < mngr->cm_nassocs; i++)
+		if (mngr->cm_assocs[i].ca_cache &&
+		    mngr->cm_assocs[i].ca_cache->c_ops == ops)
+			return -NLE_EXIST;
+
+retry:
+	for (i = 0; i < mngr->cm_nassocs; i++)
+		if (!mngr->cm_assocs[i].ca_cache)
+			break;
+
+	if (i >= mngr->cm_nassocs) {
+		mngr->cm_nassocs += 16;
+		mngr->cm_assocs = realloc(mngr->cm_assocs,
+					  mngr->cm_nassocs *
+					  sizeof(struct nl_cache_assoc));
+		if (mngr->cm_assocs == NULL)
+			return -NLE_NOMEM;
+		else {
+			NL_DBG(1, "Increased capacity of cache manager %p " \
+				  "to %d\n", mngr, mngr->cm_nassocs);
+			goto retry;
+		}
+	}
+
+	cache = nl_cache_alloc(ops);
+	if (!cache)
+		return -NLE_NOMEM;
+
+	for (grp = ops->co_groups; grp->ag_group; grp++) {
+		err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
+		if (err < 0)
+			goto errout_free_cache;
+	}
+
+	err = nl_cache_refill(mngr->cm_handle, cache);
+	if (err < 0)
+		goto errout_drop_membership;
+
+	mngr->cm_assocs[i].ca_cache = cache;
+	mngr->cm_assocs[i].ca_change = cb;
+	mngr->cm_assocs[i].ca_change_data = data;
+
+	if (mngr->cm_flags & NL_AUTO_PROVIDE)
+		nl_cache_mngt_provide(cache);
+
+	NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
+	       cache, nl_cache_name(cache), mngr);
+
+	*result = cache;
+	return 0;
+
+errout_drop_membership:
+	for (grp = ops->co_groups; grp->ag_group; grp++)
+		nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
+errout_free_cache:
+	nl_cache_free(cache);
+
+	return err;
+}
+
+/**
+ * Get file descriptor
+ * @arg mngr		Cache Manager
+ *
+ * Get the file descriptor of the socket associated to the manager.
+ * This can be used to change socket options or monitor activity
+ * using poll()/select().
+ */
+int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr)
+{
+	return nl_socket_get_fd(mngr->cm_handle);
+}
+
+/**
+ * Check for event notifications
+ * @arg mngr		Cache Manager
+ * @arg timeout		Upper limit poll() will block, in milliseconds.
+ *
+ * Causes poll() to be called to check for new event notifications
+ * being available. Automatically receives and handles available
+ * notifications.
+ *
+ * This functionally is ideally called regularly during an idle
+ * period.
+ *
+ * @return A positive value if at least one update was handled, 0
+ *         for none, or a  negative error code.
+ */
+int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
+{
+	int ret;
+	struct pollfd fds = {
+		.fd = nl_socket_get_fd(mngr->cm_handle),
+		.events = POLLIN,
+	};
+
+	NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
+	ret = poll(&fds, 1, timeout);
+	NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
+	if (ret < 0)
+		return -nl_syserr2nlerr(errno);
+
+	if (ret == 0)
+		return 0;
+
+	return nl_cache_mngr_data_ready(mngr);
+}
+
+/**
+ * Receive available event notifications
+ * @arg mngr		Cache manager
+ *
+ * This function can be called if the socket associated to the manager
+ * contains updates to be received. This function should not be used
+ * if nl_cache_mngr_poll() is used.
+ *
+ * @return A positive value if at least one update was handled, 0
+ *         for none, or a  negative error code.
+ */
+int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
+{
+	int err;
+
+	err = nl_recvmsgs_default(mngr->cm_handle);
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+
+/**
+ * Free cache manager and all caches.
+ * @arg mngr		Cache manager.
+ *
+ * Release all resources after usage of a cache manager.
+ */
+void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
+{
+	int i;
+
+	if (!mngr)
+		return;
+
+	if (mngr->cm_handle)
+		nl_close(mngr->cm_handle);
+
+	for (i = 0; i < mngr->cm_nassocs; i++)
+		if (mngr->cm_assocs[i].ca_cache)
+			nl_cache_free(mngr->cm_assocs[i].ca_cache);
+
+	free(mngr->cm_assocs);
+	free(mngr);
+
+	NL_DBG(1, "Cache manager %p freed\n", mngr);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/cache_mngt.c b/libnetwork/libnl3/lib/cache_mngt.c
new file mode 100644
index 0000000..a9ecf27
--- /dev/null
+++ b/libnetwork/libnl3/lib/cache_mngt.c
@@ -0,0 +1,256 @@
+/*
+ * lib/cache_mngt.c	Cache Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cache_mngt Caching
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+
+static struct nl_cache_ops *cache_ops;
+
+/**
+ * @name Cache Operations Sets
+ * @{
+ */
+
+/**
+ * Lookup the set cache operations of a certain cache type
+ * @arg name		name of the cache type
+ *
+ * @return The cache operations or NULL if no operations
+ *         have been registered under the specified name.
+ */
+struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
+{
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next)
+		if (!strcmp(ops->co_name, name))
+			return ops;
+
+	return NULL;
+}
+
+/**
+ * Associate a message type to a set of cache operations
+ * @arg protocol		netlink protocol
+ * @arg msgtype			netlink message type
+ *
+ * Associates the specified netlink message type with
+ * a registered set of cache operations.
+ *
+ * @return The cache operations or NULL if no association
+ *         could be made.
+ */
+struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
+{
+	int i;
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next) {
+		if (ops->co_protocol != protocol)
+			continue;
+
+		for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+			if (ops->co_msgtypes[i].mt_id == msgtype)
+				return ops;
+	}
+
+	return NULL;
+}
+
+/**
+ * Lookup message type cache association
+ * @arg ops			cache operations
+ * @arg msgtype			netlink message type
+ *
+ * Searches for a matching message type association ing the specified
+ * cache operations.
+ *
+ * @return A message type association or NULL.
+ */
+struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
+{
+	int i;
+
+	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+		if (ops->co_msgtypes[i].mt_id == msgtype)
+			return &ops->co_msgtypes[i];
+
+	return NULL;
+}
+
+static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
+{
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next)
+		if (ops->co_obj_ops == obj_ops)
+			return ops;
+
+	return NULL;
+
+}
+
+/**
+ * Call a function for each registered cache operation
+ * @arg cb		Callback function to be called
+ * @arg arg		User specific argument.
+ */
+void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
+{
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next)
+		cb(ops, arg);
+}
+
+/**
+ * Register a set of cache operations
+ * @arg ops		cache operations
+ *
+ * Called by users of caches to announce the avaibility of
+ * a certain cache type.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngt_register(struct nl_cache_ops *ops)
+{
+	if (!ops->co_name || !ops->co_obj_ops)
+		return -NLE_INVAL;
+
+	if (nl_cache_ops_lookup(ops->co_name))
+		return -NLE_EXIST;
+
+	ops->co_next = cache_ops;
+	cache_ops = ops;
+
+	NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
+
+	return 0;
+}
+
+/**
+ * Unregister a set of cache operations
+ * @arg ops		cache operations
+ *
+ * Called by users of caches to announce a set of
+ * cache operations is no longer available. The
+ * specified cache operations must have been registered
+ * previously using nl_cache_mngt_register()
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
+{
+	struct nl_cache_ops *t, **tp;
+
+	for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
+		if (t == ops)
+			break;
+
+	if (!t)
+		return -NLE_NOCACHE;
+
+	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
+
+	*tp = t->co_next;
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Global Cache Provisioning/Requiring
+ * @{
+ */
+
+/**
+ * Provide a cache for global use
+ * @arg cache		cache to provide
+ *
+ * Offers the specified cache to be used by other modules.
+ * Only one cache per type may be shared at a time,
+ * a previsouly provided caches will be overwritten.
+ */
+void nl_cache_mngt_provide(struct nl_cache *cache)
+{
+	struct nl_cache_ops *ops;
+
+	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
+	if (!ops)
+		BUG();
+	else
+		ops->co_major_cache = cache;
+}
+
+/**
+ * Unprovide a cache for global use
+ * @arg cache		cache to unprovide
+ *
+ * Cancels the offer to use a cache globally. The
+ * cache will no longer be returned via lookups but
+ * may still be in use.
+ */
+void nl_cache_mngt_unprovide(struct nl_cache *cache)
+{
+	struct nl_cache_ops *ops;
+
+	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
+	if (!ops)
+		BUG();
+	else if (ops->co_major_cache == cache)
+		ops->co_major_cache = NULL;
+}
+
+struct nl_cache *__nl_cache_mngt_require(const char *name)
+{
+	struct nl_cache_ops *ops;
+
+	ops = nl_cache_ops_lookup(name);
+	if (ops)
+		return ops->co_major_cache;
+	
+	return NULL;
+}
+
+/**
+ * Demand the use of a global cache
+ * @arg name		name of the required object type
+ *
+ * Trys to find a cache of the specified type for global
+ * use.
+ *
+ * @return A cache provided by another subsystem of the
+ *         specified type marked to be available.
+ */
+struct nl_cache *nl_cache_mngt_require(const char *name)
+{
+	struct nl_cache *cache;
+
+	if (!(cache = __nl_cache_mngt_require(name)))
+		fprintf(stderr, "Application BUG: Your application must "
+			"call nl_cache_mngt_provide() and\nprovide a valid "
+			"%s cache to be used for internal lookups.\nSee the "
+			" API documentation for more details.\n", name);
+	
+	return cache;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/cli/cls/.dirstamp b/libnetwork/libnl3/lib/cli/cls/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/cli/cls/basic.c b/libnetwork/libnl3/lib/cli/cls/basic.c
new file mode 100644
index 0000000..1939988
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/cls/basic.c
@@ -0,0 +1,93 @@
+/*
+ * lib/cli/cls/basic.c    	basic classifier module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/basic.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-cls-add [...] basic [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -t, --target=ID           Target class to send matching packets to\n"
+" -e, --ematch=EXPR         Ematch expression\n"
+"\n"
+"EXAMPLE"
+"    # Create a \"catch-all\" classifier, attached to \"q_root\", classyfing\n"
+"    # all not yet classified packets to class \"c_default\"\n"
+"    nl-cls-add --dev=eth0 --parent=q_root basic --target=c_default\n");
+}
+
+static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+	struct rtnl_ematch_tree *tree;
+	uint32_t target;
+	int err;
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_TARGET = 257,
+			ARG_DEFAULT = 258,
+		};
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "target", 1, 0, 't' },
+			{ "ematch", 1, 0, 'e' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "ht:e:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			exit(0);
+
+		case 't':
+			if ((err = rtnl_tc_str2handle(optarg, &target)) < 0)
+				nl_cli_fatal(err, "Unable to parse target \"%s\":",
+					optarg, nl_geterror(err));
+
+			rtnl_basic_set_target(cls, target);
+			break;
+
+		case 'e':
+			tree = nl_cli_cls_parse_ematch(cls, optarg);
+			rtnl_basic_set_ematch(cls, tree);
+			break;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module basic_module =
+{
+	.tm_name		= "basic",
+	.tm_type		= RTNL_TC_TYPE_CLS,
+	.tm_parse_argv		= parse_argv,
+};
+
+static void __init basic_init(void)
+{
+	nl_cli_tc_register(&basic_module);
+}
+
+static void __exit basic_exit(void)
+{
+	nl_cli_tc_unregister(&basic_module);
+}
diff --git a/libnetwork/libnl3/lib/cli/cls/cgroup.c b/libnetwork/libnl3/lib/cli/cls/cgroup.c
new file mode 100644
index 0000000..fae6208
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/cls/cgroup.c
@@ -0,0 +1,75 @@
+/*
+ * lib/cli/cls/cgroup.c    	cgroup classifier module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/cgroup.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-cls-add [...] cgroup [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -e, --ematch=EXPR         Ematch expression\n"
+"\n"
+"EXAMPLE"
+"    nl-cls-add --dev=eth0 --parent=q_root cgroup\n");
+}
+
+static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+	struct rtnl_ematch_tree *tree;
+
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "ematch", 1, 0, 'e' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "he:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			exit(0);
+
+		case 'e':
+			tree = nl_cli_cls_parse_ematch(cls, optarg);
+			rtnl_cgroup_set_ematch(cls, tree);
+			break;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module cgroup_module =
+{
+	.tm_name		= "cgroup",
+	.tm_type		= RTNL_TC_TYPE_CLS,
+	.tm_parse_argv		= parse_argv,
+};
+
+static void __init cgroup_init(void)
+{
+	nl_cli_tc_register(&cgroup_module);
+}
+
+static void __exit cgroup_exit(void)
+{
+	nl_cli_tc_unregister(&cgroup_module);
+}
diff --git a/libnetwork/libnl3/lib/cli/qdisc/.dirstamp b/libnetwork/libnl3/lib/cli/qdisc/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/cli/qdisc/bfifo.c b/libnetwork/libnl3/lib/cli/qdisc/bfifo.c
new file mode 100644
index 0000000..1ee4777
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/qdisc/bfifo.c
@@ -0,0 +1,83 @@
+/*
+ * src/lib/bfifo.c     	bfifo module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/fifo.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-qdisc-add [...] bfifo [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --limit=LIMIT         Maximum queue length in number of bytes.\n"
+"\n"
+"EXAMPLE"
+"    # Attach bfifo with a 4KB bytes limit to eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root bfifo --limit=4096\n");
+}
+
+static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+	int limit;
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_LIMIT = 257,
+		};
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "limit", 1, 0, ARG_LIMIT },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "h", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			return;
+
+		case ARG_LIMIT:
+			limit = nl_size2int(optarg);
+			if (limit < 0) {
+				nl_cli_fatal(limit, "Unable to parse bfifo limit "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_qdisc_fifo_set_limit(qdisc, limit);
+			break;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module bfifo_module =
+{
+	.tm_name		= "bfifo",
+	.tm_type		= RTNL_TC_TYPE_QDISC,
+	.tm_parse_argv		= bfifo_parse_argv,
+};
+
+static void __init bfifo_init(void)
+{
+	nl_cli_tc_register(&bfifo_module);
+}
+
+static void __exit bfifo_exit(void)
+{
+	nl_cli_tc_unregister(&bfifo_module);
+}
diff --git a/libnetwork/libnl3/lib/cli/qdisc/blackhole.c b/libnetwork/libnl3/lib/cli/qdisc/blackhole.c
new file mode 100644
index 0000000..af9dc6d
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/qdisc/blackhole.c
@@ -0,0 +1,64 @@
+/*
+ * src/lib/blackhole.c    Blackhole module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-qdisc-add [...] blackhole [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"\n"
+"EXAMPLE"
+"    # Drop all outgoing packets on eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root blackhole\n");
+}
+
+static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "h", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			return;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module blackhole_module =
+{
+	.tm_name		= "blackhole",
+	.tm_type		= RTNL_TC_TYPE_QDISC,
+	.tm_parse_argv		= blackhole_parse_argv,
+};
+
+static void __init blackhole_init(void)
+{
+	nl_cli_tc_register(&blackhole_module);
+}
+
+static void __exit blackhole_exit(void)
+{
+	nl_cli_tc_unregister(&blackhole_module);
+}
diff --git a/libnetwork/libnl3/lib/cli/qdisc/htb.c b/libnetwork/libnl3/lib/cli/qdisc/htb.c
new file mode 100644
index 0000000..1751595
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/qdisc/htb.c
@@ -0,0 +1,203 @@
+/*
+ * src/lib/htb.c     	HTB module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/htb.h>
+
+static void print_qdisc_usage(void)
+{
+	printf(
+"Usage: nl-qdisc-add [...] htb [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --r2q=DIV             Rate to quantum divisor (default: 10)\n"
+"     --default=ID          Default class for unclassified traffic.\n"
+"\n"
+"EXAMPLE"
+"    # Create htb root qdisc 1: and direct unclassified traffic to class 1:10\n"
+"    nl-qdisc-add --dev=eth1 --parent=root --handle=1: htb --default=10\n");
+}
+
+static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_R2Q = 257,
+			ARG_DEFAULT = 258,
+		};
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "r2q", 1, 0, ARG_R2Q },
+			{ "default", 1, 0, ARG_DEFAULT },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "hv", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_qdisc_usage();
+			return;
+
+		case ARG_R2Q:
+			rtnl_htb_set_rate2quantum(qdisc, nl_cli_parse_u32(optarg));
+			break;
+
+		case ARG_DEFAULT:
+			rtnl_htb_set_defcls(qdisc, nl_cli_parse_u32(optarg));
+			break;
+		}
+ 	}
+}
+
+static void print_class_usage(void)
+{
+	printf(
+"Usage: nl-class-add [...] htb [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --rate=RATE           Rate limit.\n"
+"     --ceil=RATE           Rate limit while borrowing (default: equal to --rate).\n"
+"     --prio=PRIO           Priority, lower is served first (default: 0).\n"
+"     --quantum=SIZE        Amount of bytes to serve at once (default: rate/r2q).\n"
+"     --burst=SIZE          Max charge size of rate burst buffer (default: auto).\n"
+"     --cburst=SIZE         Max charge size of ceil rate burst buffer (default: auto)\n"
+"\n"
+"EXAMPLE"
+"    # Attach class 1:1 to htb qdisc 1: and rate limit it to 20mbit\n"
+"    nl-class-add --dev=eth1 --parent=1: --classid=1:1 htb --rate=20mbit\n");
+}
+
+static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_class *class = (struct rtnl_class *) tc;
+	long rate;
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_RATE = 257,
+			ARG_QUANTUM = 258,
+			ARG_CEIL,
+			ARG_PRIO,
+			ARG_BURST,
+			ARG_CBURST,
+		};
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "rate", 1, 0, ARG_RATE },
+			{ "quantum", 1, 0, ARG_QUANTUM },
+			{ "ceil", 1, 0, ARG_CEIL },
+			{ "prio", 1, 0, ARG_PRIO },
+			{ "burst", 1, 0, ARG_BURST },
+			{ "cburst", 1, 0, ARG_CBURST },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "h", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_class_usage();
+			return;
+
+		case ARG_RATE:
+			rate = nl_size2int(optarg);
+			if (rate < 0) {
+				nl_cli_fatal(rate, "Unable to parse htb rate "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_htb_set_rate(class, rate);
+			break;
+
+		case ARG_CEIL:
+			rate = nl_size2int(optarg);
+			if (rate < 0) {
+				nl_cli_fatal(rate, "Unable to parse htb ceil rate "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_htb_set_ceil(class, rate);
+			break;
+
+		case ARG_PRIO:
+			rtnl_htb_set_prio(class, nl_cli_parse_u32(optarg));
+			break;
+
+		case ARG_QUANTUM:
+			rate = nl_size2int(optarg);
+			if (rate < 0) {
+				nl_cli_fatal(rate, "Unable to parse quantum "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_htb_set_quantum(class, rate);
+			break;
+
+		case ARG_BURST:
+			rate = nl_size2int(optarg);
+			if (rate < 0) {
+				nl_cli_fatal(rate, "Unable to parse burst "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_htb_set_rbuffer(class, rate);
+			break;
+
+		case ARG_CBURST:
+			rate = nl_size2int(optarg);
+			if (rate < 0) {
+				nl_cli_fatal(rate, "Unable to parse cburst "
+					"\"%s\": Invalid format.", optarg);
+			}
+
+			rtnl_htb_set_cbuffer(class, rate);
+			break;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module htb_qdisc_module =
+{
+	.tm_name		= "htb",
+	.tm_type		= RTNL_TC_TYPE_QDISC,
+	.tm_parse_argv		= htb_parse_qdisc_argv,
+};
+
+static struct nl_cli_tc_module htb_class_module =
+{
+	.tm_name		= "htb",
+	.tm_type		= RTNL_TC_TYPE_CLASS,
+	.tm_parse_argv		= htb_parse_class_argv,
+};
+
+static void __init htb_init(void)
+{
+	nl_cli_tc_register(&htb_qdisc_module);
+	nl_cli_tc_register(&htb_class_module);
+}
+
+static void __exit htb_exit(void)
+{
+	nl_cli_tc_unregister(&htb_class_module);
+	nl_cli_tc_unregister(&htb_qdisc_module);
+}
diff --git a/libnetwork/libnl3/lib/cli/qdisc/pfifo.c b/libnetwork/libnl3/lib/cli/qdisc/pfifo.c
new file mode 100644
index 0000000..02c4d22
--- /dev/null
+++ b/libnetwork/libnl3/lib/cli/qdisc/pfifo.c
@@ -0,0 +1,77 @@
+
+/*
+ * src/lib/pfifo.c     	pfifo module for CLI lib
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/fifo.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-qdisc-add [...] pfifo [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --limit=LIMIT         Maximum queue length in number of packets.\n"
+"\n"
+"EXAMPLE"
+"    # Attach pfifo with a 32 packet limit to eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root pfifo --limit=32\n");
+}
+
+static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_LIMIT = 257,
+		};
+		static struct option long_opts[] = {
+			{ "help", 0, 0, 'h' },
+			{ "limit", 1, 0, ARG_LIMIT },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "h", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			return;
+
+		case ARG_LIMIT:
+			rtnl_qdisc_fifo_set_limit(qdisc, nl_cli_parse_u32(optarg));
+			break;
+		}
+ 	}
+}
+
+static struct nl_cli_tc_module pfifo_module =
+{
+	.tm_name		= "pfifo",
+	.tm_type		= RTNL_TC_TYPE_QDISC,
+	.tm_parse_argv		= pfifo_parse_argv,
+};
+
+static void __init pfifo_init(void)
+{
+	nl_cli_tc_register(&pfifo_module);
+}
+
+static void __exit pfifo_exit(void)
+{
+	nl_cli_tc_unregister(&pfifo_module);
+}
diff --git a/libnetwork/libnl3/lib/data.c b/libnetwork/libnl3/lib/data.c
new file mode 100644
index 0000000..03cd9fe
--- /dev/null
+++ b/libnetwork/libnl3/lib/data.c
@@ -0,0 +1,186 @@
+/*
+ * lib/data.c		Abstract Data
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup data Abstract Data
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <linux/socket.h>
+
+/**
+ * @name General
+ * @{
+ */
+
+/**
+ * Allocate a new abstract data object.
+ * @arg buf		Data buffer containing the actual data.
+ * @arg size		Size of data buffer.
+ *
+ * Allocates a new abstract data and copies the specified data
+ * buffer into the new handle.
+ * 
+ * @return Newly allocated data handle or NULL
+ */
+struct nl_data *nl_data_alloc(void *buf, size_t size)
+{
+	struct nl_data *data;
+
+	data = calloc(1, sizeof(*data));
+	if (!data)
+		goto errout;
+
+	data->d_data = calloc(1, size);
+	if (!data->d_data) {
+		free(data);
+		goto errout;
+	}
+
+	data->d_size = size;
+
+	if (buf)
+		memcpy(data->d_data, buf, size);
+
+	return data;
+errout:
+	return NULL;
+}
+
+/**
+ * Allocate abstract data object based on netlink attribute.
+ * @arg nla		Netlink attribute of unspecific type.
+ *
+ * Allocates a new abstract data and copies the payload of the
+ * attribute to the abstract data object.
+ * 
+ * @see nla_data_alloc
+ * @return Newly allocated data handle or NULL
+ */
+struct nl_data *nl_data_alloc_attr(struct nlattr *nla)
+{
+	return nl_data_alloc(nla_data(nla), nla_len(nla));
+}
+
+/**
+ * Clone an abstract data object.
+ * @arg src		Abstract data object
+ *
+ * @return Cloned object or NULL
+ */
+struct nl_data *nl_data_clone(struct nl_data *src)
+{
+	return nl_data_alloc(src->d_data, src->d_size);
+}
+
+/**
+ * Append data to an abstract data object.
+ * @arg data		Abstract data object.
+ * @arg buf		Data buffer containing the data to be appended.
+ * @arg size		Size of data to be apppended.
+ *
+ * Reallocates an abstract data and copies the specified data
+ * buffer into the new handle.
+ * 
+ * @return 0 on success or a negative error code
+ */
+int nl_data_append(struct nl_data *data, void *buf, size_t size)
+{
+	if (size < 0)
+		BUG();
+
+	if (size > 0) {
+		data->d_data = realloc(data->d_data, data->d_size + size);
+		if (!data->d_data)
+			return -NLE_NOMEM;
+
+		if (buf)
+			memcpy(data->d_data + data->d_size, buf, size);
+		else
+			memset(data->d_data + data->d_size, 0, size);
+
+		data->d_size += size;
+	}
+
+	return 0;
+}
+
+/**
+ * Free an abstract data object.
+ * @arg data		Abstract data object.
+ */
+void nl_data_free(struct nl_data *data)
+{
+	if (data)
+		free(data->d_data);
+
+	free(data);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Get data buffer of abstract data object.
+ * @arg data		Abstract data object.
+ * @return Data buffer or NULL if empty.
+ */
+void *nl_data_get(struct nl_data *data)
+{
+	return data->d_size > 0 ? data->d_data : NULL;
+}
+
+/**
+ * Get size of data buffer of abstract data object.
+ * @arg data		Abstract data object.
+ * @return Size of data buffer.
+ */
+size_t nl_data_get_size(struct nl_data *data)
+{
+	return data->d_size;
+}
+
+/** @} */
+
+/**
+ * @name Misc
+ * @{
+ */
+
+/**
+ * Compare two abstract data objects.
+ * @arg a		Abstract data object.
+ * @arg b		Another abstract data object.
+ * @return An integer less than, equal to, or greater than zero if
+ *         a is found, respectively, to be less than, to match, or
+ *         be greater than b.
+ */
+int nl_data_cmp(struct nl_data *a, struct nl_data *b)
+{
+	void *a_ = nl_data_get(a);
+	void *b_ = nl_data_get(b);
+
+	if (a_ && b_)
+		return memcmp(a_, b_, nl_data_get_size(a));
+	else
+		return -1;
+}
+
+/** @} */
+/** @} */
diff --git a/libnetwork/libnl3/lib/defs.h b/libnetwork/libnl3/lib/defs.h
new file mode 100644
index 0000000..c3bd632
--- /dev/null
+++ b/libnetwork/libnl3/lib/defs.h
@@ -0,0 +1,85 @@
+/* lib/defs.h.  Generated from defs.h.in by configure.  */
+/* lib/defs.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "libnl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://www.infradead.org/~tgr/libnl/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libnl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libnl 3.2.3"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libnl"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "3.2.3"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "3.2.3"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
diff --git a/libnetwork/libnl3/lib/defs.h.in b/libnetwork/libnl3/lib/defs.h.in
new file mode 100644
index 0000000..cc3bf5c
--- /dev/null
+++ b/libnetwork/libnl3/lib/defs.h.in
@@ -0,0 +1,84 @@
+/* lib/defs.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
diff --git a/libnetwork/libnl3/lib/error.c b/libnetwork/libnl3/lib/error.c
new file mode 100644
index 0000000..e8ee474
--- /dev/null
+++ b/libnetwork/libnl3/lib/error.c
@@ -0,0 +1,116 @@
+/*
+ * lib/error.c		Error Handling
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+
+static const char *errmsg[NLE_MAX+1] = {
+[NLE_SUCCESS]		= "Success",
+[NLE_FAILURE]		= "Unspecific failure",
+[NLE_INTR]		= "Interrupted system call",
+[NLE_BAD_SOCK]		= "Bad socket",
+[NLE_AGAIN]		= "Try again",
+[NLE_NOMEM]		= "Out of memory",
+[NLE_EXIST]		= "Object exists",
+[NLE_INVAL]		= "Invalid input data or parameter",
+[NLE_RANGE]		= "Input data out of range",
+[NLE_MSGSIZE]		= "Message size not sufficient",
+[NLE_OPNOTSUPP]		= "Operation not supported",
+[NLE_AF_NOSUPPORT]	= "Address family not supported",
+[NLE_OBJ_NOTFOUND]	= "Object not found",
+[NLE_NOATTR]		= "Attribute not available",
+[NLE_MISSING_ATTR]	= "Missing attribute",
+[NLE_AF_MISMATCH]	= "Address family mismatch",
+[NLE_SEQ_MISMATCH]	= "Message sequence number mismatch",
+[NLE_MSG_OVERFLOW]	= "Kernel reported message overflow",
+[NLE_MSG_TRUNC]		= "Kernel reported truncated message",
+[NLE_NOADDR]		= "Invalid address for specified address family",
+[NLE_SRCRT_NOSUPPORT]	= "Source based routing not supported",
+[NLE_MSG_TOOSHORT]	= "Netlink message is too short",
+[NLE_MSGTYPE_NOSUPPORT]	= "Netlink message type is not supported",
+[NLE_OBJ_MISMATCH]	= "Object type does not match cache",
+[NLE_NOCACHE]		= "Unknown or invalid cache type",
+[NLE_BUSY]		= "Object busy",
+[NLE_PROTO_MISMATCH]	= "Protocol mismatch",
+[NLE_NOACCESS]		= "No Access",
+[NLE_PERM]		= "Operation not permitted",
+[NLE_PKTLOC_FILE]	= "Unable to open packet location file",
+[NLE_PARSE_ERR]		= "Unable to parse object",
+[NLE_NODEV]		= "No such device",
+[NLE_IMMUTABLE]		= "Immutable attribute",
+[NLE_DUMP_INTR]		= "Dump inconsistency detected, interrupted",
+};
+
+/**
+ * Return error message for an error code
+ * @return error message
+ */
+const char *nl_geterror(int error)
+{
+	error = abs(error);
+
+	if (error > NLE_MAX)
+		error = NLE_FAILURE;
+
+	return errmsg[error];
+}
+
+/**
+ * Print a libnl error message
+ * @arg s		error message prefix
+ *
+ * Prints the error message of the call that failed last.
+ *
+ * If s is not NULL and *s is not a null byte the argument
+ * string is printed, followed by a colon and a blank. Then
+ * the error message and a new-line.
+ */
+void nl_perror(int error, const char *s)
+{
+	if (s && *s)
+		fprintf(stderr, "%s: %s\n", s, nl_geterror(error));
+	else
+		fprintf(stderr, "%s\n", nl_geterror(error));
+}
+
+int nl_syserr2nlerr(int error)
+{
+	error = abs(error);
+
+	switch (error) {
+	case EBADF:		return NLE_BAD_SOCK;
+	case EADDRINUSE:	return NLE_EXIST;
+	case EEXIST:		return NLE_EXIST;
+	case EADDRNOTAVAIL:	return NLE_NOADDR;
+	case ESRCH:		/* fall through */
+	case ENOENT:		return NLE_OBJ_NOTFOUND;
+	case EINTR:		return NLE_INTR;
+	case EAGAIN:		return NLE_AGAIN;
+	case ENOTSOCK:		return NLE_BAD_SOCK;
+	case ENOPROTOOPT:	return NLE_INVAL;
+	case EFAULT:		return NLE_INVAL;
+	case EACCES:		return NLE_NOACCESS;
+	case EINVAL:		return NLE_INVAL;
+	case ENOBUFS:		return NLE_NOMEM;
+	case ENOMEM:		return NLE_NOMEM;
+	case EAFNOSUPPORT:	return NLE_AF_NOSUPPORT;
+	case EPROTONOSUPPORT:	return NLE_PROTO_MISMATCH;
+	case EOPNOTSUPP:	return NLE_OPNOTSUPP;
+	case EPERM:		return NLE_PERM;
+	case EBUSY:		return NLE_BUSY;
+	case ERANGE:		return NLE_RANGE;
+	case ENODEV:		return NLE_NODEV;
+	default:		return NLE_FAILURE;
+	}
+}
+
+/** @} */
+
diff --git a/libnetwork/libnl3/lib/fib_lookup/.dirstamp b/libnetwork/libnl3/lib/fib_lookup/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/fib_lookup/lookup.c b/libnetwork/libnl3/lib/fib_lookup/lookup.c
new file mode 100644
index 0000000..6018251
--- /dev/null
+++ b/libnetwork/libnl3/lib/fib_lookup/lookup.c
@@ -0,0 +1,348 @@
+/*
+ * lib/fib_lookup/lookup.c	FIB Lookup
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @defgroup fib_lookup FIB Lookup
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/fib_lookup/request.h>
+#include <netlink/fib_lookup/lookup.h>
+
+/** @cond SKIP */
+static struct nl_cache_ops fib_lookup_ops;
+static struct nl_object_ops result_obj_ops;
+
+/* not exported so far */
+struct fib_result_nl {
+	uint32_t	fl_addr;   /* To be looked up*/ 
+	uint32_t	fl_fwmark; 
+	unsigned char	fl_tos;
+	unsigned char   fl_scope;
+	unsigned char   tb_id_in;
+
+	unsigned char   tb_id;      /* Results */
+	unsigned char	prefixlen;
+	unsigned char	nh_sel;
+	unsigned char	type;
+	unsigned char	scope;
+	int             err;      
+};
+/** @endcond */
+
+static void result_free_data(struct nl_object *obj)
+{
+	struct flnl_result *res = nl_object_priv(obj);
+
+	if (res && res->fr_req)
+		nl_object_put(OBJ_CAST(res->fr_req));
+}
+
+static int result_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct flnl_result *dst = nl_object_priv(_dst);
+	struct flnl_result *src = nl_object_priv(_src);
+
+	if (src->fr_req)
+		if (!(dst->fr_req = (struct flnl_request *)
+				nl_object_clone(OBJ_CAST(src->fr_req))))
+			return -NLE_NOMEM;
+	
+	return 0;
+}
+
+static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			     struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+	struct flnl_result *res;
+	struct fib_result_nl *fr;
+	struct nl_addr *addr;
+	int err = -NLE_INVAL;
+
+	res = flnl_result_alloc();
+	if (!res)
+		goto errout;
+
+	res->ce_msgtype = n->nlmsg_type;
+
+	res->fr_req = flnl_request_alloc();
+	if (!res->fr_req)
+		goto errout;
+
+	fr = nlmsg_data(n);
+	addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
+	if (!addr)
+		goto errout;
+	err = flnl_request_set_addr(res->fr_req, addr);
+	nl_addr_put(addr);
+	if (err < 0)
+		goto errout;
+
+	flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
+	flnl_request_set_tos(res->fr_req, fr->fl_tos);
+	flnl_request_set_scope(res->fr_req, fr->fl_scope);
+	flnl_request_set_table(res->fr_req, fr->tb_id_in);
+
+	res->fr_table_id = fr->tb_id;
+	res->fr_prefixlen = fr->prefixlen;
+	res->fr_nh_sel = fr->nh_sel;
+	res->fr_type = fr->type;
+	res->fr_scope = fr->scope;
+	res->fr_error = fr->err;
+
+	err = pp->pp_cb((struct nl_object *) res, pp);
+	if (err < 0)
+		goto errout;
+
+	/* REAL HACK, fib_lookup doesn't support ACK nor does it
+	 * send a DONE message, enforce end of message stream
+	 * after just the first message */
+	err = NL_STOP;
+
+errout:
+	flnl_result_put(res);
+	return err;
+}
+
+static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct flnl_result *res = (struct flnl_result *) obj;
+	char buf[128];
+
+	nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n",
+		rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
+		res->fr_prefixlen, res->fr_nh_sel);
+	nl_dump_line(p, "type %s ",
+		     nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
+	nl_dump(p, "scope %s error %s (%d)\n",
+		rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
+		strerror(-res->fr_error), res->fr_error);
+}
+
+static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	result_dump_line(obj, p);
+}
+
+static int result_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	return 0;
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct flnl_result *flnl_result_alloc(void)
+{
+	return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
+}
+
+void flnl_result_put(struct flnl_result *res)
+{
+	nl_object_put((struct nl_object *) res);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Allocate lookup result cache.
+ *
+ * Allocates a new lookup result cache and initializes it properly.
+ *
+ * @note Free the memory after usage using nl_cache_destroy_and_free().
+ * @return Newly allocated cache or NULL if an error occured.
+ */
+struct nl_cache *flnl_result_alloc_cache(void)
+{
+	return nl_cache_alloc(&fib_lookup_ops);
+}
+
+/** @} */
+
+/**
+ * @name Lookup
+ * @{
+ */
+
+/**
+ * Builds a netlink request message to do a lookup
+ * @arg req		Requested match.
+ * @arg flags		additional netlink message flags
+ * @arg result		Result pointer
+ *
+ * Builds a new netlink message requesting a change of link attributes.
+ * The netlink message header isn't fully equipped with all relevant
+ * fields and must be sent out via nl_send_auto_complete() or
+ * supplemented as needed.
+ * \a old must point to a link currently configured in the kernel
+ * and \a tmpl must contain the attributes to be changed set via
+ * \c rtnl_link_set_* functions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int flnl_lookup_build_request(struct flnl_request *req, int flags,
+			      struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct nl_addr *addr;
+	uint64_t fwmark;
+	int tos, scope, table;
+	struct fib_result_nl fr = {0};
+
+	fwmark = flnl_request_get_fwmark(req);
+	tos = flnl_request_get_tos(req);
+	scope = flnl_request_get_scope(req);
+	table = flnl_request_get_table(req);
+
+	fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
+	fr.fl_tos = tos >= 0 ? tos : 0;
+	fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
+	fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
+
+	addr = flnl_request_get_addr(req);
+	if (!addr)
+		return -NLE_MISSING_ATTR;
+
+	fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
+
+	msg = nlmsg_alloc_simple(0, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0)
+		goto errout;
+
+	*result = msg;
+	return 0;
+
+errout:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Perform FIB Lookup
+ * @arg sk		Netlink socket.
+ * @arg req		Lookup request object.
+ * @arg cache		Cache for result.
+ *
+ * Builds a netlink message to request a FIB lookup, waits for the
+ * reply and adds the result to the specified cache.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int flnl_lookup(struct nl_sock *sk, struct flnl_request *req,
+		struct nl_cache *cache)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return nl_cache_pickup(sk, cache);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+int flnl_result_get_table_id(struct flnl_result *res)
+{
+	return res->fr_table_id;
+}
+
+int flnl_result_get_prefixlen(struct flnl_result *res)
+{
+	return res->fr_prefixlen;
+}
+
+int flnl_result_get_nexthop_sel(struct flnl_result *res)
+{
+	return res->fr_nh_sel;
+}
+
+int flnl_result_get_type(struct flnl_result *res)
+{
+	return res->fr_type;
+}
+
+int flnl_result_get_scope(struct flnl_result *res)
+{
+	return res->fr_scope;
+}
+
+int flnl_result_get_error(struct flnl_result *res)
+{
+	return res->fr_error;
+}
+
+/** @} */
+
+static struct nl_object_ops result_obj_ops = {
+	.oo_name		= "fib_lookup/result",
+	.oo_size		= sizeof(struct flnl_result),
+	.oo_free_data		= result_free_data,
+	.oo_clone		= result_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= result_dump_line,
+	    [NL_DUMP_DETAILS]	= result_dump_details,
+	},
+	.oo_compare		= result_compare,
+};
+
+static struct nl_cache_ops fib_lookup_ops = {
+	.co_name		= "fib_lookup/fib_lookup",
+	.co_hdrsize		= sizeof(struct fib_result_nl),
+	.co_msgtypes		= {
+					{ 0, NL_ACT_UNSPEC, "any" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_FIB_LOOKUP,
+	.co_msg_parser		= result_msg_parser,
+	.co_obj_ops		= &result_obj_ops,
+};
+
+static void __init fib_lookup_init(void)
+{
+	nl_cache_mngt_register(&fib_lookup_ops);
+}
+
+static void __exit fib_lookup_exit(void)
+{
+	nl_cache_mngt_unregister(&fib_lookup_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/fib_lookup/request.c b/libnetwork/libnl3/lib/fib_lookup/request.c
new file mode 100644
index 0000000..ffcf8f5
--- /dev/null
+++ b/libnetwork/libnl3/lib/fib_lookup/request.c
@@ -0,0 +1,185 @@
+/*
+ * lib/fib_lookup/request.c	FIB Lookup Request
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup fib_lookup
+ * @defgroup flreq Request
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/fib_lookup/request.h>
+
+static struct nl_object_ops request_obj_ops;
+
+/** @cond SKIP */
+#define REQUEST_ATTR_ADDR	0x01
+#define REQUEST_ATTR_FWMARK	0x02
+#define REQUEST_ATTR_TOS	0x04
+#define REQUEST_ATTR_SCOPE	0x08
+#define REQUEST_ATTR_TABLE	0x10
+/** @endcond */
+
+static void request_free_data(struct nl_object *obj)
+{
+	struct flnl_request *req = REQUEST_CAST(obj);
+
+	if (req)
+		nl_addr_put(req->lr_addr);
+}
+
+static int request_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct flnl_request *dst = nl_object_priv(_dst);
+	struct flnl_request *src = nl_object_priv(_src);
+
+	if (src->lr_addr)
+		if (!(dst->lr_addr = nl_addr_clone(src->lr_addr)))
+			return -NLE_NOMEM;
+
+	return 0;
+}
+
+static int request_compare(struct nl_object *_a, struct nl_object *_b,
+			   uint32_t attrs, int flags)
+{
+	struct flnl_request *a = (struct flnl_request *) _a;
+	struct flnl_request *b = (struct flnl_request *) _b;
+	int diff = 0;
+
+#define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= REQ_DIFF(FWMARK,	a->lr_fwmark != b->lr_fwmark);
+	diff |= REQ_DIFF(TOS,		a->lr_tos != b->lr_tos);
+	diff |= REQ_DIFF(SCOPE,		a->lr_scope != b->lr_scope);
+	diff |= REQ_DIFF(TABLE,		a->lr_table != b->lr_table);
+	diff |= REQ_DIFF(ADDR,		nl_addr_cmp(a->lr_addr, b->lr_addr));
+
+#undef REQ_DIFF
+
+	return diff;
+}
+
+
+/**
+ * @name Lookup Request Creation/Deletion
+ * @{
+ */
+
+struct flnl_request *flnl_request_alloc(void)
+{
+	return REQUEST_CAST(nl_object_alloc(&request_obj_ops));
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void flnl_request_set_fwmark(struct flnl_request *req, uint64_t fwmark)
+{
+	req->lr_fwmark = fwmark;
+	req->ce_mask |= REQUEST_ATTR_FWMARK;
+}
+
+uint64_t flnl_request_get_fwmark(struct flnl_request *req)
+{
+	if (req->ce_mask & REQUEST_ATTR_FWMARK)
+		return req->lr_fwmark;
+	else
+		return UINT_LEAST64_MAX;
+}
+
+void flnl_request_set_tos(struct flnl_request *req, int tos)
+{
+	req->lr_tos = tos;
+	req->ce_mask |= REQUEST_ATTR_TOS;
+}
+
+int flnl_request_get_tos(struct flnl_request *req)
+{
+	if (req->ce_mask & REQUEST_ATTR_TOS)
+		return req->lr_tos;
+	else
+		return -1;
+}
+
+void flnl_request_set_scope(struct flnl_request *req, int scope)
+{
+	req->lr_scope = scope;
+	req->ce_mask |= REQUEST_ATTR_SCOPE;
+}
+
+int flnl_request_get_scope(struct flnl_request *req)
+{
+	if (req->ce_mask & REQUEST_ATTR_SCOPE)
+		return req->lr_scope;
+	else
+		return -1;
+}
+
+void flnl_request_set_table(struct flnl_request *req, int table)
+{
+	req->lr_table = table;
+	req->ce_mask |= REQUEST_ATTR_TABLE;
+}
+
+int flnl_request_get_table(struct flnl_request *req)
+{
+	if (req->ce_mask & REQUEST_ATTR_TABLE)
+		return req->lr_table;
+	else
+		return -1;
+}
+
+int flnl_request_set_addr(struct flnl_request *req, struct nl_addr *addr)
+{
+	if (addr->a_family != AF_INET)
+		return -NLE_AF_NOSUPPORT;
+
+	if (req->lr_addr)
+		nl_addr_put(req->lr_addr);
+
+	nl_addr_get(addr);
+	req->lr_addr = addr;
+
+	req->ce_mask |= REQUEST_ATTR_ADDR;
+
+	return 0;
+}
+
+struct nl_addr *flnl_request_get_addr(struct flnl_request *req)
+{
+	if (req->ce_mask & REQUEST_ATTR_ADDR)
+		return req->lr_addr;
+	else
+		return NULL;
+}
+
+/** @} */
+
+static struct nl_object_ops request_obj_ops = {
+	.oo_name		= "fib_lookup/request",
+	.oo_size		= sizeof(struct flnl_request),
+	.oo_free_data		= request_free_data,
+	.oo_clone		= request_clone,
+	.oo_compare		= request_compare,
+	.oo_id_attrs		= ~0,
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/genl/.dirstamp b/libnetwork/libnl3/lib/genl/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/genl/ctrl.c b/libnetwork/libnl3/lib/genl/ctrl.c
new file mode 100644
index 0000000..107a4fa
--- /dev/null
+++ b/libnetwork/libnl3/lib/genl/ctrl.c
@@ -0,0 +1,380 @@
+/*
+ * lib/genl/ctrl.c		Generic Netlink Controller
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup genl_mngt
+ * @defgroup ctrl Controller
+ * @brief
+ *
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define CTRL_VERSION		0x0001
+
+static struct nl_cache_ops genl_ctrl_ops;
+/** @endcond */
+
+static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
+				CTRL_VERSION, NLM_F_DUMP);
+}
+
+static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
+	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
+	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_STRING,
+				    .maxlen = GENL_NAMSIZ },
+	[CTRL_ATTR_VERSION]	= { .type = NLA_U32 },
+	[CTRL_ATTR_HDRSIZE]	= { .type = NLA_U32 },
+	[CTRL_ATTR_MAXATTR]	= { .type = NLA_U32 },
+	[CTRL_ATTR_OPS]		= { .type = NLA_NESTED },
+	[CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
+	[CTRL_ATTR_OP_ID]	= { .type = NLA_U32 },
+	[CTRL_ATTR_OP_FLAGS]	= { .type = NLA_U32 },
+};
+
+static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
+	[CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
+	[CTRL_ATTR_MCAST_GRP_ID]   = { .type = NLA_U32 },
+};
+
+static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
+			   struct genl_info *info, void *arg)
+{
+	struct genl_family *family;
+	struct nl_parser_param *pp = arg;
+	int err;
+
+	family = genl_family_alloc();
+	if (family == NULL) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
+		err = -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
+		err = -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	family->ce_msgtype = info->nlh->nlmsg_type;
+	genl_family_set_id(family,
+			   nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
+	genl_family_set_name(family,
+		     nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
+
+	if (info->attrs[CTRL_ATTR_VERSION]) {
+		uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
+		genl_family_set_version(family, version);
+	}
+
+	if (info->attrs[CTRL_ATTR_HDRSIZE]) {
+		uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
+		genl_family_set_hdrsize(family, hdrsize);
+	}
+
+	if (info->attrs[CTRL_ATTR_MAXATTR]) {
+		uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
+		genl_family_set_maxattr(family, maxattr);
+	}
+
+	if (info->attrs[CTRL_ATTR_OPS]) {
+		struct nlattr *nla, *nla_ops;
+		int remaining;
+
+		nla_ops = info->attrs[CTRL_ATTR_OPS];
+		nla_for_each_nested(nla, nla_ops, remaining) {
+			struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
+			int flags = 0, id;
+
+			err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
+					       family_op_policy);
+			if (err < 0)
+				goto errout;
+
+			if (tb[CTRL_ATTR_OP_ID] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			
+			id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
+
+			if (tb[CTRL_ATTR_OP_FLAGS])
+				flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
+
+			err = genl_family_add_op(family, id, flags);
+			if (err < 0)
+				goto errout;
+
+		}
+	}
+	
+	if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
+		struct nlattr *nla, *nla_grps;
+		int remaining;
+
+		nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS];
+		nla_for_each_nested(nla, nla_grps, remaining) {
+			struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
+			int id;
+			const char * name;
+
+			err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
+					       family_grp_policy);
+			if (err < 0)
+				goto errout;
+
+			if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+
+			if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+
+			err = genl_family_add_grp(family, id, name);
+			if (err < 0)
+				goto errout;
+		}
+
+	}
+
+	err = pp->pp_cb((struct nl_object *) family, pp);
+errout:
+	genl_family_put(family);
+	return err;
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
+}
+
+/**
+ * Look up generic netlink family by id in the provided cache.
+ * @arg cache		Generic netlink family cache.
+ * @arg id		Family identifier.
+ *
+ * Searches through the cache looking for a registered family
+ * matching the specified identifier. The caller will own a
+ * reference on the returned object which needs to be given
+ * back after usage using genl_family_put().
+ *
+ * @return Generic netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
+{
+	struct genl_family *fam;
+
+	if (cache->c_ops != &genl_ctrl_ops)
+		BUG();
+
+	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+		if (fam->gf_id == id) {
+			nl_object_get((struct nl_object *) fam);
+			return fam;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * @name Resolver
+ * @{
+ */
+
+/**
+ * Look up generic netlink family by family name in the provided cache.
+ * @arg cache		Generic netlink family cache.
+ * @arg name		Family name.
+ *
+ * Searches through the cache looking for a registered family
+ * matching the specified name. The caller will own a reference
+ * on the returned object which needs to be given back after
+ * usage using genl_family_put().
+ *
+ * @return Generic netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
+					    const char *name)
+{
+	struct genl_family *fam;
+
+	if (cache->c_ops != &genl_ctrl_ops)
+		BUG();
+
+	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+		if (!strcmp(name, fam->gf_name)) {
+			nl_object_get((struct nl_object *) fam);
+			return fam;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * Resolve generic netlink family name to its identifier
+ * @arg sk		Netlink socket.
+ * @arg name		Name of generic netlink family
+ *
+ * Resolves the generic netlink family name to its identifer and returns
+ * it.
+ *
+ * @return A positive identifier or a negative error code.
+ */
+int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
+{
+	struct nl_cache *cache;
+	struct genl_family *family;
+	int err;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
+		return err;
+
+	family = genl_ctrl_search_by_name(cache, name);
+	if (family == NULL) {
+		err = -NLE_OBJ_NOTFOUND;
+		goto errout;
+	}
+
+	err = genl_family_get_id(family);
+	genl_family_put(family);
+errout:
+	nl_cache_free(cache);
+
+	return err;
+}
+
+static int genl_ctrl_grp_by_name(const struct genl_family *family,
+				const char *grp_name)
+{
+	struct genl_family_grp *grp;
+
+	nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
+		if (!strcmp(grp->name, grp_name)) {
+			return grp->id;
+		}
+	}
+
+	return -NLE_OBJ_NOTFOUND;
+}
+
+int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
+	const char *grp_name)
+{
+	struct nl_cache *cache;
+	struct genl_family *family;
+	int err;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
+		return err;
+
+	family = genl_ctrl_search_by_name(cache, family_name);
+	if (family == NULL) {
+		err = -NLE_OBJ_NOTFOUND;
+		goto errout;
+	}
+
+	err = genl_ctrl_grp_by_name(family, grp_name);
+	genl_family_put(family);
+errout:
+	nl_cache_free(cache);
+
+	return err;
+}
+
+/** @} */
+
+static struct genl_cmd genl_cmds[] = {
+	{
+		.c_id		= CTRL_CMD_NEWFAMILY,
+		.c_name		= "NEWFAMILY" ,
+		.c_maxattr	= CTRL_ATTR_MAX,
+		.c_attr_policy	= ctrl_policy,
+		.c_msg_parser	= ctrl_msg_parser,
+	},
+	{
+		.c_id		= CTRL_CMD_DELFAMILY,
+		.c_name		= "DELFAMILY" ,
+	},
+	{
+		.c_id		= CTRL_CMD_GETFAMILY,
+		.c_name		= "GETFAMILY" ,
+	},
+	{
+		.c_id		= CTRL_CMD_NEWOPS,
+		.c_name		= "NEWOPS" ,
+	},
+	{
+		.c_id		= CTRL_CMD_DELOPS,
+		.c_name		= "DELOPS" ,
+	},
+};
+
+static struct genl_ops genl_ops = {
+	.o_cmds			= genl_cmds,
+	.o_ncmds		= ARRAY_SIZE(genl_cmds),
+};
+
+/** @cond SKIP */
+extern struct nl_object_ops genl_family_ops;
+/** @endcond */
+
+static struct nl_cache_ops genl_ctrl_ops = {
+	.co_name		= "genl/family",
+	.co_hdrsize		= GENL_HDRSIZE(0),
+	.co_msgtypes		= GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
+	.co_genl		= &genl_ops,
+	.co_protocol		= NETLINK_GENERIC,
+	.co_request_update      = ctrl_request_update,
+	.co_obj_ops		= &genl_family_ops,
+};
+
+static void __init ctrl_init(void)
+{
+	genl_register(&genl_ctrl_ops);
+}
+
+static void __exit ctrl_exit(void)
+{
+	genl_unregister(&genl_ctrl_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/genl/family.c b/libnetwork/libnl3/lib/genl/family.c
new file mode 100644
index 0000000..ebeebcb
--- /dev/null
+++ b/libnetwork/libnl3/lib/genl/family.c
@@ -0,0 +1,316 @@
+/*
+ * lib/genl/family.c		Generic Netlink Family
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_family Generic Netlink Family
+ * @brief
+ *
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define FAMILY_ATTR_ID		0x01
+#define FAMILY_ATTR_NAME	0x02
+#define FAMILY_ATTR_VERSION	0x04
+#define FAMILY_ATTR_HDRSIZE	0x08
+#define FAMILY_ATTR_MAXATTR	0x10
+#define FAMILY_ATTR_OPS		0x20
+
+struct nl_object_ops genl_family_ops;
+/** @endcond */
+
+static void family_constructor(struct nl_object *c)
+{
+	struct genl_family *family = (struct genl_family *) c;
+
+	nl_init_list_head(&family->gf_ops);
+	nl_init_list_head(&family->gf_mc_grps);
+}
+
+static void family_free_data(struct nl_object *c)
+{
+	struct genl_family *family = (struct genl_family *) c;
+	struct genl_family_op *ops, *tmp;
+	struct genl_family_grp *grp, *t_grp;
+
+	if (family == NULL)
+		return;
+
+	nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
+		nl_list_del(&ops->o_list);
+		free(ops);
+	}
+
+	nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) {
+		nl_list_del(&grp->list);
+		free(grp);
+	}
+
+}
+
+static int family_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct genl_family *dst = nl_object_priv(_dst);
+	struct genl_family *src = nl_object_priv(_src);
+	struct genl_family_op *ops;
+	struct genl_family_grp *grp;
+	int err;
+
+	nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
+		err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
+		if (err < 0)
+			return err;
+	}
+
+	nl_list_for_each_entry(grp, &src->gf_mc_grps, list) {
+		err = genl_family_add_grp(dst, grp->id, grp->name);
+		if (err < 0)
+			return err;
+	}
+
+	
+	return 0;
+}
+
+static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct genl_family *family = (struct genl_family *) obj;
+
+	nl_dump(p, "0x%04x %s version %u\n",
+		family->gf_id, family->gf_name, family->gf_version);
+}
+
+static const struct trans_tbl ops_flags[] = {
+	__ADD(GENL_ADMIN_PERM, admin-perm)
+	__ADD(GENL_CMD_CAP_DO, has-doit)
+	__ADD(GENL_CMD_CAP_DUMP, has-dump)
+	__ADD(GENL_CMD_CAP_HASPOL, has-policy)
+};
+
+static char *ops_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags));
+}
+
+static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct genl_family_grp *grp;
+	struct genl_family *family = (struct genl_family *) obj;
+
+	family_dump_line(obj, p);
+	nl_dump_line(p, "    hdrsize %u maxattr %u\n",
+		     family->gf_hdrsize, family->gf_maxattr);
+
+	if (family->ce_mask & FAMILY_ATTR_OPS) {
+		struct genl_family_op *op;
+		char buf[64];
+
+		nl_list_for_each_entry(op, &family->gf_ops, o_list) {
+			ops_flags2str(op->o_flags, buf, sizeof(buf));
+
+			genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf));
+
+			nl_dump_line(p, "      op %s (0x%02x)", buf, op->o_id);
+
+			if (op->o_flags)
+				nl_dump(p, " <%s>",
+					ops_flags2str(op->o_flags, buf,
+						      sizeof(buf)));
+
+			nl_dump(p, "\n");
+		}
+	}
+
+	nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
+		nl_dump_line(p, "      grp %s (0x%02x)\n", grp->name, grp->id);
+	}
+
+}
+
+static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	family_dump_details(obj, p);
+}
+
+static int family_compare(struct nl_object *_a, struct nl_object *_b,
+			  uint32_t attrs, int flags)
+{
+	struct genl_family *a = (struct genl_family *) _a;
+	struct genl_family *b = (struct genl_family *) _b;
+	int diff = 0;
+
+#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= FAM_DIFF(ID,		a->gf_id != b->gf_id);
+	diff |= FAM_DIFF(VERSION,	a->gf_version != b->gf_version);
+	diff |= FAM_DIFF(HDRSIZE,	a->gf_hdrsize != b->gf_hdrsize);
+	diff |= FAM_DIFF(MAXATTR,	a->gf_maxattr != b->gf_maxattr);
+	diff |= FAM_DIFF(NAME,		strcmp(a->gf_name, b->gf_name));
+
+#undef FAM_DIFF
+
+	return diff;
+}
+
+
+/**
+ * @name Family Object
+ * @{
+ */
+
+struct genl_family *genl_family_alloc(void)
+{
+	return (struct genl_family *) nl_object_alloc(&genl_family_ops);
+}
+
+void genl_family_put(struct genl_family *family)
+{
+	nl_object_put((struct nl_object *) family);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+unsigned int genl_family_get_id(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_ID)
+		return family->gf_id;
+	else
+		return GENL_ID_GENERATE;
+}
+
+void genl_family_set_id(struct genl_family *family, unsigned int id)
+{
+	family->gf_id = id;
+	family->ce_mask |= FAMILY_ATTR_ID;
+}
+
+char *genl_family_get_name(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_NAME)
+		return family->gf_name;
+	else
+		return NULL;
+}
+
+void genl_family_set_name(struct genl_family *family, const char *name)
+{
+	strncpy(family->gf_name, name, GENL_NAMSIZ-1);
+	family->ce_mask |= FAMILY_ATTR_NAME;
+}
+
+uint8_t genl_family_get_version(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_VERSION)
+		return family->gf_version;
+	else
+		return 0;
+}
+
+void genl_family_set_version(struct genl_family *family, uint8_t version)
+{
+	family->gf_version = version;
+	family->ce_mask |= FAMILY_ATTR_VERSION;
+}
+
+uint32_t genl_family_get_hdrsize(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
+		return family->gf_hdrsize;
+	else
+		return 0;
+}
+
+void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
+{
+	family->gf_hdrsize = hdrsize;
+	family->ce_mask |= FAMILY_ATTR_HDRSIZE;
+}
+
+uint32_t genl_family_get_maxattr(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_MAXATTR)
+		return family->gf_maxattr;
+	else
+		return family->gf_maxattr;
+}
+
+void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
+{
+	family->gf_maxattr = maxattr;
+	family->ce_mask |= FAMILY_ATTR_MAXATTR;
+}
+
+int genl_family_add_op(struct genl_family *family, int id, int flags)
+{
+	struct genl_family_op *op;
+
+	op = calloc(1, sizeof(*op));
+	if (op == NULL)
+		return -NLE_NOMEM;
+
+	op->o_id = id;
+	op->o_flags = flags;
+
+	nl_list_add_tail(&op->o_list, &family->gf_ops);
+	family->ce_mask |= FAMILY_ATTR_OPS;
+
+	return 0;
+}
+
+int genl_family_add_grp(struct genl_family *family, uint32_t id,
+	       		const char *name)
+{
+	struct genl_family_grp *grp;  
+
+	grp = calloc(1, sizeof(*grp));
+	if (grp == NULL)
+		return -NLE_NOMEM;
+
+	grp->id = id;
+	strncpy(grp->name, name, GENL_NAMSIZ - 1);
+
+	nl_list_add_tail(&grp->list, &family->gf_mc_grps);
+
+	return 0;
+}
+
+/** @} */
+
+/** @cond SKIP */
+struct nl_object_ops genl_family_ops = {
+	.oo_name		= "genl/family",
+	.oo_size		= sizeof(struct genl_family),
+	.oo_constructor		= family_constructor,
+	.oo_free_data		= family_free_data,
+	.oo_clone		= family_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= family_dump_line,
+	    [NL_DUMP_DETAILS]	= family_dump_details,
+	    [NL_DUMP_STATS]	= family_dump_stats,
+	},
+	.oo_compare		= family_compare,
+	.oo_id_attrs		= FAMILY_ATTR_ID,
+};
+/** @endcond */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/genl/genl.c b/libnetwork/libnl3/lib/genl/genl.c
new file mode 100644
index 0000000..055be91
--- /dev/null
+++ b/libnetwork/libnl3/lib/genl/genl.c
@@ -0,0 +1,268 @@
+/*
+ * lib/genl/genl.c		Generic Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @defgroup genl Generic Netlink
+ *
+ * @par Message Format
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @code
+ *  <-------- GENL_HDRLEN -------> <--- hdrlen -->
+ *                                 <------- genlmsg_len(ghdr) ------>
+ * +------------------------+- - -+---------------+- - -+------------+
+ * | Generic Netlink Header | Pad | Family Header | Pad | Attributes |
+ * |    struct genlmsghdr   |     |               |     |            |
+ * +------------------------+- - -+---------------+- - -+------------+
+ * genlmsg_data(ghdr)--------------^                     ^
+ * genlmsg_attrdata(ghdr, hdrlen)-------------------------
+ * @endcode
+ *
+ * @par Example
+ * @code
+ * #include <netlink/netlink.h>
+ * #include <netlink/genl/genl.h>
+ * #include <netlink/genl/ctrl.h>
+ *
+ * struct nl_sock *sock;
+ * struct nl_msg *msg;
+ * int family;
+ *
+ * // Allocate a new netlink socket
+ * sock = nl_socket_alloc();
+ *
+ * // Connect to generic netlink socket on kernel side
+ * genl_connect(sock);
+ *
+ * // Ask kernel to resolve family name to family id
+ * family = genl_ctrl_resolve(sock, "generic_netlink_family_name");
+ *
+ * // Construct a generic netlink by allocating a new message, fill in
+ * // the header and append a simple integer attribute.
+ * msg = nlmsg_alloc();
+ * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO,
+ *             CMD_FOO_GET, FOO_VERSION);
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ *
+ * // Send message over netlink socket
+ * nl_send_auto_complete(sock, msg);
+ *
+ * // Free message
+ * nlmsg_free(msg);
+ *
+ * // Prepare socket to receive the answer by specifying the callback
+ * // function to be called for valid messages.
+ * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
+ *
+ * // Wait for the answer and receive it
+ * nl_recvmsgs_default(sock);
+ *
+ * static int parse_cb(struct nl_msg *msg, void *arg)
+ * {
+ *     struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ *     struct nlattr *attrs[ATTR_MAX+1];
+ *
+ *     // Validate message and parse attributes
+ *     genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy);
+ *
+ *     if (attrs[ATTR_FOO]) {
+ *         uint32_t value = nla_get_u32(attrs[ATTR_FOO]);
+ *         ...
+ *     }
+ *
+ *     return 0;
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Socket Creating
+ * @{
+ */
+
+int genl_connect(struct nl_sock *sk)
+{
+	return nl_connect(sk, NETLINK_GENERIC);
+}
+
+/** @} */
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send trivial generic netlink message
+ * @arg sk		Netlink socket.
+ * @arg family		Generic netlink family
+ * @arg cmd		Command
+ * @arg version		Version
+ * @arg flags		Additional netlink message flags.
+ *
+ * Fills out a routing netlink request message and sends it out
+ * using nl_send_simple().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_send_simple(struct nl_sock *sk, int family, int cmd,
+		     int version, int flags)
+{
+	struct genlmsghdr hdr = {
+		.cmd = cmd,
+		.version = version,
+	};
+
+	return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
+}
+
+/** @} */
+
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
+		return 0;
+
+	ghdr = nlmsg_data(nlh);
+	if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
+		return 0;
+
+	return 1;
+}
+
+int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+		   struct nla_policy *policy)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!genlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	ghdr = nlmsg_data(nlh);
+	return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
+			    genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
+}
+
+int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+		  int maxtype, struct nla_policy *policy)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!genlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	ghdr = nlmsg_data(nlh);
+	return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
+			 genlmsg_attrlen(ghdr, hdrlen), policy);
+}
+
+/**
+ * Get head of message payload
+ * @arg gnlh	genetlink messsage header
+ */
+void *genlmsg_data(const struct genlmsghdr *gnlh)
+{
+	return ((unsigned char *) gnlh + GENL_HDRLEN);
+}
+
+/**
+ * Get lenght of message payload
+ * @arg gnlh	genetlink message header
+ */
+int genlmsg_len(const struct genlmsghdr *gnlh)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
+							NLMSG_HDRLEN);
+	return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+/**
+ * Get head of attribute data
+ * @arg gnlh	generic netlink message header
+ * @arg hdrlen	length of family specific header
+ */
+struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen);
+}
+
+/**
+ * Get length of attribute data
+ * @arg gnlh	generic netlink message header
+ * @arg hdrlen	length of family specific header
+ */
+int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/** @} */
+
+/**
+ * @name Message Building
+ * @{
+ */
+
+/**
+ * Add generic netlink header to netlink message
+ * @arg msg		netlink message
+ * @arg pid		netlink process id or NL_AUTO_PID
+ * @arg seq		sequence number of message or NL_AUTO_SEQ
+ * @arg family		generic netlink family
+ * @arg hdrlen		length of user specific header
+ * @arg flags		message flags
+ * @arg cmd		generic netlink command
+ * @arg version		protocol version
+ *
+ * Returns pointer to user specific header.
+ */
+void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
+		  int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+	struct nlmsghdr *nlh;
+	struct genlmsghdr hdr = {
+		.cmd = cmd,
+		.version = version,
+	};
+
+	nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
+	if (nlh == NULL)
+		return NULL;
+
+	memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
+	NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
+	       msg, cmd, version);
+
+	return nlmsg_data(nlh) + GENL_HDRLEN;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/genl/mngt.c b/libnetwork/libnl3/lib/genl/mngt.c
new file mode 100644
index 0000000..0ebe74d
--- /dev/null
+++ b/libnetwork/libnl3/lib/genl/mngt.c
@@ -0,0 +1,273 @@
+/*
+ * lib/genl/mngt.c		Generic Netlink Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_mngt Management
+ *
+ * @par 1) Registering a generic netlink module
+ * @code
+ * #include <netlink/genl/mngt.h>
+ *
+ * // First step is to define all the commands being used in
+ * // particular generic netlink family. The ID and name are
+ * // mandatory to be filled out. A callback function and
+ * // most the attribute policy that comes with it must be
+ * // defined for commands expected to be issued towards
+ * // userspace.
+ * static struct genl_cmd foo_cmds[] = {
+ * 	{
+ * 		.c_id		= FOO_CMD_NEW,
+ * 		.c_name		= "NEWFOO" ,
+ * 		.c_maxattr	= FOO_ATTR_MAX,
+ * 		.c_attr_policy	= foo_policy,
+ * 		.c_msg_parser	= foo_msg_parser,
+ * 	},
+ * 	{
+ * 		.c_id		= FOO_CMD_DEL,
+ * 		.c_name		= "DELFOO" ,
+ * 	},
+ * };
+ *
+ * // The list of commands must then be integrated into a
+ * // struct genl_ops serving as handle for this particular
+ * // family.
+ * static struct genl_ops my_genl_ops = {
+ * 	.o_cmds			= foo_cmds,
+ * 	.o_ncmds		= ARRAY_SIZE(foo_cmds),
+ * };
+ *
+ * // Using the above struct genl_ops an arbitary number of
+ * // cache handles can be associated to it.
+ * //
+ * // The macro GENL_HDRSIZE() must be used to specify the
+ * // length of the header to automatically take headers on
+ * // generic layers into account.
+ * //
+ * // The macro GENL_FAMILY() is used to represent the generic
+ * // netlink family id.
+ * static struct nl_cache_ops genl_foo_ops = {
+ * 	.co_name		= "genl/foo",
+ * 	.co_hdrsize		= GENL_HDRSIZE(sizeof(struct my_hdr)),
+ * 	.co_msgtypes		= GENL_FAMILY(GENL_ID_GENERATE, "foo"),
+ * 	.co_genl		= &my_genl_ops,
+ * 	.co_protocol		= NETLINK_GENERIC,
+ * 	.co_request_update      = foo_request_update,
+ * 	.co_obj_ops		= &genl_foo_ops,
+ * };
+ *
+ * // Finally each cache handle for a generic netlink family
+ * // must be registered using genl_register().
+ * static void __init foo_init(void)
+ * {
+ * 	genl_register(&genl_foo_ops);
+ * }
+ *
+ * // ... respectively unregsted again.
+ * static void __exit foo_exit(void)
+ * {
+ * 	genl_unregister(&genl_foo_ops);
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+static NL_LIST_HEAD(genl_ops_list);
+
+static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			   struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	int i, err;
+	struct genlmsghdr *ghdr;
+	struct genl_cmd *cmd;
+
+	ghdr = nlmsg_data(nlh);
+
+	if (ops->co_genl == NULL)
+		BUG();
+
+	for (i = 0; i < ops->co_genl->o_ncmds; i++) {
+		cmd = &ops->co_genl->o_cmds[i];
+		if (cmd->c_id == ghdr->cmd)
+			goto found;
+	}
+
+	err = -NLE_MSGTYPE_NOSUPPORT;
+	goto errout;
+
+found:
+	if (cmd->c_msg_parser == NULL)
+		err = -NLE_OPNOTSUPP;
+	else {
+		struct nlattr *tb[cmd->c_maxattr + 1];
+		struct genl_info info = {
+			.who = who,
+			.nlh = nlh,
+			.genlhdr = ghdr,
+			.userhdr = genlmsg_data(ghdr),
+			.attrs = tb,
+		};
+
+		err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr,
+				  cmd->c_attr_policy);
+		if (err < 0)
+			goto errout;
+
+		err = cmd->c_msg_parser(ops, cmd, &info, pp);
+	}
+errout:
+	return err;
+
+}
+
+char *genl_op2name(int family, int op, char *buf, size_t len)
+{
+	struct genl_ops *ops;
+	int i;
+
+	nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
+		if (ops->o_family == family) {
+			for (i = 0; i < ops->o_ncmds; i++) {
+				struct genl_cmd *cmd;
+				cmd = &ops->o_cmds[i];
+
+				if (cmd->c_id == op) {
+					strncpy(buf, cmd->c_name, len - 1);
+					return buf;
+				}
+			}
+		}
+	}
+
+	strncpy(buf, "unknown", len - 1);
+	return NULL;
+}
+
+
+/**
+ * @name Register/Unregister
+ * @{
+ */
+
+/**
+ * Register generic netlink operations
+ * @arg ops		cache operations
+ */
+int genl_register(struct nl_cache_ops *ops)
+{
+	int err;
+
+	if (ops->co_protocol != NETLINK_GENERIC) {
+		err = -NLE_PROTO_MISMATCH;
+		goto errout;
+	}
+
+	if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
+		err = -NLE_INVAL;
+		goto errout;
+	}
+
+	if (ops->co_genl == NULL) {
+		err = -NLE_INVAL;
+		goto errout;
+	}
+
+	ops->co_genl->o_cache_ops = ops;
+	ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
+	ops->co_genl->o_family = ops->co_msgtypes[0].mt_id;
+	ops->co_msg_parser = genl_msg_parser;
+
+	/* FIXME: check for dup */
+
+	nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list);
+
+	err = nl_cache_mngt_register(ops);
+errout:
+	return err;
+}
+
+/**
+ * Unregister generic netlink operations
+ * @arg ops		cache operations
+ */
+void genl_unregister(struct nl_cache_ops *ops)
+{
+	nl_cache_mngt_unregister(ops);
+	nl_list_del(&ops->co_genl->o_list);
+}
+
+/** @} */
+
+/**
+ * @name Resolving ID/Name
+ * @{
+ */
+
+static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
+{
+	struct genl_family *family;
+
+	family = genl_ctrl_search_by_name(ctrl, ops->o_name);
+	if (family != NULL) {
+		ops->o_id = genl_family_get_id(family);
+		genl_family_put(family);
+
+		return 0;
+	}
+
+	return -NLE_OBJ_NOTFOUND;
+}
+
+int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops)
+{
+	struct nl_cache *ctrl;
+	int err;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
+		goto errout;
+
+	err = __genl_ops_resolve(ctrl, ops);
+
+	nl_cache_free(ctrl);
+errout:
+	return err;
+}
+
+int genl_mngt_resolve(struct nl_sock *sk)
+{
+	struct nl_cache *ctrl;
+	struct genl_ops *ops;
+	int err = 0;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
+		goto errout;
+
+	nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
+		err = __genl_ops_resolve(ctrl, ops);
+	}
+
+	nl_cache_free(ctrl);
+errout:
+	return err;
+}
+
+/** @} */
+
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/handlers.c b/libnetwork/libnl3/lib/handlers.c
new file mode 100644
index 0000000..f13b89e
--- /dev/null
+++ b/libnetwork/libnl3/lib/handlers.c
@@ -0,0 +1,395 @@
+/*
+ * lib/handlers.c	default netlink message handlers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cb Callbacks/Customization
+ *
+ * @details
+ * @par 1) Setting up a callback set
+ * @code
+ * // Allocate a callback set and initialize it to the verbose default set
+ * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
+ *
+ * // Modify the set to call my_func() for all valid messages
+ * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
+ *
+ * // Set the error message handler to the verbose default implementation
+ * // and direct it to print all errors to the given file descriptor.
+ * FILE *file = fopen(...);
+ * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/msg.h>
+#include <netlink/handlers.h>
+
+static void print_header_content(FILE *ofd, struct nlmsghdr *n)
+{
+	char flags[128];
+	char type[32];
+	
+	fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
+		nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
+		n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
+		sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
+}
+
+static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stdout;
+
+	fprintf(ofd, "-- Warning: unhandled valid message: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+
+	return NL_OK;
+}
+
+static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Error: Invalid message: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+
+	return NL_STOP;
+}
+
+static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Error: Netlink Overrun: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+	
+	return NL_STOP;
+}
+
+static int nl_error_handler_verbose(struct sockaddr_nl *who,
+				    struct nlmsgerr *e, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Error received: %s\n-- Original message: ",
+		strerror(-e->error));
+	print_header_content(ofd, &e->msg);
+	fprintf(ofd, "\n");
+
+	return -nl_syserr2nlerr(e->error);
+}
+
+static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: Unhandled Valid message: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+
+	return NL_OK;
+}
+
+static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: End of multipart message block: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+	
+	return NL_STOP;
+}
+
+static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: Received Message:\n");
+	nl_msg_dump(msg, ofd);
+	
+	return NL_OK;
+}
+
+static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: Sent Message:\n");
+	nl_msg_dump(msg, ofd);
+
+	return NL_OK;
+}
+
+static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: Skipped message: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+
+	return NL_SKIP;
+}
+
+static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
+{
+	FILE *ofd = arg ? arg : stderr;
+
+	fprintf(ofd, "-- Debug: ACK: ");
+	print_header_content(ofd, nlmsg_hdr(msg));
+	fprintf(ofd, "\n");
+
+	return NL_STOP;
+}
+
+static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
+	[NL_CB_VALID] = {
+		[NL_CB_VERBOSE]	= nl_valid_handler_verbose,
+		[NL_CB_DEBUG]	= nl_valid_handler_debug,
+	},
+	[NL_CB_FINISH] = {
+		[NL_CB_DEBUG]	= nl_finish_handler_debug,
+	},
+	[NL_CB_INVALID] = {
+		[NL_CB_VERBOSE]	= nl_invalid_handler_verbose,
+		[NL_CB_DEBUG]	= nl_invalid_handler_verbose,
+	},
+	[NL_CB_MSG_IN] = {
+		[NL_CB_DEBUG]	= nl_msg_in_handler_debug,
+	},
+	[NL_CB_MSG_OUT] = {
+		[NL_CB_DEBUG]	= nl_msg_out_handler_debug,
+	},
+	[NL_CB_OVERRUN] = {
+		[NL_CB_VERBOSE]	= nl_overrun_handler_verbose,
+		[NL_CB_DEBUG]	= nl_overrun_handler_verbose,
+	},
+	[NL_CB_SKIPPED] = {
+		[NL_CB_DEBUG]	= nl_skipped_handler_debug,
+	},
+	[NL_CB_ACK] = {
+		[NL_CB_DEBUG]	= nl_ack_handler_debug,
+	},
+};
+
+static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
+	[NL_CB_VERBOSE]	= nl_error_handler_verbose,
+	[NL_CB_DEBUG]	= nl_error_handler_verbose,
+};
+
+/**
+ * @name Callback Handle Management
+ * @{
+ */
+
+/**
+ * Allocate a new callback handle
+ * @arg kind		callback kind to be used for initialization
+ * @return Newly allocated callback handle or NULL
+ */
+struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
+{
+	int i;
+	struct nl_cb *cb;
+
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return NULL;
+
+	cb = calloc(1, sizeof(*cb));
+	if (!cb)
+		return NULL;
+
+	cb->cb_refcnt = 1;
+
+	for (i = 0; i <= NL_CB_TYPE_MAX; i++)
+		nl_cb_set(cb, i, kind, NULL, NULL);
+
+	nl_cb_err(cb, kind, NULL, NULL);
+
+	return cb;
+}
+
+/**
+ * Clone an existing callback handle
+ * @arg orig		original callback handle
+ * @return Newly allocated callback handle being a duplicate of
+ *         orig or NULL
+ */
+struct nl_cb *nl_cb_clone(struct nl_cb *orig)
+{
+	struct nl_cb *cb;
+	
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!cb)
+		return NULL;
+
+	memcpy(cb, orig, sizeof(*orig));
+	cb->cb_refcnt = 1;
+
+	return cb;
+}
+
+struct nl_cb *nl_cb_get(struct nl_cb *cb)
+{
+	cb->cb_refcnt++;
+
+	return cb;
+}
+
+void nl_cb_put(struct nl_cb *cb)
+{
+	if (!cb)
+		return;
+
+	cb->cb_refcnt--;
+
+	if (cb->cb_refcnt < 0)
+		BUG();
+
+	if (cb->cb_refcnt <= 0)
+		free(cb);
+}
+
+/** @} */
+
+/**
+ * @name Callback Setup
+ * @{
+ */
+
+/**
+ * Set up a callback 
+ * @arg cb		callback set
+ * @arg type		callback to modify
+ * @arg kind		kind of implementation
+ * @arg func		callback function (NL_CB_CUSTOM)
+ * @arg arg		argument passed to callback
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
+	      nl_recvmsg_msg_cb_t func, void *arg)
+{
+	if (type < 0 || type > NL_CB_TYPE_MAX)
+		return -NLE_RANGE;
+
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return -NLE_RANGE;
+
+	if (kind == NL_CB_CUSTOM) {
+		cb->cb_set[type] = func;
+		cb->cb_args[type] = arg;
+	} else {
+		cb->cb_set[type] = cb_def[type][kind];
+		cb->cb_args[type] = arg;
+	}
+
+	return 0;
+}
+
+/**
+ * Set up a all callbacks
+ * @arg cb		callback set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passwd to callback function
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
+		  nl_recvmsg_msg_cb_t func, void *arg)
+{
+	int i, err;
+
+	for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
+		err = nl_cb_set(cb, i, kind, func, arg);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * Set up an error callback
+ * @arg cb		callback set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passed to callback function
+ */
+int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
+	      nl_recvmsg_err_cb_t func, void *arg)
+{
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return -NLE_RANGE;
+
+	if (kind == NL_CB_CUSTOM) {
+		cb->cb_err = func;
+		cb->cb_err_arg = arg;
+	} else {
+		cb->cb_err = cb_err_def[kind];
+		cb->cb_err_arg = arg;
+	}
+
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Overwriting
+ * @{
+ */
+
+/**
+ * Overwrite internal calls to nl_recvmsgs()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_recvmsgs()
+ */
+void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
+			      int (*func)(struct nl_sock *, struct nl_cb *))
+{
+	cb->cb_recvmsgs_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_recv()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_recv()
+ */
+void nl_cb_overwrite_recv(struct nl_cb *cb,
+			  int (*func)(struct nl_sock *, struct sockaddr_nl *,
+				      unsigned char **, struct ucred **))
+{
+	cb->cb_recv_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_send()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_send()
+ */
+void nl_cb_overwrite_send(struct nl_cb *cb,
+			  int (*func)(struct nl_sock *, struct nl_msg *))
+{
+	cb->cb_send_ow = func;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/msg.c b/libnetwork/libnl3/lib/msg.c
new file mode 100644
index 0000000..235ee82
--- /dev/null
+++ b/libnetwork/libnl3/lib/msg.c
@@ -0,0 +1,1050 @@
+/*
+ * lib/msg.c		Netlink Messages Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup msg Messages
+ * Netlink Message Construction/Parsing Interface
+ * 
+ * The following information is partly extracted from RFC3549
+ * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt)
+ *
+ * @par Message Format
+ * Netlink messages consist of a byte stream with one or multiple
+ * Netlink headers and an associated payload.  If the payload is too big
+ * to fit into a single message it, can be split over multiple Netlink
+ * messages, collectively called a multipart message.  For multipart
+ * messages, the first and all following headers have the \c NLM_F_MULTI
+ * Netlink header flag set, except for the last header which has the
+ * Netlink header type \c NLMSG_DONE.
+ *
+ * @par
+ * The Netlink message header (struct nlmsghdr) is shown below.
+ * @code   
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Length                             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            Type              |           Flags              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Sequence Number                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Process ID (PID)                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * @endcode
+ *
+ * @par
+ * The netlink message header and payload must be aligned properly:
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @par
+ * Message Format:
+ * @code
+ *    <--- nlmsg_total_size(payload)  --->
+ *    <-- nlmsg_msg_size(payload) ->
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   nlmsg_data(nlh)---^                   ^
+ *   nlmsg_next(nlh)-----------------------+
+ * @endcode
+ * @par
+ * The payload may consist of arbitary data but may have strict
+ * alignment and formatting rules depening on the specific netlink
+ * families.
+ * @par
+ * @code
+ *    <---------------------- nlmsg_len(nlh) --------------------->
+ *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
+ *   +----------------------+- - -+--------------------------------+
+ *   |     Family Header    | Pad |           Attributes           |
+ *   +----------------------+- - -+--------------------------------+
+ *   nlmsg_attrdata(nlh, hdrlen)---^
+ * @endcode
+ * @par The ACK Netlink Message
+ * This message is actually used to denote both an ACK and a NACK.
+ * Typically, the direction is from FEC to CPC (in response to an ACK
+ * request message).  However, the CPC should be able to send ACKs back
+ * to FEC when requested.
+ * @code
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Netlink message header                  |
+ * |                       type = NLMSG_ERROR                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Error code                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       OLD Netlink message header              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * @endcode
+ *
+ * @par Example
+ * @code
+ * // Various methods exist to create/allocate a new netlink
+ * // message. 
+ * //
+ * // nlmsg_alloc() will allocate an empty netlink message with
+ * // a maximum payload size which defaults to the page size of
+ * // the system. This default size can be modified using the
+ * // function nlmsg_set_default_size().
+ * struct nl_msg *msg = nlmsg_alloc();
+ *
+ * // Very often, the message type and message flags are known
+ * // at allocation time while the other fields are auto generated:
+ * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS);
+ *
+ * // Alternatively an existing netlink message header can be used
+ * // to inherit the header values:
+ * struct nlmsghdr hdr = {
+ * 	.nlmsg_type = MY_TYPE,
+ * 	.nlmsg_flags = MY_FLAGS,
+ * };
+ * struct nl_msg *msg = nlmsg_inherit(&hdr);
+ *
+ * // Last but not least, netlink messages received from netlink sockets
+ * // can be converted into nl_msg objects using nlmsg_convert(). This
+ * // will create a message with a maximum payload size which equals the
+ * // length of the existing netlink message, therefore no more data can
+ * // be appened without calling nlmsg_expand() first.
+ * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock);
+ *
+ * // Payload may be added to the message via nlmsg_append(). The fourth
+ * // parameter specifies the number of alignment bytes the data should
+ * // be padding with at the end. Common values are 0 to disable it or
+ * // NLMSG_ALIGNTO to ensure proper netlink message padding.
+ * nlmsg_append(msg, &mydata, sizeof(mydata), 0);
+ *
+ * // Sometimes it may be necessary to reserve room for data but defer
+ * // the actual copying to a later point, nlmsg_reserve() can be used
+ * // for this purpose:
+ * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO);
+ *
+ * // Attributes may be added using the attributes interface.
+ *
+ * // After successful use of the message, the memory must be freed
+ * // using nlmsg_free()
+ * nlmsg_free(msg);
+ * @endcode
+ * 
+ * @par 4) Parsing messages
+ * @code
+ * int n;
+ * unsigned char *buf;
+ * struct nlmsghdr *hdr;
+ *
+ * n = nl_recv(handle, NULL, &buf);
+ * 
+ * hdr = (struct nlmsghdr *) buf;
+ * while (nlmsg_ok(hdr, n)) {
+ * 	// Process message here...
+ * 	hdr = nlmsg_next(hdr, &n);
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/cache.h>
+#include <netlink/attr.h>
+#include <linux/socket.h>
+
+static size_t default_msg_size;
+
+static void __init init_msg_size(void)
+{
+	default_msg_size = getpagesize();
+}
+
+/**
+ * @name Size Calculations
+ * @{
+ */
+
+/**
+ * Calculates size of netlink message based on payload length.
+ * @arg payload		Length of payload
+ *
+ * @return size of netlink message without padding.
+ */
+int nlmsg_size(int payload)
+{
+	return NLMSG_HDRLEN + payload;
+}
+
+static int nlmsg_msg_size(int payload)
+{
+	return nlmsg_size(payload);
+}
+
+/**
+ * Calculates size of netlink message including padding based on payload length
+ * @arg payload		Length of payload
+ *
+ * This function is idential to nlmsg_size() + nlmsg_padlen().
+ *
+ * @return Size of netlink message including padding.
+ */
+int nlmsg_total_size(int payload)
+{
+	return NLMSG_ALIGN(nlmsg_msg_size(payload));
+}
+
+/**
+ * Size of padding that needs to be added at end of message
+ * @arg payload		Length of payload
+ *
+ * Calculates the number of bytes of padding which is required to be added to
+ * the end of the message to ensure that the next netlink message header begins
+ * properly aligned to NLMSG_ALIGNTO.
+ *
+ * @return Number of bytes of padding needed.
+ */
+int nlmsg_padlen(int payload)
+{
+	return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
+}
+
+/** @} */
+
+/**
+ * @name Access to Message Payload
+ * @{
+ */
+
+/**
+ * Return pointer to message payload
+ * @arg nlh		Netlink message header
+ *
+ * @return Pointer to start of message payload.
+ */
+void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_HDRLEN;
+}
+
+void *nlmsg_tail(const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+}
+
+/**
+ * Return length of message payload
+ * @arg nlh		Netlink message header
+ *
+ * @return Length of message payload in bytes.
+ */
+int nlmsg_datalen(const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+static int nlmsg_len(const struct nlmsghdr *nlh)
+{
+	return nlmsg_datalen(nlh);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * head of attributes data
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ */
+struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
+{
+	unsigned char *data = nlmsg_data(nlh);
+	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+}
+
+/**
+ * length of attributes data
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ */
+int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+	return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
+{
+	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+		return 0;
+
+	return 1;
+}
+
+/**
+ * check if the netlink message fits into the remaining bytes
+ * @arg nlh		netlink message header
+ * @arg remaining	number of bytes remaining in message stream
+ */
+int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
+{
+	return (remaining >= (int)sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len <= remaining);
+}
+
+/**
+ * next netlink message in message stream
+ * @arg nlh		netlink message header
+ * @arg remaining	number of bytes remaining in message stream
+ *
+ * @returns the next netlink message in the message stream and
+ * decrements remaining by the size of the current message.
+ */
+struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+	*remaining -= totlen;
+
+	return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
+}
+
+/**
+ * parse attributes of a netlink message
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ * @arg tb		destination array with maxtype+1 elements
+ * @arg maxtype		maximum attribute type to be expected
+ * @arg policy		validation policy
+ *
+ * See nla_parse()
+ */
+int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+		int maxtype, struct nla_policy *policy)
+{
+	if (!nlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
+			 nlmsg_attrlen(nlh, hdrlen), policy);
+}
+
+/**
+ * nlmsg_find_attr - find a specific attribute in a netlink message
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of familiy specific header
+ * @arg attrtype	type of attribute to look for
+ *
+ * Returns the first attribute which matches the specified type.
+ */
+struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
+{
+	return nla_find(nlmsg_attrdata(nlh, hdrlen),
+			nlmsg_attrlen(nlh, hdrlen), attrtype);
+}
+
+/**
+ * nlmsg_validate - validate a netlink message including attributes
+ * @arg nlh		netlinket message header
+ * @arg hdrlen		length of familiy specific header
+ * @arg maxtype		maximum attribute type to be expected
+ * @arg policy		validation policy
+ */
+int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+		   struct nla_policy *policy)
+{
+	if (!nlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	return nla_validate(nlmsg_attrdata(nlh, hdrlen),
+			    nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
+}
+
+/** @} */
+
+/**
+ * @name Message Building/Access
+ * @{
+ */
+
+static struct nl_msg *__nlmsg_alloc(size_t len)
+{
+	struct nl_msg *nm;
+
+	if (len < sizeof(struct nlmsghdr))
+		len = sizeof(struct nlmsghdr);
+
+	nm = calloc(1, sizeof(*nm));
+	if (!nm)
+		goto errout;
+
+	nm->nm_refcnt = 1;
+
+	nm->nm_nlh = calloc(1, len);
+	if (!nm->nm_nlh)
+		goto errout;
+
+	memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
+
+	nm->nm_protocol = -1;
+	nm->nm_size = len;
+	nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
+
+	NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
+
+	return nm;
+errout:
+	free(nm);
+	return NULL;
+}
+
+/**
+ * Allocate a new netlink message with the default maximum payload size.
+ *
+ * Allocates a new netlink message without any further payload. The
+ * maximum payload size defaults to PAGESIZE or as otherwise specified
+ * with nlmsg_set_default_size().
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc(void)
+{
+	return __nlmsg_alloc(default_msg_size);
+}
+
+/**
+ * Allocate a new netlink message with maximum payload size specified.
+ */
+struct nl_msg *nlmsg_alloc_size(size_t max)
+{
+	return __nlmsg_alloc(max);
+}
+
+/**
+ * Allocate a new netlink message and inherit netlink message header
+ * @arg hdr		Netlink message header template
+ *
+ * Allocates a new netlink message and inherits the original message
+ * header. If \a hdr is not NULL it will be used as a template for
+ * the netlink message header, otherwise the header is left blank.
+ * 
+ * @return Newly allocated netlink message or NULL
+ */ 
+struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
+{
+	struct nl_msg *nm;
+
+	nm = nlmsg_alloc();
+	if (nm && hdr) {
+		struct nlmsghdr *new = nm->nm_nlh;
+
+		new->nlmsg_type = hdr->nlmsg_type;
+		new->nlmsg_flags = hdr->nlmsg_flags;
+		new->nlmsg_seq = hdr->nlmsg_seq;
+		new->nlmsg_pid = hdr->nlmsg_pid;
+	}
+
+	return nm;
+}
+
+/**
+ * Allocate a new netlink message
+ * @arg nlmsgtype	Netlink message type
+ * @arg flags		Message flags.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
+{
+	struct nl_msg *msg;
+	struct nlmsghdr nlh = {
+		.nlmsg_type = nlmsgtype,
+		.nlmsg_flags = flags,
+	};
+
+	msg = nlmsg_inherit(&nlh);
+	if (msg)
+		NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
+
+	return msg;
+}
+
+/**
+ * Set the default maximum message payload size for allocated messages
+ * @arg max		Size of payload in bytes.
+ */
+void nlmsg_set_default_size(size_t max)
+{
+	if (max < nlmsg_total_size(0))
+		max = nlmsg_total_size(0);
+
+	default_msg_size = max;
+}
+
+/**
+ * Convert a netlink message received from a netlink socket to a nl_msg
+ * @arg hdr		Netlink message received from netlink socket.
+ *
+ * Allocates a new netlink message and copies all of the data pointed to
+ * by \a hdr into the new message object.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
+{
+	struct nl_msg *nm;
+
+	nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
+	if (!nm)
+		goto errout;
+
+	memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
+
+	return nm;
+errout:
+	nlmsg_free(nm);
+	return NULL;
+}
+
+/**
+ * Reserve room for additional data in a netlink message
+ * @arg n		netlink message
+ * @arg len		length of additional data to reserve room for
+ * @arg pad		number of bytes to align data to
+ *
+ * Reserves room for additional data at the tail of the an
+ * existing netlink message. Eventual padding required will
+ * be zeroed out.
+ *
+ * @return Pointer to start of additional data tailroom or NULL.
+ */
+void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
+{
+	void *buf = n->nm_nlh;
+	size_t nlmsg_len = n->nm_nlh->nlmsg_len;
+	size_t tlen;
+
+	tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
+
+	if ((tlen + nlmsg_len) > n->nm_size)
+		return NULL;
+
+	buf += nlmsg_len;
+	n->nm_nlh->nlmsg_len += tlen;
+
+	if (tlen > len)
+		memset(buf + len, 0, tlen - len);
+
+	NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n",
+		  n, tlen, len, pad, n->nm_nlh->nlmsg_len);
+
+	return buf;
+}
+
+/**
+ * Append data to tail of a netlink message
+ * @arg n		netlink message
+ * @arg data		data to add
+ * @arg len		length of data
+ * @arg pad		Number of bytes to align data to.
+ *
+ * Extends the netlink message as needed and appends the data of given
+ * length to the message. 
+ *
+ * @return 0 on success or a negative error code
+ */
+int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
+{
+	void *tmp;
+
+	tmp = nlmsg_reserve(n, len, pad);
+	if (tmp == NULL)
+		return -NLE_NOMEM;
+
+	memcpy(tmp, data, len);
+	NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
+
+	return 0;
+}
+
+/**
+ * Expand maximum payload size of a netlink message
+ * @arg n		Netlink message.
+ * @arg newlen		New maximum payload size.
+ *
+ * Reallocates the payload section of a netlink message and increases
+ * the maximum payload size of the message.
+ *
+ * @note Any pointers pointing to old payload block will be stale and
+ *       need to be refetched. Therfore, do not expand while constructing
+ *       nested attributes or while reserved data blocks are held.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nlmsg_expand(struct nl_msg *n, size_t newlen)
+{
+	void *tmp;
+
+	if (newlen <= n->nm_size)
+		return -NLE_INVAL;
+
+	tmp = realloc(n->nm_nlh, newlen);
+	if (tmp == NULL)
+		return -NLE_NOMEM;
+
+	n->nm_nlh = tmp;
+	n->nm_size = newlen;
+
+	return 0;
+}
+
+/**
+ * Add a netlink message header to a netlink message
+ * @arg n		netlink message
+ * @arg pid		netlink process id or NL_AUTO_PID
+ * @arg seq		sequence number of message or NL_AUTO_SEQ
+ * @arg type		message type
+ * @arg payload		length of message payload
+ * @arg flags		message flags
+ *
+ * Adds or overwrites the netlink message header in an existing message
+ * object. If \a payload is greater-than zero additional room will be
+ * reserved, f.e. for family specific headers. It can be accesed via
+ * nlmsg_data().
+ *
+ * @return A pointer to the netlink message header or NULL.
+ */
+struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
+			   int type, int payload, int flags)
+{
+	struct nlmsghdr *nlh;
+
+	if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
+		BUG();
+
+	nlh = (struct nlmsghdr *) n->nm_nlh;
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_flags = flags;
+	nlh->nlmsg_pid = pid;
+	nlh->nlmsg_seq = seq;
+
+	NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
+		  "seq=%d\n", n, type, flags, pid, seq);
+
+	if (payload > 0 &&
+	    nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
+		return NULL;
+
+	return nlh;
+}
+
+/**
+ * Return actual netlink message
+ * @arg n		netlink message
+ * 
+ * Returns the actual netlink message casted to the type of the netlink
+ * message header.
+ * 
+ * @return A pointer to the netlink message.
+ */
+struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
+{
+	return n->nm_nlh;
+}
+
+/**
+ * Acquire a reference on a netlink message
+ * @arg msg		message to acquire reference from
+ */
+void nlmsg_get(struct nl_msg *msg)
+{
+	msg->nm_refcnt++;
+	NL_DBG(4, "New reference to message %p, total %d\n",
+	       msg, msg->nm_refcnt);
+}
+
+/**
+ * Release a reference from an netlink message
+ * @arg msg		message to release reference from
+ *
+ * Frees memory after the last reference has been released.
+ */
+void nlmsg_free(struct nl_msg *msg)
+{
+	if (!msg)
+		return;
+
+	msg->nm_refcnt--;
+	NL_DBG(4, "Returned message reference %p, %d remaining\n",
+	       msg, msg->nm_refcnt);
+
+	if (msg->nm_refcnt < 0)
+		BUG();
+
+	if (msg->nm_refcnt <= 0) {
+		free(msg->nm_nlh);
+		free(msg);
+		NL_DBG(2, "msg %p: Freed\n", msg);
+	}
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nlmsg_set_proto(struct nl_msg *msg, int protocol)
+{
+	msg->nm_protocol = protocol;
+}
+
+int nlmsg_get_proto(struct nl_msg *msg)
+{
+	return msg->nm_protocol;
+}
+
+size_t nlmsg_get_max_size(struct nl_msg *msg)
+{
+	return msg->nm_size;
+}
+
+void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+	memcpy(&msg->nm_src, addr, sizeof(*addr));
+}
+
+struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
+{
+	return &msg->nm_src;
+}
+
+void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+	memcpy(&msg->nm_dst, addr, sizeof(*addr));
+}
+
+struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
+{
+	return &msg->nm_dst;
+}
+
+void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
+{
+	memcpy(&msg->nm_creds, creds, sizeof(*creds));
+	msg->nm_flags |= NL_MSG_CRED_PRESENT;
+}
+
+struct ucred *nlmsg_get_creds(struct nl_msg *msg)
+{
+	if (msg->nm_flags & NL_MSG_CRED_PRESENT)
+		return &msg->nm_creds;
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Netlink Message Type Translations
+ * @{
+ */
+
+static const struct trans_tbl nl_msgtypes[] = {
+	__ADD(NLMSG_NOOP,NOOP)
+	__ADD(NLMSG_ERROR,ERROR)
+	__ADD(NLMSG_DONE,DONE)
+	__ADD(NLMSG_OVERRUN,OVERRUN)
+};
+
+char *nl_nlmsgtype2str(int type, char *buf, size_t size)
+{
+	return __type2str(type, buf, size, nl_msgtypes,
+			  ARRAY_SIZE(nl_msgtypes));
+}
+
+int nl_str2nlmsgtype(const char *name)
+{
+	return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
+}
+
+/** @} */
+
+/**
+ * @name Netlink Message Flags Translations
+ * @{
+ */
+
+char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
+{
+	memset(buf, 0, len);
+
+#define PRINT_FLAG(f) \
+	if (flags & NLM_F_##f) { \
+		flags &= ~NLM_F_##f; \
+		strncat(buf, #f, len - strlen(buf) - 1); \
+		if (flags) \
+			strncat(buf, ",", len - strlen(buf) - 1); \
+	}
+	
+	PRINT_FLAG(REQUEST);
+	PRINT_FLAG(MULTI);
+	PRINT_FLAG(ACK);
+	PRINT_FLAG(ECHO);
+	PRINT_FLAG(ROOT);
+	PRINT_FLAG(MATCH);
+	PRINT_FLAG(ATOMIC);
+	PRINT_FLAG(REPLACE);
+	PRINT_FLAG(EXCL);
+	PRINT_FLAG(CREATE);
+	PRINT_FLAG(APPEND);
+
+	if (flags) {
+		char s[32];
+		snprintf(s, sizeof(s), "0x%x", flags);
+		strncat(buf, s, len - strlen(buf) - 1);
+	}
+#undef PRINT_FLAG
+
+	return buf;
+}
+
+/** @} */
+
+/**
+ * @name Direct Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+struct dp_xdata {
+	void (*cb)(struct nl_object *, void *);
+	void *arg;
+};
+/** @endcond */
+
+static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
+{
+	struct dp_xdata *x = p->pp_arg;
+
+	x->cb(obj, x->arg);
+	return 0;
+}
+
+int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
+		 void *arg)
+{
+	struct nl_cache_ops *ops;
+	struct nl_parser_param p = {
+		.pp_cb = parse_cb
+	};
+	struct dp_xdata x = {
+		.cb = cb,
+		.arg = arg,
+	};
+
+	ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
+				     nlmsg_hdr(msg)->nlmsg_type);
+	if (ops == NULL)
+		return -NLE_MSGTYPE_NOSUPPORT;
+	p.pp_arg = &x;
+
+	return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/** @} */
+
+/**
+ * @name Dumping
+ * @{
+ */
+
+static void prefix_line(FILE *ofd, int prefix)
+{
+	int i;
+
+	for (i = 0; i < prefix; i++)
+		fprintf(ofd, "  ");
+}
+
+static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
+{
+	int i, a, c, limit;
+	char ascii[21] = {0};
+
+	limit = 18 - (prefix * 2);
+	prefix_line(ofd, prefix);
+	fprintf(ofd, "    ");
+
+	for (i = 0, a = 0, c = 0; i < len; i++) {
+		int v = *(uint8_t *) (start + i);
+
+		fprintf(ofd, "%02x ", v);
+		ascii[a++] = isprint(v) ? v : '.';
+
+		if (c == limit-1) {
+			fprintf(ofd, "%s\n", ascii);
+			if (i < (len - 1)) {
+				prefix_line(ofd, prefix);
+				fprintf(ofd, "    ");
+			}
+			a = c = 0;
+			memset(ascii, 0, sizeof(ascii));
+		} else
+			c++;
+	}
+
+	if (c != 0) {
+		for (i = 0; i < (limit - c); i++)
+			fprintf(ofd, "   ");
+		fprintf(ofd, "%s\n", ascii);
+	}
+}
+
+static void print_hdr(FILE *ofd, struct nl_msg *msg)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(msg);
+	struct nl_cache_ops *ops;
+	struct nl_msgtype *mt;
+	char buf[128];
+
+	fprintf(ofd, "    .nlmsg_len = %d\n", nlh->nlmsg_len);
+
+	ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
+	if (ops) {
+		mt = nl_msgtype_lookup(ops, nlh->nlmsg_type);
+		if (!mt)
+			BUG();
+
+		snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name);
+	} else
+		nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
+
+	fprintf(ofd, "    .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf);
+	fprintf(ofd, "    .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
+		nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
+	fprintf(ofd, "    .nlmsg_seq = %d\n", nlh->nlmsg_seq);
+	fprintf(ofd, "    .nlmsg_pid = %d\n", nlh->nlmsg_pid);
+
+}
+
+static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
+		       int prefix)
+{
+	int rem;
+	struct nlattr *nla;
+
+	nla_for_each_attr(nla, attrs, attrlen, rem) {
+		int padlen, alen = nla_len(nla);
+
+		prefix_line(ofd, prefix);
+		fprintf(ofd, "  [ATTR %02d%s] %d octets\n", nla_type(nla),
+			nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
+			alen);
+
+		if (nla->nla_type & NLA_F_NESTED)
+			dump_attrs(ofd, nla_data(nla), alen, prefix+1);
+		else
+			dump_hex(ofd, nla_data(nla), alen, prefix);
+
+		padlen = nla_padlen(alen);
+		if (padlen > 0) {
+			prefix_line(ofd, prefix);
+			fprintf(ofd, "  [PADDING] %d octets\n",
+				padlen);
+			dump_hex(ofd, nla_data(nla) + alen,
+				 padlen, prefix);
+		}
+	}
+
+	if (rem) {
+		prefix_line(ofd, prefix);
+		fprintf(ofd, "  [LEFTOVER] %d octets\n", rem);
+	}
+}
+
+/**
+ * Dump message in human readable format to file descriptor
+ * @arg msg		Message to print
+ * @arg ofd		File descriptor.
+ */
+void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
+{
+	struct nlmsghdr *hdr = nlmsg_hdr(msg);
+	
+	fprintf(ofd, 
+	"--------------------------   BEGIN NETLINK MESSAGE "
+	"---------------------------\n");
+
+	fprintf(ofd, "  [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
+	print_hdr(ofd, msg);
+
+	if (hdr->nlmsg_type == NLMSG_ERROR &&
+	    hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
+		struct nl_msg *errmsg;
+		struct nlmsgerr *err = nlmsg_data(hdr);
+
+		fprintf(ofd, "  [ERRORMSG] %Zu octets\n", sizeof(*err));
+		fprintf(ofd, "    .error = %d \"%s\"\n", err->error,
+			strerror(-err->error));
+		fprintf(ofd, "  [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
+
+		errmsg = nlmsg_inherit(&err->msg);
+		print_hdr(ofd, errmsg);
+		nlmsg_free(errmsg);
+	} else if (nlmsg_len(hdr) > 0) {
+		struct nl_cache_ops *ops;
+		int payloadlen = nlmsg_len(hdr);
+		int attrlen = 0;
+
+		ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
+					     hdr->nlmsg_type);
+		if (ops) {
+			attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
+			payloadlen -= attrlen;
+		}
+
+		fprintf(ofd, "  [PAYLOAD] %d octets\n", payloadlen);
+		dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
+
+		if (attrlen) {
+			struct nlattr *attrs;
+			int attrlen;
+			
+			attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
+			attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
+			dump_attrs(ofd, attrs, attrlen, 0);
+		}
+	}
+
+	fprintf(ofd, 
+	"---------------------------  END NETLINK MESSAGE   "
+	"---------------------------\n");
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/.dirstamp b/libnetwork/libnl3/lib/netfilter/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/netfilter/ct.c b/libnetwork/libnl3/lib/netfilter/ct.c
new file mode 100644
index 0000000..9d61b6c
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/ct.c
@@ -0,0 +1,601 @@
+/*
+ * lib/netfilter/ct.c	Conntrack
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c= 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup ct Conntrack
+ * @brief
+ * @{
+ */
+
+#include <byteswap.h>
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+#include <netlink-local.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/ct.h>
+
+static struct nl_cache_ops nfnl_ct_ops;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return __bswap_64(x);
+}
+#endif
+
+static struct nla_policy ct_policy[CTA_MAX+1] = {
+	[CTA_TUPLE_ORIG]	= { .type = NLA_NESTED },
+	[CTA_TUPLE_REPLY]	= { .type = NLA_NESTED },
+	[CTA_STATUS]		= { .type = NLA_U32 },
+	[CTA_PROTOINFO]		= { .type = NLA_NESTED },
+	//[CTA_HELP]
+	//[CTA_NAT_SRC]
+	[CTA_TIMEOUT]		= { .type = NLA_U32 },
+	[CTA_MARK]		= { .type = NLA_U32 },
+	[CTA_COUNTERS_ORIG]	= { .type = NLA_NESTED },
+	[CTA_COUNTERS_REPLY]	= { .type = NLA_NESTED },
+	[CTA_USE]		= { .type = NLA_U32 },
+	[CTA_ID]		= { .type = NLA_U32 },
+	//[CTA_NAT_DST]
+};
+
+static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
+	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
+	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
+};
+
+static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
+	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
+	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
+	[CTA_IP_V6_SRC]		= { .minlen = 16 },
+	[CTA_IP_V6_DST]		= { .minlen = 16 },
+};
+
+static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
+	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
+	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
+	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
+	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
+	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
+	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
+	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
+	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
+	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
+};
+
+static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
+	[CTA_PROTOINFO_TCP]	= { .type = NLA_NESTED },
+};
+
+static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
+	[CTA_PROTOINFO_TCP_STATE]		= { .type = NLA_U8 },
+	[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]	= { .type = NLA_U8 },
+	[CTA_PROTOINFO_TCP_WSCALE_REPLY]	= { .type = NLA_U8 },
+	[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]	= { .minlen = 2 },
+	[CTA_PROTOINFO_TCP_FLAGS_REPLY]		= { .minlen = 2 },
+
+};
+
+static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
+	[CTA_COUNTERS_PACKETS]	= { .type = NLA_U64 },
+	[CTA_COUNTERS_BYTES]	= { .type = NLA_U64 },
+	[CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
+	[CTA_COUNTERS32_BYTES]	= { .type = NLA_U32 },
+};
+
+static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_IP_MAX+1];
+	struct nl_addr *addr;
+	int err;
+
+        err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
+	if (err < 0)
+		goto errout;
+
+	if (tb[CTA_IP_V4_SRC]) {
+		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
+		if (addr == NULL)
+			goto errout_enomem;
+		err = nfnl_ct_set_src(ct, repl, addr);
+		nl_addr_put(addr);
+		if (err < 0)
+			goto errout;
+	}
+	if (tb[CTA_IP_V4_DST]) {
+		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
+		if (addr == NULL)
+			goto errout_enomem;
+		err = nfnl_ct_set_dst(ct, repl, addr);
+		nl_addr_put(addr);
+		if (err < 0)
+			goto errout;
+	}
+	if (tb[CTA_IP_V6_SRC]) {
+		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
+		if (addr == NULL)
+			goto errout_enomem;
+		err = nfnl_ct_set_src(ct, repl, addr);
+		nl_addr_put(addr);
+		if (err < 0)
+			goto errout;
+	}
+	if (tb[CTA_IP_V6_DST]) {
+		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
+		if (addr == NULL)
+			goto errout_enomem;
+		err = nfnl_ct_set_dst(ct, repl, addr);
+		nl_addr_put(addr);
+		if (err < 0)
+			goto errout;
+	}
+
+	return 0;
+
+errout_enomem:
+	err = -NLE_NOMEM;
+errout:
+	return err;
+}
+
+static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_PROTO_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
+	if (err < 0)
+		return err;
+
+	if (!repl && tb[CTA_PROTO_NUM])
+		nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
+	if (tb[CTA_PROTO_SRC_PORT])
+		nfnl_ct_set_src_port(ct, repl,
+			ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
+	if (tb[CTA_PROTO_DST_PORT])
+		nfnl_ct_set_dst_port(ct, repl,
+			ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
+	if (tb[CTA_PROTO_ICMP_ID])
+		nfnl_ct_set_icmp_id(ct, repl,
+			ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
+	if (tb[CTA_PROTO_ICMP_TYPE])
+		nfnl_ct_set_icmp_type(ct, repl,
+				nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
+	if (tb[CTA_PROTO_ICMP_CODE])
+		nfnl_ct_set_icmp_code(ct, repl,
+				nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
+
+	return 0;
+}
+
+static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_TUPLE_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[CTA_TUPLE_IP]) {
+		err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
+		if (err < 0)
+			return err;
+	}
+
+	if (tb[CTA_TUPLE_PROTO]) {
+		err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
+			       ct_protoinfo_tcp_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[CTA_PROTOINFO_TCP_STATE])
+		nfnl_ct_set_tcp_state(ct,
+				nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
+
+	return 0;
+}
+
+static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_PROTOINFO_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
+			       ct_protoinfo_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[CTA_PROTOINFO_TCP]) {
+		err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+	struct nlattr *tb[CTA_COUNTERS_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[CTA_COUNTERS_PACKETS])
+		nfnl_ct_set_packets(ct, repl,
+			ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
+	if (tb[CTA_COUNTERS32_PACKETS])
+		nfnl_ct_set_packets(ct, repl,
+			ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
+	if (tb[CTA_COUNTERS_BYTES])
+		nfnl_ct_set_bytes(ct, repl,
+			ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
+	if (tb[CTA_COUNTERS32_BYTES])
+		nfnl_ct_set_bytes(ct, repl,
+			ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
+
+	return 0;
+}
+
+int nfnlmsg_ct_group(struct nlmsghdr *nlh)
+{
+	switch (nfnlmsg_subtype(nlh)) {
+	case IPCTNL_MSG_CT_NEW:
+		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
+			return NFNLGRP_CONNTRACK_NEW;
+		else
+			return NFNLGRP_CONNTRACK_UPDATE;
+	case IPCTNL_MSG_CT_DELETE:
+		return NFNLGRP_CONNTRACK_DESTROY;
+	default:
+		return NFNLGRP_NONE;
+	}
+}
+
+int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
+{
+	struct nfnl_ct *ct;
+	struct nlattr *tb[CTA_MAX+1];
+	int err;
+
+	ct = nfnl_ct_alloc();
+	if (!ct)
+		return -NLE_NOMEM;
+
+	ct->ce_msgtype = nlh->nlmsg_type;
+
+	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
+			  ct_policy);
+	if (err < 0)
+		goto errout;
+
+	nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
+
+	if (tb[CTA_TUPLE_ORIG]) {
+		err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
+		if (err < 0)
+			goto errout;
+	}
+	if (tb[CTA_TUPLE_REPLY]) {
+		err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
+		if (err < 0)
+			goto errout;
+	}
+
+	if (tb[CTA_PROTOINFO]) {
+		err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
+		if (err < 0)
+			goto errout;
+	}
+
+	if (tb[CTA_STATUS])
+		nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
+	if (tb[CTA_TIMEOUT])
+		nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
+	if (tb[CTA_MARK])
+		nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
+	if (tb[CTA_USE])
+		nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
+	if (tb[CTA_ID])
+		nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
+
+	if (tb[CTA_COUNTERS_ORIG]) {
+		err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
+		if (err < 0)
+			goto errout;
+	}
+
+	if (tb[CTA_COUNTERS_REPLY]) {
+		err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
+		if (err < 0)
+			goto errout;
+	}
+
+	*result = ct;
+	return 0;
+
+errout:
+	nfnl_ct_put(ct);
+	return err;
+}
+
+static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct nfnl_ct *ct;
+	int err;
+
+	if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
+		goto errout;
+
+	err = pp->pp_cb((struct nl_object *) ct, pp);
+errout:
+	nfnl_ct_put(ct);
+	return err;
+}
+
+int nfnl_ct_dump_request(struct nl_sock *sk)
+{
+	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
+				NLM_F_DUMP, AF_UNSPEC, 0);
+}
+
+static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+	return nfnl_ct_dump_request(sk);
+}
+
+static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
+			       int repl)
+{
+	struct nlattr *tuple, *ip, *proto;
+	struct nl_addr *addr;
+	int family;
+
+	family = nfnl_ct_get_family(ct);
+
+	tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
+	if (!tuple)
+		goto nla_put_failure;
+
+	ip = nla_nest_start(msg, CTA_TUPLE_IP);
+	if (!ip)
+		goto nla_put_failure;
+
+	addr = nfnl_ct_get_src(ct, repl);
+	if (addr)
+		NLA_PUT_ADDR(msg,
+			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
+			     addr);
+
+	addr = nfnl_ct_get_dst(ct, repl);
+	if (addr)
+		NLA_PUT_ADDR(msg,
+			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
+			     addr);
+
+	nla_nest_end(msg, ip);
+
+	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
+	if (!proto)
+		goto nla_put_failure;
+
+	if (nfnl_ct_test_proto(ct))
+		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
+
+	if (nfnl_ct_test_src_port(ct, repl))
+		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
+			htons(nfnl_ct_get_src_port(ct, repl)));
+
+	if (nfnl_ct_test_dst_port(ct, repl))
+		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
+			htons(nfnl_ct_get_dst_port(ct, repl)));
+
+	if (nfnl_ct_test_icmp_id(ct, repl))
+		NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
+			htons(nfnl_ct_get_icmp_id(ct, repl)));
+
+	if (nfnl_ct_test_icmp_type(ct, repl))
+		NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
+			    nfnl_ct_get_icmp_type(ct, repl));
+
+	if (nfnl_ct_test_icmp_code(ct, repl))
+		NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
+			    nfnl_ct_get_icmp_code(ct, repl));
+
+	nla_nest_end(msg, proto);
+
+	nla_nest_end(msg, tuple);
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
+				 struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	int err;
+
+	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
+				   nfnl_ct_get_family(ct), 0);
+	if (msg == NULL)
+		return -NLE_NOMEM;
+
+	if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
+		goto err_out;
+
+	*result = msg;
+	return 0;
+
+err_out:
+	nlmsg_free(msg);
+	return err;
+}
+
+int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
+			      struct nl_msg **result)
+{
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
+}
+
+int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
+				 struct nl_msg **result)
+{
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
+}
+
+int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
+				struct nl_msg **result)
+{
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
+}
+
+int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a conntrack cache holding all conntrack currently in the kernel
+ * @arg sk		Netlink socket.
+ * @arg result		Pointer to store resulting cache.
+ *
+ * Allocates a new cache, initializes it properly and updates it to
+ * contain all conntracks currently in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
+}
+
+/** @} */
+
+/**
+ * @name Conntrack Addition
+ * @{
+ */
+
+/** @} */
+
+static struct nl_af_group ct_groups[] = {
+	{ AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
+	{ AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
+	{ AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
+	{ END_OF_GROUP_LIST },
+};
+
+#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
+static struct nl_cache_ops nfnl_ct_ops = {
+	.co_name		= "netfilter/ct",
+	.co_hdrsize		= NFNL_HDRLEN,
+	.co_msgtypes		= {
+		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
+		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
+		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
+		END_OF_MSGTYPES_LIST,
+	},
+	.co_protocol		= NETLINK_NETFILTER,
+	.co_groups		= ct_groups,
+	.co_request_update	= ct_request_update,
+	.co_msg_parser		= ct_msg_parser,
+	.co_obj_ops		= &ct_obj_ops,
+};
+
+static void __init ct_init(void)
+{
+	nl_cache_mngt_register(&nfnl_ct_ops);
+}
+
+static void __exit ct_exit(void)
+{
+	nl_cache_mngt_unregister(&nfnl_ct_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/ct_obj.c b/libnetwork/libnl3/lib/netfilter/ct_obj.c
new file mode 100644
index 0000000..c205427
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/ct_obj.c
@@ -0,0 +1,785 @@
+/*
+ * lib/netfilter/ct_obj.c	Conntrack Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+
+#include <netlink-local.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/ct.h>
+
+/** @cond SKIP */
+#define CT_ATTR_FAMILY		(1UL << 0)
+#define CT_ATTR_PROTO		(1UL << 1)
+
+#define CT_ATTR_TCP_STATE	(1UL << 2)
+
+#define CT_ATTR_STATUS		(1UL << 3)
+#define CT_ATTR_TIMEOUT		(1UL << 4)
+#define CT_ATTR_MARK		(1UL << 5)
+#define CT_ATTR_USE		(1UL << 6)
+#define CT_ATTR_ID		(1UL << 7)
+
+#define CT_ATTR_ORIG_SRC	(1UL << 8)
+#define CT_ATTR_ORIG_DST	(1UL << 9)
+#define CT_ATTR_ORIG_SRC_PORT	(1UL << 10)
+#define CT_ATTR_ORIG_DST_PORT	(1UL << 11)
+#define CT_ATTR_ORIG_ICMP_ID	(1UL << 12)
+#define CT_ATTR_ORIG_ICMP_TYPE	(1UL << 13)
+#define CT_ATTR_ORIG_ICMP_CODE	(1UL << 14)
+#define CT_ATTR_ORIG_PACKETS	(1UL << 15)
+#define CT_ATTR_ORIG_BYTES	(1UL << 16)
+
+#define CT_ATTR_REPL_SRC	(1UL << 17)
+#define CT_ATTR_REPL_DST	(1UL << 18)
+#define CT_ATTR_REPL_SRC_PORT	(1UL << 19)
+#define CT_ATTR_REPL_DST_PORT	(1UL << 20)
+#define CT_ATTR_REPL_ICMP_ID	(1UL << 21)
+#define CT_ATTR_REPL_ICMP_TYPE	(1UL << 22)
+#define CT_ATTR_REPL_ICMP_CODE	(1UL << 23)
+#define CT_ATTR_REPL_PACKETS	(1UL << 24)
+#define CT_ATTR_REPL_BYTES	(1UL << 25)
+/** @endcond */
+
+static void ct_free_data(struct nl_object *c)
+{
+	struct nfnl_ct *ct = (struct nfnl_ct *) c;
+
+	if (ct == NULL)
+		return;
+
+	nl_addr_put(ct->ct_orig.src);
+	nl_addr_put(ct->ct_orig.dst);
+	nl_addr_put(ct->ct_repl.src);
+	nl_addr_put(ct->ct_repl.dst);
+}
+
+static int ct_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct nfnl_ct *dst = (struct nfnl_ct *) _dst;
+	struct nfnl_ct *src = (struct nfnl_ct *) _src;
+	struct nl_addr *addr;
+
+	if (src->ct_orig.src) {
+		addr = nl_addr_clone(src->ct_orig.src);
+		if (!addr)
+			return -NLE_NOMEM;
+		dst->ct_orig.src = addr;
+	}
+
+	if (src->ct_orig.dst) {
+		addr = nl_addr_clone(src->ct_orig.dst);
+		if (!addr)
+			return -NLE_NOMEM;
+		dst->ct_orig.dst = addr;
+	}
+
+	if (src->ct_repl.src) {
+		addr = nl_addr_clone(src->ct_repl.src);
+		if (!addr)
+			return -NLE_NOMEM;
+		dst->ct_repl.src = addr;
+	}
+
+	if (src->ct_repl.dst) {
+		addr = nl_addr_clone(src->ct_repl.dst);
+		if (!addr)
+			return -NLE_NOMEM;
+		dst->ct_repl.dst = addr;
+	}
+
+	return 0;
+}
+
+static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
+{
+	char buf[64];
+
+	if (addr)
+		nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
+
+	if (port)
+		nl_dump(p, ":%u ", port);
+	else if (addr)
+		nl_dump(p, " ");
+}
+
+static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply)
+{
+	if (nfnl_ct_test_icmp_type(ct, reply))
+		nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply));
+
+	if (nfnl_ct_test_icmp_type(ct, reply))
+		nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply));
+
+	if (nfnl_ct_test_icmp_type(ct, reply))
+		nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply));
+}
+
+static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p)
+{
+	struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst;
+	int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0;
+	int sync = 0;
+
+	orig_src = nfnl_ct_get_src(ct, 0);
+	orig_dst = nfnl_ct_get_dst(ct, 0);
+	reply_src = nfnl_ct_get_src(ct, 1);
+	reply_dst = nfnl_ct_get_dst(ct, 1);
+
+	if (nfnl_ct_test_src_port(ct, 0))
+		orig_sport = nfnl_ct_get_src_port(ct, 0);
+
+	if (nfnl_ct_test_dst_port(ct, 0))
+		orig_dport = nfnl_ct_get_dst_port(ct, 0);
+
+	if (nfnl_ct_test_src_port(ct, 1))
+		reply_sport = nfnl_ct_get_src_port(ct, 1);
+
+	if (nfnl_ct_test_dst_port(ct, 1))
+		reply_dport = nfnl_ct_get_dst_port(ct, 1);
+
+	if (orig_src && orig_dst && reply_src && reply_dst &&
+	    orig_sport == reply_dport && orig_dport == reply_sport &&
+	    !nl_addr_cmp(orig_src, reply_dst) &&
+	    !nl_addr_cmp(orig_dst, reply_src))
+		sync = 1;
+
+	dump_addr(p, orig_src, orig_sport);
+	nl_dump(p, sync ? "<-> " : "-> ");
+	dump_addr(p, orig_dst, orig_dport);
+	dump_icmp(p, ct, 0);
+
+	if (!sync) {
+		dump_addr(p, reply_src, reply_sport);
+		nl_dump(p, "<- ");
+		dump_addr(p, reply_dst, reply_dport);
+		dump_icmp(p, ct, 1);
+	}
+}
+
+/* Compatible with /proc/net/nf_conntrack */
+static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_ct *ct = (struct nfnl_ct *) a;
+	char buf[64];
+
+	nl_new_line(p);
+
+	if (nfnl_ct_test_proto(ct))
+		nl_dump(p, "%s ",
+		  nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf)));
+
+	if (nfnl_ct_test_tcp_state(ct))
+		nl_dump(p, "%s ",
+			nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct),
+					      buf, sizeof(buf)));
+
+	ct_dump_tuples(ct, p);
+
+	if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct))
+		nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct));
+
+	nl_dump(p, "\n");
+}
+
+static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_ct *ct = (struct nfnl_ct *) a;
+	char buf[64];
+	int fp = 0;
+
+	ct_dump_line(a, p);
+
+	nl_dump(p, "    id 0x%x ", ct->ct_id);
+	nl_dump_line(p, "family %s ",
+		nl_af2str(ct->ct_family, buf, sizeof(buf)));
+
+	if (nfnl_ct_test_use(ct))
+		nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct));
+
+	if (nfnl_ct_test_timeout(ct)) {
+		uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL;
+		nl_dump(p, "timeout %s ",
+			nl_msec2str(timeout_ms, buf, sizeof(buf)));
+	}
+
+	if (ct->ct_status)
+		nl_dump(p, "<");
+
+#define PRINT_FLAG(str) \
+	{ nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
+
+	if (ct->ct_status & IPS_EXPECTED)
+		PRINT_FLAG("EXPECTED");
+	if (!(ct->ct_status & IPS_SEEN_REPLY))
+		PRINT_FLAG("NOREPLY");
+	if (ct->ct_status & IPS_ASSURED)
+		PRINT_FLAG("ASSURED");
+	if (!(ct->ct_status & IPS_CONFIRMED))
+		PRINT_FLAG("NOTSENT");
+	if (ct->ct_status & IPS_SRC_NAT)
+		PRINT_FLAG("SNAT");
+	if (ct->ct_status & IPS_DST_NAT)
+		PRINT_FLAG("DNAT");
+	if (ct->ct_status & IPS_SEQ_ADJUST)
+		PRINT_FLAG("SEQADJUST");
+	if (!(ct->ct_status & IPS_SRC_NAT_DONE))
+		PRINT_FLAG("SNAT_INIT");
+	if (!(ct->ct_status & IPS_DST_NAT_DONE))
+		PRINT_FLAG("DNAT_INIT");
+	if (ct->ct_status & IPS_DYING)
+		PRINT_FLAG("DYING");
+	if (ct->ct_status & IPS_FIXED_TIMEOUT)
+		PRINT_FLAG("FIXED_TIMEOUT");
+#undef PRINT_FLAG
+
+	if (ct->ct_status)
+		nl_dump(p, ">");
+	nl_dump(p, "\n");
+}
+
+static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_ct *ct = (struct nfnl_ct *) a;
+	double res;
+	char *unit;
+
+	ct_dump_details(a, p);
+
+	nl_dump_line(p, "        # packets      volume\n");
+
+	res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 1), &unit);
+	nl_dump_line(p, "    rx %10llu %7.2f %s\n",
+		nfnl_ct_get_packets(ct, 1), res, unit);
+
+	res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 0), &unit);
+	nl_dump_line(p, "    tx %10llu %7.2f %s\n",
+		nfnl_ct_get_packets(ct, 0), res, unit);
+}
+
+static int ct_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct nfnl_ct *a = (struct nfnl_ct *) _a;
+	struct nfnl_ct *b = (struct nfnl_ct *) _b;
+	int diff = 0;
+
+#define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR)
+#define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD)
+#define CT_DIFF_ADDR(ATTR, FIELD) \
+	((flags & LOOSE_COMPARISON) \
+		? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \
+		: CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
+
+	diff |= CT_DIFF_VAL(FAMILY,		ct_family);
+	diff |= CT_DIFF_VAL(PROTO,		ct_proto);
+	diff |= CT_DIFF_VAL(TCP_STATE,		ct_protoinfo.tcp.state);
+	diff |= CT_DIFF_VAL(TIMEOUT,		ct_timeout);
+	diff |= CT_DIFF_VAL(MARK,		ct_mark);
+	diff |= CT_DIFF_VAL(USE,		ct_use);
+	diff |= CT_DIFF_VAL(ID,			ct_id);
+	diff |= CT_DIFF_ADDR(ORIG_SRC,		ct_orig.src);
+	diff |= CT_DIFF_ADDR(ORIG_DST,		ct_orig.dst);
+	diff |= CT_DIFF_VAL(ORIG_SRC_PORT,	ct_orig.proto.port.src);
+	diff |= CT_DIFF_VAL(ORIG_DST_PORT,	ct_orig.proto.port.dst);
+	diff |= CT_DIFF_VAL(ORIG_ICMP_ID,	ct_orig.proto.icmp.id);
+	diff |= CT_DIFF_VAL(ORIG_ICMP_TYPE,	ct_orig.proto.icmp.type);
+	diff |= CT_DIFF_VAL(ORIG_ICMP_CODE,	ct_orig.proto.icmp.code);
+	diff |= CT_DIFF_VAL(ORIG_PACKETS,	ct_orig.packets);
+	diff |= CT_DIFF_VAL(ORIG_BYTES,		ct_orig.bytes);
+	diff |= CT_DIFF_ADDR(REPL_SRC,		ct_repl.src);
+	diff |= CT_DIFF_ADDR(REPL_DST,		ct_repl.dst);
+	diff |= CT_DIFF_VAL(REPL_SRC_PORT,	ct_repl.proto.port.src);
+	diff |= CT_DIFF_VAL(REPL_DST_PORT,	ct_repl.proto.port.dst);
+	diff |= CT_DIFF_VAL(REPL_ICMP_ID,	ct_repl.proto.icmp.id);
+	diff |= CT_DIFF_VAL(REPL_ICMP_TYPE,	ct_repl.proto.icmp.type);
+	diff |= CT_DIFF_VAL(REPL_ICMP_CODE,	ct_repl.proto.icmp.code);
+	diff |= CT_DIFF_VAL(REPL_PACKETS,	ct_repl.packets);
+	diff |= CT_DIFF_VAL(REPL_BYTES,		ct_repl.bytes);
+
+	if (flags & LOOSE_COMPARISON)
+		diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) &
+					b->ct_status_mask);
+	else
+		diff |= CT_DIFF(STATUS, a->ct_status != b->ct_status);
+
+#undef CT_DIFF
+#undef CT_DIFF_VAL
+#undef CT_DIFF_ADDR
+
+	return diff;
+}
+
+static const struct trans_tbl ct_attrs[] = {
+	__ADD(CT_ATTR_FAMILY,		family)
+	__ADD(CT_ATTR_PROTO,		proto)
+	__ADD(CT_ATTR_TCP_STATE,	tcpstate)
+	__ADD(CT_ATTR_STATUS,		status)
+	__ADD(CT_ATTR_TIMEOUT,		timeout)
+	__ADD(CT_ATTR_MARK,		mark)
+	__ADD(CT_ATTR_USE,		use)
+	__ADD(CT_ATTR_ID,		id)
+	__ADD(CT_ATTR_ORIG_SRC,		origsrc)
+	__ADD(CT_ATTR_ORIG_DST,		origdst)
+	__ADD(CT_ATTR_ORIG_SRC_PORT,	origsrcport)
+	__ADD(CT_ATTR_ORIG_DST_PORT,	origdstport)
+	__ADD(CT_ATTR_ORIG_ICMP_ID,	origicmpid)
+	__ADD(CT_ATTR_ORIG_ICMP_TYPE,	origicmptype)
+	__ADD(CT_ATTR_ORIG_ICMP_CODE,	origicmpcode)
+	__ADD(CT_ATTR_ORIG_PACKETS,	origpackets)
+	__ADD(CT_ATTR_ORIG_BYTES,	origbytes)
+	__ADD(CT_ATTR_REPL_SRC,		replysrc)
+	__ADD(CT_ATTR_REPL_DST,		replydst)
+	__ADD(CT_ATTR_REPL_SRC_PORT,	replysrcport)
+	__ADD(CT_ATTR_REPL_DST_PORT,	replydstport)
+	__ADD(CT_ATTR_REPL_ICMP_ID,	replyicmpid)
+	__ADD(CT_ATTR_REPL_ICMP_TYPE,	replyicmptype)
+	__ADD(CT_ATTR_REPL_ICMP_CODE,	replyicmpcode)
+	__ADD(CT_ATTR_REPL_PACKETS,	replypackets)
+	__ADD(CT_ATTR_REPL_BYTES,	replybytes)
+};
+
+static char *ct_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_ct *nfnl_ct_alloc(void)
+{
+	return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops);
+}
+
+void nfnl_ct_get(struct nfnl_ct *ct)
+{
+	nl_object_get((struct nl_object *) ct);
+}
+
+void nfnl_ct_put(struct nfnl_ct *ct)
+{
+	nl_object_put((struct nl_object *) ct);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_ct_set_family(struct nfnl_ct *ct, uint8_t family)
+{
+	ct->ct_family = family;
+	ct->ce_mask |= CT_ATTR_FAMILY;
+}
+
+uint8_t nfnl_ct_get_family(const struct nfnl_ct *ct)
+{
+	if (ct->ce_mask & CT_ATTR_FAMILY)
+		return ct->ct_family;
+	else
+		return AF_UNSPEC;
+}
+
+void nfnl_ct_set_proto(struct nfnl_ct *ct, uint8_t proto)
+{
+	ct->ct_proto = proto;
+	ct->ce_mask |= CT_ATTR_PROTO;
+}
+
+int nfnl_ct_test_proto(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_PROTO);
+}
+
+uint8_t nfnl_ct_get_proto(const struct nfnl_ct *ct)
+{
+	return ct->ct_proto;
+}
+
+void nfnl_ct_set_tcp_state(struct nfnl_ct *ct, uint8_t state)
+{
+	ct->ct_protoinfo.tcp.state = state;
+	ct->ce_mask |= CT_ATTR_TCP_STATE;
+}
+
+int nfnl_ct_test_tcp_state(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_TCP_STATE);
+}
+
+uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct)
+{
+	return ct->ct_protoinfo.tcp.state;
+}
+
+static const struct trans_tbl tcp_states[] = {
+	__ADD(TCP_CONNTRACK_NONE,NONE)
+	__ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT)
+	__ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV)
+	__ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED)
+	__ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT)
+	__ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT)
+	__ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK)
+	__ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT)
+	__ADD(TCP_CONNTRACK_CLOSE,CLOSE)
+	__ADD(TCP_CONNTRACK_LISTEN,LISTEN)
+};
+
+char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len)
+{
+	return __type2str(state, buf, len, tcp_states, ARRAY_SIZE(tcp_states));
+}
+
+int nfnl_ct_str2tcp_state(const char *name)
+{
+        return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states));
+}
+
+void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status)
+{
+	ct->ct_status_mask |= status;
+	ct->ct_status |= status;
+	ct->ce_mask |= CT_ATTR_STATUS;
+}
+
+void nfnl_ct_unset_status(struct nfnl_ct *ct, uint32_t status)
+{
+	ct->ct_status_mask |= status;
+	ct->ct_status &= ~status;
+	ct->ce_mask |= CT_ATTR_STATUS;
+}
+
+uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct)
+{
+	return ct->ct_status;
+}
+
+static const struct trans_tbl status_flags[] = {
+	__ADD(IPS_EXPECTED, expected)
+	__ADD(IPS_SEEN_REPLY, seen_reply)
+	__ADD(IPS_ASSURED, assured)
+	__ADD(IPS_CONFIRMED, confirmed)
+	__ADD(IPS_SRC_NAT, snat)
+	__ADD(IPS_DST_NAT, dnat)
+	__ADD(IPS_SEQ_ADJUST, seqadjust)
+	__ADD(IPS_SRC_NAT_DONE, snat_done)
+	__ADD(IPS_DST_NAT_DONE, dnat_done)
+	__ADD(IPS_DYING, dying)
+	__ADD(IPS_FIXED_TIMEOUT, fixed_timeout)
+};
+
+char * nfnl_ct_status2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, status_flags,
+			   ARRAY_SIZE(status_flags));
+}
+
+int nfnl_ct_str2status(const char *name)
+{
+	return __str2flags(name, status_flags, ARRAY_SIZE(status_flags));
+}
+
+void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout)
+{
+	ct->ct_timeout = timeout;
+	ct->ce_mask |= CT_ATTR_TIMEOUT;
+}
+
+int nfnl_ct_test_timeout(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_TIMEOUT);
+}
+
+uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *ct)
+{
+	return ct->ct_timeout;
+}
+
+void nfnl_ct_set_mark(struct nfnl_ct *ct, uint32_t mark)
+{
+	ct->ct_mark = mark;
+	ct->ce_mask |= CT_ATTR_MARK;
+}
+
+int nfnl_ct_test_mark(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_MARK);
+}
+
+uint32_t nfnl_ct_get_mark(const struct nfnl_ct *ct)
+{
+	return ct->ct_mark;
+}
+
+void nfnl_ct_set_use(struct nfnl_ct *ct, uint32_t use)
+{
+	ct->ct_use = use;
+	ct->ce_mask |= CT_ATTR_USE;
+}
+
+int nfnl_ct_test_use(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_USE);
+}
+
+uint32_t nfnl_ct_get_use(const struct nfnl_ct *ct)
+{
+	return ct->ct_use;
+}
+
+void nfnl_ct_set_id(struct nfnl_ct *ct, uint32_t id)
+{
+	ct->ct_id = id;
+	ct->ce_mask |= CT_ATTR_ID;
+}
+
+int nfnl_ct_test_id(const struct nfnl_ct *ct)
+{
+	return !!(ct->ce_mask & CT_ATTR_ID);
+}
+
+uint32_t nfnl_ct_get_id(const struct nfnl_ct *ct)
+{
+	return ct->ct_id;
+}
+
+static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr,
+		int attr, struct nl_addr ** ct_addr)
+{
+	if (ct->ce_mask & CT_ATTR_FAMILY) {
+		if (addr->a_family != ct->ct_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		nfnl_ct_set_family(ct, addr->a_family);
+
+	if (*ct_addr)
+		nl_addr_put(*ct_addr);
+
+	nl_addr_get(addr);
+	*ct_addr = addr;
+	ct->ce_mask |= attr;
+
+	return 0;
+}
+
+int nfnl_ct_set_src(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
+	return ct_set_addr(ct, addr, attr, &dir->src);
+}
+
+int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
+	return ct_set_addr(ct, addr, attr, &dir->dst);
+}
+
+struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
+	if (!(ct->ce_mask & attr))
+		return NULL;
+	return dir->src;
+}
+
+struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
+	if (!(ct->ce_mask & attr))
+		return NULL;
+	return dir->dst;
+}
+
+void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
+
+	dir->proto.port.src = port;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
+	return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->proto.port.src;
+}
+
+void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
+
+	dir->proto.port.dst = port;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
+	return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->proto.port.dst;
+}
+
+void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
+
+	dir->proto.icmp.id = id;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
+	return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->proto.icmp.id;
+}
+
+void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
+
+	dir->proto.icmp.type = type;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
+	return !!(ct->ce_mask & attr);
+}
+
+uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->proto.icmp.type;
+}
+
+void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
+
+	dir->proto.icmp.code = code;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
+	return !!(ct->ce_mask & attr);
+}
+
+uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->proto.icmp.code;
+}
+
+void nfnl_ct_set_packets(struct nfnl_ct *ct, int repl, uint64_t packets)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
+
+	dir->packets = packets;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_packets(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
+	return !!(ct->ce_mask & attr);
+}
+
+uint64_t nfnl_ct_get_packets(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->packets;
+}
+
+void nfnl_ct_set_bytes(struct nfnl_ct *ct, int repl, uint64_t bytes)
+{
+	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+	int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
+
+	dir->bytes = bytes;
+	ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_bytes(const struct nfnl_ct *ct, int repl)
+{
+	int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
+	return !!(ct->ce_mask & attr);
+}
+
+uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl)
+{
+	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+	return dir->bytes;
+}
+
+/** @} */
+
+struct nl_object_ops ct_obj_ops = {
+	.oo_name		= "netfilter/ct",
+	.oo_size		= sizeof(struct nfnl_ct),
+	.oo_free_data		= ct_free_data,
+	.oo_clone		= ct_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= ct_dump_line,
+	    [NL_DUMP_DETAILS]	= ct_dump_details,
+	    [NL_DUMP_STATS]	= ct_dump_stats,
+	},
+	.oo_compare		= ct_compare,
+	.oo_attrs2str		= ct_attrs2str,
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/log.c b/libnetwork/libnl3/lib/netfilter/log.c
new file mode 100644
index 0000000..96ae6c5
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/log.c
@@ -0,0 +1,251 @@
+/*
+ * lib/netfilter/log.c	Netfilter Log
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup log Log
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_log.h>
+
+#include <netlink-local.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+/**
+ * @name Log Commands
+ * @{
+ */
+
+static int build_log_cmd_request(uint8_t family, uint16_t queuenum,
+				 uint8_t command, struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct nfulnl_msg_config_cmd cmd;
+
+	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
+				   family, queuenum);
+	if (msg == NULL)
+		return -NLE_NOMEM;
+
+	cmd.command = command;
+	if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+		goto nla_put_failure;
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+static int send_log_request(struct nl_sock *sk, struct nl_msg *msg)
+{
+	int err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+int nfnl_log_build_pf_bind(uint8_t pf, struct nl_msg **result)
+{
+	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND, result);
+}
+
+int nfnl_log_pf_bind(struct nl_sock *nlh, uint8_t pf)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0)
+		return err;
+
+	return send_log_request(nlh, msg);
+}
+
+int nfnl_log_build_pf_unbind(uint8_t pf, struct nl_msg **result)
+{
+	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND, result);
+}
+
+int nfnl_log_pf_unbind(struct nl_sock *nlh, uint8_t pf)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0)
+		return err;
+
+	return send_log_request(nlh, msg);
+}
+
+static int nfnl_log_build_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
+{
+	struct nl_msg *msg;
+
+	if (!nfnl_log_test_group(log))
+		return -NLE_MISSING_ATTR;
+
+	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
+				   0, nfnl_log_get_group(log));
+	if (msg == NULL)
+		return -NLE_NOMEM;
+
+	/* This sucks. The nfnetlink_log interface always expects both
+	 * parameters to be present. Needs to be done properly.
+	 */
+	if (nfnl_log_test_copy_mode(log)) {
+		struct nfulnl_msg_config_mode mode;
+
+		switch (nfnl_log_get_copy_mode(log)) {
+		case NFNL_LOG_COPY_NONE:
+			mode.copy_mode = NFULNL_COPY_NONE;
+			break;
+		case NFNL_LOG_COPY_META:
+			mode.copy_mode = NFULNL_COPY_META;
+			break;
+		case NFNL_LOG_COPY_PACKET:
+			mode.copy_mode = NFULNL_COPY_PACKET;
+			break;
+		}
+		mode.copy_range = htonl(nfnl_log_get_copy_range(log));
+		mode._pad = 0;
+
+		if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0)
+			goto nla_put_failure;
+	}
+
+	if (nfnl_log_test_flush_timeout(log) &&
+	    nla_put_u32(msg, NFULA_CFG_TIMEOUT,
+			htonl(nfnl_log_get_flush_timeout(log))) < 0)
+		goto nla_put_failure;
+
+	if (nfnl_log_test_alloc_size(log) &&
+	    nla_put_u32(msg, NFULA_CFG_NLBUFSIZ,
+			htonl(nfnl_log_get_alloc_size(log))) < 0)
+		goto nla_put_failure;
+
+	if (nfnl_log_test_queue_threshold(log) &&
+	    nla_put_u32(msg, NFULA_CFG_QTHRESH,
+			htonl(nfnl_log_get_queue_threshold(log))) < 0)
+		goto nla_put_failure;
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+int nfnl_log_build_create_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
+{
+	struct nfulnl_msg_config_cmd cmd;
+	int err;
+
+	if ((err = nfnl_log_build_request(log, result)) < 0)
+		return err;
+
+	cmd.command = NFULNL_CFG_CMD_BIND;
+
+	if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(*result);
+	return -NLE_MSGSIZE;
+}
+
+int nfnl_log_create(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_log_build_create_request(log, &msg)) < 0)
+		return err;
+
+	return send_log_request(nlh, msg);
+}
+
+int nfnl_log_build_change_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
+{
+	return nfnl_log_build_request(log, result);
+}
+
+int nfnl_log_change(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_log_build_change_request(log, &msg)) < 0)
+		return err;
+
+	return send_log_request(nlh, msg);
+}
+
+int nfnl_log_build_delete_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
+{
+	if (!nfnl_log_test_group(log))
+		return -NLE_MISSING_ATTR;
+
+	return build_log_cmd_request(0, nfnl_log_get_group(log),
+				     NFULNL_CFG_CMD_UNBIND, result);
+}
+
+int nfnl_log_delete(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_log_build_delete_request(log, &msg)) < 0)
+		return err;
+
+	return send_log_request(nlh, msg);
+}
+
+/** @} */
+
+static struct nl_cache_ops nfnl_log_ops = {
+	.co_name		= "netfilter/log",
+	.co_obj_ops		= &log_obj_ops,
+	.co_msgtypes		= {
+		END_OF_MSGTYPES_LIST,
+	},
+};
+
+static void __init log_init(void)
+{
+	nl_cache_mngt_register(&nfnl_log_ops);
+}
+
+static void __exit log_exit(void)
+{
+	nl_cache_mngt_unregister(&nfnl_log_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/log_msg.c b/libnetwork/libnl3/lib/netfilter/log_msg.c
new file mode 100644
index 0000000..cad6ddd
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/log_msg.c
@@ -0,0 +1,209 @@
+/*
+ * lib/netfilter/log_msg.c	Netfilter Log Message
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup log Log
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_log.h>
+
+#include <netlink-local.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log_msg.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return __bswap_64(x);
+}
+#endif
+
+static struct nla_policy log_msg_policy[NFULA_MAX+1] = {
+	[NFULA_PACKET_HDR]		= {
+		.minlen = sizeof(struct nfulnl_msg_packet_hdr)
+	},
+	[NFULA_MARK]			= { .type = NLA_U32 },
+	[NFULA_TIMESTAMP]		= {
+		.minlen = sizeof(struct nfulnl_msg_packet_timestamp)
+	},
+	[NFULA_IFINDEX_INDEV]		= { .type = NLA_U32 },
+	[NFULA_IFINDEX_OUTDEV]		= { .type = NLA_U32 },
+	[NFULA_IFINDEX_PHYSINDEV]	= { .type = NLA_U32 },
+	[NFULA_IFINDEX_PHYSOUTDEV]	= { .type = NLA_U32 },
+	[NFULA_HWADDR]			= {
+		.minlen = sizeof(struct nfulnl_msg_packet_hw)
+	},
+	//[NFULA_PAYLOAD]
+	[NFULA_PREFIX]			= { .type = NLA_STRING, },
+	[NFULA_UID]			= { .type = NLA_U32 },
+	[NFULA_GID]			= { .type = NLA_U32 },
+	[NFULA_SEQ]			= { .type = NLA_U32 },
+	[NFULA_SEQ_GLOBAL]		= { .type = NLA_U32 },
+};
+
+int nfnlmsg_log_msg_parse(struct nlmsghdr *nlh, struct nfnl_log_msg **result)
+{
+	struct nfnl_log_msg *msg;
+	struct nlattr *tb[NFULA_MAX+1];
+	struct nlattr *attr;
+	int err;
+
+	msg = nfnl_log_msg_alloc();
+	if (!msg)
+		return -NLE_NOMEM;
+
+	msg->ce_msgtype = nlh->nlmsg_type;
+
+	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX,
+			  log_msg_policy);
+	if (err < 0)
+		goto errout;
+
+	nfnl_log_msg_set_family(msg, nfnlmsg_family(nlh));
+
+	attr = tb[NFULA_PACKET_HDR];
+	if (attr) {
+		struct nfulnl_msg_packet_hdr *hdr = nla_data(attr);
+
+		if (hdr->hw_protocol)
+			nfnl_log_msg_set_hwproto(msg, hdr->hw_protocol);
+		nfnl_log_msg_set_hook(msg, hdr->hook);
+	}
+
+	attr = tb[NFULA_MARK];
+	if (attr)
+		nfnl_log_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_TIMESTAMP];
+	if (attr) {
+		struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr);
+		struct timeval tv;
+
+		tv.tv_sec = ntohll(timestamp->sec);
+		tv.tv_usec = ntohll(timestamp->usec);
+		nfnl_log_msg_set_timestamp(msg, &tv);
+	}
+
+	attr = tb[NFULA_IFINDEX_INDEV];
+	if (attr)
+		nfnl_log_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_IFINDEX_OUTDEV];
+	if (attr)
+		nfnl_log_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_IFINDEX_PHYSINDEV];
+	if (attr)
+		nfnl_log_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_IFINDEX_PHYSOUTDEV];
+	if (attr)
+		nfnl_log_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_HWADDR];
+	if (attr) {
+		struct nfulnl_msg_packet_hw *hw = nla_data(attr);
+
+		nfnl_log_msg_set_hwaddr(msg, hw->hw_addr, ntohs(hw->hw_addrlen));
+	}
+
+	attr = tb[NFULA_PAYLOAD];
+	if (attr) {
+		err = nfnl_log_msg_set_payload(msg, nla_data(attr), nla_len(attr));
+		if (err < 0)
+			goto errout;
+	}
+
+	attr = tb[NFULA_PREFIX];
+	if (attr) {
+		err = nfnl_log_msg_set_prefix(msg, nla_data(attr));
+		if (err < 0)
+			goto errout;
+	}
+
+	attr = tb[NFULA_UID];
+	if (attr)
+		nfnl_log_msg_set_uid(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_GID];
+	if (attr)
+		nfnl_log_msg_set_gid(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_SEQ];
+	if (attr)
+		nfnl_log_msg_set_seq(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFULA_SEQ_GLOBAL];
+	if (attr)
+		nfnl_log_msg_set_seq_global(msg, ntohl(nla_get_u32(attr)));
+
+	*result = msg;
+	return 0;
+
+errout:
+	nfnl_log_msg_put(msg);
+	return err;
+}
+
+static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			  struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct nfnl_log_msg *msg;
+	int err;
+
+	if ((err = nfnlmsg_log_msg_parse(nlh, &msg)) < 0)
+		goto errout;
+
+	err = pp->pp_cb((struct nl_object *) msg, pp);
+errout:
+	nfnl_log_msg_put(msg);
+	return err;
+}
+
+/** @} */
+
+#define NFNLMSG_LOG_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_ULOG, (type))
+static struct nl_cache_ops nfnl_log_msg_ops = {
+	.co_name		= "netfilter/log_msg",
+	.co_hdrsize		= NFNL_HDRLEN,
+	.co_msgtypes		= {
+		{ NFNLMSG_LOG_TYPE(NFULNL_MSG_PACKET), NL_ACT_NEW, "new" },
+		END_OF_MSGTYPES_LIST,
+	},
+	.co_protocol		= NETLINK_NETFILTER,
+	.co_msg_parser		= log_msg_parser,
+	.co_obj_ops		= &log_msg_obj_ops,
+};
+
+static void __init log_msg_init(void)
+{
+	nl_cache_mngt_register(&nfnl_log_msg_ops);
+}
+
+static void __exit log_msg_exit(void)
+{
+	nl_cache_mngt_unregister(&nfnl_log_msg_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/log_msg_obj.c b/libnetwork/libnl3/lib/netfilter/log_msg_obj.c
new file mode 100644
index 0000000..d2cde4e
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/log_msg_obj.c
@@ -0,0 +1,458 @@
+/*
+ * lib/netfilter/log_msg_obj.c	Netfilter Log Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <netlink-local.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/netfilter.h>
+#include <netlink/netfilter/log_msg.h>
+
+/** @cond SKIP */
+#define LOG_MSG_ATTR_FAMILY		(1UL << 0)
+#define LOG_MSG_ATTR_HWPROTO		(1UL << 1)
+#define LOG_MSG_ATTR_HOOK		(1UL << 2)
+#define LOG_MSG_ATTR_MARK		(1UL << 3)
+#define LOG_MSG_ATTR_TIMESTAMP		(1UL << 4)
+#define LOG_MSG_ATTR_INDEV		(1UL << 5)
+#define LOG_MSG_ATTR_OUTDEV		(1UL << 6)
+#define LOG_MSG_ATTR_PHYSINDEV		(1UL << 7)
+#define LOG_MSG_ATTR_PHYSOUTDEV		(1UL << 8)
+#define LOG_MSG_ATTR_HWADDR		(1UL << 9)
+#define LOG_MSG_ATTR_PAYLOAD		(1UL << 10)
+#define LOG_MSG_ATTR_PREFIX		(1UL << 11)
+#define LOG_MSG_ATTR_UID		(1UL << 12)
+#define LOG_MSG_ATTR_GID		(1UL << 13)
+#define LOG_MSG_ATTR_SEQ		(1UL << 14)
+#define LOG_MSG_ATTR_SEQ_GLOBAL		(1UL << 15)
+/** @endcond */
+
+static void log_msg_free_data(struct nl_object *c)
+{
+	struct nfnl_log_msg *msg = (struct nfnl_log_msg *) c;
+
+	if (msg == NULL)
+		return;
+
+	free(msg->log_msg_payload);
+	free(msg->log_msg_prefix);
+}
+
+static int log_msg_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct nfnl_log_msg *dst = (struct nfnl_log_msg *) _dst;
+	struct nfnl_log_msg *src = (struct nfnl_log_msg *) _src;
+	int err;
+
+	if (src->log_msg_payload) {
+		err = nfnl_log_msg_set_payload(dst, src->log_msg_payload,
+					       src->log_msg_payload_len);
+		if (err < 0)
+			goto errout;
+	}
+
+	if (src->log_msg_prefix) {
+		err = nfnl_log_msg_set_prefix(dst, src->log_msg_prefix);
+		if (err < 0)
+			goto errout;
+	}
+
+	return 0;
+errout:
+	return err;
+}
+
+static void log_msg_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_log_msg *msg = (struct nfnl_log_msg *) a;
+	struct nl_cache *link_cache;
+	char buf[64];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	nl_new_line(p);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_PREFIX)
+		nl_dump(p, "%s", msg->log_msg_prefix);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_INDEV) {
+		if (link_cache)
+			nl_dump(p, "IN=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->log_msg_indev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "IN=%d ", msg->log_msg_indev);
+	}
+
+	if (msg->ce_mask & LOG_MSG_ATTR_PHYSINDEV) {
+		if (link_cache)
+			nl_dump(p, "PHYSIN=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->log_msg_physindev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "IN=%d ", msg->log_msg_physindev);
+	}
+
+	if (msg->ce_mask & LOG_MSG_ATTR_OUTDEV) {
+		if (link_cache)
+			nl_dump(p, "OUT=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->log_msg_outdev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "OUT=%d ", msg->log_msg_outdev);
+	}
+
+	if (msg->ce_mask & LOG_MSG_ATTR_PHYSOUTDEV) {
+		if (link_cache)
+			nl_dump(p, "PHYSOUT=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->log_msg_physoutdev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "PHYSOUT=%d ", msg->log_msg_physoutdev);
+	}
+
+	if (msg->ce_mask & LOG_MSG_ATTR_HWADDR) {
+		int i;
+
+		nl_dump(p, "MAC");
+		for (i = 0; i < msg->log_msg_hwaddr_len; i++)
+			nl_dump(p, "%c%02x", i?':':'=', msg->log_msg_hwaddr[i]);
+		nl_dump(p, " ");
+	}
+
+	/* FIXME: parse the payload to get iptables LOG compatible format */
+
+	if (msg->ce_mask & LOG_MSG_ATTR_FAMILY)
+		nl_dump(p, "FAMILY=%s ",
+			nl_af2str(msg->log_msg_family, buf, sizeof(buf)));
+
+	if (msg->ce_mask & LOG_MSG_ATTR_HWPROTO)
+		nl_dump(p, "HWPROTO=%s ",
+			nl_ether_proto2str(ntohs(msg->log_msg_hwproto),
+					   buf, sizeof(buf)));
+
+	if (msg->ce_mask & LOG_MSG_ATTR_HOOK)
+		nl_dump(p, "HOOK=%s ",
+			nfnl_inet_hook2str(msg->log_msg_hook,
+					   buf, sizeof(buf)));
+
+	if (msg->ce_mask & LOG_MSG_ATTR_MARK)
+		nl_dump(p, "MARK=%u ", msg->log_msg_mark);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)
+		nl_dump(p, "PAYLOADLEN=%d ", msg->log_msg_payload_len);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_UID)
+		nl_dump(p, "UID=%u ", msg->log_msg_uid);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_GID)
+		nl_dump(p, "GID=%u ", msg->log_msg_gid);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_SEQ)
+		nl_dump(p, "SEQ=%d ", msg->log_msg_seq);
+
+	if (msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL)
+		nl_dump(p, "SEQGLOBAL=%d ", msg->log_msg_seq_global);
+
+	nl_dump(p, "\n");
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_log_msg *nfnl_log_msg_alloc(void)
+{
+	return (struct nfnl_log_msg *) nl_object_alloc(&log_msg_obj_ops);
+}
+
+void nfnl_log_msg_get(struct nfnl_log_msg *msg)
+{
+	nl_object_get((struct nl_object *) msg);
+}
+
+void nfnl_log_msg_put(struct nfnl_log_msg *msg)
+{
+	nl_object_put((struct nl_object *) msg);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_log_msg_set_family(struct nfnl_log_msg *msg, uint8_t family)
+{
+	msg->log_msg_family = family;
+	msg->ce_mask |= LOG_MSG_ATTR_FAMILY;
+}
+
+uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *msg)
+{
+	if (msg->ce_mask & LOG_MSG_ATTR_FAMILY)
+		return msg->log_msg_family;
+	else
+		return AF_UNSPEC;
+}
+
+void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *msg, uint16_t hwproto)
+{
+	msg->log_msg_hwproto = hwproto;
+	msg->ce_mask |= LOG_MSG_ATTR_HWPROTO;
+}
+
+int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_HWPROTO);
+}
+
+uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_hwproto;
+}
+
+void nfnl_log_msg_set_hook(struct nfnl_log_msg *msg, uint8_t hook)
+{
+	msg->log_msg_hook = hook;
+	msg->ce_mask |= LOG_MSG_ATTR_HOOK;
+}
+
+int nfnl_log_msg_test_hook(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_HOOK);
+}
+
+uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_hook;
+}
+
+void nfnl_log_msg_set_mark(struct nfnl_log_msg *msg, uint32_t mark)
+{
+	msg->log_msg_mark = mark;
+	msg->ce_mask |= LOG_MSG_ATTR_MARK;
+}
+
+int nfnl_log_msg_test_mark(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_MARK);
+}
+
+uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_mark;
+}
+
+void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *msg, struct timeval *tv)
+{
+	msg->log_msg_timestamp.tv_sec = tv->tv_sec;
+	msg->log_msg_timestamp.tv_usec = tv->tv_usec;
+	msg->ce_mask |= LOG_MSG_ATTR_TIMESTAMP;
+}
+
+const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *msg)
+{
+	if (!(msg->ce_mask & LOG_MSG_ATTR_TIMESTAMP))
+		return NULL;
+	return &msg->log_msg_timestamp;
+}
+
+void nfnl_log_msg_set_indev(struct nfnl_log_msg *msg, uint32_t indev)
+{
+	msg->log_msg_indev = indev;
+	msg->ce_mask |= LOG_MSG_ATTR_INDEV;
+}
+
+uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_indev;
+}
+
+void nfnl_log_msg_set_outdev(struct nfnl_log_msg *msg, uint32_t outdev)
+{
+	msg->log_msg_outdev = outdev;
+	msg->ce_mask |= LOG_MSG_ATTR_OUTDEV;
+}
+
+uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_outdev;
+}
+
+void nfnl_log_msg_set_physindev(struct nfnl_log_msg *msg, uint32_t physindev)
+{
+	msg->log_msg_physindev = physindev;
+	msg->ce_mask |= LOG_MSG_ATTR_PHYSINDEV;
+}
+
+uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_physindev;
+}
+
+void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *msg, uint32_t physoutdev)
+{
+	msg->log_msg_physoutdev = physoutdev;
+	msg->ce_mask |= LOG_MSG_ATTR_PHYSOUTDEV;
+}
+
+uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_physoutdev;
+}
+
+void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *msg, uint8_t *hwaddr, int len)
+{
+	if (len > sizeof(msg->log_msg_hwaddr))
+		len = sizeof(msg->log_msg_hwaddr);
+	msg->log_msg_hwaddr_len = len;
+	memcpy(msg->log_msg_hwaddr, hwaddr, len);
+	msg->ce_mask |= LOG_MSG_ATTR_HWADDR;
+}
+
+const uint8_t *nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *msg, int *len)
+{
+	if (!(msg->ce_mask & LOG_MSG_ATTR_HWADDR)) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = msg->log_msg_hwaddr_len;
+	return msg->log_msg_hwaddr;
+}
+
+int nfnl_log_msg_set_payload(struct nfnl_log_msg *msg, uint8_t *payload, int len)
+{
+	free(msg->log_msg_payload);
+	msg->log_msg_payload = malloc(len);
+	if (!msg->log_msg_payload)
+		return -NLE_NOMEM;
+
+	memcpy(msg->log_msg_payload, payload, len);
+	msg->log_msg_payload_len = len;
+	msg->ce_mask |= LOG_MSG_ATTR_PAYLOAD;
+	return 0;
+}
+
+const void *nfnl_log_msg_get_payload(const struct nfnl_log_msg *msg, int *len)
+{
+	if (!(msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = msg->log_msg_payload_len;
+	return msg->log_msg_payload;
+}
+
+int nfnl_log_msg_set_prefix(struct nfnl_log_msg *msg, void *prefix)
+{
+	free(msg->log_msg_prefix);
+	msg->log_msg_prefix = strdup(prefix);
+	if (!msg->log_msg_prefix)
+		return -NLE_NOMEM;
+
+	msg->ce_mask |= LOG_MSG_ATTR_PREFIX;
+	return 0;
+}
+
+const char *nfnl_log_msg_get_prefix(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_prefix;
+}
+
+void nfnl_log_msg_set_uid(struct nfnl_log_msg *msg, uint32_t uid)
+{
+	msg->log_msg_uid = uid;
+	msg->ce_mask |= LOG_MSG_ATTR_UID;
+}
+
+int nfnl_log_msg_test_uid(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_UID);
+}
+
+uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_uid;
+}
+
+void nfnl_log_msg_set_gid(struct nfnl_log_msg *msg, uint32_t gid)
+{
+	msg->log_msg_gid = gid;
+	msg->ce_mask |= LOG_MSG_ATTR_GID;
+}
+
+int nfnl_log_msg_test_gid(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_GID);
+}
+
+uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_gid;
+}
+
+
+void nfnl_log_msg_set_seq(struct nfnl_log_msg *msg, uint32_t seq)
+{
+	msg->log_msg_seq = seq;
+	msg->ce_mask |= LOG_MSG_ATTR_SEQ;
+}
+
+int nfnl_log_msg_test_seq(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ);
+}
+
+uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_seq;
+}
+
+void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *msg, uint32_t seq_global)
+{
+	msg->log_msg_seq_global = seq_global;
+	msg->ce_mask |= LOG_MSG_ATTR_SEQ_GLOBAL;
+}
+
+int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *msg)
+{
+	return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL);
+}
+
+uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *msg)
+{
+	return msg->log_msg_seq_global;
+}
+
+/** @} */
+
+struct nl_object_ops log_msg_obj_ops = {
+	.oo_name		= "netfilter/log_msg",
+	.oo_size		= sizeof(struct nfnl_log_msg),
+	.oo_free_data		= log_msg_free_data,
+	.oo_clone		= log_msg_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= log_msg_dump,
+	    [NL_DUMP_DETAILS]	= log_msg_dump,
+	    [NL_DUMP_STATS]	= log_msg_dump,
+	},
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/log_obj.c b/libnetwork/libnl3/lib/netfilter/log_obj.c
new file mode 100644
index 0000000..43c4a06
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/log_obj.c
@@ -0,0 +1,287 @@
+/*
+ * lib/netfilter/log_obj.c	Netfilter Log Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+/** @cond SKIP */
+#define LOG_ATTR_GROUP			(1UL << 0)
+#define LOG_ATTR_COPY_MODE		(1UL << 1)
+#define LOG_ATTR_COPY_RANGE		(1UL << 3)
+#define LOG_ATTR_FLUSH_TIMEOUT		(1UL << 4)
+#define LOG_ATTR_ALLOC_SIZE		(1UL << 5)
+#define LOG_ATTR_QUEUE_THRESHOLD	(1UL << 6)
+
+/** @endcond */
+
+static void nfnl_log_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_log *log = (struct nfnl_log *) a;
+	char buf[64];
+
+	nl_new_line(p);
+
+	if (log->ce_mask & LOG_ATTR_GROUP)
+		nl_dump(p, "group=%u ", log->log_group);
+
+	if (log->ce_mask & LOG_ATTR_COPY_MODE)
+		nl_dump(p, "copy_mode=%s ",
+			nfnl_log_copy_mode2str(log->log_copy_mode,
+					       buf, sizeof(buf)));
+
+	if (log->ce_mask & LOG_ATTR_COPY_RANGE)
+		nl_dump(p, "copy_range=%u ", log->log_copy_range);
+
+	if (log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT)
+		nl_dump(p, "flush_timeout=%u ", log->log_flush_timeout);
+
+	if (log->ce_mask & LOG_ATTR_ALLOC_SIZE)
+		nl_dump(p, "alloc_size=%u ", log->log_alloc_size);
+
+	if (log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD)
+		nl_dump(p, "queue_threshold=%u ", log->log_queue_threshold);
+
+	nl_dump(p, "\n");
+}
+
+static const struct trans_tbl copy_modes[] = {
+	__ADD(NFNL_LOG_COPY_NONE,	none)
+	__ADD(NFNL_LOG_COPY_META,	meta)
+	__ADD(NFNL_LOG_COPY_PACKET,	packet)
+};
+
+char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf,
+			     size_t len)
+{
+	return __type2str(copy_mode, buf, len, copy_modes,
+			  ARRAY_SIZE(copy_modes));
+}
+
+enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *name)
+{
+	return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_log *nfnl_log_alloc(void)
+{
+	return (struct nfnl_log *) nl_object_alloc(&log_obj_ops);
+}
+
+void nfnl_log_get(struct nfnl_log *log)
+{
+	nl_object_get((struct nl_object *) log);
+}
+
+void nfnl_log_put(struct nfnl_log *log)
+{
+	nl_object_put((struct nl_object *) log);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_log_set_group(struct nfnl_log *log, uint16_t group)
+{
+	log->log_group = group;
+	log->ce_mask |= LOG_ATTR_GROUP;
+}
+
+int nfnl_log_test_group(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_GROUP);
+}
+
+uint16_t nfnl_log_get_group(const struct nfnl_log *log)
+{
+	return log->log_group;
+}
+
+void nfnl_log_set_copy_mode(struct nfnl_log *log, enum nfnl_log_copy_mode mode)
+{
+	log->log_copy_mode = mode;
+	log->ce_mask |= LOG_ATTR_COPY_MODE;
+}
+
+int nfnl_log_test_copy_mode(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_COPY_MODE);
+}
+
+enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *log)
+{
+	return log->log_copy_mode;
+}
+
+void nfnl_log_set_copy_range(struct nfnl_log *log, uint32_t copy_range)
+{
+	log->log_copy_range = copy_range;
+	log->ce_mask |= LOG_ATTR_COPY_RANGE;
+}
+
+int nfnl_log_test_copy_range(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_COPY_RANGE);
+}
+
+uint32_t nfnl_log_get_copy_range(const struct nfnl_log *log)
+{
+	return log->log_copy_range;
+}
+
+void nfnl_log_set_flush_timeout(struct nfnl_log *log, uint32_t timeout)
+{
+	log->log_flush_timeout = timeout;
+	log->ce_mask |= LOG_ATTR_FLUSH_TIMEOUT;
+}
+
+int nfnl_log_test_flush_timeout(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT);
+}
+
+uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *log)
+{
+	return log->log_flush_timeout;
+}
+
+void nfnl_log_set_alloc_size(struct nfnl_log *log, uint32_t alloc_size)
+{
+	log->log_alloc_size = alloc_size;
+	log->ce_mask |= LOG_ATTR_ALLOC_SIZE;
+}
+
+int nfnl_log_test_alloc_size(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_ALLOC_SIZE);
+}
+
+uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *log)
+{
+	return log->log_alloc_size;
+}
+
+void nfnl_log_set_queue_threshold(struct nfnl_log *log, uint32_t threshold)
+{
+	log->log_queue_threshold = threshold;
+	log->ce_mask |= LOG_ATTR_QUEUE_THRESHOLD;
+}
+
+int nfnl_log_test_queue_threshold(const struct nfnl_log *log)
+{
+	return !!(log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD);
+}
+
+uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *log)
+{
+	return log->log_queue_threshold;
+}
+
+/* We don't actually use the flags for anything yet since the
+ * nfnetlog_log interface truly sucks - it only contains the
+ * flag value, but not mask, so we would have to make assumptions
+ * about the supported flags.
+ */
+void nfnl_log_set_flags(struct nfnl_log *log, unsigned int flags)
+{
+	log->log_flags |= flags;
+	log->log_flag_mask |= flags;
+}
+
+void nfnl_log_unset_flags(struct nfnl_log *log, unsigned int flags)
+{
+	log->log_flags &= ~flags;
+	log->log_flag_mask |= flags;
+}
+
+static const struct trans_tbl log_flags[] = {
+	__ADD(NFNL_LOG_FLAG_SEQ,	seq)
+	__ADD(NFNL_LOG_FLAG_SEQ_GLOBAL,	seq_global)
+};
+
+char *nfnl_log_flags2str(unsigned int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, log_flags, ARRAY_SIZE(log_flags));
+}
+
+unsigned int nfnl_log_str2flags(const char *name)
+{
+	return __str2flags(name, log_flags, ARRAY_SIZE(log_flags));
+}
+
+static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b,
+			    uint32_t attrs, int flags)
+{
+	struct nfnl_log *a = (struct nfnl_log *) _a;
+	struct nfnl_log *b = (struct nfnl_log *) _b;
+	int diff = 0;
+
+#define NFNL_LOG_DIFF(ATTR, EXPR) \
+	ATTR_DIFF(attrs, LOG_ATTR_##ATTR, a, b, EXPR)
+#define NFNL_LOG_DIFF_VAL(ATTR, FIELD) \
+	NFNL_LOG_DIFF(ATTR, a->FIELD != b->FIELD)
+
+	diff |= NFNL_LOG_DIFF_VAL(GROUP,		log_group);
+	diff |= NFNL_LOG_DIFF_VAL(COPY_MODE,		log_copy_mode);
+	diff |= NFNL_LOG_DIFF_VAL(COPY_RANGE,		log_copy_range);
+	diff |= NFNL_LOG_DIFF_VAL(FLUSH_TIMEOUT,	log_flush_timeout);
+	diff |= NFNL_LOG_DIFF_VAL(ALLOC_SIZE,		log_alloc_size);
+	diff |= NFNL_LOG_DIFF_VAL(QUEUE_THRESHOLD,	log_queue_threshold);
+
+#undef NFNL_LOG_DIFF
+#undef NFNL_LOG_DIFF_VAL
+
+	return diff;
+}
+
+static const struct trans_tbl nfnl_log_attrs[] = {
+	__ADD(LOG_ATTR_GROUP,		group)
+	__ADD(LOG_ATTR_COPY_MODE,	copy_mode)
+	__ADD(LOG_ATTR_COPY_RANGE,	copy_range)
+	__ADD(LOG_ATTR_FLUSH_TIMEOUT,	flush_timeout)
+	__ADD(LOG_ATTR_ALLOC_SIZE,	alloc_size)
+	__ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold)
+};
+
+static char *nfnl_log_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, nfnl_log_attrs,
+			   ARRAY_SIZE(nfnl_log_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops log_obj_ops = {
+	.oo_name		= "netfilter/log",
+	.oo_size		= sizeof(struct nfnl_log),
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= nfnl_log_dump,
+	    [NL_DUMP_DETAILS]	= nfnl_log_dump,
+	    [NL_DUMP_STATS]	= nfnl_log_dump,
+	},
+	.oo_compare		= nfnl_log_compare,
+	.oo_attrs2str		= nfnl_log_attrs2str,
+	.oo_id_attrs		= LOG_ATTR_GROUP,
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/netfilter.c b/libnetwork/libnl3/lib/netfilter/netfilter.c
new file mode 100644
index 0000000..addecd7
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/netfilter.c
@@ -0,0 +1,53 @@
+/*
+ * lib/netfilter/netfilter.c    Netfilter Generic Functions
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netfilter/netfilter.h>
+#include <linux/netfilter.h>
+
+static const struct trans_tbl nfnl_verdicts[] = {
+	__ADD(NF_DROP,		NF_DROP)
+	__ADD(NF_ACCEPT,	NF_ACCEPT)
+	__ADD(NF_STOLEN,	NF_STOLEN)
+	__ADD(NF_QUEUE,		NF_QUEUE)
+	__ADD(NF_REPEAT,	NF_REPEAT)
+	__ADD(NF_STOP,		NF_STOP)
+};
+
+char *nfnl_verdict2str(unsigned int verdict, char *buf, size_t len)
+{
+	return __type2str(verdict, buf, len, nfnl_verdicts,
+			  ARRAY_SIZE(nfnl_verdicts));
+}
+
+unsigned int nfnl_str2verdict(const char *name)
+{
+	return __str2type(name, nfnl_verdicts, ARRAY_SIZE(nfnl_verdicts));
+}
+
+static const struct trans_tbl nfnl_inet_hooks[] = {
+	__ADD(NF_INET_PRE_ROUTING,	NF_INET_PREROUTING)
+	__ADD(NF_INET_LOCAL_IN,		NF_INET_LOCAL_IN)
+	__ADD(NF_INET_FORWARD,		NF_INET_FORWARD)
+	__ADD(NF_INET_LOCAL_OUT,	NF_INET_LOCAL_OUT)
+	__ADD(NF_INET_POST_ROUTING,	NF_INET_POST_ROUTING)
+};
+
+char *nfnl_inet_hook2str(unsigned int hook, char *buf, size_t len)
+{
+	return __type2str(hook, buf, len, nfnl_inet_hooks,
+			  ARRAY_SIZE(nfnl_inet_hooks));
+}
+
+unsigned int nfnl_str2inet_hook(const char *name)
+{
+	return __str2type(name, nfnl_inet_hooks, ARRAY_SIZE(nfnl_inet_hooks));
+}
diff --git a/libnetwork/libnl3/lib/netfilter/nfnl.c b/libnetwork/libnl3/lib/netfilter/nfnl.c
new file mode 100644
index 0000000..ddce4b9
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/nfnl.c
@@ -0,0 +1,245 @@
+/*
+ * lib/netfilter/nfnl.c		Netfilter Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc at snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+/**
+ * @defgroup nfnl Netfilter Netlink
+ *
+ * @par Message Format
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @code
+ *  <-------- NFNL_HDRLEN --------->
+ * +--------------------------+- - -+------------+
+ * | Netfilter Netlink Header | Pad | Attributes |
+ * |    struct nfgenmsg       |     |            |
+ * +--------------------------+- - -+------------+
+ * nfnlmsg_attrdata(nfg, hdrlen)-----^
+ * @endcode
+ *
+ * @par 1) Creating a new netfilter netlink message
+ * @code
+ * struct nl_msg *msg;
+ *
+ * // Create a new empty netlink message
+ * msg = nlmsg_alloc();
+ *
+ * // Append the netlink and netfilter netlink message header
+ * hdr = nfnlmsg_put(msg, PID, SEQ, SUBSYS, TYPE, NLM_F_ECHO,
+ *                   FAMILY, RES_ID);
+ *
+ * // Append the attributes.
+ * nla_put_u32(msg, 1, 0x10);
+ *
+ * // Message is ready to be sent.
+ * nl_send_auto_complete(sk, msg);
+ *
+ * // All done? Free the message.
+ * nlmsg_free(msg);
+ * @endcode
+ *
+ * @par 2) Sending of trivial messages
+ * @code
+ * // For trivial messages not requiring any subsys specific header or
+ * // attributes, nfnl_send_simple() may be used to send messages directly.
+ * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+
+/**
+ * @name Socket Creating
+ * @{
+ */
+
+/**
+ * Create and connect netfilter netlink socket.
+ * @arg sk		Netlink socket.
+ *
+ * Creates a NETLINK_NETFILTER netlink socket, binds the socket and
+ * issues a connection attempt.
+ *
+ * @see nl_connect()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nfnl_connect(struct nl_sock *sk)
+{
+	return nl_connect(sk, NETLINK_NETFILTER);
+}
+
+/** @} */
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send trivial netfilter netlink message
+ * @arg sk		Netlink socket.
+ * @arg subsys_id	nfnetlink subsystem
+ * @arg type		nfnetlink message type
+ * @arg flags		message flags
+ * @arg family		nfnetlink address family
+ * @arg res_id		nfnetlink resource id
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
+		     int flags, uint8_t family, uint16_t res_id)
+{
+	struct nfgenmsg hdr = {
+		.nfgen_family = family,
+		.version = NFNETLINK_V0,
+		.res_id = htons(res_id),
+	};
+
+	return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags,
+			      &hdr, sizeof(hdr));
+}
+
+/** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+/**
+ * Get netfilter subsystem id from message
+ * @arg nlh	netlink messsage header
+ */
+uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh)
+{
+	return NFNL_SUBSYS_ID(nlh->nlmsg_type);
+}
+
+/**
+ * Get netfilter message type from message
+ * @arg nlh	netlink messsage header
+ */
+uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
+{
+	return NFNL_MSG_TYPE(nlh->nlmsg_type);
+}
+
+/**
+ * Get netfilter family from message
+ * @arg nlh	netlink messsage header
+ */
+uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfg = nlmsg_data(nlh);
+
+	return nfg->nfgen_family;
+}
+
+/**
+ * Get netfilter resource id from message
+ * @arg nlh	netlink messsage header
+ */
+uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfg = nlmsg_data(nlh);
+
+	return ntohs(nfg->res_id);
+}
+
+/** @} */
+
+/**
+ * @name Message Building
+ * @{
+ */
+
+static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id)
+{
+	struct nfgenmsg *nfg;
+
+	nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
+	if (nfg == NULL)
+		return -NLE_NOMEM;
+
+	nfg->nfgen_family = family;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(res_id);
+	NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n",
+	       msg, family, res_id);
+	return 0;
+}
+
+/**
+ * Allocate a new netfilter netlink message
+ * @arg subsys_id	nfnetlink subsystem
+ * @arg type		nfnetlink message type
+ * @arg flags		message flags
+ * @arg family		nfnetlink address family
+ * @arg res_id		nfnetlink resource id
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags,
+				    uint8_t family, uint16_t res_id)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags);
+	if (msg == NULL)
+		return NULL;
+
+	if (nfnlmsg_append(msg, family, res_id) < 0)
+		goto nla_put_failure;
+
+	return msg;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+/**
+ * Add netlink and netfilter netlink headers to netlink message
+ * @arg msg		netlink message
+ * @arg pid		netlink process id
+ * @arg seq		sequence number of message
+ * @arg subsys_id	nfnetlink subsystem
+ * @arg type		nfnetlink message type
+ * @arg flags		message flags
+ * @arg family		nfnetlink address family
+ * @arg res_id		nfnetlink resource id
+ */
+int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq,
+		uint8_t subsys_id, uint8_t type, int flags, uint8_t family,
+		uint16_t res_id)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
+	if (nlh == NULL)
+		return -NLE_MSGSIZE;
+
+	return nfnlmsg_append(msg, family, res_id);
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/queue.c b/libnetwork/libnl3/lib/netfilter/queue.c
new file mode 100644
index 0000000..ff1de0e
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/queue.c
@@ -0,0 +1,251 @@
+/*
+ * lib/netfilter/queue.c	Netfilter Queue
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+
+#include <netlink-local.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+
+struct nl_sock *nfnl_queue_socket_alloc(void)
+{
+	struct nl_sock *nlsk;
+
+	nlsk = nl_socket_alloc();
+	if (nlsk)
+		nl_socket_disable_auto_ack(nlsk);
+	return nlsk;
+}
+
+static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
+{
+	int err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/**
+ * @name Queue Commands
+ * @{
+ */
+
+static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
+				   uint8_t command, struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct nfqnl_msg_config_cmd cmd;
+
+	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
+				   family, queuenum);
+	if (msg == NULL)
+		return -NLE_NOMEM;
+
+	cmd.pf = htons(family);
+	cmd._pad = 0;
+	cmd.command = command;
+	if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+		goto nla_put_failure;
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
+{
+	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
+}
+
+int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
+		return err;
+
+	return send_queue_request(nlh, msg);
+}
+
+int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
+{
+	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
+}
+
+int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
+		return err;
+
+	return send_queue_request(nlh, msg);
+}
+
+static int nfnl_queue_build_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
+{
+	struct nl_msg *msg;
+
+	if (!nfnl_queue_test_group(queue))
+		return -NLE_MISSING_ATTR;
+
+	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
+				   0, nfnl_queue_get_group(queue));
+	if (msg == NULL)
+		return -NLE_NOMEM;
+
+	if (nfnl_queue_test_maxlen(queue) &&
+	    nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
+			htonl(nfnl_queue_get_maxlen(queue))) < 0)
+		goto nla_put_failure;
+
+	/* This sucks, the nfnetlink_queue interface always expects both
+	 * parameters to be present. Needs to be done properly.
+	 */
+	if (nfnl_queue_test_copy_mode(queue)) {
+		struct nfqnl_msg_config_params params;
+
+		switch (nfnl_queue_get_copy_mode(queue)) {
+		case NFNL_QUEUE_COPY_NONE:
+			params.copy_mode = NFQNL_COPY_NONE;
+			break;
+		case NFNL_QUEUE_COPY_META:
+			params.copy_mode = NFQNL_COPY_META;
+			break;
+		case NFNL_QUEUE_COPY_PACKET:
+			params.copy_mode = NFQNL_COPY_PACKET;
+			break;
+		}
+		params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
+
+		if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
+			goto nla_put_failure;
+	}
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
+{
+	struct nfqnl_msg_config_cmd cmd;
+	int err;
+
+	if ((err = nfnl_queue_build_request(queue, result)) < 0)
+		return err;
+
+	cmd.pf = 0;
+	cmd._pad = 0;
+	cmd.command = NFQNL_CFG_CMD_BIND;
+
+	NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
+
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(*result);
+	return -NLE_MSGSIZE;
+}
+
+int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
+		return err;
+
+	return send_queue_request(nlh, msg);
+}
+
+int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
+{
+	return nfnl_queue_build_request(queue, result);
+}
+
+int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
+		return err;
+
+	return send_queue_request(nlh, msg);
+}
+
+int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
+{
+	if (!nfnl_queue_test_group(queue))
+		return -NLE_MISSING_ATTR;
+
+	return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
+				       NFQNL_CFG_CMD_UNBIND, result);
+}
+
+int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
+		return err;
+
+	return send_queue_request(nlh, msg);
+}
+
+/** @} */
+
+static struct nl_cache_ops nfnl_queue_ops = {
+	.co_name		= "netfilter/queue",
+	.co_obj_ops		= &queue_obj_ops,
+	.co_msgtypes		= {
+		END_OF_MSGTYPES_LIST,
+	},
+};
+
+static void __init nfnl_queue_init(void)
+{
+	nl_cache_mngt_register(&nfnl_queue_ops);
+}
+
+static void __exit nfnl_queue_exit(void)
+{
+	nl_cache_mngt_unregister(&nfnl_queue_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/queue_msg.c b/libnetwork/libnl3/lib/netfilter/queue_msg.c
new file mode 100644
index 0000000..c40f8c2
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/queue_msg.c
@@ -0,0 +1,284 @@
+/*
+ * lib/netfilter/queue_msg.c	Netfilter Queue Messages
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ * Copyright (c) 2010       Karl Hiramoto <karl at hiramoto.org>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+
+#include <netlink-local.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue_msg.h>
+
+static struct nl_cache_ops nfnl_queue_msg_ops;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+	return __bswap_64(x);
+}
+#endif
+
+static struct nla_policy queue_policy[NFQA_MAX+1] = {
+	[NFQA_PACKET_HDR]		= {
+		.minlen	= sizeof(struct nfqnl_msg_packet_hdr),
+	},
+	[NFQA_VERDICT_HDR]		= {
+		.minlen	= sizeof(struct nfqnl_msg_verdict_hdr),
+	},
+	[NFQA_MARK]			= { .type = NLA_U32 },
+	[NFQA_TIMESTAMP]		= {
+		.minlen = sizeof(struct nfqnl_msg_packet_timestamp),
+	},
+	[NFQA_IFINDEX_INDEV]		= { .type = NLA_U32 },
+	[NFQA_IFINDEX_OUTDEV]		= { .type = NLA_U32 },
+	[NFQA_IFINDEX_PHYSINDEV]	= { .type = NLA_U32 },
+	[NFQA_IFINDEX_PHYSOUTDEV]	= { .type = NLA_U32 },
+	[NFQA_HWADDR]			= {
+		.minlen	= sizeof(struct nfqnl_msg_packet_hw),
+	},
+};
+
+int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh,
+			    struct nfnl_queue_msg **result)
+{
+	struct nfnl_queue_msg *msg;
+	struct nlattr *tb[NFQA_MAX+1];
+	struct nlattr *attr;
+	int err;
+
+	msg = nfnl_queue_msg_alloc();
+	if (!msg)
+		return -NLE_NOMEM;
+
+	msg->ce_msgtype = nlh->nlmsg_type;
+
+	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX,
+			  queue_policy);
+	if (err < 0)
+		goto errout;
+
+	nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh));
+	nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh));
+
+	attr = tb[NFQA_PACKET_HDR];
+	if (attr) {
+		struct nfqnl_msg_packet_hdr *hdr = nla_data(attr);
+
+		nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id));
+		if (hdr->hw_protocol)
+			nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol);
+		nfnl_queue_msg_set_hook(msg, hdr->hook);
+	}
+
+	attr = tb[NFQA_MARK];
+	if (attr)
+		nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFQA_TIMESTAMP];
+	if (attr) {
+		struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr);
+		struct timeval tv;
+
+		tv.tv_sec = ntohll(timestamp->sec);
+		tv.tv_usec = ntohll(timestamp->usec);
+		nfnl_queue_msg_set_timestamp(msg, &tv);
+	}
+
+	attr = tb[NFQA_IFINDEX_INDEV];
+	if (attr)
+		nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFQA_IFINDEX_OUTDEV];
+	if (attr)
+		nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFQA_IFINDEX_PHYSINDEV];
+	if (attr)
+		nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFQA_IFINDEX_PHYSOUTDEV];
+	if (attr)
+		nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
+
+	attr = tb[NFQA_HWADDR];
+	if (attr) {
+		struct nfqnl_msg_packet_hw *hw = nla_data(attr);
+
+		nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr,
+					  ntohs(hw->hw_addrlen));
+	}
+
+	attr = tb[NFQA_PAYLOAD];
+	if (attr) {
+		err = nfnl_queue_msg_set_payload(msg, nla_data(attr),
+						 nla_len(attr));
+		if (err < 0)
+			goto errout;
+	}
+
+	*result = msg;
+	return 0;
+
+errout:
+	nfnl_queue_msg_put(msg);
+	return err;
+}
+
+static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct nfnl_queue_msg *msg;
+	int err;
+
+	if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0)
+		goto errout;
+
+	err = pp->pp_cb((struct nl_object *) msg, pp);
+errout:
+	nfnl_queue_msg_put(msg);
+	return err;
+}
+
+/** @} */
+
+struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
+{
+	struct nl_msg *nlmsg;
+	struct nfqnl_msg_verdict_hdr verdict;
+
+	nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0,
+				     nfnl_queue_msg_get_family(msg),
+				     nfnl_queue_msg_get_group(msg));
+	if (nlmsg == NULL)
+		return NULL;
+
+	verdict.id = htonl(nfnl_queue_msg_get_packetid(msg));
+	verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg));
+	if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0)
+		goto nla_put_failure;
+
+	if (nfnl_queue_msg_test_mark(msg) &&
+	    nla_put_u32(nlmsg, NFQA_MARK,
+			ntohl(nfnl_queue_msg_get_mark(msg))) < 0)
+		goto nla_put_failure;
+
+	return nlmsg;
+
+nla_put_failure:
+	nlmsg_free(nlmsg);
+	return NULL;
+}
+
+/**
+* Send a message verdict/mark
+* @arg nlh            netlink messsage header
+* @arg msg            queue msg
+* @return 0 on OK or error code
+*/
+int nfnl_queue_msg_send_verdict(struct nl_sock *nlh,
+				const struct nfnl_queue_msg *msg)
+{
+	struct nl_msg *nlmsg;
+	int err;
+
+	nlmsg = nfnl_queue_msg_build_verdict(msg);
+	if (nlmsg == NULL)
+		return -NLE_NOMEM;
+
+	err = nl_send_auto_complete(nlh, nlmsg);
+	nlmsg_free(nlmsg);
+	if (err < 0)
+		return err;
+	return wait_for_ack(nlh);
+}
+
+/**
+* Send a message verdict including the payload
+* @arg nlh            netlink messsage header
+* @arg msg            queue msg
+* @arg payload_data   packet payload data
+* @arg payload_len    payload length
+* @return 0 on OK or error code
+*/
+int nfnl_queue_msg_send_verdict_payload(struct nl_sock *nlh,
+				const struct nfnl_queue_msg *msg,
+				const void *payload_data, unsigned payload_len)
+{
+	struct nl_msg *nlmsg;
+	int err;
+	struct iovec iov[3];
+	struct nlattr nla;
+
+	nlmsg = nfnl_queue_msg_build_verdict(msg);
+	if (nlmsg == NULL)
+		return -NLE_NOMEM;
+
+	memset(iov, 0, sizeof(iov));
+
+	iov[0].iov_base = (void *) nlmsg_hdr(nlmsg);
+	iov[0].iov_len = nlmsg_hdr(nlmsg)->nlmsg_len;
+
+	nla.nla_type = NFQA_PAYLOAD;
+	nla.nla_len = payload_len + sizeof(nla);
+	nlmsg_hdr(nlmsg)->nlmsg_len += nla.nla_len;
+
+	iov[1].iov_base = (void *) &nla;
+	iov[1].iov_len = sizeof(nla);
+
+	iov[2].iov_base = (void *) payload_data;
+	iov[2].iov_len = NLA_ALIGN(payload_len);
+
+	nl_complete_msg(nlh, nlmsg);
+	err = nl_send_iovec(nlh, nlmsg, iov, 3);
+
+	nlmsg_free(nlmsg);
+	if (err < 0)
+		return err;
+	return wait_for_ack(nlh);
+}
+
+#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type))
+static struct nl_cache_ops nfnl_queue_msg_ops = {
+	.co_name		= "netfilter/queue_msg",
+	.co_hdrsize		= NFNL_HDRLEN,
+	.co_msgtypes		= {
+		{ NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" },
+		END_OF_MSGTYPES_LIST,
+	},
+	.co_protocol		= NETLINK_NETFILTER,
+	.co_msg_parser		= queue_msg_parser,
+	.co_obj_ops		= &queue_msg_obj_ops,
+};
+
+static void __init nfnl_msg_queue_init(void)
+{
+	nl_cache_mngt_register(&nfnl_queue_msg_ops);
+}
+
+static void __exit nfnl_queue_msg_exit(void)
+{
+	nl_cache_mngt_unregister(&nfnl_queue_msg_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c b/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c
new file mode 100644
index 0000000..33305ed
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c
@@ -0,0 +1,492 @@
+/*
+ * lib/netfilter/queue_msg_obj.c	Netfilter Queue Message Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/netfilter.h>
+#include <netlink/netfilter/queue_msg.h>
+#include <linux/netfilter.h>
+
+/** @cond SKIP */
+#define QUEUE_MSG_ATTR_GROUP		(1UL << 0)
+#define QUEUE_MSG_ATTR_FAMILY		(1UL << 1)
+#define QUEUE_MSG_ATTR_PACKETID		(1UL << 2)
+#define QUEUE_MSG_ATTR_HWPROTO		(1UL << 3)
+#define QUEUE_MSG_ATTR_HOOK		(1UL << 4)
+#define QUEUE_MSG_ATTR_MARK		(1UL << 5)
+#define QUEUE_MSG_ATTR_TIMESTAMP	(1UL << 6)
+#define QUEUE_MSG_ATTR_INDEV		(1UL << 7)
+#define QUEUE_MSG_ATTR_OUTDEV		(1UL << 8)
+#define QUEUE_MSG_ATTR_PHYSINDEV	(1UL << 9)
+#define QUEUE_MSG_ATTR_PHYSOUTDEV	(1UL << 10)
+#define QUEUE_MSG_ATTR_HWADDR		(1UL << 11)
+#define QUEUE_MSG_ATTR_PAYLOAD		(1UL << 12)
+#define QUEUE_MSG_ATTR_VERDICT		(1UL << 13)
+/** @endcond */
+
+static void nfnl_queue_msg_free_data(struct nl_object *c)
+{
+	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c;
+
+	if (msg == NULL)
+		return;
+
+	free(msg->queue_msg_payload);
+}
+
+static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst;
+	struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src;
+	int err;
+
+	if (src->queue_msg_payload) {
+		err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload,
+						 src->queue_msg_payload_len);
+		if (err < 0)
+			goto errout;
+	}
+
+	return 0;
+errout:
+	return err;
+}
+
+static void nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a;
+	struct nl_cache *link_cache;
+	char buf[64];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	nl_new_line(p);
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP)
+		nl_dump(p, "GROUP=%u ", msg->queue_msg_group);
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) {
+		if (link_cache)
+			nl_dump(p, "IN=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->queue_msg_indev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "IN=%d ", msg->queue_msg_indev);
+	}
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) {
+		if (link_cache)
+			nl_dump(p, "PHYSIN=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->queue_msg_physindev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "IN=%d ", msg->queue_msg_physindev);
+	}
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) {
+		if (link_cache)
+			nl_dump(p, "OUT=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->queue_msg_outdev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "OUT=%d ", msg->queue_msg_outdev);
+	}
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) {
+		if (link_cache)
+			nl_dump(p, "PHYSOUT=%s ",
+				rtnl_link_i2name(link_cache,
+						 msg->queue_msg_physoutdev,
+						 buf, sizeof(buf)));
+		else
+			nl_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev);
+	}
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) {
+		int i;
+
+		nl_dump(p, "MAC");
+		for (i = 0; i < msg->queue_msg_hwaddr_len; i++)
+			nl_dump(p, "%c%02x", i?':':'=',
+				msg->queue_msg_hwaddr[i]);
+		nl_dump(p, " ");
+	}
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
+		nl_dump(p, "FAMILY=%s ",
+			nl_af2str(msg->queue_msg_family, buf, sizeof(buf)));
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO)
+		nl_dump(p, "HWPROTO=%s ",
+			nl_ether_proto2str(ntohs(msg->queue_msg_hwproto),
+					   buf, sizeof(buf)));
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK)
+		nl_dump(p, "HOOK=%s ",
+			nfnl_inet_hook2str(msg->queue_msg_hook,
+					   buf, sizeof(buf)));
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_MARK)
+		nl_dump(p, "MARK=%d ", msg->queue_msg_mark);
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)
+		nl_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len);
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID)
+		nl_dump(p, "PACKETID=%u ", msg->queue_msg_packetid);
+
+	if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT)
+		nl_dump(p, "VERDICT=%s ",
+			nfnl_verdict2str(msg->queue_msg_verdict,
+					 buf, sizeof(buf)));
+
+	nl_dump(p, "\n");
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_queue_msg *nfnl_queue_msg_alloc(void)
+{
+	return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops);
+}
+
+void nfnl_queue_msg_get(struct nfnl_queue_msg *msg)
+{
+	nl_object_get((struct nl_object *) msg);
+}
+
+void nfnl_queue_msg_put(struct nfnl_queue_msg *msg)
+{
+	nl_object_put((struct nl_object *) msg);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group)
+{
+	msg->queue_msg_group = group;
+	msg->ce_mask |= QUEUE_MSG_ATTR_GROUP;
+}
+
+int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP);
+}
+
+uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_group;
+}
+
+/**
+* Set the protocol family
+* @arg msg         NF queue message
+* @arg family      AF_XXX  address family  example: AF_INET, AF_UNIX, etc
+*/
+void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family)
+{
+	msg->queue_msg_family = family;
+	msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY;
+}
+
+int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY);
+}
+
+uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg)
+{
+	if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
+		return msg->queue_msg_family;
+	else
+		return AF_UNSPEC;
+}
+
+void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid)
+{
+	msg->queue_msg_packetid = packetid;
+	msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID;
+}
+
+int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID);
+}
+
+uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_packetid;
+}
+
+void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto)
+{
+	msg->queue_msg_hwproto = hwproto;
+	msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO;
+}
+
+int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO);
+}
+
+uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_hwproto;
+}
+
+void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook)
+{
+	msg->queue_msg_hook = hook;
+	msg->ce_mask |= QUEUE_MSG_ATTR_HOOK;
+}
+
+int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK);
+}
+
+uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_hook;
+}
+
+void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark)
+{
+	msg->queue_msg_mark = mark;
+	msg->ce_mask |= QUEUE_MSG_ATTR_MARK;
+}
+
+int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK);
+}
+
+uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_mark;
+}
+
+void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg,
+				  struct timeval *tv)
+{
+	msg->queue_msg_timestamp.tv_sec = tv->tv_sec;
+	msg->queue_msg_timestamp.tv_usec = tv->tv_usec;
+	msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP;
+}
+
+int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP);
+}
+
+const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg)
+{
+	if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP))
+		return NULL;
+	return &msg->queue_msg_timestamp;
+}
+
+void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev)
+{
+	msg->queue_msg_indev = indev;
+	msg->ce_mask |= QUEUE_MSG_ATTR_INDEV;
+}
+
+int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV);
+}
+
+uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_indev;
+}
+
+void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev)
+{
+	msg->queue_msg_outdev = outdev;
+	msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV;
+}
+
+int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV);
+}
+
+uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_outdev;
+}
+
+void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg,
+				  uint32_t physindev)
+{
+	msg->queue_msg_physindev = physindev;
+	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV;
+}
+
+int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV);
+}
+
+uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_physindev;
+}
+
+void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg,
+				   uint32_t physoutdev)
+{
+	msg->queue_msg_physoutdev = physoutdev;
+	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV;
+}
+
+int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV);
+}
+
+uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_physoutdev;
+}
+
+void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
+			       int len)
+{
+	if (len > sizeof(msg->queue_msg_hwaddr))
+		len = sizeof(msg->queue_msg_hwaddr);
+
+	msg->queue_msg_hwaddr_len = len;
+	memcpy(msg->queue_msg_hwaddr, hwaddr, len);
+	msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR;
+}
+
+int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR);
+}
+
+const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
+					 int *len)
+{
+	if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = msg->queue_msg_hwaddr_len;
+	return msg->queue_msg_hwaddr;
+}
+
+int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
+			       int len)
+{
+	free(msg->queue_msg_payload);
+	msg->queue_msg_payload = malloc(len);
+	if (!msg->queue_msg_payload)
+		return -NLE_NOMEM;
+
+	memcpy(msg->queue_msg_payload, payload, len);
+	msg->queue_msg_payload_len = len;
+	msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
+	return 0;
+}
+
+int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD);
+}
+
+const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len)
+{
+	if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = msg->queue_msg_payload_len;
+	return msg->queue_msg_payload;
+}
+
+/**
+* Return the number of items matching a filter in the cache
+* @arg msg        queue msg
+* @arg verdict    NF_DROP, NF_ACCEPT, NF_REPEAT, etc
+*/
+void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg,
+				unsigned int verdict)
+{
+	msg->queue_msg_verdict = verdict;
+	msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT;
+}
+
+int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg)
+{
+	return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT);
+}
+
+unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
+{
+	return msg->queue_msg_verdict;
+}
+
+static const struct trans_tbl nfnl_queue_msg_attrs[] = {
+	__ADD(QUEUE_MSG_ATTR_GROUP,		group)
+	__ADD(QUEUE_MSG_ATTR_FAMILY,		family)
+	__ADD(QUEUE_MSG_ATTR_PACKETID,		packetid)
+	__ADD(QUEUE_MSG_ATTR_HWPROTO,		hwproto)
+	__ADD(QUEUE_MSG_ATTR_HOOK,		hook)
+	__ADD(QUEUE_MSG_ATTR_MARK,		mark)
+	__ADD(QUEUE_MSG_ATTR_TIMESTAMP,		timestamp)
+	__ADD(QUEUE_MSG_ATTR_INDEV,		indev)
+	__ADD(QUEUE_MSG_ATTR_OUTDEV,		outdev)
+	__ADD(QUEUE_MSG_ATTR_PHYSINDEV,		physindev)
+	__ADD(QUEUE_MSG_ATTR_PHYSOUTDEV,	physoutdev)
+	__ADD(QUEUE_MSG_ATTR_HWADDR,		hwaddr)
+	__ADD(QUEUE_MSG_ATTR_PAYLOAD,		payload)
+	__ADD(QUEUE_MSG_ATTR_VERDICT,		verdict)
+};
+
+static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs,
+			   ARRAY_SIZE(nfnl_queue_msg_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops queue_msg_obj_ops = {
+	.oo_name		= "netfilter/queuemsg",
+	.oo_size		= sizeof(struct nfnl_queue_msg),
+	.oo_free_data		= nfnl_queue_msg_free_data,
+	.oo_clone		= nfnl_queue_msg_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= nfnl_queue_msg_dump,
+	    [NL_DUMP_DETAILS]	= nfnl_queue_msg_dump,
+	    [NL_DUMP_STATS]	= nfnl_queue_msg_dump,
+	},
+	.oo_attrs2str		= nfnl_queue_msg_attrs2str,
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/netfilter/queue_obj.c b/libnetwork/libnl3/lib/netfilter/queue_obj.c
new file mode 100644
index 0000000..05a9cb8
--- /dev/null
+++ b/libnetwork/libnl3/lib/netfilter/queue_obj.c
@@ -0,0 +1,215 @@
+/*
+ * lib/netfilter/queue_obj.c	Netfilter Queue
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+
+/** @cond SKIP */
+#define QUEUE_ATTR_GROUP		(1UL << 0)
+#define QUEUE_ATTR_MAXLEN		(1UL << 1)
+#define QUEUE_ATTR_COPY_MODE		(1UL << 2)
+#define QUEUE_ATTR_COPY_RANGE		(1UL << 3)
+/** @endcond */
+
+
+static void nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct nfnl_queue *queue = (struct nfnl_queue *) a;
+	char buf[64];
+
+	nl_new_line(p);
+
+	if (queue->ce_mask & QUEUE_ATTR_GROUP)
+		nl_dump(p, "group=%u ", queue->queue_group);
+
+	if (queue->ce_mask & QUEUE_ATTR_MAXLEN)
+		nl_dump(p, "maxlen=%u ", queue->queue_maxlen);
+
+	if (queue->ce_mask & QUEUE_ATTR_COPY_MODE)
+		nl_dump(p, "copy_mode=%s ",
+			nfnl_queue_copy_mode2str(queue->queue_copy_mode,
+						 buf, sizeof(buf)));
+
+	if (queue->ce_mask & QUEUE_ATTR_COPY_RANGE)
+		nl_dump(p, "copy_range=%u ", queue->queue_copy_range);
+
+	nl_dump(p, "\n");
+}
+
+static const struct trans_tbl copy_modes[] = {
+	__ADD(NFNL_QUEUE_COPY_NONE,	none)
+	__ADD(NFNL_QUEUE_COPY_META,	meta)
+	__ADD(NFNL_QUEUE_COPY_PACKET,	packet)
+};
+
+char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf,
+			       size_t len)
+{
+	return __type2str(copy_mode, buf, len, copy_modes,
+			   ARRAY_SIZE(copy_modes));
+}
+
+enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name)
+{
+	return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_queue *nfnl_queue_alloc(void)
+{
+	return (struct nfnl_queue *) nl_object_alloc(&queue_obj_ops);
+}
+
+void nfnl_queue_get(struct nfnl_queue *queue)
+{
+	nl_object_get((struct nl_object *) queue);
+}
+
+void nfnl_queue_put(struct nfnl_queue *queue)
+{
+	nl_object_put((struct nl_object *) queue);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_queue_set_group(struct nfnl_queue *queue, uint16_t group)
+{
+	queue->queue_group = group;
+	queue->ce_mask |= QUEUE_ATTR_GROUP;
+}
+
+int nfnl_queue_test_group(const struct nfnl_queue *queue)
+{
+	return !!(queue->ce_mask & QUEUE_ATTR_GROUP);
+}
+
+uint16_t nfnl_queue_get_group(const struct nfnl_queue *queue)
+{
+	return queue->queue_group;
+}
+
+void nfnl_queue_set_maxlen(struct nfnl_queue *queue, uint32_t maxlen)
+{
+	queue->queue_maxlen = maxlen;
+	queue->ce_mask |= QUEUE_ATTR_MAXLEN;
+}
+
+int nfnl_queue_test_maxlen(const struct nfnl_queue *queue)
+{
+	return !!(queue->ce_mask & QUEUE_ATTR_MAXLEN);
+}
+
+uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *queue)
+{
+	return queue->queue_maxlen;
+}
+
+void nfnl_queue_set_copy_mode(struct nfnl_queue *queue, enum nfnl_queue_copy_mode mode)
+{
+	queue->queue_copy_mode = mode;
+	queue->ce_mask |= QUEUE_ATTR_COPY_MODE;
+}
+
+int nfnl_queue_test_copy_mode(const struct nfnl_queue *queue)
+{
+	return !!(queue->ce_mask & QUEUE_ATTR_COPY_MODE);
+}
+
+enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *queue)
+{
+	return queue->queue_copy_mode;
+}
+
+void nfnl_queue_set_copy_range(struct nfnl_queue *queue, uint32_t copy_range)
+{
+	queue->queue_copy_range = copy_range;
+	queue->ce_mask |= QUEUE_ATTR_COPY_RANGE;
+}
+
+int nfnl_queue_test_copy_range(const struct nfnl_queue *queue)
+{
+	return !!(queue->ce_mask & QUEUE_ATTR_COPY_RANGE);
+}
+
+uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue)
+{
+	return queue->queue_copy_range;
+}
+
+static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
+			      uint32_t attrs, int flags)
+{
+	struct nfnl_queue *a = (struct nfnl_queue *) _a;
+	struct nfnl_queue *b = (struct nfnl_queue *) _b;
+	int diff = 0;
+
+#define NFNL_QUEUE_DIFF(ATTR, EXPR) \
+	ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR)
+#define NFNL_QUEUE_DIFF_VAL(ATTR, FIELD) \
+	NFNL_QUEUE_DIFF(ATTR, a->FIELD != b->FIELD)
+
+	diff |= NFNL_QUEUE_DIFF_VAL(GROUP,	queue_group);
+	diff |= NFNL_QUEUE_DIFF_VAL(MAXLEN,	queue_maxlen);
+	diff |= NFNL_QUEUE_DIFF_VAL(COPY_MODE,	queue_copy_mode);
+	diff |= NFNL_QUEUE_DIFF_VAL(COPY_RANGE,	queue_copy_range);
+
+#undef NFNL_QUEUE_DIFF
+#undef NFNL_QUEUE_DIFF_VAL
+
+	return diff;
+}
+
+static const struct trans_tbl nfnl_queue_attrs[] = {
+	__ADD(QUEUE_ATTR_GROUP,		group)
+	__ADD(QUEUE_ATTR_MAXLEN,	maxlen)
+	__ADD(QUEUE_ATTR_COPY_MODE,	copy_mode)
+	__ADD(QUEUE_ATTR_COPY_RANGE,	copy_range)
+};
+
+static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, nfnl_queue_attrs,
+			   ARRAY_SIZE(nfnl_queue_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops queue_obj_ops = {
+	.oo_name		= "netfilter/queue",
+	.oo_size		= sizeof(struct nfnl_queue),
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= nfnl_queue_dump,
+	    [NL_DUMP_DETAILS]	= nfnl_queue_dump,
+	    [NL_DUMP_STATS]	= nfnl_queue_dump,
+	},
+	.oo_compare		= nfnl_queue_compare,
+	.oo_attrs2str		= nfnl_queue_attrs2str,
+	.oo_id_attrs		= QUEUE_ATTR_GROUP,
+};
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/nl.c b/libnetwork/libnl3/lib/nl.c
new file mode 100644
index 0000000..bcf89da
--- /dev/null
+++ b/libnetwork/libnl3/lib/nl.c
@@ -0,0 +1,896 @@
+/*
+ * lib/nl.c		Core Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @defgroup core Core
+ *
+ * @details
+ * @par 1) Connecting the socket
+ * @code
+ * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
+ * nl_connect(sk, NETLINK_ROUTE);
+ * @endcode
+ *
+ * @par 2) Sending data
+ * @code
+ * // The most rudimentary method is to use nl_sendto() simply pushing
+ * // a piece of data to the other netlink peer. This method is not
+ * // recommended.
+ * const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
+ * nl_sendto(sk, buf, sizeof(buf));
+ *
+ * // A more comfortable interface is nl_send() taking a pointer to
+ * // a netlink message.
+ * struct nl_msg *msg = my_msg_builder();
+ * nl_send(sk, nlmsg_hdr(msg));
+ *
+ * // nl_sendmsg() provides additional control over the sendmsg() message
+ * // header in order to allow more specific addressing of multiple peers etc.
+ * struct msghdr hdr = { ... };
+ * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr);
+ *
+ * // You're probably too lazy to fill out the netlink pid, sequence number
+ * // and message flags all the time. nl_send_auto_complete() automatically
+ * // extends your message header as needed with an appropriate sequence
+ * // number, the netlink pid stored in the netlink socket and the message
+ * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket)
+ * nl_send_auto_complete(sk, nlmsg_hdr(msg));
+ *
+ * // Simple protocols don't require the complex message construction interface
+ * // and may favour nl_send_simple() to easly send a bunch of payload
+ * // encapsulated in a netlink message header.
+ * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf));
+ * @endcode
+ *
+ * @par 3) Receiving data
+ * @code
+ * // nl_recv() receives a single message allocating a buffer for the message
+ * // content and gives back the pointer to you.
+ * struct sockaddr_nl peer;
+ * unsigned char *msg;
+ * nl_recv(sk, &peer, &msg);
+ *
+ * // nl_recvmsgs() receives a bunch of messages until the callback system
+ * // orders it to state, usually after receving a compolete multi part
+ * // message series.
+ * nl_recvmsgs(sk, my_callback_configuration);
+ *
+ * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
+ * // configuration stored in the socket.
+ * nl_recvmsgs_default(sk);
+ *
+ * // In case you want to wait for the ACK to be recieved that you requested
+ * // with your latest message, you can call nl_wait_for_ack()
+ * nl_wait_for_ack(sk);
+ * @endcode
+ *
+ * @par 4) Closing
+ * @code
+ * // Close the socket first to release kernel memory
+ * nl_close(sk);
+ * @endcode
+ * 
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+/**
+ * @name Connection Management
+ * @{
+ */
+
+/**
+ * Create and connect netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg protocol	Netlink protocol to use.
+ *
+ * Creates a netlink socket using the specified protocol, binds the socket
+ * and issues a connection attempt.
+ *
+ * @note SOCK_CLOEXEC is set on the socket if available.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_connect(struct nl_sock *sk, int protocol)
+{
+	int err, flags = 0;
+	socklen_t addrlen;
+
+#ifdef SOCK_CLOEXEC
+	flags |= SOCK_CLOEXEC;
+#endif
+
+	sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
+	if (sk->s_fd < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
+		err = nl_socket_set_buffer_size(sk, 0, 0);
+		if (err < 0)
+			goto errout;
+	}
+
+	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
+		   sizeof(sk->s_local));
+	if (err < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	addrlen = sizeof(sk->s_local);
+	err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
+			  &addrlen);
+	if (err < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	if (addrlen != sizeof(sk->s_local)) {
+		err = -NLE_NOADDR;
+		goto errout;
+	}
+
+	if (sk->s_local.nl_family != AF_NETLINK) {
+		err = -NLE_AF_NOSUPPORT;
+		goto errout;
+	}
+
+	sk->s_proto = protocol;
+
+	return 0;
+errout:
+	close(sk->s_fd);
+	sk->s_fd = -1;
+
+	return err;
+}
+
+/**
+ * Close/Disconnect netlink socket.
+ * @arg sk		Netlink socket.
+ */
+void nl_close(struct nl_sock *sk)
+{
+	if (sk->s_fd >= 0) {
+		close(sk->s_fd);
+		sk->s_fd = -1;
+	}
+
+	sk->s_proto = 0;
+}
+
+/** @} */
+
+/**
+ * @name Send
+ * @{
+ */
+
+/**
+ * Send raw data over netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg buf		Data buffer.
+ * @arg size		Size of data buffer.
+ * @return Number of characters written on success or a negative error code.
+ */
+int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
+{
+	int ret;
+
+	ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
+		     &sk->s_peer, sizeof(sk->s_peer));
+	if (ret < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return ret;
+}
+
+/**
+ * Send netlink message with control over sendmsg() message header.
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ * @arg hdr		Sendmsg() message header.
+ * @return Number of characters sent on sucess or a negative error code.
+ */
+int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
+{
+	struct nl_cb *cb;
+	int ret;
+
+	nlmsg_set_src(msg, &sk->s_local);
+
+	cb = sk->s_cb;
+	if (cb->cb_set[NL_CB_MSG_OUT])
+		if ((ret = nl_cb_call(cb, NL_CB_MSG_OUT, msg)) != NL_OK)
+			return ret;
+
+	ret = sendmsg(sk->s_fd, hdr, 0);
+	if (ret < 0)
+		return -nl_syserr2nlerr(errno);
+
+	NL_DBG(4, "sent %d bytes\n", ret);
+	return ret;
+}
+
+
+/**
+ * Send netlink message.
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ * @arg iov		iovec to be sent.
+ * @arg iovlen		number of struct iovec to be sent.
+ * @see nl_sendmsg()
+ * @return Number of characters sent on success or a negative error code.
+ */
+int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
+{
+	struct sockaddr_nl *dst;
+	struct ucred *creds;
+	struct msghdr hdr = {
+		.msg_name = (void *) &sk->s_peer,
+		.msg_namelen = sizeof(struct sockaddr_nl),
+		.msg_iov = iov,
+		.msg_iovlen = iovlen,
+	};
+
+	/* Overwrite destination if specified in the message itself, defaults
+	 * to the peer address of the socket.
+	 */
+	dst = nlmsg_get_dst(msg);
+	if (dst->nl_family == AF_NETLINK)
+		hdr.msg_name = dst;
+
+	/* Add credentials if present. */
+	creds = nlmsg_get_creds(msg);
+	if (creds != NULL) {
+		char buf[CMSG_SPACE(sizeof(struct ucred))];
+		struct cmsghdr *cmsg;
+
+		hdr.msg_control = buf;
+		hdr.msg_controllen = sizeof(buf);
+
+		cmsg = CMSG_FIRSTHDR(&hdr);
+		cmsg->cmsg_level = SOL_SOCKET;
+		cmsg->cmsg_type = SCM_CREDENTIALS;
+		cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+		memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
+	}
+
+	return nl_sendmsg(sk, msg, &hdr);
+}
+
+
+
+/**
+* Send netlink message.
+* @arg sk		Netlink socket.
+* @arg msg		Netlink message to be sent.
+* @see nl_sendmsg()
+* @return Number of characters sent on success or a negative error code.
+*/
+int nl_send(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct iovec iov = {
+		.iov_base = (void *) nlmsg_hdr(msg),
+		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
+	};
+
+	return nl_send_iovec(sk, msg, &iov, 1);
+}
+
+void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_hdr(msg);
+	if (nlh->nlmsg_pid == 0)
+		nlh->nlmsg_pid = sk->s_local.nl_pid;
+
+	if (nlh->nlmsg_seq == 0)
+		nlh->nlmsg_seq = sk->s_seq_next++;
+
+	if (msg->nm_protocol == -1)
+		msg->nm_protocol = sk->s_proto;
+
+	nlh->nlmsg_flags |= NLM_F_REQUEST;
+
+	if (!(sk->s_flags & NL_NO_AUTO_ACK))
+		nlh->nlmsg_flags |= NLM_F_ACK;
+}
+
+void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+	nl_complete_msg(sk, msg);
+}
+
+/**
+ * Automatically complete and send a netlink message
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ *
+ * This function takes a netlink message and passes it on to
+ * nl_auto_complete() for completion.
+ *
+ * Checks the netlink message \c nlh for completness and extends it
+ * as required before sending it out. Checked fields include pid,
+ * sequence nr, and flags.
+ *
+ * @see nl_send()
+ * @return Number of characters sent or a negative error code.
+ */
+int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct nl_cb *cb = sk->s_cb;
+
+	nl_complete_msg(sk, msg);
+
+	if (cb->cb_send_ow)
+		return cb->cb_send_ow(sk, msg);
+	else
+		return nl_send(sk, msg);
+}
+
+int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+	return nl_send_auto(sk, msg);
+}
+
+/**
+ * Send netlink message and wait for response (sync request-response)
+ * @arg sk		Netlink socket
+ * @arg msg		Netlink message to be sent
+ *
+ * This function takes a netlink message and sends it using nl_send_auto().
+ * It will then wait for the response (ACK or error message) to be
+ * received. Threfore this function will block until the operation has
+ * been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any eventual
+ *       error messages returned.
+ *
+ * @see nl_send_auto().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg)
+{
+	int err;
+
+	err = nl_send_auto(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/**
+ * Send simple netlink message using nl_send_auto_complete()
+ * @arg sk		Netlink socket.
+ * @arg type		Netlink message type.
+ * @arg flags		Netlink message flags.
+ * @arg buf		Data buffer.
+ * @arg size		Size of data buffer.
+ *
+ * Builds a netlink message with the specified type and flags and
+ * appends the specified data as payload to the message.
+ *
+ * @see nl_send_auto_complete()
+ * @return Number of characters sent on success or a negative error code.
+ */
+int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
+		   size_t size)
+{
+	int err;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc_simple(type, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (buf && size) {
+		err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
+		if (err < 0)
+			goto errout;
+	}
+	
+
+	err = nl_send_auto_complete(sk, msg);
+errout:
+	nlmsg_free(msg);
+
+	return err;
+}
+
+/** @} */
+
+/**
+ * @name Receive
+ * @{
+ */
+
+/**
+ * Receive data from netlink socket
+ * @arg sk		Netlink socket.
+ * @arg nla		Destination pointer for peer's netlink address.
+ * @arg buf		Destination pointer for message content.
+ * @arg creds		Destination pointer for credentials.
+ *
+ * Receives a netlink message, allocates a buffer in \c *buf and
+ * stores the message content. The peer's netlink address is stored
+ * in \c *nla. The caller is responsible for freeing the buffer allocated
+ * in \c *buf if a positive value is returned.  Interrupted system calls
+ * are handled by repeating the read. The input buffer size is determined
+ * by peeking before the actual read is done.
+ *
+ * A non-blocking sockets causes the function to return immediately with
+ * a return value of 0 if no data is available.
+ *
+ * @return Number of octets read, 0 on EOF or a negative error code.
+ */
+int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
+	    unsigned char **buf, struct ucred **creds)
+{
+	int n;
+	int flags = 0;
+	static int page_size = 0;
+	struct iovec iov;
+	struct msghdr msg = {
+		.msg_name = (void *) nla,
+		.msg_namelen = sizeof(struct sockaddr_nl),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_flags = 0,
+	};
+	struct cmsghdr *cmsg;
+
+	memset(nla, 0, sizeof(*nla));
+
+	if (sk->s_flags & NL_MSG_PEEK)
+		flags |= MSG_PEEK;
+
+	if (page_size == 0)
+		page_size = getpagesize();
+
+	iov.iov_len = page_size;
+	iov.iov_base = *buf = malloc(iov.iov_len);
+
+	if (sk->s_flags & NL_SOCK_PASSCRED) {
+		msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
+		msg.msg_control = calloc(1, msg.msg_controllen);
+	}
+retry:
+
+	n = recvmsg(sk->s_fd, &msg, flags);
+	if (!n)
+		goto abort;
+	else if (n < 0) {
+		if (errno == EINTR) {
+			NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
+			goto retry;
+		} else if (errno == EAGAIN) {
+			NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
+			goto abort;
+		} else {
+			free(msg.msg_control);
+			free(*buf);
+			return -nl_syserr2nlerr(errno);
+		}
+	}
+
+	if (iov.iov_len < n ||
+	    msg.msg_flags & MSG_TRUNC) {
+		/* Provided buffer is not long enough, enlarge it
+		 * and try again. */
+		iov.iov_len *= 2;
+		iov.iov_base = *buf = realloc(*buf, iov.iov_len);
+		goto retry;
+	} else if (msg.msg_flags & MSG_CTRUNC) {
+		msg.msg_controllen *= 2;
+		msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
+		goto retry;
+	} else if (flags != 0) {
+		/* Buffer is big enough, do the actual reading */
+		flags = 0;
+		goto retry;
+	}
+
+	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
+		free(msg.msg_control);
+		free(*buf);
+		return -NLE_NOADDR;
+	}
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_CREDENTIALS) {
+			if (creds) {
+				*creds = calloc(1, sizeof(struct ucred));
+				memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
+			}
+			break;
+		}
+	}
+
+	free(msg.msg_control);
+	return n;
+
+abort:
+	free(msg.msg_control);
+	free(*buf);
+	return 0;
+}
+
+#define NL_CB_CALL(cb, type, msg) \
+do { \
+	err = nl_cb_call(cb, type, msg); \
+	switch (err) { \
+	case NL_OK: \
+		err = 0; \
+		break; \
+	case NL_SKIP: \
+		goto skip; \
+	case NL_STOP: \
+		goto stop; \
+	default: \
+		goto out; \
+	} \
+} while (0)
+
+static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+	int n, err = 0, multipart = 0, interrupted = 0;
+	unsigned char *buf = NULL;
+	struct nlmsghdr *hdr;
+	struct sockaddr_nl nla = {0};
+	struct nl_msg *msg = NULL;
+	struct ucred *creds = NULL;
+
+continue_reading:
+	NL_DBG(3, "Attempting to read from %p\n", sk);
+	if (cb->cb_recv_ow)
+		n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
+	else
+		n = nl_recv(sk, &nla, &buf, &creds);
+
+	if (n <= 0)
+		return n;
+
+	NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);
+
+	hdr = (struct nlmsghdr *) buf;
+	while (nlmsg_ok(hdr, n)) {
+		NL_DBG(3, "recvmsgs(%p): Processing valid message...\n", sk);
+
+		nlmsg_free(msg);
+		msg = nlmsg_convert(hdr);
+		if (!msg) {
+			err = -NLE_NOMEM;
+			goto out;
+		}
+
+		nlmsg_set_proto(msg, sk->s_proto);
+		nlmsg_set_src(msg, &nla);
+		if (creds)
+			nlmsg_set_creds(msg, creds);
+
+		/* Raw callback is the first, it gives the most control
+		 * to the user and he can do his very own parsing. */
+		if (cb->cb_set[NL_CB_MSG_IN])
+			NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
+
+		/* Sequence number checking. The check may be done by
+		 * the user, otherwise a very simple check is applied
+		 * enforcing strict ordering */
+		if (cb->cb_set[NL_CB_SEQ_CHECK]) {
+			NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
+
+		/* Only do sequence checking if auto-ack mode is enabled */
+		} else if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
+			if (hdr->nlmsg_seq != sk->s_seq_expect) {
+				if (cb->cb_set[NL_CB_INVALID])
+					NL_CB_CALL(cb, NL_CB_INVALID, msg);
+				else {
+					err = -NLE_SEQ_MISMATCH;
+					goto out;
+				}
+			}
+		}
+
+		if (hdr->nlmsg_type == NLMSG_DONE ||
+		    hdr->nlmsg_type == NLMSG_ERROR ||
+		    hdr->nlmsg_type == NLMSG_NOOP ||
+		    hdr->nlmsg_type == NLMSG_OVERRUN) {
+			/* We can't check for !NLM_F_MULTI since some netlink
+			 * users in the kernel are broken. */
+			sk->s_seq_expect++;
+			NL_DBG(3, "recvmsgs(%p): Increased expected " \
+			       "sequence number to %d\n",
+			       sk, sk->s_seq_expect);
+		}
+
+		if (hdr->nlmsg_flags & NLM_F_MULTI)
+			multipart = 1;
+
+		if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
+			if (cb->cb_set[NL_CB_DUMP_INTR])
+				NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg);
+			else {
+				/*
+				 * We have to continue reading to clear
+				 * all messages until a NLMSG_DONE is
+				 * received and report the inconsistency.
+				 */
+				interrupted = 1;
+			}
+		}
+	
+		/* Other side wishes to see an ack for this message */
+		if (hdr->nlmsg_flags & NLM_F_ACK) {
+			if (cb->cb_set[NL_CB_SEND_ACK])
+				NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
+			else {
+				/* FIXME: implement */
+			}
+		}
+
+		/* messages terminates a multpart message, this is
+		 * usually the end of a message and therefore we slip
+		 * out of the loop by default. the user may overrule
+		 * this action by skipping this packet. */
+		if (hdr->nlmsg_type == NLMSG_DONE) {
+			multipart = 0;
+			if (cb->cb_set[NL_CB_FINISH])
+				NL_CB_CALL(cb, NL_CB_FINISH, msg);
+		}
+
+		/* Message to be ignored, the default action is to
+		 * skip this message if no callback is specified. The
+		 * user may overrule this action by returning
+		 * NL_PROCEED. */
+		else if (hdr->nlmsg_type == NLMSG_NOOP) {
+			if (cb->cb_set[NL_CB_SKIPPED])
+				NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
+			else
+				goto skip;
+		}
+
+		/* Data got lost, report back to user. The default action is to
+		 * quit parsing. The user may overrule this action by retuning
+		 * NL_SKIP or NL_PROCEED (dangerous) */
+		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
+			if (cb->cb_set[NL_CB_OVERRUN])
+				NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
+			else {
+				err = -NLE_MSG_OVERFLOW;
+				goto out;
+			}
+		}
+
+		/* Message carries a nlmsgerr */
+		else if (hdr->nlmsg_type == NLMSG_ERROR) {
+			struct nlmsgerr *e = nlmsg_data(hdr);
+
+			if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
+				/* Truncated error message, the default action
+				 * is to stop parsing. The user may overrule
+				 * this action by returning NL_SKIP or
+				 * NL_PROCEED (dangerous) */
+				if (cb->cb_set[NL_CB_INVALID])
+					NL_CB_CALL(cb, NL_CB_INVALID, msg);
+				else {
+					err = -NLE_MSG_TRUNC;
+					goto out;
+				}
+			} else if (e->error) {
+				/* Error message reported back from kernel. */
+				if (cb->cb_err) {
+					err = cb->cb_err(&nla, e,
+							   cb->cb_err_arg);
+					if (err < 0)
+						goto out;
+					else if (err == NL_SKIP)
+						goto skip;
+					else if (err == NL_STOP) {
+						err = -nl_syserr2nlerr(e->error);
+						goto out;
+					}
+				} else {
+					err = -nl_syserr2nlerr(e->error);
+					goto out;
+				}
+			} else if (cb->cb_set[NL_CB_ACK])
+				NL_CB_CALL(cb, NL_CB_ACK, msg);
+		} else {
+			/* Valid message (not checking for MULTIPART bit to
+			 * get along with broken kernels. NL_SKIP has no
+			 * effect on this.  */
+			if (cb->cb_set[NL_CB_VALID])
+				NL_CB_CALL(cb, NL_CB_VALID, msg);
+		}
+skip:
+		err = 0;
+		hdr = nlmsg_next(hdr, &n);
+	}
+	
+	nlmsg_free(msg);
+	free(buf);
+	free(creds);
+	buf = NULL;
+	msg = NULL;
+	creds = NULL;
+
+	if (multipart) {
+		/* Multipart message not yet complete, continue reading */
+		goto continue_reading;
+	}
+stop:
+	err = 0;
+out:
+	nlmsg_free(msg);
+	free(buf);
+	free(creds);
+
+	if (interrupted)
+		err = -NLE_DUMP_INTR;
+
+	return err;
+}
+
+/**
+ * Receive a set of messages from a netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg cb		set of callbacks to control behaviour.
+ *
+ * Repeatedly calls nl_recv() or the respective replacement if provided
+ * by the application (see nl_cb_overwrite_recv()) and parses the
+ * received data as netlink messages. Stops reading if one of the
+ * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
+ *
+ * A non-blocking sockets causes the function to return immediately if
+ * no data is available.
+ *
+ * @return 0 on success or a negative error code from nl_recv().
+ */
+int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+	if (cb->cb_recvmsgs_ow)
+		return cb->cb_recvmsgs_ow(sk, cb);
+	else
+		return recvmsgs(sk, cb);
+}
+
+/**
+ * Receive a set of message from a netlink socket using handlers in nl_sock.
+ * @arg sk		Netlink socket.
+ *
+ * Calls nl_recvmsgs() with the handlers configured in the netlink socket.
+ */
+int nl_recvmsgs_default(struct nl_sock *sk)
+{
+	return nl_recvmsgs(sk, sk->s_cb);
+
+}
+
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+	return NL_STOP;
+}
+
+/**
+ * Wait for ACK.
+ * @arg sk		Netlink socket.
+ * @pre The netlink socket must be in blocking state.
+ *
+ * Waits until an ACK is received for the latest not yet acknowledged
+ * netlink message.
+ */
+int nl_wait_for_ack(struct nl_sock *sk)
+{
+	int err;
+	struct nl_cb *cb;
+
+	cb = nl_cb_clone(sk->s_cb);
+	if (cb == NULL)
+		return -NLE_NOMEM;
+
+	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
+	err = nl_recvmsgs(sk, cb);
+	nl_cb_put(cb);
+
+	return err;
+}
+
+/** @cond SKIP */
+struct pickup_param
+{
+	int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+		      struct nlmsghdr *, struct nl_parser_param *);
+	struct nl_object *result;
+};
+
+static int __store_answer(struct nl_object *obj, struct nl_parser_param *p)
+{
+	struct pickup_param *pp = p->pp_arg;
+	/*
+	 * the parser will put() the object at the end, expecting the cache
+	 * to take the reference.
+	 */
+	nl_object_get(obj);
+	pp->result =  obj;
+
+	return 0;
+}
+
+static int __pickup_answer(struct nl_msg *msg, void *arg)
+{
+	struct pickup_param *pp = arg;
+	struct nl_parser_param parse_arg = {
+		.pp_cb = __store_answer,
+		.pp_arg = pp,
+	};
+
+	return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg);
+}
+
+/** @endcond */
+
+/**
+ * Pickup netlink answer, parse is and return object
+ * @arg sk		Netlink socket
+ * @arg parser		Parser function to parse answer
+ * @arg result		Result pointer to return parsed object
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_pickup(struct nl_sock *sk,
+	      int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+			    struct nlmsghdr *, struct nl_parser_param *),
+	      struct nl_object **result)
+{
+	struct nl_cb *cb;
+	int err;
+	struct pickup_param pp = {
+		.parser = parser,
+	};
+
+	cb = nl_cb_clone(sk->s_cb);
+	if (cb == NULL)
+		return -NLE_NOMEM;
+
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __pickup_answer, &pp);
+
+	err = nl_recvmsgs(sk, cb);
+	if (err < 0)
+		goto errout;
+
+	*result = pp.result;
+errout:
+	nl_cb_put(cb);
+
+	return err;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/object.c b/libnetwork/libnl3/lib/object.c
new file mode 100644
index 0000000..3bf02ea
--- /dev/null
+++ b/libnetwork/libnl3/lib/object.c
@@ -0,0 +1,395 @@
+/*
+ * lib/object.c		Generic Cacheable Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cache
+ * @defgroup object Object
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/utils.h>
+
+static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
+{
+	if (!obj->ce_ops)
+		BUG();
+
+	return obj->ce_ops;
+}
+
+/**
+ * @name Object Creation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate a new object of kind specified by the operations handle
+ * @arg ops		cache operations handle
+ * @return The new object or NULL
+ */
+struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
+{
+	struct nl_object *new;
+
+	if (ops->oo_size < sizeof(*new))
+		BUG();
+
+	new = calloc(1, ops->oo_size);
+	if (!new)
+		return NULL;
+
+	new->ce_refcnt = 1;
+	nl_init_list_head(&new->ce_list);
+
+	new->ce_ops = ops;
+	if (ops->oo_constructor)
+		ops->oo_constructor(new);
+
+	NL_DBG(4, "Allocated new object %p\n", new);
+
+	return new;
+}
+
+/**
+ * Allocate new object of kind specified by the name
+ * @arg kind		name of object type
+ * @arg result		Result pointer
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_object_alloc_name(const char *kind, struct nl_object **result)
+{
+	struct nl_cache_ops *ops;
+
+	ops = nl_cache_ops_lookup(kind);
+	if (!ops)
+		return -NLE_OPNOTSUPP;
+
+	if (!(*result = nl_object_alloc(ops->co_obj_ops)))
+		return -NLE_NOMEM;
+
+	return 0;
+}
+
+struct nl_derived_object {
+	NLHDR_COMMON
+	char data;
+};
+
+/**
+ * Allocate a new object and copy all data from an existing object
+ * @arg obj		object to inherite data from
+ * @return The new object or NULL.
+ */
+struct nl_object *nl_object_clone(struct nl_object *obj)
+{
+	struct nl_object *new;
+	struct nl_object_ops *ops = obj_ops(obj);
+	int doff = offsetof(struct nl_derived_object, data);
+	int size;
+
+	new = nl_object_alloc(ops);
+	if (!new)
+		return NULL;
+
+	size = ops->oo_size - doff;
+	if (size < 0)
+		BUG();
+
+	new->ce_ops = obj->ce_ops;
+	new->ce_msgtype = obj->ce_msgtype;
+	new->ce_mask = obj->ce_mask;
+
+	if (size)
+		memcpy((void *)new + doff, (void *)obj + doff, size);
+
+	if (ops->oo_clone) {
+		if (ops->oo_clone(new, obj) < 0) {
+			nl_object_free(new);
+			return NULL;
+		}
+	} else if (size && ops->oo_free_data)
+		BUG();
+
+	return new;
+}
+
+/**
+ * Free a cacheable object
+ * @arg obj		object to free
+ *
+ * @return 0 or a negative error code.
+ */
+void nl_object_free(struct nl_object *obj)
+{
+	struct nl_object_ops *ops = obj_ops(obj);
+
+	if (obj->ce_refcnt > 0)
+		NL_DBG(1, "Warning: Freeing object in use...\n");
+
+	if (obj->ce_cache)
+		nl_cache_remove(obj);
+
+	if (ops->oo_free_data)
+		ops->oo_free_data(obj);
+
+	free(obj);
+
+	NL_DBG(4, "Freed object %p\n", obj);
+}
+
+/** @} */
+
+/**
+ * @name Reference Management
+ * @{
+ */
+
+/**
+ * Acquire a reference on a object
+ * @arg obj		object to acquire reference from
+ */
+void nl_object_get(struct nl_object *obj)
+{
+	obj->ce_refcnt++;
+	NL_DBG(4, "New reference to object %p, total %d\n",
+	       obj, obj->ce_refcnt);
+}
+
+/**
+ * Release a reference from an object
+ * @arg obj		object to release reference from
+ */
+void nl_object_put(struct nl_object *obj)
+{
+	if (!obj)
+		return;
+
+	obj->ce_refcnt--;
+	NL_DBG(4, "Returned object reference %p, %d remaining\n",
+	       obj, obj->ce_refcnt);
+
+	if (obj->ce_refcnt < 0)
+		BUG();
+
+	if (obj->ce_refcnt <= 0)
+		nl_object_free(obj);
+}
+
+/**
+ * Check whether this object is used by multiple users
+ * @arg obj		object to check
+ * @return true or false
+ */
+int nl_object_shared(struct nl_object *obj)
+{
+	return obj->ce_refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Marks
+ * @{
+ */
+
+/**
+ * Add mark to object
+ * @arg obj		Object to mark
+ */
+void nl_object_mark(struct nl_object *obj)
+{
+	obj->ce_flags |= NL_OBJ_MARK;
+}
+
+/**
+ * Remove mark from object
+ * @arg obj		Object to unmark
+ */
+void nl_object_unmark(struct nl_object *obj)
+{
+	obj->ce_flags &= ~NL_OBJ_MARK;
+}
+
+/**
+ * Return true if object is marked
+ * @arg obj		Object to check
+ * @return true if object is marked, otherwise false
+ */
+int nl_object_is_marked(struct nl_object *obj)
+{
+	return (obj->ce_flags & NL_OBJ_MARK);
+}
+
+/** @} */
+
+/**
+ * @name Utillities
+ * @{
+ */
+
+/**
+ * Dump this object according to the specified parameters
+ * @arg obj		object to dump
+ * @arg params		dumping parameters
+ */
+void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
+{
+	dump_from_ops(obj, params);
+}
+
+void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len)
+{
+        struct nl_dump_params dp = {
+                .dp_buf = buf,
+                .dp_buflen = len,
+        };
+
+        return nl_object_dump(obj, &dp);
+}
+
+/**
+ * Check if the identifiers of two objects are identical 
+ * @arg a		an object
+ * @arg b		another object of same type
+ *
+ * @return true if both objects have equal identifiers, otherwise false.
+ */
+int nl_object_identical(struct nl_object *a, struct nl_object *b)
+{
+	struct nl_object_ops *ops = obj_ops(a);
+	int req_attrs;
+
+	/* Both objects must be of same type */
+	if (ops != obj_ops(b))
+		return 0;
+
+	req_attrs = ops->oo_id_attrs;
+	if (req_attrs == ~0)
+		req_attrs = a->ce_mask & b->ce_mask;
+
+	/* Both objects must provide all required attributes to uniquely
+	 * identify an object */
+	if ((a->ce_mask & req_attrs) != req_attrs ||
+	    (b->ce_mask & req_attrs) != req_attrs)
+		return 0;
+
+	/* Can't judge unless we can compare */
+	if (ops->oo_compare == NULL)
+		return 0;
+
+	return !(ops->oo_compare(a, b, req_attrs, 0));
+}
+
+/**
+ * Compute bitmask representing difference in attribute values
+ * @arg a		an object
+ * @arg b		another object of same type
+ *
+ * The bitmask returned is specific to an object type, each bit set represents
+ * an attribute which mismatches in either of the two objects. Unavailability
+ * of an attribute in one object and presence in the other is regarded a
+ * mismatch as well.
+ *
+ * @return Bitmask describing differences or 0 if they are completely identical.
+ */
+uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
+{
+	struct nl_object_ops *ops = obj_ops(a);
+
+	if (ops != obj_ops(b) || ops->oo_compare == NULL)
+		return UINT_MAX;
+
+	return ops->oo_compare(a, b, ~0, 0);
+}
+
+/**
+ * Match a filter against an object
+ * @arg obj		object to check
+ * @arg filter		object of same type acting as filter
+ *
+ * @return 1 if the object matches the filter or 0
+ *           if no filter procedure is available or if the
+ *           filter does not match.
+ */
+int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
+{
+	struct nl_object_ops *ops = obj_ops(obj);
+
+	if (ops != obj_ops(filter) || ops->oo_compare == NULL)
+		return 0;
+	
+	return !(ops->oo_compare(obj, filter, filter->ce_mask,
+				 LOOSE_COMPARISON));
+}
+
+/**
+ * Convert bitmask of attributes to a character string
+ * @arg obj		object of same type as attribute bitmask
+ * @arg attrs		bitmask of attribute types
+ * @arg buf		destination buffer
+ * @arg len		length of destination buffer
+ *
+ * Converts the bitmask of attribute types into a list of attribute
+ * names separated by comas.
+ *
+ * @return destination buffer.
+ */
+char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
+			  char *buf, size_t len)
+{
+	struct nl_object_ops *ops = obj_ops(obj);
+
+	if (ops->oo_attrs2str != NULL)
+		return ops->oo_attrs2str(attrs, buf, len);
+	else {
+		memset(buf, 0, len);
+		return buf;
+	}
+}
+
+/**
+ * Return list of attributes present in an object
+ * @arg obj		an object
+ * @arg buf		destination buffer
+ * @arg len		length of destination buffer
+ *
+ * @return destination buffer.
+ */
+char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
+{
+	return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+int nl_object_get_refcnt(struct nl_object *obj)
+{
+	return obj->ce_refcnt;
+}
+
+struct nl_cache *nl_object_get_cache(struct nl_object *obj)
+{
+	return obj->ce_cache;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/.dirstamp b/libnetwork/libnl3/lib/route/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/route/addr.c b/libnetwork/libnl3/lib/route/addr.c
new file mode 100644
index 0000000..deb88ba
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/addr.c
@@ -0,0 +1,1054 @@
+/*
+ * lib/route/addr.c		Addresses
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch at ev-en.org>,
+ *                         Mediatrix Telecom, inc. <ericb at mediatrix.com>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup rtaddr Addresses
+ * @brief
+ *
+ * @note The maximum size of an address label is IFNAMSIZ.
+ *
+ * @note The address may not contain a prefix length if the peer address
+ *       has been specified already.
+ *
+ * @par 1) Address Addition
+ * @code
+ * // Allocate an empty address object to be filled out with the attributes
+ * // of the new address.
+ * struct rtnl_addr *addr = rtnl_addr_alloc();
+ *
+ * // Fill out the mandatory attributes of the new address. Setting the
+ * // local address will automatically set the address family and the
+ * // prefix length to the correct values.
+ * rtnl_addr_set_ifindex(addr, ifindex);
+ * rtnl_addr_set_local(addr, local_addr);
+ *
+ * // The label of the address can be specified, currently only supported
+ * // by IPv4 and DECnet.
+ * rtnl_addr_set_label(addr, "mylabel");
+ *
+ * // The peer address can be specified if necessary, in either case a peer
+ * // address will be sent to the kernel in order to fullfil the interface
+ * // requirements. If none is set, it will equal the local address.
+ * // Note: Real peer addresses are only supported by IPv4 for now.
+ * rtnl_addr_set_peer(addr, peer_addr);
+ *
+ * // In case you want to have the address have a scope other than global
+ * // it may be overwritten using rtnl_addr_set_scope(). The scope currently
+ * // cannot be set for IPv6 addresses.
+ * rtnl_addr_set_scope(addr, rtnl_str2scope("site"));
+ *
+ * // Broadcast address may be specified using the relevant
+ * // functions, the address family will be verified if one of the other
+ * // addresses has been set already. Currently only works for IPv4.
+ * rtnl_addr_set_broadcast(addr, broadcast_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_addr_build_add_request() to be
+ * // sent out using nl_send_auto_complete().
+ * rtnl_addr_add(sk, addr, 0);
+ *
+ * // Free the memory
+ * rtnl_addr_put(addr);
+ * @endcode
+ *
+ * @par 2) Address Deletion
+ * @code
+ * // Allocate an empty address object to be filled out with the attributes
+ * // matching the address to be deleted. Alternatively a fully equipped
+ * // address object out of a cache can be used instead.
+ * struct rtnl_addr *addr = rtnl_addr_alloc();
+ *
+ * // The only mandatory parameter besides the address family is the interface
+ * // index the address is on, i.e. leaving out all other parameters will
+ * // result in all addresses of the specified address family interface tuple
+ * // to be deleted.
+ * rtnl_addr_set_ifindex(addr, ifindex);
+ *
+ * // Specyfing the address family manually is only required if neither the
+ * // local nor peer address have been specified.
+ * rtnl_addr_set_family(addr, AF_INET);
+ *
+ * // Specyfing the local address is optional but the best choice to delete
+ * // specific addresses.
+ * rtnl_addr_set_local(addr, local_addr);
+ *
+ * // The label of the address can be specified, currently only supported
+ * // by IPv4 and DECnet.
+ * rtnl_addr_set_label(addr, "mylabel");
+ *
+ * // The peer address can be specified if necessary, in either case a peer
+ * // address will be sent to the kernel in order to fullfil the interface
+ * // requirements. If none is set, it will equal the local address.
+ * // Note: Real peer addresses are only supported by IPv4 for now.
+ * rtnl_addr_set_peer(addr, peer_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_addr_build_delete_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_addr_delete(sk, addr, 0);
+ *
+ * // Free the memory
+ * rtnl_addr_put(addr);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define ADDR_ATTR_FAMILY	0x0001
+#define ADDR_ATTR_PREFIXLEN	0x0002
+#define ADDR_ATTR_FLAGS		0x0004
+#define ADDR_ATTR_SCOPE		0x0008
+#define ADDR_ATTR_IFINDEX	0x0010
+#define ADDR_ATTR_LABEL		0x0020
+#define ADDR_ATTR_CACHEINFO	0x0040
+#define ADDR_ATTR_PEER		0x0080
+#define ADDR_ATTR_LOCAL		0x0100
+#define ADDR_ATTR_BROADCAST	0x0200
+#define ADDR_ATTR_MULTICAST	0x0400
+#define ADDR_ATTR_ANYCAST	0x0800
+
+static struct nl_cache_ops rtnl_addr_ops;
+static struct nl_object_ops addr_obj_ops;
+/** @endcond */
+
+static void addr_constructor(struct nl_object *obj)
+{
+	struct rtnl_addr *addr = nl_object_priv(obj);
+
+	addr->a_scope = RT_SCOPE_NOWHERE;
+}
+
+static void addr_free_data(struct nl_object *obj)
+{
+	struct rtnl_addr *addr = nl_object_priv(obj);
+
+	if (!addr)
+		return;
+
+	nl_addr_put(addr->a_peer);
+	nl_addr_put(addr->a_local);
+	nl_addr_put(addr->a_bcast);
+	nl_addr_put(addr->a_multicast);
+	nl_addr_put(addr->a_anycast);
+	rtnl_link_put(addr->a_link);
+}
+
+static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct rtnl_addr *dst = nl_object_priv(_dst);
+	struct rtnl_addr *src = nl_object_priv(_src);
+
+	if (src->a_link) {
+		nl_object_get(OBJ_CAST(src->a_link));
+		dst->a_link = src->a_link;
+	}
+
+	if (src->a_peer)
+		if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
+			return -NLE_NOMEM;
+	
+	if (src->a_local)
+		if (!(dst->a_local = nl_addr_clone(src->a_local)))
+			return -NLE_NOMEM;
+
+	if (src->a_bcast)
+		if (!(dst->a_bcast = nl_addr_clone(src->a_bcast)))
+			return -NLE_NOMEM;
+
+	if (src->a_multicast)
+		if (!(dst->a_multicast = nl_addr_clone(src->a_multicast)))
+			return -NLE_NOMEM;
+
+	if (src->a_anycast)
+		if (!(dst->a_anycast = nl_addr_clone(src->a_anycast)))
+			return -NLE_NOMEM;
+
+	return 0;
+}
+
+static struct nla_policy addr_policy[IFA_MAX+1] = {
+	[IFA_LABEL]	= { .type = NLA_STRING,
+			    .maxlen = IFNAMSIZ },
+	[IFA_CACHEINFO]	= { .minlen = sizeof(struct ifa_cacheinfo) },
+};
+
+static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			   struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct rtnl_addr *addr;
+	struct ifaddrmsg *ifa;
+	struct nlattr *tb[IFA_MAX+1];
+	int err, peer_prefix = 0, family;
+	struct nl_cache *link_cache;
+
+	addr = rtnl_addr_alloc();
+	if (!addr)
+		return -NLE_NOMEM;
+
+	addr->ce_msgtype = nlh->nlmsg_type;
+
+	err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
+	if (err < 0)
+		goto errout;
+
+	ifa = nlmsg_data(nlh);
+	addr->a_family = family = ifa->ifa_family;
+	addr->a_prefixlen = ifa->ifa_prefixlen;
+	addr->a_flags = ifa->ifa_flags;
+	addr->a_scope = ifa->ifa_scope;
+	addr->a_ifindex = ifa->ifa_index;
+
+	addr->ce_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
+			 ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);
+
+	if (tb[IFA_LABEL]) {
+		nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
+		addr->ce_mask |= ADDR_ATTR_LABEL;
+	}
+
+	if (tb[IFA_CACHEINFO]) {
+		struct ifa_cacheinfo *ca;
+		
+		ca = nla_data(tb[IFA_CACHEINFO]);
+		addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
+		addr->a_cacheinfo.aci_valid = ca->ifa_valid;
+		addr->a_cacheinfo.aci_cstamp = ca->cstamp;
+		addr->a_cacheinfo.aci_tstamp = ca->tstamp;
+		addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+	}
+
+	if (tb[IFA_LOCAL]) {
+		addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
+		if (!addr->a_local)
+			goto errout_nomem;
+		addr->ce_mask |= ADDR_ATTR_LOCAL;
+	}
+
+	if (tb[IFA_ADDRESS]) {
+		struct nl_addr *a;
+
+		a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
+		if (!a)
+			goto errout_nomem;
+
+		/* IPv6 sends the local address as IFA_ADDRESS with
+		 * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
+		 * with IFA_ADDRESS being the peer address if they differ */
+		if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
+			nl_addr_put(addr->a_local);
+			addr->a_local = a;
+			addr->ce_mask |= ADDR_ATTR_LOCAL;
+		} else {
+			addr->a_peer = a;
+			addr->ce_mask |= ADDR_ATTR_PEER;
+			peer_prefix = 1;
+		}
+	}
+
+	nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local,
+			      addr->a_prefixlen);
+
+	if (tb[IFA_BROADCAST]) {
+		addr->a_bcast = nl_addr_alloc_attr(tb[IFA_BROADCAST], family);
+		if (!addr->a_bcast)
+			goto errout_nomem;
+
+		addr->ce_mask |= ADDR_ATTR_BROADCAST;
+	}
+
+	if (tb[IFA_MULTICAST]) {
+		addr->a_multicast = nl_addr_alloc_attr(tb[IFA_MULTICAST],
+						       family);
+		if (!addr->a_multicast)
+			goto errout_nomem;
+
+		addr->ce_mask |= ADDR_ATTR_MULTICAST;
+	}
+
+	if (tb[IFA_ANYCAST]) {
+		addr->a_anycast = nl_addr_alloc_attr(tb[IFA_ANYCAST],
+						       family);
+		if (!addr->a_anycast)
+			goto errout_nomem;
+
+		addr->ce_mask |= ADDR_ATTR_ANYCAST;
+	}
+
+	if ((link_cache = __nl_cache_mngt_require("route/link"))) {
+		struct rtnl_link *link;
+
+		if ((link = rtnl_link_get(link_cache, addr->a_ifindex))) {
+			rtnl_addr_set_link(addr, link);
+
+			/* rtnl_addr_set_link incs refcnt */
+			rtnl_link_put(link);
+		}
+	}
+
+	err = pp->pp_cb((struct nl_object *) addr, pp);
+errout:
+	rtnl_addr_put(addr);
+
+	return err;
+
+errout_nomem:
+	err = -NLE_NOMEM;
+	goto errout;
+}
+
+static int addr_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+	return nl_rtgen_request(sk, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP);
+}
+
+static void addr_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_addr *addr = (struct rtnl_addr *) obj;
+	struct nl_cache *link_cache;
+	char buf[128];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	if (addr->ce_mask & ADDR_ATTR_LOCAL)
+		nl_dump_line(p, "%s",
+			nl_addr2str(addr->a_local, buf, sizeof(buf)));
+	else
+		nl_dump_line(p, "none");
+
+	if (addr->ce_mask & ADDR_ATTR_PEER)
+		nl_dump(p, " peer %s",
+			nl_addr2str(addr->a_peer, buf, sizeof(buf)));
+
+	nl_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf)));
+
+	if (link_cache)
+		nl_dump(p, "dev %s ",
+			rtnl_link_i2name(link_cache, addr->a_ifindex,
+					 buf, sizeof(buf)));
+	else
+		nl_dump(p, "dev %d ", addr->a_ifindex);
+
+	nl_dump(p, "scope %s",
+		rtnl_scope2str(addr->a_scope, buf, sizeof(buf)));
+
+	rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf));
+	if (buf[0])
+		nl_dump(p, " <%s>", buf);
+
+	nl_dump(p, "\n");
+}
+
+static void addr_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_addr *addr = (struct rtnl_addr *) obj;
+	char buf[128];
+
+	addr_dump_line(obj, p);
+
+	if (addr->ce_mask & (ADDR_ATTR_LABEL | ADDR_ATTR_BROADCAST |
+			     ADDR_ATTR_MULTICAST)) {
+		nl_dump_line(p, "  ");
+
+		if (addr->ce_mask & ADDR_ATTR_LABEL)
+			nl_dump(p, " label %s", addr->a_label);
+
+		if (addr->ce_mask & ADDR_ATTR_BROADCAST)
+			nl_dump(p, " broadcast %s",
+				nl_addr2str(addr->a_bcast, buf, sizeof(buf)));
+
+		if (addr->ce_mask & ADDR_ATTR_MULTICAST)
+			nl_dump(p, " multicast %s",
+				nl_addr2str(addr->a_multicast, buf,
+					      sizeof(buf)));
+
+		if (addr->ce_mask & ADDR_ATTR_ANYCAST)
+			nl_dump(p, " anycast %s",
+				nl_addr2str(addr->a_anycast, buf,
+					      sizeof(buf)));
+
+		nl_dump(p, "\n");
+	}
+
+	if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
+		struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
+
+		nl_dump_line(p, "   valid-lifetime %s",
+			     ci->aci_valid == 0xFFFFFFFFU ? "forever" :
+			     nl_msec2str(ci->aci_valid * 1000,
+					   buf, sizeof(buf)));
+
+		nl_dump(p, " preferred-lifetime %s\n",
+			ci->aci_prefered == 0xFFFFFFFFU ? "forever" :
+			nl_msec2str(ci->aci_prefered * 1000,
+				      buf, sizeof(buf)));
+
+		nl_dump_line(p, "   created boot-time+%s ",
+			     nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10,
+					   buf, sizeof(buf)));
+		    
+		nl_dump(p, "last-updated boot-time+%s\n",
+			nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10,
+				      buf, sizeof(buf)));
+	}
+}
+
+static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	addr_dump_details(obj, p);
+}
+
+static int addr_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_addr *a = (struct rtnl_addr *) _a;
+	struct rtnl_addr *b = (struct rtnl_addr *) _b;
+	int diff = 0;
+
+#define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= ADDR_DIFF(IFINDEX,	a->a_ifindex != b->a_ifindex);
+	diff |= ADDR_DIFF(FAMILY,	a->a_family != b->a_family);
+	diff |= ADDR_DIFF(SCOPE,	a->a_scope != b->a_scope);
+	diff |= ADDR_DIFF(LABEL,	strcmp(a->a_label, b->a_label));
+	diff |= ADDR_DIFF(PEER,		nl_addr_cmp(a->a_peer, b->a_peer));
+	diff |= ADDR_DIFF(LOCAL,	nl_addr_cmp(a->a_local, b->a_local));
+	diff |= ADDR_DIFF(MULTICAST,	nl_addr_cmp(a->a_multicast,
+						    b->a_multicast));
+	diff |= ADDR_DIFF(BROADCAST,	nl_addr_cmp(a->a_bcast, b->a_bcast));
+	diff |= ADDR_DIFF(ANYCAST,	nl_addr_cmp(a->a_anycast, b->a_anycast));
+
+	if (flags & LOOSE_COMPARISON)
+		diff |= ADDR_DIFF(FLAGS,
+				  (a->a_flags ^ b->a_flags) & b->a_flag_mask);
+	else
+		diff |= ADDR_DIFF(FLAGS, a->a_flags != b->a_flags);
+
+#undef ADDR_DIFF
+
+	return diff;
+}
+
+static const struct trans_tbl addr_attrs[] = {
+	__ADD(ADDR_ATTR_FAMILY, family)
+	__ADD(ADDR_ATTR_PREFIXLEN, prefixlen)
+	__ADD(ADDR_ATTR_FLAGS, flags)
+	__ADD(ADDR_ATTR_SCOPE, scope)
+	__ADD(ADDR_ATTR_IFINDEX, ifindex)
+	__ADD(ADDR_ATTR_LABEL, label)
+	__ADD(ADDR_ATTR_CACHEINFO, cacheinfo)
+	__ADD(ADDR_ATTR_PEER, peer)
+	__ADD(ADDR_ATTR_LOCAL, local)
+	__ADD(ADDR_ATTR_BROADCAST, broadcast)
+	__ADD(ADDR_ATTR_MULTICAST, multicast)
+};
+
+static char *addr_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, addr_attrs,
+			   ARRAY_SIZE(addr_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_addr *rtnl_addr_alloc(void)
+{
+	return (struct rtnl_addr *) nl_object_alloc(&addr_obj_ops);
+}
+
+void rtnl_addr_put(struct rtnl_addr *addr)
+{
+	nl_object_put((struct nl_object *) addr);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result);
+}
+
+/**
+ * Search address in cache
+ * @arg cache		Address cache
+ * @arg ifindex		Interface index of address
+ * @arg addr		Local address part
+ *
+ * Searches address cache previously allocated with rtnl_addr_alloc_cache()
+ * for an address with a matching local address.
+ *
+ * The reference counter is incremented before returning the address, therefore
+ * the reference must be given back with rtnl_addr_put() after usage.
+ *
+ * @return Address object or NULL if no match was found.
+ */
+struct rtnl_addr *rtnl_addr_get(struct nl_cache *cache, int ifindex,
+				struct nl_addr *addr)
+{
+	struct rtnl_addr *a;
+
+	if (cache->c_ops != &rtnl_addr_ops)
+		return NULL;
+
+	nl_list_for_each_entry(a, &cache->c_items, ce_list) {
+		if (ifindex && a->a_ifindex != ifindex)
+			continue;
+
+		if (a->ce_mask & ADDR_ATTR_LOCAL &&
+		    !nl_addr_cmp(a->a_local, addr)) {
+			nl_object_get((struct nl_object *) a);
+			return a;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags,
+			  struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct ifaddrmsg am = {
+		.ifa_family = tmpl->a_family,
+		.ifa_index = tmpl->a_ifindex,
+		.ifa_prefixlen = tmpl->a_prefixlen,
+	};
+
+	if (tmpl->ce_mask & ADDR_ATTR_SCOPE)
+		am.ifa_scope = tmpl->a_scope;
+	else {
+		/* compatibility hack */
+		if (tmpl->a_family == AF_INET &&
+		    tmpl->ce_mask & ADDR_ATTR_LOCAL &&
+		    *((char *) nl_addr_get_binary_addr(tmpl->a_local)) == 127)
+			am.ifa_scope = RT_SCOPE_HOST;
+		else
+			am.ifa_scope = RT_SCOPE_UNIVERSE;
+	}
+
+	msg = nlmsg_alloc_simple(cmd, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (tmpl->ce_mask & ADDR_ATTR_LOCAL)
+		NLA_PUT_ADDR(msg, IFA_LOCAL, tmpl->a_local);
+
+	if (tmpl->ce_mask & ADDR_ATTR_PEER)
+		NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer);
+	else if (tmpl->ce_mask & ADDR_ATTR_LOCAL)
+		NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local);
+
+	if (tmpl->ce_mask & ADDR_ATTR_LABEL)
+		NLA_PUT_STRING(msg, IFA_LABEL, tmpl->a_label);
+
+	if (tmpl->ce_mask & ADDR_ATTR_BROADCAST)
+		NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast);
+
+	if (tmpl->ce_mask & ADDR_ATTR_CACHEINFO) {
+		struct ifa_cacheinfo ca = {
+			.ifa_valid = tmpl->a_cacheinfo.aci_valid,
+			.ifa_prefered = tmpl->a_cacheinfo.aci_prefered,
+		};
+
+		NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca);
+	}
+
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Addition
+ * @{
+ */
+
+/**
+ * Build netlink request message to request addition of new address
+ * @arg addr		Address object representing the new address.
+ * @arg flags		Additional netlink message flags.
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting the addition of a new
+ * address. The netlink message header isn't fully equipped with
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed.
+ *
+ * Minimal required attributes:
+ *   - interface index (rtnl_addr_set_ifindex())
+ *   - local address (rtnl_addr_set_local())
+ *
+ * The scope will default to universe except for loopback addresses in
+ * which case a host scope is used if not specified otherwise.
+ *
+ * @note Free the memory after usage using nlmsg_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags,
+				struct nl_msg **result)
+{
+	int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY |
+		       ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL;
+
+	if ((addr->ce_mask & required) != required)
+		return -NLE_MISSING_ATTR;
+	
+	return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result);
+}
+
+/**
+ * Request addition of new address
+ * @arg sk		Netlink socket.
+ * @arg addr		Address object representing the new address.
+ * @arg flags		Additional netlink message flags.
+ *
+ * Builds a netlink message by calling rtnl_addr_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @see rtnl_addr_build_add_request()
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_addr_add(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink request message to request deletion of an address
+ * @arg addr		Address object to be deleteted.
+ * @arg flags		Additional netlink message flags.
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting a deletion of an address.
+ * The netlink message header isn't fully equipped with all relevant
+ * fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed.
+ *
+ * Minimal required attributes:
+ *   - interface index (rtnl_addr_set_ifindex())
+ *   - address family (rtnl_addr_set_family())
+ *
+ * Optional attributes:
+ *   - local address (rtnl_addr_set_local())
+ *   - label (rtnl_addr_set_label(), IPv4/DECnet only)
+ *   - peer address (rtnl_addr_set_peer(), IPv4 only)
+ *
+ * @note Free the memory after usage using nlmsg_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags,
+				   struct nl_msg **result)
+{
+	int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY;
+
+	if ((addr->ce_mask & required) != required)
+		return -NLE_MISSING_ATTR;
+
+	return build_addr_msg(addr, RTM_DELADDR, flags, result);
+}
+
+/**
+ * Request deletion of an address
+ * @arg sk		Netlink socket.
+ * @arg addr		Address object to be deleted.
+ * @arg flags		Additional netlink message flags.
+ *
+ * Builds a netlink message by calling rtnl_addr_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @see rtnl_addr_build_delete_request();
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_addr_delete(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+int rtnl_addr_set_label(struct rtnl_addr *addr, const char *label)
+{
+	if (strlen(label) > sizeof(addr->a_label) - 1)
+		return -NLE_RANGE;
+
+	strcpy(addr->a_label, label);
+	addr->ce_mask |= ADDR_ATTR_LABEL;
+
+	return 0;
+}
+
+char *rtnl_addr_get_label(struct rtnl_addr *addr)
+{
+	if (addr->ce_mask & ADDR_ATTR_LABEL)
+		return addr->a_label;
+	else
+		return NULL;
+}
+
+void rtnl_addr_set_ifindex(struct rtnl_addr *addr, int ifindex)
+{
+	addr->a_ifindex = ifindex;
+	addr->ce_mask |= ADDR_ATTR_IFINDEX;
+}
+
+int rtnl_addr_get_ifindex(struct rtnl_addr *addr)
+{
+	return addr->a_ifindex;
+}
+
+void rtnl_addr_set_link(struct rtnl_addr *addr, struct rtnl_link *link)
+{
+	rtnl_link_put(addr->a_link);
+
+	if (!link)
+		return;
+
+	nl_object_get(OBJ_CAST(link));
+	addr->a_link = link;
+	addr->a_ifindex = link->l_index;
+	addr->ce_mask |= ADDR_ATTR_IFINDEX;
+}
+
+struct rtnl_link *rtnl_addr_get_link(struct rtnl_addr *addr)
+{
+	if (addr->a_link) {
+		nl_object_get(OBJ_CAST(addr->a_link));
+		return addr->a_link;
+	}
+
+	return NULL;
+}
+
+void rtnl_addr_set_family(struct rtnl_addr *addr, int family)
+{
+	addr->a_family = family;
+	addr->ce_mask |= ADDR_ATTR_FAMILY;
+}
+
+int rtnl_addr_get_family(struct rtnl_addr *addr)
+{
+	return addr->a_family;
+}
+
+void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix)
+{
+	addr->a_prefixlen = prefix;
+	addr->ce_mask |= ADDR_ATTR_PREFIXLEN;
+}
+
+int rtnl_addr_get_prefixlen(struct rtnl_addr *addr)
+{
+	return addr->a_prefixlen;
+}
+
+void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope)
+{
+	addr->a_scope = scope;
+	addr->ce_mask |= ADDR_ATTR_SCOPE;
+}
+
+int rtnl_addr_get_scope(struct rtnl_addr *addr)
+{
+	return addr->a_scope;
+}
+
+void rtnl_addr_set_flags(struct rtnl_addr *addr, unsigned int flags)
+{
+	addr->a_flag_mask |= flags;
+	addr->a_flags |= flags;
+	addr->ce_mask |= ADDR_ATTR_FLAGS;
+}
+
+void rtnl_addr_unset_flags(struct rtnl_addr *addr, unsigned int flags)
+{
+	addr->a_flag_mask |= flags;
+	addr->a_flags &= ~flags;
+	addr->ce_mask |= ADDR_ATTR_FLAGS;
+}
+
+unsigned int rtnl_addr_get_flags(struct rtnl_addr *addr)
+{
+	return addr->a_flags;
+}
+
+static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos,
+			        struct nl_addr *new, int flag)
+{
+	if (addr->ce_mask & ADDR_ATTR_FAMILY) {
+		if (new->a_family != addr->a_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		addr->a_family = new->a_family;
+
+	if (*pos)
+		nl_addr_put(*pos);
+
+	*pos = nl_addr_get(new);
+	addr->ce_mask |= (flag | ADDR_ATTR_FAMILY);
+
+	return 0;
+}
+
+int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local)
+{
+	int err;
+
+	err = __assign_addr(addr, &addr->a_local, local, ADDR_ATTR_LOCAL);
+	if (err < 0)
+		return err;
+
+	if (!(addr->ce_mask & ADDR_ATTR_PEER)) {
+		addr->a_prefixlen = nl_addr_get_prefixlen(addr->a_local);
+		addr->ce_mask |= ADDR_ATTR_PREFIXLEN;
+	}
+
+	return 0;
+}
+
+struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr)
+{
+	return addr->a_local;
+}
+
+int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer)
+{
+	return __assign_addr(addr, &addr->a_peer, peer, ADDR_ATTR_PEER);
+
+	addr->a_prefixlen = nl_addr_get_prefixlen(addr->a_peer);
+	addr->ce_mask |= ADDR_ATTR_PREFIXLEN;
+
+	return 0;
+}
+
+struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr)
+{
+	return addr->a_peer;
+}
+
+int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast)
+{
+	return __assign_addr(addr, &addr->a_bcast, bcast, ADDR_ATTR_BROADCAST);
+}
+
+struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr)
+{
+	return addr->a_bcast;
+}
+
+int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast)
+{
+	return __assign_addr(addr, &addr->a_multicast, multicast,
+			     ADDR_ATTR_MULTICAST);
+}
+
+struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr)
+{
+	return addr->a_multicast;
+}
+
+int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast)
+{
+	return __assign_addr(addr, &addr->a_anycast, anycast,
+			     ADDR_ATTR_ANYCAST);
+}
+
+struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *addr)
+{
+	return addr->a_anycast;
+}
+
+uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *addr)
+{
+	if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+		return addr->a_cacheinfo.aci_valid;
+	else
+		return 0xFFFFFFFFU;
+}
+
+void rtnl_addr_set_valid_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
+{
+	addr->a_cacheinfo.aci_valid = lifetime;
+	addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+}
+
+uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *addr)
+{
+	if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+		return addr->a_cacheinfo.aci_prefered;
+	else
+		return 0xFFFFFFFFU;
+}
+
+void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
+{
+	addr->a_cacheinfo.aci_prefered = lifetime;
+	addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+}
+
+uint32_t rtnl_addr_get_create_time(struct rtnl_addr *addr)
+{
+	return addr->a_cacheinfo.aci_cstamp;
+}
+
+uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr)
+{
+	return addr->a_cacheinfo.aci_tstamp;
+}
+
+/** @} */
+
+/**
+ * @name Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl addr_flags[] = {
+	__ADD(IFA_F_SECONDARY, secondary)
+	__ADD(IFA_F_NODAD, nodad)
+	__ADD(IFA_F_OPTIMISTIC, optimistic)
+	__ADD(IFA_F_HOMEADDRESS, homeaddress)
+	__ADD(IFA_F_DEPRECATED, deprecated)
+	__ADD(IFA_F_TENTATIVE, tentative)
+	__ADD(IFA_F_PERMANENT, permanent)
+};
+
+char *rtnl_addr_flags2str(int flags, char *buf, size_t size)
+{
+	return __flags2str(flags, buf, size, addr_flags,
+			   ARRAY_SIZE(addr_flags));
+}
+
+int rtnl_addr_str2flags(const char *name)
+{
+	return __str2flags(name, addr_flags, ARRAY_SIZE(addr_flags));
+}
+
+/** @} */
+
+static struct nl_object_ops addr_obj_ops = {
+	.oo_name		= "route/addr",
+	.oo_size		= sizeof(struct rtnl_addr),
+	.oo_constructor		= addr_constructor,
+	.oo_free_data		= addr_free_data,
+	.oo_clone		= addr_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE] 	= addr_dump_line,
+	    [NL_DUMP_DETAILS]	= addr_dump_details,
+	    [NL_DUMP_STATS]	= addr_dump_stats,
+	},
+	.oo_compare		= addr_compare,
+	.oo_attrs2str		= addr_attrs2str,
+	.oo_id_attrs		= (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+				   ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN),
+};
+
+static struct nl_af_group addr_groups[] = {
+	{ AF_INET,	RTNLGRP_IPV4_IFADDR },
+	{ AF_INET6,	RTNLGRP_IPV6_IFADDR },
+	{ END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_addr_ops = {
+	.co_name		= "route/addr",
+	.co_hdrsize		= sizeof(struct ifaddrmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWADDR, NL_ACT_NEW, "new" },
+					{ RTM_DELADDR, NL_ACT_DEL, "del" },
+					{ RTM_GETADDR, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_groups		= addr_groups,
+	.co_request_update      = addr_request_update,
+	.co_msg_parser          = addr_msg_parser,
+	.co_obj_ops		= &addr_obj_ops,
+};
+
+static void __init addr_init(void)
+{
+	nl_cache_mngt_register(&rtnl_addr_ops);
+}
+
+static void __exit addr_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_addr_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/class.c b/libnetwork/libnl3/lib/route/class.c
new file mode 100644
index 0000000..2a9606b
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/class.c
@@ -0,0 +1,473 @@
+/*
+ * lib/route/class.c            Traffic Classes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup class Traffic Classes
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/class.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/classifier.h>
+#include <netlink/utils.h>
+
+static struct nl_cache_ops rtnl_class_ops;
+static struct nl_object_ops class_obj_ops;
+
+static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+	struct rtnl_class *class = (struct rtnl_class *) tc;
+	char buf[32];
+
+	if (class->c_info)
+		nl_dump(p, "child-qdisc %s ",
+			rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
+}
+
+
+static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct rtnl_class *class;
+	int err;
+
+	if (!(class = rtnl_class_alloc()))
+		return -NLE_NOMEM;
+
+	if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0)
+		goto errout;
+
+	err = pp->pp_cb(OBJ_CAST(class), pp);
+errout:
+	rtnl_class_put(class);
+
+	return err;
+}
+
+static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+	struct tcmsg tchdr = {
+		.tcm_family = AF_UNSPEC,
+		.tcm_ifindex = cache->c_iarg1,
+	};
+
+	return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
+			      sizeof(tchdr));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_class *rtnl_class_alloc(void)
+{
+	struct rtnl_tc *tc;
+
+	tc = TC_CAST(nl_object_alloc(&class_obj_ops));
+	if (tc)
+		tc->tc_type = RTNL_TC_TYPE_CLASS;
+
+	return (struct rtnl_class *) tc;
+}
+
+void rtnl_class_put(struct rtnl_class *class)
+{
+	nl_object_put((struct nl_object *) class);
+}
+
+/** @} */
+
+
+/**
+ * @name Addition/Modification/Deletion
+ * @{
+ */
+
+static int class_build(struct rtnl_class *class, int type, int flags,
+		       struct nl_msg **result)
+{
+	int needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE;
+
+	if ((class->ce_mask & needed) == needed &&
+	    TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) &&
+	    TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) {
+		APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)");
+		return -NLE_INVAL;
+	}
+
+	return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
+}
+
+/**
+ * Build a netlink message requesting the addition of a traffic class
+ * @arg class		Traffic class to add 
+ * @arg flags		Additional netlink message flags
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_class_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_class_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
+				 struct nl_msg **result)
+{
+	return class_build(class, RTM_NEWTCLASS, flags, result);
+}
+
+/**
+ * Add/Update traffic class
+ * @arg sk		Netlink socket
+ * @arg class		Traffic class to add 
+ * @arg flags		Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWTCLASS netlink message requesting the addition
+ * of a new traffic class and sends the message to the kernel. The
+ * configuration of the traffic class is derived from the attributes
+ * of the specified traffic class.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create traffic class if it does not exist,
+ *                      otherwise -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a traffic class with
+ *                      matching handle exists already.
+ *
+ * Existing traffic classes with matching handles will be updated,
+ * unless the flag \c NLM_F_EXCL is specified. If no matching traffic
+ * class exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
+ *
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a traffic class
+ * @arg class		Traffic class to delete
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_class_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_class_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct tcmsg tchdr;
+	int required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE;
+
+	if ((class->ce_mask & required) != required) {
+		APPBUG("ifindex and handle must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0)))
+		return -NLE_NOMEM;
+
+	memset(&tchdr, 0, sizeof(tchdr));
+	tchdr.tcm_family = AF_UNSPEC;
+	tchdr.tcm_ifindex = class->c_ifindex;
+	tchdr.tcm_handle = class->c_handle;
+
+	if (class->ce_mask & TCA_ATTR_PARENT)
+		tchdr.tcm_parent = class->c_parent;
+
+	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+		nlmsg_free(msg);
+		return -NLE_MSGSIZE;
+	}
+
+	*result = msg;
+	return 0;
+}
+
+/**
+ * Delete traffic class
+ * @arg sk		Netlink socket
+ * @arg class		Traffic class to delete
+ *
+ * Builds a \c RTM_DELTCLASS netlink message requesting the deletion
+ * of a traffic class and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex and \c handle (required)
+ * - \c parent (optional, must match if provided)
+ *
+ * All other class attributes including all class type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Leaf Qdisc
+ * @{
+ */
+
+/**
+ * Lookup the leaf qdisc of a traffic class
+ * @arg class		the parent traffic class
+ * @arg cache		a qdisc cache allocated using rtnl_qdisc_alloc_cache()
+ *
+ * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc
+ */
+struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
+					 struct nl_cache *cache)
+{
+	struct rtnl_qdisc *leaf;
+
+	if (!class->c_info)
+		return NULL;
+
+	leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
+					class->c_handle);
+	if (!leaf || leaf->q_handle != class->c_info)
+		return NULL;
+
+	return leaf;
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured traffic classes
+ * @arg sk		Netlink socket
+ * @arg ifindex		Interface index of the network device
+ * @arg result		Pointer to store the created cache
+ *
+ * Allocates a new traffic class cache and fills it with a list of all
+ * configured traffic classes on a specific network device. Release the
+ * cache with nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
+			   struct nl_cache **result)
+{
+	struct nl_cache * cache;
+	int err;
+
+	if (!ifindex) {
+		APPBUG("ifindex must be specified");
+		return -NLE_INVAL;
+	}
+	
+	if (!(cache = nl_cache_alloc(&rtnl_class_ops)))
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = ifindex;
+	
+	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/**
+ * Search traffic class by interface index and handle
+ * @arg cache		Traffic class cache
+ * @arg ifindex		Interface index
+ * @arg handle		ID of traffic class
+ *
+ * Searches a traffic class cache previously allocated with
+ * rtnl_class_alloc_cache() and searches for a traffi class matching
+ * the interface index and handle.
+ *
+ * The reference counter is incremented before returning the traffic
+ * class, therefore the reference must be given back with rtnl_class_put()
+ * after usage.
+ *
+ * @return Traffic class or NULL if no match was found.
+ */
+struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
+				  uint32_t handle)
+{
+	struct rtnl_class *class;
+	
+	if (cache->c_ops != &rtnl_class_ops)
+		return NULL;
+
+	nl_list_for_each_entry(class, &cache->c_items, ce_list) {
+		if (class->c_handle == handle && class->c_ifindex == ifindex) {
+			nl_object_get((struct nl_object *) class);
+			return class;
+		}
+	}
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ * @{
+ */
+
+/**
+ * Call a callback for each child of a class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
+			      void (*cb)(struct nl_object *, void *), void *arg)
+{
+	struct rtnl_class *filter;
+	
+	filter = rtnl_class_alloc();
+	if (!filter)
+		return;
+
+	rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
+	rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
+	rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
+
+	nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+	rtnl_class_put(filter);
+}
+
+/**
+ * Call a callback for each classifier attached to the class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
+			    void (*cb)(struct nl_object *, void *), void *arg)
+{
+	struct rtnl_cls *filter;
+
+	filter = rtnl_cls_alloc();
+	if (!filter)
+		return;
+
+	rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
+	rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
+
+	nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
+	rtnl_cls_put(filter);
+}
+
+/** @} */
+
+static struct rtnl_tc_type_ops class_ops = {
+	.tt_type		= RTNL_TC_TYPE_CLASS,
+	.tt_dump_prefix		= "class",
+	.tt_dump = {
+	    [NL_DUMP_DETAILS]	= class_dump_details,
+	},
+};
+
+static struct nl_object_ops class_obj_ops = {
+	.oo_name		= "route/class",
+	.oo_size		= sizeof(struct rtnl_class),
+	.oo_free_data         	= rtnl_tc_free_data,
+	.oo_clone		= rtnl_tc_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= rtnl_tc_dump_line,
+	    [NL_DUMP_DETAILS]	= rtnl_tc_dump_details,
+	    [NL_DUMP_STATS]	= rtnl_tc_dump_stats,
+	},
+	.oo_compare		= rtnl_tc_compare,
+	.oo_id_attrs		= (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static struct nl_cache_ops rtnl_class_ops = {
+	.co_name		= "route/class",
+	.co_hdrsize		= sizeof(struct tcmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWTCLASS, NL_ACT_NEW, "new" },
+					{ RTM_DELTCLASS, NL_ACT_DEL, "del" },
+					{ RTM_GETTCLASS, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_request_update	= &class_request_update,
+	.co_msg_parser		= &class_msg_parser,
+	.co_obj_ops		= &class_obj_ops,
+};
+
+static void __init class_init(void)
+{
+	rtnl_tc_type_register(&class_ops);
+	nl_cache_mngt_register(&rtnl_class_ops);
+}
+
+static void __exit class_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_class_ops);
+	rtnl_tc_type_unregister(&class_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/classid.c b/libnetwork/libnl3/lib/route/classid.c
new file mode 100644
index 0000000..abed244
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/classid.c
@@ -0,0 +1,441 @@
+/*
+ * lib/route/classid.c       ClassID Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup classid ClassID Management
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc.h>
+
+struct classid_map
+{
+	uint32_t		classid;
+	char *			name;
+	struct nl_list_head	name_list;
+};
+
+#define CLASSID_NAME_HT_SIZ 256
+
+static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
+
+static void *id_root = NULL;
+
+static int compare_id(const void *pa, const void *pb)
+{
+	const struct classid_map *ma = pa;
+	const struct classid_map *mb = pb;
+
+	if (ma->classid < mb->classid)
+		return -1;
+	
+	if (ma->classid > mb->classid)
+		return 1;
+
+	return 0;
+}
+
+/* djb2 */
+static unsigned int classid_tbl_hash(const char *str)
+{
+	unsigned long hash = 5381;
+	int c;
+
+	while ((c = *str++))
+		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+	return hash % CLASSID_NAME_HT_SIZ;
+}
+
+static int classid_lookup(const char *name, uint32_t *result)
+{
+	struct classid_map *map;
+	int n = classid_tbl_hash(name);
+
+	nl_list_for_each_entry(map, &tbl_name[n], name_list) {
+		if (!strcasecmp(map->name, name)) {
+			*result = map->classid;
+			return 0;
+		}
+	}
+
+	return -NLE_OBJ_NOTFOUND;
+}
+
+static char *name_lookup(const uint32_t classid)
+{
+	void *res;
+	struct classid_map cm = {
+		.classid = classid,
+		.name = "search entry",
+	};
+
+	if ((res = tfind(&cm, &id_root, &compare_id)))
+		return (*(struct classid_map **) res)->name;
+
+	return NULL;
+}
+
+/**
+ * @name Traffic Control Handle Translations
+ * @{
+ */
+
+/**
+ * Convert a traffic control handle to a character string (Reentrant).
+ * @arg handle		traffic control handle
+ * @arg buf		destination buffer
+ * @arg len		buffer length
+ *
+ * Converts a tarffic control handle to a character string in the
+ * form of \c MAJ:MIN and stores it in the specified destination buffer.
+ *
+ * @return The destination buffer or the type encoded in hexidecimal
+ *         form if no match was found.
+ */
+char *rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
+{
+	if (TC_H_ROOT == handle)
+		snprintf(buf, len, "root");
+	else if (TC_H_UNSPEC == handle)
+		snprintf(buf, len, "none");
+	else if (TC_H_INGRESS == handle)
+		snprintf(buf, len, "ingress");
+	else {
+		char *name;
+
+		if ((name = name_lookup(handle)))
+			snprintf(buf, len, "%s", name);
+		else if (0 == TC_H_MAJ(handle))
+			snprintf(buf, len, ":%x", TC_H_MIN(handle));
+		else if (0 == TC_H_MIN(handle))
+			snprintf(buf, len, "%x:", TC_H_MAJ(handle) >> 16);
+		else
+			snprintf(buf, len, "%x:%x",
+				TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
+	}
+
+	return buf;
+}
+
+/**
+ * Convert a charactering strint to a traffic control handle
+ * @arg str		traffic control handle as character string
+ * @arg res		destination buffer
+ *
+ * Converts the provided character string specifying a traffic
+ * control handle to the corresponding numeric value.
+ *
+ * The handle must be provided in one of the following formats:
+ *  - NAME
+ *  - root
+ *  - none
+ *  - MAJ:
+ *  - :MIN
+ *  - NAME:MIN
+ *  - MAJ:MIN
+ *  - MAJMIN
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_tc_str2handle(const char *str, uint32_t *res)
+{
+	char *colon, *end;
+	uint32_t h, err;
+
+	if (!strcasecmp(str, "root")) {
+		*res = TC_H_ROOT;
+		return 0;
+	}
+
+	if (!strcasecmp(str, "none")) {
+		*res = TC_H_UNSPEC;
+		return 0;
+	}
+
+	h = strtoul(str, &colon, 16);
+
+	/* MAJ is not a number */
+	if (colon == str) {
+not_a_number:
+		if (*colon == ':') {
+			/* :YYYY */
+			h = 0;
+		} else {
+			size_t len;
+			char name[64] = { 0 };
+
+			if (!(colon = strpbrk(str, ":"))) {
+				/* NAME */
+				return classid_lookup(str, res);
+			} else {
+				/* NAME:YYYY */
+				len = colon - str;
+				if (len >= sizeof(name))
+					return -NLE_INVAL;
+
+				memcpy(name, str, len);
+
+				if ((err = classid_lookup(name, &h)) < 0)
+					return err;
+
+				/* Name must point to a qdisc alias */
+				if (TC_H_MIN(h))
+					return -NLE_INVAL;
+
+				/* NAME: is not allowed */
+				if (colon[1] == '\0')
+					return -NLE_INVAL;
+
+				goto update;
+			}
+		}
+	}
+
+	if (':' == *colon) {
+		/* check if we would lose bits */
+		if (TC_H_MAJ(h))
+			return -NLE_RANGE;
+		h <<= 16;
+
+		if ('\0' == colon[1]) {
+			/* XXXX: */
+			*res = h;
+		} else {
+			/* XXXX:YYYY */
+			uint32_t l;
+			
+update:
+			l = strtoul(colon+1, &end, 16);
+
+			/* check if we overlap with major part */
+			if (TC_H_MAJ(l))
+				return -NLE_RANGE;
+
+			if ('\0' != *end)
+				return -NLE_INVAL;
+
+			*res = (h | l);
+		}
+	} else if ('\0' == *colon) {
+		/* XXXXYYYY */
+		*res = h;
+	} else
+		goto not_a_number;
+
+	return 0;
+}
+
+static void free_nothing(void *arg)
+{
+}
+
+static void classid_map_free(struct classid_map *map)
+{
+	if (!map)
+		return;
+
+	free(map->name);
+	free(map);
+}
+
+static void clear_hashtable(void)
+{
+	int i;
+
+	for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
+		struct classid_map *map, *n;
+
+		nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
+			classid_map_free(map);
+
+		nl_init_list_head(&tbl_name[i]);
+
+	}
+
+	if (id_root) {
+		tdestroy(&id_root, &free_nothing);
+		id_root = NULL;
+	}
+}
+
+static int classid_map_add(uint32_t classid, const char *name)
+{
+	struct classid_map *map;
+	int n;
+
+	if (!(map = calloc(1, sizeof(*map))))
+		return -NLE_NOMEM;
+
+	map->classid = classid;
+	map->name = strdup(name);
+
+	n = classid_tbl_hash(map->name);
+	nl_list_add_tail(&map->name_list, &tbl_name[n]);
+
+	if (!tsearch((void *) map, &id_root, &compare_id)) {
+		classid_map_free(map);
+		return -NLE_NOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * (Re-)read classid file
+ * 
+ * Rereads the contents of the classid file (typically found at the location
+ * /etc/libnl/classid) and refreshes the classid maps.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_tc_read_classid_file(void)
+{
+	static time_t last_read;
+	struct stat st = {0};
+	char buf[256], *path;
+	FILE *fd;
+	int err;
+
+	if (build_sysconf_path(&path, "classid") < 0)
+		return -NLE_NOMEM;
+
+	/* if stat fails, just (re-)read the file */
+	if (stat(path, &st) == 0) {
+		/* Don't re-read file if file is unchanged */
+		if (last_read == st.st_mtime) {
+			err = 0;
+			goto errout;
+		}
+	}
+
+	if (!(fd = fopen(path, "r"))) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	clear_hashtable();
+
+	while (fgets(buf, sizeof(buf), fd)) {
+		uint32_t classid;
+		char *ptr, *tok;
+
+		/* ignore comments and empty lines */
+		if (*buf == '#' || *buf == '\n' || *buf == '\r')
+			continue;
+
+		/* token 1 */
+		if (!(tok = strtok_r(buf, " \t", &ptr))) {
+			err = -NLE_INVAL;
+			goto errout_close;
+		}
+
+		if ((err = rtnl_tc_str2handle(tok, &classid)) < 0)
+			goto errout_close;
+
+		if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) {
+			err = -NLE_INVAL;
+			goto errout_close;
+		}
+
+		if ((err = classid_map_add(classid, tok)) < 0)
+			goto errout_close;
+	}
+
+	err = 0;
+	last_read = st.st_mtime;
+
+errout_close:
+	fclose(fd);
+errout:
+	free(path);
+
+	return err;
+
+}
+
+int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
+{
+	static uint32_t base = 0x4000 << 16;
+	uint32_t classid;
+	char *path;
+	FILE *fd;
+	int err = 0;
+
+	if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
+		do {
+			base += (1 << 16);
+			if (base == TC_H_MAJ(TC_H_ROOT))
+				base = 0x4000 << 16;
+		} while (name_lookup(base));
+
+		classid = base;
+	} else {
+		classid = TC_H_MAJ(parent);
+		do {
+			if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
+				return -NLE_RANGE;
+		} while (name_lookup(classid));
+	}
+
+	NL_DBG(2, "Generated new classid %#x\n", classid);
+
+	if (build_sysconf_path(&path, "classid") < 0)
+		return -NLE_NOMEM;
+
+	if (!(fd = fopen(path, "a"))) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16);
+	if (TC_H_MIN(classid))
+		fprintf(fd, "%x", TC_H_MIN(classid));
+	fprintf(fd, "\t\t\t%s\n", name);
+
+	fclose(fd);
+
+	if ((err = classid_map_add(classid, name)) < 0) {
+		/* 
+		 * Error adding classid map, re-read classid file is best
+		 * option here. It is likely to fail as well but better
+		 * than nothing, entry was added to the file already anyway.
+		 */
+		rtnl_tc_read_classid_file();
+	}
+
+	*result = classid;
+	err = 0;
+errout:
+	free(path);
+
+	return err;
+}
+
+/** @} */
+
+static void __init classid_init(void)
+{
+	int err, i;
+
+	for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
+		nl_init_list_head(&tbl_name[i]);
+
+	if ((err = rtnl_tc_read_classid_file()) < 0)
+		fprintf(stderr, "Failed to read classid file: %s\n", nl_geterror(err));
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls.c b/libnetwork/libnl3/lib/route/cls.c
new file mode 100644
index 0000000..fb2e9be
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls.c
@@ -0,0 +1,441 @@
+/*
+ * lib/route/classifier.c       Classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup cls Classifiers
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/link.h>
+
+/** @cond SKIP */
+#define CLS_ATTR_PRIO		(TCA_ATTR_MAX << 1)
+#define CLS_ATTR_PROTOCOL	(TCA_ATTR_MAX << 2)
+/** @endcond */
+
+static struct nl_object_ops cls_obj_ops;
+static struct nl_cache_ops rtnl_cls_ops;
+
+
+static int cls_build(struct rtnl_cls *cls, int type, int flags,
+		     struct nl_msg **result)
+{
+	int err, prio, proto;
+	struct tcmsg *tchdr;
+	int required = TCA_ATTR_IFINDEX;
+
+	if ((cls->ce_mask & required) != required) {
+		APPBUG("ifindex must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
+	if (err < 0)
+		return err;
+
+	tchdr = nlmsg_data(nlmsg_hdr(*result));
+	prio = rtnl_cls_get_prio(cls);
+	proto = rtnl_cls_get_protocol(cls);
+	tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
+
+	return 0;
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_cls *rtnl_cls_alloc(void)
+{
+	struct rtnl_tc *tc;
+
+	tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
+	if (tc)
+		tc->tc_type = RTNL_TC_TYPE_CLS;
+
+	return (struct rtnl_cls *) tc;
+}
+
+void rtnl_cls_put(struct rtnl_cls *cls)
+{
+	nl_object_put((struct nl_object *) cls);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
+{
+	cls->c_prio = prio;
+	cls->ce_mask |= CLS_ATTR_PRIO;
+}
+
+uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
+{
+	if (cls->ce_mask & CLS_ATTR_PRIO)
+		return cls->c_prio;
+	else
+		return 0;
+}
+
+void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
+{
+	cls->c_protocol = protocol;
+	cls->ce_mask |= CLS_ATTR_PROTOCOL;
+}
+
+uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
+{
+	if (cls->ce_mask & CLS_ATTR_PROTOCOL)
+		return cls->c_protocol;
+	else
+		return ETH_P_ALL;
+}
+
+/** @} */
+
+
+/**
+ * @name Addition/Modification/Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the addition of a classifier
+ * @arg cls		Classifier to add 
+ * @arg flags		Additional netlink message flags
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_cls_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_cls_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
+			       struct nl_msg **result)
+{
+	if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
+		APPBUG("prio must be specified if not a new classifier");
+		return -NLE_MISSING_ATTR;
+	}
+
+	return cls_build(cls, RTM_NEWTFILTER, flags, result);
+}
+
+/**
+ * Add/Update classifier
+ * @arg sk		Netlink socket
+ * @arg cls		Classifier to add/update
+ * @arg flags		Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
+ * of a new classifier and sends the message to the kernel. The
+ * configuration of the classifier is derived from the attributes of
+ * the specified traffic class.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create classifier if it does not exist,
+ *                      otherwise -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a classifier with
+ *                      matching handle exists already.
+ *
+ * Existing classifiers with matching handles will be updated, unless
+ * the flag \c NLM_F_EXCL is specified. If no matching classifier
+ * exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
+ *
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build a netlink message to change classifier attributes
+ * @arg cls		classifier to change
+ * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting a change of a neigh
+ * attributes. The netlink message header isn't fully equipped with
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
+				  struct nl_msg **result)
+{
+	return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
+}
+
+/**
+ * Change a classifier
+ * @arg sk		Netlink socket.
+ * @arg cls		classifier to change
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_cls_build_change_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been processed.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
+		return err;
+	
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a classifier
+ * @arg cls		Classifier to delete
+ * @arg flags		Additional netlink message flags
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_cls_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_cls_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
+				  struct nl_msg **result)
+{
+	int required = CLS_ATTR_PRIO;
+
+	if ((cls->ce_mask & required) != required) {
+		APPBUG("prio must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	return cls_build(cls, RTM_DELTFILTER, flags, result);
+}
+
+/**
+ * Delete classifier
+ * @arg sk		Netlink socket
+ * @arg cls		Classifier to delete
+ * @arg flags		Additional netlink message flags
+ *
+ * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
+ * of a classifier and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex (required)
+ * - \c prio (required)
+ * - \c protocol (required)
+ * - \c handle (required)
+ * - \c parent (optional, if not specified parent equals root-qdisc)
+ * - \c kind (optional, must match if provided)
+ *
+ * All other classifier attributes including all class type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
+		return err;
+	
+	return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured classifiers
+ * @arg sk		Netlink socket
+ * @arg ifindex		Interface index of the network device
+ * @arg parent		Parent qdisc/traffic class class
+ * @arg result		Pointer to store the created cache
+ *
+ * Allocates a new classifier cache and fills it with a list of all
+ * configured classifier attached to the specified parent qdisc/traffic
+ * class on the specified network device. Release the cache with
+ * nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,			 struct nl_cache **result)
+{
+	struct nl_cache * cache;
+	int err;
+	
+	if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = ifindex;
+	cache->c_iarg2 = parent;
+	
+	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/** @} */
+
+static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+	struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+	char buf[32];
+
+	nl_dump(p, " prio %u protocol %s", cls->c_prio,
+		nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
+}
+
+static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			  struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct rtnl_cls *cls;
+	int err;
+
+	if (!(cls = rtnl_cls_alloc()))
+		return -NLE_NOMEM;
+
+	if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
+		goto errout;
+
+	cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
+	cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
+
+	err = pp->pp_cb(OBJ_CAST(cls), pp);
+errout:
+	rtnl_cls_put(cls);
+
+	return err;
+}
+
+static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+	struct tcmsg tchdr = {
+		.tcm_family = AF_UNSPEC,
+		.tcm_ifindex = cache->c_iarg1,
+		.tcm_parent = cache->c_iarg2,
+	};
+
+	return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
+			      sizeof(tchdr));
+}
+
+static struct rtnl_tc_type_ops cls_ops = {
+	.tt_type		= RTNL_TC_TYPE_CLS,
+	.tt_dump_prefix		= "cls",
+	.tt_dump = {
+		[NL_DUMP_LINE]	= cls_dump_line,
+	},
+};
+
+static struct nl_cache_ops rtnl_cls_ops = {
+	.co_name		= "route/cls",
+	.co_hdrsize		= sizeof(struct tcmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWTFILTER, NL_ACT_NEW, "new" },
+					{ RTM_DELTFILTER, NL_ACT_DEL, "del" },
+					{ RTM_GETTFILTER, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_request_update	= cls_request_update,
+	.co_msg_parser		= cls_msg_parser,
+	.co_obj_ops		= &cls_obj_ops,
+};
+
+static struct nl_object_ops cls_obj_ops = {
+	.oo_name		= "route/cls",
+	.oo_size		= sizeof(struct rtnl_cls),
+	.oo_free_data		= rtnl_tc_free_data,
+	.oo_clone		= rtnl_tc_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= rtnl_tc_dump_line,
+	    [NL_DUMP_DETAILS]	= rtnl_tc_dump_details,
+	    [NL_DUMP_STATS]	= rtnl_tc_dump_stats,
+	},
+	.oo_compare		= rtnl_tc_compare,
+	.oo_id_attrs		= (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static void __init cls_init(void)
+{
+	rtnl_tc_type_register(&cls_ops);
+	nl_cache_mngt_register(&rtnl_cls_ops);
+}
+
+static void __exit cls_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_cls_ops);
+	rtnl_tc_type_unregister(&cls_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/.dirstamp b/libnetwork/libnl3/lib/route/cls/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/route/cls/basic.c b/libnetwork/libnl3/lib/route/cls/basic.c
new file mode 100644
index 0000000..9d7710a
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/basic.c
@@ -0,0 +1,229 @@
+/*
+ * lib/route/cls/basic.c	Basic Classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_basic Basic Classifier
+ *
+ * @par Introduction
+ * The basic classifier is the simplest form of a classifier. It does
+ * not have any special classification capabilities, instead it can be
+ * used to classify exclusively based on extended matches or to
+ * create a "catch-all" filter.
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/basic.h>
+#include <netlink/route/cls/ematch.h>
+
+struct rtnl_basic
+{
+	uint32_t			b_target;
+	struct rtnl_ematch_tree *	b_ematch;
+	int				b_mask;
+};
+
+/** @cond SKIP */
+#define BASIC_ATTR_TARGET	0x001
+#define BASIC_ATTR_EMATCH	0x002
+/** @endcond */
+
+static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = {
+	[TCA_BASIC_CLASSID]	= { .type = NLA_U32 },
+	[TCA_BASIC_EMATCHES]	= { .type = NLA_NESTED },
+};
+
+static int basic_clone(void *_dst, void *_src)
+{
+	return -NLE_OPNOTSUPP;
+}
+
+static void basic_free_data(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_basic *b = data;
+
+	if (!b)
+		return;
+
+	rtnl_ematch_tree_free(b->b_ematch);
+}
+
+static int basic_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_BASIC_MAX + 1];
+	struct rtnl_basic *b = data;
+	int err;
+
+	err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_BASIC_CLASSID]) {
+		b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]);
+		b->b_mask |= BASIC_ATTR_TARGET;
+	}
+
+	if (tb[TCA_BASIC_EMATCHES]) {
+		if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES],
+					     &b->b_ematch)) < 0)
+			return err;
+
+		if (b->b_ematch)
+			b->b_mask |= BASIC_ATTR_EMATCH;
+	}
+
+	return 0;
+}
+
+static void basic_dump_line(struct rtnl_tc *tc, void *data,
+			    struct nl_dump_params *p)
+{
+	struct rtnl_basic *b = data;
+	char buf[32];
+
+	if (!b)
+		return;
+
+	if (b->b_mask & BASIC_ATTR_EMATCH)
+		nl_dump(p, " ematch");
+	else
+		nl_dump(p, " match-all");
+
+	if (b->b_mask & BASIC_ATTR_TARGET)
+		nl_dump(p, " target %s",
+			rtnl_tc_handle2str(b->b_target, buf, sizeof(buf)));
+}
+
+static void basic_dump_details(struct rtnl_tc *tc, void *data,
+			       struct nl_dump_params *p)
+{
+	struct rtnl_basic *b = data;
+
+	if (!b)
+		return;
+
+	if (b->b_mask & BASIC_ATTR_EMATCH) {
+		nl_dump_line(p, "    ematch ");
+		rtnl_ematch_tree_dump(b->b_ematch, p);
+	} else
+		nl_dump(p, "no options.\n");
+}
+
+static int basic_msg_fill(struct rtnl_tc *tc, void *data,
+			  struct nl_msg *msg)
+{
+	struct rtnl_basic *b = data;
+
+	if (!b)
+		return 0;
+
+	if (!(b->b_mask & BASIC_ATTR_TARGET))
+		return -NLE_MISSING_ATTR;
+
+	NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target);
+
+	if (b->b_mask & BASIC_ATTR_EMATCH &&
+	    rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0)
+		goto nla_put_failure;
+	
+	return 0;
+
+nla_put_failure:
+	return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target)
+{
+	struct rtnl_basic *b;
+
+	if (!(b = rtnl_tc_data(TC_CAST(cls))))
+		return;
+
+	b->b_target = target;
+	b->b_mask |= BASIC_ATTR_TARGET;
+}
+
+uint32_t rtnl_basic_get_target(struct rtnl_cls *cls)
+{
+	struct rtnl_basic *b;
+
+	if (!(b = rtnl_tc_data(TC_CAST(cls))))
+		return 0;
+
+	return b->b_target;
+}
+
+void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+	struct rtnl_basic *b;
+
+	if (!(b = rtnl_tc_data(TC_CAST(cls))))
+		return;
+
+	if (b->b_ematch) {
+		rtnl_ematch_tree_free(b->b_ematch);
+		b->b_mask &= ~BASIC_ATTR_EMATCH;
+	}
+
+	b->b_ematch = tree;
+
+	if (tree)
+		b->b_mask |= BASIC_ATTR_EMATCH;
+}
+
+struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
+{
+	struct rtnl_basic *b;
+
+	if (!(b = rtnl_tc_data(TC_CAST(cls))))
+		return NULL;
+
+	return b->b_ematch;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops basic_ops = {
+	.to_kind		= "basic",
+	.to_type		= RTNL_TC_TYPE_CLS,
+	.to_size		= sizeof(struct rtnl_basic),
+	.to_msg_parser		= basic_msg_parser,
+	.to_clone		= basic_clone,
+	.to_free_data		= basic_free_data,
+	.to_msg_fill		= basic_msg_fill,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= basic_dump_line,
+	    [NL_DUMP_DETAILS]	= basic_dump_details,
+	},
+};
+
+static void __init basic_init(void)
+{
+	rtnl_tc_register(&basic_ops);
+}
+
+static void __exit basic_exit(void)
+{
+	rtnl_tc_unregister(&basic_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/cgroup.c b/libnetwork/libnl3/lib/route/cls/cgroup.c
new file mode 100644
index 0000000..230863b
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/cgroup.c
@@ -0,0 +1,189 @@
+/*
+ * lib/route/cls/cgroup.c	Control Groups Classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2009-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_cgroup Control Groups Classifier
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/cgroup.h>
+#include <netlink/route/cls/ematch.h>
+
+/** @cond SKIP */
+#define CGROUP_ATTR_EMATCH      0x001
+/** @endcond */
+
+static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
+	[TCA_CGROUP_EMATCHES]	= { .type = NLA_NESTED },
+};
+
+static int cgroup_clone(void *dst, void *src)
+{
+	return -NLE_OPNOTSUPP;
+}
+
+static void cgroup_free_data(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_cgroup *c = data;
+
+	if (!c)
+		return;
+
+	rtnl_ematch_tree_free(c->cg_ematch);
+}
+
+static int cgroup_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_CGROUP_MAX + 1];
+	struct rtnl_cgroup *c = data;
+	int err;
+
+	err = tca_parse(tb, TCA_CGROUP_MAX, tc, cgroup_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_CGROUP_EMATCHES]) {
+		if ((err = rtnl_ematch_parse_attr(tb[TCA_CGROUP_EMATCHES],
+						  &c->cg_ematch)) < 0)
+			return err;
+		c->cg_mask |= CGROUP_ATTR_EMATCH;
+	}
+
+#if 0
+	TODO:
+	TCA_CGROUP_ACT,
+	TCA_CGROUP_POLICE,
+#endif
+
+	return 0;
+}
+
+static void cgroup_dump_line(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_cgroup *c = data;
+
+	if (!c)
+		return;
+
+	if (c->cg_mask & CGROUP_ATTR_EMATCH)
+		nl_dump(p, " ematch");
+	else
+		nl_dump(p, " match-all");
+}
+
+static void cgroup_dump_details(struct rtnl_tc *tc, void *data,
+				struct nl_dump_params *p)
+{
+	struct rtnl_cgroup *c = data;
+
+	if (!c)
+		return;
+
+	if (c->cg_mask & CGROUP_ATTR_EMATCH) {
+		nl_dump_line(p, "    ematch ");
+
+		if (c->cg_ematch)
+			rtnl_ematch_tree_dump(c->cg_ematch, p);
+		else
+			nl_dump(p, "<no tree>");
+	} else
+		nl_dump(p, "no options");
+}
+
+static int cgroup_fill_msg(struct rtnl_tc *tc, void *data,
+			   struct nl_msg *msg)
+{
+	struct rtnl_cgroup *c = data;
+
+	if (!c)
+		BUG();
+
+	if (!(tc->ce_mask & TCA_ATTR_HANDLE))
+		return -NLE_MISSING_ATTR;
+
+	if (c->cg_mask & CGROUP_ATTR_EMATCH)
+		return rtnl_ematch_fill_attr(msg, TCA_CGROUP_EMATCHES,
+					     c->cg_ematch);
+
+	return 0;
+}
+
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+	struct rtnl_cgroup *c;
+
+	if (!(c = rtnl_tc_data(TC_CAST(cls))))
+		BUG();
+
+	if (c->cg_ematch) {
+		rtnl_ematch_tree_free(c->cg_ematch);
+		c->cg_mask &= ~CGROUP_ATTR_EMATCH;
+	}
+
+	c->cg_ematch = tree;
+
+	if (tree)
+		c->cg_mask |= CGROUP_ATTR_EMATCH;
+}
+
+struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls)
+{
+	struct rtnl_cgroup *c;
+
+	if (!(c = rtnl_tc_data(TC_CAST(cls))))
+		BUG();
+
+	return c->cg_ematch;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops cgroup_ops = {
+	.to_kind		= "cgroup",
+	.to_type		= RTNL_TC_TYPE_CLS,
+	.to_size		= sizeof(struct rtnl_cgroup),
+	.to_clone		= cgroup_clone,
+	.to_msg_parser		= cgroup_msg_parser,
+	.to_free_data		= cgroup_free_data,
+	.to_msg_fill		= cgroup_fill_msg,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= cgroup_dump_line,
+	    [NL_DUMP_DETAILS]	= cgroup_dump_details,
+	},
+};
+
+static void __init cgroup_init(void)
+{
+	rtnl_tc_register(&cgroup_ops);
+}
+
+static void __exit cgroup_exit(void)
+{
+	rtnl_tc_unregister(&cgroup_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch.c b/libnetwork/libnl3/lib/route/cls/ematch.c
new file mode 100644
index 0000000..8c9c3dd
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch.c
@@ -0,0 +1,701 @@
+/*
+ * lib/route/cls/ematch.c	Extended Matches
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup ematch Extended Match
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
+
+#include "ematch_syntax.h"
+#include "ematch_grammar.h"
+
+/**
+ * @name Module API
+ * @{
+ */
+
+static NL_LIST_HEAD(ematch_ops_list);
+
+/**
+ * Register ematch module
+ * @arg ops		Module operations.
+ *
+ * This function must be called by each ematch module at initialization
+ * time. It registers the calling module as available module.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
+{
+	if (rtnl_ematch_lookup_ops(ops->eo_kind))
+		return -NLE_EXIST;
+
+	NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name);
+
+	nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
+
+	return 0;
+}
+
+/**
+ * Lookup ematch module by identification number.
+ * @arg kind		Module kind.
+ *
+ * Searches the list of registered ematch modules for match and returns it.
+ *
+ * @return Module operations or NULL if not found.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
+{
+	struct rtnl_ematch_ops *ops;
+
+	nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+		if (ops->eo_kind == kind)
+			return ops;
+
+	return NULL;
+}
+
+/**
+ * Lookup ematch module by name
+ * @arg name		Name of ematch module.
+ *
+ * Searches the list of registered ematch modules for a match and returns it.
+ *
+ * @return Module operations or NULL if not fuond.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name)
+{
+	struct rtnl_ematch_ops *ops;
+
+	nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+		if (!strcasecmp(ops->eo_name, name))
+			return ops;
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Match
+ */
+
+/**
+ * Allocate ematch object.
+ *
+ * Allocates and initializes an ematch object.
+ *
+ * @return New ematch object or NULL.
+ */
+struct rtnl_ematch *rtnl_ematch_alloc(void)
+{
+	struct rtnl_ematch *e;
+
+	if (!(e = calloc(1, sizeof(*e))))
+		return NULL;
+
+	NL_DBG(2, "allocated ematch %p\n", e);
+
+	NL_INIT_LIST_HEAD(&e->e_list);
+	NL_INIT_LIST_HEAD(&e->e_childs);
+
+	return e;
+}
+
+/**
+ * Add ematch to the end of the parent's list of children.
+ * @arg parent		parent ematch object
+ * @arg child		ematch object to be added to parent
+ *
+ * The parent must be a container ematch.
+ */
+int rtnl_ematch_add_child(struct rtnl_ematch *parent,
+			   struct rtnl_ematch *child)
+{
+	if (parent->e_kind != TCF_EM_CONTAINER)
+		return -NLE_OPNOTSUPP;
+
+	NL_DBG(2, "added ematch %p \"%s\" to container %p\n",
+		  child, child->e_ops->eo_name, parent);
+
+	nl_list_add_tail(&child->e_list, &parent->e_childs);
+
+	return 0;
+}
+
+/**
+ * Remove ematch from the list of ematches it is linked to.
+ * @arg ematch		ematch object
+ */
+void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
+{
+	NL_DBG(2, "unlinked ematch %p from any lists\n", ematch);
+
+	if (!nl_list_empty(&ematch->e_childs))
+		NL_DBG(1, "warning: ematch %p with childs was unlinked\n",
+			  ematch);
+
+	nl_list_del(&ematch->e_list);
+	nl_init_list_head(&ematch->e_list);
+}
+
+void rtnl_ematch_free(struct rtnl_ematch *ematch)
+{
+	NL_DBG(2, "freed ematch %p\n", ematch);
+	rtnl_ematch_unlink(ematch);
+	free(ematch->e_data);
+	free(ematch);
+}
+
+int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops)
+{
+	if (ematch->e_ops)
+		return -NLE_EXIST;
+
+	ematch->e_ops = ops;
+	ematch->e_kind = ops->eo_kind;
+
+	if (ops->eo_datalen) {
+		ematch->e_data = calloc(1, ops->eo_datalen);
+		if (!ematch->e_data)
+			return -NLE_NOMEM;
+
+		ematch->e_datalen = ops->eo_datalen;
+	}
+
+	return 0;
+}
+
+int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind)
+{
+	struct rtnl_ematch_ops *ops;
+
+	if (ematch->e_kind)
+		return -NLE_EXIST;
+
+	ematch->e_kind = kind;
+
+	if ((ops = rtnl_ematch_lookup_ops(kind)))
+		rtnl_ematch_set_ops(ematch, ops);
+
+	return 0;
+}
+
+int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name)
+{
+	struct rtnl_ematch_ops *ops;
+
+	if (ematch->e_kind)
+		return -NLE_EXIST;
+
+	if (!(ops = rtnl_ematch_lookup_ops_by_name(name)))
+		return -NLE_OPNOTSUPP;
+
+	rtnl_ematch_set_ops(ematch, ops);
+
+	return 0;
+}
+
+void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+	ematch->e_flags |= flags;
+}
+
+void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+	ematch->e_flags &= ~flags;
+}
+
+uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
+{
+	return ematch->e_flags;
+}
+
+void *rtnl_ematch_data(struct rtnl_ematch *ematch)
+{
+	return ematch->e_data;
+}
+
+/** @} */
+
+/**
+ * @name Tree
+ */
+
+/**
+ * Allocate ematch tree object
+ * @arg progid		program id
+ */
+struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
+{
+	struct rtnl_ematch_tree *tree;
+
+	if (!(tree = calloc(1, sizeof(*tree))))
+		return NULL;
+	
+	NL_INIT_LIST_HEAD(&tree->et_list);
+	tree->et_progid = progid;
+
+	NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid);
+
+	return tree;
+}
+
+static void free_ematch_list(struct nl_list_head *head)
+{
+	struct rtnl_ematch *pos, *next;
+
+	nl_list_for_each_entry_safe(pos, next, head, e_list) {
+		if (!nl_list_empty(&pos->e_childs))
+			free_ematch_list(&pos->e_childs);
+		rtnl_ematch_free(pos);
+	}
+}
+
+/**
+ * Free ematch tree object
+ * @arg tree		ematch tree object
+ *
+ * This function frees the ematch tree and all ematches attached to it.
+ */
+void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
+{
+	if (!tree)
+		return;
+
+	free_ematch_list(&tree->et_list);
+	free(tree);
+
+	NL_DBG(2, "Freed ematch tree %p\n", tree);
+}
+
+/**
+ * Add ematch object to the end of the ematch tree
+ * @arg tree		ematch tree object
+ * @arg ematch		ematch object to add
+ */
+void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree,
+			  struct rtnl_ematch *ematch)
+{
+	nl_list_add_tail(&ematch->e_list, &tree->et_list);
+}
+
+static inline uint32_t container_ref(struct rtnl_ematch *ematch)
+{
+	return *((uint32_t *) rtnl_ematch_data(ematch));
+}
+
+static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
+		     struct nl_list_head *root)
+{
+	struct rtnl_ematch *ematch;
+	int i;
+
+	for (i = pos; i < nmatches; i++) {
+		ematch = index[i];
+
+		nl_list_add_tail(&ematch->e_list, root);
+
+		if (ematch->e_kind == TCF_EM_CONTAINER)
+			link_tree(index, nmatches, container_ref(ematch),
+				  &ematch->e_childs);
+
+		if (!(ematch->e_flags & TCF_EM_REL_MASK))
+			return 0;
+	}
+
+	/* Last entry in chain can't possibly have no relation */
+	return -NLE_INVAL;
+}
+
+static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
+	[TCA_EMATCH_TREE_HDR]  = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
+	[TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
+};
+
+/**
+ * Parse ematch netlink attributes
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
+{
+	struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
+	struct tcf_ematch_tree_hdr *thdr;
+	struct rtnl_ematch_tree *tree;
+	struct rtnl_ematch **index;
+	int nmatches = 0, err, remaining;
+
+	NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr);
+
+	err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
+	if (err < 0)
+		return err;
+
+	if (!tb[TCA_EMATCH_TREE_HDR])
+		return -NLE_MISSING_ATTR;
+
+	thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
+
+	/* Ignore empty trees */
+	if (thdr->nmatches == 0) {
+		NL_DBG(2, "Ignoring empty ematch configuration\n");
+		return 0;
+	}
+
+	if (!tb[TCA_EMATCH_TREE_LIST])
+		return -NLE_MISSING_ATTR;
+
+	NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n",
+		  thdr->nmatches, thdr->progid);
+
+	/*
+	 * Do some basic sanity checking since we will allocate
+	 * index[thdr->nmatches]. Calculate how many ematch headers fit into
+	 * the provided data and make sure nmatches does not exceed it.
+	 */
+	if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
+			      nla_total_size(sizeof(struct tcf_ematch_hdr))))
+		return -NLE_INVAL;
+
+	if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
+		return -NLE_NOMEM;
+
+	if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
+		struct rtnl_ematch_ops *ops;
+		struct tcf_ematch_hdr *hdr;
+		struct rtnl_ematch *ematch;
+		void *data;
+		size_t len;
+
+		NL_DBG(3, "parsing ematch attribute %d, len=%u\n",
+			  nmatches+1, nla_len(a));
+
+		if (nla_len(a) < sizeof(*hdr)) {
+			err = -NLE_INVAL;
+			goto errout;
+		}
+
+		/* Quit as soon as we've parsed more matches than expected */
+		if (nmatches >= thdr->nmatches) {
+			err = -NLE_RANGE;
+			goto errout;
+		}
+
+		hdr = nla_data(a);
+		data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
+		len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
+
+		NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n",
+			  hdr->matchid, hdr->kind, hdr->flags);
+
+		/*
+		 * Container matches contain a reference to another sequence
+		 * of matches. Ensure that the reference is within boundries.
+		 */
+		if (hdr->kind == TCF_EM_CONTAINER &&
+		    *((uint32_t *) data) >= thdr->nmatches) {
+			err = -NLE_INVAL;
+			goto errout;
+		}
+
+		if (!(ematch = rtnl_ematch_alloc())) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+
+		ematch->e_id = hdr->matchid;
+		ematch->e_kind = hdr->kind;
+		ematch->e_flags = hdr->flags;
+
+		if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) {
+			if (ops->eo_minlen && len < ops->eo_minlen) {
+				rtnl_ematch_free(ematch);
+				err = -NLE_INVAL;
+				goto errout;
+			}
+
+			rtnl_ematch_set_ops(ematch, ops);
+
+			if (ops->eo_parse &&
+			    (err = ops->eo_parse(ematch, data, len)) < 0) {
+				rtnl_ematch_free(ematch);
+				goto errout;
+			}
+		}
+
+		NL_DBG(3, "index[%d] = %p\n", nmatches, ematch);
+		index[nmatches++] = ematch;
+	}
+
+	if (nmatches != thdr->nmatches) {
+		err = -NLE_INVAL;
+		goto errout;
+	}
+
+	err = link_tree(index, nmatches, 0, &tree->et_list);
+	if (err < 0)
+		goto errout;
+
+	free(index);
+	*result = tree;
+
+	return 0;
+
+errout:
+	rtnl_ematch_tree_free(tree);
+	free(index);
+	return err;
+}
+
+static void dump_ematch_sequence(struct nl_list_head *head,
+				 struct nl_dump_params *p)
+{
+	struct rtnl_ematch *match;
+
+	nl_list_for_each_entry(match, head, e_list) {
+		if (match->e_flags & TCF_EM_INVERT)
+			nl_dump(p, "!");
+
+		if (match->e_kind == TCF_EM_CONTAINER) {
+			nl_dump(p, "(");
+			dump_ematch_sequence(&match->e_childs, p);
+			nl_dump(p, ")");
+		} else if (!match->e_ops) {
+			nl_dump(p, "[unknown ematch %d]", match->e_kind);
+		} else {
+			if (match->e_ops->eo_dump)
+				match->e_ops->eo_dump(match, p);
+			else
+				nl_dump(p, "[data]");
+		}
+
+		switch (match->e_flags & TCF_EM_REL_MASK) {
+		case TCF_EM_REL_AND:
+			nl_dump(p, " AND ");
+			break;
+		case TCF_EM_REL_OR:
+			nl_dump(p, " OR ");
+			break;
+		default:
+			/* end of first level ematch sequence */
+			return;
+		}
+	}
+}
+
+void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
+			   struct nl_dump_params *p)
+{
+	if (!tree)
+		BUG();
+
+	dump_ematch_sequence(&tree->et_list, p);
+	nl_dump(p, "\n");
+}
+
+static int update_container_index(struct nl_list_head *list, int *index)
+{
+	struct rtnl_ematch *e;
+
+	nl_list_for_each_entry(e, list, e_list)
+		e->e_index = (*index)++;
+
+	nl_list_for_each_entry(e, list, e_list) {
+		if (e->e_kind == TCF_EM_CONTAINER) {
+			int err;
+
+			if (nl_list_empty(&e->e_childs))
+				return -NLE_OBJ_NOTFOUND;
+
+			*((uint32_t *) e->e_data) = *index;
+
+			err = update_container_index(&e->e_childs, index);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list)
+{
+	struct rtnl_ematch *e;
+
+	nl_list_for_each_entry(e, list, e_list) {
+		struct tcf_ematch_hdr match = {
+			.matchid = e->e_id,
+			.kind = e->e_kind,
+			.flags = e->e_flags,
+		};
+		struct nlattr *attr;
+		int err = 0;
+
+		if (!(attr = nla_nest_start(msg, e->e_index + 1)))
+			return -NLE_NOMEM;
+
+		if (nlmsg_append(msg, &match, sizeof(match), 0) < 0)
+			return -NLE_NOMEM;
+
+		if (e->e_ops->eo_fill)
+			err = e->e_ops->eo_fill(e, msg);
+		else if (e->e_flags & TCF_EM_SIMPLE)
+			err = nlmsg_append(msg, e->e_data, 4, 0);
+		else if (e->e_datalen > 0)
+			err = nlmsg_append(msg, e->e_data, e->e_datalen, 0);
+
+		NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
+			  msg, e->e_index, match.matchid, match.kind, match.flags);
+
+		if (err < 0)
+			return -NLE_NOMEM;
+
+		nla_nest_end(msg, attr);
+	}
+
+	nl_list_for_each_entry(e, list, e_list) {
+		if (e->e_kind == TCF_EM_CONTAINER &&
+		    fill_ematch_sequence(msg, &e->e_childs) < 0)
+			return -NLE_NOMEM;
+	}
+
+	return 0;
+}
+
+int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid,
+			  struct rtnl_ematch_tree *tree)
+{
+	struct tcf_ematch_tree_hdr thdr = {
+		.progid = tree->et_progid,
+	};
+	struct nlattr *list, *topattr;
+	int err, index = 0;
+
+	/* Assign index number to each ematch to allow for references
+	 * to be made while constructing the sequence of matches. */
+	err = update_container_index(&tree->et_list, &index);
+	if (err < 0)
+		return err;
+
+	if (!(topattr = nla_nest_start(msg, attrid)))
+		goto nla_put_failure;
+
+	thdr.nmatches = index;
+	NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr);
+
+	if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST)))
+		goto nla_put_failure;
+
+	if (fill_ematch_sequence(msg, &tree->et_list) < 0)
+		goto nla_put_failure;
+
+	nla_nest_end(msg, list);
+
+	nla_nest_end(msg, topattr);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_NOMEM;
+}
+
+/** @} */
+
+extern int ematch_parse(void *, char **, struct nl_list_head *);
+
+int rtnl_ematch_parse_expr(const char *expr, char **errp,
+			   struct rtnl_ematch_tree **result)
+{
+	struct rtnl_ematch_tree *tree;
+	YY_BUFFER_STATE buf = NULL;
+	yyscan_t scanner = NULL;
+	int err;
+
+	NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr);
+
+	if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID)))
+		return -NLE_FAILURE;
+
+	if ((err = ematch_lex_init(&scanner)) < 0) {
+		err = -NLE_FAILURE;
+		goto errout;
+	}
+
+	buf = ematch__scan_string(expr, scanner);
+
+	if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) {
+		ematch__delete_buffer(buf, scanner);
+		err = -NLE_PARSE_ERR;
+		goto errout;
+	}
+
+	if (scanner)
+		ematch_lex_destroy(scanner);
+
+	*result = tree;
+
+	return 0;
+
+errout:
+	if (scanner)
+		ematch_lex_destroy(scanner);
+
+	rtnl_ematch_tree_free(tree);
+
+	return err;
+}
+
+static const char *layer_txt[] = {
+	[TCF_LAYER_LINK]	= "eth",
+	[TCF_LAYER_NETWORK]	= "ip",
+	[TCF_LAYER_TRANSPORT]	= "tcp",
+};
+
+char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
+{
+	snprintf(buf, len, "%s+%u",
+		 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
+		 offset);
+
+	return buf;
+}
+
+static const char *operand_txt[] = {
+	[TCF_EM_OPND_EQ] = "=",
+	[TCF_EM_OPND_LT] = "<",
+	[TCF_EM_OPND_GT] = ">",
+};
+
+char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
+{
+	snprintf(buf, len, "%s",
+		opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");
+
+	return buf;
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/.dirstamp b/libnetwork/libnl3/lib/route/cls/ematch/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/cmp.c b/libnetwork/libnl3/lib/route/cls/ematch/cmp.c
new file mode 100644
index 0000000..2a1070a
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch/cmp.c
@@ -0,0 +1,93 @@
+/*
+ * lib/route/cls/ematch/cmp.c	Simple packet data comparison ematch
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_cmp Simple packet data comparison
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+void rtnl_ematch_cmp_set(struct rtnl_ematch *e, struct tcf_em_cmp *cfg)
+{
+	memcpy(rtnl_ematch_data(e), cfg, sizeof(*cfg));
+}
+
+struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *e)
+{
+	return rtnl_ematch_data(e);
+}
+
+static int cmp_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+	memcpy(rtnl_ematch_data(e), data, len);
+
+	return 0;
+}
+
+static const char *align_txt[] = {
+	[TCF_EM_ALIGN_U8] = "u8",
+	[TCF_EM_ALIGN_U16] = "u16",
+	[TCF_EM_ALIGN_U32] = "u32"
+};
+
+static const char *layer_txt[] = {
+	[TCF_LAYER_LINK] = "eth",
+	[TCF_LAYER_NETWORK] = "ip",
+	[TCF_LAYER_TRANSPORT] = "tcp"
+};
+
+static const char *operand_txt[] = {
+	[TCF_EM_OPND_EQ] = "=",
+	[TCF_EM_OPND_LT] = "<",
+	[TCF_EM_OPND_GT] = ">",
+};
+
+static void cmp_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+	struct tcf_em_cmp *cmp = rtnl_ematch_data(e);
+
+	if (cmp->flags & TCF_EM_CMP_TRANS)
+		nl_dump(p, "ntoh%c(", (cmp->align == TCF_EM_ALIGN_U32) ? 'l' : 's');
+
+	nl_dump(p, "%s at %s+%u",
+		align_txt[cmp->align], layer_txt[cmp->layer], cmp->off);
+
+	if (cmp->mask)
+		nl_dump(p, " & 0x%x", cmp->mask);
+
+	if (cmp->flags & TCF_EM_CMP_TRANS)
+		nl_dump(p, ")");
+
+	nl_dump(p, " %s %u", operand_txt[cmp->opnd], cmp->val);
+}
+
+static struct rtnl_ematch_ops cmp_ops = {
+	.eo_kind	= TCF_EM_CMP,
+	.eo_name	= "cmp",
+	.eo_minlen	= sizeof(struct tcf_em_cmp),
+	.eo_datalen	= sizeof(struct tcf_em_cmp),
+	.eo_parse	= cmp_parse,
+	.eo_dump	= cmp_dump,
+};
+
+static void __init cmp_init(void)
+{
+	rtnl_ematch_register(&cmp_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/container.c b/libnetwork/libnl3/lib/route/cls/ematch/container.c
new file mode 100644
index 0000000..ddbdce0
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch/container.c
@@ -0,0 +1,41 @@
+/*
+ * lib/route/cls/ematch/container.c	Container Ematch
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+
+static int container_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+	memcpy(e->e_data, data, sizeof(uint32_t));
+
+	return 0;
+}
+
+static int container_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+	return nlmsg_append(msg, e->e_data, sizeof(uint32_t), 0);
+}
+
+static struct rtnl_ematch_ops container_ops = {
+	.eo_kind	= TCF_EM_CONTAINER,
+	.eo_name	= "container",
+	.eo_minlen	= sizeof(uint32_t),
+	.eo_datalen	= sizeof(uint32_t),
+	.eo_parse	= container_parse,
+	.eo_fill	= container_fill,
+};
+
+static void __init container_init(void)
+{
+	rtnl_ematch_register(&container_ops);
+}
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/meta.c b/libnetwork/libnl3/lib/route/cls/ematch/meta.c
new file mode 100644
index 0000000..11f87d6
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch/meta.c
@@ -0,0 +1,334 @@
+/*
+ * lib/route/cls/ematch/meta.c		Metadata Match
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_meta Metadata Match
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+struct rtnl_meta_value
+{
+	uint8_t			mv_type;
+	uint8_t			mv_shift;
+	uint16_t		mv_id;
+	size_t			mv_len;
+};
+
+struct meta_data
+{
+	struct rtnl_meta_value *	left;
+	struct rtnl_meta_value *	right;
+	uint8_t				opnd;
+};
+
+static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id,
+					  uint8_t shift, void *data,
+					  size_t len)
+{
+	struct rtnl_meta_value *value;
+
+	if (!(value = calloc(1, sizeof(*value) + len)))
+		return NULL;
+
+	value->mv_type = type;
+	value->mv_id = id;
+	value->mv_shift = shift;
+	value->mv_len = len;
+
+	memcpy(value + 1, data, len);
+
+	return value;
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_int(uint64_t value)
+{
+	return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_var(void *data, size_t len)
+{
+	return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t id,
+						 uint8_t shift, uint64_t mask)
+{
+	size_t masklen = 0;
+
+	if (id > TCF_META_ID_MAX)
+		return NULL;
+
+	if (mask) {
+		if (type == TCF_META_TYPE_VAR)
+			return NULL;
+
+		masklen = 8;
+	}
+
+	return meta_alloc(type, id, shift, &mask, masklen);
+}
+
+void rtnl_meta_value_put(struct rtnl_meta_value *mv)
+{
+	free(mv);
+}
+
+void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	m->left = v;
+}
+
+void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	m->right = v;
+}
+
+void rtnl_ematch_meta_set_operand(struct rtnl_ematch *e, uint8_t opnd)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	m->opnd = opnd;
+}
+
+static struct nla_policy meta_policy[TCA_EM_META_MAX+1] = {
+	[TCA_EM_META_HDR]	= { .minlen = sizeof(struct tcf_meta_hdr) },
+	[TCA_EM_META_LVALUE]	= { .minlen = 1, },
+	[TCA_EM_META_RVALUE]	= { .minlen = 1, },
+};
+
+static int meta_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	struct nlattr *tb[TCA_EM_META_MAX+1];
+	struct rtnl_meta_value *v;
+	struct tcf_meta_hdr *hdr;
+	void *vdata = NULL;
+	size_t vlen = 0;
+	int err;
+
+	if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0)
+		return err;
+
+	if (!tb[TCA_EM_META_HDR])
+		return -NLE_MISSING_ATTR;
+
+	hdr = nla_data(tb[TCA_EM_META_HDR]);
+
+	if (tb[TCA_EM_META_LVALUE]) {
+		vdata = nla_data(tb[TCA_EM_META_LVALUE]);
+		vlen = nla_len(tb[TCA_EM_META_LVALUE]);
+	}
+
+	v = meta_alloc(TCF_META_TYPE(hdr->left.kind),
+		       TCF_META_ID(hdr->left.kind),
+		       hdr->left.shift, vdata, vlen);
+	if (!v)
+		return -NLE_NOMEM;
+
+	m->left = v;
+
+	vlen = 0;
+	if (tb[TCA_EM_META_RVALUE]) {
+		vdata = nla_data(tb[TCA_EM_META_RVALUE]);
+		vlen = nla_len(tb[TCA_EM_META_RVALUE]);
+	}
+
+	v = meta_alloc(TCF_META_TYPE(hdr->right.kind),
+		       TCF_META_ID(hdr->right.kind),
+		       hdr->right.shift, vdata, vlen);
+	if (!v) {
+		rtnl_meta_value_put(m->left);
+		return -NLE_NOMEM;
+	}
+
+	m->right = v;
+	m->opnd = hdr->left.op;
+
+	return 0;
+}
+
+static const struct trans_tbl meta_int[] = {
+	__ADD(TCF_META_ID_RANDOM, random)
+	__ADD(TCF_META_ID_LOADAVG_0, loadavg_0)
+	__ADD(TCF_META_ID_LOADAVG_1, loadavg_1)
+	__ADD(TCF_META_ID_LOADAVG_2, loadavg_2)
+	__ADD(TCF_META_ID_DEV, dev)
+	__ADD(TCF_META_ID_PRIORITY, prio)
+	__ADD(TCF_META_ID_PROTOCOL, proto)
+	__ADD(TCF_META_ID_PKTTYPE, pkttype)
+	__ADD(TCF_META_ID_PKTLEN, pktlen)
+	__ADD(TCF_META_ID_DATALEN, datalen)
+	__ADD(TCF_META_ID_MACLEN, maclen)
+	__ADD(TCF_META_ID_NFMARK, mark)
+	__ADD(TCF_META_ID_TCINDEX, tcindex)
+	__ADD(TCF_META_ID_RTCLASSID, rtclassid)
+	__ADD(TCF_META_ID_RTIIF, rtiif)
+	__ADD(TCF_META_ID_SK_FAMILY, sk_family)
+	__ADD(TCF_META_ID_SK_STATE, sk_state)
+	__ADD(TCF_META_ID_SK_REUSE, sk_reuse)
+	__ADD(TCF_META_ID_SK_REFCNT, sk_refcnt)
+	__ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf)
+	__ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf)
+	__ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown)
+	__ADD(TCF_META_ID_SK_PROTO, sk_proto)
+	__ADD(TCF_META_ID_SK_TYPE, sk_type)
+	__ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc)
+	__ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc)
+	__ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued)
+	__ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen)
+	__ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen)
+	__ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen)
+	__ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs)
+	__ADD(TCF_META_ID_SK_ALLOCS, sk_allocs)
+	__ADD(TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps)
+	__ADD(TCF_META_ID_SK_HASH, sk_hash)
+	__ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime)
+	__ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog)
+	__ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog)
+	__ADD(TCF_META_ID_SK_PRIO, sk_prio)
+	__ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat)
+	__ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo)
+	__ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo)
+	__ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off)
+	__ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending)
+	__ADD(TCF_META_ID_VLAN_TAG, vlan)
+	__ADD(TCF_META_ID_RXHASH, rxhash)
+};
+
+static char *int_id2str(int id, char *buf, size_t size)
+{
+	return __type2str(id, buf, size, meta_int, ARRAY_SIZE(meta_int));
+}
+
+static const struct trans_tbl meta_var[] = {
+	__ADD(TCF_META_ID_DEV,devname)
+	__ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if)
+};
+
+static char *var_id2str(int id, char *buf, size_t size)
+{
+	return __type2str(id, buf, size, meta_var, ARRAY_SIZE(meta_var));
+}
+
+static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p)
+{
+	char buf[32];
+
+	switch (v->mv_type) {
+		case TCF_META_TYPE_INT:
+			if (v->mv_id == TCF_META_ID_VALUE) {
+				nl_dump(p, "%u",
+					*(uint32_t *) (v + 1));
+			} else {
+				nl_dump(p, "%s",
+					int_id2str(v->mv_id, buf, sizeof(buf)));
+
+				if (v->mv_shift)
+					nl_dump(p, " >> %u", v->mv_shift);
+
+				if (v->mv_len == 4)
+					nl_dump(p, " & %#x", *(uint32_t *) (v + 1));
+				else if (v->mv_len == 8)
+					nl_dump(p, " & %#x", *(uint64_t *) (v + 1));
+			}
+		break;
+
+		case TCF_META_TYPE_VAR:
+			if (v->mv_id == TCF_META_ID_VALUE) {
+				nl_dump(p, "%s", (char *) (v + 1));
+			} else {
+				nl_dump(p, "%s",
+					var_id2str(v->mv_id, buf, sizeof(buf)));
+
+				if (v->mv_shift)
+					nl_dump(p, " >> %u", v->mv_shift);
+			}
+		break;
+	}
+}
+
+static void meta_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	char buf[32];
+
+	nl_dump(p, "meta(");
+	dump_value(m->left, p);
+
+	nl_dump(p, " %s ", rtnl_ematch_opnd2txt(m->opnd, buf, sizeof(buf)));
+
+	dump_value(m->right, p);
+	nl_dump(p, ")");
+}
+
+static int meta_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	struct tcf_meta_hdr hdr;
+
+	if (!(m->left && m->right))
+		return -NLE_MISSING_ATTR;
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.left.kind = (m->left->mv_type << 12) & TCF_META_TYPE_MASK;
+	hdr.left.kind |= m->left->mv_id & TCF_META_ID_MASK;
+	hdr.left.shift = m->left->mv_shift;
+	hdr.left.op = m->opnd;
+	hdr.right.kind = (m->right->mv_type << 12) & TCF_META_TYPE_MASK;
+	hdr.right.kind |= m->right->mv_id & TCF_META_ID_MASK;
+
+	NLA_PUT(msg, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+
+	if (m->left->mv_len)
+		NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1));
+	
+	if (m->right->mv_len)
+		NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1));
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_NOMEM;
+}
+
+static void meta_free(struct rtnl_ematch *e)
+{
+	struct meta_data *m = rtnl_ematch_data(e);
+	free(m->left);
+	free(m->right);
+}
+
+static struct rtnl_ematch_ops meta_ops = {
+	.eo_kind	= TCF_EM_META,
+	.eo_name	= "meta",
+	.eo_minlen	= sizeof(struct tcf_meta_hdr),
+	.eo_datalen	= sizeof(struct meta_data),
+	.eo_parse	= meta_parse,
+	.eo_dump	= meta_dump,
+	.eo_fill	= meta_fill,
+	.eo_free	= meta_free,
+};
+
+static void __init meta_init(void)
+{
+	rtnl_ematch_register(&meta_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c b/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c
new file mode 100644
index 0000000..25a9866
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c
@@ -0,0 +1,139 @@
+/*
+ * lib/route/cls/ematch/nbyte.c		Nbyte comparison
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_nbyte N-Byte Comparison
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/nbyte.h>
+
+struct nbyte_data
+{
+	struct tcf_em_nbyte	cfg;
+	uint8_t *		pattern;
+};
+
+void rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *e, uint8_t layer,
+				  uint16_t offset)
+{
+	struct nbyte_data *n = rtnl_ematch_data(e);
+	n->cfg.off = offset;
+	n->cfg.layer = layer;
+}
+
+uint16_t rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *e)
+{
+	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.off;
+}
+
+uint8_t rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *e)
+{
+	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.layer;
+}
+
+void rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *e,
+				   uint8_t *pattern, size_t len)
+{
+	struct nbyte_data *n = rtnl_ematch_data(e);
+
+	if (n->pattern)
+		free(n->pattern);
+
+	n->pattern = pattern;
+	n->cfg.len = len;
+}
+
+uint8_t *rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *e)
+{
+	return ((struct nbyte_data *) rtnl_ematch_data(e))->pattern;
+}
+
+size_t rtnl_ematch_nbyte_get_len(struct rtnl_ematch *e)
+{
+	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.len;
+}
+
+static const char *layer_txt(struct tcf_em_nbyte *nbyte)
+{
+	switch (nbyte->layer) {
+	case TCF_LAYER_LINK:
+		return "link";
+	case TCF_LAYER_NETWORK:
+		return "net";
+	case TCF_LAYER_TRANSPORT:
+		return "trans";
+	default:
+		return "?";
+	}
+}
+
+static int nbyte_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+	struct nbyte_data *n = rtnl_ematch_data(e);
+	size_t hdrlen = sizeof(struct tcf_em_nbyte);
+	size_t plen = len - hdrlen;
+
+	memcpy(&n->cfg, data, hdrlen);
+	if (plen > 0) {
+		if (!(n->pattern = calloc(1, plen)))
+			return -NLE_NOMEM;
+
+		memcpy(n->pattern, data + hdrlen, plen);
+	}
+
+	return 0;
+}
+
+static void nbyte_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+	struct nbyte_data *n = rtnl_ematch_data(e);
+	int i;
+
+	nl_dump(p, "pattern(%u:[", n->cfg.len);
+
+	for (i = 0; i < n->cfg.len; i++) {
+		nl_dump(p, "%02x", n->pattern[i]);
+		if (i+1 < n->cfg.len)
+			nl_dump(p, " ");
+	}
+
+	nl_dump(p, "] at %s+%u)", layer_txt(&n->cfg), n->cfg.off);
+}
+
+static void nbyte_free(struct rtnl_ematch *e)
+{
+	struct nbyte_data *n = rtnl_ematch_data(e);
+	free(n->pattern);
+}
+
+static struct rtnl_ematch_ops nbyte_ops = {
+	.eo_kind	= TCF_EM_NBYTE,
+	.eo_name	= "nbyte",
+	.eo_minlen	= sizeof(struct tcf_em_nbyte),
+	.eo_datalen	= sizeof(struct nbyte_data),
+	.eo_parse	= nbyte_parse,
+	.eo_dump	= nbyte_dump,
+	.eo_free	= nbyte_free,
+};
+
+static void __init nbyte_init(void)
+{
+	rtnl_ematch_register(&nbyte_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch/text.c b/libnetwork/libnl3/lib/route/cls/ematch/text.c
new file mode 100644
index 0000000..9d0241e
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch/text.c
@@ -0,0 +1,183 @@
+/*
+ * lib/route/cls/ematch/text.c		Text Search
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_text Text Search
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/text.h>
+
+struct text_data
+{
+	struct tcf_em_text	cfg;
+	char *			pattern;
+};
+
+void rtnl_ematch_text_set_from(struct rtnl_ematch *e, uint8_t layer,
+			       uint16_t offset)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	t->cfg.from_offset = offset;
+	t->cfg.from_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_from_offset(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_offset;
+}
+
+uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_layer;
+}
+
+void rtnl_ematch_text_set_to(struct rtnl_ematch *e, uint8_t layer,
+			       uint16_t offset)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	t->cfg.to_offset = offset;
+	t->cfg.to_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_to_offset(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_offset;
+}
+
+uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_layer;
+}
+
+void rtnl_ematch_text_set_pattern(struct rtnl_ematch *e,
+				  char *pattern, size_t len)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+
+	if (t->pattern)
+		free(t->pattern);
+
+	t->pattern = pattern;
+	t->cfg.pattern_len = len;
+}
+
+char *rtnl_ematch_text_get_pattern(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->pattern;
+}
+
+size_t rtnl_ematch_text_get_len(struct rtnl_ematch *e)
+{
+	return ((struct text_data *) rtnl_ematch_data(e))->cfg.pattern_len;
+}
+
+void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+
+	strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo));
+}
+
+char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+
+	return t->cfg.algo[0] ? t->cfg.algo : NULL;
+}
+
+static int text_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	size_t hdrlen = sizeof(struct tcf_em_text);
+	size_t plen = len - hdrlen;
+
+	memcpy(&t->cfg, data, hdrlen);
+
+	if (t->cfg.pattern_len > plen)
+		return -NLE_INVAL;
+
+	if (t->cfg.pattern_len > 0) {
+		if (!(t->pattern = calloc(1, t->cfg.pattern_len)))
+			return -NLE_NOMEM;
+
+		memcpy(t->pattern, data + hdrlen, t->cfg.pattern_len);
+	}
+
+	return 0;
+}
+
+static void text_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	char buf[64];
+
+	nl_dump(p, "text(%s \"%s\"",
+		t->cfg.algo[0] ? t->cfg.algo : "no-algo",
+		t->pattern ? : "no-pattern");
+
+	if (t->cfg.from_layer || t->cfg.from_offset) {
+		nl_dump(p, " from %s",
+			rtnl_ematch_offset2txt(t->cfg.from_layer,
+					       t->cfg.from_offset,
+					       buf, sizeof(buf)));
+	}
+
+	if (t->cfg.to_layer || t->cfg.to_offset) {
+		nl_dump(p, " to %s",
+			rtnl_ematch_offset2txt(t->cfg.to_layer,
+					       t->cfg.to_offset,
+					       buf, sizeof(buf)));
+	}
+
+	nl_dump(p, ")");
+}
+
+static int text_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	int err;
+
+	if ((err = nlmsg_append(msg, &t->cfg, sizeof(t->cfg), 0)) < 0)
+		return err;
+
+	return nlmsg_append(msg, t->pattern, t->cfg.pattern_len, 0);
+}
+
+static void text_free(struct rtnl_ematch *e)
+{
+	struct text_data *t = rtnl_ematch_data(e);
+	free(t->pattern);
+}
+
+static struct rtnl_ematch_ops text_ops = {
+	.eo_kind	= TCF_EM_TEXT,
+	.eo_name	= "text",
+	.eo_minlen	= sizeof(struct tcf_em_text),
+	.eo_datalen	= sizeof(struct text_data),
+	.eo_parse	= text_parse,
+	.eo_dump	= text_dump,
+	.eo_fill	= text_fill,
+	.eo_free	= text_free,
+};
+
+static void __init text_init(void)
+{
+	rtnl_ematch_register(&text_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/ematch_grammar.l b/libnetwork/libnl3/lib/route/cls/ematch_grammar.l
new file mode 100644
index 0000000..07e7e8c
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch_grammar.l
@@ -0,0 +1,162 @@
+/*
+ * lib/route/cls/ematch_grammar.l	ematch expression grammar
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+%{
+ #include <netlink-local.h>
+ #include <netlink-tc.h>
+ #include <netlink/netlink.h>
+ #include <netlink/route/cls/ematch.h>
+ #include <netlink/route/cls/ematch/cmp.h>
+ #include "ematch_syntax.h"
+%}
+
+%option 8bit
+%option reentrant
+%option warn
+%option noyywrap
+%option noinput
+%option nounput
+%option bison-bridge
+%option prefix="ematch_"
+
+%x QUOTE
+
+%%
+
+[ \t\r\n]+
+
+\"			{
+				NL_DBG(4, "Beginning of quote\n");
+				yylval->q.len = 32;
+				if (!(yylval->q.data = calloc(1, yylval->q.len)))
+					return ERROR;
+
+				yylval->q.index = 0;
+				BEGIN(QUOTE);
+			}
+
+<QUOTE>[^\\\n\"]+	{
+				memcpy(yylval->q.data + yylval->q.index, yytext,
+				       strlen(yytext));
+				yylval->q.index += strlen(yytext);
+			}
+
+<QUOTE>\"		{
+				BEGIN(0);
+				return QUOTED;
+			}
+
+
+[[:digit:]]+		|
+0[xX][[:xdigit:]]+	{
+				yylval->i = strtoul(yytext, NULL, 0);
+				return NUMBER;
+			}
+
+eq			|
+"="			return KW_EQ;
+gt			|
+">"			return KW_GT;
+lt			|
+"<"			return KW_LT;
+
+[aA][nN][dD]		|
+"&&"			{ yylval->i = TCF_EM_REL_AND; return LOGIC; }
+[oO][rR]		|
+"||"			{ yylval->i = TCF_EM_REL_OR; return LOGIC; }
+[nN][oO][tT]		|
+"!"			return NOT;
+
+[cC][mM][pP]		{ yylval->i = TCF_EM_CMP; return EMATCH_CMP; }
+[pP][aA][tT][tT][eE][rR][nN] { yylval->i = TCF_EM_NBYTE; return EMATCH_NBYTE; }
+[tT][eE][xX][tT]	{ yylval->i = TCF_EM_TEXT; return EMATCH_TEXT; }
+[mM][eE][tT][aA]	{ yylval->i = TCF_EM_META; return EMATCH_META; }
+
+"("			return KW_OPEN;
+")"			return KW_CLOSE;
+[mM][aA][sS][kK]	|
+"&"			return KW_MASK;
+[sS][hH][iI][fF][tT]	|
+">>"			return KW_SHIFT;
+[aA][tT]		return KW_AT;
+"+"			return KW_PLUS;
+[fF][rR][oO][mM]	return KW_FROM;
+[tT][oO]		return KW_TO;
+
+[uU]8			{ yylval->i = TCF_EM_ALIGN_U8; return ALIGN; }
+[uU]16			{ yylval->i = TCF_EM_ALIGN_U16; return ALIGN; }
+[uU]32			{ yylval->i = TCF_EM_ALIGN_U32; return ALIGN; }
+
+[lL][iI][nN][kK]	|
+[eE][tT][hH]		{ yylval->i = TCF_LAYER_LINK; return LAYER; }
+[nN][eE][tT]		|
+[iI][pP]6		|
+[iI][pP]		{ yylval->i = TCF_LAYER_NETWORK; return LAYER; }
+[tT][rR][aA][nN][sS][pP][oO][rR][tT] |
+[tT][cC][pP]		{ yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+
+random			return META_RANDOM;
+loadavg_0		return META_LOADAVG_0;
+loadavg_1		return META_LOADAVG_1;
+loadavg_2		return META_LOADAVG_2;
+dev			return META_DEV;
+prio			return META_PRIO;
+proto			return META_PROTO;
+pkttype			return META_PKTTYPE;
+pktlen			return META_PKTLEN;
+datalen			return META_DATALEN;
+maclen			return META_MACLEN;
+mark			return META_MARK;
+tcindex			return META_TCINDEX;
+rtclassid		return META_RTCLASSID;
+rtiif			return META_RTIIF;
+sk_family		return META_SK_FAMILY;
+sk_state		return META_SK_STATE;
+sk_reuse		return META_SK_REUSE;
+sk_refcnt		return META_SK_REFCNT;
+sk_rcvbuf		return META_SK_RCVBUF;
+sk_sndbuf		return META_SK_SNDBUF;
+sk_shutdown		return META_SK_SHUTDOWN;
+sk_proto		return META_SK_PROTO;
+sk_type			return META_SK_TYPE;
+sk_rmem_alloc		return META_SK_RMEM_ALLOC;
+sk_wmem_alloc		return META_SK_WMEM_ALLOC;
+sk_wmem_queued		return META_SK_WMEM_QUEUED;
+sk_rcv_qlen		return META_SK_RCV_QLEN;
+sk_snd_qlen		return META_SK_SND_QLEN;
+sk_err_qlen		return META_SK_ERR_QLEN;
+sk_forward_allocs	return META_SK_FORWARD_ALLOCS;
+sk_allocs		return META_SK_ALLOCS;
+sk_route_caps		return META_SK_ROUTE_CAPS;
+sk_hash			return META_SK_HASH;
+sk_lingertime		return META_SK_LINGERTIME;
+sk_ack_backlog		return META_SK_ACK_BACKLOG;
+sk_max_ack_backlog	return META_SK_MAX_ACK_BACKLOG;
+sk_prio			return META_SK_PRIO;
+sk_rcvlowat		return META_SK_RCVLOWAT;
+sk_rcvtimeo		return META_SK_RCVTIMEO;
+sk_sndtimeo		return META_SK_SNDTIMEO;
+sk_sendmsg_off		return META_SK_SENDMSG_OFF;
+sk_write_pending	return META_SK_WRITE_PENDING;
+vlan			return META_VLAN;
+rxhash			return META_RXHASH;
+
+devname			return META_DEVNAME;
+sk_bound_if		return META_SK_BOUND_IF;
+
+
+[^ \t\r\n+()=<>&|\"]+	{
+				yylval->s = strdup(yytext);
+				if (yylval->s == NULL)
+					return ERROR;
+				NL_DBG(4, "lex STR=%s\n", yylval->s);
+				return STR;
+			}
diff --git a/libnetwork/libnl3/lib/route/cls/ematch_syntax.y b/libnetwork/libnl3/lib/route/cls/ematch_syntax.y
new file mode 100644
index 0000000..61c91d1
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/ematch_syntax.y
@@ -0,0 +1,497 @@
+/*
+ * lib/route/cls/ematch_syntax.y	ematch expression syntax
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+%{
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
+#include <netlink/route/cls/ematch/nbyte.h>
+#include <netlink/route/cls/ematch/text.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+#define META_ALLOC rtnl_meta_value_alloc_id
+#define META_ID(name) TCF_META_ID_##name
+#define META_INT TCF_META_TYPE_INT
+#define META_VAR TCF_META_TYPE_VAR
+%}
+
+%error-verbose
+%define api.pure
+%name-prefix "ematch_"
+
+%parse-param {void *scanner}
+%parse-param {char **errp}
+%parse-param {struct nl_list_head *root}
+%lex-param {void *scanner}
+
+%union {
+	struct tcf_em_cmp	cmp;
+	struct ematch_quoted	q;
+	struct rtnl_ematch *	e;
+	struct rtnl_pktloc *	loc;
+	struct rtnl_meta_value *mv;
+	uint32_t		i;
+	uint64_t		i64;
+	char *			s;
+}
+
+%{
+extern int ematch_lex(YYSTYPE *, void *);
+
+static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg)
+{
+	if (msg)
+		asprintf(errp, "%s", msg);
+}
+%}
+
+%token <i> ERROR LOGIC NOT OPERAND NUMBER ALIGN LAYER
+%token <i> KW_OPEN "("
+%token <i> KW_CLOSE ")"
+%token <i> KW_PLUS "+"
+%token <i> KW_MASK "mask"
+%token <i> KW_SHIFT ">>"
+%token <i> KW_AT "at"
+%token <i> EMATCH_CMP "cmp"
+%token <i> EMATCH_NBYTE "pattern"
+%token <i> EMATCH_TEXT "text"
+%token <i> EMATCH_META "meta"
+%token <i> KW_EQ "="
+%token <i> KW_GT ">"
+%token <i> KW_LT "<"
+%token <i> KW_FROM "from"
+%token <i> KW_TO "to"
+
+%token <i> META_RANDOM "random"
+%token <i> META_LOADAVG_0 "loadavg_0"
+%token <i> META_LOADAVG_1 "loadavg_1"
+%token <i> META_LOADAVG_2 "loadavg_2"
+%token <i> META_DEV "dev"
+%token <i> META_PRIO "prio"
+%token <i> META_PROTO "proto"
+%token <i> META_PKTTYPE "pkttype"
+%token <i> META_PKTLEN "pktlen"
+%token <i> META_DATALEN "datalen"
+%token <i> META_MACLEN "maclen"
+%token <i> META_MARK "mark"
+%token <i> META_TCINDEX "tcindex"
+%token <i> META_RTCLASSID "rtclassid"
+%token <i> META_RTIIF "rtiif"
+%token <i> META_SK_FAMILY "sk_family"
+%token <i> META_SK_STATE "sk_state"
+%token <i> META_SK_REUSE "sk_reuse"
+%token <i> META_SK_REFCNT "sk_refcnt"
+%token <i> META_SK_RCVBUF "sk_rcvbuf"
+%token <i> META_SK_SNDBUF "sk_sndbuf"
+%token <i> META_SK_SHUTDOWN "sk_shutdown"
+%token <i> META_SK_PROTO "sk_proto"
+%token <i> META_SK_TYPE "sk_type"
+%token <i> META_SK_RMEM_ALLOC "sk_rmem_alloc"
+%token <i> META_SK_WMEM_ALLOC "sk_wmem_alloc"
+%token <i> META_SK_WMEM_QUEUED "sk_wmem_queued"
+%token <i> META_SK_RCV_QLEN "sk_rcv_qlen"
+%token <i> META_SK_SND_QLEN "sk_snd_qlen"
+%token <i> META_SK_ERR_QLEN "sk_err_qlen"
+%token <i> META_SK_FORWARD_ALLOCS "sk_forward_allocs"
+%token <i> META_SK_ALLOCS "sk_allocs"
+%token <i> META_SK_ROUTE_CAPS "sk_route_caps"
+%token <i> META_SK_HASH "sk_hash"
+%token <i> META_SK_LINGERTIME "sk_lingertime"
+%token <i> META_SK_ACK_BACKLOG "sk_ack_backlog"
+%token <i> META_SK_MAX_ACK_BACKLOG "sk_max_ack_backlog"
+%token <i> META_SK_PRIO "sk_prio"
+%token <i> META_SK_RCVLOWAT "sk_rcvlowat"
+%token <i> META_SK_RCVTIMEO "sk_rcvtimeo"
+%token <i> META_SK_SNDTIMEO "sk_sndtimeo"
+%token <i> META_SK_SENDMSG_OFF "sk_sendmsg_off"
+%token <i> META_SK_WRITE_PENDING "sk_write_pending"
+%token <i> META_VLAN "vlan"
+%token <i> META_RXHASH "rxhash"
+%token <i> META_DEVNAME "devname"
+%token <i> META_SK_BOUND_IF "sk_bound_if"
+
+%token <s> STR
+
+%token <q> QUOTED
+
+%type <i> align operand shift meta_int_id meta_var_id
+%type <i64> mask
+%type <e> expr match ematch
+%type <cmp> cmp_expr cmp_match
+%type <loc> pktloc text_from text_to
+%type <q> pattern
+%type <mv> meta_value
+
+%destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
+%destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } <loc>
+%destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } <q>
+%destructor { rtnl_meta_value_put($$); NL_DBG(2, "meta value destructor\n"); } <mv>
+
+%start input
+
+%%
+
+input:
+	/* empty */
+	| expr
+		{
+			nl_list_add_tail(root, &$1->e_list);
+		}
+	;
+
+expr:
+	match
+		{
+			$$ = $1;
+		}
+	| match LOGIC expr
+		{
+			rtnl_ematch_set_flags($1, $2);
+
+			/* make ematch new head */
+			nl_list_add_tail(&$1->e_list, &$3->e_list);
+
+			$$ = $1;
+		}
+	;
+
+match:
+	NOT ematch
+		{
+			rtnl_ematch_set_flags($2, TCF_EM_INVERT);
+			$$ = $2;
+		}
+	| ematch
+		{
+			$$ = $1;
+		}
+	;
+
+ematch:
+	/* CMP */
+	cmp_match
+		{
+			struct rtnl_ematch *e;
+
+			if (!(e = rtnl_ematch_alloc())) {
+				asprintf(errp, "Unable to allocate ematch object");
+				YYABORT;
+			}
+
+			if (rtnl_ematch_set_kind(e, TCF_EM_CMP) < 0)
+				BUG();
+
+			rtnl_ematch_cmp_set(e, &$1);
+			$$ = e;
+		}
+	| EMATCH_NBYTE "(" pktloc KW_EQ pattern ")"
+		{
+			struct rtnl_ematch *e;
+
+			if (!(e = rtnl_ematch_alloc())) {
+				asprintf(errp, "Unable to allocate ematch object");
+				YYABORT;
+			}
+
+			if (rtnl_ematch_set_kind(e, TCF_EM_NBYTE) < 0)
+				BUG();
+
+			rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset);
+			rtnl_pktloc_put($3);
+			rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index);
+
+			$$ = e;
+		}
+	| EMATCH_TEXT "(" STR QUOTED text_from text_to ")"
+		{
+			struct rtnl_ematch *e;
+
+			if (!(e = rtnl_ematch_alloc())) {
+				asprintf(errp, "Unable to allocate ematch object");
+				YYABORT;
+			}
+
+			if (rtnl_ematch_set_kind(e, TCF_EM_TEXT) < 0)
+				BUG();
+
+			rtnl_ematch_text_set_algo(e, $3);
+			rtnl_ematch_text_set_pattern(e, $4.data, $4.index);
+
+			if ($5) {
+				rtnl_ematch_text_set_from(e, $5->layer, $5->offset);
+				rtnl_pktloc_put($5);
+			}
+
+			if ($6) {
+				rtnl_ematch_text_set_to(e, $6->layer, $6->offset);
+				rtnl_pktloc_put($6);
+			}
+
+			$$ = e;
+		}
+	| EMATCH_META "(" meta_value operand meta_value ")"
+		{
+			struct rtnl_ematch *e;
+
+			if (!(e = rtnl_ematch_alloc())) {
+				asprintf(errp, "Unable to allocate ematch object");
+				YYABORT;
+			}
+
+			if (rtnl_ematch_set_kind(e, TCF_EM_META) < 0)
+				BUG();
+
+			rtnl_ematch_meta_set_lvalue(e, $3);
+			rtnl_ematch_meta_set_rvalue(e, $5);
+			rtnl_ematch_meta_set_operand(e, $4);
+
+			$$ = e;
+		}
+	/* CONTAINER */
+	| "(" expr ")"
+		{
+			struct rtnl_ematch *e;
+
+			if (!(e = rtnl_ematch_alloc())) {
+				asprintf(errp, "Unable to allocate ematch object");
+				YYABORT;
+			}
+
+			if (rtnl_ematch_set_kind(e, TCF_EM_CONTAINER) < 0)
+				BUG();
+
+			/* Make e->childs the list head of a the ematch sequence */
+			nl_list_add_tail(&e->e_childs, &$2->e_list);
+
+			$$ = e;
+		}
+	;
+
+/*
+ * CMP match
+ *
+ * match  := cmp(expr) | expr
+ * expr   := pktloc (=|>|<) NUMBER
+ * pktloc := alias | definition
+ *
+ */
+cmp_match:
+	EMATCH_CMP "(" cmp_expr ")"
+		{ $$ = $3; }
+	| cmp_expr
+		{ $$ = $1; }
+	;
+
+cmp_expr:
+	pktloc operand NUMBER
+		{
+			if ($1->align == TCF_EM_ALIGN_U16 ||
+			    $1->align == TCF_EM_ALIGN_U32)
+				$$.flags = TCF_EM_CMP_TRANS;
+
+			memset(&$$, 0, sizeof($$));
+
+			$$.mask = $1->mask;
+			$$.off = $1->offset;
+			$$.align = $1->align;
+			$$.layer = $1->layer;
+			$$.opnd = $2;
+			$$.val = $3;
+
+			rtnl_pktloc_put($1);
+		}
+	;
+
+text_from:
+	/* empty */
+		{ $$ = NULL; }
+	| "from" pktloc
+		{ $$ = $2; }
+	;
+
+text_to:
+	/* empty */
+		{ $$ = NULL; }
+	| "to" pktloc
+		{ $$ = $2; }
+	;
+
+meta_value:
+	QUOTED
+		{ $$ = rtnl_meta_value_alloc_var($1.data, $1.len); }
+	| NUMBER
+		{ $$ = rtnl_meta_value_alloc_int($1); }
+	| meta_int_id shift mask
+		{ $$ = META_ALLOC(META_INT, $1, $2, $3); }
+	| meta_var_id shift
+		{ $$ = META_ALLOC(META_VAR, $1, $2, 0); }
+	;
+
+meta_int_id:
+	META_RANDOM			{ $$ = META_ID(RANDOM); }
+	|META_LOADAVG_0			{ $$ = META_ID(LOADAVG_0); }
+	|META_LOADAVG_1			{ $$ = META_ID(LOADAVG_1); }
+	|META_LOADAVG_2			{ $$ = META_ID(LOADAVG_2); }
+	| META_DEV			{ $$ = META_ID(DEV); }
+	| META_PRIO			{ $$ = META_ID(PRIORITY); }
+	| META_PROTO			{ $$ = META_ID(PROTOCOL); }
+	| META_PKTTYPE			{ $$ = META_ID(PKTTYPE); }
+	| META_PKTLEN			{ $$ = META_ID(PKTLEN); }
+	| META_DATALEN			{ $$ = META_ID(DATALEN); }
+	| META_MACLEN			{ $$ = META_ID(MACLEN); }
+	| META_MARK			{ $$ = META_ID(NFMARK); }
+	| META_TCINDEX			{ $$ = META_ID(TCINDEX); }
+	| META_RTCLASSID		{ $$ = META_ID(RTCLASSID); }
+	| META_RTIIF			{ $$ = META_ID(RTIIF); }
+	| META_SK_FAMILY		{ $$ = META_ID(SK_FAMILY); }
+	| META_SK_STATE			{ $$ = META_ID(SK_STATE); }
+	| META_SK_REUSE			{ $$ = META_ID(SK_REUSE); }
+	| META_SK_REFCNT		{ $$ = META_ID(SK_REFCNT); }
+	| META_SK_RCVBUF		{ $$ = META_ID(SK_RCVBUF); }
+	| META_SK_SNDBUF		{ $$ = META_ID(SK_SNDBUF); }
+	| META_SK_SHUTDOWN		{ $$ = META_ID(SK_SHUTDOWN); }
+	| META_SK_PROTO			{ $$ = META_ID(SK_PROTO); }
+	| META_SK_TYPE			{ $$ = META_ID(SK_TYPE); }
+	| META_SK_RMEM_ALLOC		{ $$ = META_ID(SK_RMEM_ALLOC); }
+	| META_SK_WMEM_ALLOC		{ $$ = META_ID(SK_WMEM_ALLOC); }
+	| META_SK_WMEM_QUEUED		{ $$ = META_ID(SK_WMEM_QUEUED); }
+	| META_SK_RCV_QLEN		{ $$ = META_ID(SK_RCV_QLEN); }
+	| META_SK_SND_QLEN		{ $$ = META_ID(SK_SND_QLEN); }
+	| META_SK_ERR_QLEN		{ $$ = META_ID(SK_ERR_QLEN); }
+	| META_SK_FORWARD_ALLOCS	{ $$ = META_ID(SK_FORWARD_ALLOCS); }
+	| META_SK_ALLOCS		{ $$ = META_ID(SK_ALLOCS); }
+	| META_SK_ROUTE_CAPS		{ $$ = META_ID(SK_ROUTE_CAPS); }
+	| META_SK_HASH			{ $$ = META_ID(SK_HASH); }
+	| META_SK_LINGERTIME		{ $$ = META_ID(SK_LINGERTIME); }
+	| META_SK_ACK_BACKLOG		{ $$ = META_ID(SK_ACK_BACKLOG); }
+	| META_SK_MAX_ACK_BACKLOG	{ $$ = META_ID(SK_MAX_ACK_BACKLOG); }
+	| META_SK_PRIO			{ $$ = META_ID(SK_PRIO); }
+	| META_SK_RCVLOWAT		{ $$ = META_ID(SK_RCVLOWAT); }
+	| META_SK_RCVTIMEO		{ $$ = META_ID(SK_RCVTIMEO); }
+	| META_SK_SNDTIMEO		{ $$ = META_ID(SK_SNDTIMEO); }
+	| META_SK_SENDMSG_OFF		{ $$ = META_ID(SK_SENDMSG_OFF); }
+	| META_SK_WRITE_PENDING		{ $$ = META_ID(SK_WRITE_PENDING); }
+	| META_VLAN			{ $$ = META_ID(VLAN_TAG); }
+	| META_RXHASH			{ $$ = META_ID(RXHASH); }
+	;
+
+meta_var_id:
+	META_DEVNAME		{ $$ = META_ID(DEV); }
+	| META_SK_BOUND_IF	{ $$ = META_ID(SK_BOUND_IF); }
+	;
+
+/*
+ * pattern
+ */
+pattern:
+	QUOTED
+		{
+			$$ = $1;
+		}
+	| STR
+		{
+			struct nl_addr *addr;
+
+			if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) {
+				$$.len = nl_addr_get_len(addr);
+
+				$$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8);
+
+				if (!($$.data = calloc(1, $$.len))) {
+					nl_addr_put(addr);
+					YYABORT;
+				}
+
+				memcpy($$.data, nl_addr_get_binary_addr(addr), $$.len);
+				nl_addr_put(addr);
+			} else {
+				asprintf(errp, "invalid pattern \"%s\"", $1);
+				YYABORT;
+			}
+		}
+	;
+
+/*
+ * packet location
+ */
+
+pktloc:
+	STR
+		{
+			struct rtnl_pktloc *loc;
+
+			if (rtnl_pktloc_lookup($1, &loc) < 0) {
+				asprintf(errp, "Packet location \"%s\" not found", $1);
+				YYABORT;
+			}
+
+			$$ = loc;
+		}
+	/* [u8|u16|u32|NUM at] LAYER + OFFSET [mask MASK] */
+	| align LAYER "+" NUMBER mask
+		{
+			struct rtnl_pktloc *loc;
+
+			if ($5 && (!$1 || $1 > TCF_EM_ALIGN_U32)) {
+				asprintf(errp, "mask only allowed for alignments u8|u16|u32");
+				YYABORT;
+			}
+
+			if (!(loc = rtnl_pktloc_alloc())) {
+				asprintf(errp, "Unable to allocate packet location object");
+				YYABORT;
+			}
+
+			loc->name = strdup("<USER-DEFINED>");
+			loc->align = $1;
+			loc->layer = $2;
+			loc->offset = $4;
+			loc->mask = $5;
+
+			$$ = loc;
+		}
+	;
+
+align:
+	/* empty */
+		{ $$ = 0; }
+	| ALIGN "at"
+		{ $$ = $1; }
+	| NUMBER "at"
+		{ $$ = $1; }
+	;
+
+mask:
+	/* empty */
+		{ $$ = 0; }
+	| KW_MASK NUMBER
+		{ $$ = $2; }
+	;
+
+shift:
+	/* empty */
+		{ $$ = 0; }
+	| KW_SHIFT NUMBER
+		{ $$ = $2; }
+	;
+
+operand:
+	KW_EQ
+		{ $$ = TCF_EM_OPND_EQ; }
+	| KW_GT
+		{ $$ = TCF_EM_OPND_GT; }
+	| KW_LT
+		{ $$ = TCF_EM_OPND_LT; }
+	;
diff --git a/libnetwork/libnl3/lib/route/cls/fw.c b/libnetwork/libnl3/lib/route/cls/fw.c
new file mode 100644
index 0000000..11c9c67
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/fw.c
@@ -0,0 +1,190 @@
+/*
+ * lib/route/cls/fw.c		fw classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2006 Petr Gotthard <petr.gotthard at siemens.com>
+ * Copyright (c) 2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_fw Firewall Classifier
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/fw.h>
+
+/** @cond SKIP */
+#define FW_ATTR_CLASSID      0x001
+#define FW_ATTR_ACTION       0x002
+#define FW_ATTR_POLICE       0x004
+#define FW_ATTR_INDEV        0x008
+/** @endcond */
+
+static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
+	[TCA_FW_CLASSID]	= { .type = NLA_U32 },
+	[TCA_FW_INDEV]		= { .type = NLA_STRING,
+				    .maxlen = IFNAMSIZ },
+};
+
+static int fw_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_FW_MAX + 1];
+	struct rtnl_fw *f = data;
+	int err;
+
+	err = tca_parse(tb, TCA_FW_MAX, tc, fw_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_FW_CLASSID]) {
+		f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
+		f->cf_mask |= FW_ATTR_CLASSID;
+	}
+
+	if (tb[TCA_FW_ACT]) {
+		f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]);
+		if (!f->cf_act)
+			return -NLE_NOMEM;
+		f->cf_mask |= FW_ATTR_ACTION;
+	}
+
+	if (tb[TCA_FW_POLICE]) {
+		f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]);
+		if (!f->cf_police)
+			return -NLE_NOMEM;
+		f->cf_mask |= FW_ATTR_POLICE;
+	}
+
+	if (tb[TCA_FW_INDEV]) {
+		nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ);
+		f->cf_mask |= FW_ATTR_INDEV;
+	}
+
+	return 0;
+}
+
+static void fw_free_data(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_fw *f = data;
+
+	nl_data_free(f->cf_act);
+	nl_data_free(f->cf_police);
+}
+
+static int fw_clone(void *_dst, void *_src)
+{
+	struct rtnl_fw *dst = _dst, *src = _src;
+
+	if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act)))
+		return -NLE_NOMEM;
+	
+	if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police)))
+		return -NLE_NOMEM;
+
+	return 0;
+}
+
+static void fw_dump_line(struct rtnl_tc *tc, void *data,
+			 struct nl_dump_params *p)
+{
+	struct rtnl_fw *f = data;
+
+	if (f && f->cf_mask & FW_ATTR_CLASSID) {
+		char buf[32];
+
+		nl_dump(p, " target %s",
+			rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
+	}
+}
+
+static void fw_dump_details(struct rtnl_tc *tc, void *data,
+			    struct nl_dump_params *p)
+{
+	struct rtnl_fw *f = data;
+
+	if (f && f->cf_mask & FW_ATTR_INDEV)
+		nl_dump(p, "indev %s ", f->cf_indev);
+}
+
+static int fw_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_fw *f = data;
+
+	if (!f)
+		return 0;
+
+	if (f->cf_mask & FW_ATTR_CLASSID)
+		NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid);
+
+	if (f->cf_mask & FW_ATTR_ACTION)
+		NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act);
+
+	if (f->cf_mask & FW_ATTR_POLICE)
+		NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police);
+
+	if (f->cf_mask & FW_ATTR_INDEV)
+		NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+	struct rtnl_fw *f;
+
+	if (!(f = rtnl_tc_data(TC_CAST(cls))))
+		return -NLE_NOMEM;
+	
+	f->cf_classid = classid;
+	f->cf_mask |= FW_ATTR_CLASSID;
+
+	return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops fw_ops = {
+	.to_kind		= "fw",
+	.to_type		= RTNL_TC_TYPE_CLS,
+	.to_size		= sizeof(struct rtnl_fw),
+	.to_msg_parser		= fw_msg_parser,
+	.to_msg_fill		= fw_msg_fill,
+	.to_free_data		= fw_free_data,
+	.to_clone		= fw_clone,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= fw_dump_line,
+	    [NL_DUMP_DETAILS]	= fw_dump_details,
+	},
+};
+
+static void __init fw_init(void)
+{
+	rtnl_tc_register(&fw_ops);
+}
+
+static void __exit fw_exit(void)
+{
+	rtnl_tc_unregister(&fw_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/police.c b/libnetwork/libnl3/lib/route/cls/police.c
new file mode 100644
index 0000000..d7ab26b
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/police.c
@@ -0,0 +1,66 @@
+/*
+ * lib/route/cls/police.c	Policer
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/police.h>
+
+/**
+ * @name Policer Type
+ * @{
+ */
+
+static const struct trans_tbl police_types[] = {
+	__ADD(TC_POLICE_UNSPEC,unspec)
+	__ADD(TC_POLICE_OK,ok)
+	__ADD(TC_POLICE_RECLASSIFY,reclassify)
+	__ADD(TC_POLICE_SHOT,shot)
+#ifdef TC_POLICE_PIPE
+	__ADD(TC_POLICE_PIPE,pipe)
+#endif
+};
+
+/**
+ * Transform a policer type number into a character string (Reentrant).
+ * @arg type		policer type
+ * @arg buf		destination buffer
+ * @arg len		buffer length
+ *
+ * Transforms a policer type number into a character string and stores
+ * it in the provided buffer.
+ *
+ * @return The destination buffer or the type encoded in hex if no match was found.
+ */
+char * nl_police2str(int type, char *buf, size_t len)
+{
+	return __type2str(type, buf, len, police_types,
+			  ARRAY_SIZE(police_types));
+}
+
+/**
+ * Transform a character string into a policer type number
+ * @arg name		policer type name
+ *
+ * Transform the provided character string specifying a policer
+ * type into the corresponding numeric value
+ *
+ * @return Policer type number or a negative value.
+ */
+int nl_str2police(const char *name)
+{
+	return __str2type(name, police_types, ARRAY_SIZE(police_types));
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/cls/u32.c b/libnetwork/libnl3/lib/route/cls/u32.c
new file mode 100644
index 0000000..2016460
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/cls/u32.c
@@ -0,0 +1,551 @@
+/*
+ * lib/route/cls/u32.c		u32 classifier
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard at siemens.com>
+ * Copyright (c) 2005-2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_u32 Universal 32-bit Classifier
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/u32.h>
+
+/** @cond SKIP */
+#define U32_ATTR_DIVISOR      0x001
+#define U32_ATTR_HASH         0x002
+#define U32_ATTR_CLASSID      0x004
+#define U32_ATTR_LINK         0x008
+#define U32_ATTR_PCNT         0x010
+#define U32_ATTR_SELECTOR     0x020
+#define U32_ATTR_ACTION       0x040
+#define U32_ATTR_POLICE       0x080
+#define U32_ATTR_INDEV        0x100
+/** @endcond */
+
+static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
+{
+	return (struct tc_u32_sel *) u->cu_selector->d_data;
+}
+
+static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
+{
+	if (!u->cu_selector)
+		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
+
+	return u32_selector(u);
+}
+
+static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
+	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
+	[TCA_U32_HASH]		= { .type = NLA_U32 },
+	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
+	[TCA_U32_LINK]		= { .type = NLA_U32 },
+	[TCA_U32_INDEV]		= { .type = NLA_STRING,
+				    .maxlen = IFNAMSIZ },
+	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
+	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
+};
+
+static int u32_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_u32 *u = data;
+	struct nlattr *tb[TCA_U32_MAX + 1];
+	int err;
+
+	err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_U32_DIVISOR]) {
+		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
+		u->cu_mask |= U32_ATTR_DIVISOR;
+	}
+
+	if (tb[TCA_U32_SEL]) {
+		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
+		if (!u->cu_selector)
+			goto errout_nomem;
+		u->cu_mask |= U32_ATTR_SELECTOR;
+	}
+
+	if (tb[TCA_U32_HASH]) {
+		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
+		u->cu_mask |= U32_ATTR_HASH;
+	}
+
+	if (tb[TCA_U32_CLASSID]) {
+		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
+		u->cu_mask |= U32_ATTR_CLASSID;
+	}
+
+	if (tb[TCA_U32_LINK]) {
+		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
+		u->cu_mask |= U32_ATTR_LINK;
+	}
+
+	if (tb[TCA_U32_ACT]) {
+		u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
+		if (!u->cu_act)
+			goto errout_nomem;
+		u->cu_mask |= U32_ATTR_ACTION;
+	}
+
+	if (tb[TCA_U32_POLICE]) {
+		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
+		if (!u->cu_police)
+			goto errout_nomem;
+		u->cu_mask |= U32_ATTR_POLICE;
+	}
+
+	if (tb[TCA_U32_PCNT]) {
+		struct tc_u32_sel *sel;
+		int pcnt_size;
+
+		if (!tb[TCA_U32_SEL]) {
+			err = -NLE_MISSING_ATTR;
+			goto errout;
+		}
+		
+		sel = u->cu_selector->d_data;
+		pcnt_size = sizeof(struct tc_u32_pcnt) +
+				(sel->nkeys * sizeof(uint64_t));
+		if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
+			err = -NLE_INVAL;
+			goto errout;
+		}
+
+		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
+		if (!u->cu_pcnt)
+			goto errout_nomem;
+		u->cu_mask |= U32_ATTR_PCNT;
+	}
+
+	if (tb[TCA_U32_INDEV]) {
+		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
+		u->cu_mask |= U32_ATTR_INDEV;
+	}
+
+	return 0;
+
+errout_nomem:
+	err = -NLE_NOMEM;
+errout:
+	return err;
+}
+
+static void u32_free_data(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_u32 *u = data;
+
+	nl_data_free(u->cu_selector);
+	nl_data_free(u->cu_act);
+	nl_data_free(u->cu_police);
+	nl_data_free(u->cu_pcnt);
+}
+
+static int u32_clone(void *_dst, void *_src)
+{
+	struct rtnl_u32 *dst = _dst, *src = _src;
+
+	if (src->cu_selector &&
+	    !(dst->cu_selector = nl_data_clone(src->cu_selector)))
+		return -NLE_NOMEM;
+
+	if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
+		return -NLE_NOMEM;
+
+	if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
+		return -NLE_NOMEM;
+
+	if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
+		return -NLE_NOMEM;
+
+	return 0;
+}
+
+static void u32_dump_line(struct rtnl_tc *tc, void *data,
+			  struct nl_dump_params *p)
+{
+	struct rtnl_u32 *u = data;
+	char buf[32];
+	
+	if (!u)
+		return;
+
+	if (u->cu_mask & U32_ATTR_DIVISOR)
+		nl_dump(p, " divisor %u", u->cu_divisor);
+	else if (u->cu_mask & U32_ATTR_CLASSID)
+		nl_dump(p, " target %s",
+			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
+}
+
+static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
+			   struct rtnl_u32 *u)
+{
+	int i;
+	struct tc_u32_key *key;
+
+	if (sel->hmask || sel->hoff) {
+		/* I guess this will never be used since the kernel only
+		 * exports the selector if no divisor is set but hash offset
+		 * and hash mask make only sense in hash filters with divisor
+		 * set */
+		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
+	}
+
+	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
+		nl_dump(p, " offset at %u", sel->off);
+
+		if (sel->flags & TC_U32_VAROFFSET)
+			nl_dump(p, " variable (at %u & 0x%x) >> %u",
+				sel->offoff, ntohs(sel->offmask), sel->offshift);
+	}
+
+	if (sel->flags) {
+		int flags = sel->flags;
+		nl_dump(p, " <");
+
+#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
+	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+
+		PRINT_FLAG(TERMINAL);
+		PRINT_FLAG(OFFSET);
+		PRINT_FLAG(VAROFFSET);
+		PRINT_FLAG(EAT);
+#undef PRINT_FLAG
+
+		nl_dump(p, ">");
+	}
+		
+	
+	for (i = 0; i < sel->nkeys; i++) {
+		key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
+
+		nl_dump(p, "\n");
+		nl_dump_line(p, "      match key at %s%u ",
+			key->offmask ? "nexthdr+" : "", key->off);
+
+		if (key->offmask)
+			nl_dump(p, "[0x%u] ", key->offmask);
+
+		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
+
+		if (p->dp_type == NL_DUMP_STATS &&
+		    (u->cu_mask & U32_ATTR_PCNT)) {
+			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
+			nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
+		}
+	}
+}
+
+static void u32_dump_details(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_u32 *u = data;
+	struct tc_u32_sel *s;
+
+	if (!u)
+		return;
+
+	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
+		nl_dump(p, "no-selector\n");
+		return;
+	}
+	
+	s = u->cu_selector->d_data;
+
+	nl_dump(p, "nkeys %u ", s->nkeys);
+
+	if (u->cu_mask & U32_ATTR_HASH)
+		nl_dump(p, "ht key 0x%x hash 0x%u",
+			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
+
+	if (u->cu_mask & U32_ATTR_LINK)
+		nl_dump(p, "link %u ", u->cu_link);
+
+	if (u->cu_mask & U32_ATTR_INDEV)
+		nl_dump(p, "indev %s ", u->cu_indev);
+
+	print_selector(p, s, u);
+	nl_dump(p, "\n");
+
+#if 0	
+#define U32_ATTR_ACTION       0x040
+#define U32_ATTR_POLICE       0x080
+
+	struct nl_data   act;
+	struct nl_data   police;
+#endif
+}
+
+static void u32_dump_stats(struct rtnl_tc *tc, void *data,
+			   struct nl_dump_params *p)
+{
+	struct rtnl_u32 *u = data;
+
+	if (!u)
+		return;
+
+	if (u->cu_mask & U32_ATTR_PCNT) {
+		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
+		nl_dump(p, "\n");
+		nl_dump_line(p, "    hit %8llu count %8llu\n",
+			     pc->rhit, pc->rcnt);
+	}
+}
+
+static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_u32 *u = data;
+
+	if (!u)
+		return 0;
+	
+	if (u->cu_mask & U32_ATTR_DIVISOR)
+		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
+
+	if (u->cu_mask & U32_ATTR_HASH)
+		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
+
+	if (u->cu_mask & U32_ATTR_CLASSID)
+		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
+
+	if (u->cu_mask & U32_ATTR_LINK)
+		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
+
+	if (u->cu_mask & U32_ATTR_SELECTOR)
+		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
+
+	if (u->cu_mask & U32_ATTR_ACTION)
+		NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
+
+	if (u->cu_mask & U32_ATTR_POLICE)
+		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
+
+	if (u->cu_mask & U32_ATTR_INDEV)
+		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
+			 int nodeid)
+{
+	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
+
+	rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
+}
+ 
+int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+	struct rtnl_u32 *u;
+
+	if (!(u = rtnl_tc_data(TC_CAST(cls))))
+		return -NLE_NOMEM;
+	
+	u->cu_classid = classid;
+	u->cu_mask |= U32_ATTR_CLASSID;
+
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Selector Modifications
+ * @{
+ */
+
+int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
+{
+	struct tc_u32_sel *sel;
+	struct rtnl_u32 *u;
+
+	if (!(u = rtnl_tc_data(TC_CAST(cls))))
+		return -NLE_NOMEM;
+
+	sel = u32_selector_alloc(u);
+	if (!sel)
+		return -NLE_NOMEM;
+
+	sel->flags |= flags;
+	u->cu_mask |= U32_ATTR_SELECTOR;
+
+	return 0;
+}
+
+/**
+ * Append new 32-bit key to the selector
+ *
+ * @arg cls	classifier to be modifier
+ * @arg val	value to be matched (network byte-order)
+ * @arg mask	mask to be applied before matching (network byte-order)
+ * @arg off	offset, in bytes, to start matching
+ * @arg offmask	offset mask
+ *
+ * General selectors define the pattern, mask and offset the pattern will be
+ * matched to the packet contents. Using the general selectors you can match
+ * virtually any single bit in the IP (or upper layer) header.
+ *
+*/
+int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
+		     int off, int offmask)
+{
+	struct tc_u32_sel *sel;
+	struct rtnl_u32 *u;
+	int err;
+
+	if (!(u = rtnl_tc_data(TC_CAST(cls))))
+		return -NLE_NOMEM;
+
+	sel = u32_selector_alloc(u);
+	if (!sel)
+		return -NLE_NOMEM;
+
+	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
+	if (err < 0)
+		return err;
+
+	/* the selector might have been moved by realloc */
+	sel = u32_selector(u);
+
+	sel->keys[sel->nkeys].mask = mask;
+	sel->keys[sel->nkeys].val = val & mask;
+	sel->keys[sel->nkeys].off = off;
+	sel->keys[sel->nkeys].offmask = offmask;
+	sel->nkeys++;
+	u->cu_mask |= U32_ATTR_SELECTOR;
+
+	return 0;
+}
+
+int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
+			   int off, int offmask)
+{
+	int shift = 24 - 8 * (off & 3);
+
+	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
+				htonl((uint32_t)mask << shift),
+				off & ~3, offmask);
+}
+
+/**
+ * Append new selector key to match a 16-bit number
+ *
+ * @arg cls	classifier to be modified
+ * @arg val	value to be matched (host byte-order)
+ * @arg mask	mask to be applied before matching (host byte-order)
+ * @arg off	offset, in bytes, to start matching
+ * @arg offmask	offset mask
+*/
+int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
+			    int off, int offmask)
+{
+	int shift = ((off & 3) == 0 ? 16 : 0);
+	if (off % 2)
+		return -NLE_INVAL;
+
+	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
+				htonl((uint32_t)mask << shift),
+				off & ~3, offmask);
+}
+
+/**
+ * Append new selector key to match a 32-bit number
+ *
+ * @arg cls	classifier to be modified
+ * @arg val	value to be matched (host byte-order)
+ * @arg mask	mask to be applied before matching (host byte-order)
+ * @arg off	offset, in bytes, to start matching
+ * @arg offmask	offset mask
+*/
+int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
+			    int off, int offmask)
+{
+	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
+				off & ~3, offmask);
+}
+
+int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
+			     uint8_t bitmask, int off, int offmask)
+{
+	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
+	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
+}
+
+int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
+			      uint8_t bitmask, int off, int offmask)
+{
+	int i, err;
+
+	for (i = 1; i <= 4; i++) {
+		if (32 * i - bitmask <= 0) {
+			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
+						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
+				return err;
+		}
+		else if (32 * i - bitmask < 32) {
+			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
+			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
+						htonl(mask), off+4*(i-1), offmask)) < 0)
+				return err;
+		}
+		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
+	}
+
+	return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops u32_ops = {
+	.to_kind		= "u32",
+	.to_type		= RTNL_TC_TYPE_CLS,
+	.to_size		= sizeof(struct rtnl_u32),
+	.to_msg_parser		= u32_msg_parser,
+	.to_free_data		= u32_free_data,
+	.to_clone		= u32_clone,
+	.to_msg_fill		= u32_msg_fill,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= u32_dump_line,
+	    [NL_DUMP_DETAILS]	= u32_dump_details,
+	    [NL_DUMP_STATS]	= u32_dump_stats,
+	},
+};
+
+static void __init u32_init(void)
+{
+	rtnl_tc_register(&u32_ops);
+}
+
+static void __exit u32_exit(void)
+{
+	rtnl_tc_unregister(&u32_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/link.c b/libnetwork/libnl3/lib/route/link.c
new file mode 100644
index 0000000..e486b3f
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link.c
@@ -0,0 +1,2342 @@
+/*
+ * lib/route/link.c	Links (Interfaces)
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup link Links (Interfaces)
+ *
+ * @details
+ * @route_doc{route_link, Link Documentation}
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/api.h>
+
+/** @cond SKIP */
+#define LINK_ATTR_MTU     0x0001
+#define LINK_ATTR_LINK    0x0002
+#define LINK_ATTR_TXQLEN  0x0004
+#define LINK_ATTR_WEIGHT  0x0008
+#define LINK_ATTR_MASTER  0x0010
+#define LINK_ATTR_QDISC   0x0020
+#define LINK_ATTR_MAP     0x0040
+#define LINK_ATTR_ADDR    0x0080
+#define LINK_ATTR_BRD     0x0100
+#define LINK_ATTR_FLAGS   0x0200
+#define LINK_ATTR_IFNAME  0x0400
+#define LINK_ATTR_IFINDEX 0x0800
+#define LINK_ATTR_FAMILY  0x1000
+#define LINK_ATTR_ARPTYPE 0x2000
+#define LINK_ATTR_STATS   0x4000
+#define LINK_ATTR_CHANGE  0x8000
+#define LINK_ATTR_OPERSTATE 0x10000
+#define LINK_ATTR_LINKMODE  0x20000
+#define LINK_ATTR_LINKINFO  0x40000
+#define LINK_ATTR_IFALIAS   0x80000
+#define LINK_ATTR_NUM_VF   0x100000
+
+static struct nl_cache_ops rtnl_link_ops;
+static struct nl_object_ops link_obj_ops;
+/** @endcond */
+
+static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
+						    int family)
+{
+	struct rtnl_link_af_ops *af_ops;
+	void *data;
+
+	af_ops = rtnl_link_af_ops_lookup(family);
+	if (!af_ops)
+		return NULL;
+
+	if (!(data = rtnl_link_af_alloc(link, af_ops)))
+		return NULL;
+
+	return af_ops;
+}
+
+static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+		    void *data, void *arg)
+{
+	if (ops->ao_free)
+		ops->ao_free(link, data);
+
+	rtnl_link_af_ops_put(ops);
+
+	return 0;
+}
+
+static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+		    void *data, void *arg)
+{
+	struct rtnl_link *dst = arg;
+
+	if (ops->ao_clone &&
+	    !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
+		return -NLE_NOMEM;
+
+	return 0;
+}
+
+static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+		   void *data, void *arg)
+{
+	struct nl_msg *msg = arg;
+	struct nlattr *af_attr;
+	int err;
+
+	if (!ops->ao_fill_af)
+		return 0;
+
+	if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
+		return -NLE_MSGSIZE;
+
+	if ((err = ops->ao_fill_af(link, arg, data)) < 0)
+		return err;
+
+	nla_nest_end(msg, af_attr);
+
+	return 0;
+}
+
+static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+			 void *data, void *arg)
+{
+	struct nl_dump_params *p = arg;
+
+	if (ops->ao_dump[NL_DUMP_LINE])
+		ops->ao_dump[NL_DUMP_LINE](link, p, data);
+
+	return 0;
+}
+
+static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+			   void *data, void *arg)
+{
+	struct nl_dump_params *p = arg;
+
+	if (ops->ao_dump[NL_DUMP_DETAILS])
+		ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
+
+	return 0;
+}
+
+static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+			 void *data, void *arg)
+{
+	struct nl_dump_params *p = arg;
+
+	if (ops->ao_dump[NL_DUMP_STATS])
+		ops->ao_dump[NL_DUMP_STATS](link, p, data);
+
+	return 0;
+}
+
+static int do_foreach_af(struct rtnl_link *link,
+			 int (*cb)(struct rtnl_link *,
+			 	   struct rtnl_link_af_ops *, void *, void *),
+			 void *arg)
+{
+	int i, err;
+
+	for (i = 0; i < AF_MAX; i++) {
+		if (link->l_af_data[i]) {
+			struct rtnl_link_af_ops *ops;
+
+			if (!(ops = rtnl_link_af_ops_lookup(i)))
+				BUG();
+
+			if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static void release_link_info(struct rtnl_link *link)
+{
+	struct rtnl_link_info_ops *io = link->l_info_ops;
+
+	if (io != NULL) {
+		if (io->io_free)
+			io->io_free(link);
+		rtnl_link_info_ops_put(io);
+		link->l_info_ops = NULL;
+	}
+}
+
+static void link_free_data(struct nl_object *c)
+{
+	struct rtnl_link *link = nl_object_priv(c);
+
+	if (link) {
+		struct rtnl_link_info_ops *io;
+
+		if ((io = link->l_info_ops) != NULL)
+			release_link_info(link);
+
+		nl_addr_put(link->l_addr);
+		nl_addr_put(link->l_bcast);
+
+		free(link->l_ifalias);
+
+		do_foreach_af(link, af_free, NULL);
+	}
+}
+
+static int link_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct rtnl_link *dst = nl_object_priv(_dst);
+	struct rtnl_link *src = nl_object_priv(_src);
+	int err;
+
+	if (src->l_addr)
+		if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
+			return -NLE_NOMEM;
+
+	if (src->l_bcast)
+		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
+			return -NLE_NOMEM;
+
+	if (src->l_ifalias)
+		if (!(dst->l_ifalias = strdup(src->l_ifalias)))
+			return -NLE_NOMEM;
+
+	if (src->l_info_ops && src->l_info_ops->io_clone) {
+		err = src->l_info_ops->io_clone(dst, src);
+		if (err < 0)
+			return err;
+	}
+
+	if ((err = do_foreach_af(src, af_clone, dst)) < 0)
+		return err;
+
+	return 0;
+}
+
+static struct nla_policy link_policy[IFLA_MAX+1] = {
+	[IFLA_IFNAME]	= { .type = NLA_STRING,
+			    .maxlen = IFNAMSIZ },
+	[IFLA_MTU]	= { .type = NLA_U32 },
+	[IFLA_TXQLEN]	= { .type = NLA_U32 },
+	[IFLA_LINK]	= { .type = NLA_U32 },
+	[IFLA_WEIGHT]	= { .type = NLA_U32 },
+	[IFLA_MASTER]	= { .type = NLA_U32 },
+	[IFLA_OPERSTATE]= { .type = NLA_U8 },
+	[IFLA_LINKMODE] = { .type = NLA_U8 },
+	[IFLA_LINKINFO]	= { .type = NLA_NESTED },
+	[IFLA_QDISC]	= { .type = NLA_STRING,
+			    .maxlen = IFQDISCSIZ },
+	[IFLA_STATS]	= { .minlen = sizeof(struct rtnl_link_stats) },
+	[IFLA_STATS64]	= { .minlen = sizeof(struct rtnl_link_stats64) },
+	[IFLA_MAP]	= { .minlen = sizeof(struct rtnl_link_ifmap) },
+	[IFLA_IFALIAS]	= { .type = NLA_STRING, .maxlen = IFALIASZ },
+	[IFLA_NUM_VF]	= { .type = NLA_U32 },
+	[IFLA_AF_SPEC]	= { .type = NLA_NESTED },
+};
+
+static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
+	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
+	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
+	[IFLA_INFO_XSTATS]	= { .type = NLA_NESTED },
+};
+
+static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			   struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+	struct rtnl_link *link;
+	struct ifinfomsg *ifi;
+	struct nlattr *tb[IFLA_MAX+1];
+	struct rtnl_link_af_ops *af_ops = NULL;
+	int err, family;
+
+	link = rtnl_link_alloc();
+	if (link == NULL) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+		
+	link->ce_msgtype = n->nlmsg_type;
+
+	if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
+		return -NLE_MSG_TOOSHORT;
+
+	ifi = nlmsg_data(n);
+	link->l_family = family = ifi->ifi_family;
+	link->l_arptype = ifi->ifi_type;
+	link->l_index = ifi->ifi_index;
+	link->l_flags = ifi->ifi_flags;
+	link->l_change = ifi->ifi_change;
+	link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
+			  LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
+			  LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
+
+	if ((af_ops = af_lookup_and_alloc(link, family))) {
+		if (af_ops->ao_protinfo_policy) {
+			memcpy(&link_policy[IFLA_PROTINFO],
+			       af_ops->ao_protinfo_policy,
+			       sizeof(struct nla_policy));
+		}
+	}
+
+	err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
+	if (err < 0)
+		goto errout;
+
+	if (tb[IFLA_IFNAME] == NULL) {
+		err = -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
+
+
+	if (tb[IFLA_STATS]) {
+		struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
+
+		link->l_stats[RTNL_LINK_RX_PACKETS]	= st->rx_packets;
+		link->l_stats[RTNL_LINK_TX_PACKETS]	= st->tx_packets;
+		link->l_stats[RTNL_LINK_RX_BYTES]	= st->rx_bytes;
+		link->l_stats[RTNL_LINK_TX_BYTES]	= st->tx_bytes;
+		link->l_stats[RTNL_LINK_RX_ERRORS]	= st->rx_errors;
+		link->l_stats[RTNL_LINK_TX_ERRORS]	= st->tx_errors;
+		link->l_stats[RTNL_LINK_RX_DROPPED]	= st->rx_dropped;
+		link->l_stats[RTNL_LINK_TX_DROPPED]	= st->tx_dropped;
+		link->l_stats[RTNL_LINK_MULTICAST]	= st->multicast;
+		link->l_stats[RTNL_LINK_COLLISIONS]	= st->collisions;
+
+		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st->rx_length_errors;
+		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st->rx_over_errors;
+		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st->rx_crc_errors;
+		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st->rx_frame_errors;
+		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st->rx_fifo_errors;
+		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st->rx_missed_errors;
+
+		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st->tx_aborted_errors;
+		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st->tx_carrier_errors;
+		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st->tx_fifo_errors;
+		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st->tx_heartbeat_errors;
+		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st->tx_window_errors;
+
+		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st->rx_compressed;
+		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st->tx_compressed;
+
+		link->ce_mask |= LINK_ATTR_STATS;
+	}
+
+	if (tb[IFLA_STATS64]) {
+		/*
+		 * This structure contains 64bit parameters, and per the
+		 * documentation in lib/attr.c, must not be accessed
+		 * directly (because of alignment to 4 instead of 8).
+		 * Therefore, copy the data to the stack and access it from
+		 * there, where it will be aligned to 8.
+		 */
+		struct rtnl_link_stats64 st;
+
+		nla_memcpy(&st, tb[IFLA_STATS64], 
+			   sizeof(struct rtnl_link_stats64));
+		
+		link->l_stats[RTNL_LINK_RX_PACKETS]	= st.rx_packets;
+		link->l_stats[RTNL_LINK_TX_PACKETS]	= st.tx_packets;
+		link->l_stats[RTNL_LINK_RX_BYTES]	= st.rx_bytes;
+		link->l_stats[RTNL_LINK_TX_BYTES]	= st.tx_bytes;
+		link->l_stats[RTNL_LINK_RX_ERRORS]	= st.rx_errors;
+		link->l_stats[RTNL_LINK_TX_ERRORS]	= st.tx_errors;
+		link->l_stats[RTNL_LINK_RX_DROPPED]	= st.rx_dropped;
+		link->l_stats[RTNL_LINK_TX_DROPPED]	= st.tx_dropped;
+		link->l_stats[RTNL_LINK_MULTICAST]	= st.multicast;
+		link->l_stats[RTNL_LINK_COLLISIONS]	= st.collisions;
+
+		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st.rx_length_errors;
+		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st.rx_over_errors;
+		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st.rx_crc_errors;
+		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st.rx_frame_errors;
+		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st.rx_fifo_errors;
+		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st.rx_missed_errors;
+
+		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st.tx_aborted_errors;
+		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st.tx_carrier_errors;
+		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st.tx_fifo_errors;
+		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st.tx_heartbeat_errors;
+		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st.tx_window_errors;
+
+		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st.rx_compressed;
+		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st.tx_compressed;
+
+		link->ce_mask |= LINK_ATTR_STATS;
+	}
+
+	if (tb[IFLA_TXQLEN]) {
+		link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
+		link->ce_mask |= LINK_ATTR_TXQLEN;
+	}
+
+	if (tb[IFLA_MTU]) {
+		link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
+		link->ce_mask |= LINK_ATTR_MTU;
+	}
+
+	if (tb[IFLA_ADDRESS]) {
+		link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
+		if (link->l_addr == NULL) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+		nl_addr_set_family(link->l_addr,
+				   nl_addr_guess_family(link->l_addr));
+		link->ce_mask |= LINK_ATTR_ADDR;
+	}
+
+	if (tb[IFLA_BROADCAST]) {
+		link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
+						   AF_UNSPEC);
+		if (link->l_bcast == NULL) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+		nl_addr_set_family(link->l_bcast,
+				   nl_addr_guess_family(link->l_bcast));
+		link->ce_mask |= LINK_ATTR_BRD;
+	}
+
+	if (tb[IFLA_LINK]) {
+		link->l_link = nla_get_u32(tb[IFLA_LINK]);
+		link->ce_mask |= LINK_ATTR_LINK;
+	}
+
+	if (tb[IFLA_WEIGHT]) {
+		link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
+		link->ce_mask |= LINK_ATTR_WEIGHT;
+	}
+
+	if (tb[IFLA_QDISC]) {
+		nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
+		link->ce_mask |= LINK_ATTR_QDISC;
+	}
+
+	if (tb[IFLA_MAP]) {
+		nla_memcpy(&link->l_map, tb[IFLA_MAP], 
+			   sizeof(struct rtnl_link_ifmap));
+		link->ce_mask |= LINK_ATTR_MAP;
+	}
+
+	if (tb[IFLA_MASTER]) {
+		link->l_master = nla_get_u32(tb[IFLA_MASTER]);
+		link->ce_mask |= LINK_ATTR_MASTER;
+	}
+
+	if (tb[IFLA_OPERSTATE]) {
+		link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
+		link->ce_mask |= LINK_ATTR_OPERSTATE;
+	}
+
+	if (tb[IFLA_LINKMODE]) {
+		link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
+		link->ce_mask |= LINK_ATTR_LINKMODE;
+	}
+
+	if (tb[IFLA_IFALIAS]) {
+		link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
+		if (link->l_ifalias == NULL) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+		link->ce_mask |= LINK_ATTR_IFALIAS;
+	}
+
+	if (tb[IFLA_NUM_VF]) {
+		link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
+		link->ce_mask |= LINK_ATTR_NUM_VF;
+	}
+
+	if (tb[IFLA_LINKINFO]) {
+		struct nlattr *li[IFLA_INFO_MAX+1];
+
+		err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
+				       link_info_policy);
+		if (err < 0)
+			goto errout;
+
+		if (li[IFLA_INFO_KIND]) {
+			struct rtnl_link_info_ops *ops;
+			char *kind;
+
+			kind = nla_get_string(li[IFLA_INFO_KIND]);
+			ops = rtnl_link_info_ops_lookup(kind);
+			link->l_info_ops = ops;
+			
+			if (ops && ops->io_parse &&
+			    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
+				err = ops->io_parse(link, li[IFLA_INFO_DATA],
+						    li[IFLA_INFO_XSTATS]);
+				if (err < 0)
+					goto errout;
+			} else {
+				/* XXX: Warn about unparsed info? */
+			}
+		}
+	}
+
+	if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
+		err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
+						link->l_af_data[link->l_family]);
+		if (err < 0)
+			goto errout;
+	}
+
+	if (tb[IFLA_AF_SPEC]) {
+		struct nlattr *af_attr;
+		int remaining;
+
+		nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
+			af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
+			if (af_ops && af_ops->ao_parse_af) {
+				char *af_data = link->l_af_data[nla_type(af_attr)];
+
+				err = af_ops->ao_parse_af(link, af_attr, af_data);
+
+				rtnl_link_af_ops_put(af_ops);
+
+				if (err < 0)
+					goto errout;
+			}
+
+		}
+	}
+
+	err = pp->pp_cb((struct nl_object *) link, pp);
+errout:
+	rtnl_link_af_ops_put(af_ops);
+	rtnl_link_put(link);
+	return err;
+}
+
+static int link_event_filter(struct nl_cache *cache, struct nl_object *obj)
+{
+	struct rtnl_link *link = (struct rtnl_link *) obj;
+
+	/*
+	 * Ignore bridging messages when keeping the cache manager up to date.
+	 */
+	if (link->l_family == AF_BRIDGE)
+		return NL_SKIP;
+
+	return NL_OK;
+}
+
+static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+	int family = cache->c_iarg1;
+
+	return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
+}
+
+static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+	char buf[128];
+	struct nl_cache *cache = dp_cache(obj);
+	struct rtnl_link *link = (struct rtnl_link *) obj;
+
+	nl_dump_line(p, "%s %s ", link->l_name,
+		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
+
+	if (link->l_addr && !nl_addr_iszero(link->l_addr))
+		nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
+
+	if (link->ce_mask & LINK_ATTR_MASTER) {
+		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
+		nl_dump(p, "master %s ", master ? master->l_name : "inv");
+		if (master)
+			rtnl_link_put(master);
+	}
+
+	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
+	if (buf[0])
+		nl_dump(p, "<%s> ", buf);
+
+	if (link->ce_mask & LINK_ATTR_LINK) {
+		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
+		nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
+		if (ll)
+			rtnl_link_put(ll);
+	}
+
+	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
+		link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
+
+	do_foreach_af(link, af_dump_line, p);
+
+	nl_dump(p, "\n");
+}
+
+static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_link *link = (struct rtnl_link *) obj;
+	char buf[64];
+
+	link_dump_line(obj, p);
+
+	nl_dump_line(p, "    mtu %u ", link->l_mtu);
+	nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
+
+	if (link->ce_mask & LINK_ATTR_QDISC)
+		nl_dump(p, "qdisc %s ", link->l_qdisc);
+
+	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
+		nl_dump(p, "irq %u ", link->l_map.lm_irq);
+
+	if (link->ce_mask & LINK_ATTR_IFINDEX)
+		nl_dump(p, "index %u ", link->l_index);
+
+
+	nl_dump(p, "\n");
+
+	if (link->ce_mask & LINK_ATTR_IFALIAS)
+		nl_dump_line(p, "    alias %s\n", link->l_ifalias);
+
+	nl_dump_line(p, "    ");
+
+	if (link->ce_mask & LINK_ATTR_BRD)
+		nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
+						   sizeof(buf)));
+
+	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
+	    link->l_operstate != IF_OPER_UNKNOWN) {
+		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
+		nl_dump(p, "state %s ", buf);
+	}
+
+	if (link->ce_mask & LINK_ATTR_NUM_VF)
+		nl_dump(p, "num-vf %u ", link->l_num_vf);
+
+	nl_dump(p, "mode %s\n",
+		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
+
+	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
+		link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
+
+	do_foreach_af(link, af_dump_details, p);
+}
+
+static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_link *link = (struct rtnl_link *) obj;
+	char *unit, fmt[64];
+	float res;
+	
+	link_dump_details(obj, p);
+
+	nl_dump_line(p, "    Stats:    bytes    packets     errors "
+			"   dropped   fifo-err compressed\n");
+
+	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
+
+	strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
+	fmt[9] = *unit == 'B' ? '9' : '7';
+	
+	nl_dump_line(p, fmt, res, unit,
+		link->l_stats[RTNL_LINK_RX_PACKETS],
+		link->l_stats[RTNL_LINK_RX_ERRORS],
+		link->l_stats[RTNL_LINK_RX_DROPPED],
+		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
+		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
+
+	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
+
+	strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
+	fmt[9] = *unit == 'B' ? '9' : '7';
+	
+	nl_dump_line(p, fmt, res, unit,
+		link->l_stats[RTNL_LINK_TX_PACKETS],
+		link->l_stats[RTNL_LINK_TX_ERRORS],
+		link->l_stats[RTNL_LINK_TX_DROPPED],
+		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
+		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
+
+	nl_dump_line(p, "    Errors:  length       over        crc "
+			"     frame     missed  multicast\n");
+
+	nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
+				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
+				PRIu64 "\n",
+		link->l_stats[RTNL_LINK_RX_LEN_ERR],
+		link->l_stats[RTNL_LINK_RX_OVER_ERR],
+		link->l_stats[RTNL_LINK_RX_CRC_ERR],
+		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
+		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
+		link->l_stats[RTNL_LINK_MULTICAST]);
+
+	nl_dump_line(p, "            aborted    carrier  heartbeat "
+			"    window  collision\n");
+	
+	nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
+			PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
+		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
+		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
+		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
+		link->l_stats[RTNL_LINK_TX_WIN_ERR],
+		link->l_stats[RTNL_LINK_COLLISIONS]);
+
+	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
+		link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
+
+	do_foreach_af(link, af_dump_stats, p);
+}
+
+#if 0
+static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
+{
+	struct rtnl_link *l = (struct rtnl_link *) a;
+	struct nl_cache *c = dp_cache(a);
+	int nevents = 0;
+
+	if (l->l_change == ~0U) {
+		if (l->ce_msgtype == RTM_NEWLINK)
+			cb->le_register(l);
+		else
+			cb->le_unregister(l);
+
+		return 1;
+	}
+
+	if (l->l_change & IFF_SLAVE) {
+		if (l->l_flags & IFF_SLAVE) {
+			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
+			cb->le_new_bonding(l, m);
+			if (m)
+				rtnl_link_put(m);
+		} else
+			cb->le_cancel_bonding(l);
+	}
+
+#if 0
+	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
+		dp_dump_line(p, line++, "link %s changed state to %s.\n",
+			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
+
+	if (l->l_change & IFF_PROMISC) {
+		dp_new_line(p, line++);
+		dp_dump(p, "link %s %s promiscuous mode.\n",
+		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
+	}
+
+	if (line == 0)
+		dp_dump_line(p, line++, "link %s sent unknown event.\n",
+			     l->l_name);
+#endif
+
+	return nevents;
+}
+#endif
+
+static int link_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_link *a = (struct rtnl_link *) _a;
+	struct rtnl_link *b = (struct rtnl_link *) _b;
+	int diff = 0;
+
+#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
+	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
+	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
+	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
+	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
+	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
+	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
+	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
+	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
+	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
+	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
+	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
+	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
+	diff |= LINK_DIFF(IFALIAS,	strcmp(a->l_ifalias, b->l_ifalias));
+	diff |= LINK_DIFF(NUM_VF,	a->l_num_vf != b->l_num_vf);
+
+	if (flags & LOOSE_COMPARISON)
+		diff |= LINK_DIFF(FLAGS,
+				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
+	else
+		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
+
+#undef LINK_DIFF
+
+	return diff;
+}
+
+static const struct trans_tbl link_attrs[] = {
+	__ADD(LINK_ATTR_MTU, mtu)
+	__ADD(LINK_ATTR_LINK, link)
+	__ADD(LINK_ATTR_TXQLEN, txqlen)
+	__ADD(LINK_ATTR_WEIGHT, weight)
+	__ADD(LINK_ATTR_MASTER, master)
+	__ADD(LINK_ATTR_QDISC, qdisc)
+	__ADD(LINK_ATTR_MAP, map)
+	__ADD(LINK_ATTR_ADDR, address)
+	__ADD(LINK_ATTR_BRD, broadcast)
+	__ADD(LINK_ATTR_FLAGS, flags)
+	__ADD(LINK_ATTR_IFNAME, name)
+	__ADD(LINK_ATTR_IFINDEX, ifindex)
+	__ADD(LINK_ATTR_FAMILY, family)
+	__ADD(LINK_ATTR_ARPTYPE, arptype)
+	__ADD(LINK_ATTR_STATS, stats)
+	__ADD(LINK_ATTR_CHANGE, change)
+	__ADD(LINK_ATTR_OPERSTATE, operstate)
+	__ADD(LINK_ATTR_LINKMODE, linkmode)
+	__ADD(LINK_ATTR_IFALIAS, ifalias)
+	__ADD(LINK_ATTR_NUM_VF, num_vf)
+};
+
+static char *link_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, link_attrs,
+			   ARRAY_SIZE(link_attrs));
+}
+
+/**
+ * @name Get / List
+ * @{
+ */
+
+
+/**
+ * Allocate link cache and fill in all configured links.
+ * @arg sk		Netlink socket.
+ * @arg family		Link address family or AF_UNSPEC
+ * @arg result		Pointer to store resulting cache.
+ *
+ * Allocates and initializes a new link cache. A netlink message is sent to
+ * the kernel requesting a full dump of all configured links. The returned
+ * messages are parsed and filled into the cache. If the operation succeeds
+ * the resulting cache will a link object for each link configured in the
+ * kernel.
+ *
+ * If \c family is set to an address family other than \c AF_UNSPEC the
+ * contents of the cache can be limited to a specific address family.
+ * Currently the following address families are supported:
+ * - AF_BRIDGE
+ * - AF_INET6
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get()
+ * @see rtnl_link_get_by_name()
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
+{
+	struct nl_cache * cache;
+	int err;
+	
+	cache = nl_cache_alloc(&rtnl_link_ops);
+	if (!cache)
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = family;
+	
+	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/**
+ * Lookup link in cache by interface index
+ * @arg cache		Link cache
+ * @arg ifindex		Interface index
+ *
+ * Searches through the provided cache looking for a link with matching
+ * interface index.
+ *
+ * @attention The reference counter of the returned link object will be
+ *            incremented. Use rtnl_link_put() to release the reference.
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get_by_name()
+ * @return Link object or NULL if no match was found.
+ */
+struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
+{
+	struct rtnl_link *link;
+
+	if (cache->c_ops != &rtnl_link_ops)
+		return NULL;
+
+	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
+		if (link->l_index == ifindex) {
+			nl_object_get((struct nl_object *) link);
+			return link;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Lookup link in cache by link name
+ * @arg cache		Link cache
+ * @arg name		Name of link
+ *
+ * Searches through the provided cache looking for a link with matching
+ * link name
+ *
+ * @attention The reference counter of the returned link object will be
+ *            incremented. Use rtnl_link_put() to release the reference.
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get()
+ * @return Link object or NULL if no match was found.
+ */
+struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
+					 const char *name)
+{
+	struct rtnl_link *link;
+
+	if (cache->c_ops != &rtnl_link_ops)
+		return NULL;
+
+	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
+		if (!strcmp(name, link->l_name)) {
+			nl_object_get((struct nl_object *) link);
+			return link;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Construct RTM_GETLINK netlink message
+ * @arg ifindex		Interface index
+ * @arg name		Name of link
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_get_kernel()
+ * with the exception that it will not send the message but return it in
+ * the provided return pointer instead.
+ *
+ * @see rtnl_link_get_kernel()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_get_request(int ifindex, const char *name,
+				struct nl_msg **result)
+{
+	struct ifinfomsg ifi;
+	struct nl_msg *msg;
+
+	if (ifindex <= 0 && !name) {
+		APPBUG("ifindex or name must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	memset(&ifi, 0, sizeof(ifi));
+
+	if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
+		return -NLE_NOMEM;
+
+	if (ifindex > 0)
+		ifi.ifi_index = ifindex;
+
+	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (name)
+		NLA_PUT_STRING(msg, IFLA_IFNAME, name);
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Get a link object directly from kernel
+ * @arg sk		Netlink socket
+ * @arg ifindex		Interface index
+ * @arg name		Name of link
+ * @arg result		Pointer to store resulting link object
+ *
+ * This function builds a \c RTM_GETLINK netlink message to request
+ * a specific link directly from the kernel. The returned answer is
+ * parsed into a struct rtnl_link object and returned via the result
+ * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
+ * found.
+ *
+ * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
+			 struct rtnl_link **result)
+{
+	struct nl_msg *msg = NULL;
+	struct nl_object *obj;
+	int err;
+
+	if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
+		return err;
+
+	/* We have used link_msg_parser(), object is definitely a link */
+	*result = (struct rtnl_link *) obj;
+
+	/* If an object has been returned, we also need to wait for the ACK */
+	 if (err == 0 && obj)
+		 nl_wait_for_ack(sk);
+
+	return 0;
+}
+
+/**
+ * Translate interface index to corresponding link name
+ * @arg cache		Link cache
+ * @arg ifindex		Interface index
+ * @arg dst		String to store name
+ * @arg len		Length of destination string
+ *
+ * Translates the specified interface index to the corresponding
+ * link name and stores the name in the destination string.
+ *
+ * @route_doc{link_translate_ifindex, Translating interface index to link name}
+ * @see rtnl_link_name2i()
+ * @return Name of link or NULL if no match was found.
+ */
+char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
+			size_t len)
+{
+	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
+
+	if (link) {
+		strncpy(dst, link->l_name, len - 1);
+		rtnl_link_put(link);
+		return dst;
+	}
+
+	return NULL;
+}
+
+/**
+ * Translate link name to corresponding interface index
+ * @arg cache		Link cache
+ * @arg name		Name of link
+ *
+ * @route_doc{link_translate_ifindex, Translating interface index to link name}
+ * @see rtnl_link_i2name()
+ * @return Interface index or 0 if no match was found.
+ */
+int rtnl_link_name2i(struct nl_cache *cache, const char *name)
+{
+	int ifindex = 0;
+	struct rtnl_link *link;
+	
+	link = rtnl_link_get_by_name(cache, name);
+	if (link) {
+		ifindex = link->l_index;
+		rtnl_link_put(link);
+	}
+
+	return ifindex;
+}
+
+/** @} */
+
+static int build_link_msg(int cmd, struct ifinfomsg *hdr,
+			  struct rtnl_link *link, int flags, struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct nlattr *af_spec;
+
+	msg = nlmsg_alloc_simple(cmd, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (link->ce_mask & LINK_ATTR_ADDR)
+		NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr);
+
+	if (link->ce_mask & LINK_ATTR_BRD)
+		NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast);
+
+	if (link->ce_mask & LINK_ATTR_MTU)
+		NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
+
+	if (link->ce_mask & LINK_ATTR_TXQLEN)
+		NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
+
+	if (link->ce_mask & LINK_ATTR_WEIGHT)
+		NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight);
+
+	if (link->ce_mask & LINK_ATTR_IFNAME)
+		NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
+
+	if (link->ce_mask & LINK_ATTR_OPERSTATE)
+		NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
+
+	if (link->ce_mask & LINK_ATTR_LINKMODE)
+		NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
+
+	if (link->ce_mask & LINK_ATTR_IFALIAS)
+		NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias);
+
+	if (link->ce_mask & LINK_ATTR_LINK)
+		NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
+
+	if (link->ce_mask & LINK_ATTR_MASTER)
+		NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
+
+	if ((link->ce_mask & LINK_ATTR_LINKINFO) && link->l_info_ops) {
+		struct nlattr *info;
+
+		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
+			goto nla_put_failure;
+
+		NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_ops->io_name);
+
+		if (link->l_info_ops->io_put_attrs &&
+		    link->l_info_ops->io_put_attrs(msg, link) < 0)
+			goto nla_put_failure;
+
+		nla_nest_end(msg, info);
+	}
+
+	if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
+		goto nla_put_failure;
+
+	if (do_foreach_af(link, af_fill, msg) < 0)
+		goto nla_put_failure;
+
+	nla_nest_end(msg, af_spec);
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Add / Modify
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the addition of new virtual link
+ * @arg link		new link to add
+ * @arg flags		additional netlink message flags
+ * @arg result		pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_add() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_add()
+ *
+ * @note This operation is not supported on all kernel versions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
+				struct nl_msg **result)
+{
+	struct ifinfomsg ifi = {
+		.ifi_family = link->l_family,
+		.ifi_index = link->l_index,
+		.ifi_flags = link->l_flags,
+	};
+
+	return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
+}
+
+/**
+ * Add virtual link
+ * @arg sk		netlink socket.
+ * @arg link		new link to add
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a \c RTM_NEWLINK netlink message requesting the addition of
+ * a new virtual link.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	err = rtnl_link_build_add_request(link, flags, &msg);
+	if (err < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build a netlink message requesting the modification of link
+ * @arg orig		original link to change
+ * @arg changes		link containing the changes to be made
+ * @arg flags		additional netlink message flags
+ * @arg result		pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_change() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_change()
+ *
+ * @note The resulting message will have message type set to RTM_NEWLINK
+ *       which may not work with older kernels. You may have to modify it
+ *       to RTM_SETLINK (does not allow changing link info attributes) to
+ *       have the change request work with older kernels.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_change_request(struct rtnl_link *orig,
+				   struct rtnl_link *changes, int flags,
+				   struct nl_msg **result)
+{
+	struct ifinfomsg ifi = {
+		.ifi_family = orig->l_family,
+		.ifi_index = orig->l_index,
+	};
+	int err;
+
+	if (changes->ce_mask & LINK_ATTR_FLAGS) {
+		ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
+		ifi.ifi_flags |= changes->l_flags;
+	}
+
+	if (changes->l_family && changes->l_family != orig->l_family) {
+		APPBUG("link change: family is immutable");
+		return -NLE_IMMUTABLE;
+	}
+
+	/* Avoid unnecessary name change requests */
+	if (orig->ce_mask & LINK_ATTR_IFINDEX &&
+	    orig->ce_mask & LINK_ATTR_IFNAME &&
+	    changes->ce_mask & LINK_ATTR_IFNAME &&
+	    !strcmp(orig->l_name, changes->l_name))
+		changes->ce_mask &= ~LINK_ATTR_IFNAME;
+
+	if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
+		goto errout;
+
+	return 0;
+
+errout:
+	return err;
+}
+
+/**
+ * Change link
+ * @arg sk		netlink socket.
+ * @arg orig		original link to be changed
+ * @arg changes		link containing the changes to be made
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a \c RTM_NEWLINK netlink message requesting the change of
+ * a network link. If -EOPNOTSUPP is returned by the kernel, the
+ * message type will be changed to \c RTM_SETLINK and the message is
+ * resent to work around older kernel versions.
+ *
+ * The link to be changed is looked up based on the interface index
+ * supplied in the \p orig link. Optionaly the link name is used but
+ * only if no interface index is provided, otherwise providing an
+ * link name will result in the link name being changed.
+ *
+ * If no matching link exists, the function will return
+ * -NLE_OBJ_NOTFOUND.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @note The link name can only be changed if the link has been put
+ *       in opertional down state. (~IF_UP)
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
+		     struct rtnl_link *changes, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	err = rtnl_link_build_change_request(orig, changes, flags, &msg);
+	if (err < 0)
+		return err;
+
+retry:
+	err = nl_send_auto_complete(sk, msg);
+	if (err < 0)
+		goto errout;
+
+	err = wait_for_ack(sk);
+	if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
+		msg->nm_nlh->nlmsg_type = RTM_SETLINK;
+		goto retry;
+	}
+
+errout:
+	nlmsg_free(msg);
+	return err;
+}
+
+/** @} */
+
+/**
+ * @name Delete
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the deletion of a link
+ * @arg link		Link to delete
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_delete_request(const struct rtnl_link *link,
+				   struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct ifinfomsg ifi = {
+		.ifi_index = link->l_index,
+	};
+
+	if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
+		APPBUG("ifindex or name must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (link->ce_mask & LINK_ATTR_IFNAME)
+		NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Delete link
+ * @arg sk		Netlink socket
+ * @arg link		Link to delete
+ *
+ * Builds a \c RTM_DELLINK netlink message requesting the deletion of
+ * a network link which has been previously added to the kernel and
+ * sends the message to the kernel.
+ *
+ * If no matching link exists, the function will return
+ * -NLE_OBJ_NOTFOUND.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @note Only virtual links such as dummy interface or vlan interfaces
+ *       can be deleted. It is not possible to delete physical interfaces
+ *       such as ethernet interfaces or the loopback device.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Link Object
+ * @{
+ */
+
+/**
+ * Allocate link object
+ *
+ * @see rtnl_link_put()
+ * @return New link object or NULL if allocation failed
+ */
+struct rtnl_link *rtnl_link_alloc(void)
+{
+	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
+}
+
+/**
+ * Return a link object reference
+ *
+ * @copydetails nl_object_put()
+ */
+void rtnl_link_put(struct rtnl_link *link)
+{
+	nl_object_put((struct nl_object *) link);
+}
+
+/**
+ * Set name of link object
+ * @arg link		Link object
+ * @arg name		New name
+ *
+ * @note To change the name of a link in the kernel, set the interface
+ *       index to the link you wish to change, modify the link name using
+ *       this function and pass the link object to rtnl_link_change() or
+ *       rtnl_link_add().
+ *
+ * @route_doc{link_attr_name, Link Name}
+ * @see rtnl_link_get_name()
+ * @see rtnl_link_set_ifindex()
+ */
+void rtnl_link_set_name(struct rtnl_link *link, const char *name)
+{
+	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
+	link->ce_mask |= LINK_ATTR_IFNAME;
+}
+
+/**
+ * Return name of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_name, Link Name}
+ * @see rtnl_link_set_name()
+ * @return Link name or NULL if name is not specified
+ */
+char *rtnl_link_get_name(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
+}
+
+static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
+				 struct nl_addr *new, int flag)
+{
+	if (*pos)
+		nl_addr_put(*pos);
+
+	nl_addr_get(new);
+	*pos = new;
+
+	link->ce_mask |= flag;
+}
+
+/**
+ * Set link layer address of link object
+ * @arg link		Link object
+ * @arg addr		New link layer address
+ *
+ * The function increments the reference counter of the address object
+ * and overwrites any existing link layer address previously assigned.
+ *
+ * @route_doc{link_attr_address, Link layer address}
+ * @see rtnl_link_get_addr()
+ */
+void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
+{
+	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
+}
+
+/**
+ * Return link layer address of link object
+ * @arg link		Link object
+ *
+ * @copydoc pointer_lifetime_warning
+ * @route_doc{link_attr_address, Link Layer Address}
+ * @see rtnl_link_set_addr()
+ * @return Link layer address or NULL if not set.
+ */
+struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
+}
+
+/**
+ * Set link layer broadcast address of link object
+ * @arg link		Link object
+ * @arg addr		New broadcast address
+ *
+ * The function increments the reference counter of the address object
+ * and overwrites any existing link layer broadcast address previously
+ * assigned.
+ *
+ * @route_doc{link_attr_broadcast, Link Layer Broadcast Address}
+ * @see rtnl_link_get_broadcast()
+ */
+void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr)
+{
+	__assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
+}
+
+/**
+ * Return link layer broadcast address of link object
+ * @arg link		Link object
+ *
+ * @copydoc pointer_lifetime_warning
+ * @route_doc{link_attr_address, Link Layer Address}
+ * @see rtnl_link_set_broadcast()
+ * @return Link layer address or NULL if not set.
+ */
+struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
+}
+
+/**
+ * Set flags of link object
+ * @arg link		Link object
+ * @arg flags		Flags
+ *
+ * @see rtnl_link_get_flags()
+ * @see rtnl_link_unset_flags()
+ */
+void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
+{
+	link->l_flag_mask |= flags;
+	link->l_flags |= flags;
+	link->ce_mask |= LINK_ATTR_FLAGS;
+}
+
+/**
+ * Unset flags of link object
+ * @arg link		Link object
+ * @arg flags		Flags
+ *
+ * @see rtnl_link_set_flags()
+ * @see rtnl_link_get_flags()
+ */
+void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
+{
+	link->l_flag_mask |= flags;
+	link->l_flags &= ~flags;
+	link->ce_mask |= LINK_ATTR_FLAGS;
+}
+
+/**
+ * Return flags of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_flags, Link Flags}
+ * @see rtnl_link_set_flags()
+ * @see rtnl_link_unset_flags()
+ * @return Link flags or 0 if none have been set.
+ */
+unsigned int rtnl_link_get_flags(struct rtnl_link *link)
+{
+	return link->l_flags;
+}
+
+/**
+ * Set address family of link object
+ *
+ * @see rtnl_link_get_family()
+ */
+void rtnl_link_set_family(struct rtnl_link *link, int family)
+{
+	link->l_family = family;
+	link->ce_mask |= LINK_ATTR_FAMILY;
+}
+
+/**
+ * Return address family of link object
+ * @arg link		Link object
+ *
+ * @see rtnl_link_set_family()
+ * @return Address family or \c AF_UNSPEC if not specified.
+ */
+int rtnl_link_get_family(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
+}
+
+/**
+ * Set hardware type of link object
+ * @arg link		Link object
+ * @arg arptype		New hardware type \c (ARPHRD_*)
+ *
+ * @route_doc{link_attr_arptype, Hardware Type}
+ * @copydoc read_only_attribute
+ * @see rtnl_link_get_arptype()
+ */
+void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
+{
+	link->l_arptype = arptype;
+	link->ce_mask |= LINK_ATTR_ARPTYPE;
+}
+
+/**
+ * Get hardware type of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_arptype, Hardware Type}
+ * @see rtnl_link_set_arptype()
+ * @return Hardware type \c (ARPHRD_ETHER *) or \c ARPHRD_VOID
+ */
+unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
+{
+	if (link->ce_mask & LINK_ATTR_ARPTYPE)
+		return link->l_arptype;
+	else
+		return ARPHRD_VOID;
+}
+
+/**
+ * Set interface index of link object
+ * @arg link		Link object
+ * @arg ifindex		Interface index
+ *
+ * @route_doc{link_attr_ifindex, Interface Index}
+ * @see rtnl_link_get_ifindex()
+ */
+void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
+{
+	link->l_index = ifindex;
+	link->ce_mask |= LINK_ATTR_IFINDEX;
+}
+
+
+/**
+ * Return interface index of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_ifindex, Interface Index}
+ * @see rtnl_link_set_ifindex()
+ * @return Interface index or 0 if not set.
+ */
+int rtnl_link_get_ifindex(struct rtnl_link *link)
+{
+	return link->l_index;
+}
+
+/**
+ * Set Maximum Transmission Unit of link object
+ * @arg link		Link object
+ * @arg mtu		New MTU value in number of bytes
+ *
+ * @route_doc{link_attr_mtu, Maximum Transmission Unit}
+ * @see rtnl_link_get_mtu()
+ */
+void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
+{
+	link->l_mtu = mtu;
+	link->ce_mask |= LINK_ATTR_MTU;
+}
+
+/**
+ * Return maximum transmission unit of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_mtu, Maximum Transmission Unit}
+ * @see rtnl_link_set_mtu()
+ * @return MTU in bytes or 0 if not set
+ */
+unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
+{
+	return link->l_mtu;
+}
+
+/**
+ * Set transmission queue length
+ * @arg link		Link object
+ * @arg txqlen		New queue length
+ *
+ * The unit is dependant on the link type. The most common units is number
+ * of packets.
+ *
+ * @route_doc{link_attr_txqlen, Transmission Queue Length}
+ */
+void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
+{
+	link->l_txqlen = txqlen;
+	link->ce_mask |= LINK_ATTR_TXQLEN;
+}
+
+/**
+ * Return transmission queue length
+ * @arg link		Link object
+ *
+ * The unit is dependant on the link type. The most common units is number
+ * of packets.
+ *
+ * @route_doc{link_attr_txqlen, Transmission Queue Length}
+ * @return queue length or 0 if not specified.
+ */
+unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
+}
+
+void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
+{
+	link->l_link = ifindex;
+	link->ce_mask |= LINK_ATTR_LINK;
+}
+
+int rtnl_link_get_link(struct rtnl_link *link)
+{
+	return link->l_link;
+}
+
+/**
+ * Set master link of link object
+ * @arg link		Link object
+ * @arg ifindex		Interface index of master link
+ *
+ * @see rtnl_link_get_master()
+ */
+void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
+{
+	link->l_master = ifindex;
+	link->ce_mask |= LINK_ATTR_MASTER;
+}
+
+/**
+ * Return master link of link object
+ * @arg link		Link object
+ *
+ * @see rtnl_link_set_master()
+ * @return Interface index of master link or 0 if not specified
+ */
+int rtnl_link_get_master(struct rtnl_link *link)
+{
+	return link->l_master;
+}
+
+/**
+ * Set operational status of link object
+ * @arg link		Link object
+ * @arg status		New opertional status
+ *
+ * @route_doc{link_attr_operstate, Operational Status}}
+ * @see rtnl_link_get_operstate()
+ */
+void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status)
+{
+	link->l_operstate = status;
+	link->ce_mask |= LINK_ATTR_OPERSTATE;
+}
+
+/**
+ * Return operational status of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_operstate, Operational Status}
+ * @see rtnl_link_set_operstate()
+ * @return Opertional state or \c IF_OPER_UNKNOWN
+ */
+uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
+{
+	return link->l_operstate;
+}
+
+/**
+ * Set link mode of link object
+ * @arg link		Link object
+ * @arg mode		New link mode
+ *
+ * @route_doc{link_attr_mode, Mode}
+ * @see rtnl_link_get_linkmode()
+ */
+void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode)
+{
+	link->l_linkmode = mode;
+	link->ce_mask |= LINK_ATTR_LINKMODE;
+}
+
+/**
+ * Return link mode of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_mode, Mode}
+ * @see rtnl_link_get_linkmode()
+ * @return Link mode or \c IF_LINK_MODE_DEFAULT
+ */
+uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
+{
+	return link->l_linkmode;
+}
+
+/**
+ * Return alias name of link object (SNMP IfAlias)
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_alias, Alias}
+ * @see rtnl_link_set_ifalias()
+ * @return Alias name or NULL if not set.
+ */
+const char *rtnl_link_get_ifalias(struct rtnl_link *link)
+{
+	return link->l_ifalias;
+}
+
+/**
+ * Set alias name of link object (SNMP IfAlias)
+ * @arg link		Link object
+ * @arg alias		Alias name or NULL to unset
+ *
+ * Sets the alias name of the link to the specified name. The alias
+ * name can be unset by specyfing NULL as the alias. The name will
+ * be strdup()ed, so no need to provide a persistent character string.
+ *
+ * @route_doc{link_attr_alias, Alias}
+ * @see rtnl_link_get_ifalias()
+ */
+void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
+{
+	free(link->l_ifalias);
+	link->ce_mask &= ~LINK_ATTR_IFALIAS;
+
+	if (alias) {
+		link->l_ifalias = strdup(alias);
+		link->ce_mask |= LINK_ATTR_IFALIAS;
+	}
+}
+
+/**
+ * Set queueing discipline name of link object
+ * @arg link		Link object
+ * @arg name		Name of queueing discipline
+ *
+ * @copydoc read_only_attribute
+ *
+ * For more information on how to modify the qdisc of a link, see section
+ * @ref_route{route_tc, Traffic Control}.
+ *
+ * @route_doc{link_attr_qdisc, Queueing Discipline Name}
+ * @see rtnl_link_get_qdisc()
+ */
+void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
+{
+	strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
+	link->ce_mask |= LINK_ATTR_QDISC;
+}
+
+/**
+ * Return name of queueing discipline of link object
+ * @arg link		Link object
+ *
+ * @route_doc{link_attr_qdisc, Queueing Discipline Name}
+ * @see rtnl_link_set_qdisc()
+ * @return Name of qdisc or NULL if not specified.
+ */
+char *rtnl_link_get_qdisc(struct rtnl_link *link)
+{
+	return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
+}
+
+
+/**
+ * Return number of PCI virtual functions of link object
+ * @arg link		Link object
+ * @arg num_vf		Pointer to store number of VFs
+ *
+ * @return 0 on success or -NLE_OPNOTSUPP if not available
+ */
+int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
+{
+	if (link->ce_mask & LINK_ATTR_NUM_VF) {
+		*num_vf = link->l_num_vf;
+		return 0;
+	} else
+		return -NLE_OPNOTSUPP;
+}
+
+/**
+ * Return value of link statistics counter
+ * @arg link		Link object
+ * @arg id		Identifier of statistical counter
+ *
+ * @return Value of counter or 0 if not specified.
+ */
+uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id)
+{
+	if (id > RTNL_LINK_STATS_MAX)
+		return 0;
+
+	return link->l_stats[id];
+}
+
+/**
+ * Set value of link statistics counter
+ * @arg link		Link object
+ * @arg id		Identifier of statistical counter
+ * @arg value		New value
+ *
+ * \note Changing the value of a statistical counter will not change the
+ *       value in the kernel.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
+		       const uint64_t value)
+{
+	if (id > RTNL_LINK_STATS_MAX)
+		return -NLE_INVAL;
+
+	link->l_stats[id] = value;
+
+	return 0;
+}
+
+/**
+ * Set type of link object
+ * @arg link		Link object
+ * @arg type		Name of link type
+ *
+ * Looks up the link type module and prepares the link to store type
+ * specific attributes. If a type has been assigned already it will
+ * be released with all link type specific attributes lost.
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return 0 on success or a negative errror code.
+ */
+int rtnl_link_set_type(struct rtnl_link *link, const char *type)
+{
+	struct rtnl_link_info_ops *io;
+	int err;
+
+	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
+		return -NLE_OPNOTSUPP;
+
+	if (link->l_info_ops)
+		release_link_info(link);
+
+	if (io->io_alloc && (err = io->io_alloc(link)) < 0)
+		return err;
+
+	link->ce_mask |= LINK_ATTR_LINKINFO;
+	link->l_info_ops = io;
+
+	return 0;
+}
+
+/**
+ * Return type of link
+ * @arg link		Link object
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return Name of link type or NULL if not specified.
+ */
+char *rtnl_link_get_type(struct rtnl_link *link)
+{
+	return link->l_info_ops ? link->l_info_ops->io_name : NULL;
+}
+
+/** @} */
+
+/**
+ * @name Master/Slave
+ * @{
+ */
+
+/**
+ * Enslave slave link to master link
+ * @arg sock		netlink socket
+ * @arg master		ifindex of master link
+ * @arg slave		ifindex of slave link
+ *
+ * This function is identical to rtnl_link_enslave() except that
+ * it takes interface indices instead of rtnl_link objects.
+ *
+ * @see rtnl_link_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
+{
+	struct rtnl_link *link;
+	int err;
+
+	if (!(link = rtnl_link_alloc()))
+		return -NLE_NOMEM;
+
+	rtnl_link_set_ifindex(link, slave);
+	rtnl_link_set_master(link, master);
+	
+	if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
+		goto errout;
+
+	rtnl_link_put(link);
+
+	/*
+	 * Due to the kernel not signaling whether this opertion is
+	 * supported or not, we will retrieve the attribute to see  if the
+	 * request was successful. If the master assigned remains unchanged
+	 * we will return NLE_OPNOTSUPP to allow performing backwards
+	 * compatibility of some sort.
+	 */
+	if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
+		return err;
+
+	if (rtnl_link_get_master(link) != master)
+		err = -NLE_OPNOTSUPP;
+
+errout:
+	rtnl_link_put(link);
+
+	return err;
+}
+
+/**
+ * Enslave slave link to master link
+ * @arg sock		netlink socket
+ * @arg master		master link
+ * @arg slave		slave link
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
+ * the master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_enslave_ifindex()
+ * @see rtnl_link_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master,
+		      struct rtnl_link *slave)
+{
+	return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master),
+					 rtnl_link_get_ifindex(slave));
+}
+
+/**
+ * Release slave link from its master
+ * @arg sock		netlink socket
+ * @arg slave		slave link
+ *
+ * This function is identical to rtnl_link_release() except that
+ * it takes an interface index instead of a rtnl_link object.
+ *
+ * @see rtnl_link_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_release_ifindex(struct nl_sock *sock, int slave)
+{
+	return rtnl_link_enslave_ifindex(sock, 0, slave);
+}
+
+/**
+ * Release slave link from its master
+ * @arg sock		netlink socket
+ * @arg slave		slave link
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
+ * its master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_release_ifindex()
+ * @see rtnl_link_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
+{
+	return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave));
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+static const struct trans_tbl link_flags[] = {
+	__ADD(IFF_LOOPBACK, loopback)
+	__ADD(IFF_BROADCAST, broadcast)
+	__ADD(IFF_POINTOPOINT, pointopoint)
+	__ADD(IFF_MULTICAST, multicast)
+	__ADD(IFF_NOARP, noarp)
+	__ADD(IFF_ALLMULTI, allmulti)
+	__ADD(IFF_PROMISC, promisc)
+	__ADD(IFF_MASTER, master)
+	__ADD(IFF_SLAVE, slave)
+	__ADD(IFF_DEBUG, debug)
+	__ADD(IFF_DYNAMIC, dynamic)
+	__ADD(IFF_AUTOMEDIA, automedia)
+	__ADD(IFF_PORTSEL, portsel)
+	__ADD(IFF_NOTRAILERS, notrailers)
+	__ADD(IFF_UP, up)
+	__ADD(IFF_RUNNING, running)
+	__ADD(IFF_LOWER_UP, lowerup)
+	__ADD(IFF_DORMANT, dormant)
+	__ADD(IFF_ECHO, echo)
+};
+
+char *rtnl_link_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, link_flags,
+			   ARRAY_SIZE(link_flags));
+}
+
+int rtnl_link_str2flags(const char *name)
+{
+	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
+}
+
+static const struct trans_tbl link_stats[] = {
+	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
+	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
+	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
+	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
+	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
+	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
+	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
+	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
+	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
+	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
+	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
+	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
+	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
+	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
+	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
+	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
+	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
+	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
+	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
+	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
+	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
+	__ADD(RTNL_LINK_COLLISIONS, collisions)
+	__ADD(RTNL_LINK_MULTICAST, multicast)
+	__ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
+	__ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
+	__ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
+	__ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
+	__ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
+	__ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
+	__ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
+	__ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
+	__ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
+	__ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
+	__ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
+	__ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
+	__ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
+	__ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
+	__ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
+	__ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
+	__ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
+	__ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
+	__ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
+	__ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
+	__ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
+	__ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
+	__ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
+	__ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
+	__ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
+	__ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
+	__ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
+	__ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
+	__ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
+	__ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
+	__ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
+	__ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
+	__ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
+	__ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
+};
+
+char *rtnl_link_stat2str(int st, char *buf, size_t len)
+{
+	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
+}
+
+int rtnl_link_str2stat(const char *name)
+{
+	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
+}
+
+static const struct trans_tbl link_operstates[] = {
+	__ADD(IF_OPER_UNKNOWN, unknown)
+	__ADD(IF_OPER_NOTPRESENT, notpresent)
+	__ADD(IF_OPER_DOWN, down)
+	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
+	__ADD(IF_OPER_TESTING, testing)
+	__ADD(IF_OPER_DORMANT, dormant)
+	__ADD(IF_OPER_UP, up)
+};
+
+char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
+{
+	return __type2str(st, buf, len, link_operstates,
+			  ARRAY_SIZE(link_operstates));
+}
+
+int rtnl_link_str2operstate(const char *name)
+{
+	return __str2type(name, link_operstates,
+			  ARRAY_SIZE(link_operstates));
+}
+
+static const struct trans_tbl link_modes[] = {
+	__ADD(IF_LINK_MODE_DEFAULT, default)
+	__ADD(IF_LINK_MODE_DORMANT, dormant)
+};
+
+char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
+{
+	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
+}
+
+int rtnl_link_str2mode(const char *name)
+{
+	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ */
+
+/**
+ * @deprecated Use of this function is deprecated, use rtnl_link_set_type()
+ */
+int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
+{
+	return rtnl_link_set_type(link, type);
+}
+
+/**
+ * @deprecated Use of this function is deprecated, use rtnl_link_get_type()
+ */
+char *rtnl_link_get_info_type(struct rtnl_link *link)
+{
+	return rtnl_link_get_type(link);
+}
+
+/**
+ * @deprecated The weight attribute is unused and obsoleted in all recent kernels
+ */
+void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
+{
+	link->l_weight = weight;
+	link->ce_mask |= LINK_ATTR_WEIGHT;
+}
+
+/**
+ * @deprecated The weight attribute is unused and obsoleted in all recent kernels
+ */
+unsigned int rtnl_link_get_weight(struct rtnl_link *link)
+{
+	return link->l_weight;
+}
+
+/** @} */
+
+static struct nl_object_ops link_obj_ops = {
+	.oo_name		= "route/link",
+	.oo_size		= sizeof(struct rtnl_link),
+	.oo_free_data		= link_free_data,
+	.oo_clone		= link_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= link_dump_line,
+	    [NL_DUMP_DETAILS]	= link_dump_details,
+	    [NL_DUMP_STATS]	= link_dump_stats,
+	},
+	.oo_compare		= link_compare,
+	.oo_attrs2str		= link_attrs2str,
+	.oo_id_attrs		= LINK_ATTR_IFINDEX,
+};
+
+static struct nl_af_group link_groups[] = {
+	{ AF_UNSPEC,	RTNLGRP_LINK },
+	{ END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_link_ops = {
+	.co_name		= "route/link",
+	.co_hdrsize		= sizeof(struct ifinfomsg),
+	.co_msgtypes		= {
+					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
+					{ RTM_DELLINK, NL_ACT_DEL, "del" },
+					{ RTM_GETLINK, NL_ACT_GET, "get" },
+					{ RTM_SETLINK, NL_ACT_CHANGE, "set" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_groups		= link_groups,
+	.co_request_update	= link_request_update,
+	.co_msg_parser		= link_msg_parser,
+	.co_event_filter	= link_event_filter,
+	.co_obj_ops		= &link_obj_ops,
+};
+
+static void __init link_init(void)
+{
+	nl_cache_mngt_register(&rtnl_link_ops);
+}
+
+static void __exit link_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_link_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/link/.dirstamp b/libnetwork/libnl3/lib/route/link/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/route/link/api.c b/libnetwork/libnl3/lib/route/link/api.c
new file mode 100644
index 0000000..f7907a7
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/api.c
@@ -0,0 +1,316 @@
+/*
+ * lib/route/link/api.c		Link Info API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup link_API Link Modules API
+ * @brief API for modules implementing specific link types/semantics.
+ *
+ * @par 1) Registering/Unregistering a new link info type
+ * @code
+ * static struct rtnl_link_info_ops vlan_info_ops = {
+ * 	.io_name		= "vlan",
+ * 	.io_alloc		= vlan_alloc,
+ * 	.io_parse		= vlan_parse,
+ * 	.io_dump[NL_DUMP_BRIEF]	= vlan_dump_brief,
+ * 	.io_dump[NL_DUMP_FULL]	= vlan_dump_full,
+ * 	.io_free		= vlan_free,
+ * };
+ *
+ * static void __init vlan_init(void)
+ * {
+ * 	rtnl_link_register_info(&vlan_info_ops);
+ * }
+ *
+ * static void __exit vlan_exit(void)
+ * {
+ * 	rtnl_link_unregister_info(&vlan_info_ops);
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/api.h>
+
+static NL_LIST_HEAD(info_ops);
+
+static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
+{
+	struct rtnl_link_info_ops *ops;
+
+	nl_list_for_each_entry(ops, &info_ops, io_list)
+		if (!strcmp(ops->io_name, name))
+			return ops;
+
+	return NULL;
+}
+
+/**
+ * @name Link Info Modules
+ * @{
+ */
+
+/**
+ * Return operations of a specific link info type
+ * @arg name		Name of link info type.
+ *
+ * @note The returned pointer must be given back using rtnl_link_info_ops_put()
+ *
+ * @return Pointer to operations or NULL if unavailable.
+ */
+struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
+{
+	struct rtnl_link_info_ops *ops;
+
+	if ((ops = __rtnl_link_info_ops_lookup(name)))
+		ops->io_refcnt++;
+
+	return ops;
+}
+
+/**
+ * Give back reference to a set of operations.
+ * @arg ops		Link info operations.
+ */
+void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
+{
+	if (ops)
+		ops->io_refcnt--;
+}
+
+/**
+ * Register operations for a link info type
+ * @arg ops		Link info operations
+ *
+ * This function must be called by modules implementing a specific link
+ * info type. It will make the operations implemented by the module
+ * available for everyone else.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_INVAL Link info name not specified.
+ * @return -NLE_EXIST Operations for address family already registered.
+ */
+int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
+{
+	if (ops->io_name == NULL)
+		return -NLE_INVAL;
+
+	if (__rtnl_link_info_ops_lookup(ops->io_name))
+		return -NLE_EXIST;
+
+	NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
+
+	nl_list_add_tail(&ops->io_list, &info_ops);
+
+	return 0;
+}
+
+/**
+ * Unregister operations for a link info type
+ * @arg ops		Link info operations
+ *
+ * This function must be called if a module implementing a specific link
+ * info type is unloaded or becomes unavailable. It must provide a
+ * set of operations which have previously been registered using
+ * rtnl_link_register_info().
+ *
+ * @return 0 on success or a negative error code
+ * @return _NLE_OPNOTSUPP Link info operations not registered.
+ * @return -NLE_BUSY Link info operations still in use.
+ */
+int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
+{
+	struct rtnl_link_info_ops *t;
+
+	nl_list_for_each_entry(t, &info_ops, io_list) {
+		if (t == ops) {
+			if (t->io_refcnt > 0)
+				return -NLE_BUSY;
+
+			nl_list_del(&t->io_list);
+
+			NL_DBG(1, "Unregistered link info operations %s\n",
+				ops->io_name);
+
+			return 0;
+		}
+	}
+
+	return -NLE_OPNOTSUPP;
+}
+
+/** @} */
+
+/**
+ * @name Link Address Family Modules
+ * @{
+ */
+
+static struct rtnl_link_af_ops *af_ops[AF_MAX];
+
+/**
+ * Return operations of a specific link address family
+ * @arg family		Address family
+ *
+ * @note The returned pointer must be given back using rtnl_link_af_ops_put()
+ *
+ * @return Pointer to operations or NULL if unavailable.
+ */
+struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
+{
+	if (family == AF_UNSPEC || family >= AF_MAX)
+		return NULL;
+
+	if (af_ops[family])
+		af_ops[family]->ao_refcnt++;
+
+	return af_ops[family];
+}
+
+/**
+ * Give back reference to a set of operations.
+ * @arg ops		Address family operations.
+ */
+void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
+{
+	if (ops)
+		ops->ao_refcnt--;
+}
+
+/**
+ * Allocate and return data buffer for link address family modules
+ * @arg link		Link object
+ * @arg ops		Address family operations
+ *
+ * This function must be called by link address family modules in all
+ * cases where the API does not provide the data buffer as argument
+ * already. This typically includes set functions the module provides.
+ * Calling this function is strictly required to ensure proper allocation
+ * of the buffer upon first use. Link objects will NOT proactively
+ * allocate a data buffer for each registered link address family.
+ *
+ * @return Pointer to data buffer or NULL on error.
+ */
+void *rtnl_link_af_alloc(struct rtnl_link *link,
+			 const struct rtnl_link_af_ops *ops)
+{
+	int family;
+
+	if (!link || !ops)
+		BUG();
+
+	family = ops->ao_family;
+
+	if (!link->l_af_data[family]) {
+		if (!ops->ao_alloc)
+			BUG();
+		
+		link->l_af_data[family] = ops->ao_alloc(link);
+		if (!link->l_af_data[family])
+			return NULL;
+	}
+
+	return link->l_af_data[family];
+}
+
+/**
+ * Return data buffer for link address family modules
+ * @arg link		Link object
+ * @arg ops		Address family operations
+ *
+ * This function returns a pointer to the data buffer for the specified link
+ * address family module or NULL if the buffer was not allocated yet. This
+ * function is typically used by get functions of modules which are not
+ * interested in having the data buffer allocated if no values have been set
+ * yet.
+ *
+ * @return Pointer to data buffer or NULL on error.
+ */
+void *rtnl_link_af_data(const struct rtnl_link *link,
+			const struct rtnl_link_af_ops *ops)
+{
+	if (!link || !ops)
+		BUG();
+
+	return link->l_af_data[ops->ao_family];
+}
+
+/**
+ * Register operations for a link address family
+ * @arg ops		Address family operations
+ *
+ * This function must be called by modules implementing a specific link
+ * address family. It will make the operations implemented by the module
+ * available for everyone else.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
+ * @return -NLE_EXIST Operations for address family already registered.
+ */
+int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
+{
+	if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
+		return -NLE_INVAL;
+
+	if (af_ops[ops->ao_family])
+		return -NLE_EXIST;
+
+	ops->ao_refcnt = 0;
+	af_ops[ops->ao_family] = ops;
+
+	NL_DBG(1, "Registered link address family operations %u\n",
+		ops->ao_family);
+
+	return 0;
+}
+
+/**
+ * Unregister operations for a link address family
+ * @arg ops		Address family operations
+ *
+ * This function must be called if a module implementing a specific link
+ * address family is unloaded or becomes unavailable. It must provide a
+ * set of operations which have previously been registered using
+ * rtnl_link_af_register().
+ *
+ * @return 0 on success or a negative error code
+ * @return -NLE_INVAL ops is NULL
+ * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
+ * @return -NLE_BUSY Address family operations still in use.
+ */
+int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
+{
+	if (!ops)
+		return -NLE_INVAL;
+
+	if (!af_ops[ops->ao_family])
+		return -NLE_OBJ_NOTFOUND;
+
+	if (ops->ao_refcnt > 0)
+		return -NLE_BUSY;
+
+	af_ops[ops->ao_family] = NULL;
+
+	NL_DBG(1, "Unregistered link address family operations %u\n",
+		ops->ao_family);
+
+	return 0;
+}
+
+/** @} */
+
+/** @} */
+
diff --git a/libnetwork/libnl3/lib/route/link/bonding.c b/libnetwork/libnl3/lib/route/link/bonding.c
new file mode 100644
index 0000000..5788f69
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/bonding.c
@@ -0,0 +1,217 @@
+/*
+ * lib/route/link/bonding.c	Bonding Link Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup bonding Bonding
+ *
+ * @details
+ * \b Link Type Name: "bond"
+ *
+ * @route_doc{link_bonding, Bonding Documentation}
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/route/link/api.h>
+
+/**
+ * Create a new kernel bonding device
+ * @arg sock		netlink socket
+ * @arg name		name of bonding device or NULL
+ * @arg opts		bonding options (currently unused)
+ *
+ * Creates a new bonding device in the kernel. If no name is
+ * provided, the kernel will automatically pick a name of the
+ * form "type%d" (e.g. bond0, vlan1, etc.)
+ *
+ * The \a opts argument is currently unused. In the future, it
+ * may be used to carry additional bonding options to be set
+ * when creating the bonding device.
+ *
+ * @note When letting the kernel assign a name, it will become
+ *       difficult to retrieve the interface afterwards because
+ *       you have to guess the name the kernel has chosen. It is
+ *       therefore not recommended to not provide a device name.
+ *
+ * @see rtnl_link_bond_enslave()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
+		       struct rtnl_link *opts)
+{
+	struct rtnl_link *link;
+	int err;
+
+	if (!(link = rtnl_link_alloc()))
+		return -NLE_NOMEM;
+
+	if (!name) {
+		if (opts)
+			name = rtnl_link_get_name(opts);
+
+		if (!name)
+			return -NLE_MISSING_ATTR;
+	}
+
+	if ((err = rtnl_link_set_type(link, "bond")) < 0)
+		goto errout;
+	
+
+		rtnl_link_set_name(link, name);
+
+	err = rtnl_link_add(sock, link, NLM_F_CREATE);
+errout:
+	rtnl_link_put(link);
+
+	return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock		netlink socket
+ * @arg master		ifindex of bonding master
+ * @arg slave		ifindex of slave link to add to bond
+ *
+ * This function is identical to rtnl_link_bond_enslave() except that
+ * it takes interface indices instead of rtnl_link objcets.
+ *
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
+				   int slave)
+{
+	struct rtnl_link *link;
+	int err;
+
+	if (!(link = rtnl_link_alloc()))
+		return -NLE_NOMEM;
+
+	if ((err = rtnl_link_set_type(link, "bond")) < 0)
+		goto errout;
+
+	rtnl_link_set_ifindex(link, slave);
+	rtnl_link_set_master(link, master);
+	
+	if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
+		goto errout;
+
+	rtnl_link_put(link);
+
+	/*
+	 * Due to the kernel not signaling whether this opertion is
+	 * supported or not, we will retrieve the attribute to see  if the
+	 * request was successful. If the master assigned remains unchanged
+	 * we will return NLE_OPNOTSUPP to allow performing backwards
+	 * compatibility of some sort.
+	 */
+	if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
+		return err;
+
+	if (rtnl_link_get_master(link) != master)
+		err = -NLE_OPNOTSUPP;
+
+errout:
+	rtnl_link_put(link);
+
+	return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock		netlink socket
+ * @arg master		bonding master
+ * @arg slave		slave link to add to bond
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
+ * the master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_enslave_ifindex()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
+			   struct rtnl_link *slave)
+{
+	return rtnl_link_bond_enslave_ifindex(sock,
+				rtnl_link_get_ifindex(master),
+				rtnl_link_get_ifindex(slave));
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock		netlink socket
+ * @arg slave		slave link to be released
+ *
+ * This function is identical to rtnl_link_bond_release() except that
+ * it takes an interface index instead of a rtnl_link object.
+ *
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
+{
+	return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock		netlink socket
+ * @arg slave		slave link to be released
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
+ * its master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_release_ifindex()
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
+{
+	return rtnl_link_bond_release_ifindex(sock,
+				rtnl_link_get_ifindex(slave));
+}
+
+static struct rtnl_link_info_ops bonding_info_ops = {
+	.io_name		= "bond",
+};
+
+static void __init bonding_init(void)
+{
+	rtnl_link_register_info(&bonding_info_ops);
+}
+
+static void __exit bonding_exit(void)
+{
+	rtnl_link_unregister_info(&bonding_info_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/link/bridge.c b/libnetwork/libnl3/lib/route/link/bridge.c
new file mode 100644
index 0000000..32fd38f
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/bridge.c
@@ -0,0 +1,83 @@
+/*
+ * lib/route/link/bridge.c	AF_BRIDGE link oeprations
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/api.h>
+
+struct bridge_data
+{
+	uint8_t			b_port_state;
+};
+
+static void *bridge_alloc(struct rtnl_link *link)
+{
+	return calloc(1, sizeof(struct bridge_data));
+}
+
+static void *bridge_clone(struct rtnl_link *link, void *data)
+{
+	struct bridge_data *bd;
+
+	if ((bd = bridge_alloc(link)))
+		memcpy(bd, data, sizeof(*bd));
+
+	return bd;
+}
+
+static void bridge_free(struct rtnl_link *link, void *data)
+{
+	free(data);
+}
+
+static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
+				 void *data)
+{
+	struct bridge_data *bd = data;
+
+	bd->b_port_state = nla_get_u8(attr);
+
+	return 0;
+}
+
+static void bridge_dump_details(struct rtnl_link *link,
+				struct nl_dump_params *p, void *data)
+{
+	struct bridge_data *bd = data;
+
+	nl_dump(p, "port-state %u ", bd->b_port_state);
+}
+
+static const struct nla_policy protinfo_policy = {
+	.type			= NLA_U8,
+};
+
+static struct rtnl_link_af_ops bridge_ops = {
+	.ao_family			= AF_BRIDGE,
+	.ao_alloc			= &bridge_alloc,
+	.ao_clone			= &bridge_clone,
+	.ao_free			= &bridge_free,
+	.ao_parse_protinfo		= &bridge_parse_protinfo,
+	.ao_dump[NL_DUMP_DETAILS]	= &bridge_dump_details,
+	.ao_protinfo_policy		= &protinfo_policy,
+};
+
+static void __init bridge_init(void)
+{
+	rtnl_link_af_register(&bridge_ops);
+}
+
+static void __exit bridge_exit(void)
+{
+	rtnl_link_af_unregister(&bridge_ops);
+}
diff --git a/libnetwork/libnl3/lib/route/link/dummy.c b/libnetwork/libnl3/lib/route/link/dummy.c
new file mode 100644
index 0000000..c7dabc1
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/dummy.c
@@ -0,0 +1,40 @@
+/*
+ * lib/route/link/dummy.c	Dummy Interfaces
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup dummy Dummy
+ *
+ * @details
+ * \b Link Type Name: "dummy"
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/route/link/api.h>
+
+static struct rtnl_link_info_ops dummy_info_ops = {
+	.io_name		= "dummy",
+};
+
+static void __init dummy_init(void)
+{
+	rtnl_link_register_info(&dummy_info_ops);
+}
+
+static void __exit dummy_exit(void)
+{
+	rtnl_link_unregister_info(&dummy_info_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/link/inet.c b/libnetwork/libnl3/lib/route/link/inet.c
new file mode 100644
index 0000000..a0e2318
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/inet.c
@@ -0,0 +1,280 @@
+/*
+ * lib/route/link/inet.c	AF_INET link operations
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup link_API
+ * @defgroup link_inet IPv4 Link Module
+ * @brief Implementation of IPv4 specific link attributes
+ *
+ *
+ *
+ * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
+ * @code
+ * struct nl_cache *cache;
+ * struct rtnl_link *link;
+ * uint32_t value;
+ *
+ * // Allocate a link cache
+ * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
+ *
+ * // Search for the link we wish to see the value from
+ * link = rtnl_link_get_by_name(cache, "eth0");
+ *
+ * // Read the value of the setting IPV4_DEVCONF_FORWARDING
+ * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
+ *         // Error: Unable to read config setting
+ *
+ * printf("forwarding is %s\n", value ? "enabled" : "disabled");
+ * @endcode
+ *
+ * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
+ * @code
+ * //
+ * // ... Continueing from the previous example ...
+ * //
+ *
+ * struct rtnl_link *new;
+ *
+ * // Allocate a new link to store the changes we wish to make.
+ * new = rtnl_link_alloc();
+ *
+ * // Set IPV4_DEVCONF_FORWARDING to '1'
+ * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
+ *
+ * // Send the change request to the kernel.
+ * rtnl_link_change(sock, link, new, 0);
+ * @endcode
+ *
+ * @{
+ */
+
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/api.h>
+
+/** @cond SKIP */
+struct inet_data
+{
+	uint8_t			i_confset[IPV4_DEVCONF_MAX];
+	uint32_t		i_conf[IPV4_DEVCONF_MAX];
+};
+/** @endcond */
+
+static void *inet_alloc(struct rtnl_link *link)
+{
+	return calloc(1, sizeof(struct inet_data));
+}
+
+static void *inet_clone(struct rtnl_link *link, void *data)
+{
+	struct inet_data *id;
+
+	if ((id = inet_alloc(link)))
+		memcpy(id, data, sizeof(*id));
+
+	return id;
+}
+
+static void inet_free(struct rtnl_link *link, void *data)
+{
+	free(data);
+}
+
+static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = {
+	[IFLA_INET_CONF]	= { .minlen = IPV4_DEVCONF_MAX * 4 },
+};
+
+static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
+{
+	struct inet_data *id = data;
+	struct nlattr *tb[IFLA_INET_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[IFLA_INET_CONF])
+		nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
+
+	return 0;
+}
+
+static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
+{
+	struct inet_data *id = data;
+	struct nlattr *nla;
+	int i;
+
+	if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
+		return -NLE_MSGSIZE;
+
+	for (i = 0; i < IPV4_DEVCONF_MAX; i++)
+		if (id->i_confset[i])
+			NLA_PUT_U32(msg, i+1, id->i_conf[i]);
+
+	nla_nest_end(msg, nla);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+static const struct trans_tbl inet_devconf[] = {
+	__ADD(IPV4_DEVCONF_FORWARDING, forwarding)
+	__ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding)
+	__ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp)
+	__ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
+	__ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects)
+	__ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects)
+	__ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media)
+	__ADD(IPV4_DEVCONF_RP_FILTER, rp_filter)
+	__ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
+	__ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay)
+	__ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians)
+	__ADD(IPV4_DEVCONF_TAG, tag)
+	__ADD(IPV4_DEVCONF_ARPFILTER, arpfilter)
+	__ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id)
+	__ADD(IPV4_DEVCONF_NOXFRM, noxfrm)
+	__ADD(IPV4_DEVCONF_NOPOLICY, nopolicy)
+	__ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version)
+	__ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce)
+	__ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore)
+	__ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries)
+	__ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept)
+	__ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify)
+	__ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local)
+	__ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark)
+	__ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan)
+};
+
+const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
+{
+	return __type2str(type, buf, len, inet_devconf,
+			  ARRAY_SIZE(inet_devconf));
+}
+
+int rtnl_link_inet_str2devconf(const char *name)
+{
+	return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
+}
+
+static void inet_dump_details(struct rtnl_link *link,
+			      struct nl_dump_params *p, void *data)
+{
+	struct inet_data *id = data;
+	char buf[64];
+	int i, n = 0;
+
+	nl_dump_line(p, "    ipv4 devconf:\n");
+	nl_dump_line(p, "      ");
+
+	for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
+		nl_dump_line(p, "%-19s %3u",
+			rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
+			id->i_conf[i]);
+
+		if (++n == 3) {
+			nl_dump(p, "\n");
+			nl_dump_line(p, "      ");
+			n = 0;
+		} else
+			nl_dump(p, "  ");
+	}
+
+	if (n != 0)
+		nl_dump(p, "\n");
+}
+
+static struct rtnl_link_af_ops inet_ops = {
+	.ao_family			= AF_INET,
+	.ao_alloc			= &inet_alloc,
+	.ao_clone			= &inet_clone,
+	.ao_free			= &inet_free,
+	.ao_parse_af			= &inet_parse_af,
+	.ao_fill_af			= &inet_fill_af,
+	.ao_dump[NL_DUMP_DETAILS]	= &inet_dump_details,
+};
+
+/**
+ * Get value of a ipv4 link configuration setting
+ * @arg link		Link object
+ * @arg cfgid		Configuration identifier
+ * @arg res		Result pointer
+ *
+ * Stores the value of the specified configuration setting in the provided
+ * result pointer.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
+ * @return -NLE_NOATTR configuration setting not available
+ */
+int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
+			    uint32_t *res)
+{
+	struct inet_data *id;
+
+	if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
+		return -NLE_RANGE;
+
+	if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
+		return -NLE_NOATTR;
+
+	*res = id->i_conf[cfgid - 1];
+
+	return 0;
+}
+
+/**
+ * Change value of a ipv4 link configuration setting
+ * @arg link		Link object
+ * @arg cfgid		Configuration identifier
+ * @arg value		New value
+ *
+ * Changes the value in the per link ipv4 configuration array. 
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
+ * @return -NLE_NOMEM memory allocation failed
+ */
+int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
+			    uint32_t value)
+{
+	struct inet_data *id;
+
+	if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
+		return -NLE_NOMEM;
+
+	if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
+		return -NLE_RANGE;
+
+	id->i_confset[cfgid - 1] = 1;
+	id->i_conf[cfgid - 1] = value;
+
+	return 0;
+}
+
+
+static void __init inet_init(void)
+{
+	rtnl_link_af_register(&inet_ops);
+}
+
+static void __exit inet_exit(void)
+{
+	rtnl_link_af_unregister(&inet_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/link/inet6.c b/libnetwork/libnl3/lib/route/link/inet6.c
new file mode 100644
index 0000000..5f75342
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/inet6.c
@@ -0,0 +1,377 @@
+/*
+ * lib/route/link/inet6.c	AF_INET6 link operations
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/api.h>
+
+struct inet6_data
+{
+	uint32_t		i6_flags;
+	struct ifla_cacheinfo	i6_cacheinfo;
+	uint32_t		i6_conf[DEVCONF_MAX];
+};
+
+static void *inet6_alloc(struct rtnl_link *link)
+{
+	return calloc(1, sizeof(struct inet6_data));
+}
+
+static void *inet6_clone(struct rtnl_link *link, void *data)
+{
+	struct inet6_data *i6;
+
+	if ((i6 = inet6_alloc(link)))
+		memcpy(i6, data, sizeof(*i6));
+
+	return i6;
+}
+
+static void inet6_free(struct rtnl_link *link, void *data)
+{
+	free(data);
+}
+
+static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
+	[IFLA_INET6_FLAGS]	= { .type = NLA_U32 },
+	[IFLA_INET6_CACHEINFO]	= { .minlen = sizeof(struct ifla_cacheinfo) },
+	[IFLA_INET6_CONF]	= { .minlen = DEVCONF_MAX * 4 },
+	[IFLA_INET6_STATS]	= { .minlen = __IPSTATS_MIB_MAX * 8 },
+	[IFLA_INET6_ICMP6STATS]	= { .minlen = __ICMP6_MIB_MAX * 8 },
+};
+
+static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
+				void *data)
+{
+	struct inet6_data *i6 = data;
+	struct nlattr *tb[IFLA_INET6_MAX+1];
+	int err;
+
+	err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[IFLA_INET6_FLAGS])
+		i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
+
+	if (tb[IFLA_INET6_CACHEINFO])
+		nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
+			   sizeof(i6->i6_cacheinfo));
+
+	if (tb[IFLA_INET6_CONF])
+		nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
+			   sizeof(i6->i6_conf));
+ 
+	/*
+	 * Due to 32bit data alignment, these addresses must be copied to an
+	 * aligned location prior to access.
+	 */
+	if (tb[IFLA_INET6_STATS]) {
+		unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]);
+		uint64_t stat;
+		int i;
+
+		for (i = 1; i < __IPSTATS_MIB_MAX; i++) {
+			memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
+			rtnl_link_set_stat(link, RTNL_LINK_IP6_INPKTS + i - 1,
+					   stat);
+		}
+	}
+
+	if (tb[IFLA_INET6_ICMP6STATS]) {
+		unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]);
+		uint64_t stat;
+		int i;
+
+		for (i = 1; i < __ICMP6_MIB_MAX; i++) {
+			memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
+			rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1,
+					   stat);
+		}
+	}
+
+	return 0;
+}
+
+/* These live in include/net/if_inet6.h and should be moved to include/linux */
+#define IF_RA_OTHERCONF	0x80
+#define IF_RA_MANAGED	0x40
+#define IF_RA_RCVD	0x20
+#define IF_RS_SENT	0x10
+#define IF_READY	0x80000000
+
+static const struct trans_tbl inet6_flags[] = {
+	__ADD(IF_RA_OTHERCONF, ra_otherconf)
+	__ADD(IF_RA_MANAGED, ra_managed)
+	__ADD(IF_RA_RCVD, ra_rcvd)
+	__ADD(IF_RS_SENT, rs_sent)
+	__ADD(IF_READY, ready)
+};
+
+static char *inet6_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, inet6_flags,
+			   ARRAY_SIZE(inet6_flags));
+}
+
+static const struct trans_tbl inet6_devconf[] = {
+	__ADD(DEVCONF_FORWARDING, forwarding)
+	__ADD(DEVCONF_HOPLIMIT, hoplimit)
+	__ADD(DEVCONF_MTU6, mtu6)
+	__ADD(DEVCONF_ACCEPT_RA, accept_ra)
+	__ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
+	__ADD(DEVCONF_AUTOCONF, autoconf)
+	__ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
+	__ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
+	__ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
+	__ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
+	__ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
+	__ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
+	__ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
+	__ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
+	__ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
+	__ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
+	__ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
+	__ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
+	__ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
+	__ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
+	__ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
+	__ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
+	__ADD(DEVCONF_PROXY_NDP, proxy_ndp)
+	__ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
+	__ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
+	__ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
+	__ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
+	__ADD(DEVCONF_ACCEPT_DAD, accept_dad)
+	__ADD(DEVCONF_FORCE_TLLAO, force_tllao)
+};
+
+static char *inet6_devconf2str(int type, char *buf, size_t len)
+{
+	return __type2str(type, buf, len, inet6_devconf,
+			  ARRAY_SIZE(inet6_devconf));
+}
+
+
+static void inet6_dump_details(struct rtnl_link *link,
+				struct nl_dump_params *p, void *data)
+{
+	struct inet6_data *i6 = data;
+	char buf[64], buf2[64];
+	int i, n = 0;
+
+	nl_dump_line(p, "    ipv6 max-reasm-len %s",
+		nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
+
+	nl_dump(p, " <%s>\n",
+		inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
+
+
+	nl_dump_line(p, "      create-stamp %.2fs reachable-time %s",
+		(double) i6->i6_cacheinfo.tstamp / 100.,
+		nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
+
+	nl_dump(p, " retrans-time %s\n",
+		nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
+
+	nl_dump_line(p, "      devconf:\n");
+	nl_dump_line(p, "      ");
+
+	for (i = 0; i < DEVCONF_MAX; i++) {
+		uint32_t value = i6->i6_conf[i];
+		int x, offset;
+
+		switch (i) {
+		case DEVCONF_TEMP_VALID_LFT:
+		case DEVCONF_TEMP_PREFERED_LFT:
+			nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2));
+			break;
+
+		case DEVCONF_RTR_PROBE_INTERVAL:
+		case DEVCONF_RTR_SOLICIT_INTERVAL:
+		case DEVCONF_RTR_SOLICIT_DELAY:
+			nl_msec2str(value, buf2, sizeof(buf2));
+			break;
+
+		default:
+			snprintf(buf2, sizeof(buf2), "%u", value);
+			break;
+			
+		}
+
+		inet6_devconf2str(i, buf, sizeof(buf));
+
+		offset = 23 - strlen(buf2);
+		if (offset < 0)
+			offset = 0;
+
+		for (x = strlen(buf); x < offset; x++)
+			buf[x] = ' ';
+
+		strncpy(&buf[offset], buf2, strlen(buf2));
+
+		nl_dump_line(p, "%s", buf);
+
+		if (++n == 3) {
+			nl_dump(p, "\n");
+			nl_dump_line(p, "      ");
+			n = 0;
+		} else
+			nl_dump(p, "  ");
+	}
+
+	if (n != 0)
+		nl_dump(p, "\n");
+}
+
+static void inet6_dump_stats(struct rtnl_link *link,
+			     struct nl_dump_params *p, void *data)
+{
+	double octets;
+	char *octetsUnit;
+
+	nl_dump(p, "    IPv6:       InPkts           InOctets     "
+		   "    InDiscards         InDelivers\n");
+	nl_dump(p, "    %18llu ", link->l_stats[RTNL_LINK_IP6_INPKTS]);
+
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B ", 0);
+	
+	nl_dump(p, "%18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_INDISCARDS],
+		link->l_stats[RTNL_LINK_IP6_INDELIVERS]);
+
+	nl_dump(p, "               OutPkts          OutOctets     "
+		   "   OutDiscards        OutForwards\n");
+
+	nl_dump(p, "    %18llu ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]);
+
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B ", 0);
+
+	nl_dump(p, "%18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
+		link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]);
+
+	nl_dump(p, "           InMcastPkts      InMcastOctets     "
+		   "   InBcastPkts     InBcastOctests\n");
+
+	nl_dump(p, "    %18llu ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]);
+
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B ", 0);
+
+	nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B\n", 0);
+
+	nl_dump(p, "          OutMcastPkts     OutMcastOctets     "
+		   "  OutBcastPkts    OutBcastOctests\n");
+
+	nl_dump(p, "    %18llu ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]);
+
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B ", 0);
+
+	nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
+	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
+				      &octetsUnit);
+	if (octets)
+		nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+	else
+		nl_dump(p, "%16llu B\n", 0);
+
+	nl_dump(p, "              ReasmOKs         ReasmFails     "
+		   "    ReasmReqds       ReasmTimeout\n");
+	nl_dump(p, "    %18llu %18llu %18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_REASMOKS],
+		link->l_stats[RTNL_LINK_IP6_REASMFAILS],
+		link->l_stats[RTNL_LINK_IP6_REASMREQDS],
+		link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]);
+
+	nl_dump(p, "               FragOKs          FragFails    "
+		   "    FragCreates\n");
+	nl_dump(p, "    %18llu %18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_FRAGOKS],
+		link->l_stats[RTNL_LINK_IP6_FRAGFAILS],
+		link->l_stats[RTNL_LINK_IP6_FRAGCREATES]);
+
+	nl_dump(p, "           InHdrErrors      InTooBigErrors   "
+		   "     InNoRoutes       InAddrErrors\n");
+	nl_dump(p, "    %18llu %18llu %18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_INHDRERRORS],
+		link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS],
+		link->l_stats[RTNL_LINK_IP6_INNOROUTES],
+		link->l_stats[RTNL_LINK_IP6_INADDRERRORS]);
+
+	nl_dump(p, "       InUnknownProtos     InTruncatedPkts   "
+		   "    OutNoRoutes\n");
+	nl_dump(p, "    %18llu %18llu %18llu\n",
+		link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS],
+		link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS],
+		link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]);
+
+	nl_dump(p, "    ICMPv6:     InMsgs           InErrors        "
+		   "    OutMsgs          OutErrors\n");
+	nl_dump(p, "    %18llu %18llu %18llu %18llu\n",
+		link->l_stats[RTNL_LINK_ICMP6_INMSGS],
+		link->l_stats[RTNL_LINK_ICMP6_INERRORS],
+		link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
+		link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]);
+}
+
+static const struct nla_policy protinfo_policy = {
+	.type			= NLA_NESTED,
+};
+
+static struct rtnl_link_af_ops inet6_ops = {
+	.ao_family			= AF_INET6,
+	.ao_alloc			= &inet6_alloc,
+	.ao_clone			= &inet6_clone,
+	.ao_free			= &inet6_free,
+	.ao_parse_protinfo		= &inet6_parse_protinfo,
+	.ao_parse_af			= &inet6_parse_protinfo,
+	.ao_dump[NL_DUMP_DETAILS]	= &inet6_dump_details,
+	.ao_dump[NL_DUMP_STATS]		= &inet6_dump_stats,
+	.ao_protinfo_policy		= &protinfo_policy,
+};
+
+static void __init inet6_init(void)
+{
+	rtnl_link_af_register(&inet6_ops);
+}
+
+static void __exit inet6_exit(void)
+{
+	rtnl_link_af_unregister(&inet6_ops);
+}
diff --git a/libnetwork/libnl3/lib/route/link/vlan.c b/libnetwork/libnl3/lib/route/link/vlan.c
new file mode 100644
index 0000000..a30ff77
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/link/vlan.c
@@ -0,0 +1,565 @@
+/*
+ * lib/route/link/vlan.c	VLAN Link Info
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup vlan VLAN
+ * Virtual LAN link module
+ *
+ * @details
+ * \b Link Type Name: "vlan"
+ *
+ * @route_doc{link_vlan, VLAN Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/api.h>
+#include <netlink/route/link/vlan.h>
+
+#include <linux/if_vlan.h>
+
+/** @cond SKIP */
+#define VLAN_HAS_ID		(1<<0)
+#define VLAN_HAS_FLAGS		(1<<1)
+#define VLAN_HAS_INGRESS_QOS	(1<<2)
+#define VLAN_HAS_EGRESS_QOS	(1<<3)
+
+struct vlan_info
+{
+	uint16_t		vi_vlan_id;
+	uint32_t		vi_flags;
+	uint32_t		vi_flags_mask;
+	uint32_t		vi_ingress_qos[VLAN_PRIO_MAX+1];
+	uint32_t		vi_negress;
+	uint32_t		vi_egress_size;
+	struct vlan_map * 	vi_egress_qos;
+	uint32_t		vi_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = {
+	[IFLA_VLAN_ID]		= { .type = NLA_U16 },
+	[IFLA_VLAN_FLAGS]	= { .minlen = sizeof(struct ifla_vlan_flags) },
+	[IFLA_VLAN_INGRESS_QOS]	= { .type = NLA_NESTED },
+	[IFLA_VLAN_EGRESS_QOS]	= { .type = NLA_NESTED },
+};
+
+static int vlan_alloc(struct rtnl_link *link)
+{
+	struct vlan_info *vi;
+
+	if ((vi = calloc(1, sizeof(*vi))) == NULL)
+		return -NLE_NOMEM;
+
+	link->l_info = vi;
+
+	return 0;
+}
+
+static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
+		      struct nlattr *xstats)
+{
+	struct nlattr *tb[IFLA_VLAN_MAX+1];
+	struct vlan_info *vi;
+	int err;
+
+	NL_DBG(3, "Parsing VLAN link info");
+
+	if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
+		goto errout;
+
+	if ((err = vlan_alloc(link)) < 0)
+		goto errout;
+
+	vi = link->l_info;
+
+	if (tb[IFLA_VLAN_ID]) {
+		vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]);
+		vi->vi_mask |= VLAN_HAS_ID;
+	}
+
+	if (tb[IFLA_VLAN_FLAGS]) {
+		struct ifla_vlan_flags flags;
+		nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
+
+		vi->vi_flags = flags.flags;
+		vi->vi_mask |= VLAN_HAS_FLAGS;
+	}
+
+	if (tb[IFLA_VLAN_INGRESS_QOS]) {
+		struct ifla_vlan_qos_mapping *map;
+		struct nlattr *nla;
+		int remaining;
+
+		memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
+
+		nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
+			if (nla_len(nla) < sizeof(*map))
+				return -NLE_INVAL;
+
+			map = nla_data(nla);
+			if (map->from < 0 || map->from > VLAN_PRIO_MAX) {
+				return -NLE_INVAL;
+			}
+
+			vi->vi_ingress_qos[map->from] = map->to;
+		}
+
+		vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
+	}
+
+	if (tb[IFLA_VLAN_EGRESS_QOS]) {
+		struct ifla_vlan_qos_mapping *map;
+		struct nlattr *nla;
+		int remaining, i = 0;
+
+		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
+			if (nla_len(nla) < sizeof(*map))
+				return -NLE_INVAL;
+			i++;
+		}
+
+		/* align to have a little reserve */
+		vi->vi_egress_size = (i + 32) & ~31;
+		vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map));
+		if (vi->vi_egress_qos == NULL)
+			return -NLE_NOMEM;
+
+		i = 0;
+		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
+			map = nla_data(nla);
+			NL_DBG(4, "Assigning egress qos mapping %d\n", i);
+			vi->vi_egress_qos[i].vm_from = map->from;
+			vi->vi_egress_qos[i++].vm_to = map->to;
+		}
+
+		vi->vi_negress = i;
+		vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
+	}
+
+	err = 0;
+errout:
+	return err;
+}
+
+static void vlan_free(struct rtnl_link *link)
+{
+	struct vlan_info *vi = link->l_info;
+
+	if (vi) {
+		free(vi->vi_egress_qos);
+		vi->vi_egress_qos = NULL;
+	}
+
+	free(vi);
+	link->l_info = NULL;
+}
+
+static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+	struct vlan_info *vi = link->l_info;
+
+	nl_dump(p, "vlan-id %d", vi->vi_vlan_id);
+}
+
+static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+	struct vlan_info *vi = link->l_info;
+	int i, printed;
+	char buf[64];
+
+	rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
+	nl_dump_line(p, "    vlan-info id %d <%s>\n", vi->vi_vlan_id, buf);
+
+	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
+		nl_dump_line(p, 
+		"      ingress vlan prio -> qos/socket prio mapping:\n");
+		for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
+			if (vi->vi_ingress_qos[i]) {
+				if (printed == 0)
+					nl_dump_line(p, "      ");
+				nl_dump(p, "%x -> %#08x, ",
+					i, vi->vi_ingress_qos[i]);
+				if (printed++ == 3) {
+					nl_dump(p, "\n");
+					printed = 0;
+				}
+			}
+		}
+
+		if (printed > 0 && printed != 4)
+			nl_dump(p, "\n");
+	}
+
+	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+		nl_dump_line(p, 
+		"      egress qos/socket prio -> vlan prio mapping:\n");
+		for (i = 0, printed = 0; i < vi->vi_negress; i++) {
+			if (printed == 0)
+				nl_dump_line(p, "      ");
+			nl_dump(p, "%#08x -> %x, ",
+				vi->vi_egress_qos[i].vm_from,
+				vi->vi_egress_qos[i].vm_to);
+			if (printed++ == 3) {
+				nl_dump(p, "\n");
+				printed = 0;
+			}
+		}
+
+		if (printed > 0 && printed != 4)
+			nl_dump(p, "\n");
+	}
+}
+
+static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+	struct vlan_info *vdst, *vsrc = src->l_info;
+	int err;
+
+	dst->l_info = NULL;
+	if ((err = rtnl_link_set_type(dst, "vlan")) < 0)
+		return err;
+	vdst = dst->l_info;
+
+	vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
+				     sizeof(struct vlan_map));
+	if (!vdst->vi_egress_qos)
+		return -NLE_NOMEM;
+
+	memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
+	       vsrc->vi_egress_size * sizeof(struct vlan_map));
+
+	return 0;
+}
+
+static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+	struct vlan_info *vi = link->l_info;
+	struct nlattr *data;
+
+	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+		return -NLE_MSGSIZE;
+
+	if (vi->vi_mask & VLAN_HAS_ID)
+		NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
+
+	if (vi->vi_mask & VLAN_HAS_FLAGS) {
+		struct ifla_vlan_flags flags = {
+			.flags = vi->vi_flags,
+			.mask = vi->vi_flags_mask,
+		};
+
+		NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags);
+	}
+
+	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
+		struct ifla_vlan_qos_mapping map;
+		struct nlattr *qos;
+		int i;
+
+		if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
+			goto nla_put_failure;
+
+		for (i = 0; i <= VLAN_PRIO_MAX; i++) {
+			if (vi->vi_ingress_qos[i]) {
+				map.from = i;
+				map.to = vi->vi_ingress_qos[i];
+
+				NLA_PUT(msg, i, sizeof(map), &map);
+			}
+		}
+
+		nla_nest_end(msg, qos);
+	}
+
+	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+		struct ifla_vlan_qos_mapping map;
+		struct nlattr *qos;
+		int i;
+
+		if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
+			goto nla_put_failure;
+
+		for (i = 0; i < vi->vi_negress; i++) {
+			map.from = vi->vi_egress_qos[i].vm_from;
+			map.to = vi->vi_egress_qos[i].vm_to;
+
+			NLA_PUT(msg, i, sizeof(map), &map);
+		}
+
+		nla_nest_end(msg, qos);
+	}
+
+	nla_nest_end(msg, data);
+
+nla_put_failure:
+
+	return 0;
+}
+
+static struct rtnl_link_info_ops vlan_info_ops = {
+	.io_name		= "vlan",
+	.io_alloc		= vlan_alloc,
+	.io_parse		= vlan_parse,
+	.io_dump = {
+	    [NL_DUMP_LINE]	= vlan_dump_line,
+	    [NL_DUMP_DETAILS]	= vlan_dump_details,
+	},
+	.io_clone		= vlan_clone,
+	.io_put_attrs		= vlan_put_attrs,
+	.io_free		= vlan_free,
+};
+
+/** @cond SKIP */
+#define IS_VLAN_LINK_ASSERT(link) \
+	if ((link)->l_info_ops != &vlan_info_ops) { \
+		APPBUG("Link is not a vlan link. set type \"vlan\" first."); \
+		return -NLE_OPNOTSUPP; \
+	}
+/** @endcond */
+
+/**
+ * @name VLAN Object
+ * @{
+ */
+
+/**
+ * Check if link is a VLAN link
+ * @arg link		Link object
+ *
+ * @return True if link is a VLAN link, otherwise false is returned.
+ */
+int rtnl_link_is_vlan(struct rtnl_link *link)
+{
+	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vlan");
+}
+
+/**
+ * Set VLAN ID
+ * @arg link		Link object
+ * @arg id		VLAN identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vlan_set_id(struct rtnl_link *link, uint16_t id)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	vi->vi_vlan_id = id;
+	vi->vi_mask |= VLAN_HAS_ID;
+
+	return 0;
+}
+
+/**
+ * Get VLAN Id
+ * @arg link		Link object
+ *
+ * @return VLAN id, 0 if not set or a negative error code.
+ */
+int rtnl_link_vlan_get_id(struct rtnl_link *link)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	if (vi->vi_mask & VLAN_HAS_ID)
+		return vi->vi_vlan_id;
+	else
+		return 0;
+}
+
+/**
+ * Set VLAN flags
+ * @arg link		Link object
+ * @arg flags		VLAN flags
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	vi->vi_flags_mask |= flags;
+	vi->vi_flags |= flags;
+	vi->vi_mask |= VLAN_HAS_FLAGS;
+
+	return 0;
+}
+
+/**
+ * Unset VLAN flags
+ * @arg link		Link object
+ * @arg flags		VLAN flags
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	vi->vi_flags_mask |= flags;
+	vi->vi_flags &= ~flags;
+	vi->vi_mask |= VLAN_HAS_FLAGS;
+
+	return 0;
+}
+
+/**
+ * Get VLAN flags
+ * @arg link		Link object
+ *
+ * @return VLAN flags, 0 if none set, or a negative error code.
+ */
+int rtnl_link_vlan_get_flags(struct rtnl_link *link)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	return vi->vi_flags;
+}
+
+/** @} */
+
+/**
+ * @name Quality of Service
+ * @{
+ */
+
+int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
+				   uint32_t to)
+{
+	struct vlan_info *vi = link->l_info;
+
+	IS_VLAN_LINK_ASSERT(link);
+
+	if (from < 0 || from > VLAN_PRIO_MAX)
+		return -NLE_INVAL;
+
+	vi->vi_ingress_qos[from] = to;
+	vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
+
+	return 0;
+}
+
+uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
+{
+	struct vlan_info *vi = link->l_info;
+
+	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
+		return NULL;
+
+	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
+		return vi->vi_ingress_qos;
+	else
+		return NULL;
+}
+
+int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
+{
+	struct vlan_info *vi = link->l_info;
+
+	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
+		return -NLE_OPNOTSUPP;
+
+	if (to < 0 || to > VLAN_PRIO_MAX)
+		return -NLE_INVAL;
+
+	if (vi->vi_negress >= vi->vi_egress_size) {
+		int new_size = vi->vi_egress_size + 32;
+		void *ptr;
+
+		ptr = realloc(vi->vi_egress_qos, new_size);
+		if (!ptr)
+			return -NLE_NOMEM;
+
+		vi->vi_egress_qos = ptr;
+		vi->vi_egress_size = new_size;
+	}
+
+	vi->vi_egress_qos[vi->vi_negress].vm_from = from;
+	vi->vi_egress_qos[vi->vi_negress].vm_to = to;
+	vi->vi_negress++;
+	vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
+
+	return 0;
+}
+
+struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
+					       int *negress)
+{
+	struct vlan_info *vi = link->l_info;
+
+	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
+		return NULL;
+
+	if (negress == NULL)
+		return NULL;
+
+	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+		*negress = vi->vi_negress;
+		return vi->vi_egress_qos;
+	} else {
+		*negress = 0;
+		return NULL;
+	}
+}
+
+/** @} */
+
+static const struct trans_tbl vlan_flags[] = {
+	__ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr)
+};
+
+/**
+ * @name Flag Translation
+ * @{
+ */
+
+char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags));
+}
+
+int rtnl_link_vlan_str2flags(const char *name)
+{
+	return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags));
+}
+
+/** @} */
+
+
+static void __init vlan_init(void)
+{
+	rtnl_link_register_info(&vlan_info_ops);
+}
+
+static void __exit vlan_exit(void)
+{
+	rtnl_link_unregister_info(&vlan_info_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/neigh.c b/libnetwork/libnl3/lib/route/neigh.c
new file mode 100644
index 0000000..7985d34
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/neigh.c
@@ -0,0 +1,846 @@
+/*
+ * lib/route/neigh.c	Neighbours
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup neigh Neighbours
+ * @brief
+ *
+ * The neighbour table establishes bindings between protocol addresses and
+ * link layer addresses for hosts sharing the same physical link. This
+ * module allows you to access and manipulate the content of these tables.
+ *
+ * @par Neighbour States
+ * @code
+ * NUD_INCOMPLETE
+ * NUD_REACHABLE
+ * NUD_STALE
+ * NUD_DELAY
+ * NUD_PROBE
+ * NUD_FAILED
+ * NUD_NOARP
+ * NUD_PERMANENT
+ * @endcode
+ *
+ * @par Neighbour Flags
+ * @code
+ * NTF_USE
+ * NTF_PROXY
+ * NTF_ROUTER
+ * @endcode
+ *
+ * @par Neighbour Identification
+ * A neighbour is uniquely identified by the attributes listed below, whenever
+ * you refer to an existing neighbour all of the attributes must be set.
+ * Neighbours from caches automatically have all required attributes set.
+ *   - interface index (rtnl_neigh_set_ifindex())
+ *   - destination address (rtnl_neigh_set_dst())
+ *
+ * @par Changeable Attributes
+ * \anchor neigh_changeable
+ *  - state (rtnl_neigh_set_state())
+ *  - link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @par Required Caches for Dumping
+ * In order to dump neighbour attributes you must provide the following
+ * caches via nl_cache_provide()
+ *  - link cache holding all links
+ *
+ * @par TODO
+ *   - Document proxy settings
+ *   - Document states and their influence
+ *
+ * @par 1) Retrieving information about configured neighbours
+ * @code
+ * // The first step is to retrieve a list of all available neighbour within
+ * // the kernel and put them into a cache.
+ * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
+ *
+ * // Neighbours can then be looked up by the interface and destination
+ * // address:
+ * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
+ * 
+ * // After successful usage, the object must be given back to the cache
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 2) Adding new neighbours
+ * @code
+ * // Allocate an empty neighbour handle to be filled out with the attributes
+ * // of the new neighbour.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Fill out the attributes of the new neighbour
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent"));
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_add_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 3) Deleting an existing neighbour
+ * @code
+ * // Allocate an empty neighbour object to be filled out with the attributes
+ * // matching the neighbour to be deleted. Alternatively a fully equipped
+ * // neighbour object out of a cache can be used instead.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Neighbours are uniquely identified by their interface index and
+ * // destination address, you may fill out other attributes but they
+ * // will have no influence.
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_delete_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_delete(sk, neigh, 0);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 4) Changing neighbour attributes
+ * @code
+ * // Allocate an empty neighbour object to be filled out with the attributes
+ * // matching the neighbour to be changed and the new parameters. Alternatively
+ * // a fully equipped modified neighbour object out of a cache can be used.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Identify the neighbour to be changed by its interface index and
+ * // destination address
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ *
+ * // The link layer address may be modified, if so it is wise to change
+ * // its state to "permanent" in order to avoid having it overwritten.
+ * rtnl_neigh_set_lladdr(neigh, lladdr);
+ *
+ * // Secondly the state can be modified allowing normal neighbours to be
+ * // converted into permanent entries or to manually confirm a neighbour.
+ * rtnl_neigh_set_state(neigh, state);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_change_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/neighbour.h>
+#include <netlink/route/link.h>
+
+/** @cond SKIP */
+#define NEIGH_ATTR_FLAGS        0x01
+#define NEIGH_ATTR_STATE        0x02
+#define NEIGH_ATTR_LLADDR       0x04
+#define NEIGH_ATTR_DST          0x08
+#define NEIGH_ATTR_CACHEINFO    0x10
+#define NEIGH_ATTR_IFINDEX      0x20
+#define NEIGH_ATTR_FAMILY       0x40
+#define NEIGH_ATTR_TYPE         0x80
+#define NEIGH_ATTR_PROBES       0x100
+
+static struct nl_cache_ops rtnl_neigh_ops;
+static struct nl_object_ops neigh_obj_ops;
+/** @endcond */
+
+static void neigh_free_data(struct nl_object *c)
+{
+	struct rtnl_neigh *neigh = nl_object_priv(c);
+
+	if (!neigh)
+		return;
+
+	nl_addr_put(neigh->n_lladdr);
+	nl_addr_put(neigh->n_dst);
+}
+
+static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct rtnl_neigh *dst = nl_object_priv(_dst);
+	struct rtnl_neigh *src = nl_object_priv(_src);
+
+	if (src->n_lladdr)
+		if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
+			return -NLE_NOMEM;
+
+	if (src->n_dst)
+		if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
+			return -NLE_NOMEM;
+
+	return 0;
+}
+
+static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
+	struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
+	int diff = 0;
+
+#define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= NEIGH_DIFF(IFINDEX,	a->n_ifindex != b->n_ifindex);
+	diff |= NEIGH_DIFF(FAMILY,	a->n_family != b->n_family);
+	diff |= NEIGH_DIFF(TYPE,	a->n_type != b->n_type);
+	diff |= NEIGH_DIFF(LLADDR,	nl_addr_cmp(a->n_lladdr, b->n_lladdr));
+	diff |= NEIGH_DIFF(DST,		nl_addr_cmp(a->n_dst, b->n_dst));
+
+	if (flags & LOOSE_COMPARISON) {
+		diff |= NEIGH_DIFF(STATE,
+				  (a->n_state ^ b->n_state) & b->n_state_mask);
+		diff |= NEIGH_DIFF(FLAGS,
+				  (a->n_flags ^ b->n_flags) & b->n_flag_mask);
+	} else {
+		diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
+		diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
+	}
+
+#undef NEIGH_DIFF
+
+	return diff;
+}
+
+static const struct trans_tbl neigh_attrs[] = {
+	__ADD(NEIGH_ATTR_FLAGS, flags)
+	__ADD(NEIGH_ATTR_STATE, state)
+	__ADD(NEIGH_ATTR_LLADDR, lladdr)
+	__ADD(NEIGH_ATTR_DST, dst)
+	__ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
+	__ADD(NEIGH_ATTR_IFINDEX, ifindex)
+	__ADD(NEIGH_ATTR_FAMILY, family)
+	__ADD(NEIGH_ATTR_TYPE, type)
+	__ADD(NEIGH_ATTR_PROBES, probes)
+};
+
+static char *neigh_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, neigh_attrs,
+			   ARRAY_SIZE(neigh_attrs));
+}
+
+static struct nla_policy neigh_policy[NDA_MAX+1] = {
+	[NDA_CACHEINFO]	= { .minlen = sizeof(struct nda_cacheinfo) },
+	[NDA_PROBES]	= { .type = NLA_U32 },
+};
+
+static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			    struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+	struct rtnl_neigh *neigh;
+	struct nlattr *tb[NDA_MAX + 1];
+	struct ndmsg *nm;
+	int err;
+
+	neigh = rtnl_neigh_alloc();
+	if (!neigh) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	neigh->ce_msgtype = n->nlmsg_type;
+	nm = nlmsg_data(n);
+
+	err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
+	if (err < 0)
+		goto errout;
+
+	neigh->n_family  = nm->ndm_family;
+	neigh->n_ifindex = nm->ndm_ifindex;
+	neigh->n_state   = nm->ndm_state;
+	neigh->n_flags   = nm->ndm_flags;
+	neigh->n_type    = nm->ndm_type;
+
+	neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
+			   NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
+			   NEIGH_ATTR_TYPE);
+
+	if (tb[NDA_LLADDR]) {
+		neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
+		if (!neigh->n_lladdr) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+		nl_addr_set_family(neigh->n_lladdr,
+				   nl_addr_guess_family(neigh->n_lladdr));
+		neigh->ce_mask |= NEIGH_ATTR_LLADDR;
+	}
+
+	if (tb[NDA_DST]) {
+		neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
+		if (!neigh->n_dst) {
+			err = -NLE_NOMEM;
+			goto errout;
+		}
+		neigh->ce_mask |= NEIGH_ATTR_DST;
+	}
+
+	if (tb[NDA_CACHEINFO]) {
+		struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
+
+		neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
+		neigh->n_cacheinfo.nci_used = ci->ndm_used;
+		neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
+		neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
+		
+		neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
+	}
+
+	if (tb[NDA_PROBES]) {
+		neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
+		neigh->ce_mask |= NEIGH_ATTR_PROBES;
+	}
+
+	err = pp->pp_cb((struct nl_object *) neigh, pp);
+errout:
+	rtnl_neigh_put(neigh);
+	return err;
+}
+
+static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
+}
+
+
+static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+	char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
+	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
+	struct nl_cache *link_cache;
+	char state[128], flags[64];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
+
+	if (link_cache)
+		nl_dump(p, "dev %s ",
+			rtnl_link_i2name(link_cache, n->n_ifindex,
+					 state, sizeof(state)));
+	else
+		nl_dump(p, "dev %d ", n->n_ifindex);
+
+	if (n->ce_mask & NEIGH_ATTR_LLADDR)
+		nl_dump(p, "lladdr %s ",
+			nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
+
+	rtnl_neigh_state2str(n->n_state, state, sizeof(state));
+	rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
+
+	if (state[0])
+		nl_dump(p, "<%s", state);
+	if (flags[0])
+		nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
+	if (state[0] || flags[0])
+		nl_dump(p, ">");
+	nl_dump(p, "\n");
+}
+
+static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+	char rtn_type[32];
+	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
+	int hz = nl_get_user_hz();
+
+	neigh_dump_line(a, p);
+
+	nl_dump_line(p, "    refcnt %u type %s confirmed %u used "
+				"%u updated %u\n",
+		n->n_cacheinfo.nci_refcnt,
+		nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
+		n->n_cacheinfo.nci_confirmed/hz,
+		n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
+}
+
+static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+	neigh_dump_details(a, p);
+}
+
+/**
+ * @name Neighbour Object Allocation/Freeage
+ * @{
+ */
+
+struct rtnl_neigh *rtnl_neigh_alloc(void)
+{
+	return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
+}
+
+void rtnl_neigh_put(struct rtnl_neigh *neigh)
+{
+	nl_object_put((struct nl_object *) neigh);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Cache Managament
+ * @{
+ */
+
+/**
+ * Build a neighbour cache including all neighbours currently configured in the kernel.
+ * @arg sock		Netlink socket.
+ * @arg result		Pointer to store resulting cache.
+ *
+ * Allocates a new neighbour cache, initializes it properly and updates it
+ * to include all neighbours currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
+}
+
+/**
+ * Look up a neighbour by interface index and destination address
+ * @arg cache		neighbour cache
+ * @arg ifindex		interface index the neighbour is on
+ * @arg dst		destination address of the neighbour
+ * @return neighbour handle or NULL if no match was found.
+ */
+struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
+				   struct nl_addr *dst)
+{
+	struct rtnl_neigh *neigh;
+
+	nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
+		if (neigh->n_ifindex == ifindex &&
+		    !nl_addr_cmp(neigh->n_dst, dst)) {
+			nl_object_get((struct nl_object *) neigh);
+			return neigh;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Addition
+ * @{
+ */
+
+static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
+			   struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct ndmsg nhdr = {
+		.ndm_ifindex = tmpl->n_ifindex,
+		.ndm_state = NUD_PERMANENT,
+	};
+
+	if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
+		return -NLE_MISSING_ATTR;
+
+	nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
+
+	if (tmpl->ce_mask & NEIGH_ATTR_FLAGS)
+		nhdr.ndm_flags = tmpl->n_flags;
+
+	if (tmpl->ce_mask & NEIGH_ATTR_STATE)
+		nhdr.ndm_state = tmpl->n_state;
+
+	msg = nlmsg_alloc_simple(cmd, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
+
+	if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
+		NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Build netlink request message to add a new neighbour
+ * @arg tmpl		template with data of new neighbour
+ * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting a addition of a new
+ * neighbour. The netlink message header isn't fully equipped with
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a tmpl must contain the attributes of the new
+ * neighbour set via \c rtnl_neigh_set_* functions.
+ * 
+ * The following attributes must be set in the template:
+ *  - Interface index (rtnl_neigh_set_ifindex())
+ *  - State (rtnl_neigh_set_state())
+ *  - Destination address (rtnl_neigh_set_dst())
+ *  - Link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
+				 struct nl_msg **result)
+{
+	return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
+}
+
+/**
+ * Add a new neighbour
+ * @arg sk		Netlink socket.
+ * @arg tmpl		template with requested changes
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_neigh_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * The following attributes must be set in the template:
+ *  - Interface index (rtnl_neigh_set_ifindex())
+ *  - State (rtnl_neigh_set_state())
+ *  - Destination address (rtnl_neigh_set_dst())
+ *  - Link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
+{
+	int err;
+	struct nl_msg *msg;
+	
+	if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink request message to delete a neighbour
+ * @arg neigh		neighbour to delete
+ * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting a deletion of a neighbour.
+ * The netlink message header isn't fully equipped with all relevant
+ * fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a neigh must point to an existing
+ * neighbour.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
+				    struct nl_msg **result)
+{
+	return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
+}
+
+/**
+ * Delete a neighbour
+ * @arg sk		Netlink socket.
+ * @arg neigh		neighbour to delete
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_neigh_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
+		      int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour States Translations
+ * @{
+ */
+
+static const struct trans_tbl neigh_states[] = {
+	__ADD(NUD_INCOMPLETE, incomplete)
+	__ADD(NUD_REACHABLE, reachable)
+	__ADD(NUD_STALE, stale)
+	__ADD(NUD_DELAY, delay)
+	__ADD(NUD_PROBE, probe)
+	__ADD(NUD_FAILED, failed)
+	__ADD(NUD_NOARP, norarp)
+	__ADD(NUD_PERMANENT, permanent)
+};
+
+char * rtnl_neigh_state2str(int state, char *buf, size_t len)
+{
+	return __flags2str(state, buf, len, neigh_states,
+	    ARRAY_SIZE(neigh_states));
+}
+
+int rtnl_neigh_str2state(const char *name)
+{
+	return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl neigh_flags[] = {
+	__ADD(NTF_USE, use)
+	__ADD(NTF_PROXY, proxy)
+	__ADD(NTF_ROUTER, router)
+};
+
+char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, neigh_flags,
+	    ARRAY_SIZE(neigh_flags));
+}
+
+int rtnl_neigh_str2flag(const char *name)
+{
+	return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
+{
+	neigh->n_state_mask |= state;
+	neigh->n_state |= state;
+	neigh->ce_mask |= NEIGH_ATTR_STATE;
+}
+
+int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
+{
+	if (neigh->ce_mask & NEIGH_ATTR_STATE)
+		return neigh->n_state;
+	else
+		return -1;
+}
+
+void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
+{
+	neigh->n_state_mask |= state;
+	neigh->n_state &= ~state;
+	neigh->ce_mask |= NEIGH_ATTR_STATE;
+}
+
+void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
+{
+	neigh->n_flag_mask |= flags;
+	neigh->n_flags |= flags;
+	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
+}
+
+unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
+{
+	return neigh->n_flags;
+}
+
+void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
+{
+	neigh->n_flag_mask |= flags;
+	neigh->n_flags &= ~flags;
+	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
+}
+
+void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
+{
+	neigh->n_ifindex = ifindex;
+	neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
+}
+
+int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
+{
+	return neigh->n_ifindex;
+}
+
+static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
+			        struct nl_addr *new, int flag, int nocheck)
+{
+	if (!nocheck) {
+		if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
+			if (new->a_family != neigh->n_family)
+				return -NLE_AF_MISMATCH;
+		} else {
+			neigh->n_family = new->a_family;
+			neigh->ce_mask |= NEIGH_ATTR_FAMILY;
+		}
+	}
+
+	if (*pos)
+		nl_addr_put(*pos);
+
+	nl_addr_get(new);
+	*pos = new;
+
+	neigh->ce_mask |= flag;
+
+	return 0;
+}
+
+void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
+{
+	__assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
+}
+
+struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
+{
+	if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
+		return neigh->n_lladdr;
+	else
+		return NULL;
+}
+
+int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
+{
+	return __assign_addr(neigh, &neigh->n_dst, addr,
+			     NEIGH_ATTR_DST, 0);
+}
+
+struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
+{
+	if (neigh->ce_mask & NEIGH_ATTR_DST)
+		return neigh->n_dst;
+	else
+		return NULL;
+}
+
+void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
+{
+	neigh->n_family = family;
+	neigh->ce_mask |= NEIGH_ATTR_FAMILY;
+}
+
+int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
+{
+	return neigh->n_family;
+}
+
+void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
+{
+	neigh->n_type = type;
+	neigh->ce_mask = NEIGH_ATTR_TYPE;
+}
+
+int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
+{
+	if (neigh->ce_mask & NEIGH_ATTR_TYPE)
+		return neigh->n_type;
+	else
+		return -1;
+}
+
+/** @} */
+
+static struct nl_object_ops neigh_obj_ops = {
+	.oo_name		= "route/neigh",
+	.oo_size		= sizeof(struct rtnl_neigh),
+	.oo_free_data		= neigh_free_data,
+	.oo_clone		= neigh_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= neigh_dump_line,
+	    [NL_DUMP_DETAILS]	= neigh_dump_details,
+	    [NL_DUMP_STATS]	= neigh_dump_stats,
+	},
+	.oo_compare		= neigh_compare,
+	.oo_attrs2str		= neigh_attrs2str,
+	.oo_id_attrs		= (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
+};
+
+static struct nl_af_group neigh_groups[] = {
+	{ AF_UNSPEC, RTNLGRP_NEIGH },
+	{ END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_neigh_ops = {
+	.co_name		= "route/neigh",
+	.co_hdrsize		= sizeof(struct ndmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWNEIGH, NL_ACT_NEW, "new" },
+					{ RTM_DELNEIGH, NL_ACT_DEL, "del" },
+					{ RTM_GETNEIGH, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_groups		= neigh_groups,
+	.co_request_update	= neigh_request_update,
+	.co_msg_parser		= neigh_msg_parser,
+	.co_obj_ops		= &neigh_obj_ops,
+};
+
+static void __init neigh_init(void)
+{
+	nl_cache_mngt_register(&rtnl_neigh_ops);
+}
+
+static void __exit neigh_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_neigh_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/neightbl.c b/libnetwork/libnl3/lib/route/neightbl.c
new file mode 100644
index 0000000..9599faa
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/neightbl.c
@@ -0,0 +1,815 @@
+/*
+ * lib/route/neightbl.c         neighbour tables
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup neightbl Neighbour Tables
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/neightbl.h>
+#include <netlink/route/link.h>
+
+/** @cond SKIP */
+#define NEIGHTBL_ATTR_FAMILY       0x001
+#define NEIGHTBL_ATTR_STATS        0x002
+#define NEIGHTBL_ATTR_NAME	  0x004
+#define NEIGHTBL_ATTR_THRESH1	  0x008
+#define NEIGHTBL_ATTR_THRESH2	  0x010
+#define NEIGHTBL_ATTR_THRESH3	  0x020
+#define NEIGHTBL_ATTR_CONFIG	  0x040
+#define NEIGHTBL_ATTR_PARMS	  0x080
+#define NEIGHTBL_ATTR_GC_INTERVAL  0x100
+
+#define NEIGHTBLPARM_ATTR_IFINDEX	0x0001
+#define NEIGHTBLPARM_ATTR_REFCNT		0x0002
+#define NEIGHTBLPARM_ATTR_QUEUE_LEN	0x0004
+#define NEIGHTBLPARM_ATTR_APP_PROBES	0x0008
+#define NEIGHTBLPARM_ATTR_UCAST_PROBES	0x0010
+#define NEIGHTBLPARM_ATTR_MCAST_PROBES	0x0020
+#define NEIGHTBLPARM_ATTR_PROXY_QLEN	0x0040
+#define NEIGHTBLPARM_ATTR_REACHABLE_TIME	0x0080
+#define NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME 0x0100
+#define NEIGHTBLPARM_ATTR_RETRANS_TIME	0x0200
+#define NEIGHTBLPARM_ATTR_GC_STALETIME	0x0400
+#define NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME 0x0800
+#define NEIGHTBLPARM_ATTR_ANYCAST_DELAY	0x1000
+#define NEIGHTBLPARM_ATTR_PROXY_DELAY	0x2000
+#define NEIGHTBLPARM_ATTR_LOCKTIME	0x4000
+
+static struct nl_cache_ops rtnl_neightbl_ops;
+static struct nl_object_ops neightbl_obj_ops;
+/** @endcond */
+
+static int neightbl_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_neightbl *a = (struct rtnl_neightbl *) _a;
+	struct rtnl_neightbl *b = (struct rtnl_neightbl *) _b;
+	int diff = 0;
+
+#define NT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGHTBL_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= NT_DIFF(FAMILY,		a->nt_family != b->nt_family);
+	diff |= NT_DIFF(NAME,		strcmp(a->nt_name, b->nt_name));
+	diff |= NT_DIFF(THRESH1,	a->nt_gc_thresh1 != b->nt_gc_thresh1);
+	diff |= NT_DIFF(THRESH2,	a->nt_gc_thresh2 != b->nt_gc_thresh2);
+	diff |= NT_DIFF(THRESH3,	a->nt_gc_thresh3 != b->nt_gc_thresh3);
+	diff |= NT_DIFF(GC_INTERVAL,	a->nt_gc_interval != b->nt_gc_interval);
+
+#undef NT_DIFF
+
+	if (!(a->ce_mask & NEIGHTBL_ATTR_PARMS) &&
+	    !(b->ce_mask & NEIGHTBL_ATTR_PARMS))
+		return diff;
+
+	/* XXX: FIXME: Compare parameter table */
+
+
+#if 0
+#define REQ(F) (fp->ntp_mask & NEIGHTBLPARM_ATTR_##F)
+#define AVAIL(F) (op->ntp_mask & NEIGHTBLPARM_ATTR_##F)
+#define _C(F, N) (REQ(F) && (!AVAIL(F) || (op->N != fp->N)))
+	if (_C(IFINDEX,			ntp_ifindex)			||
+	    _C(QUEUE_LEN,		ntp_queue_len)			||
+	    _C(APP_PROBES,		ntp_app_probes)			||
+	    _C(UCAST_PROBES,		ntp_ucast_probes)		||
+	    _C(MCAST_PROBES,		ntp_mcast_probes)		||
+	    _C(PROXY_QLEN,		ntp_proxy_qlen)			||
+	    _C(LOCKTIME,		ntp_locktime)			||
+	    _C(RETRANS_TIME,		ntp_retrans_time)		||
+	    _C(BASE_REACHABLE_TIME,	ntp_base_reachable_time)	||
+	    _C(GC_STALETIME,		ntp_gc_stale_time)		||
+	    _C(DELAY_PROBE_TIME,	ntp_probe_delay)		||
+	    _C(ANYCAST_DELAY,		ntp_anycast_delay)		||
+	    _C(PROXY_DELAY,		ntp_proxy_delay))
+		return 0;
+#undef REQ
+#undef AVAIL
+#undef _C
+#endif
+
+	return diff;
+}
+
+
+static struct nla_policy neightbl_policy[NDTA_MAX+1] = {
+	[NDTA_NAME]		= { .type = NLA_STRING,
+				    .maxlen = NTBLNAMSIZ },
+	[NDTA_THRESH1]		= { .type = NLA_U32 },
+	[NDTA_THRESH2]		= { .type = NLA_U32 },
+	[NDTA_THRESH3]		= { .type = NLA_U32 },
+	[NDTA_GC_INTERVAL]	= { .type = NLA_U32 },
+	[NDTA_CONFIG]		= { .minlen = sizeof(struct ndt_config) },
+	[NDTA_STATS]		= { .minlen = sizeof(struct ndt_stats) },
+	[NDTA_PARMS]		= { .type = NLA_NESTED },
+};
+
+static int neightbl_msg_parser(struct nl_cache_ops *ops,
+			       struct sockaddr_nl *who, struct nlmsghdr *n,
+			       struct nl_parser_param *pp)
+{
+	struct rtnl_neightbl *ntbl;
+	struct nlattr *tb[NDTA_MAX + 1];
+	struct rtgenmsg *rtmsg;
+	int err;
+
+	ntbl = rtnl_neightbl_alloc();
+	if (!ntbl) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	ntbl->ce_msgtype = n->nlmsg_type;
+	rtmsg = nlmsg_data(n);
+	
+	err = nlmsg_parse(n, sizeof(*rtmsg), tb, NDTA_MAX, neightbl_policy);
+	if (err < 0)
+		goto errout;
+
+	ntbl->nt_family = rtmsg->rtgen_family;
+
+	if (tb[NDTA_NAME] == NULL) {
+		return -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	nla_strlcpy(ntbl->nt_name, tb[NDTA_NAME], NTBLNAMSIZ);
+	ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
+
+	if (tb[NDTA_THRESH1]) {
+		ntbl->nt_gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
+		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
+	}
+
+	if (tb[NDTA_THRESH2]) {
+		ntbl->nt_gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
+		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
+	}
+
+	if (tb[NDTA_THRESH3]) {
+		ntbl->nt_gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
+		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
+	}
+
+	if (tb[NDTA_GC_INTERVAL]) {
+		ntbl->nt_gc_interval = nla_get_u32(tb[NDTA_GC_INTERVAL]);
+		ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
+	}
+
+	if (tb[NDTA_CONFIG]) {
+		nla_memcpy(&ntbl->nt_config, tb[NDTA_CONFIG],
+			   sizeof(ntbl->nt_config));
+		ntbl->ce_mask |= NEIGHTBL_ATTR_CONFIG;
+	}
+
+	if (tb[NDTA_STATS]) {
+		nla_memcpy(&ntbl->nt_stats, tb[NDTA_STATS],
+			   sizeof(ntbl->nt_stats));
+		ntbl->ce_mask |= NEIGHTBL_ATTR_STATS;
+	}
+
+	if (tb[NDTA_PARMS]) {
+		struct nlattr *tbp[NDTPA_MAX + 1];
+		struct rtnl_neightbl_parms *p = &ntbl->nt_parms;
+
+		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], NULL);
+		if (err < 0)
+			goto errout;
+
+#define COPY_ENTRY(name, var) \
+		if (tbp[NDTPA_ ##name]) { \
+			p->ntp_ ##var = nla_get_u32(tbp[NDTPA_ ##name]); \
+			p->ntp_mask |= NEIGHTBLPARM_ATTR_ ##name; \
+		}
+
+		COPY_ENTRY(IFINDEX, ifindex);
+		COPY_ENTRY(REFCNT, refcnt);
+		COPY_ENTRY(QUEUE_LEN, queue_len);
+		COPY_ENTRY(APP_PROBES, app_probes);
+		COPY_ENTRY(UCAST_PROBES, ucast_probes);
+		COPY_ENTRY(MCAST_PROBES, mcast_probes);
+		COPY_ENTRY(PROXY_QLEN, proxy_qlen);
+		COPY_ENTRY(PROXY_DELAY, proxy_delay);
+		COPY_ENTRY(ANYCAST_DELAY, anycast_delay);
+		COPY_ENTRY(LOCKTIME, locktime);
+		COPY_ENTRY(REACHABLE_TIME, reachable_time);
+		COPY_ENTRY(BASE_REACHABLE_TIME, base_reachable_time);
+		COPY_ENTRY(RETRANS_TIME, retrans_time);
+		COPY_ENTRY(GC_STALETIME, gc_stale_time);
+		COPY_ENTRY(DELAY_PROBE_TIME, probe_delay);
+#undef COPY_ENTRY
+
+		ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+	}
+
+	err = pp->pp_cb((struct nl_object *) ntbl, pp);
+errout:
+	rtnl_neightbl_put(ntbl);
+	return err;
+}
+
+static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP);
+}
+
+
+static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
+{
+	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+	nl_dump_line(p, "%s", ntbl->nt_name);
+
+	if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) {
+		struct nl_cache *link_cache;
+		
+		link_cache = nl_cache_mngt_require("route/link");
+
+		if (link_cache) {
+			char buf[32];
+			nl_dump(p, "<%s> ",
+				rtnl_link_i2name(link_cache,
+						 ntbl->nt_parms.ntp_ifindex,
+						 buf, sizeof(buf)));
+		} else
+			nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex);
+	} else
+		nl_dump(p, " ");
+
+	if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG)
+		nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries);
+
+	if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
+		char rt[32], rt2[32];
+		struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
+
+		nl_dump(p, "reachable-time %s retransmit-time %s",
+			nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)),
+			nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2)));
+	}
+
+	nl_dump(p, "\n");
+}
+
+static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p)
+{
+	char x[32], y[32], z[32];
+	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+	neightbl_dump_line(arg, p);
+
+	if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) {
+		nl_dump_line(p, "    key-len %u entry-size %u last-flush %s\n",
+			ntbl->nt_config.ndtc_key_len,
+			ntbl->nt_config.ndtc_entry_size,
+			nl_msec2str(ntbl->nt_config.ndtc_last_flush,
+				      x, sizeof(x)));
+
+		nl_dump_line(p, "    gc threshold %u/%u/%u interval %s " \
+			    "chain-position %u\n",
+			ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
+			ntbl->nt_gc_thresh3,
+			nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
+			ntbl->nt_config.ndtc_hash_chain_gc);
+
+		nl_dump_line(p, "    hash-rand 0x%08X/0x%08X last-rand %s\n",
+			ntbl->nt_config.ndtc_hash_rnd,
+			ntbl->nt_config.ndtc_hash_mask,
+			nl_msec2str(ntbl->nt_config.ndtc_last_rand,
+				      x, sizeof(x)));
+	}
+
+	if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
+		struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
+
+		nl_dump_line(p, "    refcnt %u pending-queue-limit %u " \
+			    "proxy-delayed-queue-limit %u\n",
+			pa->ntp_refcnt,
+			pa->ntp_queue_len,
+			pa->ntp_proxy_qlen);
+
+		nl_dump_line(p, "    num-userspace-probes %u num-unicast-probes " \
+			    "%u num-multicast-probes %u\n",
+			pa->ntp_app_probes,
+			pa->ntp_ucast_probes,
+			pa->ntp_mcast_probes);
+
+		nl_dump_line(p, "    min-age %s base-reachable-time %s " \
+			    "stale-check-interval %s\n",
+			nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
+			nl_msec2str(pa->ntp_base_reachable_time,
+				      y, sizeof(y)),
+			nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
+
+		nl_dump_line(p, "    initial-probe-delay %s answer-delay %s " \
+			    "proxy-answer-delay %s\n",
+			nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
+			nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
+			nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
+	}
+}
+
+static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
+{
+	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+	neightbl_dump_details(arg, p);
+
+	if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS))
+		return;
+
+	nl_dump_line(p, "    lookups %lld hits %lld failed %lld " \
+		    "allocations %lld destroys %lld\n",
+		ntbl->nt_stats.ndts_lookups,
+		ntbl->nt_stats.ndts_hits,
+		ntbl->nt_stats.ndts_res_failed,
+		ntbl->nt_stats.ndts_allocs,
+		ntbl->nt_stats.ndts_destroys);
+
+	nl_dump_line(p, "    hash-grows %lld forced-gc-runs %lld " \
+		    "periodic-gc-runs %lld\n",
+		ntbl->nt_stats.ndts_hash_grows,
+		ntbl->nt_stats.ndts_forced_gc_runs,
+		ntbl->nt_stats.ndts_periodic_gc_runs);
+
+	nl_dump_line(p, "    rcv-unicast-probes %lld rcv-multicast-probes %lld\n",
+		ntbl->nt_stats.ndts_rcv_probes_ucast,
+		ntbl->nt_stats.ndts_rcv_probes_mcast);
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_neightbl *rtnl_neightbl_alloc(void)
+{
+	return (struct rtnl_neightbl *) nl_object_alloc(&neightbl_obj_ops);
+}
+
+void rtnl_neightbl_put(struct rtnl_neightbl *neightbl)
+{
+	nl_object_put((struct nl_object *) neightbl);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Table Cache Management
+ * @{
+ */
+
+/**
+ * Build a neighbour table cache including all neighbour tables currently configured in the kernel.
+ * @arg sk		Netlink socket.
+ * @arg result		Pointer to store resulting cache.
+ *
+ * Allocates a new neighbour table cache, initializes it properly and
+ * updates it to include all neighbour tables currently configured in
+ * the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result);
+}
+
+/**
+ * Lookup neighbour table by name and optional interface index
+ * @arg cache		neighbour table cache
+ * @arg name		name of table
+ * @arg ifindex		optional interface index
+ *
+ * Looks up the neighbour table matching the specified name and
+ * optionally the specified ifindex to retrieve device specific
+ * parameter sets.
+ *
+ * @return ptr to neighbour table inside the cache or NULL if no
+ *         match was found.
+ */
+struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
+					const char *name, int ifindex)
+{
+	struct rtnl_neightbl *nt;
+
+	if (cache->c_ops != &rtnl_neightbl_ops)
+		return NULL;
+
+	nl_list_for_each_entry(nt, &cache->c_items, ce_list) {
+		if (!strcasecmp(nt->nt_name, name) &&
+		    ((!ifindex && !nt->nt_parms.ntp_ifindex) ||
+		     (ifindex && ifindex == nt->nt_parms.ntp_ifindex))) {
+			nl_object_get((struct nl_object *) nt);
+			return nt;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Table Modifications
+ * @{
+ */
+
+/**
+ * Builds a netlink change request message to change neighbour table attributes
+ * @arg old		neighbour table to change
+ * @arg tmpl		template with requested changes
+ * @arg result		Pointer to store resulting message.
+ *
+ * Builds a new netlink message requesting a change of neighbour table
+ * attributes. The netlink message header isn't fully equipped with all
+ * relevant fields and must be sent out via nl_send_auto_complete() or
+ * supplemented as needed.
+ * \a old must point to a neighbour table currently configured in the
+ * kernel and \a tmpl must contain the attributes to be changed set via
+ * \c rtnl_neightbl_set_* functions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
+				       struct rtnl_neightbl *tmpl,
+				       struct nl_msg **result)
+{
+	struct nl_msg *m, *parms = NULL;
+	struct ndtmsg ndt = {
+		.ndtm_family = old->nt_family,
+	};
+
+	m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0);
+	if (!m)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	NLA_PUT_STRING(m, NDTA_NAME, old->nt_name);
+
+	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1)
+		NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
+
+	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
+		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+
+	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
+		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+
+	if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL)
+		NLA_PUT_U64(m, NDTA_GC_INTERVAL,
+				      tmpl->nt_gc_interval);
+
+	if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) {
+		struct rtnl_neightbl_parms *p = &tmpl->nt_parms;
+
+		parms = nlmsg_alloc();
+		if (!parms)
+			goto nla_put_failure;
+
+		if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX)
+			NLA_PUT_U32(parms, NDTPA_IFINDEX,
+					      old->nt_parms.ntp_ifindex);
+
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN)
+			NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES)
+			NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES)
+			NLA_PUT_U32(parms, NDTPA_UCAST_PROBES,
+				    p->ntp_ucast_probes);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES)
+			NLA_PUT_U32(parms, NDTPA_MCAST_PROBES,
+				    p->ntp_mcast_probes);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN)
+			NLA_PUT_U32(parms, NDTPA_PROXY_QLEN,
+				    p->ntp_proxy_qlen);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME)
+			NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME,
+				    p->ntp_base_reachable_time);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME)
+			NLA_PUT_U64(parms, NDTPA_RETRANS_TIME,
+				    p->ntp_retrans_time);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME)
+			NLA_PUT_U64(parms, NDTPA_GC_STALETIME,
+				    p->ntp_gc_stale_time);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME)
+			NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME,
+				    p->ntp_proxy_delay);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY)
+			NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY,
+				    p->ntp_anycast_delay);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY)
+			NLA_PUT_U64(parms, NDTPA_PROXY_DELAY,
+					      p->ntp_proxy_delay);
+
+		if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
+			NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
+
+		if (nla_put_nested(m, NDTA_PARMS, parms) < 0)
+			goto nla_put_failure;
+
+		nlmsg_free(parms);
+	}
+
+	*result = m;
+	return 0;
+
+nla_put_failure:
+	if (parms)
+		nlmsg_free(parms);
+	nlmsg_free(m);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Change neighbour table attributes
+ * @arg sk		Netlink socket.
+ * @arg old		neighbour table to be changed
+ * @arg tmpl		template with requested changes
+ *
+ * Builds a new netlink message by calling
+ * rtnl_neightbl_build_change_request(), sends the request to the
+ * kernel and waits for the next ACK to be received, i.e. blocks
+ * until the request has been processed.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old,
+			 struct rtnl_neightbl *tmpl)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+void rtnl_neightbl_set_family(struct rtnl_neightbl *ntbl, int family)
+{
+	ntbl->nt_family = family;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_FAMILY;
+}
+
+void rtnl_neightbl_set_gc_interval(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_gc_interval = ms;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
+}
+
+void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *ntbl, int thresh)
+{
+	ntbl->nt_gc_thresh1 = thresh;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
+}
+
+void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *ntbl, int thresh)
+{
+	ntbl->nt_gc_thresh2 = thresh;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
+}
+
+void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *ntbl, int thresh)
+{
+	ntbl->nt_gc_thresh3 = thresh;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
+}
+
+void rtnl_neightbl_set_name(struct rtnl_neightbl *ntbl, const char *name)
+{
+	strncpy(ntbl->nt_name, name, sizeof(ntbl->nt_name) - 1);
+	ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
+}
+
+void rtnl_neightbl_set_dev(struct rtnl_neightbl *ntbl, int ifindex)
+{
+	ntbl->nt_parms.ntp_ifindex = ifindex;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_IFINDEX;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the queue length for pending requests of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg len		new queue len
+ */
+void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *ntbl, int len)
+{
+	ntbl->nt_parms.ntp_queue_len = len;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_QUEUE_LEN;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the queue length for delay proxy arp requests of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg len		new queue len
+ */
+void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *ntbl, int len)
+{
+	ntbl->nt_parms.ntp_proxy_qlen = len;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_QLEN;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of application probes of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg probes		new probes value
+ */
+void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+	ntbl->nt_parms.ntp_app_probes = probes;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_APP_PROBES;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of unicast probes of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg probes		new probes value
+ */
+void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+	ntbl->nt_parms.ntp_ucast_probes = probes;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_UCAST_PROBES;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of multicast probes of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg probes		new probes value
+ */
+void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+	ntbl->nt_parms.ntp_mcast_probes = probes;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_MCAST_PROBES;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the base reachable time of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new base reachable time in milliseconds
+ */
+void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *ntbl,
+					   uint64_t ms)
+{
+	ntbl->nt_parms.ntp_base_reachable_time = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the retransmit time of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new retransmit time
+ */
+void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_retrans_time = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_RETRANS_TIME;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the gc stale time of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new gc stale time in milliseconds
+ */
+void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_gc_stale_time = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_GC_STALETIME;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the first probe delay time of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new first probe delay time in milliseconds
+ */
+void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_probe_delay = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the anycast delay of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new anycast delay in milliseconds
+ */
+void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_anycast_delay = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_ANYCAST_DELAY;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the proxy delay of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new proxy delay in milliseconds
+ */
+void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_proxy_delay = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_DELAY;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the locktime of a neighbour table to the specified value
+ * @arg ntbl		neighbour table to change
+ * @arg ms		new locktime in milliseconds
+ */
+void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+	ntbl->nt_parms.ntp_locktime = ms;
+	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_LOCKTIME;
+	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/** @} */
+
+static struct nl_object_ops neightbl_obj_ops = {
+	.oo_name		= "route/neightbl",
+	.oo_size		= sizeof(struct rtnl_neightbl),
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= neightbl_dump_line,
+	    [NL_DUMP_DETAILS]	= neightbl_dump_details,
+	    [NL_DUMP_STATS]	= neightbl_dump_stats,
+	},
+	.oo_compare		= neightbl_compare,
+};
+
+static struct nl_cache_ops rtnl_neightbl_ops = {
+	.co_name		= "route/neightbl",
+	.co_hdrsize		= sizeof(struct rtgenmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWNEIGHTBL, NL_ACT_NEW, "new" },
+					{ RTM_SETNEIGHTBL, NL_ACT_SET, "set" },
+					{ RTM_GETNEIGHTBL, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_request_update	= neightbl_request_update,
+	.co_msg_parser		= neightbl_msg_parser,
+	.co_obj_ops		= &neightbl_obj_ops,
+};
+
+static void __init neightbl_init(void)
+{
+	nl_cache_mngt_register(&rtnl_neightbl_ops);
+}
+
+static void __exit neightbl_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_neightbl_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/nexthop.c b/libnetwork/libnl3/lib/route/nexthop.c
new file mode 100644
index 0000000..48cbfcf
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/nexthop.c
@@ -0,0 +1,290 @@
+/*
+ * lib/route/nexthop.c	Routing Nexthop
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup route_obj
+ * @defgroup nexthop Nexthop
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+
+/** @cond SKIP */
+#define NH_ATTR_FLAGS   0x000001
+#define NH_ATTR_WEIGHT  0x000002
+#define NH_ATTR_IFINDEX 0x000004
+#define NH_ATTR_GATEWAY 0x000008
+#define NH_ATTR_REALMS  0x000010
+/** @endcond */
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_nexthop *rtnl_route_nh_alloc(void)
+{
+	struct rtnl_nexthop *nh;
+
+	nh = calloc(1, sizeof(*nh));
+	if (!nh)
+		return NULL;
+
+	nl_init_list_head(&nh->rtnh_list);
+
+	return nh;
+}
+
+struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
+{
+	struct rtnl_nexthop *nh;
+
+	nh = rtnl_route_nh_alloc();
+	if (!nh)
+		return NULL;
+
+	nh->rtnh_flags = src->rtnh_flags;
+	nh->rtnh_flag_mask = src->rtnh_flag_mask;
+	nh->rtnh_weight = src->rtnh_weight;
+	nh->rtnh_ifindex = src->rtnh_ifindex;
+	nh->ce_mask = src->ce_mask;
+
+	if (src->rtnh_gateway) {
+		nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
+		if (!nh->rtnh_gateway) {
+			free(nh);
+			return NULL;
+		}
+	}
+
+	return nh;
+}
+
+void rtnl_route_nh_free(struct rtnl_nexthop *nh)
+{
+	nl_addr_put(nh->rtnh_gateway);
+	free(nh);
+}
+
+/** @} */
+
+int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
+			  uint32_t attrs, int loose)
+{
+	int diff = 0;
+
+#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= NH_DIFF(IFINDEX,	a->rtnh_ifindex != b->rtnh_ifindex);
+	diff |= NH_DIFF(WEIGHT,		a->rtnh_weight != b->rtnh_weight);
+	diff |= NH_DIFF(REALMS,		a->rtnh_realms != b->rtnh_realms);
+	diff |= NH_DIFF(GATEWAY,	nl_addr_cmp(a->rtnh_gateway,
+						    b->rtnh_gateway));
+
+	if (loose)
+		diff |= NH_DIFF(FLAGS,
+			  (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
+	else
+		diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
+	
+#undef NH_DIFF
+
+	return diff;
+}
+
+static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+	struct nl_cache *link_cache;
+	char buf[128];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	nl_dump(dp, "via");
+
+	if (nh->ce_mask & NH_ATTR_GATEWAY)
+		nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
+						   buf, sizeof(buf)));
+
+	if(nh->ce_mask & NH_ATTR_IFINDEX) {
+		if (link_cache) {
+			nl_dump(dp, " dev %s",
+				rtnl_link_i2name(link_cache,
+						 nh->rtnh_ifindex,
+						 buf, sizeof(buf)));
+		} else
+			nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+	}
+
+	nl_dump(dp, " ");
+}
+
+static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+	struct nl_cache *link_cache;
+	char buf[128];
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	nl_dump(dp, "nexthop");
+
+	if (nh->ce_mask & NH_ATTR_GATEWAY)
+		nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
+						   buf, sizeof(buf)));
+
+	if(nh->ce_mask & NH_ATTR_IFINDEX) {
+		if (link_cache) {
+			nl_dump(dp, " dev %s",
+				rtnl_link_i2name(link_cache,
+						 nh->rtnh_ifindex,
+						 buf, sizeof(buf)));
+		} else
+			nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+	}
+
+	if (nh->ce_mask & NH_ATTR_WEIGHT)
+		nl_dump(dp, " weight %u", nh->rtnh_weight);
+
+	if (nh->ce_mask & NH_ATTR_REALMS)
+		nl_dump(dp, " realm %04x:%04x",
+			RTNL_REALM_FROM(nh->rtnh_realms),
+			RTNL_REALM_TO(nh->rtnh_realms));
+
+	if (nh->ce_mask & NH_ATTR_FLAGS)
+		nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
+							buf, sizeof(buf)));
+}
+
+void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+	switch (dp->dp_type) {
+	case NL_DUMP_LINE:
+		nh_dump_line(nh, dp);
+		break;
+
+	case NL_DUMP_DETAILS:
+	case NL_DUMP_STATS:
+		if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
+			nh_dump_details(nh, dp);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
+{
+	nh->rtnh_weight = weight;
+	nh->ce_mask |= NH_ATTR_WEIGHT;
+}
+
+uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
+{
+	return nh->rtnh_weight;
+}
+
+void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
+{
+	nh->rtnh_ifindex = ifindex;
+	nh->ce_mask |= NH_ATTR_IFINDEX;
+}
+
+int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
+{
+	return nh->rtnh_ifindex;
+}	
+
+void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
+{
+	struct nl_addr *old = nh->rtnh_gateway;
+
+	if (addr) {
+		nh->rtnh_gateway = nl_addr_get(addr);
+		nh->ce_mask |= NH_ATTR_GATEWAY;
+	} else {
+		nh->ce_mask &= ~NH_ATTR_GATEWAY;
+		nh->rtnh_gateway = NULL;
+	}
+
+	if (old)
+		nl_addr_put(old);
+}
+
+struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
+{
+	return nh->rtnh_gateway;
+}
+
+void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
+{
+	nh->rtnh_flag_mask |= flags;
+	nh->rtnh_flags |= flags;
+	nh->ce_mask |= NH_ATTR_FLAGS;
+}
+
+void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
+{
+	nh->rtnh_flag_mask |= flags;
+	nh->rtnh_flags &= ~flags;
+	nh->ce_mask |= NH_ATTR_FLAGS;
+}
+
+unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
+{
+	return nh->rtnh_flags;
+}
+
+void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
+{
+	nh->rtnh_realms = realms;
+	nh->ce_mask |= NH_ATTR_REALMS;
+}
+
+uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
+{
+	return nh->rtnh_realms;
+}
+
+/** @} */
+
+/**
+ * @name Nexthop Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl nh_flags[] = {
+	__ADD(RTNH_F_DEAD, dead)
+	__ADD(RTNH_F_PERVASIVE, pervasive)
+	__ADD(RTNH_F_ONLINK, onlink)
+};
+
+char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
+{
+	return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
+}
+
+int rtnl_route_nh_str2flags(const char *name)
+{
+	return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/pktloc.c b/libnetwork/libnl3/lib/route/pktloc.c
new file mode 100644
index 0000000..e7dffe5
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/pktloc.c
@@ -0,0 +1,260 @@
+/*
+ * lib/route/pktloc.c     Packet Location Aliasing
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup pktloc Packet Location Aliasing
+ * Packet Location Aliasing
+ *
+ * The packet location aliasing interface eases the use of offset definitions
+ * inside packets by allowing them to be referenced by name. Known positions
+ * of protocol fields are stored in a configuration file and associated with
+ * a name for later reference. The configuration file is distributed with the
+ * library and provides a well defined set of definitions for most common
+ * protocol fields.
+ *
+ * @section pktloc_examples Examples
+ * @par Example 1.1 Looking up a packet location
+ * @code
+ * struct rtnl_pktloc *loc;
+ *
+ * rtnl_pktloc_lookup("ip.src", &loc);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+
+#include "pktloc_syntax.h"
+#include "pktloc_grammar.h"
+
+/** @cond SKIP */
+#define PKTLOC_NAME_HT_SIZ 256
+
+static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
+
+/* djb2 */
+static unsigned int pktloc_hash(const char *str)
+{
+	unsigned long hash = 5381;
+	int c;
+
+	while ((c = *str++))
+		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+	return hash % PKTLOC_NAME_HT_SIZ;
+}
+
+static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result)
+{
+	struct rtnl_pktloc *loc;
+	int hash;
+
+	hash = pktloc_hash(name);
+	nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
+		if (!strcasecmp(loc->name, name)) {
+			loc->refcnt++;
+			*result = loc;
+			return 0;
+		}
+	}
+
+	return -NLE_OBJ_NOTFOUND;
+}
+
+extern int pktloc_parse(void *scanner);
+
+static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
+{
+	if (!loc)
+		return;
+
+	free(loc->name);
+	free(loc);
+}
+
+static int read_pktlocs(void)
+{
+	YY_BUFFER_STATE buf = NULL;
+	yyscan_t scanner = NULL;
+	static time_t last_read;
+	struct stat st = {0};
+	char *path;
+	int i, err;
+	FILE *fd;
+
+	if (build_sysconf_path(&path, "pktloc") < 0)
+		return -NLE_NOMEM;
+
+	/* if stat fails, just try to read the file */
+	if (stat(path, &st) == 0) {
+		/* Don't re-read file if file is unchanged */
+		if (last_read == st.st_mtime)
+			return 0;
+	}
+
+	NL_DBG(2, "Reading packet location file \"%s\"\n", path);
+
+	if (!(fd = fopen(path, "r"))) {
+		err = -NLE_PKTLOC_FILE;
+		goto errout;
+	}
+
+	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
+		struct rtnl_pktloc *loc, *n;
+
+		nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
+			rtnl_pktloc_put(loc);
+
+		nl_init_list_head(&pktloc_name_ht[i]);
+	}
+
+	if ((err = pktloc_lex_init(&scanner)) < 0) {
+		err = -NLE_FAILURE;
+		goto errout_close;
+	}
+
+	buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
+	pktloc__switch_to_buffer(buf, scanner);
+
+	if ((err = pktloc_parse(scanner)) != 0) {
+		pktloc__delete_buffer(buf, scanner);
+		err = -NLE_PARSE_ERR;
+		goto errout_scanner;
+	}
+
+	last_read = st.st_mtime;
+
+errout_scanner:
+	if (scanner)
+		pktloc_lex_destroy(scanner);
+errout_close:
+	fclose(fd);
+errout:
+	free(path);
+
+	return 0;
+}
+
+/** @endcond */
+
+/**
+ * Lookup packet location alias
+ * @arg name		Name of packet location.
+ * @arg result		Result pointer
+ *
+ * Tries to find a matching packet location alias for the supplied
+ * packet location name.
+ *
+ * The file containing the packet location definitions is automatically
+ * re-read if its modification time has changed since the last call.
+ *
+ * The returned packet location has to be returned after use by calling
+ * rtnl_pktloc_put() in order to allow freeing its memory after the last
+ * user has abandoned it.
+ *
+ * @return 0 on success or a negative error code.
+ * @retval NLE_PKTLOC_FILE Unable to open packet location file.
+ * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
+ */
+int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
+{
+	int err;
+
+	if ((err = read_pktlocs()) < 0)
+		return err;
+	
+	return __pktloc_lookup(name, result);
+}
+
+/**
+ * Allocate packet location object
+ */
+struct rtnl_pktloc *rtnl_pktloc_alloc(void)
+{
+	struct rtnl_pktloc *loc;
+
+	if (!(loc = calloc(1, sizeof(*loc))))
+		return NULL;
+
+	loc->refcnt = 1;
+	nl_init_list_head(&loc->list);
+
+	return loc;
+}
+
+/**
+ * Return reference of a packet location
+ * @arg loc		packet location object.
+ */
+void rtnl_pktloc_put(struct rtnl_pktloc *loc)
+{
+	if (!loc)
+		return;
+
+	loc->refcnt--;
+	if (loc->refcnt <= 0)
+		rtnl_pktloc_free(loc);
+}
+
+/**
+ * Add a packet location to the hash table
+ * @arg loc		packet location object
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_pktloc_add(struct rtnl_pktloc *loc)
+{
+	struct rtnl_pktloc *l;
+
+	if (__pktloc_lookup(loc->name, &l) == 0) {
+		rtnl_pktloc_put(l);
+		return -NLE_EXIST;
+	}
+
+	NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u "
+		  "offset=%u mask=%#x shift=%u refnt=%u\n",
+		  loc->name, loc->align, loc->layer, loc->offset,
+		  loc->mask, loc->shift, loc->refcnt);
+
+	nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
+
+	return 0;
+}
+
+void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg)
+{
+	struct rtnl_pktloc *loc;
+	int i;
+
+	/* ignore errors */
+	read_pktlocs();
+
+	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
+		nl_list_for_each_entry(loc, &pktloc_name_ht[i], list)
+			cb(loc, arg);
+}
+
+static int __init pktloc_init(void)
+{
+	int i;
+
+	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
+		nl_init_list_head(&pktloc_name_ht[i]);
+	
+	return 0;
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/pktloc_grammar.l b/libnetwork/libnl3/lib/route/pktloc_grammar.l
new file mode 100644
index 0000000..6b7a933
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/pktloc_grammar.l
@@ -0,0 +1,51 @@
+%{
+ #include <netlink-local.h>
+ #include <netlink-tc.h>
+ #include <netlink/netlink.h>
+ #include <netlink/utils.h>
+ #include <netlink/route/pktloc.h>
+ #include "pktloc_syntax.h"
+%}
+
+%option 8bit
+%option reentrant
+%option warn
+%option noyywrap
+%option noinput
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option prefix="pktloc_"
+
+%%
+
+[ \t\r\n]+
+
+"#".*
+
+[[:digit:]]+		|
+0[xX][[:xdigit:]]+	{
+				yylval->i = strtoul(yytext, NULL, 0);
+				return NUMBER;
+			}
+
+"+"			{ return yylval->i = yytext[0]; }
+
+[uU]8			{ yylval->i = TCF_EM_ALIGN_U8; return ALIGN; }
+[uU]16			{ yylval->i = TCF_EM_ALIGN_U16; return ALIGN; }
+[uU]32			{ yylval->i = TCF_EM_ALIGN_U32; return ALIGN; }
+
+[lL][iI][nN][kK]	|
+[eE][tT][hH]		{ yylval->i = TCF_LAYER_LINK; return LAYER; }
+[nN][eE][tT]		|
+[iI][pP]		{ yylval->i = TCF_LAYER_NETWORK; return LAYER; }
+[tT][rR][aA][nN][sS][pP][oO][rR][tT] |
+[tT][cC][pP]		{ yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+
+
+[^ \t\r\n+]+		{
+				yylval->s = strdup(yytext);
+				if (yylval->s == NULL)
+					return ERROR;
+				return NAME;
+			}
diff --git a/libnetwork/libnl3/lib/route/pktloc_syntax.y b/libnetwork/libnl3/lib/route/pktloc_syntax.y
new file mode 100644
index 0000000..4a2ce48
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/pktloc_syntax.y
@@ -0,0 +1,103 @@
+%{
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+%}
+
+%locations
+%error-verbose
+%define api.pure
+%name-prefix "pktloc_"
+
+%parse-param {void *scanner}
+%lex-param {void *scanner}
+%expect 1
+
+%union {
+	struct rtnl_pktloc *l;
+	uint32_t i;
+	char *s;
+}
+
+%{
+extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *);
+
+static void yyerror(YYLTYPE *locp, void *scanner, const char *msg)
+{
+	NL_DBG(1, "Error while parsing packet location file: %s\n", msg);
+}
+%}
+
+%token <i> ERROR NUMBER LAYER ALIGN
+%token <s> NAME
+
+%type <i> mask layer align shift
+%type <l> location
+
+%destructor { free($$); } NAME
+
+%start input
+
+%%
+
+input:
+	/* empty */
+	| location input
+	;
+
+location:
+	NAME align layer NUMBER mask shift
+		{
+			struct rtnl_pktloc *loc;
+
+			if (!(loc = rtnl_pktloc_alloc())) {
+				NL_DBG(1, "Allocating a packet location "
+					  "object failed.\n");
+				YYABORT;
+			}
+
+			loc->name = $1;
+			loc->align = $2;
+			loc->layer = $3;
+			loc->offset = $4;
+			loc->mask = $5;
+			loc->shift = $6;
+
+			if (rtnl_pktloc_add(loc) < 0) {
+				NL_DBG(1, "Duplicate packet location entry "
+					  "\"%s\"\n", $1);
+			}
+
+			$$ = loc;
+		}
+	;
+
+align:
+	ALIGN
+		{ $$ = $1; }
+	| NUMBER
+		{ $$ = $1; }
+	;
+
+layer:
+	/* empty */
+		{ $$ = TCF_LAYER_NETWORK; }
+	| LAYER '+' 
+		{ $$ = $1; }
+	;
+
+mask:
+	/* empty */
+		{ $$ = 0; }
+	| NUMBER
+		{ $$ = $1; }
+	;
+
+shift:
+	/* empty */
+		{ $$ = 0; }
+	| NUMBER
+		{ $$ = $1; }
+	;
diff --git a/libnetwork/libnl3/lib/route/qdisc.c b/libnetwork/libnl3/lib/route/qdisc.c
new file mode 100644
index 0000000..e5a8aa0
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc.c
@@ -0,0 +1,575 @@
+/*
+ * lib/route/qdisc.c            Queueing Disciplines
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup qdisc Queueing Disciplines
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/link.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/classifier.h>
+
+static struct nl_cache_ops rtnl_qdisc_ops;
+static struct nl_object_ops qdisc_obj_ops;
+
+static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			    struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+	struct rtnl_qdisc *qdisc;
+	int err;
+
+	if (!(qdisc = rtnl_qdisc_alloc()))
+		return -NLE_NOMEM;
+
+	if ((err = rtnl_tc_msg_parse(n, TC_CAST(qdisc))) < 0)
+		goto errout;
+
+	err = pp->pp_cb(OBJ_CAST(qdisc), pp);
+errout:
+	rtnl_qdisc_put(qdisc);
+
+	return err;
+}
+
+static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk)
+{
+	struct tcmsg tchdr = {
+		.tcm_family = AF_UNSPEC,
+		.tcm_ifindex = c->c_iarg1,
+	};
+
+	return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
+			      sizeof(tchdr));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_qdisc *rtnl_qdisc_alloc(void)
+{
+	struct rtnl_tc *tc;
+
+	tc = TC_CAST(nl_object_alloc(&qdisc_obj_ops));
+	if (tc)
+		tc->tc_type = RTNL_TC_TYPE_QDISC;
+
+	return (struct rtnl_qdisc *) tc;
+}
+
+void rtnl_qdisc_put(struct rtnl_qdisc *qdisc)
+{
+	nl_object_put((struct nl_object *) qdisc);
+}
+
+/** @} */
+
+/**
+ * @name Addition / Modification / Deletion
+ * @{
+ */
+
+static int build_qdisc_msg(struct rtnl_qdisc *qdisc, int type, int flags,
+			   struct nl_msg **result)
+{
+	if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
+		APPBUG("ifindex must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result);
+}
+
+/**
+ * Build a netlink message requesting the addition of a qdisc
+ * @arg qdisc		Qdisc to add 
+ * @arg flags		Additional netlink message flags
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags,
+				 struct nl_msg **result)
+{
+	if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
+		APPBUG("handle or parent must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result);
+}
+
+/**
+ * Add qdisc
+ * @arg sk		Netlink socket
+ * @arg qdisc		Qdisc to add 
+ * @arg flags		Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the addition
+ * of a new qdisc and sends the message to the kernel. The configuration
+ * of the qdisc is derived from the attributes of the specified qdisc.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create qdisc if it does not exist, otherwise 
+ *                      -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_REPLACE: If another qdisc is already attached to the
+ *                      parent, replace it even if the handles mismatch.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a qdisc with matching
+ *                      handle exists already.
+ *
+ * Existing qdiscs with matching handles will be updated, unless the
+ * flag \c NLM_F_EXCL is specified. If their handles do not match, the
+ * error -NLE_EXISTS is returned unless the flag \c NLM_F_REPLACE is
+ * specified in which case the existing qdisc is replaced with the new
+ * one.  If no matching qdisc exists, it will be created if the flag
+ * \c NLM_F_CREATE is set, otherwise the error -NLE_OBJ_NOTFOUND is
+ * returned. 
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the update of a qdisc
+ * @arg qdisc		Qdisc to update
+ * @arg new		Qdisc with updated attributes
+ * @arg flags		Additional netlink message flags
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_update() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_update()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_update_request(struct rtnl_qdisc *qdisc,
+				    struct rtnl_qdisc *new, int flags,
+				    struct nl_msg **result)
+{
+	if (flags & (NLM_F_CREATE | NLM_F_EXCL)) {
+		APPBUG("NLM_F_CREATE and NLM_F_EXCL may not be used here, "
+		       "use rtnl_qdisc_add()");
+		return -NLE_INVAL;
+	}
+
+	if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
+		APPBUG("ifindex must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
+		APPBUG("handle or parent must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	rtnl_tc_set_ifindex(TC_CAST(new), qdisc->q_ifindex);
+
+	if (qdisc->ce_mask & TCA_ATTR_HANDLE)
+		rtnl_tc_set_handle(TC_CAST(new), qdisc->q_handle);
+
+	if (qdisc->ce_mask & TCA_ATTR_PARENT)
+		rtnl_tc_set_parent(TC_CAST(new), qdisc->q_parent);
+
+	return build_qdisc_msg(new, RTM_NEWQDISC, flags, result);
+}
+
+/**
+ * Update qdisc
+ * @arg sk		Netlink socket
+ * @arg qdisc		Qdisc to update
+ * @arg new		Qdisc with updated attributes
+ * @arg flags		Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the update
+ * of an existing qdisc and sends the message to the kernel.
+ *
+ * This function is a varation of rtnl_qdisc_add() to update qdiscs
+ * if the qdisc to be updated is available as qdisc object. The
+ * behaviour is identical to the one of rtnl_qdisc_add except that
+ * before constructing the message, it copies the \c ifindex,
+ * \c handle, and \c parent from the original \p qdisc to the \p new
+ * qdisc.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_update(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
+		      struct rtnl_qdisc *new, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	err = rtnl_qdisc_build_update_request(qdisc, new, flags, &msg);
+	if (err < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a qdisc
+ * @arg qdisc		Qdisc to delete
+ * @arg result		Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc,
+				    struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct tcmsg tchdr;
+	int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
+
+	if ((qdisc->ce_mask & required) != required) {
+		APPBUG("ifindex and parent must be specified");
+		return -NLE_MISSING_ATTR;
+	}
+
+	if (!(msg = nlmsg_alloc_simple(RTM_DELQDISC, 0)))
+		return -NLE_NOMEM;
+
+	memset(&tchdr, 0, sizeof(tchdr));
+
+	tchdr.tcm_family = AF_UNSPEC;
+	tchdr.tcm_ifindex = qdisc->q_ifindex;
+	tchdr.tcm_parent = qdisc->q_parent;
+
+	if (qdisc->ce_mask & TCA_ATTR_HANDLE)
+		tchdr.tcm_handle = qdisc->q_handle;
+
+	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (qdisc->ce_mask & TCA_ATTR_KIND)
+		NLA_PUT_STRING(msg, TCA_KIND, qdisc->q_kind);
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Delete qdisc
+ * @arg sk		Netlink socket
+ * @arg qdisc		Qdisc to add 
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the deletion
+ * of a qdisc and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex and \c parent
+ * - \c handle (optional, must match if provided)
+ * - \c kind (optional, must match if provided)
+ *
+ * All other qdisc attributes including all qdisc type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note It is not possible to delete default qdiscs.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0)
+		return err;
+
+	return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured qdiscs
+ * @arg sk		Netlink socket
+ * @arg result		Pointer to store the created cache
+ *
+ * Allocates a new qdisc cache and fills it with a list of all configured
+ * qdiscs on all network devices. Release the cache with nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result);
+}
+
+/**
+ * Search qdisc by interface index and parent
+ * @arg cache		Qdisc cache
+ * @arg ifindex		Interface index
+ * @arg parent		Handle of parent qdisc
+ *
+ * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache()
+ * and searches for a qdisc matching the interface index and parent qdisc.
+ *
+ * The reference counter is incremented before returning the qdisc, therefore
+ * the reference must be given back with rtnl_qdisc_put() after usage.
+ *
+ * @return pointer to qdisc inside the cache or NULL if no match was found.
+ */
+struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache,
+					    int ifindex, uint32_t parent)
+{
+	struct rtnl_qdisc *q;
+
+	if (cache->c_ops != &rtnl_qdisc_ops)
+		return NULL;
+
+	nl_list_for_each_entry(q, &cache->c_items, ce_list) {
+		if (q->q_parent == parent && q->q_ifindex == ifindex) {
+			nl_object_get((struct nl_object *) q);
+			return q;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Search qdisc by interface index and handle
+ * @arg cache		Qdisc cache
+ * @arg ifindex		Interface index
+ * @arg handle		Handle
+ *
+ * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache()
+ * and searches for a qdisc matching the interface index and handle.
+ *
+ * The reference counter is incremented before returning the qdisc, therefore
+ * the reference must be given back with rtnl_qdisc_put() after usage.
+ *
+ * @return Qdisc or NULL if no match was found.
+ */
+struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex,
+				  uint32_t handle)
+{
+	struct rtnl_qdisc *q;
+
+	if (cache->c_ops != &rtnl_qdisc_ops)
+		return NULL;
+
+	nl_list_for_each_entry(q, &cache->c_items, ce_list) {
+		if (q->q_handle == handle && q->q_ifindex == ifindex) {
+			nl_object_get((struct nl_object *) q);
+			return q;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ * @{
+ */
+
+/**
+ * Call a callback for each child class of a qdisc (deprecated)
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
+			      void (*cb)(struct nl_object *, void *), void *arg)
+{
+	struct rtnl_class *filter;
+	
+	filter = rtnl_class_alloc();
+	if (!filter)
+		return;
+
+	rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_handle);
+	rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex);
+	rtnl_tc_set_kind(TC_CAST(filter), qdisc->q_kind);
+
+	nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+
+	rtnl_class_put(filter);
+}
+
+/**
+ * Call a callback for each filter attached to the qdisc (deprecated)
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
+			    void (*cb)(struct nl_object *, void *), void *arg)
+{
+	struct rtnl_cls *filter;
+
+	if (!(filter = rtnl_cls_alloc()))
+		return;
+
+	rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex);
+	rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_parent);
+
+	nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+	rtnl_cls_put(filter);
+}
+
+/**
+ * Build a netlink message requesting the update of a qdisc
+ *
+ * @deprecated Use of this function is deprecated in favour of
+ *             rtnl_qdisc_build_update_request() due to the missing
+ *             possibility of specifying additional flags.
+ */
+int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
+				    struct rtnl_qdisc *new,
+				    struct nl_msg **result)
+{
+	return rtnl_qdisc_build_update_request(qdisc, new, NLM_F_REPLACE,
+					       result);
+}
+
+/**
+ * Change attributes of a qdisc
+ *
+ * @deprecated Use of this function is deprecated in favour of
+ *             rtnl_qdisc_update() due to the missing possibility of
+ *             specifying additional flags.
+ */
+int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
+		      struct rtnl_qdisc *new)
+{
+	return rtnl_qdisc_update(sk, qdisc, new, NLM_F_REPLACE);
+}
+
+/** @} */
+
+static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+	nl_dump(p, "refcnt %u ", qdisc->q_info);
+}
+
+static struct rtnl_tc_type_ops qdisc_ops = {
+	.tt_type		= RTNL_TC_TYPE_QDISC,
+	.tt_dump_prefix		= "qdisc",
+	.tt_dump = {
+	    [NL_DUMP_DETAILS]	= qdisc_dump_details,
+	},
+};
+
+static struct nl_cache_ops rtnl_qdisc_ops = {
+	.co_name		= "route/qdisc",
+	.co_hdrsize		= sizeof(struct tcmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWQDISC, NL_ACT_NEW, "new" },
+					{ RTM_DELQDISC, NL_ACT_DEL, "del" },
+					{ RTM_GETQDISC, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_request_update	= qdisc_request_update,
+	.co_msg_parser		= qdisc_msg_parser,
+	.co_obj_ops		= &qdisc_obj_ops,
+};
+
+static struct nl_object_ops qdisc_obj_ops = {
+	.oo_name		= "route/qdisc",
+	.oo_size		= sizeof(struct rtnl_qdisc),
+	.oo_free_data		= rtnl_tc_free_data,
+	.oo_clone		= rtnl_tc_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= rtnl_tc_dump_line,
+	    [NL_DUMP_DETAILS]	= rtnl_tc_dump_details,
+	    [NL_DUMP_STATS]	= rtnl_tc_dump_stats,
+	},
+	.oo_compare		= rtnl_tc_compare,
+	.oo_id_attrs		= (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static void __init qdisc_init(void)
+{
+	rtnl_tc_type_register(&qdisc_ops);
+	nl_cache_mngt_register(&rtnl_qdisc_ops);
+}
+
+static void __exit qdisc_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_qdisc_ops);
+	rtnl_tc_type_unregister(&qdisc_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/.dirstamp b/libnetwork/libnl3/lib/route/qdisc/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/libnetwork/libnl3/lib/route/qdisc/blackhole.c b/libnetwork/libnl3/lib/route/qdisc/blackhole.c
new file mode 100644
index 0000000..06f5380
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/blackhole.c
@@ -0,0 +1,37 @@
+/*
+ * lib/route/qdisc/blackhole.c	Blackhole Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_blackhole Blackhole
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/route/tc-api.h>
+
+static struct rtnl_tc_ops blackhole_ops = {
+	.to_kind		= "blackhole",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+};
+
+static void __init blackhole_init(void)
+{
+	rtnl_tc_register(&blackhole_ops);
+}
+
+static void __exit blackhole_exit(void)
+{
+	rtnl_tc_unregister(&blackhole_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/cbq.c b/libnetwork/libnl3/lib/route/qdisc/cbq.c
new file mode 100644
index 0000000..e791a10
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/cbq.c
@@ -0,0 +1,204 @@
+/*
+ * lib/route/qdisc/cbq.c	Class Based Queueing
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/cbq.h>
+#include <netlink/route/cls/police.h>
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_cbq Class Based Queueing (CBQ)
+ * @{
+ */
+
+static const struct trans_tbl ovl_strategies[] = {
+	__ADD(TC_CBQ_OVL_CLASSIC,classic)
+	__ADD(TC_CBQ_OVL_DELAY,delay)
+	__ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
+	__ADD(TC_CBQ_OVL_DROP,drop)
+	__ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
+};
+
+/**
+ * Convert a CBQ OVL strategy to a character string
+ * @arg type		CBQ OVL strategy
+ * @arg buf		destination buffer
+ * @arg len		length of destination buffer
+ *
+ * Converts a CBQ OVL strategy to a character string and stores in the
+ * provided buffer. Returns the destination buffer or the type
+ * encoded in hex if no match was found.
+ */
+char *nl_ovl_strategy2str(int type, char *buf, size_t len)
+{
+	return __type2str(type, buf, len, ovl_strategies,
+			    ARRAY_SIZE(ovl_strategies));
+}
+
+/**
+ * Convert a string to a CBQ OVL strategy
+ * @arg name		CBQ OVL stragegy name
+ *
+ * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
+ * type. Returns the type or -1 if none was found.
+ */
+int nl_str2ovl_strategy(const char *name)
+{
+	return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
+}
+
+static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
+	[TCA_CBQ_LSSOPT]	= { .minlen = sizeof(struct tc_cbq_lssopt) },
+	[TCA_CBQ_RATE]		= { .minlen = sizeof(struct tc_ratespec) },
+	[TCA_CBQ_WRROPT]	= { .minlen = sizeof(struct tc_cbq_wrropt) },
+	[TCA_CBQ_OVL_STRATEGY]	= { .minlen = sizeof(struct tc_cbq_ovl) },
+	[TCA_CBQ_FOPT]		= { .minlen = sizeof(struct tc_cbq_fopt) },
+	[TCA_CBQ_POLICE]	= { .minlen = sizeof(struct tc_cbq_police) },
+};
+
+static int cbq_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_CBQ_MAX + 1];
+	struct rtnl_cbq *cbq = data;
+	int err;
+
+	err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy);
+	if (err < 0)
+		return err;
+
+	nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
+	nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
+	nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
+	nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
+	nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
+		   sizeof(cbq->cbq_ovl));
+	nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
+		    sizeof(cbq->cbq_police));
+	
+	return 0;
+}
+
+static void cbq_dump_line(struct rtnl_tc *tc, void *data,
+			  struct nl_dump_params *p)
+{
+	struct rtnl_cbq *cbq = data;
+	double r, rbit;
+	char *ru, *rubit;
+
+	if (!cbq)
+		return;
+
+	r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
+	rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
+
+	nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
+		r, ru, rbit, rubit, cbq->cbq_wrr.priority);
+}
+
+static void cbq_dump_details(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_cbq *cbq = data;
+	char *unit, buf[32];
+	double w;
+	uint32_t el;
+
+	if (!cbq)
+		return;
+
+	w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
+
+	nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
+		cbq->cbq_lss.avpkt,
+		cbq->cbq_rate.mpu,
+		1 << cbq->cbq_rate.cell_log,
+		cbq->cbq_wrr.allot, w, unit);
+
+	el = cbq->cbq_lss.ewma_log;
+	nl_dump_line(p, "  minidle %uus maxidle %uus offtime "
+				"%uus level %u ewma_log %u\n",
+		nl_ticks2us(cbq->cbq_lss.minidle >> el),
+		nl_ticks2us(cbq->cbq_lss.maxidle >> el),
+		nl_ticks2us(cbq->cbq_lss.offtime >> el),
+		cbq->cbq_lss.level,
+		cbq->cbq_lss.ewma_log);
+
+	nl_dump_line(p, "  penalty %uus strategy %s ",
+		nl_ticks2us(cbq->cbq_ovl.penalty),
+		nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
+
+	nl_dump(p, "split %s defmap 0x%08x ",
+		rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
+		cbq->cbq_fopt.defmap);
+	
+	nl_dump(p, "police %s",
+		nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
+}
+
+static void cbq_dump_stats(struct rtnl_tc *tc, void *data,
+			   struct nl_dump_params *p)
+{
+	struct tc_cbq_xstats *x;
+	
+	if (!(x = tca_xstats(tc)))
+		return;
+
+	nl_dump_line(p, "            borrows    overact  "
+			"  avgidle  undertime\n");
+	nl_dump_line(p, "         %10u %10u %10u %10u\n",
+		     x->borrows, x->overactions, x->avgidle, x->undertime);
+}
+
+static struct rtnl_tc_ops cbq_qdisc_ops = {
+	.to_kind		= "cbq",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_cbq),
+	.to_msg_parser		= cbq_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= cbq_dump_line,
+	    [NL_DUMP_DETAILS]	= cbq_dump_details,
+	    [NL_DUMP_STATS]	= cbq_dump_stats,
+	},
+};
+
+static struct rtnl_tc_ops cbq_class_ops = {
+	.to_kind		= "cbq",
+	.to_type		= RTNL_TC_TYPE_CLASS,
+	.to_size		= sizeof(struct rtnl_cbq),
+	.to_msg_parser		= cbq_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= cbq_dump_line,
+	    [NL_DUMP_DETAILS]	= cbq_dump_details,
+	    [NL_DUMP_STATS]	= cbq_dump_stats,
+	},
+};
+
+static void __init cbq_init(void)
+{
+	rtnl_tc_register(&cbq_qdisc_ops);
+	rtnl_tc_register(&cbq_class_ops);
+}
+
+static void __exit cbq_exit(void)
+{
+	rtnl_tc_unregister(&cbq_qdisc_ops);
+	rtnl_tc_unregister(&cbq_class_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/dsmark.c b/libnetwork/libnl3/lib/route/qdisc/dsmark.c
new file mode 100644
index 0000000..b5fd0d6
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/dsmark.c
@@ -0,0 +1,413 @@
+/*
+ * lib/route/qdisc/dsmark.c	DSMARK
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK)
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/class.h>
+#include <netlink/route/qdisc/dsmark.h>
+
+/** @cond SKIP */
+#define SCH_DSMARK_ATTR_INDICES		0x1
+#define SCH_DSMARK_ATTR_DEFAULT_INDEX	0x2
+#define SCH_DSMARK_ATTR_SET_TC_INDEX	0x4
+
+#define SCH_DSMARK_ATTR_MASK		0x1
+#define SCH_DSMARK_ATTR_VALUE		0x2
+/** @endcond */
+
+static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = {
+	[TCA_DSMARK_INDICES]		= { .type = NLA_U16 },
+	[TCA_DSMARK_DEFAULT_INDEX]	= { .type = NLA_U16 },
+	[TCA_DSMARK_SET_TC_INDEX]	= { .type = NLA_FLAG },
+	[TCA_DSMARK_VALUE]		= { .type = NLA_U8 },
+	[TCA_DSMARK_MASK]		= { .type = NLA_U8 },
+};
+
+static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_dsmark_qdisc *dsmark = data;
+	struct nlattr *tb[TCA_DSMARK_MAX + 1];
+	int err;
+
+	err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_DSMARK_INDICES]) {
+		dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
+		dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
+	}
+
+	if (tb[TCA_DSMARK_DEFAULT_INDEX]) {
+		dsmark->qdm_default_index =
+				nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]);
+		dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
+	}
+
+	if (tb[TCA_DSMARK_SET_TC_INDEX]) {
+		dsmark->qdm_set_tc_index = 1;
+		dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
+	}
+
+	return 0;
+}
+
+static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_dsmark_class *dsmark = data;
+	struct nlattr *tb[TCA_DSMARK_MAX + 1];
+	int err;
+
+	err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_DSMARK_MASK]) {
+		dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]);
+		dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
+	}
+
+	if (tb[TCA_DSMARK_VALUE]) {
+		dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]);
+		dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
+	}
+
+	return 0;
+}
+
+static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+				   struct nl_dump_params *p)
+{
+	struct rtnl_dsmark_qdisc *dsmark = data;
+
+	if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES))
+		nl_dump(p, " indices 0x%04x", dsmark->qdm_indices);
+}
+
+static void dsmark_qdisc_dump_details(struct rtnl_tc *tc, void *data,
+				      struct nl_dump_params *p)
+{
+	struct rtnl_dsmark_qdisc *dsmark = data;
+
+	if (!dsmark)
+		return;
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+		nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index);
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+		nl_dump(p, " set-tc-index");
+}
+
+static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data,
+				   struct nl_dump_params *p)
+{
+	struct rtnl_dsmark_class *dsmark = data;
+
+	if (!dsmark)
+		return;
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+		nl_dump(p, " value 0x%02x", dsmark->cdm_value);
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+		nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask);
+}
+
+static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
+				 struct nl_msg *msg)
+{
+	struct rtnl_dsmark_qdisc *dsmark = data;
+
+	if (!dsmark)
+		return 0;
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
+		NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices);
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+		NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX,
+			    dsmark->qdm_default_index);
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+		NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data,
+				 struct nl_msg *msg)
+{
+	struct rtnl_dsmark_class *dsmark = data;
+
+	if (!dsmark)
+		return 0;
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+		NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask);
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+		NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Class Attribute Access
+ * @{
+ */
+
+/**
+ * Set bitmask of DSMARK class.
+ * @arg class		DSMARK class to be modified.
+ * @arg mask		New bitmask.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask)
+{
+	struct rtnl_dsmark_class *dsmark;
+	
+	if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+		return -NLE_NOMEM;
+
+	dsmark->cdm_bmask = mask;
+	dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
+
+	return 0;
+}
+
+/**
+ * Get bitmask of DSMARK class.
+ * @arg class		DSMARK class.
+ * @return Bitmask or a negative error code.
+ */
+int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class)
+{
+	struct rtnl_dsmark_class *dsmark;
+	
+	if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+		return -NLE_NOMEM;
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+		return dsmark->cdm_bmask;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set value of DSMARK class.
+ * @arg class		DSMARK class to be modified.
+ * @arg value		New value.
+ * @return 0 on success or a negative errror code.
+ */
+int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value)
+{
+	struct rtnl_dsmark_class *dsmark;
+	
+	if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+		return -NLE_NOMEM;
+
+	dsmark->cdm_value = value;
+	dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
+
+	return 0;
+}
+
+/**
+ * Get value of DSMARK class.
+ * @arg class		DSMARK class.
+ * @return Value or a negative error code.
+ */
+int rtnl_class_dsmark_get_value(struct rtnl_class *class)
+{
+	struct rtnl_dsmark_class *dsmark;
+	
+	if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+		return -NLE_NOMEM;
+
+	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+		return dsmark->cdm_value;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Qdisc Attribute Access
+ * @{
+ */
+
+/**
+ * Set indices of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc to be modified.
+ * @arg indices		New indices.
+ */
+int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	dsmark->qdm_indices = indices;
+	dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
+
+	return 0;
+}
+
+/**
+ * Get indices of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc.
+ * @return Indices or a negative error code.
+ */
+int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
+		return dsmark->qdm_indices;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set default index of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc to be modified.
+ * @arg default_index	New default index.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc,
+					uint16_t default_index)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	dsmark->qdm_default_index = default_index;
+	dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
+
+	return 0;
+}
+
+/**
+ * Get default index of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc.
+ * @return Default index or a negative error code.
+ */
+int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+		return dsmark->qdm_default_index;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set set-tc-index flag of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc to be modified.
+ * @arg flag		Flag indicating whether to enable or disable.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	dsmark->qdm_set_tc_index = !!flag;
+	dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
+
+	return 0;
+}
+
+/**
+ * Get set-tc-index flag of DSMARK qdisc.
+ * @arg qdisc		DSMARK qdisc to be modified.
+ * @return 1 or 0 to indicate wehther the flag is enabled or a negative
+ *         error code.
+ */
+int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_dsmark_qdisc *dsmark;
+
+	if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+		return dsmark->qdm_set_tc_index;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops dsmark_qdisc_ops = {
+	.to_kind		= "dsmark",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_dsmark_qdisc),
+	.to_msg_parser		= dsmark_qdisc_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= dsmark_qdisc_dump_line,
+	    [NL_DUMP_DETAILS]	= dsmark_qdisc_dump_details,
+	},
+	.to_msg_fill		= dsmark_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops dsmark_class_ops = {
+	.to_kind		= "dsmark",
+	.to_type		= RTNL_TC_TYPE_CLASS,
+	.to_size		= sizeof(struct rtnl_dsmark_class),
+	.to_msg_parser		= dsmark_class_msg_parser,
+	.to_dump[NL_DUMP_LINE]	= dsmark_class_dump_line,
+	.to_msg_fill		= dsmark_class_msg_fill,
+};
+
+static void __init dsmark_init(void)
+{
+	rtnl_tc_register(&dsmark_qdisc_ops);
+	rtnl_tc_register(&dsmark_class_ops);
+}
+
+static void __exit dsmark_exit(void)
+{
+	rtnl_tc_unregister(&dsmark_qdisc_ops);
+	rtnl_tc_unregister(&dsmark_class_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/fifo.c b/libnetwork/libnl3/lib/route/qdisc/fifo.c
new file mode 100644
index 0000000..e87c79a
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/fifo.c
@@ -0,0 +1,169 @@
+/*
+ * lib/route/qdisc/fifo.c		(p|b)fifo
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo)
+ * @brief
+ *
+ * The FIFO qdisc comes in two flavours:
+ * @par bfifo (Byte FIFO)
+ * Allows enqueuing until the currently queued volume in bytes exceeds
+ * the configured limit.backlog contains currently enqueued volume in bytes.
+ *
+ * @par pfifo (Packet FIFO)
+ * Allows enquueing until the currently queued number of packets
+ * exceeds the configured limit.
+ *
+ * The configuration is exactly the same, the decision which of
+ * the two variations is going to be used is made based on the
+ * kind of the qdisc (rtnl_tc_set_kind()).
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/fifo.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define SCH_FIFO_ATTR_LIMIT 1
+/** @endcond */
+
+static int fifo_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_fifo *fifo = data;
+	struct tc_fifo_qopt *opt;
+
+	if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt))
+		return -NLE_INVAL;
+
+	opt = (struct tc_fifo_qopt *) tc->tc_opts->d_data;
+	fifo->qf_limit = opt->limit;
+	fifo->qf_mask = SCH_FIFO_ATTR_LIMIT;
+
+	return 0;
+}
+
+static void pfifo_dump_line(struct rtnl_tc *tc, void *data,
+			    struct nl_dump_params *p)
+{
+	struct rtnl_fifo *fifo = data;
+
+	if (fifo)
+		nl_dump(p, " limit %u packets", fifo->qf_limit);
+}
+
+static void bfifo_dump_line(struct rtnl_tc *tc, void *data,
+			    struct nl_dump_params *p)
+{
+	struct rtnl_fifo *fifo = data;
+	char *unit;
+	double r;
+
+	if (!fifo)
+		return;
+
+	r = nl_cancel_down_bytes(fifo->qf_limit, &unit);
+	nl_dump(p, " limit %.1f%s", r, unit);
+}
+
+static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_fifo *fifo = data;
+	struct tc_fifo_qopt opts = {0};
+
+	if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT))
+		return -NLE_INVAL;
+
+	opts.limit = fifo->qf_limit;
+
+	return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set limit of FIFO qdisc.
+ * @arg qdisc		FIFO qdisc to be modified.
+ * @arg limit		New limit.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+	struct rtnl_fifo *fifo;
+	
+	if (!(fifo = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+		
+	fifo->qf_limit = limit;
+	fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT;
+
+	return 0;
+}
+
+/**
+ * Get limit of a FIFO qdisc.
+ * @arg qdisc		FIFO qdisc.
+ * @return Numeric limit or a negative error code.
+ */
+int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_fifo *fifo;
+	
+	if (!(fifo = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+	
+	if (fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)
+		return fifo->qf_limit;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops pfifo_ops = {
+	.to_kind		= "pfifo",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_fifo),
+	.to_msg_parser		= fifo_msg_parser,
+	.to_dump[NL_DUMP_LINE]	= pfifo_dump_line,
+	.to_msg_fill		= fifo_msg_fill,
+};
+
+static struct rtnl_tc_ops bfifo_ops = {
+	.to_kind		= "bfifo",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_fifo),
+	.to_msg_parser		= fifo_msg_parser,
+	.to_dump[NL_DUMP_LINE]	= bfifo_dump_line,
+	.to_msg_fill		= fifo_msg_fill,
+};
+
+static void __init fifo_init(void)
+{
+	rtnl_tc_register(&pfifo_ops);
+	rtnl_tc_register(&bfifo_ops);
+}
+
+static void __exit fifo_exit(void)
+{
+	rtnl_tc_unregister(&pfifo_ops);
+	rtnl_tc_unregister(&bfifo_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/htb.c b/libnetwork/libnl3/lib/route/qdisc/htb.c
new file mode 100644
index 0000000..f1d0e75
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/htb.c
@@ -0,0 +1,643 @@
+/*
+ * lib/route/qdisc/htb.c	HTB Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard at siemens.com>
+ * Copyright (c) 2005-2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_htb Hierachical Token Bucket (HTB)
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/htb.h>
+
+/** @cond SKIP */
+#define SCH_HTB_HAS_RATE2QUANTUM	0x01
+#define SCH_HTB_HAS_DEFCLS		0x02
+
+#define SCH_HTB_HAS_PRIO		0x001
+#define SCH_HTB_HAS_RATE		0x002
+#define SCH_HTB_HAS_CEIL		0x004
+#define SCH_HTB_HAS_RBUFFER		0x008
+#define SCH_HTB_HAS_CBUFFER		0x010
+#define SCH_HTB_HAS_QUANTUM		0x020
+#define SCH_HTB_HAS_LEVEL		0x040
+/** @endcond */
+
+static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
+	[TCA_HTB_INIT]	= { .minlen = sizeof(struct tc_htb_glob) },
+	[TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
+};
+
+static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_HTB_MAX + 1];
+	struct rtnl_htb_qdisc *htb = data;
+	int err;
+
+	if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
+		return err;
+	
+	if (tb[TCA_HTB_INIT]) {
+		struct tc_htb_glob opts;
+
+		nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
+		htb->qh_rate2quantum = opts.rate2quantum;
+		htb->qh_defcls = opts.defcls;
+		htb->qh_direct_pkts = opts.direct_pkts;
+
+		htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
+	}
+
+	return 0;
+}
+
+static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_HTB_MAX + 1];
+	struct rtnl_htb_class *htb = data;
+	int err;
+
+	if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
+		return err;
+	
+	if (tb[TCA_HTB_PARMS]) {
+		struct tc_htb_opt opts;
+
+		nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
+		htb->ch_prio = opts.prio;
+		rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
+		rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
+		htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer,
+						       opts.rate.rate);
+		htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer,
+						       opts.ceil.rate);
+		htb->ch_quantum = opts.quantum;
+		htb->ch_level = opts.level;
+
+		rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
+		rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
+
+		htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
+				SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
+				SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
+				SCH_HTB_HAS_LEVEL);
+	}
+
+	return 0;
+}
+
+static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+				struct nl_dump_params *p)
+{
+	struct rtnl_htb_qdisc *htb = data;
+
+	if (!htb)
+		return;
+
+	if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+		nl_dump(p, " r2q %u", htb->qh_rate2quantum);
+
+	if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
+		char buf[64];
+		nl_dump(p, " default-class %s",
+			rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
+	}
+}
+
+static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
+				struct nl_dump_params *p)
+{
+	struct rtnl_htb_class *htb = data;
+
+	if (!htb)
+		return;
+
+	if (htb->ch_mask & SCH_HTB_HAS_RATE) {
+		double r, rbit;
+		char *ru, *rubit;
+
+		r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
+		rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
+
+		nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
+			r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
+	}
+}
+
+static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
+				   struct nl_dump_params *p)
+{
+	struct rtnl_htb_class *htb = data;
+
+	if (!htb)
+		return;
+
+	/* line 1 */
+	if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
+		double r, rbit;
+		char *ru, *rubit;
+
+		r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
+		rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
+
+		nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
+			r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
+	}
+
+	if (htb->ch_mask & SCH_HTB_HAS_PRIO)
+		nl_dump(p, " prio %u", htb->ch_prio);
+
+	if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
+		double b;
+		char *bu;
+
+		b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
+		nl_dump(p, " rbuffer %.2f%s", b, bu);
+	}
+
+	if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
+		double b;
+		char *bu;
+
+		b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
+		nl_dump(p, " cbuffer %.2f%s", b, bu);
+	}
+
+	if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+		nl_dump(p, " quantum %u", htb->ch_quantum);
+}
+
+static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
+			      struct nl_msg *msg)
+{
+	struct rtnl_htb_qdisc *htb = data;
+	struct tc_htb_glob opts = {0};
+
+	opts.version = TC_HTB_PROTOVER;
+	opts.rate2quantum = 10;
+
+	if (htb) {
+		if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+			opts.rate2quantum = htb->qh_rate2quantum;
+
+		if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
+			opts.defcls = htb->qh_defcls;
+	}
+
+	return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
+}
+
+static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
+			      struct nl_msg *msg)
+{
+	struct rtnl_htb_class *htb = data;
+	uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
+	struct tc_htb_opt opts;
+	int buffer, cbuffer;
+
+	if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
+		BUG();
+
+	memset(&opts, 0, sizeof(opts));
+
+	/* if not set, zero (0) is used as priority */
+	if (htb->ch_mask & SCH_HTB_HAS_PRIO)
+		opts.prio = htb->ch_prio;
+
+	mtu = rtnl_tc_get_mtu(tc);
+
+	rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
+	rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
+
+	if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
+		rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
+		rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
+	} else {
+		/*
+		 * If not set, configured rate is used as ceil, which implies
+		 * no borrowing.
+		 */
+		memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
+	}
+
+	if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
+		buffer = htb->ch_rbuffer;
+	else
+		buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */
+
+	opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
+
+	if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
+		cbuffer = htb->ch_cbuffer;
+	else
+		cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */
+
+	opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
+
+	if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+		opts.quantum = htb->ch_quantum;
+
+	NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
+	NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
+	NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+static struct rtnl_tc_ops htb_qdisc_ops;
+static struct rtnl_tc_ops htb_class_ops;
+
+static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc)
+{
+	return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops);
+}
+
+static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class)
+{
+	return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Return rate/quantum ratio of HTB qdisc
+ * @arg qdisc		htb qdisc object
+ *
+ * @return rate/quantum ratio or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_htb_qdisc *htb;
+
+	if ((htb = htb_qdisc_data(qdisc)) &&
+	    htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+		return htb->qh_rate2quantum;
+
+	return 0;
+}
+
+int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
+{
+	struct rtnl_htb_qdisc *htb;
+
+	if (!(htb = htb_qdisc_data(qdisc)))
+		return -NLE_OPNOTSUPP;
+
+	htb->qh_rate2quantum = rate2quantum;
+	htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
+
+	return 0;
+}
+
+/**
+ * Return default class of HTB qdisc
+ * @arg qdisc		htb qdisc object
+ *
+ * Returns the classid of the class where all unclassified traffic
+ * goes to.
+ *
+ * @return classid or TC_H_UNSPEC if unspecified.
+ */
+uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_htb_qdisc *htb;
+
+	if ((htb = htb_qdisc_data(qdisc)) &&
+	    htb->qh_mask & SCH_HTB_HAS_DEFCLS)
+		return htb->qh_defcls;
+
+	return TC_H_UNSPEC;
+}
+
+/**
+ * Set default class of the htb qdisc to the specified value
+ * @arg qdisc		qdisc to change
+ * @arg defcls		new default class
+ */
+int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
+{
+	struct rtnl_htb_qdisc *htb;
+
+	if (!(htb = htb_qdisc_data(qdisc)))
+		return -NLE_OPNOTSUPP;
+
+	htb->qh_defcls = defcls;
+	htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
+
+	return 0;
+}
+
+uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO)
+		return htb->ch_prio;
+
+	return 0;
+}
+
+int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_prio = prio;
+	htb->ch_mask |= SCH_HTB_HAS_PRIO;
+
+	return 0;
+}
+
+/**
+ * Return rate of HTB class
+ * @arg class		htb class object
+ *
+ * @return Rate in bytes/s or 0 if unspecified.
+ */
+uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE)
+		return htb->ch_rate.rs_rate;
+
+	return 0;
+}
+
+/**
+ * Set rate of HTB class
+ * @arg class		htb class object
+ * @arg rate		new rate in bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
+	htb->ch_rate.rs_rate = rate;
+	htb->ch_mask |= SCH_HTB_HAS_RATE;
+
+	return 0;
+}
+
+/**
+ * Return ceil rate of HTB class
+ * @arg class		htb class object
+ *
+ * @return Ceil rate in bytes/s or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL)
+		return htb->ch_ceil.rs_rate;
+
+	return 0;
+}
+
+/**
+ * Set ceil rate of HTB class
+ * @arg class		htb class object
+ * @arg ceil		new ceil rate number of bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
+	htb->ch_ceil.rs_rate = ceil;
+	htb->ch_mask |= SCH_HTB_HAS_CEIL;
+
+	return 0;
+}
+
+/**
+ * Return burst buffer size of HTB class
+ * @arg class		htb class object
+ *
+ * @return Burst buffer size or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) &&
+	     htb->ch_mask & SCH_HTB_HAS_RBUFFER)
+		return htb->ch_rbuffer;
+
+	return 0;
+}
+
+/**
+ * Set size of the rate bucket of HTB class.
+ * @arg class		HTB class to be modified.
+ * @arg rbuffer		New size in bytes.
+ */
+int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_rbuffer = rbuffer;
+	htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
+
+	return 0;
+}
+
+/**
+ * Return ceil burst buffer size of HTB class
+ * @arg class		htb class object
+ *
+ * @return Ceil burst buffer size or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) &&
+	     htb->ch_mask & SCH_HTB_HAS_CBUFFER)
+		return htb->ch_cbuffer;
+
+	return 0;
+}
+
+/**
+ * Set size of the ceil bucket of HTB class.
+ * @arg class		HTB class to be modified.
+ * @arg cbuffer		New size in bytes.
+ */
+int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_cbuffer = cbuffer;
+	htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
+
+	return 0;
+}
+
+/**
+ * Return quantum of HTB class
+ * @arg class		htb class object
+ *
+ * See XXX[quantum def]
+ *
+ * @return Quantum or 0 if unspecified.
+ */
+uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) &&
+	    htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+		return htb->ch_quantum;
+
+	return 0;
+}
+
+/**
+ * Set quantum of HTB class (overwrites value calculated based on r2q)
+ * @arg class		htb class object
+ * @arg quantum		new quantum in number of bytes
+ *
+ * See XXX[quantum def]
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_quantum = quantum;
+	htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
+
+	return 0;
+}
+
+/**
+ * Return level of HTB class
+ * @arg class		htb class object
+ *
+ * Returns the level of the HTB class. Leaf classes are assigned level
+ * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes
+ * have a level of one less than their parent.
+ *
+ * @return Level or -NLE_OPNOTSUPP
+ */
+int rtnl_htb_get_level(struct rtnl_class *class)
+{
+	struct rtnl_htb_class *htb;
+
+	if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL)
+		return htb->ch_level;
+
+	return -NLE_OPNOTSUPP;
+}
+
+/**
+ * Set level of HTB class
+ * @arg class		htb class object
+ * @arg level		new level of HTB class
+ *
+ * Sets the level of a HTB class. Note that changing the level of a HTB
+ * class does not change the level of its in kernel counterpart. This
+ * function is provided only to create HTB objects which can be compared
+ * against or filtered upon.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_level(struct rtnl_class *class, int level)
+{
+	struct rtnl_htb_class *htb;
+
+	if (!(htb = htb_class_data(class)))
+		return -NLE_OPNOTSUPP;
+
+	htb->ch_level = level;
+	htb->ch_mask |= SCH_HTB_HAS_LEVEL;
+
+	return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops htb_qdisc_ops = {
+	.to_kind		= "htb",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_htb_qdisc),
+	.to_msg_parser		= htb_qdisc_msg_parser,
+	.to_dump[NL_DUMP_LINE]	= htb_qdisc_dump_line,
+	.to_msg_fill		= htb_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops htb_class_ops = {
+	.to_kind		= "htb",
+	.to_type		= RTNL_TC_TYPE_CLASS,
+	.to_size		= sizeof(struct rtnl_htb_class),
+	.to_msg_parser		= htb_class_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= htb_class_dump_line,
+	    [NL_DUMP_DETAILS]	= htb_class_dump_details,
+	},
+	.to_msg_fill		= htb_class_msg_fill,
+};
+
+static void __init htb_init(void)
+{
+	rtnl_tc_register(&htb_qdisc_ops);
+	rtnl_tc_register(&htb_class_ops);
+}
+
+static void __exit htb_exit(void)
+{
+	rtnl_tc_unregister(&htb_qdisc_ops);
+	rtnl_tc_unregister(&htb_class_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/netem.c b/libnetwork/libnl3/lib/route/qdisc/netem.c
new file mode 100644
index 0000000..997a31f
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/netem.c
@@ -0,0 +1,906 @@
+/*
+ * lib/route/qdisc/netem.c		Network Emulator Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_netem Network Emulator
+ * @brief
+ *
+ * For further documentation see http://linux-net.osdl.org/index.php/Netem
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/netem.h>
+
+/** @cond SKIP */
+#define SCH_NETEM_ATTR_LATENCY		0x0001
+#define SCH_NETEM_ATTR_LIMIT		0x0002
+#define SCH_NETEM_ATTR_LOSS			0x0004
+#define SCH_NETEM_ATTR_GAP			0x0008
+#define SCH_NETEM_ATTR_DUPLICATE	0x0010
+#define SCH_NETEM_ATTR_JITTER		0x0020
+#define SCH_NETEM_ATTR_DELAY_CORR	0x0040
+#define SCH_NETEM_ATTR_LOSS_CORR	0x0080
+#define SCH_NETEM_ATTR_DUP_CORR		0x0100
+#define SCH_NETEM_ATTR_RO_PROB		0x0200
+#define SCH_NETEM_ATTR_RO_CORR		0x0400
+#define SCH_NETEM_ATTR_CORRUPT_PROB	0x0800
+#define SCH_NETEM_ATTR_CORRUPT_CORR	0x1000
+#define SCH_NETEM_ATTR_DIST         0x2000
+/** @endcond */
+
+static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
+	[TCA_NETEM_CORR]	= { .minlen = sizeof(struct tc_netem_corr) },
+	[TCA_NETEM_REORDER]	= { .minlen = sizeof(struct tc_netem_reorder) },
+	[TCA_NETEM_CORRUPT]	= { .minlen = sizeof(struct tc_netem_corrupt) },
+};
+
+static int netem_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_netem *netem = data;
+	struct tc_netem_qopt *opts;
+	int len, err = 0;
+
+	if (tc->tc_opts->d_size < sizeof(*opts))
+		return -NLE_INVAL;
+
+	opts = (struct tc_netem_qopt *) tc->tc_opts->d_data;
+	netem->qnm_latency = opts->latency;
+	netem->qnm_limit = opts->limit;
+	netem->qnm_loss = opts->loss;
+	netem->qnm_gap = opts->gap;
+	netem->qnm_duplicate = opts->duplicate;
+	netem->qnm_jitter = opts->jitter;
+
+	netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT |
+			   SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP |
+			   SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER);
+
+	len = tc->tc_opts->d_size - sizeof(*opts);
+
+	if (len > 0) {
+		struct nlattr *tb[TCA_NETEM_MAX+1];
+
+		err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
+				(tc->tc_opts->d_data + sizeof(*opts)),
+				len, netem_policy);
+		if (err < 0) {
+			free(netem);
+			return err;
+		}
+
+		if (tb[TCA_NETEM_CORR]) {
+			struct tc_netem_corr cor;
+
+			nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor));
+			netem->qnm_corr.nmc_delay = cor.delay_corr;
+			netem->qnm_corr.nmc_loss = cor.loss_corr;
+			netem->qnm_corr.nmc_duplicate = cor.dup_corr;
+
+			netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR |
+					    SCH_NETEM_ATTR_LOSS_CORR |
+					SCH_NETEM_ATTR_DUP_CORR);
+		}
+
+		if (tb[TCA_NETEM_REORDER]) {
+			struct tc_netem_reorder ro;
+
+			nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro));
+			netem->qnm_ro.nmro_probability = ro.probability;
+			netem->qnm_ro.nmro_correlation = ro.correlation;
+
+			netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
+					    SCH_NETEM_ATTR_RO_CORR);
+		}
+			
+		if (tb[TCA_NETEM_CORRUPT]) {
+			struct tc_netem_corrupt corrupt;
+						
+			nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
+			netem->qnm_crpt.nmcr_probability = corrupt.probability;
+			netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
+	
+			netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
+						SCH_NETEM_ATTR_CORRUPT_CORR);
+		}
+		
+		/* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
+		netem->qnm_dist.dist_data = NULL;
+		netem->qnm_dist.dist_size = 0;
+	}
+
+	return 0;
+}
+
+static void netem_free_data(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_netem *netem = data;
+	
+	if (!netem)
+		return;
+	
+	free(netem->qnm_dist.dist_data);
+}
+
+static void netem_dump_line(struct rtnl_tc *tc, void *data,
+			    struct nl_dump_params *p)
+{
+	struct rtnl_netem *netem = data;
+
+	if (netem)
+		nl_dump(p, "limit %d", netem->qnm_limit);
+}
+
+static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
+			      struct nl_msg *msg)
+{
+	int err = 0;
+	struct tc_netem_qopt opts;
+	struct tc_netem_corr cor;
+	struct tc_netem_reorder reorder;
+	struct tc_netem_corrupt corrupt;
+	struct rtnl_netem *netem = data;
+	
+	unsigned char set_correlation = 0, set_reorder = 0,
+		set_corrupt = 0, set_dist = 0;
+
+	if (!netem)
+		BUG();
+
+	memset(&opts, 0, sizeof(opts));
+	memset(&cor, 0, sizeof(cor));
+	memset(&reorder, 0, sizeof(reorder));
+	memset(&corrupt, 0, sizeof(corrupt));
+
+	msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
+	
+	if ( netem->qnm_ro.nmro_probability != 0 ) {
+		if (netem->qnm_latency == 0) {
+			return -NLE_MISSING_ATTR;
+		}
+		if (netem->qnm_gap == 0) netem->qnm_gap = 1;
+	}
+	else if ( netem->qnm_gap ) { 
+		return -NLE_MISSING_ATTR;
+	}
+
+	if ( netem->qnm_corr.nmc_delay != 0 ) {
+		if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+			return -NLE_MISSING_ATTR;
+		}
+		set_correlation = 1;
+	}
+	
+	if ( netem->qnm_corr.nmc_loss != 0 ) {
+		if ( netem->qnm_loss == 0 ) {
+			return -NLE_MISSING_ATTR;
+		}
+		set_correlation = 1;
+	}
+
+	if ( netem->qnm_corr.nmc_duplicate != 0 ) {
+		if ( netem->qnm_duplicate == 0 ) {
+			return -NLE_MISSING_ATTR;
+		}
+		set_correlation = 1;
+	}
+	
+	if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1;
+	else if ( netem->qnm_ro.nmro_correlation != 0 ) {
+			return -NLE_MISSING_ATTR;
+	}
+	
+	if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
+	else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
+			return -NLE_MISSING_ATTR;
+	}
+	
+	if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) {
+		if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+			return -NLE_MISSING_ATTR;
+	}
+	else {
+		/* Resize to accomodate the large distribution table */
+		int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
+			sizeof(netem->qnm_dist.dist_data[0]);
+		
+		msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
+		if ( msg->nm_nlh == NULL )
+			return -NLE_NOMEM;
+		msg->nm_size = new_msg_len;
+			set_dist = 1;
+		}
+	}
+	
+	opts.latency = netem->qnm_latency;
+	opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
+	opts.loss = netem->qnm_loss;
+	opts.gap = netem->qnm_gap;
+	opts.duplicate = netem->qnm_duplicate;
+	opts.jitter = netem->qnm_jitter;
+	
+	NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
+	
+	if ( set_correlation ) {
+		cor.delay_corr = netem->qnm_corr.nmc_delay;
+		cor.loss_corr = netem->qnm_corr.nmc_loss;
+		cor.dup_corr = netem->qnm_corr.nmc_duplicate;
+
+		NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
+	}
+	
+	if ( set_reorder ) {
+		reorder.probability = netem->qnm_ro.nmro_probability;
+		reorder.correlation = netem->qnm_ro.nmro_correlation;
+
+		NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
+	}
+	
+	if ( set_corrupt ) {
+		corrupt.probability = netem->qnm_crpt.nmcr_probability;
+		corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
+
+		NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
+	}
+	
+	if ( set_dist ) {
+		NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
+			netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
+			netem->qnm_dist.dist_data);
+	}
+
+	/* Length specified in the TCA_OPTIONS section must span the entire
+	 * remainder of the message. That's just the way that sch_netem expects it.
+	 * Maybe there's a more succinct way to do this at a higher level.
+	 */
+	struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) +
+		NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
+		
+	struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) +
+		NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
+	
+	int old_len = head->nla_len;
+	head->nla_len = (void *)tail - (void *)head;
+	msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
+	
+	return err;
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Queue Limit
+ * @{
+ */
+
+/**
+ * Set limit of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg limit		New limit in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+	
+	netem->qnm_limit = limit;
+	netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Limit in bytes or a negative error code.
+ */
+int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)
+		return netem->qnm_limit;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Re-ordering
+ * @{
+ */
+
+/**
+ * Set re-ordering gap of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg gap		New gap in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_gap = gap;
+	netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
+}
+
+/**
+ * Get re-ordering gap of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Re-ordering gap in packets or a negative error code.
+ */
+int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_GAP)
+		return netem->qnm_gap;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set re-ordering probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New re-ordering probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_ro.nmro_probability = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
+}
+
+/**
+ * Get re-ordering probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Re-ordering probability or a negative error code.
+ */
+int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)
+		return netem->qnm_ro.nmro_probability;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set re-order correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New re-ordering correlation probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_ro.nmro_correlation = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
+}
+
+/**
+ * Get re-ordering correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Re-ordering correlation probability or a negative error code.
+ */
+int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		return -NLE_NOMEM;
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)
+		return netem->qnm_ro.nmro_correlation;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Corruption
+ * @{
+ */
+ 
+/**
+ * Set corruption probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New corruption probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_crpt.nmcr_probability = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
+}
+
+/**
+ * Get corruption probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Corruption probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)
+		return netem->qnm_crpt.nmcr_probability;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set corruption correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New corruption correlation probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_crpt.nmcr_correlation = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
+}
+
+/**
+ * Get corruption correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Corruption correlation probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)
+		return netem->qnm_crpt.nmcr_correlation;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Loss
+ * @{
+ */
+
+/**
+ * Set packet loss probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New packet loss probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_loss = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
+}
+
+/**
+ * Get packet loss probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet loss probability or a negative error code.
+ */
+int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)
+		return netem->qnm_loss;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set packet loss correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob	New packet loss correlation.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_corr.nmc_loss = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
+}
+
+/**
+ * Get packet loss correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet loss correlation probability or a negative error code.
+ */
+int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)
+		return netem->qnm_corr.nmc_loss;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Duplication
+ * @{
+ */
+
+/**
+ * Set packet duplication probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob	New packet duplication probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_duplicate = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
+}
+
+/**
+ * Get packet duplication probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet duplication probability or a negative error code.
+ */
+int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)
+		return netem->qnm_duplicate;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set packet duplication correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New packet duplication correlation probability.
+ * @return 0 on sucess or a negative error code.
+ */
+void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_corr.nmc_duplicate = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
+}
+
+/**
+ * Get packet duplication correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet duplication correlation probability or a negative error code.
+ */
+int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)
+		return netem->qnm_corr.nmc_duplicate;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Delay
+ * @{
+ */
+
+/**
+ * Set packet delay of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg delay		New packet delay in micro seconds.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_latency = nl_us2ticks(delay);
+	netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
+}
+
+/**
+ * Get packet delay of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet delay in micro seconds or a negative error code.
+ */
+int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)
+		return nl_ticks2us(netem->qnm_latency);
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set packet delay jitter of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg jitter		New packet delay jitter in micro seconds.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_jitter = nl_us2ticks(jitter);
+	netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
+}
+
+/**
+ * Get packet delay jitter of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet delay jitter in micro seconds or a negative error code.
+ */
+int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)
+		return nl_ticks2us(netem->qnm_jitter);
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set packet delay correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc to be modified.
+ * @arg prob		New packet delay correlation probability.
+ */
+void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	netem->qnm_corr.nmc_delay = prob;
+	netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
+}
+
+/**
+ * Get packet delay correlation probability of netem qdisc.
+ * @arg qdisc		Netem qdisc.
+ * @return Packet delay correlation probability or a negative error code.
+ */
+int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)
+		return netem->qnm_corr.nmc_delay;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Get the size of the distribution table.
+ * @arg qdisc		Netem qdisc.
+ * @return Distribution table size or a negative error code.
+ */
+int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_DIST)
+		return netem->qnm_dist.dist_size;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Get a pointer to the distribution table.
+ * @arg qdisc		Netem qdisc.
+ * @arg dist_ptr	The pointer to set.
+ * @return Negative error code on failure or 0 on success.
+ */
+int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr)
+{
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) {
+		*dist_ptr = netem->qnm_dist.dist_data;
+		return 0;
+	} else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set the delay distribution. Latency/jitter must be set before applying.
+ * @arg qdisc Netem qdisc.
+ * @arg dist_type The name of the distribution (type, file, path/file).
+ * @return 0 on success, error code on failure.
+ */
+int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
+	struct rtnl_netem *netem;
+
+	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+		
+	FILE *f = NULL;
+	int i, n = 0;
+	size_t len = 2048;
+	char *line;
+	char name[NAME_MAX];
+	char dist_suffix[] = ".dist";
+	
+	/* If the given filename already ends in .dist, don't append it later */
+	char *test_suffix = strstr(dist_type, dist_suffix);
+	if (test_suffix != NULL && strlen(test_suffix) == 5)
+		strcpy(dist_suffix, "");
+	
+	/* Check several locations for the dist file */
+	char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" };
+	
+	for (i = 0; i < sizeof(test_path) && f == NULL; i++) {
+		snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
+		f = fopen(name, "r");
+	}
+	
+	if ( f == NULL )
+		return -nl_syserr2nlerr(errno);
+	
+	netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
+	
+	line = (char *) calloc (sizeof(char), len + 1);
+	
+	while (getline(&line, &len, f) != -1) {
+		char *p, *endp;
+		
+		if (*line == '\n' || *line == '#')
+			continue;
+
+		for (p = line; ; p = endp) {
+			long x = strtol(p, &endp, 0);
+			if (endp == p) break;
+
+			if (n >= MAXDIST) {
+				free(line);
+				fclose(f);
+				return -NLE_INVAL;
+			}
+			netem->qnm_dist.dist_data[n++] = x;
+		}		
+	}
+	
+	free(line);
+	
+	netem->qnm_dist.dist_size = n;
+	netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
+	
+	fclose(f);
+	return 0;	
+}
+
+/** @} */
+
+static struct rtnl_tc_ops netem_ops = {
+	.to_kind		= "netem",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_netem),
+	.to_msg_parser		= netem_msg_parser,
+	.to_free_data		= netem_free_data,
+	.to_dump[NL_DUMP_LINE]	= netem_dump_line,
+	.to_msg_fill_raw	= netem_msg_fill_raw,
+};
+
+static void __init netem_init(void)
+{
+	rtnl_tc_register(&netem_ops);
+}
+
+static void __exit netem_exit(void)
+{
+	rtnl_tc_unregister(&netem_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/prio.c b/libnetwork/libnl3/lib/route/qdisc/prio.c
new file mode 100644
index 0000000..2433c61
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/prio.c
@@ -0,0 +1,294 @@
+/*
+ * lib/route/qdisc/prio.c		PRIO Qdisc/Class
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_prio (Fast) Prio
+ * @brief
+ *
+ * @par 1) Typical PRIO configuration
+ * @code
+ * // Specify the maximal number of bands to be used for this PRIO qdisc.
+ * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
+ *
+ * // Provide a map assigning each priority to a band number.
+ * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
+ * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/prio.h>
+
+/** @cond SKIP */
+#define SCH_PRIO_ATTR_BANDS	1
+#define SCH_PRIO_ATTR_PRIOMAP	2
+/** @endcond */
+
+static int prio_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_prio *prio = data;
+	struct tc_prio_qopt *opt;
+
+	if (tc->tc_opts->d_size < sizeof(*opt))
+		return -NLE_INVAL;
+
+	opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
+	prio->qp_bands = opt->bands;
+	memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
+	prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
+	
+	return 0;
+}
+
+static void prio_dump_line(struct rtnl_tc *tc, void *data,
+			   struct nl_dump_params *p)
+{
+	struct rtnl_prio *prio = data;
+
+	if (prio)
+		nl_dump(p, " bands %u", prio->qp_bands);
+}
+
+static void prio_dump_details(struct rtnl_tc *tc, void *data,
+			      struct nl_dump_params *p)
+{
+	struct rtnl_prio *prio = data;
+	int i, hp;
+
+	if (!prio)
+		return;
+
+	nl_dump(p, "priomap [");
+	
+	for (i = 0; i <= TC_PRIO_MAX; i++)
+		nl_dump(p, "%u%s", prio->qp_priomap[i],
+			i < TC_PRIO_MAX ? " " : "");
+
+	nl_dump(p, "]\n");
+	nl_new_line(p);
+
+	hp = (((TC_PRIO_MAX/2) + 1) & ~1);
+
+	for (i = 0; i < hp; i++) {
+		char a[32];
+		nl_dump(p, "    %18s => %u",
+			rtnl_prio2str(i, a, sizeof(a)),
+			prio->qp_priomap[i]);
+		if (hp+i <= TC_PRIO_MAX) {
+			nl_dump(p, " %18s => %u",
+				rtnl_prio2str(hp+i, a, sizeof(a)),
+				prio->qp_priomap[hp+i]);
+			if (i < (hp - 1)) {
+				nl_dump(p, "\n");
+				nl_new_line(p);
+			}
+		}
+	}
+}
+
+static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_prio *prio = data;
+	struct tc_prio_qopt opts;
+
+	if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
+		BUG();
+
+	opts.bands = prio->qp_bands;
+	memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
+
+	return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set number of bands of PRIO qdisc.
+ * @arg qdisc		PRIO qdisc to be modified.
+ * @arg bands		New number of bands.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
+{
+	struct rtnl_prio *prio;
+
+	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	prio->qp_bands = bands;
+	prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
+}
+
+/**
+ * Get number of bands of PRIO qdisc.
+ * @arg qdisc		PRIO qdisc.
+ * @return Number of bands or a negative error code.
+ */
+int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_prio *prio;
+
+	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
+		return prio->qp_bands;
+	else
+		return -NLE_NOMEM;
+}
+
+/**
+ * Set priomap of the PRIO qdisc.
+ * @arg qdisc		PRIO qdisc to be modified.
+ * @arg priomap		New priority mapping.
+ * @arg len		Length of priomap (# of elements).
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
+				int len)
+{
+	struct rtnl_prio *prio;
+	int i;
+
+	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
+		return -NLE_MISSING_ATTR;
+
+	if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
+		return -NLE_RANGE;
+
+	for (i = 0; i <= TC_PRIO_MAX; i++) {
+		if (priomap[i] > prio->qp_bands)
+			return -NLE_RANGE;
+	}
+
+	memcpy(prio->qp_priomap, priomap, len);
+	prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
+
+	return 0;
+}
+
+/**
+ * Get priomap of a PRIO qdisc.
+ * @arg qdisc		PRIO qdisc.
+ * @return Priority mapping as array of size TC_PRIO_MAX+1
+ *         or NULL if an error occured.
+ */
+uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_prio *prio;
+
+	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
+		return prio->qp_priomap;
+	else
+		return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Priority Band Translations
+ * @{
+ */
+
+static const struct trans_tbl prios[] = {
+	__ADD(TC_PRIO_BESTEFFORT,besteffort)
+	__ADD(TC_PRIO_FILLER,filler)
+	__ADD(TC_PRIO_BULK,bulk)
+	__ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
+	__ADD(TC_PRIO_INTERACTIVE,interactive)
+	__ADD(TC_PRIO_CONTROL,control)
+};
+
+/**
+ * Convert priority to character string.
+ * @arg prio		Priority.
+ * @arg buf		Destination buffer
+ * @arg size		Size of destination buffer.
+ *
+ * Converts a priority to a character string and stores the result in
+ * the specified destination buffer.
+ *
+ * @return Name of priority as character string.
+ */
+char * rtnl_prio2str(int prio, char *buf, size_t size)
+{
+	return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
+}
+
+/**
+ * Convert character string to priority.
+ * @arg name		Name of priority.
+ *
+ * Converts the provided character string specifying a priority
+ * to the corresponding numeric value.
+ *
+ * @return Numeric priority or a negative value if no match was found.
+ */
+int rtnl_str2prio(const char *name)
+{
+	return __str2type(name, prios, ARRAY_SIZE(prios));
+}
+
+/** @} */
+
+static struct rtnl_tc_ops prio_ops = {
+	.to_kind		= "prio",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_prio),
+	.to_msg_parser		= prio_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= prio_dump_line,
+	    [NL_DUMP_DETAILS]	= prio_dump_details,
+	},
+	.to_msg_fill		= prio_msg_fill,
+};
+
+static struct rtnl_tc_ops pfifo_fast_ops = {
+	.to_kind		= "pfifo_fast",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_prio),
+	.to_msg_parser		= prio_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= prio_dump_line,
+	    [NL_DUMP_DETAILS]	= prio_dump_details,
+	},
+	.to_msg_fill		= prio_msg_fill,
+};
+
+static void __init prio_init(void)
+{
+	rtnl_tc_register(&prio_ops);
+	rtnl_tc_register(&pfifo_fast_ops);
+}
+
+static void __exit prio_exit(void)
+{
+	rtnl_tc_unregister(&prio_ops);
+	rtnl_tc_unregister(&pfifo_fast_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/red.c b/libnetwork/libnl3/lib/route/qdisc/red.c
new file mode 100644
index 0000000..0480282
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/red.c
@@ -0,0 +1,190 @@
+/*
+ * lib/route/qdisc/red.c		RED Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_red Random Early Detection (RED)
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/red.h>
+
+/** @cond SKIP */
+#define RED_ATTR_LIMIT		0x01
+#define RED_ATTR_QTH_MIN	0x02
+#define RED_ATTR_QTH_MAX	0x04
+#define RED_ATTR_FLAGS		0x08
+#define RED_ATTR_WLOG		0x10
+#define RED_ATTR_PLOG		0x20
+#define RED_ATTR_SCELL_LOG	0x40
+/** @endcond */
+
+static struct nla_policy red_policy[TCA_RED_MAX+1] = {
+	[TCA_RED_PARMS]		= { .minlen = sizeof(struct tc_red_qopt) },
+};
+
+static int red_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_RED_MAX+1];
+	struct rtnl_red *red = data;
+	struct tc_red_qopt *opts;
+	int err;
+
+	if (!(tc->ce_mask & TCA_ATTR_OPTS))
+		return 0;
+
+	err = tca_parse(tb, TCA_RED_MAX, tc, red_policy);
+	if (err < 0)
+		return err;
+
+	if (!tb[TCA_RED_PARMS])
+		return -NLE_MISSING_ATTR;
+
+	opts = nla_data(tb[TCA_RED_PARMS]);
+
+	red->qr_limit = opts->limit;
+	red->qr_qth_min = opts->qth_min;
+	red->qr_qth_max = opts->qth_max;
+	red->qr_flags = opts->flags;
+	red->qr_wlog = opts->Wlog;
+	red->qr_plog = opts->Plog;
+	red->qr_scell_log = opts->Scell_log;
+
+	red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
+			RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
+			RED_ATTR_SCELL_LOG);
+
+	return 0;
+}
+
+static void red_dump_line(struct rtnl_tc *tc, void *data,
+			  struct nl_dump_params *p)
+{
+	struct rtnl_red *red = data;
+
+	if (red) {
+		/* XXX: limit, min, max, flags */
+	}
+}
+
+static void red_dump_details(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_red *red = data;
+
+	if (red) {
+		/* XXX: wlog, plog, scell_log */
+	}
+}
+
+static void red_dump_stats(struct rtnl_tc *tc, void *data,
+			   struct nl_dump_params *p)
+{
+	struct rtnl_red *red = data;
+
+	if (red) {
+		/* XXX: xstats */
+	}
+}
+
+static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_red *red = data;
+
+	if (!red)
+		BUG();
+
+#if 0
+	memset(&opts, 0, sizeof(opts));
+	opts.quantum = sfq->qs_quantum;
+	opts.perturb_period = sfq->qs_perturb;
+	opts.limit = sfq->qs_limit;
+
+	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
+		goto errout;
+#endif
+
+	return -NLE_OPNOTSUPP;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set limit of RED qdisc.
+ * @arg qdisc		RED qdisc to be modified.
+ * @arg limit		New limit in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+	struct rtnl_red *red;
+
+	if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	red->qr_limit = limit;
+	red->qr_mask |= RED_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of RED qdisc.
+ * @arg qdisc		RED qdisc.
+ * @return Limit or a negative error code.
+ */
+int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_red *red;
+
+	if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (red->qr_mask & RED_ATTR_LIMIT)
+		return red->qr_limit;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops red_ops = {
+	.to_kind		= "red",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_red),
+	.to_msg_parser		= red_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= red_dump_line,
+	    [NL_DUMP_DETAILS]	= red_dump_details,
+	    [NL_DUMP_STATS]	= red_dump_stats,
+	},
+	.to_msg_fill		= red_msg_fill,
+};
+
+static void __init red_init(void)
+{
+	rtnl_tc_register(&red_ops);
+}
+
+static void __exit red_exit(void)
+{
+	rtnl_tc_unregister(&red_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/sfq.c b/libnetwork/libnl3/lib/route/qdisc/sfq.c
new file mode 100644
index 0000000..207140f
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/sfq.c
@@ -0,0 +1,256 @@
+/*
+ * lib/route/qdisc/sfq.c		SFQ Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ)
+ * @brief
+ *
+ * @par Parameter Description
+ * - \b Quantum: Number of bytes to send out per slot and round.
+ * - \b Perturbation: Timer period between changing the hash function.
+ * - \b Limit:  Upper limit of queue in number of packets before SFQ starts
+ *	        dropping packets.
+ * - \b Divisor: Hash table divisor, i.e. size of hash table.
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/sfq.h>
+
+/** @cond SKIP */
+#define SCH_SFQ_ATTR_QUANTUM	0x01
+#define SCH_SFQ_ATTR_PERTURB	0x02
+#define SCH_SFQ_ATTR_LIMIT	0x04
+#define SCH_SFQ_ATTR_DIVISOR	0x08
+#define SCH_SFQ_ATTR_FLOWS	0x10
+/** @endcond */
+
+static int sfq_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct rtnl_sfq *sfq = data;
+	struct tc_sfq_qopt *opts;
+
+	if (!(tc->ce_mask & TCA_ATTR_OPTS))
+		return 0;
+
+	if (tc->tc_opts->d_size < sizeof(*opts))
+		return -NLE_INVAL;
+
+	opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data;
+
+	sfq->qs_quantum = opts->quantum;
+	sfq->qs_perturb = opts->perturb_period;
+	sfq->qs_limit = opts->limit;
+	sfq->qs_divisor = opts->divisor;
+	sfq->qs_flows = opts->flows;
+
+	sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
+			SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
+			SCH_SFQ_ATTR_FLOWS);
+
+	return 0;
+}
+
+static void sfq_dump_line(struct rtnl_tc *tc, void *data,
+			  struct nl_dump_params *p)
+{
+	struct rtnl_sfq *sfq = data;
+
+	if (sfq)
+		nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
+			sfq->qs_perturb);
+}
+
+static void sfq_dump_details(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_sfq *sfq = data;
+
+	if (sfq)
+		nl_dump(p, "limit %u divisor %u",
+			sfq->qs_limit, sfq->qs_divisor);
+}
+
+static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	struct rtnl_sfq *sfq = data;
+	struct tc_sfq_qopt opts = {0};
+
+	if (!sfq)
+		BUG();
+
+	opts.quantum = sfq->qs_quantum;
+	opts.perturb_period = sfq->qs_perturb;
+	opts.limit = sfq->qs_limit;
+
+	return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set quantum of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc to be modified.
+ * @arg quantum		New quantum in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	sfq->qs_quantum = quantum;
+	sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
+}
+
+/**
+ * Get quantum of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc.
+ * @return Quantum in bytes or a negative error code.
+ */
+int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
+		return sfq->qs_quantum;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set limit of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc to be modified.
+ * @arg limit		New limit in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	sfq->qs_limit = limit;
+	sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc.
+ * @return Limit or a negative error code.
+ */
+int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
+		return sfq->qs_limit;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Set perturbation interval of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc to be modified.
+ * @arg perturb		New perturbation interval in seconds.
+ * @note A value of 0 disables perturbation altogether.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	sfq->qs_perturb = perturb;
+	sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
+}
+
+/**
+ * Get perturbation interval of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc.
+ * @return Perturbation interval in seconds or a negative error code.
+ */
+int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
+		return sfq->qs_perturb;
+	else
+		return -NLE_NOATTR;
+}
+
+/**
+ * Get divisor of SFQ qdisc.
+ * @arg qdisc		SFQ qdisc.
+ * @return Divisor in number of entries or a negative error code.
+ */
+int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_sfq *sfq;
+	
+	if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
+		return sfq->qs_divisor;
+	else
+		return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops sfq_ops = {
+	.to_kind		= "sfq",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_sfq),
+	.to_msg_parser		= sfq_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= sfq_dump_line,
+	    [NL_DUMP_DETAILS]	= sfq_dump_details,
+	},
+	.to_msg_fill		= sfq_msg_fill,
+};
+
+static void __init sfq_init(void)
+{
+	rtnl_tc_register(&sfq_ops);
+}
+
+static void __exit sfq_exit(void)
+{
+	rtnl_tc_unregister(&sfq_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/qdisc/tbf.c b/libnetwork/libnl3/lib/route/qdisc/tbf.c
new file mode 100644
index 0000000..8a6c400
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/qdisc/tbf.c
@@ -0,0 +1,460 @@
+/*
+ * lib/route/qdisc/tbf.c		TBF Qdisc
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_tbf Token Bucket Filter (TBF)
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/tbf.h>
+
+/** @cond SKIP */
+#define TBF_ATTR_LIMIT			0x01
+#define TBF_ATTR_RATE			0x02
+#define TBF_ATTR_PEAKRATE		0x10
+/** @endcond */
+
+static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
+	[TCA_TBF_PARMS]	= { .minlen = sizeof(struct tc_tbf_qopt) },
+};
+
+static int tbf_msg_parser(struct rtnl_tc *tc, void *data)
+{
+	struct nlattr *tb[TCA_TBF_MAX + 1];
+	struct rtnl_tbf *tbf = data;
+	int err;
+
+	if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
+		return err;
+	
+	if (tb[TCA_TBF_PARMS]) {
+		struct tc_tbf_qopt opts;
+		int bufsize;
+
+		nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
+		tbf->qt_limit = opts.limit;
+	
+		rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
+		tbf->qt_rate_txtime = opts.buffer;
+		bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
+					       opts.rate.rate);
+		tbf->qt_rate_bucket = bufsize;
+
+		rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
+		tbf->qt_peakrate_txtime = opts.mtu;
+		bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
+					       opts.peakrate.rate);
+		tbf->qt_peakrate_bucket = bufsize;
+
+		rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu);
+		rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead);
+
+		tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
+	}
+
+	return 0;
+}
+
+static void tbf_dump_line(struct rtnl_tc *tc, void *data,
+			  struct nl_dump_params *p)
+{
+	double r, rbit, lim;
+	char *ru, *rubit, *limu;
+	struct rtnl_tbf *tbf = data;
+
+	if (!tbf)
+		return;
+
+	r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
+	rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
+	lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
+
+	nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
+		r, ru, rbit, rubit, lim, limu);
+}
+
+static void tbf_dump_details(struct rtnl_tc *tc, void *data,
+			     struct nl_dump_params *p)
+{
+	struct rtnl_tbf *tbf = data;
+
+	if (!tbf)
+		return;
+
+	if (1) {
+		char *bu, *cu;
+		double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
+		double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
+						 &cu);
+
+		nl_dump(p, "rate-bucket-size %1.f%s "
+			   "rate-cell-size %.1f%s\n",
+			bs, bu, cl, cu);
+
+	}
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+		char *pru, *prbu, *bsu, *clu;
+		double pr, prb, bs, cl;
+		
+		pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
+		prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
+		bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
+		cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
+					 &clu);
+
+		nl_dump_line(p, "    peak-rate %.2f%s/s (%.0f%s) "
+				"bucket-size %.1f%s cell-size %.1f%s"
+				"latency %.1f%s",
+			     pr, pru, prb, prbu, bs, bsu, cl, clu);
+	}
+}
+
+static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+	uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
+	struct tc_tbf_qopt opts;
+	struct rtnl_tbf *tbf = data;
+	int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
+
+	if (!(tbf->qt_mask & required) != required)
+		return -NLE_MISSING_ATTR;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.limit = tbf->qt_limit;
+	opts.buffer = tbf->qt_rate_txtime;
+
+	rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab);
+	rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+		opts.mtu = tbf->qt_peakrate_txtime;
+		rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab);
+		rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
+
+	}
+
+	NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
+	NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+		NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set limit of TBF qdisc.
+ * @arg qdisc		TBF qdisc to be modified.
+ * @arg limit		New limit in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+	struct rtnl_tbf *tbf;
+	
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	tbf->qt_limit = limit;
+	tbf->qt_mask |= TBF_ATTR_LIMIT;
+}
+
+static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
+				int bucket)
+{
+	double limit;
+
+	limit = (double) spec->rs_rate * ((double) latency / 1000000.);
+	limit += bucket;
+
+	return limit;
+}
+
+/**
+ * Set limit of TBF qdisc by latency.
+ * @arg qdisc		TBF qdisc to be modified.
+ * @arg latency		Latency in micro seconds.
+ *
+ * Calculates and sets the limit based on the desired latency and the
+ * configured rate and peak rate. In order for this operation to succeed,
+ * the rate and if required the peak rate must have been set in advance.
+ *
+ * @f[
+ *   limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
+ * @f]
+ * @f[
+ *   limit = min(limit_{rate},limit_{peak})
+ * @f]
+ * 
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
+{
+	struct rtnl_tbf *tbf;
+	double limit, limit2;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (!(tbf->qt_mask & TBF_ATTR_RATE))
+		return -NLE_MISSING_ATTR;
+
+	limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+		limit2 = calc_limit(&tbf->qt_peakrate, latency,
+				    tbf->qt_peakrate_bucket);
+
+		if (limit2 < limit)
+			limit = limit2;
+	}
+
+	rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
+
+	return 0;
+}
+
+/**
+ * Get limit of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Limit in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+	
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_LIMIT)
+		return tbf->qt_limit;
+	else
+		return -NLE_NOATTR;
+}
+
+static inline int calc_cell_log(int cell, int bucket)
+{
+		cell = rtnl_tc_calc_cell_log(cell);
+	return cell;
+}
+
+/**
+ * Set rate of TBF qdisc.
+ * @arg qdisc		TBF qdisc to be modified.
+ * @arg rate		New rate in bytes per second.
+ * @arg bucket		Size of bucket in bytes.
+ * @arg cell		Size of a rate cell or 0 to get default value.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
+			    int cell)
+{
+	struct rtnl_tbf *tbf;
+	int cell_log;
+	
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (!cell)
+		cell_log = UINT8_MAX;
+	else
+		cell_log = rtnl_tc_calc_cell_log(cell);
+
+	tbf->qt_rate.rs_rate = rate;
+	tbf->qt_rate_bucket = bucket;
+	tbf->qt_rate.rs_cell_log = cell_log;
+	tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
+	tbf->qt_mask |= TBF_ATTR_RATE;
+}
+
+/**
+ * Get rate of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Rate in bytes per seconds or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_RATE)
+		return tbf->qt_rate.rs_rate;
+	else
+		return -1;
+}
+
+/**
+ * Get rate bucket size of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Size of rate bucket or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_RATE)
+		return tbf->qt_rate_bucket;
+	else
+		return -1;
+}
+
+/**
+ * Get rate cell size of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Size of rate cell in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_RATE)
+		return (1 << tbf->qt_rate.rs_cell_log);
+	else
+		return -1;
+}
+
+/**
+ * Set peak rate of TBF qdisc.
+ * @arg qdisc		TBF qdisc to be modified.
+ * @arg rate		New peak rate in bytes per second.
+ * @arg bucket		Size of peakrate bucket.
+ * @arg cell		Size of a peakrate cell or 0 to get default value.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
+				int cell)
+{
+	struct rtnl_tbf *tbf;
+	int cell_log;
+	
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	cell_log = calc_cell_log(cell, bucket);
+	if (cell_log < 0)
+		return cell_log;
+
+	tbf->qt_peakrate.rs_rate = rate;
+	tbf->qt_peakrate_bucket = bucket;
+	tbf->qt_peakrate.rs_cell_log = cell_log;
+	tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
+	
+	tbf->qt_mask |= TBF_ATTR_PEAKRATE;
+
+	return 0;
+}
+
+/**
+ * Get peak rate of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Peak rate in bytes per seconds or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+		return tbf->qt_peakrate.rs_rate;
+	else
+		return -1;
+}
+
+/**
+ * Get peak rate bucket size of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Size of peak rate bucket or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+		return tbf->qt_peakrate_bucket;
+	else
+		return -1;
+}
+
+/**
+ * Get peak rate cell size of TBF qdisc.
+ * @arg qdisc		TBF qdisc.
+ * @return Size of peak rate cell in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
+{
+	struct rtnl_tbf *tbf;
+
+	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+		BUG();
+
+	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+		return (1 << tbf->qt_peakrate.rs_cell_log);
+	else
+		return -1;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops tbf_tc_ops = {
+	.to_kind		= "tbf",
+	.to_type		= RTNL_TC_TYPE_QDISC,
+	.to_size		= sizeof(struct rtnl_tbf),
+	.to_msg_parser		= tbf_msg_parser,
+	.to_dump = {
+	    [NL_DUMP_LINE]	= tbf_dump_line,
+	    [NL_DUMP_DETAILS]	= tbf_dump_details,
+	},
+	.to_msg_fill		= tbf_msg_fill,
+};
+
+static void __init tbf_init(void)
+{
+	rtnl_tc_register(&tbf_tc_ops);
+}
+
+static void __exit tbf_exit(void)
+{
+	rtnl_tc_unregister(&tbf_tc_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/route.c b/libnetwork/libnl3/lib/route/route.c
new file mode 100644
index 0000000..f684f96
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/route.c
@@ -0,0 +1,202 @@
+/*
+ * lib/route/route.c	Routes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup route Routing
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/data.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+
+static struct nl_cache_ops rtnl_route_ops;
+
+static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	struct rtnl_route *route;
+	int err;
+
+	if ((err = rtnl_route_parse(nlh, &route)) < 0)
+		return err;
+
+	err = pp->pp_cb((struct nl_object *) route, pp);
+
+	rtnl_route_put(route);
+	return err;
+}
+
+static int route_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	struct rtmsg rhdr = {
+		.rtm_family = c->c_iarg1,
+	};
+
+	if (c->c_iarg2 & ROUTE_CACHE_CONTENT)
+		rhdr.rtm_flags |= RTM_F_CLONED;
+
+	return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr));
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a route cache holding all routes currently configured in the kernel
+ * @arg sk		Netlink socket.
+ * @arg family		Address family of routes to cover or AF_UNSPEC
+ * @arg flags		Flags
+ * @arg result		Result pointer
+ *
+ * Allocates a new cache, initializes it properly and updates it to
+ * contain all routes currently configured in the kernel.
+ *
+ * @note The caller is responsible for destroying and freeing the
+ *       cache after using it.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags,
+			   struct nl_cache **result)
+{
+	struct nl_cache *cache;
+	int err;
+
+	if (!(cache = nl_cache_alloc(&rtnl_route_ops)))
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = family;
+	cache->c_iarg2 = flags;
+
+	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+		free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Route Addition
+ * @{
+ */
+
+static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags,
+			   struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if (!(msg = nlmsg_alloc_simple(cmd, flags)))
+		return -NLE_NOMEM;
+
+	if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) {
+		nlmsg_free(msg);
+		return err;
+	}
+
+	*result = msg;
+	return 0;
+}
+
+int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags,
+				 struct nl_msg **result)
+{
+	return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags,
+			       result);
+}
+
+int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags,
+				 struct nl_msg **result)
+{
+	return build_route_msg(tmpl, RTM_DELROUTE, flags, result);
+}
+
+int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+
+	if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+static struct nl_af_group route_groups[] = {
+	{ AF_INET,	RTNLGRP_IPV4_ROUTE },
+	{ AF_INET6,	RTNLGRP_IPV6_ROUTE },
+	{ AF_DECnet,	RTNLGRP_DECnet_ROUTE },
+	{ END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_route_ops = {
+	.co_name		= "route/route",
+	.co_hdrsize		= sizeof(struct rtmsg),
+	.co_msgtypes		= {
+					{ RTM_NEWROUTE, NL_ACT_NEW, "new" },
+					{ RTM_DELROUTE, NL_ACT_DEL, "del" },
+					{ RTM_GETROUTE, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_groups		= route_groups,
+	.co_request_update	= route_request_update,
+	.co_msg_parser		= route_msg_parser,
+	.co_obj_ops		= &route_obj_ops,
+};
+
+static void __init route_init(void)
+{
+	nl_cache_mngt_register(&rtnl_route_ops);
+}
+
+static void __exit route_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_route_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/route_obj.c b/libnetwork/libnl3/lib/route/route_obj.c
new file mode 100644
index 0000000..d322633
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/route_obj.c
@@ -0,0 +1,1148 @@
+/*
+ * lib/route/route_obj.c	Route Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup route
+ * @defgroup route_obj Route Object
+ *
+ * @par Attributes
+ * @code
+ * Name                                           Default
+ * -------------------------------------------------------------
+ * routing table                                  RT_TABLE_MAIN
+ * scope                                          RT_SCOPE_NOWHERE
+ * tos                                            0
+ * protocol                                       RTPROT_STATIC
+ * prio                                           0
+ * family                                         AF_UNSPEC
+ * type                                           RTN_UNICAST
+ * iif                                            NULL
+ * @endcode
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/data.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+#include <netlink/route/nexthop.h>
+
+/** @cond SKIP */
+#define ROUTE_ATTR_FAMILY    0x000001
+#define ROUTE_ATTR_TOS       0x000002
+#define ROUTE_ATTR_TABLE     0x000004
+#define ROUTE_ATTR_PROTOCOL  0x000008
+#define ROUTE_ATTR_SCOPE     0x000010
+#define ROUTE_ATTR_TYPE      0x000020
+#define ROUTE_ATTR_FLAGS     0x000040
+#define ROUTE_ATTR_DST       0x000080
+#define ROUTE_ATTR_SRC       0x000100
+#define ROUTE_ATTR_IIF       0x000200
+#define ROUTE_ATTR_OIF       0x000400
+#define ROUTE_ATTR_GATEWAY   0x000800
+#define ROUTE_ATTR_PRIO      0x001000
+#define ROUTE_ATTR_PREF_SRC  0x002000
+#define ROUTE_ATTR_METRICS   0x004000
+#define ROUTE_ATTR_MULTIPATH 0x008000
+#define ROUTE_ATTR_REALMS    0x010000
+#define ROUTE_ATTR_CACHEINFO 0x020000
+/** @endcond */
+
+static void route_constructor(struct nl_object *c)
+{
+	struct rtnl_route *r = (struct rtnl_route *) c;
+
+	r->rt_family = AF_UNSPEC;
+	r->rt_scope = RT_SCOPE_NOWHERE;
+	r->rt_table = RT_TABLE_MAIN;
+	r->rt_protocol = RTPROT_STATIC;
+	r->rt_type = RTN_UNICAST;
+
+	nl_init_list_head(&r->rt_nexthops);
+}
+
+static void route_free_data(struct nl_object *c)
+{
+	struct rtnl_route *r = (struct rtnl_route *) c;
+	struct rtnl_nexthop *nh, *tmp;
+
+	if (r == NULL)
+		return;
+
+	nl_addr_put(r->rt_dst);
+	nl_addr_put(r->rt_src);
+	nl_addr_put(r->rt_pref_src);
+
+	nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
+		rtnl_route_remove_nexthop(r, nh);
+		rtnl_route_nh_free(nh);
+	}
+}
+
+static int route_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct rtnl_route *dst = (struct rtnl_route *) _dst;
+	struct rtnl_route *src = (struct rtnl_route *) _src;
+	struct rtnl_nexthop *nh, *new;
+
+	if (src->rt_dst)
+		if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
+			return -NLE_NOMEM;
+
+	if (src->rt_src)
+		if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
+			return -NLE_NOMEM;
+
+	if (src->rt_pref_src)
+		if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
+			return -NLE_NOMEM;
+
+	nl_init_list_head(&dst->rt_nexthops);
+	nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
+		new = rtnl_route_nh_clone(nh);
+		if (!new)
+			return -NLE_NOMEM;
+
+		rtnl_route_add_nexthop(dst, new);
+	}
+
+	return 0;
+}
+
+static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct rtnl_route *r = (struct rtnl_route *) a;
+	int cache = 0, flags;
+	char buf[64];
+
+	if (r->rt_flags & RTM_F_CLONED)
+		cache = 1;
+
+	nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
+
+	if (cache)
+		nl_dump(p, "cache ");
+
+	if (!(r->ce_mask & ROUTE_ATTR_DST) ||
+	    nl_addr_get_len(r->rt_dst) == 0)
+		nl_dump(p, "default ");
+	else
+		nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
+		nl_dump(p, "table %s ",
+			rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_TYPE)
+		nl_dump(p, "type %s ",
+			nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
+		nl_dump(p, "tos %#x ", r->rt_tos);
+
+	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+		struct rtnl_nexthop *nh;
+
+		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+			p->dp_ivar = NH_DUMP_FROM_ONELINE;
+			rtnl_route_nh_dump(nh, p);
+		}
+	}
+
+	flags = r->rt_flags & ~(RTM_F_CLONED);
+	if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
+
+		nl_dump(p, "<");
+
+#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
+		flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+		PRINT_FLAG(DEAD);
+		PRINT_FLAG(ONLINK);
+		PRINT_FLAG(PERVASIVE);
+#undef PRINT_FLAG
+
+#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
+		flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+		PRINT_FLAG(NOTIFY);
+		PRINT_FLAG(EQUALIZE);
+		PRINT_FLAG(PREFIX);
+#undef PRINT_FLAG
+
+#define PRINT_FLAG(f) if (flags & RTCF_##f) { \
+		flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+		PRINT_FLAG(NOTIFY);
+		PRINT_FLAG(REDIRECTED);
+		PRINT_FLAG(DOREDIRECT);
+		PRINT_FLAG(DIRECTSRC);
+		PRINT_FLAG(DNAT);
+		PRINT_FLAG(BROADCAST);
+		PRINT_FLAG(MULTICAST);
+		PRINT_FLAG(LOCAL);
+#undef PRINT_FLAG
+
+		nl_dump(p, ">");
+	}
+
+	nl_dump(p, "\n");
+}
+
+static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+	struct rtnl_route *r = (struct rtnl_route *) a;
+	struct nl_cache *link_cache;
+	char buf[128];
+	int i;
+
+	link_cache = nl_cache_mngt_require("route/link");
+
+	route_dump_line(a, p);
+	nl_dump_line(p, "    ");
+
+	if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
+		nl_dump(p, "preferred-src %s ",
+			nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
+		nl_dump(p, "scope %s ",
+			rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_PRIO)
+		nl_dump(p, "priority %#x ", r->rt_prio);
+
+	if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
+		nl_dump(p, "protocol %s ",
+			rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
+
+	if (r->ce_mask & ROUTE_ATTR_IIF) {
+		if (link_cache) {
+			nl_dump(p, "iif %s ",
+				rtnl_link_i2name(link_cache, r->rt_iif,
+						 buf, sizeof(buf)));
+		} else
+			nl_dump(p, "iif %d ", r->rt_iif);
+	}
+
+	if (r->ce_mask & ROUTE_ATTR_SRC)
+		nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
+
+	nl_dump(p, "\n");
+
+	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+		struct rtnl_nexthop *nh;
+
+		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+			nl_dump_line(p, "    ");
+			p->dp_ivar = NH_DUMP_FROM_DETAILS;
+			rtnl_route_nh_dump(nh, p);
+			nl_dump(p, "\n");
+		}
+	}
+
+	if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
+		nl_dump_line(p, "    cacheinfo error %d (%s)\n",
+			r->rt_cacheinfo.rtci_error,
+			strerror(-r->rt_cacheinfo.rtci_error));
+	}
+
+	if (r->ce_mask & ROUTE_ATTR_METRICS) {
+		nl_dump_line(p, "    metrics [");
+		for (i = 0; i < RTAX_MAX; i++)
+			if (r->rt_metrics_mask & (1 << i))
+				nl_dump(p, "%s %u ",
+					rtnl_route_metric2str(i+1,
+							      buf, sizeof(buf)),
+					r->rt_metrics[i]);
+		nl_dump(p, "]\n");
+	}
+}
+
+static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_route *route = (struct rtnl_route *) obj;
+
+	route_dump_details(obj, p);
+
+	if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
+		struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
+
+		nl_dump_line(p, "    used %u refcnt %u last-use %us "
+				"expires %us\n",
+			     ci->rtci_used, ci->rtci_clntref,
+			     ci->rtci_last_use / nl_get_user_hz(),
+			     ci->rtci_expires / nl_get_user_hz());
+	}
+}
+
+static int route_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_route *a = (struct rtnl_route *) _a;
+	struct rtnl_route *b = (struct rtnl_route *) _b;
+	struct rtnl_nexthop *nh_a, *nh_b;
+	int i, diff = 0, found;
+
+#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= ROUTE_DIFF(FAMILY,	a->rt_family != b->rt_family);
+	diff |= ROUTE_DIFF(TOS,		a->rt_tos != b->rt_tos);
+	diff |= ROUTE_DIFF(TABLE,	a->rt_table != b->rt_table);
+	diff |= ROUTE_DIFF(PROTOCOL,	a->rt_protocol != b->rt_protocol);
+	diff |= ROUTE_DIFF(SCOPE,	a->rt_scope != b->rt_scope);
+	diff |= ROUTE_DIFF(TYPE,	a->rt_type != b->rt_type);
+	diff |= ROUTE_DIFF(PRIO,	a->rt_prio != b->rt_prio);
+	diff |= ROUTE_DIFF(DST,		nl_addr_cmp(a->rt_dst, b->rt_dst));
+	diff |= ROUTE_DIFF(SRC,		nl_addr_cmp(a->rt_src, b->rt_src));
+	diff |= ROUTE_DIFF(IIF,		a->rt_iif != b->rt_iif);
+	diff |= ROUTE_DIFF(PREF_SRC,	nl_addr_cmp(a->rt_pref_src,
+						    b->rt_pref_src));
+
+	if (flags & LOOSE_COMPARISON) {
+		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+			found = 0;
+			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+					       rtnh_list) {
+				if (!rtnl_route_nh_compare(nh_a, nh_b,
+							nh_b->ce_mask, 1)) {
+					found = 1;
+					break;
+				}
+			}
+
+			if (!found)
+				goto nh_mismatch;
+		}
+
+		for (i = 0; i < RTAX_MAX - 1; i++) {
+			if (a->rt_metrics_mask & (1 << i) &&
+			    (!(b->rt_metrics_mask & (1 << i)) ||
+			     a->rt_metrics[i] != b->rt_metrics[i]))
+				ROUTE_DIFF(METRICS, 1);
+		}
+
+		diff |= ROUTE_DIFF(FLAGS,
+			  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
+	} else {
+		if (a->rt_nr_nh != a->rt_nr_nh)
+			goto nh_mismatch;
+
+		/* search for a dup in each nh of a */
+		nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
+			found = 0;
+			nl_list_for_each_entry(nh_b, &b->rt_nexthops,
+					       rtnh_list) {
+				if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found)
+				goto nh_mismatch;
+		}
+
+		/* search for a dup in each nh of b, covers case where a has
+		 * dupes itself */
+		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+			found = 0;
+			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+					       rtnh_list) {
+				if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found)
+				goto nh_mismatch;
+		}
+
+		for (i = 0; i < RTAX_MAX - 1; i++) {
+			if ((a->rt_metrics_mask & (1 << i)) ^
+			    (b->rt_metrics_mask & (1 << i)))
+				diff |= ROUTE_DIFF(METRICS, 1);
+			else
+				diff |= ROUTE_DIFF(METRICS,
+					a->rt_metrics[i] != b->rt_metrics[i]);
+		}
+
+		diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
+	}
+
+out:
+	return diff;
+
+nh_mismatch:
+	diff |= ROUTE_DIFF(MULTIPATH, 1);
+	goto out;
+
+#undef ROUTE_DIFF
+}
+
+static const struct trans_tbl route_attrs[] = {
+	__ADD(ROUTE_ATTR_FAMILY, family)
+	__ADD(ROUTE_ATTR_TOS, tos)
+	__ADD(ROUTE_ATTR_TABLE, table)
+	__ADD(ROUTE_ATTR_PROTOCOL, protocol)
+	__ADD(ROUTE_ATTR_SCOPE, scope)
+	__ADD(ROUTE_ATTR_TYPE, type)
+	__ADD(ROUTE_ATTR_FLAGS, flags)
+	__ADD(ROUTE_ATTR_DST, dst)
+	__ADD(ROUTE_ATTR_SRC, src)
+	__ADD(ROUTE_ATTR_IIF, iif)
+	__ADD(ROUTE_ATTR_OIF, oif)
+	__ADD(ROUTE_ATTR_GATEWAY, gateway)
+	__ADD(ROUTE_ATTR_PRIO, prio)
+	__ADD(ROUTE_ATTR_PREF_SRC, pref_src)
+	__ADD(ROUTE_ATTR_METRICS, metrics)
+	__ADD(ROUTE_ATTR_MULTIPATH, multipath)
+	__ADD(ROUTE_ATTR_REALMS, realms)
+	__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
+};
+
+static char *route_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, route_attrs,
+			   ARRAY_SIZE(route_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_route *rtnl_route_alloc(void)
+{
+	return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
+}
+
+void rtnl_route_get(struct rtnl_route *route)
+{
+	nl_object_get((struct nl_object *) route);
+}
+
+void rtnl_route_put(struct rtnl_route *route)
+{
+	nl_object_put((struct nl_object *) route);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
+{
+	route->rt_table = table;
+	route->ce_mask |= ROUTE_ATTR_TABLE;
+}
+
+uint32_t rtnl_route_get_table(struct rtnl_route *route)
+{
+	return route->rt_table;
+}
+
+void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
+{
+	route->rt_scope = scope;
+	route->ce_mask |= ROUTE_ATTR_SCOPE;
+}
+
+uint8_t rtnl_route_get_scope(struct rtnl_route *route)
+{
+	return route->rt_scope;
+}
+
+void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
+{
+	route->rt_tos = tos;
+	route->ce_mask |= ROUTE_ATTR_TOS;
+}
+
+uint8_t rtnl_route_get_tos(struct rtnl_route *route)
+{
+	return route->rt_tos;
+}
+
+void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
+{
+	route->rt_protocol = protocol;
+	route->ce_mask |= ROUTE_ATTR_PROTOCOL;
+}
+
+uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
+{
+	return route->rt_protocol;
+}
+
+void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
+{
+	route->rt_prio = prio;
+	route->ce_mask |= ROUTE_ATTR_PRIO;
+}
+
+uint32_t rtnl_route_get_priority(struct rtnl_route *route)
+{
+	return route->rt_prio;
+}
+
+int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
+{
+	if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
+		return -NLE_AF_NOSUPPORT;
+
+	route->rt_family = family;
+	route->ce_mask |= ROUTE_ATTR_FAMILY;
+
+	return 0;
+}
+
+uint8_t rtnl_route_get_family(struct rtnl_route *route)
+{
+	return route->rt_family;
+}
+
+int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
+{
+	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+		if (addr->a_family != route->rt_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		route->rt_family = addr->a_family;
+
+	if (route->rt_dst)
+		nl_addr_put(route->rt_dst);
+
+	nl_addr_get(addr);
+	route->rt_dst = addr;
+	
+	route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
+
+	return 0;
+}
+
+struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
+{
+	return route->rt_dst;
+}
+
+int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
+{
+	if (addr->a_family == AF_INET)
+		return -NLE_SRCRT_NOSUPPORT;
+
+	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+		if (addr->a_family != route->rt_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		route->rt_family = addr->a_family;
+
+	if (route->rt_src)
+		nl_addr_put(route->rt_src);
+
+	nl_addr_get(addr);
+	route->rt_src = addr;
+	route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
+
+	return 0;
+}
+
+struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
+{
+	return route->rt_src;
+}
+
+int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
+{
+	if (type > RTN_MAX)
+		return -NLE_RANGE;
+
+	route->rt_type = type;
+	route->ce_mask |= ROUTE_ATTR_TYPE;
+
+	return 0;
+}
+
+uint8_t rtnl_route_get_type(struct rtnl_route *route)
+{
+	return route->rt_type;
+}
+
+void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
+{
+	route->rt_flag_mask |= flags;
+	route->rt_flags |= flags;
+	route->ce_mask |= ROUTE_ATTR_FLAGS;
+}
+
+void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
+{
+	route->rt_flag_mask |= flags;
+	route->rt_flags &= ~flags;
+	route->ce_mask |= ROUTE_ATTR_FLAGS;
+}
+
+uint32_t rtnl_route_get_flags(struct rtnl_route *route)
+{
+	return route->rt_flags;
+}
+
+int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
+{
+	if (metric > RTAX_MAX || metric < 1)
+		return -NLE_RANGE;
+
+	route->rt_metrics[metric - 1] = value;
+
+	if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
+		route->rt_nmetrics++;
+		route->rt_metrics_mask |= (1 << (metric - 1));
+	}
+
+	route->ce_mask |= ROUTE_ATTR_METRICS;
+
+	return 0;
+}
+
+int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
+{
+	if (metric > RTAX_MAX || metric < 1)
+		return -NLE_RANGE;
+
+	if (route->rt_metrics_mask & (1 << (metric - 1))) {
+		route->rt_nmetrics--;
+		route->rt_metrics_mask &= ~(1 << (metric - 1));
+	}
+
+	return 0;
+}
+
+int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
+{
+	if (metric > RTAX_MAX || metric < 1)
+		return -NLE_RANGE;
+
+	if (!(route->rt_metrics_mask & (1 << (metric - 1))))
+		return -NLE_OBJ_NOTFOUND;
+
+	if (value)
+		*value = route->rt_metrics[metric - 1];
+
+	return 0;
+}
+
+int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
+{
+	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+		if (addr->a_family != route->rt_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		route->rt_family = addr->a_family;
+
+	if (route->rt_pref_src)
+		nl_addr_put(route->rt_pref_src);
+
+	nl_addr_get(addr);
+	route->rt_pref_src = addr;
+	route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
+
+	return 0;
+}
+
+struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
+{
+	return route->rt_pref_src;
+}
+
+void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
+{
+	route->rt_iif = ifindex;
+	route->ce_mask |= ROUTE_ATTR_IIF;
+}
+
+int rtnl_route_get_iif(struct rtnl_route *route)
+{
+	return route->rt_iif;
+}
+
+void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
+{
+	nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
+	route->rt_nr_nh++;
+	route->ce_mask |= ROUTE_ATTR_MULTIPATH;
+}
+
+void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
+{
+	if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
+		route->rt_nr_nh--;
+		nl_list_del(&nh->rtnh_list);
+	}
+}
+
+struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
+{
+	if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
+		return &route->rt_nexthops;
+
+	return NULL;
+}
+
+int rtnl_route_get_nnexthops(struct rtnl_route *route)
+{
+	if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
+		return route->rt_nr_nh;
+
+	return 0;
+}
+
+void rtnl_route_foreach_nexthop(struct rtnl_route *r,
+                                void (*cb)(struct rtnl_nexthop *, void *),
+                                void *arg)
+{
+	struct rtnl_nexthop *nh;
+    
+	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                        cb(nh, arg);
+		}
+	}
+}
+
+struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
+{
+	struct rtnl_nexthop *nh;
+	int i;
+    
+	if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
+		i = 0;
+		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                        if (i == n) return nh;
+			i++;
+		}
+	}
+        return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Guess scope of a route object.
+ * @arg route		Route object.
+ *
+ * Guesses the scope of a route object, based on the following rules:
+ * @code
+ *   1) Local route -> local scope
+ *   2) At least one nexthop not directly connected -> universe scope
+ *   3) All others -> link scope
+ * @endcode
+ *
+ * @return Scope value.
+ */
+int rtnl_route_guess_scope(struct rtnl_route *route)
+{
+	if (route->rt_type == RTN_LOCAL)
+		return RT_SCOPE_HOST;
+
+	if (!nl_list_empty(&route->rt_nexthops)) {
+		struct rtnl_nexthop *nh;
+
+		/*
+		 * Use scope uiniverse if there is at least one nexthop which
+		 * is not directly connected
+		 */
+		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+			if (nh->rtnh_gateway)
+				return RT_SCOPE_UNIVERSE;
+		}
+	}
+
+	return RT_SCOPE_LINK;
+}
+
+/** @} */
+
+static struct nla_policy route_policy[RTA_MAX+1] = {
+	[RTA_IIF]	= { .type = NLA_U32 },
+	[RTA_OIF]	= { .type = NLA_U32 },
+	[RTA_PRIORITY]	= { .type = NLA_U32 },
+	[RTA_FLOW]	= { .type = NLA_U32 },
+	[RTA_CACHEINFO]	= { .minlen = sizeof(struct rta_cacheinfo) },
+	[RTA_METRICS]	= { .type = NLA_NESTED },
+	[RTA_MULTIPATH]	= { .type = NLA_NESTED },
+};
+
+static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
+{
+	struct rtnl_nexthop *nh = NULL;
+	struct rtnexthop *rtnh = nla_data(attr);
+	size_t tlen = nla_len(attr);
+	int err;
+
+	while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
+		nh = rtnl_route_nh_alloc();
+		if (!nh)
+			return -NLE_NOMEM;
+
+		rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
+		rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
+		rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
+
+		if (rtnh->rtnh_len > sizeof(*rtnh)) {
+			struct nlattr *ntb[RTA_MAX + 1];
+
+			err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
+					RTNH_DATA(rtnh),
+					rtnh->rtnh_len - sizeof(*rtnh),
+					route_policy);
+			if (err < 0)
+				goto errout;
+
+			if (ntb[RTA_GATEWAY]) {
+				struct nl_addr *addr;
+
+				addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
+							  route->rt_family);
+				if (!addr) {
+					err = -NLE_NOMEM;
+					goto errout;
+				}
+
+				rtnl_route_nh_set_gateway(nh, addr);
+				nl_addr_put(addr);
+			}
+
+			if (ntb[RTA_FLOW]) {
+				uint32_t realms;
+				
+				realms = nla_get_u32(ntb[RTA_FLOW]);
+				rtnl_route_nh_set_realms(nh, realms);
+			}
+		}
+
+		rtnl_route_add_nexthop(route, nh);
+		tlen -= RTNH_ALIGN(rtnh->rtnh_len);
+		rtnh = RTNH_NEXT(rtnh);
+	}
+
+	err = 0;
+errout:
+	if (err && nh)
+		rtnl_route_nh_free(nh);
+
+	return err;
+}
+
+int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
+{
+	struct rtmsg *rtm;
+	struct rtnl_route *route;
+	struct nlattr *tb[RTA_MAX + 1];
+	struct nl_addr *src = NULL, *dst = NULL, *addr;
+	struct rtnl_nexthop *old_nh = NULL;
+	int err, family;
+
+	route = rtnl_route_alloc();
+	if (!route) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	route->ce_msgtype = nlh->nlmsg_type;
+
+	err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
+	if (err < 0)
+		goto errout;
+
+	rtm = nlmsg_data(nlh);
+	route->rt_family = family = rtm->rtm_family;
+	route->rt_tos = rtm->rtm_tos;
+	route->rt_table = rtm->rtm_table;
+	route->rt_type = rtm->rtm_type;
+	route->rt_scope = rtm->rtm_scope;
+	route->rt_protocol = rtm->rtm_protocol;
+	route->rt_flags = rtm->rtm_flags;
+
+	route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
+			  ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
+			  ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
+			  ROUTE_ATTR_FLAGS;
+
+	if (tb[RTA_DST]) {
+		if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
+			goto errout_nomem;
+	} else {
+		if (!(dst = nl_addr_alloc(0)))
+			goto errout_nomem;
+		nl_addr_set_family(dst, rtm->rtm_family);
+	}
+
+	nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
+	err = rtnl_route_set_dst(route, dst);
+	if (err < 0)
+		goto errout;
+
+	nl_addr_put(dst);
+
+	if (tb[RTA_SRC]) {
+		if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
+			goto errout_nomem;
+	} else if (rtm->rtm_src_len)
+		if (!(src = nl_addr_alloc(0)))
+			goto errout_nomem;
+
+	if (src) {
+		nl_addr_set_prefixlen(src, rtm->rtm_src_len);
+		rtnl_route_set_src(route, src);
+		nl_addr_put(src);
+	}
+
+	if (tb[RTA_IIF])
+		rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
+
+	if (tb[RTA_PRIORITY])
+		rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
+
+	if (tb[RTA_PREFSRC]) {
+		if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
+			goto errout_nomem;
+		rtnl_route_set_pref_src(route, addr);
+		nl_addr_put(addr);
+	}
+
+	if (tb[RTA_METRICS]) {
+		struct nlattr *mtb[RTAX_MAX + 1];
+		int i;
+
+		err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
+		if (err < 0)
+			goto errout;
+
+		for (i = 1; i <= RTAX_MAX; i++) {
+			if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
+				uint32_t m = nla_get_u32(mtb[i]);
+				if (rtnl_route_set_metric(route, i, m) < 0)
+					goto errout;
+			}
+		}
+	}
+
+	if (tb[RTA_MULTIPATH])
+		if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
+			goto errout;
+
+	if (tb[RTA_CACHEINFO]) {
+		nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
+			   sizeof(route->rt_cacheinfo));
+		route->ce_mask |= ROUTE_ATTR_CACHEINFO;
+	}
+
+	if (tb[RTA_OIF]) {
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout;
+
+		rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
+	}
+
+	if (tb[RTA_GATEWAY]) {
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout;
+
+		if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
+			goto errout_nomem;
+
+		rtnl_route_nh_set_gateway(old_nh, addr);
+		nl_addr_put(addr);
+	}
+
+	if (tb[RTA_FLOW]) {
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout;
+
+		rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
+	}
+
+	if (old_nh) {
+		if (route->rt_nr_nh == 0) {
+			/* If no nexthops have been provided via RTA_MULTIPATH
+			 * we add it as regular nexthop to maintain backwards
+			 * compatibility */
+			rtnl_route_add_nexthop(route, old_nh);
+		} else {
+			/* Kernel supports new style nexthop configuration,
+			 * verify that it is a duplicate and discard nexthop. */
+			struct rtnl_nexthop *first;
+
+			first = nl_list_first_entry(&route->rt_nexthops,
+						    struct rtnl_nexthop,
+						    rtnh_list);
+			if (!first)
+				BUG();
+
+			if (rtnl_route_nh_compare(old_nh, first,
+						  old_nh->ce_mask, 0)) {
+				err = -NLE_INVAL;
+				goto errout;
+			}
+
+			rtnl_route_nh_free(old_nh);
+		}
+	}
+
+	*result = route;
+	return 0;
+
+errout:
+	rtnl_route_put(route);
+	return err;
+
+errout_nomem:
+	err = -NLE_NOMEM;
+	goto errout;
+}
+
+int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
+{
+	int i;
+	struct nlattr *metrics;
+	struct rtmsg rtmsg = {
+		.rtm_family = route->rt_family,
+		.rtm_tos = route->rt_tos,
+		.rtm_table = route->rt_table,
+		.rtm_protocol = route->rt_protocol,
+		.rtm_scope = route->rt_scope,
+		.rtm_type = route->rt_type,
+		.rtm_flags = route->rt_flags,
+	};
+
+	if (route->rt_dst == NULL)
+		return -NLE_MISSING_ATTR;
+
+	rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
+	if (route->rt_src)
+		rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
+
+
+	if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
+		rtmsg.rtm_scope = rtnl_route_guess_scope(route);
+
+	if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	/* Additional table attribute replacing the 8bit in the header, was
+	 * required to allow more than 256 tables. */
+	NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
+
+	if (nl_addr_get_len(route->rt_dst))
+		NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
+	NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
+
+	if (route->ce_mask & ROUTE_ATTR_SRC)
+		NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
+
+	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
+		NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
+
+	if (route->ce_mask & ROUTE_ATTR_IIF)
+		NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
+
+	if (route->rt_nmetrics > 0) {
+		uint32_t val;
+
+		metrics = nla_nest_start(msg, RTA_METRICS);
+		if (metrics == NULL)
+			goto nla_put_failure;
+
+		for (i = 1; i <= RTAX_MAX; i++) {
+			if (!rtnl_route_get_metric(route, i, &val))
+				NLA_PUT_U32(msg, i, val);
+		}
+
+		nla_nest_end(msg, metrics);
+	}
+
+	if (rtnl_route_get_nnexthops(route) == 1) {
+		struct rtnl_nexthop *nh;
+
+		nh = rtnl_route_nexthop_n(route, 0);
+		if (nh->rtnh_gateway)
+			NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway);
+		if (nh->rtnh_ifindex)
+			NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex);
+		if (nh->rtnh_realms)
+			NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+	} else if (rtnl_route_get_nnexthops(route) > 1) {
+		struct nlattr *multipath;
+		struct rtnl_nexthop *nh;
+
+		if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
+			goto nla_put_failure;
+
+		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+			struct rtnexthop *rtnh;
+
+			rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
+			if (!rtnh)
+				goto nla_put_failure;
+
+			rtnh->rtnh_flags = nh->rtnh_flags;
+			rtnh->rtnh_hops = nh->rtnh_weight;
+			rtnh->rtnh_ifindex = nh->rtnh_ifindex;
+
+			if (nh->rtnh_gateway)
+				NLA_PUT_ADDR(msg, RTA_GATEWAY,
+					     nh->rtnh_gateway);
+
+			if (nh->rtnh_realms)
+				NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+
+			rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
+						(void *) rtnh;
+		}
+
+		nla_nest_end(msg, multipath);
+	}
+
+	return 0;
+
+nla_put_failure:
+	return -NLE_MSGSIZE;
+}
+
+/** @cond SKIP */
+struct nl_object_ops route_obj_ops = {
+	.oo_name		= "route/route",
+	.oo_size		= sizeof(struct rtnl_route),
+	.oo_constructor		= route_constructor,
+	.oo_free_data		= route_free_data,
+	.oo_clone		= route_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= route_dump_line,
+	    [NL_DUMP_DETAILS]	= route_dump_details,
+	    [NL_DUMP_STATS]	= route_dump_stats,
+	},
+	.oo_compare		= route_compare,
+	.oo_attrs2str		= route_attrs2str,
+	.oo_id_attrs		= (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
+				   ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
+};
+/** @endcond */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/route_utils.c b/libnetwork/libnl3/lib/route/route_utils.c
new file mode 100644
index 0000000..8b73f2b
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/route_utils.c
@@ -0,0 +1,171 @@
+/*
+ * lib/route/route_utils.c	Routing Utilities
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup route
+ * @defgroup route_utils Utilities
+ * @brief Routing Utility Functions
+ *
+ *
+ * @par 1) Translating Routing Table Names
+ * @code
+ * // libnl is only aware of the de facto standard routing table names.
+ * // Additional name <-> identifier associations have to be read in via
+ * // a configuration file, f.e. /etc/iproute2/rt_tables
+ * err = rtnl_route_read_table_names("/etc/iproute2/rt_tables");
+ *
+ * // Translating a table name to its idenfier
+ * int table = rtnl_route_str2table("main");
+ *
+ * // ... and the other way around.
+ * char buf[32];
+ * printf("Name: %s\n",
+ *        rtnl_route_table2str(table, buf, sizeof(buf)));
+ * @endcode
+ *
+ *
+ *
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+	
+/**
+ * @name Routing Table Identifier Translations
+ * @{
+ */
+
+static NL_LIST_HEAD(table_names);
+
+static int add_routing_table_name(long id, const char *name)
+{
+	return __trans_list_add(id, name, &table_names);
+}
+
+static void __init init_routing_table_names(void)
+{
+	add_routing_table_name(RT_TABLE_UNSPEC, "unspec");
+	add_routing_table_name(RT_TABLE_COMPAT, "compat");
+	add_routing_table_name(RT_TABLE_DEFAULT, "default");
+	add_routing_table_name(RT_TABLE_MAIN, "main");
+	add_routing_table_name(RT_TABLE_LOCAL, "local");
+};
+
+static void __exit release_routing_table_names(void)
+{
+	__trans_list_clear(&table_names);
+}
+
+int rtnl_route_read_table_names(const char *path)
+{
+	__trans_list_clear(&table_names);
+
+	return __nl_read_num_str_file(path, &add_routing_table_name);
+}
+
+char *rtnl_route_table2str(int table, char *buf, size_t size)
+{
+	return __list_type2str(table, buf, size, &table_names);
+}
+
+int rtnl_route_str2table(const char *name)
+{
+	return __list_str2type(name, &table_names);
+}
+
+
+/** @} */
+
+/**
+ * @name Routing Protocol Translations
+ * @{
+ */
+
+static NL_LIST_HEAD(proto_names);
+
+static int add_proto_name(long id, const char *name)
+{
+	return __trans_list_add(id, name, &proto_names);
+}
+
+static void __init init_proto_names(void)
+{
+	add_proto_name(RTPROT_UNSPEC, "unspec");
+	add_proto_name(RTPROT_REDIRECT, "redirect");
+	add_proto_name(RTPROT_KERNEL, "kernel");
+	add_proto_name(RTPROT_BOOT, "boot");
+	add_proto_name(RTPROT_STATIC, "static");
+};
+
+static void __exit release_proto_names(void)
+{
+	__trans_list_clear(&proto_names);
+}
+
+int rtnl_route_read_protocol_names(const char *path)
+{
+	__trans_list_clear(&proto_names);
+
+	return __nl_read_num_str_file(path, &add_proto_name);
+}
+
+char *rtnl_route_proto2str(int proto, char *buf, size_t size)
+{
+	return __list_type2str(proto, buf, size, &proto_names);
+}
+
+int rtnl_route_str2proto(const char *name)
+{
+	return __list_str2type(name, &proto_names);
+}
+
+/** @} */
+
+/**
+ * @name Routing Metrices Translations
+ * @{
+ */
+
+static const struct trans_tbl route_metrices[] = {
+	__ADD(RTAX_UNSPEC, unspec)
+	__ADD(RTAX_LOCK, lock)
+	__ADD(RTAX_MTU, mtu)
+	__ADD(RTAX_WINDOW, window)
+	__ADD(RTAX_RTT, rtt)
+	__ADD(RTAX_RTTVAR, rttvar)
+	__ADD(RTAX_SSTHRESH, ssthresh)
+	__ADD(RTAX_CWND, cwnd)
+	__ADD(RTAX_ADVMSS, advmss)
+	__ADD(RTAX_REORDERING, reordering)
+	__ADD(RTAX_HOPLIMIT, hoplimit)
+	__ADD(RTAX_INITCWND, initcwnd)
+	__ADD(RTAX_FEATURES, features)
+};
+
+char *rtnl_route_metric2str(int metric, char *buf, size_t size)
+{
+	return __type2str(metric, buf, size, route_metrices,
+			  ARRAY_SIZE(route_metrices));
+}
+
+int rtnl_route_str2metric(const char *name)
+{
+	return __str2type(name, route_metrices, ARRAY_SIZE(route_metrices));
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/rtnl.c b/libnetwork/libnl3/lib/route/rtnl.c
new file mode 100644
index 0000000..e5c0798
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/rtnl.c
@@ -0,0 +1,124 @@
+/*
+ * lib/route/rtnl.c		Routing Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @defgroup rtnl Routing Family
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send routing netlink request message
+ * @arg sk		Netlink socket.
+ * @arg type		Netlink message type.
+ * @arg family		Address family.
+ * @arg flags		Additional netlink message flags.
+ *
+ * Fills out a routing netlink request message and sends it out
+ * using nl_send_simple().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
+{
+	struct rtgenmsg gmsg = {
+		.rtgen_family = family,
+	};
+
+	return nl_send_simple(sk, type, flags, &gmsg, sizeof(gmsg));
+}
+
+/** @} */
+
+/**
+ * @name Routing Type Translations
+ * @{
+ */
+
+static const struct trans_tbl rtntypes[] = {
+	__ADD(RTN_UNSPEC,unspec)
+	__ADD(RTN_UNICAST,unicast)
+	__ADD(RTN_LOCAL,local)
+	__ADD(RTN_BROADCAST,broadcast)
+	__ADD(RTN_ANYCAST,anycast)
+	__ADD(RTN_MULTICAST,multicast)
+	__ADD(RTN_BLACKHOLE,blackhole)
+	__ADD(RTN_UNREACHABLE,unreachable)
+	__ADD(RTN_PROHIBIT,prohibit)
+	__ADD(RTN_THROW,throw)
+	__ADD(RTN_NAT,nat)
+	__ADD(RTN_XRESOLVE,xresolve)
+};
+
+char *nl_rtntype2str(int type, char *buf, size_t size)
+{
+	return __type2str(type, buf, size, rtntypes, ARRAY_SIZE(rtntypes));
+}
+
+int nl_str2rtntype(const char *name)
+{
+	return __str2type(name, rtntypes, ARRAY_SIZE(rtntypes));
+}
+
+/** @} */
+
+/**
+ * @name Scope Translations
+ * @{
+ */
+
+static const struct trans_tbl scopes[] = {
+	__ADD(255,nowhere)
+	__ADD(254,host)
+	__ADD(253,link)
+	__ADD(200,site)
+	__ADD(0,global)
+};
+
+char *rtnl_scope2str(int scope, char *buf, size_t size)
+{
+	return __type2str(scope, buf, size, scopes, ARRAY_SIZE(scopes));
+}
+
+int rtnl_str2scope(const char *name)
+{
+	return __str2type(name, scopes, ARRAY_SIZE(scopes));
+}
+
+/** @} */
+
+/**
+ * @name Realms Translations
+ * @{
+ */
+
+char * rtnl_realms2str(uint32_t realms, char *buf, size_t len)
+{
+	int from = RTNL_REALM_FROM(realms);
+	int to = RTNL_REALM_TO(realms);
+
+	snprintf(buf, len, "%d/%d", from, to);
+
+	return buf;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/rule.c b/libnetwork/libnl3/lib/route/rule.c
new file mode 100644
index 0000000..1a695cd
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/rule.c
@@ -0,0 +1,753 @@
+/*
+ * lib/route/rule.c          Routing Rules
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup rule Routing Rules
+ * @brief
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/rule.h>
+#include <inttypes.h>
+
+/** @cond SKIP */
+#define RULE_ATTR_FAMILY	0x0001
+#define RULE_ATTR_TABLE		0x0002
+#define RULE_ATTR_ACTION	0x0004
+#define RULE_ATTR_FLAGS		0x0008
+#define RULE_ATTR_IIFNAME	0x0010
+#define RULE_ATTR_OIFNAME	0x0020
+#define RULE_ATTR_PRIO		0x0040
+#define RULE_ATTR_MARK		0x0080
+#define RULE_ATTR_MASK		0x0100
+#define RULE_ATTR_GOTO		0x0200
+#define RULE_ATTR_SRC		0x0400
+#define RULE_ATTR_DST		0x0800
+#define RULE_ATTR_DSFIELD	0x1000
+#define RULE_ATTR_FLOW		0x2000
+
+static struct nl_cache_ops rtnl_rule_ops;
+static struct nl_object_ops rule_obj_ops;
+/** @endcond */
+
+static void rule_free_data(struct nl_object *c)
+{
+	struct rtnl_rule *rule = nl_object_priv(c);
+
+	if (!rule)
+		return;
+
+	nl_addr_put(rule->r_src);
+	nl_addr_put(rule->r_dst);
+}
+
+static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct rtnl_rule *dst = nl_object_priv(_dst);
+	struct rtnl_rule *src = nl_object_priv(_src);
+
+	if (src->r_src)
+		if (!(dst->r_src = nl_addr_clone(src->r_src)))
+			return -NLE_NOMEM;
+
+	if (src->r_dst)
+		if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
+			return -NLE_NOMEM;
+
+	return 0;
+}
+
+static struct nla_policy rule_policy[FRA_MAX+1] = {
+	[FRA_TABLE]	= { .type = NLA_U32 },
+	[FRA_IIFNAME]	= { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+	[FRA_OIFNAME]	= { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+	[FRA_PRIORITY]	= { .type = NLA_U32 },
+	[FRA_FWMARK]	= { .type = NLA_U32 },
+	[FRA_FWMASK]	= { .type = NLA_U32 },
+	[FRA_GOTO]	= { .type = NLA_U32 },
+	[FRA_FLOW]	= { .type = NLA_U32 },
+};
+
+static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			   struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+	struct rtnl_rule *rule;
+	struct fib_rule_hdr *frh;
+	struct nlattr *tb[FRA_MAX+1];
+	int err = 1, family;
+
+	rule = rtnl_rule_alloc();
+	if (!rule) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	rule->ce_msgtype = n->nlmsg_type;
+	frh = nlmsg_data(n);
+
+	err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy);
+	if (err < 0)
+		goto errout;
+
+	rule->r_family = family = frh->family;
+	rule->r_table = frh->table;
+	rule->r_action = frh->action;
+	rule->r_flags = frh->flags;
+
+	rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
+			 RULE_ATTR_FLAGS);
+
+	/* ipv4 only */
+	if (frh->tos) {
+		rule->r_dsfield = frh->tos;
+		rule->ce_mask |= RULE_ATTR_DSFIELD;
+	}
+
+	if (tb[FRA_TABLE]) {
+		rule->r_table = nla_get_u32(tb[FRA_TABLE]);
+		rule->ce_mask |= RULE_ATTR_TABLE;
+	}
+
+	if (tb[FRA_IIFNAME]) {
+		nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ);
+		rule->ce_mask |= RULE_ATTR_IIFNAME;
+	}
+
+	if (tb[FRA_OIFNAME]) {
+		nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ);
+		rule->ce_mask |= RULE_ATTR_OIFNAME;
+	}
+
+	if (tb[FRA_PRIORITY]) {
+		rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]);
+		rule->ce_mask |= RULE_ATTR_PRIO;
+	}
+
+	if (tb[FRA_FWMARK]) {
+		rule->r_mark = nla_get_u32(tb[FRA_FWMARK]);
+		rule->ce_mask |= RULE_ATTR_MARK;
+	}
+
+	if (tb[FRA_FWMASK]) {
+		rule->r_mask = nla_get_u32(tb[FRA_FWMASK]);
+		rule->ce_mask |= RULE_ATTR_MASK;
+	}
+
+	if (tb[FRA_GOTO]) {
+		rule->r_goto = nla_get_u32(tb[FRA_GOTO]);
+		rule->ce_mask |= RULE_ATTR_GOTO;
+	}
+
+	if (tb[FRA_SRC]) {
+		if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family)))
+			goto errout_enomem;
+
+		nl_addr_set_prefixlen(rule->r_src, frh->src_len);
+		rule->ce_mask |= RULE_ATTR_SRC;
+	}
+
+	if (tb[FRA_DST]) {
+		if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family)))
+			goto errout_enomem;
+		nl_addr_set_prefixlen(rule->r_dst, frh->dst_len);
+		rule->ce_mask |= RULE_ATTR_DST;
+	}
+
+	/* ipv4 only */
+	if (tb[FRA_FLOW]) {
+		rule->r_flow = nla_get_u32(tb[FRA_FLOW]);
+		rule->ce_mask |= RULE_ATTR_FLOW;
+	}
+
+	err = pp->pp_cb((struct nl_object *) rule, pp);
+errout:
+	rtnl_rule_put(rule);
+	return err;
+
+errout_enomem:
+	err = -NLE_NOMEM;
+	goto errout;
+}
+
+static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
+}
+
+static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
+{
+	struct rtnl_rule *r = (struct rtnl_rule *) o;
+	char buf[128];
+
+	nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
+	nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
+
+	if (r->ce_mask & RULE_ATTR_SRC)
+		nl_dump(p, "from %s ",
+			nl_addr2str(r->r_src, buf, sizeof(buf)));
+
+	if (r->ce_mask & RULE_ATTR_DST)
+		nl_dump(p, "to %s ",
+			nl_addr2str(r->r_dst, buf, sizeof(buf)));
+
+	if (r->ce_mask & RULE_ATTR_DSFIELD)
+		nl_dump(p, "tos %u ", r->r_dsfield);
+
+	if (r->ce_mask & (RULE_ATTR_MARK | RULE_ATTR_MASK))
+		nl_dump(p, "mark %#x/%#x", r->r_mark, r->r_mask);
+
+	if (r->ce_mask & RULE_ATTR_IIFNAME)
+		nl_dump(p, "iif %s ", r->r_iifname);
+
+	if (r->ce_mask & RULE_ATTR_OIFNAME)
+		nl_dump(p, "oif %s ", r->r_oifname);
+
+	if (r->ce_mask & RULE_ATTR_TABLE)
+		nl_dump(p, "lookup %s ",
+			rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
+
+	if (r->ce_mask & RULE_ATTR_FLOW)
+		nl_dump(p, "flow %s ",
+			rtnl_realms2str(r->r_flow, buf, sizeof(buf)));
+
+	if (r->ce_mask & RULE_ATTR_GOTO)
+		nl_dump(p, "goto %u ", r->r_goto);
+
+	if (r->ce_mask & RULE_ATTR_ACTION)
+		nl_dump(p, "action %s",
+			nl_rtntype2str(r->r_action, buf, sizeof(buf)));
+
+	nl_dump(p, "\n");
+}
+
+static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	rule_dump_line(obj, p);
+}
+
+static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	rule_dump_details(obj, p);
+}
+
+#define RULE_ATTR_FLAGS		0x0008
+
+static int rule_compare(struct nl_object *_a, struct nl_object *_b,
+			uint32_t attrs, int flags)
+{
+	struct rtnl_rule *a = (struct rtnl_rule *) _a;
+	struct rtnl_rule *b = (struct rtnl_rule *) _b;
+	int diff = 0;
+
+#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= RULE_DIFF(FAMILY,	a->r_family != b->r_family);
+	diff |= RULE_DIFF(TABLE,	a->r_table != b->r_table);
+	diff |= RULE_DIFF(ACTION,	a->r_action != b->r_action);
+	diff |= RULE_DIFF(IIFNAME,	strcmp(a->r_iifname, b->r_iifname));
+	diff |= RULE_DIFF(OIFNAME,	strcmp(a->r_oifname, b->r_oifname));
+	diff |= RULE_DIFF(PRIO,		a->r_prio != b->r_prio);
+	diff |= RULE_DIFF(MARK,		a->r_mark != b->r_mark);
+	diff |= RULE_DIFF(MASK,		a->r_mask != b->r_mask);
+	diff |= RULE_DIFF(GOTO,		a->r_goto != b->r_goto);
+	diff |= RULE_DIFF(SRC,		nl_addr_cmp(a->r_src, b->r_src));
+	diff |= RULE_DIFF(DST,		nl_addr_cmp(a->r_dst, b->r_dst));
+	diff |= RULE_DIFF(DSFIELD,	a->r_dsfield != b->r_dsfield);
+	diff |= RULE_DIFF(FLOW,		a->r_flow != b->r_flow);
+	
+#undef RULE_DIFF
+
+	return diff;
+}
+
+static const struct trans_tbl rule_attrs[] = {
+	__ADD(RULE_ATTR_FAMILY, family)
+	__ADD(RULE_ATTR_TABLE, table)
+	__ADD(RULE_ATTR_ACTION, action)
+	__ADD(RULE_ATTR_IIFNAME, iifname)
+	__ADD(RULE_ATTR_OIFNAME, oifname)
+	__ADD(RULE_ATTR_PRIO, prio)
+	__ADD(RULE_ATTR_MARK, mark)
+	__ADD(RULE_ATTR_MASK, mask)
+	__ADD(RULE_ATTR_GOTO, goto)
+	__ADD(RULE_ATTR_SRC, src)
+	__ADD(RULE_ATTR_DST, dst)
+	__ADD(RULE_ATTR_DSFIELD, dsfield)
+	__ADD(RULE_ATTR_FLOW, flow)
+};
+
+static char *rule_attrs2str(int attrs, char *buf, size_t len)
+{
+	return __flags2str(attrs, buf, len, rule_attrs,
+			   ARRAY_SIZE(rule_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_rule *rtnl_rule_alloc(void)
+{
+	return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
+}
+
+void rtnl_rule_put(struct rtnl_rule *rule)
+{
+	nl_object_put((struct nl_object *) rule);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a rule cache including all rules currently configured in the kernel.
+ * @arg sock		Netlink socket.
+ * @arg family		Address family or AF_UNSPEC.
+ * @arg result		Pointer to store resulting cache.
+ *
+ * Allocates a new rule cache, initializes it properly and updates it
+ * to include all rules currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
+			  struct nl_cache **result)
+{
+	struct nl_cache * cache;
+	int err;
+
+	if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = family;
+
+	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+		free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Rule Addition
+ * @{
+ */
+
+static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
+			  struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct fib_rule_hdr frh = {
+		.family = tmpl->r_family,
+		.table = tmpl->r_table,
+		.action = tmpl->r_action,
+		.flags = tmpl->r_flags,
+		.tos = tmpl->r_dsfield,
+	};
+
+	if (!(tmpl->ce_mask & RULE_ATTR_FAMILY))
+		return -NLE_MISSING_ATTR;
+
+	msg = nlmsg_alloc_simple(cmd, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (tmpl->ce_mask & RULE_ATTR_SRC) 
+		frh.src_len = nl_addr_get_prefixlen(tmpl->r_src);
+
+	if (tmpl->ce_mask & RULE_ATTR_DST)
+		frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst);
+
+	if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (tmpl->ce_mask & RULE_ATTR_SRC)
+		NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src);
+
+	if (tmpl->ce_mask & RULE_ATTR_DST) 
+		NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst);
+
+	if (tmpl->ce_mask & RULE_ATTR_IIFNAME)
+		NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname);
+
+	if (tmpl->ce_mask & RULE_ATTR_OIFNAME)
+		NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname);
+
+	if (tmpl->ce_mask & RULE_ATTR_PRIO)
+		NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio);
+
+	if (tmpl->ce_mask & RULE_ATTR_MARK)
+		NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark);
+
+	if (tmpl->ce_mask & RULE_ATTR_MASK)
+		NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask);
+
+	if (tmpl->ce_mask & RULE_ATTR_GOTO)
+		NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto);
+
+	if (tmpl->ce_mask & RULE_ATTR_FLOW)
+		NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
+
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -NLE_MSGSIZE;
+}
+
+/**
+ * Build netlink request message to add a new rule
+ * @arg tmpl		template with data of new rule
+ * @arg flags		additional netlink message flags
+ * @arg result		Result pointer
+ *
+ * Builds a new netlink message requesting a addition of a new
+ * rule. The netlink message header isn't fully equipped with
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a tmpl must contain the attributes of the new
+ * address set via \c rtnl_rule_set_* functions.
+ * 
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
+				struct nl_msg **result)
+{
+	return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
+			      result);
+}
+
+/**
+ * Add a new rule
+ * @arg sk		Netlink socket.
+ * @arg tmpl		template with requested changes
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_rule_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Rule Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink request message to delete a rule
+ * @arg rule		rule to delete
+ * @arg flags		additional netlink message flags
+ * @arg result		Result pointer
+ *
+ * Builds a new netlink message requesting a deletion of a rule.
+ * The netlink message header isn't fully equipped with all relevant
+ * fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a rule must point to an existing
+ * address.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
+				   struct nl_msg **result)
+{
+	return build_rule_msg(rule, RTM_DELRULE, flags, result);
+}
+
+/**
+ * Delete a rule
+ * @arg sk		Netlink socket.
+ * @arg rule		rule to delete
+ * @arg flags		additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_rule_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
+{
+	struct nl_msg *msg;
+	int err;
+	
+	if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
+		return err;
+
+	err = nl_send_auto_complete(sk, msg);
+	nlmsg_free(msg);
+	if (err < 0)
+		return err;
+
+	return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
+{
+	rule->r_family = family;
+	rule->ce_mask |= RULE_ATTR_FAMILY;
+}
+
+int rtnl_rule_get_family(struct rtnl_rule *rule)
+{
+	if (rule->ce_mask & RULE_ATTR_FAMILY)
+		return rule->r_family;
+	else
+		return AF_UNSPEC;
+}
+
+void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio)
+{
+	rule->r_prio = prio;
+	rule->ce_mask |= RULE_ATTR_PRIO;
+}
+
+uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule)
+{
+	return rule->r_prio;
+}
+
+void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark)
+{
+	rule->r_mark = mark;
+	rule->ce_mask |= RULE_ATTR_MARK;
+}
+
+uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule)
+{
+	return rule->r_mark;
+}
+
+void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask)
+{
+	rule->r_mask = mask;
+	rule->ce_mask |= RULE_ATTR_MASK;
+}
+
+uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule)
+{
+	return rule->r_mask;
+}
+
+void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table)
+{
+	rule->r_table = table;
+	rule->ce_mask |= RULE_ATTR_TABLE;
+}
+
+uint32_t rtnl_rule_get_table(struct rtnl_rule *rule)
+{
+	return rule->r_table;
+}
+
+void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield)
+{
+	rule->r_dsfield = dsfield;
+	rule->ce_mask |= RULE_ATTR_DSFIELD;
+}
+
+uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule)
+{
+	return rule->r_dsfield;
+}
+
+static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
+			        struct nl_addr *new, int flag)
+{
+	if (rule->ce_mask & RULE_ATTR_FAMILY) {
+		if (new->a_family != rule->r_family)
+			return -NLE_AF_MISMATCH;
+	} else
+		rule->r_family = new->a_family;
+
+	if (*pos)
+		nl_addr_put(*pos);
+
+	nl_addr_get(new);
+	*pos = new;
+
+	rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
+
+	return 0;
+}
+
+int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
+{
+	return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC);
+}
+
+struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
+{
+	return rule->r_src;
+}
+
+int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
+{
+	return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST);
+}
+
+struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
+{
+	return rule->r_dst;
+}
+
+int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
+{
+	if (strlen(dev) > IFNAMSIZ-1)
+		return -NLE_RANGE;
+
+	strcpy(rule->r_iifname, dev);
+	rule->ce_mask |= RULE_ATTR_IIFNAME;
+	return 0;
+}
+
+char *rtnl_rule_get_iif(struct rtnl_rule *rule)
+{
+	if (rule->ce_mask & RULE_ATTR_IIFNAME)
+		return rule->r_iifname;
+	else
+		return NULL;
+}
+
+int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev)
+{
+	if (strlen(dev) > IFNAMSIZ-1)
+		return -NLE_RANGE;
+
+	strcpy(rule->r_oifname, dev);
+	rule->ce_mask |= RULE_ATTR_OIFNAME;
+	return 0;
+}
+
+char *rtnl_rule_get_oif(struct rtnl_rule *rule)
+{
+	if (rule->ce_mask & RULE_ATTR_OIFNAME)
+		return rule->r_oifname;
+	else
+		return NULL;
+}
+
+void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action)
+{
+	rule->r_action = action;
+	rule->ce_mask |= RULE_ATTR_ACTION;
+}
+
+uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
+{
+	return rule->r_action;
+}
+
+void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
+{
+	rule->r_flow = realms;
+	rule->ce_mask |= RULE_ATTR_FLOW;
+}
+
+uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
+{
+	return rule->r_flow;
+}
+
+void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref)
+{
+	rule->r_goto = ref;
+	rule->ce_mask |= RULE_ATTR_GOTO;
+}
+
+uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule)
+{
+	return rule->r_goto;
+}
+
+/** @} */
+
+static struct nl_object_ops rule_obj_ops = {
+	.oo_name		= "route/rule",
+	.oo_size		= sizeof(struct rtnl_rule),
+	.oo_free_data		= rule_free_data,
+	.oo_clone		= rule_clone,
+	.oo_dump = {
+	    [NL_DUMP_LINE]	= rule_dump_line,
+	    [NL_DUMP_DETAILS]	= rule_dump_details,
+	    [NL_DUMP_STATS]	= rule_dump_stats,
+	},
+	.oo_compare		= rule_compare,
+	.oo_attrs2str		= rule_attrs2str,
+	.oo_id_attrs		= ~0,
+};
+
+static struct nl_cache_ops rtnl_rule_ops = {
+	.co_name		= "route/rule",
+	.co_hdrsize		= sizeof(struct fib_rule_hdr),
+	.co_msgtypes		= {
+					{ RTM_NEWRULE, NL_ACT_NEW, "new" },
+					{ RTM_DELRULE, NL_ACT_DEL, "del" },
+					{ RTM_GETRULE, NL_ACT_GET, "get" },
+					END_OF_MSGTYPES_LIST,
+				  },
+	.co_protocol		= NETLINK_ROUTE,
+	.co_request_update	= rule_request_update,
+	.co_msg_parser		= rule_msg_parser,
+	.co_obj_ops		= &rule_obj_ops,
+};
+
+static void __init rule_init(void)
+{
+	nl_cache_mngt_register(&rtnl_rule_ops);
+}
+
+static void __exit rule_exit(void)
+{
+	nl_cache_mngt_unregister(&rtnl_rule_ops);
+}
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/route/tc.c b/libnetwork/libnl3/lib/route/tc.c
new file mode 100644
index 0000000..6826a05
--- /dev/null
+++ b/libnetwork/libnl3/lib/route/tc.c
@@ -0,0 +1,1069 @@
+/*
+ * lib/route/tc.c		Traffic Control
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup tc Traffic Control
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/tc-api.h>
+
+/** @cond SKIP */
+
+static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
+static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX];
+
+static struct nla_policy tc_policy[TCA_MAX+1] = {
+	[TCA_KIND]	= { .type = NLA_STRING,
+			    .maxlen = TCKINDSIZ },
+	[TCA_STATS]	= { .minlen = sizeof(struct tc_stats) },
+	[TCA_STATS2]	= { .type = NLA_NESTED },
+};
+
+int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g,
+	      struct nla_policy *policy)
+{
+	
+	if (g->ce_mask & TCA_ATTR_OPTS)
+		return nla_parse(tb, maxattr,
+				 (struct nlattr *) g->tc_opts->d_data,
+				 g->tc_opts->d_size, policy);
+	else {
+		/* Ugly but tb[] must be in a defined state even if no
+		 * attributes can be found. */
+		memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1));
+		return 0;
+	}
+}
+
+static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
+	[TCA_STATS_BASIC]    = { .minlen = sizeof(struct gnet_stats_basic) },
+	[TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) },
+	[TCA_STATS_QUEUE]    = { .minlen = sizeof(struct gnet_stats_queue) },
+};
+
+int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
+{
+	struct nl_cache *link_cache;
+	struct rtnl_tc_ops *ops;
+	struct nlattr *tb[TCA_MAX + 1];
+	char kind[TCKINDSIZ];
+	struct tcmsg *tm;
+	int err;
+
+	tc->ce_msgtype = n->nlmsg_type;
+
+	err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_KIND] == NULL)
+		return -NLE_MISSING_ATTR;
+
+	nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
+	rtnl_tc_set_kind(tc, kind);
+
+	tm = nlmsg_data(n);
+	tc->tc_family  = tm->tcm_family;
+	tc->tc_ifindex = tm->tcm_ifindex;
+	tc->tc_handle  = tm->tcm_handle;
+	tc->tc_parent  = tm->tcm_parent;
+	tc->tc_info    = tm->tcm_info;
+
+	tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
+		        TCA_ATTR_PARENT | TCA_ATTR_INFO);
+
+	if (tb[TCA_OPTIONS]) {
+		tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
+		if (!tc->tc_opts)
+			return -NLE_NOMEM;
+		tc->ce_mask |= TCA_ATTR_OPTS;
+	}
+
+	if (tb[TCA_STATS2]) {
+		struct nlattr *tbs[TCA_STATS_MAX + 1];
+
+		err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
+				       tc_stats2_policy);
+		if (err < 0)
+			return err;
+
+		if (tbs[TCA_STATS_BASIC]) {
+			struct gnet_stats_basic *bs;
+			
+			bs = nla_data(tbs[TCA_STATS_BASIC]);
+			tc->tc_stats[RTNL_TC_BYTES]	= bs->bytes;
+			tc->tc_stats[RTNL_TC_PACKETS]	= bs->packets;
+		}
+
+		if (tbs[TCA_STATS_RATE_EST]) {
+			struct gnet_stats_rate_est *re;
+
+			re = nla_data(tbs[TCA_STATS_RATE_EST]);
+			tc->tc_stats[RTNL_TC_RATE_BPS]	= re->bps;
+			tc->tc_stats[RTNL_TC_RATE_PPS]	= re->pps;
+		}
+		
+		if (tbs[TCA_STATS_QUEUE]) {
+			struct gnet_stats_queue *q;
+
+			q = nla_data(tbs[TCA_STATS_QUEUE]);
+			tc->tc_stats[RTNL_TC_QLEN]	= q->qlen;
+			tc->tc_stats[RTNL_TC_BACKLOG]	= q->backlog;
+			tc->tc_stats[RTNL_TC_DROPS]	= q->drops;
+			tc->tc_stats[RTNL_TC_REQUEUES]	= q->requeues;
+			tc->tc_stats[RTNL_TC_OVERLIMITS]	= q->overlimits;
+		}
+
+		tc->ce_mask |= TCA_ATTR_STATS;
+		
+		if (tbs[TCA_STATS_APP]) {
+			tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
+			if (tc->tc_xstats == NULL)
+				return -NLE_NOMEM;
+		} else
+			goto compat_xstats;
+	} else {
+		if (tb[TCA_STATS]) {
+			struct tc_stats *st = nla_data(tb[TCA_STATS]);
+
+			tc->tc_stats[RTNL_TC_BYTES]	= st->bytes;
+			tc->tc_stats[RTNL_TC_PACKETS]	= st->packets;
+			tc->tc_stats[RTNL_TC_RATE_BPS]	= st->bps;
+			tc->tc_stats[RTNL_TC_RATE_PPS]	= st->pps;
+			tc->tc_stats[RTNL_TC_QLEN]	= st->qlen;
+			tc->tc_stats[RTNL_TC_BACKLOG]	= st->backlog;
+			tc->tc_stats[RTNL_TC_DROPS]	= st->drops;
+			tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits;
+
+			tc->ce_mask |= TCA_ATTR_STATS;
+		}
+
+compat_xstats:
+		if (tb[TCA_XSTATS]) {
+			tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
+			if (tc->tc_xstats == NULL)
+				return -NLE_NOMEM;
+			tc->ce_mask |= TCA_ATTR_XSTATS;
+		}
+	}
+
+	ops = rtnl_tc_get_ops(tc);
+	if (ops && ops->to_msg_parser) {
+		void *data = rtnl_tc_data(tc);
+
+		if (!data)
+			return -NLE_NOMEM;
+
+		err = ops->to_msg_parser(tc, data);
+		if (err < 0)
+			return err;
+	}
+
+	if ((link_cache = __nl_cache_mngt_require("route/link"))) {
+		struct rtnl_link *link;
+
+		if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
+			rtnl_tc_set_link(tc, link);
+
+			/* rtnl_tc_set_link incs refcnt */
+			rtnl_link_put(link);
+		}
+	}
+
+	return 0;
+}
+
+int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
+		      struct nl_msg **result)
+{
+	struct nl_msg *msg;
+	struct rtnl_tc_ops *ops;
+	struct tcmsg tchdr = {
+		.tcm_family = AF_UNSPEC,
+		.tcm_ifindex = tc->tc_ifindex,
+		.tcm_handle = tc->tc_handle,
+		.tcm_parent = tc->tc_parent,
+	};
+	int err = -NLE_MSGSIZE;
+
+	msg = nlmsg_alloc_simple(type, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	if (tc->ce_mask & TCA_ATTR_KIND)
+	    NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);
+
+	ops = rtnl_tc_get_ops(tc);
+	if (ops && ops->to_msg_fill) {
+		struct nlattr *opts;
+		void *data = rtnl_tc_data(tc);
+
+		if (!(opts = nla_nest_start(msg, TCA_OPTIONS)))
+			goto nla_put_failure;
+
+		if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
+			goto nla_put_failure;
+
+		nla_nest_end(msg, opts);
+	}
+
+	*result = msg;
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return err;
+}
+
+void tca_set_kind(struct rtnl_tc *t, const char *kind)
+{
+	strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
+	t->ce_mask |= TCA_ATTR_KIND;
+}
+
+
+/** @endcond */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+/**
+ * Set interface index of traffic control object
+ * @arg tc		traffic control object
+ * @arg ifindex		interface index.
+ *
+ * Sets the interface index of a traffic control object. The interface
+ * index defines the network device which this tc object is attached to.
+ * This function will overwrite any network device assigned with previous
+ * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link().
+ */
+void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
+{
+	/* Obsolete possible old link reference */
+	rtnl_link_put(tc->tc_link);
+	tc->tc_link = NULL;
+	tc->ce_mask &= ~TCA_ATTR_LINK;
+
+	tc->tc_ifindex = ifindex;
+	tc->ce_mask |= TCA_ATTR_IFINDEX;
+}
+
+/**
+ * Return interface index of traffic control object
+ * @arg tc		traffic control object
+ */
+int rtnl_tc_get_ifindex(struct rtnl_tc *tc)
+{
+	return tc->tc_ifindex;
+}
+
+/**
+ * Set link of traffic control object
+ * @arg tc		traffic control object
+ * @arg link		link object
+ *
+ * Sets the link of a traffic control object. This function serves
+ * the same purpose as rtnl_tc_set_ifindex() but due to the continued
+ * allowed access to the link object it gives it the possibility to
+ * retrieve sane default values for the the MTU and the linktype.
+ * Always prefer this function over rtnl_tc_set_ifindex() if you can
+ * spare to have an additional link object around.
+ */
+void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
+{
+	rtnl_link_put(tc->tc_link);
+
+	if (!link)
+		return;
+
+	nl_object_get(OBJ_CAST(link));
+	tc->tc_link = link;
+	tc->tc_ifindex = link->l_index;
+	tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
+}
+
+/**
+ * Get link of traffic control object
+ * @arg tc		traffic control object
+ *
+ * Returns the link of a traffic control object. The link is only
+ * returned if it has been set before via rtnl_tc_set_link() or
+ * if a link cache was available while parsing the tc object. This
+ * function may still return NULL even if an ifindex is assigned to
+ * the tc object. It will _not_ look up the link by itself.
+ *
+ * @note The returned link will have its reference counter incremented.
+ *       It is in the responsibility of the caller to return the
+ *       reference.
+ *
+ * @return link object or NULL if not set.
+ */
+struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc)
+{
+	if (tc->tc_link) {
+		nl_object_get(OBJ_CAST(tc->tc_link));
+		return tc->tc_link;
+	}
+
+	return NULL;
+}
+
+/**
+ * Set the Maximum Transmission Unit (MTU) of traffic control object
+ * @arg tc		traffic control object
+ * @arg mtu		largest packet size expected
+ *
+ * Sets the MTU of a traffic control object. Not all traffic control
+ * objects will make use of this but it helps while calculating rate
+ * tables. This value is typically derived directly from the link
+ * the tc object is attached to if the link has been assigned via
+ * rtnl_tc_set_link(). It is usually not necessary to set the MTU
+ * manually, this function is provided to allow overwriting the derived
+ * value.
+ */
+void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu)
+{
+	tc->tc_mtu = mtu;
+	tc->ce_mask |= TCA_ATTR_MTU;
+}
+
+/**
+ * Return the MTU of traffic control object
+ * @arg tc		traffic control object
+ *
+ * Returns the MTU of a traffic control object which has been set via:
+ * -# User specified value set via rtnl_tc_set_mtu()
+ * -# Dervied from link set via rtnl_tc_set_link()
+ * -# Fall back to default: ethernet = 1500
+ */
+uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
+{
+	if (tc->ce_mask & TCA_ATTR_MTU)
+		return tc->tc_mtu;
+	else if (tc->ce_mask & TCA_ATTR_LINK)
+		return tc->tc_link->l_mtu;
+	else
+		return 1500; /* default to ethernet */
+}
+
+/**
+ * Set the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc		traffic control object
+ * @arg mpu		minimum packet size expected
+ *
+ * Sets the MPU of a traffic contorl object. It specifies the minimum
+ * packet size to ever hit this traffic control object. Not all traffic
+ * control objects will make use of this but it helps while calculating
+ * rate tables.
+ */
+void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
+{
+	tc->tc_mpu = mpu;
+	tc->ce_mask |= TCA_ATTR_MPU;
+}
+
+/**
+ * Return the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc		traffic control object
+ *
+ * @return The MPU previously set via rtnl_tc_set_mpu() or 0.
+ */
+uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc)
+{
+	return tc->tc_mpu;
+}
+
+/**
+ * Set per packet overhead of a traffic control object
+ * @arg tc		traffic control object
+ * @arg overhead	overhead per packet in bytes
+ *
+ * Sets the per packet overhead in bytes occuring on the link not seen
+ * by the kernel. This value can be used to correct size calculations
+ * if the packet size on the wire does not match the packet sizes seen
+ * in the network stack. Not all traffic control objects will make use
+ * this but it helps while calculating accurate packet sizes in the
+ * kernel.
+ */
+void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
+{
+	tc->tc_overhead = overhead;
+	tc->ce_mask |= TCA_ATTR_OVERHEAD;
+}
+
+/**
+ * Return per packet overhead of a traffic control object
+ * @arg tc		traffic control object
+ *
+ * @return The overhead previously set by rtnl_tc_set_overhead() or 0.
+ */
+uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc)
+{
+	return tc->tc_overhead;
+}
+
+/**
+ * Set the linktype of a traffic control object
+ * @arg tc		traffic control object
+ * @arg type		type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER)
+ *
+ * Overwrites the type of link this traffic control object is attached to.
+ * This value is typically derived from the link this tc object is attached
+ * if the link has been assigned via rtnl_tc_set_link(). It is usually not
+ * necessary to set the linktype manually. This function is provided to
+ * allow overwriting the linktype.
+ */
+void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type)
+{
+	tc->tc_linktype = type;
+	tc->ce_mask |= TCA_ATTR_LINKTYPE;
+}
+
+/**
+ * Return the linktype of a traffic control object
+ * @arg tc		traffic control object
+ *
+ * Returns the linktype of the link the traffic control object is attached to:
+ * -# User specified value via rtnl_tc_set_linktype()
+ * -# Value derived from link set via rtnl_tc_set_link()
+ * -# Default fall-back: ARPHRD_ETHER
+ */
+uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc)
+{
+	if (tc->ce_mask & TCA_ATTR_LINKTYPE)
+		return tc->tc_linktype;
+	else if (tc->ce_mask & TCA_ATTR_LINK)
+		return tc->tc_link->l_arptype;
+	else
+		return ARPHRD_ETHER; /* default to ethernet */
+}
+
+/**
+ * Set identifier of traffic control object
+ * @arg tc		traffic control object
+ * @arg id		unique identifier
+ */
+void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
+{
+	tc->tc_handle = id;
+	tc->ce_mask |= TCA_ATTR_HANDLE;
+}
+
+/**
+ * Return identifier of a traffic control object
+ * @arg tc		traffic control object
+ */
+uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc)
+{
+	return tc->tc_handle;
+}
+
+/**
+ * Set the parent identifier of a traffic control object
+ * @arg tc		traffic control object
+ * @arg parent		identifier of parent traffif control object
+ *
+ */
+void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
+{
+	tc->tc_parent = parent;
+	tc->ce_mask |= TCA_ATTR_PARENT;
+}
+
+/**
+ * Return parent identifier of a traffic control object
+ * @arg tc		traffic control object
+ */
+uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc)
+{
+	return tc->tc_parent;
+}
+
+/**
+ * Define the type of traffic control object
+ * @arg tc		traffic control object
+ * @arg kind		name of the tc object type
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
+{
+	if (tc->ce_mask & TCA_ATTR_KIND)
+		return -NLE_EXIST;
+
+	strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1);
+	tc->ce_mask |= TCA_ATTR_KIND;
+
+	/* Force allocation of data */
+	rtnl_tc_data(tc);
+
+	return 0;
+}
+
+/**
+ * Return kind of traffic control object
+ * @arg tc		traffic control object
+ *
+ * @return Kind of traffic control object or NULL if not set.
+ */
+char *rtnl_tc_get_kind(struct rtnl_tc *tc)
+{
+	if (tc->ce_mask & TCA_ATTR_KIND)
+		return tc->tc_kind;
+	else
+		return NULL;
+}
+
+/**
+ * Return value of a statistical counter of a traffic control object
+ * @arg tc		traffic control object
+ * @arg id		identifier of statistical counter
+ *
+ * @return Value of requested statistic counter or 0.
+ */
+uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
+{
+	if (id < 0 || id > RTNL_TC_STATS_MAX)
+		return 0;
+
+	return tc->tc_stats[id];
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Calculate time required to transmit buffer at a specific rate
+ * @arg bufsize		Size of buffer to be transmited in bytes.
+ * @arg rate		Transmit rate in bytes per second.
+ *
+ * Calculates the number of micro seconds required to transmit a
+ * specific buffer at a specific transmit rate.
+ *
+ * @f[
+ *   txtime=\frac{bufsize}{rate}10^6
+ * @f]
+ * 
+ * @return Required transmit time in micro seconds.
+ */
+int rtnl_tc_calc_txtime(int bufsize, int rate)
+{
+	double tx_time_secs;
+	
+	tx_time_secs = (double) bufsize / (double) rate;
+
+	return tx_time_secs * 1000000.;
+}
+
+/**
+ * Calculate buffer size able to transmit in a specific time and rate.
+ * @arg txtime		Available transmit time in micro seconds.
+ * @arg rate		Transmit rate in bytes per second.
+ *
+ * Calculates the size of the buffer that can be transmitted in a
+ * specific time period at a specific transmit rate.
+ *
+ * @f[
+ *   bufsize=\frac{{txtime} \times {rate}}{10^6}
+ * @f]
+ *
+ * @return Size of buffer in bytes.
+ */
+int rtnl_tc_calc_bufsize(int txtime, int rate)
+{
+	double bufsize;
+
+	bufsize = (double) txtime * (double) rate;
+
+	return bufsize / 1000000.;
+}
+
+/**
+ * Calculate the binary logarithm for a specific cell size
+ * @arg cell_size	Size of cell, must be a power of two.
+ * @return Binary logirhtm of cell size or a negative error code.
+ */
+int rtnl_tc_calc_cell_log(int cell_size)
+{
+	int i;
+
+	for (i = 0; i < 32; i++)
+		if ((1 << i) == cell_size)
+			return i;
+
+	return -NLE_INVAL;
+}
+
+
+/** @} */
+
+/**
+ * @name Rate Tables
+ * @{
+ */
+
+/*
+ * COPYRIGHT NOTE:
+ * align_to_atm() and adjust_size() derived/coped from iproute2 source.
+ */
+
+/*
+ * The align to ATM cells is used for determining the (ATM) SAR
+ * alignment overhead at the ATM layer. (SAR = Segmentation And
+ * Reassembly).  This is for example needed when scheduling packet on
+ * an ADSL connection.  Note that the extra ATM-AAL overhead is _not_
+ * included in this calculation. This overhead is added in the kernel
+ * before doing the rate table lookup, as this gives better precision
+ * (as the table will always be aligned for 48 bytes).
+ *  --Hawk, d.7/11-2004. <hawk at diku.dk>
+ */
+static unsigned int align_to_atm(unsigned int size)
+{
+	int linksize, cells;
+	cells = size / ATM_CELL_PAYLOAD;
+	if ((size % ATM_CELL_PAYLOAD) > 0)
+		cells++;
+
+	linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
+	return linksize;
+}
+
+static unsigned int adjust_size(unsigned int size, unsigned int mpu,
+				uint32_t linktype)
+{
+	if (size < mpu)
+		size = mpu;
+
+	switch (linktype) {
+	case ARPHRD_ATM:
+		return align_to_atm(size);
+
+	case ARPHRD_ETHER:
+	default:
+		return size;
+	}
+}
+
+/**
+ * Compute a transmission time lookup table
+ * @arg tc		traffic control object
+ * @arg spec		Rate specification
+ * @arg dst		Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
+ *
+ * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the
+ * transmission times for various packet sizes, e.g. the transmission
+ * time for a packet of size \c pktsize could be looked up:
+ * @code
+ * txtime = table[pktsize >> log2(mtu)];
+ * @endcode
+ */
+int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
+			     uint32_t *dst)
+{
+	uint32_t mtu = rtnl_tc_get_mtu(tc);
+	uint32_t linktype = rtnl_tc_get_linktype(tc);
+	uint8_t cell_log = spec->rs_cell_log;
+	unsigned int size, i;
+
+	spec->rs_mpu = rtnl_tc_get_mpu(tc);
+	spec->rs_overhead = rtnl_tc_get_overhead(tc);
+
+	if (mtu == 0)
+		mtu = 2047;
+
+	if (cell_log == UINT8_MAX) {
+		/*
+		 * cell_log not specified, calculate it. It has to specify the
+		 * minimum number of rshifts required to break the MTU to below
+		 * RTNL_TC_RTABLE_SIZE.
+		 */
+		cell_log = 0;
+		while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
+			cell_log++;
+	}
+
+	for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
+		size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
+		dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate);
+	}
+
+	spec->rs_cell_align = -1;
+	spec->rs_cell_log = cell_log;
+
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name TC implementation of cache functions
+ */
+
+void rtnl_tc_free_data(struct nl_object *obj)
+{
+	struct rtnl_tc *tc = TC_CAST(obj);
+	struct rtnl_tc_ops *ops;
+	
+	rtnl_link_put(tc->tc_link);
+	nl_data_free(tc->tc_opts);
+	nl_data_free(tc->tc_xstats);
+
+	if (tc->tc_subdata) {
+		ops = rtnl_tc_get_ops(tc);
+		if (ops && ops->to_free_data)
+			ops->to_free_data(tc, nl_data_get(tc->tc_subdata));
+
+		nl_data_free(tc->tc_subdata);
+	}
+}
+
+int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
+{
+	struct rtnl_tc *dst = TC_CAST(dstobj);
+	struct rtnl_tc *src = TC_CAST(srcobj);
+	struct rtnl_tc_ops *ops;
+
+	if (src->tc_link) {
+		nl_object_get(OBJ_CAST(src->tc_link));
+		dst->tc_link = src->tc_link;
+	}
+
+	if (src->tc_opts) {
+		dst->tc_opts = nl_data_clone(src->tc_opts);
+		if (!dst->tc_opts)
+			return -NLE_NOMEM;
+	}
+	
+	if (src->tc_xstats) {
+		dst->tc_xstats = nl_data_clone(src->tc_xstats);
+		if (!dst->tc_xstats)
+			return -NLE_NOMEM;
+	}
+
+	if (src->tc_subdata) {
+		if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) {
+			return -NLE_NOMEM;
+		}
+	}
+
+	ops = rtnl_tc_get_ops(src);
+	if (ops && ops->to_clone) {
+		void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src);
+
+		if (!a)
+			return 0;
+		else if (!b)
+			return -NLE_NOMEM;
+
+		return ops->to_clone(a, b);
+	}
+
+	return 0;
+}
+
+static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type,
+		   struct nl_dump_params *p)
+{
+	struct rtnl_tc_type_ops *type_ops;
+	struct rtnl_tc_ops *ops;
+	void *data = rtnl_tc_data(tc);
+
+	type_ops = tc_type_ops[tc->tc_type];
+	if (type_ops && type_ops->tt_dump[type])
+		type_ops->tt_dump[type](tc, p);
+
+	ops = rtnl_tc_get_ops(tc);
+	if (ops && ops->to_dump[type]) {
+		ops->to_dump[type](tc, data, p);
+		return 1;
+	}
+
+	return 0;
+}
+
+void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_tc_type_ops *type_ops;
+	struct rtnl_tc *tc = TC_CAST(obj);
+	struct nl_cache *link_cache;
+	char buf[32];
+
+	nl_new_line(p);
+
+	type_ops = tc_type_ops[tc->tc_type];
+	if (type_ops && type_ops->tt_dump_prefix)
+		nl_dump(p, "%s ", type_ops->tt_dump_prefix);
+
+	nl_dump(p, "%s ", tc->tc_kind);
+
+	if ((link_cache = nl_cache_mngt_require("route/link"))) {
+		nl_dump(p, "dev %s ",
+			rtnl_link_i2name(link_cache, tc->tc_ifindex,
+					 buf, sizeof(buf)));
+	} else
+		nl_dump(p, "dev %u ", tc->tc_ifindex);
+	
+	nl_dump(p, "id %s ",
+		rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf)));
+	
+	nl_dump(p, "parent %s",
+		rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf)));
+
+	tc_dump(tc, NL_DUMP_LINE, p);
+	nl_dump(p, "\n");
+}
+
+void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_tc *tc = TC_CAST(obj);
+
+	rtnl_tc_dump_line(OBJ_CAST(tc), p);
+
+	nl_dump_line(p, "  ");
+
+	if (tc->ce_mask & TCA_ATTR_MTU)
+		nl_dump(p, " mtu %u", tc->tc_mtu);
+
+	if (tc->ce_mask & TCA_ATTR_MPU)
+		nl_dump(p, " mpu %u", tc->tc_mpu);
+
+	if (tc->ce_mask & TCA_ATTR_OVERHEAD)
+		nl_dump(p, " overhead %u", tc->tc_overhead);
+
+	if (!tc_dump(tc, NL_DUMP_DETAILS, p))
+		nl_dump(p, "no options");
+	nl_dump(p, "\n");
+}
+
+void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+	struct rtnl_tc *tc = TC_CAST(obj);
+	char *unit, fmt[64];
+	float res;
+
+	rtnl_tc_dump_details(OBJ_CAST(tc), p);
+
+	strcpy(fmt, "        %7.2f %s %10u %10u %10u %10u %10u\n");
+
+	nl_dump_line(p, 
+		"    Stats:    bytes    packets      drops overlimits" \
+		"       qlen    backlog\n");
+
+	res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit);
+	if (*unit == 'B')
+		fmt[11] = '9';
+
+	nl_dump_line(p, fmt, res, unit,
+		tc->tc_stats[RTNL_TC_PACKETS],
+		tc->tc_stats[RTNL_TC_DROPS],
+		tc->tc_stats[RTNL_TC_OVERLIMITS],
+		tc->tc_stats[RTNL_TC_QLEN],
+		tc->tc_stats[RTNL_TC_BACKLOG]);
+
+	res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit);
+
+	strcpy(fmt, "        %7.2f %s/s%9u pps");
+
+	if (*unit == 'B')
+		fmt[11] = '9';
+
+	nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]);
+
+	tc_dump(tc, NL_DUMP_LINE, p);
+	nl_dump(p, "\n");
+}
+
+int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,
+		    uint32_t attrs, int flags)
+{
+	struct rtnl_tc *a = TC_CAST(aobj);
+	struct rtnl_tc *b = TC_CAST(bobj);
+	int diff = 0;
+
+#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= TC_DIFF(HANDLE,		a->tc_handle != b->tc_handle);
+	diff |= TC_DIFF(PARENT,		a->tc_parent != b->tc_parent);
+	diff |= TC_DIFF(IFINDEX,	a->tc_ifindex != b->tc_ifindex);
+	diff |= TC_DIFF(KIND,		strcmp(a->tc_kind, b->tc_kind));
+
+#undef TC_DIFF
+
+	return diff;
+}
+
+/** @} */
+
+/**
+ * @name Modules API
+ */
+
+struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind)
+{
+	struct rtnl_tc_ops *ops;
+
+	nl_list_for_each_entry(ops, &tc_ops_list[type], to_list)
+		if (!strcmp(kind, ops->to_kind))
+			return ops;
+
+	return NULL;
+}
+
+struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc)
+{
+	if (!tc->tc_ops)
+		tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind);
+
+	return tc->tc_ops;
+}
+
+/**
+ * Register a traffic control module
+ * @arg ops		traffic control module operations
+ */
+int rtnl_tc_register(struct rtnl_tc_ops *ops)
+{
+	static int init = 0;
+
+	/*
+	 * Initialiation hack, make sure list is initialized when
+	 * the first tc module registers. Putting this in a
+	 * separate __init would required correct ordering of init
+	 * functions
+	 */
+	if (!init) {
+		int i;
+
+		for (i = 0; i < __RTNL_TC_TYPE_MAX; i++)
+			nl_init_list_head(&tc_ops_list[i]);
+
+		init = 1;
+	}
+
+	if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX)
+		BUG();
+
+	if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind))
+		return -NLE_EXIST;
+
+	nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]);
+
+	return 0;
+}
+
+/**
+ * Unregister a traffic control module
+ * @arg ops		traffic control module operations
+ */
+void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
+{
+	nl_list_del(&ops->to_list);
+}
+
+/**
+ * Return pointer to private data of traffic control object
+ * @arg tc		traffic control object
+ *
+ * Allocates the private traffic control object data section
+ * as necessary and returns it.
+ *
+ * @return Pointer to private tc data or NULL if allocation failed.
+ */
+void *rtnl_tc_data(struct rtnl_tc *tc)
+{
+	if (!tc->tc_subdata) {
+		size_t size;
+
+		if (!tc->tc_ops) {
+			if (!tc->tc_kind)
+				BUG();
+
+			if (!rtnl_tc_get_ops(tc))
+				return NULL;
+		}
+
+		if (!(size = tc->tc_ops->to_size))
+			BUG();
+
+		if (!(tc->tc_subdata = nl_data_alloc(NULL, size)))
+			return NULL;
+	}
+
+	return nl_data_get(tc->tc_subdata);
+}
+
+/**
+ * Check traffic control object type and return private data section 
+ * @arg tc		traffic control object
+ * @arg ops		expected traffic control object operations
+ *
+ * Checks whether the traffic control object matches the type
+ * specified with the traffic control object operations. If the
+ * type matches, the private tc object data is returned. If type
+ * mismatches, APPBUG() will print a application bug warning.
+ *
+ * @see rtnl_tc_data()
+ *
+ * @return Pointer to private tc data or NULL if type mismatches.
+ */
+void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops)
+{
+	if (tc->tc_ops != ops) {
+		char buf[64];
+
+		snprintf(buf, sizeof(buf),
+			 "tc object %p used in %s context but is of type %s",
+			 tc, ops->to_kind, tc->tc_ops->to_kind);
+		APPBUG(buf);
+
+		return NULL;
+	}
+
+	return rtnl_tc_data(tc);
+}
+
+void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops)
+{
+	if (ops->tt_type > RTNL_TC_TYPE_MAX)
+		BUG();
+
+	tc_type_ops[ops->tt_type] = ops;
+}
+
+void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops)
+{
+	if (ops->tt_type > RTNL_TC_TYPE_MAX)
+		BUG();
+
+	tc_type_ops[ops->tt_type] = NULL;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/socket.c b/libnetwork/libnl3/lib/socket.c
new file mode 100644
index 0000000..01b9872
--- /dev/null
+++ b/libnetwork/libnl3/lib/socket.c
@@ -0,0 +1,628 @@
+/*
+ * lib/socket.c		Netlink Socket
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup socket Socket
+ * @{
+ */
+
+#include <pthread.h>
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+static int default_cb = NL_CB_DEFAULT;
+
+static void __init init_default_cb(void)
+{
+	char *nlcb;
+
+	if ((nlcb = getenv("NLCB"))) {
+		if (!strcasecmp(nlcb, "default"))
+			default_cb = NL_CB_DEFAULT;
+		else if (!strcasecmp(nlcb, "verbose"))
+			default_cb = NL_CB_VERBOSE;
+		else if (!strcasecmp(nlcb, "debug"))
+			default_cb = NL_CB_DEBUG;
+		else {
+			fprintf(stderr, "Unknown value for NLCB, valid values: "
+				"{default | verbose | debug}\n");
+		}
+	}
+}
+
+static uint32_t used_ports_map[32];
+static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static uint32_t generate_local_port(void)
+{
+	int i, n;
+	uint32_t pid = getpid() & 0x3FFFFF;
+
+	pthread_mutex_lock(&port_map_mutex);
+
+	for (i = 0; i < 32; i++) {
+		if (used_ports_map[i] == 0xFFFFFFFF)
+			continue;
+
+		for (n = 0; n < 32; n++) {
+			if (1UL & (used_ports_map[i] >> n))
+				continue;
+
+			used_ports_map[i] |= (1UL << n);
+			n += (i * 32);
+
+			/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
+			 * to, i.e. 1024 unique ports per application. */
+
+			pthread_mutex_unlock(&port_map_mutex);
+
+			return pid + (n << 22);
+		}
+	}
+
+	pthread_mutex_unlock(&port_map_mutex);
+
+	/* Out of sockets in our own PID namespace, what to do? FIXME */
+	return UINT_MAX;
+}
+
+static void release_local_port(uint32_t port)
+{
+	int nr;
+
+	if (port == UINT_MAX)
+		return;
+	
+	nr = port >> 22;
+
+	pthread_mutex_lock(&port_map_mutex);
+	used_ports_map[nr / 32] &= ~(1 << (nr % 32));
+	pthread_mutex_unlock(&port_map_mutex);
+}
+
+/**
+ * @name Allocation
+ * @{
+ */
+
+static struct nl_sock *__alloc_socket(struct nl_cb *cb)
+{
+	struct nl_sock *sk;
+
+	sk = calloc(1, sizeof(*sk));
+	if (!sk)
+		return NULL;
+
+	sk->s_fd = -1;
+	sk->s_cb = cb;
+	sk->s_local.nl_family = AF_NETLINK;
+	sk->s_peer.nl_family = AF_NETLINK;
+	sk->s_seq_expect = sk->s_seq_next = time(0);
+	sk->s_local.nl_pid = generate_local_port();
+	if (sk->s_local.nl_pid == UINT_MAX) {
+		nl_socket_free(sk);
+		return NULL;
+	}
+
+	return sk;
+}
+
+/**
+ * Allocate new netlink socket
+ *
+ * @return Newly allocated netlink socket or NULL.
+ */
+struct nl_sock *nl_socket_alloc(void)
+{
+	struct nl_cb *cb;
+	
+	cb = nl_cb_alloc(default_cb);
+	if (!cb)
+		return NULL;
+
+	return __alloc_socket(cb);
+}
+
+/**
+ * Allocate new socket with custom callbacks
+ * @arg cb		Callback handler
+ *
+ * The reference to the callback handler is taken into account
+ * automatically, it is released again upon calling nl_socket_free().
+ *
+ *@return Newly allocted socket handle or NULL.
+ */
+struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
+{
+	if (cb == NULL)
+		BUG();
+
+	return __alloc_socket(nl_cb_get(cb));
+}
+
+/**
+ * Free a netlink socket.
+ * @arg sk		Netlink socket.
+ */
+void nl_socket_free(struct nl_sock *sk)
+{
+	if (!sk)
+		return;
+
+	if (sk->s_fd >= 0)
+		close(sk->s_fd);
+
+	if (!(sk->s_flags & NL_OWN_PORT))
+		release_local_port(sk->s_local.nl_pid);
+
+	nl_cb_put(sk->s_cb);
+	free(sk);
+}
+
+/** @} */
+
+/**
+ * @name Sequence Numbers
+ * @{
+ */
+
+static int noop_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+
+/**
+ * Disable sequence number checking.
+ * @arg sk		Netlink socket.
+ *
+ * Disables checking of sequence numbers on the netlink socket This is
+ * required to allow messages to be processed which were not requested by
+ * a preceding request message, e.g. netlink events.
+ *
+ * @note This function modifies the NL_CB_SEQ_CHECK configuration in
+ * the callback handle associated with the socket.
+ */
+void nl_socket_disable_seq_check(struct nl_sock *sk)
+{
+	nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK,
+		  NL_CB_CUSTOM, noop_seq_check, NULL);
+}
+
+/**
+ * Use next sequence number
+ * @arg sk		Netlink socket.
+ *
+ * Uses the next available sequence number and increases the counter
+ * by one for subsequent calls.
+ *
+ * @return Unique serial sequence number
+ */
+unsigned int nl_socket_use_seq(struct nl_sock *sk)
+{
+	return sk->s_seq_next++;
+}
+
+/**
+ * Disable automatic request for ACK
+ * @arg sk		Netlink socket.
+ *
+ * The default behaviour of a socket is to request an ACK for
+ * each message sent to allow for the caller to synchronize to
+ * the completion of the netlink operation. This function
+ * disables this behaviour and will result in requests being
+ * sent which will not have the NLM_F_ACK flag set automatically.
+ * However, it is still possible for the caller to set the
+ * NLM_F_ACK flag explicitely.
+ */
+void nl_socket_disable_auto_ack(struct nl_sock *sk)
+{
+	sk->s_flags |= NL_NO_AUTO_ACK;
+}
+
+/**
+ * Enable automatic request for ACK (default)
+ * @arg sk		Netlink socket.
+ * @see nl_socket_disable_auto_ack
+ */
+void nl_socket_enable_auto_ack(struct nl_sock *sk)
+{
+	sk->s_flags &= ~NL_NO_AUTO_ACK;
+}
+
+/** @} */
+
+/**
+ * @name Source Idenficiation
+ * @{
+ */
+
+uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
+{
+	return sk->s_local.nl_pid;
+}
+
+/**
+ * Set local port of socket
+ * @arg sk		Netlink socket.
+ * @arg port		Local port identifier
+ *
+ * Assigns a local port identifier to the socket. If port is 0
+ * a unique port identifier will be generated automatically.
+ */
+void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
+{
+	if (port == 0) {
+		port = generate_local_port(); 
+		/*
+		 * Release local port after generation of a new one to be
+		 * able to change local port using nl_socket_set_local_port(, 0)
+		 */
+		if (!(sk->s_flags & NL_OWN_PORT))
+			release_local_port(sk->s_local.nl_pid);
+		else
+			sk->s_flags &= ~NL_OWN_PORT;
+	} else  {
+		if (!(sk->s_flags & NL_OWN_PORT))
+			release_local_port(sk->s_local.nl_pid);
+		sk->s_flags |= NL_OWN_PORT;
+	}
+
+	sk->s_local.nl_pid = port;
+}
+
+/** @} */
+
+/**
+ * @name Group Subscriptions
+ * @{
+ */
+
+/**
+ * Join groups
+ * @arg sk		Netlink socket
+ * @arg group		Group identifier
+ *
+ * Joins the specified groups using the modern socket option which
+ * is available since kernel version 2.6.14. It allows joining an
+ * almost arbitary number of groups without limitation.  The list
+ * of groups has to be terminated by 0 (%NFNLGRP_NONE).
+ *
+ * Make sure to use the correct group definitions as the older
+ * bitmask definitions for nl_join_groups() are likely to still
+ * be present for backward compatibility reasons.
+ *
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
+{
+	int err;
+	va_list ap;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	va_start(ap, group);
+
+	while (group != 0) {
+		if (group < 0)
+			return -NLE_INVAL;
+
+		err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+						 &group, sizeof(group));
+		if (err < 0)
+			return -nl_syserr2nlerr(errno);
+
+		group = va_arg(ap, int);
+	}
+
+	va_end(ap);
+
+	return 0;
+}
+
+int nl_socket_add_membership(struct nl_sock *sk, int group)
+{
+	return nl_socket_add_memberships(sk, group, 0);
+}
+
+/**
+ * Leave groups
+ * @arg sk		Netlink socket
+ * @arg group		Group identifier
+ *
+ * Leaves the specified groups using the modern socket option
+ * which is available since kernel version 2.6.14. The list of groups
+ * has to terminated by 0 (%NFNLGRP_NONE).
+ *
+ * @see nl_socket_add_membership
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
+{
+	int err;
+	va_list ap;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	va_start(ap, group);
+
+	while (group != 0) {
+		if (group < 0)
+			return -NLE_INVAL;
+
+		err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+						 &group, sizeof(group));
+		if (err < 0)
+			return -nl_syserr2nlerr(errno);
+
+		group = va_arg(ap, int);
+	}
+
+	va_end(ap);
+
+	return 0;
+}
+
+int nl_socket_drop_membership(struct nl_sock *sk, int group)
+{
+	return nl_socket_drop_memberships(sk, group, 0);
+}
+
+
+/**
+ * Join multicast groups (deprecated)
+ * @arg sk		Netlink socket.
+ * @arg groups		Bitmask of groups to join.
+ *
+ * This function defines the old way of joining multicast group which
+ * has to be done prior to calling nl_connect(). It works on any kernel
+ * version but is very limited as only 32 groups can be joined.
+ */
+void nl_join_groups(struct nl_sock *sk, int groups)
+{
+	sk->s_local.nl_groups |= groups;
+}
+
+
+/** @} */
+
+/**
+ * @name Peer Identfication
+ * @{
+ */
+
+uint32_t nl_socket_get_peer_port(const struct nl_sock *sk)
+{
+	return sk->s_peer.nl_pid;
+}
+
+void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port)
+{
+	sk->s_peer.nl_pid = port;
+}
+
+uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk)
+{
+	return sk->s_peer.nl_groups;
+}
+
+void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups)
+{
+	sk->s_peer.nl_groups = groups;
+}
+
+
+
+/** @} */
+
+/**
+ * @name File Descriptor
+ * @{
+ */
+
+int nl_socket_get_fd(const struct nl_sock *sk)
+{
+	return sk->s_fd;
+}
+
+/**
+ * Set file descriptor of socket to non-blocking state
+ * @arg sk		Netlink socket.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_set_nonblocking(const struct nl_sock *sk)
+{
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return 0;
+}
+
+/**
+ * Enable use of MSG_PEEK when reading from socket
+ * @arg sk		Netlink socket.
+ */
+void nl_socket_enable_msg_peek(struct nl_sock *sk)
+{
+	sk->s_flags |= NL_MSG_PEEK;
+}
+
+/**
+ * Disable use of MSG_PEEK when reading from socket
+ * @arg sk		Netlink socket.
+ */
+void nl_socket_disable_msg_peek(struct nl_sock *sk)
+{
+	sk->s_flags &= ~NL_MSG_PEEK;
+}
+
+/** @} */
+
+/**
+ * @name Callback Handler
+ * @{
+ */
+
+struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk)
+{
+	return nl_cb_get(sk->s_cb);
+}
+
+void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+	nl_cb_put(sk->s_cb);
+	sk->s_cb = nl_cb_get(cb);
+}
+
+/**
+ * Modify the callback handler associated with the socket
+ * @arg sk		Netlink socket.
+ * @arg type		which type callback to set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passed to callback function
+ *
+ * @see nl_cb_set
+ */
+int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type,
+			enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
+			void *arg)
+{
+	return nl_cb_set(sk->s_cb, type, kind, func, arg);
+}
+
+/**
+ * Modify the error callback handler associated with the socket
+ * @arg sk		Netlink socket.
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passed to callback function
+ *
+ * @see nl_cb_err
+ */
+int nl_socket_modify_err_cb(struct nl_sock *sk, enum nl_cb_kind kind,
+			    nl_recvmsg_err_cb_t func, void *arg)
+{
+	return nl_cb_err(sk->s_cb, kind, func, arg);
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Set socket buffer size of netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg rxbuf		New receive socket buffer size in bytes.
+ * @arg txbuf		New transmit socket buffer size in bytes.
+ *
+ * Sets the socket buffer size of a netlink socket to the specified
+ * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
+ * good default value.
+ *
+ * @note It is not required to call this function prior to nl_connect().
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
+{
+	int err;
+
+	if (rxbuf <= 0)
+		rxbuf = 32768;
+
+	if (txbuf <= 0)
+		txbuf = 32768;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+	
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
+			 &txbuf, sizeof(txbuf));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
+			 &rxbuf, sizeof(rxbuf));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	sk->s_flags |= NL_SOCK_BUFSIZE_SET;
+
+	return 0;
+}
+
+/**
+ * Enable/disable credential passing on netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg state		New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_set_passcred(struct nl_sock *sk, int state)
+{
+	int err;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
+			 &state, sizeof(state));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	if (state)
+		sk->s_flags |= NL_SOCK_PASSCRED;
+	else
+		sk->s_flags &= ~NL_SOCK_PASSCRED;
+
+	return 0;
+}
+
+/**
+ * Enable/disable receival of additional packet information
+ * @arg sk		Netlink socket.
+ * @arg state		New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
+{
+	int err;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
+			 &state, sizeof(state));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/libnetwork/libnl3/lib/stamp-h1 b/libnetwork/libnl3/lib/stamp-h1
new file mode 100644
index 0000000..166946b
--- /dev/null
+++ b/libnetwork/libnl3/lib/stamp-h1
@@ -0,0 +1 @@
+timestamp for lib/defs.h
diff --git a/libnetwork/libnl3/lib/utils.c b/libnetwork/libnl3/lib/utils.c
new file mode 100644
index 0000000..0ec7626
--- /dev/null
+++ b/libnetwork/libnl3/lib/utils.c
@@ -0,0 +1,1040 @@
+/*
+ * lib/utils.c		Utility Functions
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf at suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup utils Utilities
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <linux/socket.h>
+
+/**
+ * Debug level
+ */
+int nl_debug = 0;
+
+struct nl_dump_params nl_debug_dp = {
+	.dp_type = NL_DUMP_DETAILS,
+};
+
+static void __init nl_debug_init(void)
+{
+	char *nldbg, *end;
+	
+	if ((nldbg = getenv("NLDBG"))) {
+		long level = strtol(nldbg, &end, 0);
+		if (nldbg != end)
+			nl_debug = level;
+	}
+
+	nl_debug_dp.dp_fd = stderr;
+}
+
+int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
+{
+	FILE *fd;
+	char buf[128];
+
+	fd = fopen(path, "r");
+	if (fd == NULL)
+		return -nl_syserr2nlerr(errno);
+
+	while (fgets(buf, sizeof(buf), fd)) {
+		int goodlen, err;
+		long num;
+		char *end;
+
+		if (*buf == '#' || *buf == '\n' || *buf == '\r')
+			continue;
+
+		num = strtol(buf, &end, 0);
+		if (end == buf)
+			return -NLE_INVAL;
+
+		if (num == LONG_MIN || num == LONG_MAX)
+			return -NLE_RANGE;
+
+		while (*end == ' ' || *end == '\t')
+			end++;
+
+		goodlen = strcspn(end, "#\r\n\t ");
+		if (goodlen == 0)
+			return -NLE_INVAL;
+
+		end[goodlen] = '\0';
+
+		err = cb(num, end);
+		if (err < 0)
+			return err;
+	}
+
+	fclose(fd);
+
+	return 0;
+}
+
+/**
+ * @name Unit Pretty-Printing
+ * @{
+ */
+
+/**
+ * Cancel down a byte counter
+ * @arg	l		byte counter
+ * @arg	unit		destination unit pointer
+ *
+ * Cancels down a byte counter until it reaches a reasonable
+ * unit. The chosen unit is assigned to \a unit.
+ * 
+ * @return The cancelled down byte counter in the new unit.
+ */
+double nl_cancel_down_bytes(unsigned long long l, char **unit)
+{
+	if (l >= 1099511627776LL) {
+		*unit = "TiB";
+		return ((double) l) / 1099511627776LL;
+	} else if (l >= 1073741824) {
+		*unit = "GiB";
+		return ((double) l) / 1073741824;
+	} else if (l >= 1048576) {
+		*unit = "MiB";
+		return ((double) l) / 1048576;
+	} else if (l >= 1024) {
+		*unit = "KiB";
+		return ((double) l) / 1024;
+	} else {
+		*unit = "B";
+		return (double) l;
+	}
+}
+
+/**
+ * Cancel down a bit counter
+ * @arg	l		bit counter
+ * @arg unit		destination unit pointer
+ *
+ * Cancels downa bit counter until it reaches a reasonable
+ * unit. The chosen unit is assigned to \a unit.
+ *
+ * @return The cancelled down bit counter in the new unit.
+ */
+double nl_cancel_down_bits(unsigned long long l, char **unit)
+{
+	if (l >= 1099511627776ULL) {
+		*unit = "Tbit";
+		return ((double) l) / 1099511627776ULL;
+	} else if (l >= 1073741824) {
+		*unit = "Gbit";
+		return ((double) l) / 1073741824;
+	} else if (l >= 1048576) {
+		*unit = "Mbit";
+		return ((double) l) / 1048576;
+	} else if (l >= 1024) {
+		*unit = "Kbit";
+		return ((double) l) / 1024;
+	} else {
+		*unit = "bit";
+		return (double) l;
+	}
+		
+}
+
+int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
+{
+	char *unit;
+	double frac;
+
+	switch (type) {
+	case NL_BYTE_RATE:
+		frac = nl_cancel_down_bytes(rate, &unit);
+		break;
+	
+	case NL_BIT_RATE:
+		frac = nl_cancel_down_bits(rate, &unit);
+		break;
+	
+	default:
+		BUG();
+	}
+
+	return snprintf(buf, len, "%.2f%s/s", frac, unit);
+}
+
+/**
+ * Cancel down a micro second value
+ * @arg	l		micro seconds
+ * @arg unit		destination unit pointer
+ *
+ * Cancels down a microsecond counter until it reaches a
+ * reasonable unit. The chosen unit is assigned to \a unit.
+ *
+ * @return The cancelled down microsecond in the new unit
+ */
+double nl_cancel_down_us(uint32_t l, char **unit)
+{
+	if (l >= 1000000) {
+		*unit = "s";
+		return ((double) l) / 1000000;
+	} else if (l >= 1000) {
+		*unit = "ms";
+		return ((double) l) / 1000;
+	} else {
+		*unit = "us";
+		return (double) l;
+	}
+}
+
+/** @} */
+
+/**
+ * @name Generic Unit Translations
+ * @{
+ */
+
+/**
+ * Convert a character string to a size
+ * @arg str		size encoded as character string
+ *
+ * Converts the specified size as character to the corresponding
+ * number of bytes.
+ *
+ * Supported formats are:
+ *  - b,kb/k,m/mb,gb/g for bytes
+ *  - bit,kbit/mbit/gbit
+ *
+ * @return The number of bytes or -1 if the string is unparseable
+ */
+long nl_size2int(const char *str)
+{
+	char *p;
+	long l = strtol(str, &p, 0);
+	if (p == str)
+		return -NLE_INVAL;
+
+	if (*p) {
+		if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
+			l *= 1024;
+		else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
+			l *= 1024*1024*1024;
+		else if (!strcasecmp(p, "gbit"))
+			l *= 1024*1024*1024/8;
+		else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
+			l *= 1024*1024;
+		else if (!strcasecmp(p, "mbit"))
+			l *= 1024*1024/8;
+		else if (!strcasecmp(p, "kbit"))
+			l *= 1024/8;
+		else if (!strcasecmp(p, "bit"))
+			l /= 8;
+		else if (strcasecmp(p, "b") != 0)
+			return -NLE_INVAL;
+	}
+
+	return l;
+}
+
+static const struct {
+	double limit;
+	const char *unit;
+} size_units[] = {
+	{ 1024. * 1024. * 1024. * 1024. * 1024., "EiB" },
+	{ 1024. * 1024. * 1024. * 1024., "TiB" },
+	{ 1024. * 1024. * 1024., "GiB" },
+	{ 1024. * 1024., "MiB" },
+	{ 1024., "KiB" },
+	{ 0., "B" },
+};
+
+/**
+ * Convert a size toa character string
+ * @arg size		Size in number of bytes
+ * @arg buf		Buffer to write character string to
+ * @arg len		Size of buf
+ *
+ * This function converts a value in bytes to a human readable representation
+ * of it. The function uses IEC prefixes:
+ *
+ * @code
+ * 1024 bytes => 1 KiB
+ * 1048576 bytes => 1 MiB
+ * @endcode
+ *
+ * The highest prefix is used which ensures a result of >= 1.0, the result
+ * is provided as floating point number with a maximum precision of 2 digits:
+ * @code
+ * 965176 bytes => 942.55 KiB
+ * @endcode
+ *
+ * @return pointer to buf
+ */
+char *nl_size2str(const size_t size, char *buf, const size_t len)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(size_units); i++) {
+		if (size >= size_units[i].limit) {
+			snprintf(buf, len, "%.2g%s",
+				(double) size / size_units[i].limit,
+				size_units[i].unit);
+			return buf;
+		}
+	}
+
+	BUG();
+}
+
+/**
+ * Convert a character string to a probability
+ * @arg str		probability encoded as character string
+ *
+ * Converts the specified probability as character to the
+ * corresponding probability number.
+ *
+ * Supported formats are:
+ *  - 0.0-1.0
+ *  - 0%-100%
+ *
+ * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
+ */
+long nl_prob2int(const char *str)
+{
+	char *p;
+	double d = strtod(str, &p);
+
+	if (p == str)
+		return -NLE_INVAL;
+
+	if (d > 1.0)
+		d /= 100.0f;
+
+	if (d > 1.0f || d < 0.0f)
+		return -NLE_RANGE;
+
+	if (*p && strcmp(p, "%") != 0)
+		return -NLE_INVAL;
+
+	return rint(d * NL_PROB_MAX);
+}
+
+/** @} */
+
+/**
+ * @name Time Translations
+ * @{
+ */
+
+#ifdef USER_HZ
+static uint32_t user_hz = USER_HZ;
+#else
+static uint32_t user_hz = 100;
+#endif
+
+static double ticks_per_usec = 1.0f;
+
+/* Retrieves the configured HZ and ticks/us value in the kernel.
+ * The value is cached. Supported ways of getting it:
+ *
+ * 1) environment variable
+ * 2) /proc/net/psched and sysconf
+ *
+ * Supports the environment variables:
+ *   PROC_NET_PSCHED  - may point to psched file in /proc
+ *   PROC_ROOT        - may point to /proc fs */ 
+static void __init get_psched_settings(void)
+{
+	char name[FILENAME_MAX];
+	FILE *fd;
+	int got_hz = 0;
+
+	if (getenv("HZ")) {
+		long hz = strtol(getenv("HZ"), NULL, 0);
+
+		if (LONG_MIN != hz && LONG_MAX != hz) {
+			user_hz = hz;
+			got_hz = 1;
+		}
+	}
+
+	if (!got_hz)
+		user_hz = sysconf(_SC_CLK_TCK);
+
+	if (getenv("TICKS_PER_USEC")) {
+		double t = strtod(getenv("TICKS_PER_USEC"), NULL);
+		ticks_per_usec = t;
+	}
+	else {
+		if (getenv("PROC_NET_PSCHED"))
+			snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
+		else if (getenv("PROC_ROOT"))
+			snprintf(name, sizeof(name), "%s/net/psched",
+				 getenv("PROC_ROOT"));
+		else
+			strncpy(name, "/proc/net/psched", sizeof(name) - 1);
+		
+		if ((fd = fopen(name, "r"))) {
+			uint32_t ns_per_usec, ns_per_tick;
+			/* the file contains 4 hexadecimals, but we just use
+			   the first two of them */
+			fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick);
+
+			ticks_per_usec = (double) ns_per_usec / 
+					 (double) ns_per_tick;
+
+
+			fclose(fd);
+		}
+	}
+}
+
+
+/**
+ * Return the value of HZ
+ */
+int nl_get_user_hz(void)
+{
+	return user_hz;
+}
+
+
+/**
+ * Convert micro seconds to ticks
+ * @arg us		micro seconds
+ * @return number of ticks
+ */
+uint32_t nl_us2ticks(uint32_t us)
+{
+	return us * ticks_per_usec;
+}
+
+
+/**
+ * Convert ticks to micro seconds
+ * @arg ticks		number of ticks
+ * @return microseconds
+ */
+uint32_t nl_ticks2us(uint32_t ticks)
+{
+	return ticks / ticks_per_usec;
+}
+
+int nl_str2msec(const char *str, uint64_t *result)
+{
+	uint64_t total = 0, l;
+	int plen;
+	char *p;
+
+	do {
+		l = strtoul(str, &p, 0);
+		if (p == str)
+			return -NLE_INVAL;
+		else if (*p) {
+			plen = strcspn(p, " \t");
+
+			if (!plen)
+				total += l;
+			else if (!strncasecmp(p, "sec", plen))
+				total += (l * 1000);
+			else if (!strncasecmp(p, "min", plen))
+				total += (l * 1000*60);
+			else if (!strncasecmp(p, "hour", plen))
+				total += (l * 1000*60*60);
+			else if (!strncasecmp(p, "day", plen))
+				total += (l * 1000*60*60*24);
+			else
+				return -NLE_INVAL;
+
+			str = p + plen;
+		} else
+			total += l;
+	} while (*str && *p);
+
+	*result = total;
+
+	return 0;
+}
+
+/**
+ * Convert milliseconds to a character string
+ * @arg msec		number of milliseconds
+ * @arg buf		destination buffer
+ * @arg len		buffer length
+ *
+ * Converts milliseconds to a character string split up in days, hours,
+ * minutes, seconds, and milliseconds and stores it in the specified
+ * destination buffer.
+ *
+ * @return The destination buffer.
+ */
+char * nl_msec2str(uint64_t msec, char *buf, size_t len)
+{
+	int i, split[5];
+	char *units[] = {"d", "h", "m", "s", "msec"};
+
+#define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit
+	_SPLIT(0, 86400000);	/* days */
+	_SPLIT(1, 3600000);	/* hours */
+	_SPLIT(2, 60000);	/* minutes */
+	_SPLIT(3, 1000);	/* seconds */
+#undef  _SPLIT
+	split[4] = msec;
+
+	memset(buf, 0, len);
+
+	for (i = 0; i < ARRAY_SIZE(split); i++) {
+		if (split[i] > 0) {
+			char t[64];
+			snprintf(t, sizeof(t), "%s%d%s",
+				 strlen(buf) ? " " : "", split[i], units[i]);
+			strncat(buf, t, len - strlen(buf) - 1);
+		}
+	}
+
+	return buf;
+}
+
+/** @} */
+
+/**
+ * @name Netlink Family Translations
+ * @{
+ */
+
+static const struct trans_tbl nlfamilies[] = {
+	__ADD(NETLINK_ROUTE,route)
+	__ADD(NETLINK_USERSOCK,usersock)
+	__ADD(NETLINK_FIREWALL,firewall)
+	__ADD(NETLINK_INET_DIAG,inetdiag)
+	__ADD(NETLINK_NFLOG,nflog)
+	__ADD(NETLINK_XFRM,xfrm)
+	__ADD(NETLINK_SELINUX,selinux)
+	__ADD(NETLINK_ISCSI,iscsi)
+	__ADD(NETLINK_AUDIT,audit)
+	__ADD(NETLINK_FIB_LOOKUP,fib_lookup)
+	__ADD(NETLINK_CONNECTOR,connector)
+	__ADD(NETLINK_NETFILTER,netfilter)
+	__ADD(NETLINK_IP6_FW,ip6_fw)
+	__ADD(NETLINK_DNRTMSG,dnrtmsg)
+	__ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
+	__ADD(NETLINK_GENERIC,generic)
+	__ADD(NETLINK_SCSITRANSPORT,scsitransport)
+	__ADD(NETLINK_ECRYPTFS,ecryptfs)
+};
+
+char * nl_nlfamily2str(int family, char *buf, size_t size)
+{
+	return __type2str(family, buf, size, nlfamilies,
+			  ARRAY_SIZE(nlfamilies));
+}
+
+int nl_str2nlfamily(const char *name)
+{
+	return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @name Link Layer Protocol Translations
+ * @{
+ */
+
+static const struct trans_tbl llprotos[] = {
+	{0, "generic"},
+	__ADD(ARPHRD_ETHER,ether)
+	__ADD(ARPHRD_EETHER,eether)
+	__ADD(ARPHRD_AX25,ax25)
+	__ADD(ARPHRD_PRONET,pronet)
+	__ADD(ARPHRD_CHAOS,chaos)
+	__ADD(ARPHRD_IEEE802,ieee802)
+	__ADD(ARPHRD_ARCNET,arcnet)
+	__ADD(ARPHRD_APPLETLK,atalk)
+	__ADD(ARPHRD_DLCI,dlci)
+	__ADD(ARPHRD_ATM,atm)
+	__ADD(ARPHRD_METRICOM,metricom)
+	__ADD(ARPHRD_IEEE1394,ieee1394)
+#ifdef ARPHRD_EUI64
+	__ADD(ARPHRD_EUI64,eui64)
+#endif
+	__ADD(ARPHRD_INFINIBAND,infiniband)
+	__ADD(ARPHRD_SLIP,slip)
+	__ADD(ARPHRD_CSLIP,cslip)
+	__ADD(ARPHRD_SLIP6,slip6)
+	__ADD(ARPHRD_CSLIP6,cslip6)
+	__ADD(ARPHRD_RSRVD,rsrvd)
+	__ADD(ARPHRD_ADAPT,adapt)
+	__ADD(ARPHRD_ROSE,rose)
+	__ADD(ARPHRD_X25,x25)
+#ifdef ARPHRD_HWX25
+	__ADD(ARPHRD_HWX25,hwx25)
+#endif
+	__ADD(ARPHRD_CAN,can)
+	__ADD(ARPHRD_PPP,ppp)
+	__ADD(ARPHRD_HDLC,hdlc)
+	__ADD(ARPHRD_LAPB,lapb)
+	__ADD(ARPHRD_DDCMP,ddcmp)
+	__ADD(ARPHRD_RAWHDLC,rawhdlc)
+	__ADD(ARPHRD_TUNNEL,ipip)
+	__ADD(ARPHRD_TUNNEL6,tunnel6)
+	__ADD(ARPHRD_FRAD,frad)
+	__ADD(ARPHRD_SKIP,skip)
+	__ADD(ARPHRD_LOOPBACK,loopback)
+	__ADD(ARPHRD_LOCALTLK,localtlk)
+	__ADD(ARPHRD_FDDI,fddi)
+	__ADD(ARPHRD_BIF,bif)
+	__ADD(ARPHRD_SIT,sit)
+	__ADD(ARPHRD_IPDDP,ip/ddp)
+	__ADD(ARPHRD_IPGRE,gre)
+	__ADD(ARPHRD_PIMREG,pimreg)
+	__ADD(ARPHRD_HIPPI,hippi)
+	__ADD(ARPHRD_ASH,ash)
+	__ADD(ARPHRD_ECONET,econet)
+	__ADD(ARPHRD_IRDA,irda)
+	__ADD(ARPHRD_FCPP,fcpp)
+	__ADD(ARPHRD_FCAL,fcal)
+	__ADD(ARPHRD_FCPL,fcpl)
+	__ADD(ARPHRD_FCFABRIC,fcfb_0)
+	__ADD(ARPHRD_FCFABRIC+1,fcfb_1)
+	__ADD(ARPHRD_FCFABRIC+2,fcfb_2)
+	__ADD(ARPHRD_FCFABRIC+3,fcfb_3)
+	__ADD(ARPHRD_FCFABRIC+4,fcfb_4)
+	__ADD(ARPHRD_FCFABRIC+5,fcfb_5)
+	__ADD(ARPHRD_FCFABRIC+6,fcfb_6)
+	__ADD(ARPHRD_FCFABRIC+7,fcfb_7)
+	__ADD(ARPHRD_FCFABRIC+8,fcfb_8)
+	__ADD(ARPHRD_FCFABRIC+9,fcfb_9)
+	__ADD(ARPHRD_FCFABRIC+10,fcfb_10)
+	__ADD(ARPHRD_FCFABRIC+11,fcfb_11)
+	__ADD(ARPHRD_FCFABRIC+12,fcfb_12)
+	__ADD(ARPHRD_IEEE802_TR,tr)
+	__ADD(ARPHRD_IEEE80211,ieee802.11)
+	__ADD(ARPHRD_PHONET,phonet)
+	__ADD(ARPHRD_CAIF, caif)
+#ifdef ARPHRD_IEEE80211_PRISM
+	__ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
+#endif
+#ifdef ARPHRD_VOID
+	__ADD(ARPHRD_VOID,void)
+#endif
+#ifdef ARPHRD_NONE
+	__ADD(ARPHRD_NONE,nohdr)
+#endif
+};
+
+char * nl_llproto2str(int llproto, char *buf, size_t len)
+{
+	return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
+}
+
+int nl_str2llproto(const char *name)
+{
+	return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
+}
+
+/** @} */
+
+
+/**
+ * @name Ethernet Protocol Translations
+ * @{
+ */
+
+static const struct trans_tbl ether_protos[] = {
+	__ADD(ETH_P_LOOP,loop)
+	__ADD(ETH_P_PUP,pup)
+	__ADD(ETH_P_PUPAT,pupat)
+	__ADD(ETH_P_IP,ip)
+	__ADD(ETH_P_X25,x25)
+	__ADD(ETH_P_ARP,arp)
+	__ADD(ETH_P_BPQ,bpq)
+	__ADD(ETH_P_IEEEPUP,ieeepup)
+	__ADD(ETH_P_IEEEPUPAT,ieeepupat)
+	__ADD(ETH_P_DEC,dec)
+	__ADD(ETH_P_DNA_DL,dna_dl)
+	__ADD(ETH_P_DNA_RC,dna_rc)
+	__ADD(ETH_P_DNA_RT,dna_rt)
+	__ADD(ETH_P_LAT,lat)
+	__ADD(ETH_P_DIAG,diag)
+	__ADD(ETH_P_CUST,cust)
+	__ADD(ETH_P_SCA,sca)
+	__ADD(ETH_P_TEB,teb)
+	__ADD(ETH_P_RARP,rarp)
+	__ADD(ETH_P_ATALK,atalk)
+	__ADD(ETH_P_AARP,aarp)
+#ifdef ETH_P_8021Q
+	__ADD(ETH_P_8021Q,802.1q)
+#endif
+	__ADD(ETH_P_IPX,ipx)
+	__ADD(ETH_P_IPV6,ipv6)
+	__ADD(ETH_P_PAUSE,pause)
+	__ADD(ETH_P_SLOW,slow)
+#ifdef ETH_P_WCCP
+	__ADD(ETH_P_WCCP,wccp)
+#endif
+	__ADD(ETH_P_PPP_DISC,ppp_disc)
+	__ADD(ETH_P_PPP_SES,ppp_ses)
+	__ADD(ETH_P_MPLS_UC,mpls_uc)
+	__ADD(ETH_P_MPLS_MC,mpls_mc)
+	__ADD(ETH_P_ATMMPOA,atmmpoa)
+	__ADD(ETH_P_LINK_CTL,link_ctl)
+	__ADD(ETH_P_ATMFATE,atmfate)
+	__ADD(ETH_P_PAE,pae)
+	__ADD(ETH_P_AOE,aoe)
+	__ADD(ETH_P_TIPC,tipc)
+	__ADD(ETH_P_1588,ieee1588)
+	__ADD(ETH_P_FCOE,fcoe)
+	__ADD(ETH_P_FIP,fip)
+	__ADD(ETH_P_EDSA,edsa)
+	__ADD(ETH_P_EDP2,edp2)
+	__ADD(ETH_P_802_3,802.3)
+	__ADD(ETH_P_AX25,ax25)
+	__ADD(ETH_P_ALL,all)
+	__ADD(ETH_P_802_2,802.2)
+	__ADD(ETH_P_SNAP,snap)
+	__ADD(ETH_P_DDCMP,ddcmp)
+	__ADD(ETH_P_WAN_PPP,wan_ppp)
+	__ADD(ETH_P_PPP_MP,ppp_mp)
+	__ADD(ETH_P_LOCALTALK,localtalk)
+	__ADD(ETH_P_CAN,can)
+	__ADD(ETH_P_PPPTALK,ppptalk)
+	__ADD(ETH_P_TR_802_2,tr_802.2)
+	__ADD(ETH_P_MOBITEX,mobitex)
+	__ADD(ETH_P_CONTROL,control)
+	__ADD(ETH_P_IRDA,irda)
+	__ADD(ETH_P_ECONET,econet)
+	__ADD(ETH_P_HDLC,hdlc)
+	__ADD(ETH_P_ARCNET,arcnet)
+	__ADD(ETH_P_DSA,dsa)
+	__ADD(ETH_P_TRAILER,trailer)
+	__ADD(ETH_P_PHONET,phonet)
+	__ADD(ETH_P_IEEE802154,ieee802154)
+	__ADD(ETH_P_CAIF,caif)
+};
+
+char *nl_ether_proto2str(int eproto, char *buf, size_t len)
+{
+	return __type2str(eproto, buf, len, ether_protos,
+			    ARRAY_SIZE(ether_protos));
+}
+
+int nl_str2ether_proto(const char *name)
+{
+	return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
+}
+
+/** @} */
+
+/**
+ * @name IP Protocol Translations
+ * @{
+ */
+
+char *nl_ip_proto2str(int proto, char *buf, size_t len)
+{
+	struct protoent *p = getprotobynumber(proto);
+
+	if (p) {
+		snprintf(buf, len, "%s", p->p_name);
+		return buf;
+	}
+
+	snprintf(buf, len, "0x%x", proto);
+	return buf;
+}
+
+int nl_str2ip_proto(const char *name)
+{
+	struct protoent *p = getprotobyname(name);
+	unsigned long l;
+	char *end;
+
+	if (p)
+		return p->p_proto;
+
+	l = strtoul(name, &end, 0);
+	if (l == ULONG_MAX || *end != '\0')
+		return -NLE_OBJ_NOTFOUND;
+
+	return (int) l;
+}
+
+/** @} */
+
+/**
+ * @name Dumping Helpers
+ * @{
+ */
+
+/**
+ * Handle a new line while dumping
+ * @arg params		Dumping parameters
+ *
+ * This function must be called before dumping any onto a
+ * new line. It will ensure proper prefixing as specified
+ * by the dumping parameters.
+ *
+ * @note This function will NOT dump any newlines itself
+ */
+void nl_new_line(struct nl_dump_params *params)
+{
+	params->dp_line++;
+
+	if (params->dp_prefix) {
+		int i;
+		for (i = 0; i < params->dp_prefix; i++) {
+			if (params->dp_fd)
+				fprintf(params->dp_fd, " ");
+			else if (params->dp_buf)
+				strncat(params->dp_buf, " ",
+					params->dp_buflen -
+					sizeof(params->dp_buf) - 1);
+		}
+	}
+
+	if (params->dp_nl_cb)
+		params->dp_nl_cb(params, params->dp_line);
+}
+
+static void dump_one(struct nl_dump_params *parms, const char *fmt,
+		     va_list args)
+{
+	if (parms->dp_fd)
+		vfprintf(parms->dp_fd, fmt, args);
+	else if (parms->dp_buf || parms->dp_cb) {
+		char *buf = NULL;
+		if (vasprintf(&buf, fmt, args) >= 0) {
+			if (parms->dp_cb)
+				parms->dp_cb(parms, buf);
+			else
+				strncat(parms->dp_buf, buf,
+					parms->dp_buflen - strlen(parms->dp_buf) - 1);
+			free(buf);
+		}
+	}
+}
+
+
+/**
+ * Dump a formatted character string
+ * @arg params		Dumping parameters
+ * @arg fmt		printf style formatting string
+ * @arg ...		Arguments to formatting string
+ *
+ * Dumps a printf style formatting string to the output device
+ * as specified by the dumping parameters.
+ */
+void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	dump_one(params, fmt, args);
+	va_end(args);
+}
+
+void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
+{
+	va_list args;
+
+	nl_new_line(parms);
+
+	va_start(args, fmt);
+	dump_one(parms, fmt, args);
+	va_end(args);
+}
+
+
+/** @} */
+
+/** @cond SKIP */
+
+int __trans_list_add(int i, const char *a, struct nl_list_head *head)
+{
+	struct trans_list *tl;
+
+	tl = calloc(1, sizeof(*tl));
+	if (!tl)
+		return -NLE_NOMEM;
+
+	tl->i = i;
+	tl->a = strdup(a);
+
+	nl_list_add_tail(&tl->list, head);
+
+	return 0;
+}
+
+void __trans_list_clear(struct nl_list_head *head)
+{
+	struct trans_list *tl, *next;
+
+	nl_list_for_each_entry_safe(tl, next, head, list) {
+		free(tl->a);
+		free(tl);
+	}
+
+	nl_init_list_head(head);
+}
+
+char *__type2str(int type, char *buf, size_t len,
+		 const struct trans_tbl *tbl, size_t tbl_len)
+{
+	int i;
+	for (i = 0; i < tbl_len; i++) {
+		if (tbl[i].i == type) {
+			snprintf(buf, len, "%s", tbl[i].a);
+			return buf;
+		}
+	}
+
+	snprintf(buf, len, "0x%x", type);
+	return buf;
+}
+
+char *__list_type2str(int type, char *buf, size_t len,
+		      struct nl_list_head *head)
+{
+	struct trans_list *tl;
+
+	nl_list_for_each_entry(tl, head, list) {
+		if (tl->i == type) {
+			snprintf(buf, len, "%s", tl->a);
+			return buf;
+		}
+	}
+
+	snprintf(buf, len, "0x%x", type);
+	return buf;
+}
+
+char *__flags2str(int flags, char *buf, size_t len,
+		  const struct trans_tbl *tbl, size_t tbl_len)
+{
+	int i;
+	int tmp = flags;
+
+	memset(buf, 0, len);
+	
+	for (i = 0; i < tbl_len; i++) {
+		if (tbl[i].i & tmp) {
+			tmp &= ~tbl[i].i;
+			strncat(buf, tbl[i].a, len - strlen(buf) - 1);
+			if ((tmp & flags))
+				strncat(buf, ",", len - strlen(buf) - 1);
+		}
+	}
+
+	return buf;
+}
+
+int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
+{
+	unsigned long l;
+	char *end;
+	int i;
+
+	if (*buf == '\0')
+		return -NLE_INVAL;
+
+	for (i = 0; i < tbl_len; i++)
+		if (!strcasecmp(tbl[i].a, buf))
+			return tbl[i].i;
+
+	l = strtoul(buf, &end, 0);
+	if (l == ULONG_MAX || *end != '\0')
+		return -NLE_OBJ_NOTFOUND;
+
+	return (int) l;
+}
+
+int __list_str2type(const char *buf, struct nl_list_head *head)
+{
+	struct trans_list *tl;
+	unsigned long l;
+	char *end;
+
+	if (*buf == '\0')
+		return -NLE_INVAL;
+
+	nl_list_for_each_entry(tl, head, list) {
+		if (!strcasecmp(tl->a, buf))
+			return tl->i;
+	}
+
+	l = strtoul(buf, &end, 0);
+	if (l == ULONG_MAX || *end != '\0')
+		return -NLE_OBJ_NOTFOUND;
+
+	return (int) l;
+}
+
+int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
+{
+	int i, flags = 0, len;
+	char *p = (char *) buf, *t;
+
+	for (;;) {
+		if (*p == ' ')
+			p++;
+	
+		t = strchr(p, ',');
+		len = t ? t - p : strlen(p);
+		for (i = 0; i < tbl_len; i++)
+			if (!strncasecmp(tbl[i].a, p, len))
+				flags |= tbl[i].i;
+
+		if (!t)
+			return flags;
+
+		p = ++t;
+	}
+
+	return 0;
+}
+
+void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
+{
+	int type = params->dp_type;
+
+	if (type < 0 || type > NL_DUMP_MAX)
+		BUG();
+
+	params->dp_line = 0;
+
+	if (params->dp_dump_msgtype) {
+#if 0
+		/* XXX */
+		char buf[64];
+
+		dp_dump_line(params, 0, "%s ",
+			     nl_cache_mngt_type2name(obj->ce_ops,
+			     			     obj->ce_ops->co_protocol,
+						     obj->ce_msgtype,
+						     buf, sizeof(buf)));
+#endif
+		params->dp_pre_dump = 1;
+	}
+
+	if (params->dp_buf)
+                memset(params->dp_buf, 0, params->dp_buflen);
+
+	if (obj->ce_ops->oo_dump[type])
+		obj->ce_ops->oo_dump[type](obj, params);
+}
+
+/** @endcond */
+
+/** @} */
-- 
1.7.6





More information about the Libvirt-cim mailing list