Checkign in new iproute2
authorSapan Bhatia <sapanb@cs.princeton.edu>
Thu, 26 Feb 2009 13:54:16 +0000 (13:54 +0000)
committerSapan Bhatia <sapanb@cs.princeton.edu>
Thu, 26 Feb 2009 13:54:16 +0000 (13:54 +0000)
207 files changed:
.gitignore [new file with mode: 0644]
COPYING
Config [new file with mode: 0644]
Makefile
README
doc/actions/actions-general
doc/actions/ifb-README [moved from doc/actions/dummy-README with 58% similarity]
doc/actions/mirred-usage
doc/do-psnup [changed mode: 0755->0644]
doc/ip-cref.tex
etc/iproute2/rt_dsfield
examples/cbqinit.eth1 [changed mode: 0755->0644]
examples/dhcp-client-script [changed mode: 0755->0644]
genl/.gitignore [new file with mode: 0644]
genl/Makefile [new file with mode: 0644]
genl/ctrl.c [new file with mode: 0644]
genl/genl.c [new file with mode: 0644]
genl/genl_utils.h [new file with mode: 0644]
include/SNAPSHOT.h
include/ip6tables.h
include/iptables.h
include/iptables_common.h
include/libiptc/ipt_kernel_headers.h
include/libnetlink.h
include/linux/atm.h [new file with mode: 0644]
include/linux/atmapi.h [new file with mode: 0644]
include/linux/atmioc.h [new file with mode: 0644]
include/linux/atmsap.h [new file with mode: 0644]
include/linux/fib_rules.h [new file with mode: 0644]
include/linux/genetlink.h [new file with mode: 0644]
include/linux/hdlc/ioctl.h [new file with mode: 0644]
include/linux/if.h [new file with mode: 0644]
include/linux/if_addr.h [new file with mode: 0644]
include/linux/if_addrlabel.h [new file with mode: 0644]
include/linux/if_ether.h
include/linux/if_link.h [new file with mode: 0644]
include/linux/if_tunnel.h
include/linux/if_vlan.h [new file with mode: 0644]
include/linux/inet_diag.h
include/linux/ip6_tunnel.h [new file with mode: 0644]
include/linux/ip_mp_alg.h [deleted file]
include/linux/neighbour.h [new file with mode: 0644]
include/linux/netfilter.h [new file with mode: 0644]
include/linux/netfilter/x_tables.h [new file with mode: 0644]
include/linux/netfilter/xt_tcpudp.h [new file with mode: 0644]
include/linux/netfilter_ipv4.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netlink.h
include/linux/pkt_cls.h
include/linux/pkt_sched.h
include/linux/rtnetlink.h
include/linux/socket.h
include/linux/tc_act/tc_defact.h [deleted file]
include/linux/tc_act/tc_nat.h [new file with mode: 0644]
include/linux/tc_act/tc_skbedit.h [new file with mode: 0644]
include/linux/tc_ematch/tc_em_meta.h
include/linux/tcp.h [deleted file]
include/linux/types.h [new file with mode: 0644]
include/linux/veth.h [new file with mode: 0644]
include/linux/xfrm.h
include/ll_map.h
include/net/tcp_states.h [deleted file]
include/netinet/tcp.h [new file with mode: 0644]
include/rt_names.h
include/utils.h
ip.8 [deleted file]
ip/.gitignore [new file with mode: 0644]
ip/Makefile
ip/ifcfg [changed mode: 0755->0644]
ip/ip.c
ip/ip6tunnel.c [new file with mode: 0644]
ip/ip_common.h
ip/ipaddress.c
ip/ipaddrlabel.c [new file with mode: 0644]
ip/iplink.c
ip/iplink_vlan.c [new file with mode: 0644]
ip/ipmaddr.c
ip/ipmonitor.c
ip/ipmroute.c
ip/ipneigh.c
ip/ipntable.c
ip/ipprefix.c
ip/iproute.c
ip/iprule.c
ip/iptunnel.c
ip/ipxfrm.c
ip/link_gre.c [new file with mode: 0644]
ip/link_veth.c [new file with mode: 0644]
ip/routef [changed mode: 0755->0644]
ip/routel [changed mode: 0755->0644]
ip/rtmon.c
ip/rtpr [changed mode: 0755->0644]
ip/tunnel.c [new file with mode: 0644]
ip/tunnel.h [new file with mode: 0644]
ip/xfrm.h
ip/xfrm_monitor.c
ip/xfrm_policy.c
ip/xfrm_state.c
iproute.spec [deleted file]
lib/ipx_ntop.c
lib/libnetlink.c
lib/ll_addr.c
lib/ll_map.c
lib/ll_proto.c
lib/ll_types.c
lib/rt_names.c
lib/utils.c
man/man3/libnetlink.3
man/man8/arpd.8 [new file with mode: 0644]
man/man8/ip.8
man/man8/lnstat.8 [new file with mode: 0644]
man/man8/routel.8 [new file with mode: 0644]
man/man8/rtacct.8 [new file with mode: 0644]
man/man8/rtmon.8 [new file with mode: 0644]
man/man8/ss.8 [new file with mode: 0644]
man/man8/tc-bfifo.8 [moved from man/man8/tc-pbfifo.8 with 100% similarity]
man/man8/tc-cbq-details.8
man/man8/tc-htb.8
man/man8/tc-pfifo.8 [changed from file to symlink]
man/man8/tc-prio.8
man/man8/tc.8
misc/.gitignore [new file with mode: 0644]
misc/Makefile
misc/arpd.c
misc/ifstat.c
misc/lnstat.c
misc/lnstat_util.c
misc/netbug [deleted file]
misc/nstat.c
misc/rtacct.c
misc/ss.c
misc/ssfilter.y
netem/.gitignore [new file with mode: 0644]
netem/Makefile
netem/maketable.c
netem/stats.c [new file with mode: 0644]
svn-commit.2.tmp [new file with mode: 0644]
svn-commit.3.tmp [new file with mode: 0644]
svn-commit.tmp [new file with mode: 0644]
tc-cbq-details.8 [deleted file]
tc-cbq.8 [deleted file]
tc-htb.8 [deleted file]
tc-pbfifo.8 [deleted file]
tc-pfifo_fast.8 [deleted file]
tc-prio.8 [deleted file]
tc-red.8 [deleted file]
tc-sfq.8 [deleted file]
tc-tbf.8 [deleted file]
tc.8 [deleted file]
tc/.gitignore [new file with mode: 0644]
tc/Makefile
tc/em_cmp.c
tc/em_meta.c
tc/em_nbyte.c
tc/em_u32.c
tc/emp_ematch.l
tc/f_basic.c
tc/f_flow.c [new file with mode: 0644]
tc/f_fw.c
tc/f_route.c
tc/f_rsvp.c
tc/f_u32.c
tc/m_action.c
tc/m_ematch.c
tc/m_ematch.h
tc/m_estimator.c
tc/m_gact.c
tc/m_ipt.c
tc/m_mirred.c
tc/m_nat.c [new file with mode: 0644]
tc/m_pedit.c
tc/m_pedit.h
tc/m_police.c
tc/m_skbedit.c [new file with mode: 0644]
tc/p_icmp.c
tc/p_ip.c
tc/p_tcp.c
tc/p_udp.c
tc/q_cbq.c
tc/q_gred.c
tc/q_hfsc.c
tc/q_htb.c
tc/q_multiq.c [new file with mode: 0644]
tc/q_netem.c
tc/q_prio.c
tc/q_red.c
tc/q_rr.c [new file with mode: 0644]
tc/q_sfq.c
tc/q_tbf.c
tc/tc.c
tc/tc_cbq.c
tc/tc_class.c
tc/tc_common.h
tc/tc_core.c
tc/tc_core.h
tc/tc_estimator.c
tc/tc_filter.c
tc/tc_monitor.c [new file with mode: 0644]
tc/tc_qdisc.c
tc/tc_red.c
tc/tc_stab.c [new file with mode: 0644]
tc/tc_util.c
tc/tc_util.h
testsuite/tests/cbq.t [changed mode: 0644->0755]
testsuite/tests/cls-testbed.t [changed mode: 0644->0755]
testsuite/tests/dsmark.t [changed mode: 0644->0755]
testsuite/tests/policer [changed mode: 0644->0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..8199aae
--- /dev/null
@@ -0,0 +1,5 @@
+Config
+*.o
+*.a
+*.so
+*~
diff --git a/COPYING b/COPYING
index 2b7b643..3912109 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -2,7 +2,7 @@
                       Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -11,7 +11,7 @@
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
 License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
+software--to make sure the software is free for all its users.  This
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
@@ -19,7 +19,7 @@ the GNU Library General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
+price.  Our General Public Licenses are designed to make sure that you
 have the freedom to distribute copies of free software (and charge for
 this service if you wish), that you receive source code or can get it
 if you want it, that you can change the software or use pieces of it
@@ -201,7 +201,7 @@ otherwise) that contradict the conditions of this License, they do not
 excuse you from the conditions of this License.  If you cannot
 distribute so as to satisfy simultaneously your obligations under this
 License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
+may not distribute the Program at all.  For example, if a patent
 license would not permit royalty-free redistribution of the Program by
 all those who receive copies directly or indirectly through you, then
 the only way you could satisfy both it and this License would be to
@@ -239,7 +239,7 @@ of the General Public License from time to time.  Such new versions will
 be similar in spirit to the present version, but may differ in detail to
 address new problems or concerns.
 
-Each version is given a distinguishing version number. If the Program
+Each version is given a distinguishing version number.  If the Program
 specifies a version number of this License which applies to it and "any
 later version", you have the option of following the terms and conditions
 either of that version or of any later version published by the Free
@@ -249,7 +249,7 @@ Foundation.
 
   10. If you wish to incorporate parts of the Program into other free
 programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
+to ask for permission.  For software which is copyrighted by the Free
 Software Foundation, write to the Free Software Foundation; we sometimes
 make exceptions for this.  Our decision will be guided by the two goals
 of preserving the free status of all derivatives of our free software and
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy <name of author>
+    Copyright (C) <year>  <name of author>
 
     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
@@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
 
     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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 Also add information on how to contact you by electronic and paper mail.
@@ -313,7 +313,7 @@ Also add information on how to contact you by electronic and paper mail.
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
diff --git a/Config b/Config
new file mode 100644 (file)
index 0000000..4360f0f
--- /dev/null
+++ b/Config
@@ -0,0 +1 @@
+# Generated config based on /d/Projects/iproute2-2.6.28/include
index ac58cd9..6096a99 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,14 @@
-DESTDIR=
-SBINDIR=/usr/sbin
+DESTDIR=/usr/
+LIBDIR=/usr/lib/
+SBINDIR=/sbin
 CONFDIR=/etc/iproute2
-DOCDIR=/usr/share/doc/iproute2
-MANDIR=/usr/share/man
+DOCDIR=/share/doc/iproute2
+MANDIR=/share/man
 
 # Path to db_185.h include
 DBM_INCLUDE:=/usr/include
 
-DEFINES= -DRESOLVE_HOSTNAMES
+DEFINES= -DRESOLVE_HOSTNAMES -DLIBDIR=\"$(LIBDIR)\"
 
 #options if you have a bind>=4.9.4 libresolv (or, maybe, glibc)
 LDLIBS=-lresolv
@@ -27,12 +28,13 @@ YACCFLAGS = -d -t -v
 
 LDLIBS += -L../lib -lnetlink -lutil
 
-SUBDIRS=lib ip tc misc netem
+SUBDIRS=lib ip tc misc netem genl
 
 LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
 
 all: Config
-       @for i in $(SUBDIRS); \
+       @set -e; \
+       for i in $(SUBDIRS); \
        do $(MAKE) $(MFLAGS) -C $$i; done
 
 Config:
@@ -51,11 +53,18 @@ install: all
        install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR)
        install -m 0755 -d $(DESTDIR)$(MANDIR)/man8
        install -m 0644 $(shell find man/man8 -maxdepth 1 -type f) $(DESTDIR)$(MANDIR)/man8
-       ln -sf tc-pbfifo.8  $(DESTDIR)$(MANDIR)/man8/tc-bfifo.8
-       ln -sf tc-pbfifo.8  $(DESTDIR)$(MANDIR)/man8/tc-pfifo.8
+       ln -sf tc-bfifo.8  $(DESTDIR)$(MANDIR)/man8/tc-pfifo.8
+       ln -sf lnstat.8  $(DESTDIR)$(MANDIR)/man8/rtstat.8
+       ln -sf lnstat.8  $(DESTDIR)$(MANDIR)/man8/ctstat.8
+       ln -sf rtacct.8  $(DESTDIR)$(MANDIR)/man8/nstat.8
+       ln -sf routel.8  $(DESTDIR)$(MANDIR)/man8/routef.8
        install -m 0755 -d $(DESTDIR)$(MANDIR)/man3
        install -m 0644 $(shell find man/man3 -maxdepth 1 -type f) $(DESTDIR)$(MANDIR)/man3
 
+snapshot:
+       echo "static const char SNAPSHOT[] = \""`date +%y%m%d`"\";" \
+               > include/SNAPSHOT.h
+
 clean:
        rm -f cscope.*
        @for i in $(SUBDIRS) doc; \
diff --git a/README b/README
index d86f605..7d54bd2 100644 (file)
--- a/README
+++ b/README
@@ -11,6 +11,8 @@ How to compile this.
 KERNEL_INCLUDE should point to correct linux kernel include directory.
 Default (/usr/src/linux/include) is right as rule.
 
+arpd needs to have the db4 development libraries. For debian
+users this is the package with a name like libdb4.x-dev.
 DBM_INCLUDE points to the directory with db_185.h which
 is the include file used by arpd to get to the old format Berkely
 database routines.  Often this is in the db-devel package.
index bb2295d..70f7cd6 100644 (file)
@@ -65,7 +65,7 @@ action police mtu 4000 rate 1500kbit burst 90k
 { drop, pass, reclassify, continue}
 (If you have others, no listed here give me a reason and we will add them)
 +drop says to drop the packet
-+pass says to accept it
++pass and ok (are equivalent) says to accept it
 +reclassify requests for reclassification of the packet
 +continue requests for next lookup to match
 
@@ -88,6 +88,9 @@ tc filter add dev lo parent ffff: protocol ip prio 8 u32 \
 match ip dst 127.0.0.8/32 flowid 1:12 \
 action ipt -j mark --set-mark 2
 
+NOTE: flowid 1:12 is parsed flowid 0x1:0x12.  Make sure if you want flowid
+decimal 12, then use flowid 1:c.
+
 3) A feature i call pipe
 The motivation is derived from Unix pipe mechanism but applied to packets.
 Essentially take a matching packet and pass it through 
similarity index 58%
rename from doc/actions/dummy-README
rename to doc/actions/ifb-README
index 3ef9f21..3d01179 100644 (file)
@@ -1,16 +1,16 @@
 
+IFB is intended to replace IMQ.
 Advantage over current IMQ; cleaner in particular in in SMP;
 with a _lot_ less code.
-Old Dummy device functionality is preserved while new one only
-kicks in if you use actions.
 
-IMQ USES
---------
+Known IMQ/IFB USES
+------------------
+
 As far as i know the reasons listed below is why people use IMQ. 
 It would be nice to know of anything else that i missed.
 
 1) qdiscs/policies that are per device as opposed to system wide.
-IMQ allows for sharing.
+IFB allows for sharing.
 
 2) Allows for queueing incoming traffic for shaping instead of
 dropping. I am not aware of any study that shows policing is 
@@ -25,70 +25,41 @@ the IMQ somewhere prelocal hook.
 I think this is a pretty neat feature to have in Linux in general.
 (i.e not just for IMQ).
 But i wont go back to putting netfilter hooks in the device to satisfy
-this.  I also dont think its worth it hacking dummy some more to be 
+this.  I also dont think its worth it hacking ifb some more to be 
 aware of say L3 info and play ip rule tricks to achieve this.
 --> Instead the plan is to have a contrack related action. This action will
 selectively either query/create contrack state on incoming packets. 
-Packets could then be redirected to dummy based on what happens -> eg 
+Packets could then be redirected to ifb based on what happens -> eg 
 on incoming packets; if we find they are of known state we could send to 
 a different queue than one which didnt have existing state. This
 all however is dependent on whatever rules the admin enters.
 
-At the moment this function does not exist yet. I have decided instead
-of sitting on the patch to release it and then if theres pressure i will
-add this feature.
-
-What you can do with dummy currently with actions
---------------------------------------------------
-
-Lets say you are policing packets from alias 192.168.200.200/32
-you dont want those to exceed 100kbps going out.
-
-tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
-match ip src 192.168.200.200/32 flowid 1:2 \
-action police rate 100kbit burst 90k drop
-
-If you run tcpdump on eth0 you will see all packets going out
-with src 192.168.200.200/32 dropped or not
-Extend the rule a little to see only the ones that made it out:
-
-tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
-match ip src 192.168.200.200/32 flowid 1:2 \
-action police rate 10kbit burst 90k drop \
-action mirred egress mirror dev dummy0 
-
-Now fire tcpdump on dummy0 to see only those packets ..
-tcpdump -n -i dummy0 -x -e -t 
-
-Essentially a good debugging/logging interface.
-
-If you replace mirror with redirect, those packets will be
-blackholed and will never make it out. This redirect behavior
-changes with new patch (but not the mirror). 
+At the moment this 3rd function does not exist yet. I have decided that
+instead of sitting on the patch for another year, to release it and then 
+if theres pressure i will add this feature.
 
-What you can do with the patch to provide functionality
-that most people use IMQ for below:
+An example, to provide functionality that most people use IMQ for below:
 
 --------
 export TC="/sbin/tc"
 
-$TC qdisc add dev dummy0 root handle 1: prio 
-$TC qdisc add dev dummy0 parent 1:1 handle 10: sfq
-$TC qdisc add dev dummy0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000
-$TC qdisc add dev dummy0 parent 1:3 handle 30: sfq                                
-$TC filter add dev dummy0 protocol ip pref 1 parent 1: handle 1 fw classid 1:1
-$TC filter add dev dummy0 protocol ip pref 2 parent 1: handle 2 fw classid 1:2
+$TC qdisc add dev ifb0 root handle 1: prio 
+$TC qdisc add dev ifb0 parent 1:1 handle 10: sfq
+$TC qdisc add dev ifb0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000
+$TC qdisc add dev ifb0 parent 1:3 handle 30: sfq                                
+$TC filter add dev ifb0 protocol ip pref 1 parent 1: handle 1 fw classid 1:1
+$TC filter add dev ifb0 protocol ip pref 2 parent 1: handle 2 fw classid 1:2
 
-ifconfig dummy0 up
+ifconfig ifb0 up
 
 $TC qdisc add dev eth0 ingress
 
-# redirect all IP packets arriving in eth0 to dummy
+# redirect all IP packets arriving in eth0 to ifb
 # use mark 1 --> puts them onto class 1:1
 $TC filter add dev eth0 parent ffff: protocol ip prio 10 u32 \
 match u32 0 0 flowid 1:1 \
 action ipt -j MARK --set-mark 1 \
-action mirred egress redirect dev dummy0
+action mirred egress redirect dev ifb0
 
 --------
 
@@ -121,24 +92,24 @@ filter protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:
         index 1 ref 1 bind 1 installed 4195sec  used 27sec 
          Sent 252 bytes 3 pkts (dropped 0, overlimits 0) 
 
-        action order 2: mirred (Egress Redirect to device dummy0) stolen
+        action order 2: mirred (Egress Redirect to device ifb0) stolen
         index 1 ref 1 bind 1 installed 165 sec used 27 sec
          Sent 252 bytes 3 pkts (dropped 0, overlimits 0) 
 
 [root@jmandrake]:~# $TC -s qdisc
-qdisc sfq 30: dev dummy0 limit 128p quantum 1514b 
+qdisc sfq 30: dev ifb0 limit 128p quantum 1514b 
  Sent 0 bytes 0 pkts (dropped 0, overlimits 0) 
-qdisc tbf 20: dev dummy0 rate 20Kbit burst 1575b lat 2147.5s 
+qdisc tbf 20: dev ifb0 rate 20Kbit burst 1575b lat 2147.5s 
  Sent 210 bytes 3 pkts (dropped 0, overlimits 0) 
-qdisc sfq 10: dev dummy0 limit 128p quantum 1514b 
+qdisc sfq 10: dev ifb0 limit 128p quantum 1514b 
  Sent 294 bytes 3 pkts (dropped 0, overlimits 0) 
-qdisc prio 1: dev dummy0 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
+qdisc prio 1: dev ifb0 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
  Sent 504 bytes 6 pkts (dropped 0, overlimits 0) 
 qdisc ingress ffff: dev eth0 ---------------- 
  Sent 308 bytes 5 pkts (dropped 0, overlimits 0) 
 
-[root@jmandrake]:~# ifconfig dummy0
-dummy0    Link encap:Ethernet  HWaddr 00:00:00:00:00:00  
+[root@jmandrake]:~# ifconfig ifb0
+ifb0    Link encap:Ethernet  HWaddr 00:00:00:00:00:00  
           inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link
           UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1
           RX packets:6 errors:0 dropped:3 overruns:0 frame:0
@@ -147,7 +118,6 @@ dummy0    Link encap:Ethernet  HWaddr 00:00:00:00:00:00
           RX bytes:504 (504.0 b)  TX bytes:252 (252.0 b)
 -----
 
-Dummy continues to behave like it always did.
 You send it any packet not originating from the actions it will drop them.
 [In this case the three dropped packets were ipv6 ndisc].
 
index aa942e5..2622c43 100644 (file)
@@ -1,7 +1,11 @@
 
 Very funky action. I do plan to add to a few more things to it
 This is the basic stuff. Idea borrowed from the way ethernet switches
-mirror and redirect packets.
+mirror and redirect packets. The main difference with say a vannila
+ethernet switch is that you can use u32 classifier to select a
+flow to be mirrored. High end switches typically can select based
+on more than just a port (eg a 5 tuple classifier). They may also be
+capable of redirecting.
 
 Usage: 
 
@@ -12,23 +16,78 @@ ACTION := <mirror | redirect>
 INDEX is the specific policy instance id
 DEVICENAME is the devicename
 
-
-Mirroring essentially takes a copy of the packet whereas redirecting
-steals the packet and redirects to specified destination.
+Direction:
+- Ingress is not supported at the moment. It will be in the
+future as well as mirror/redirecting to a socket. 
+
+Action:
+- Mirror takes a copy of the packet and sends it to specified
+dev ("port" in ethernet switch/bridging terminology)
+- redirect
+steals the packet and redirects to specified destination dev.
+
+What NOT to do if you dont want your machine to crash:
+------------------------------------------------------
+
+Do not create loops! 
+Loops are not hard to create in the egress qdiscs.
+
+Here are simple rules to follow if you dont want to get
+hurt:
+A) Do not have the same packet go to same netdevice twice
+in a single graph of policies. Your machine will just hang!
+This is design intent _not a bug_ to teach you some lessons. 
+
+In the future if there are easy ways to do this in the kernel
+without affecting other packets not interested in this feature
+I will add them. At the moment that is not clear.
+
+Some examples of bad things NOT to do:
+1) redirecting eth0 to eth0
+2) eth0->eth1-> eth0
+3) eth0->lo-> eth1-> eth0
+
+B) Do not redirect from one IFB device to another.
+Remember that IFB is a very specialized case of packet redirecting
+device. Instead of redirecting it puts packets at the exact spot
+on the stack it found them from.
+Redirecting from ifbX->ifbY will actually not crash your machine but your 
+packets will all be dropped (this is much simpler to detect
+and resolve and is only affecting users of ifb as opposed to the
+whole stack).
+
+In the case of A) the problem has to do with a recursive contention
+for the devices queue lock and in the second case for the transmit lock.
 
 Some examples:
-Host A is hooked  up to us on eth0
+-------------
+
+1) Mirror all packets arriving on eth0 to be sent out on eth1.
+You may have a sniffer or some accounting box hooked up on eth1.
+---
+tc qdisc add dev eth0 ingress
+tc filter add dev eth0 parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:2 action mirred egress mirror dev eth1
+---
+
+If you replace "mirror" with "redirect" then not a copy but rather
+the original packet is sent to eth1.
+
+2) Host A is hooked  up to us on eth0
 
-tc qdisc add dev lo ingress
 # redirect all packets arriving on ingress of lo to eth0
+---
+tc qdisc add dev lo ingress
 tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
 match u32 0 0 flowid 1:2 action mirred egress redirect dev eth0
+---
 
 On host A start a tcpdump on interface connecting to us.
 
 on our host ping -c 2 127.0.0.1
 
-Ping would fail sinc all packets are heading out eth0
+Ping would fail since all packets are heading out eth0
 tcpudmp on host A would show them
 
 if you substitute the redirect with mirror above as in:
@@ -38,34 +97,68 @@ match u32 0 0 flowid 1:2 action mirred egress mirror dev eth0
 Then you should see the packets on both host A and the local
 stack (i.e ping would work).
 
-Even more funky example:
+3) Even more funky example:
 
 #
-#allow 1 out 10 packets to randomly make it to the 
+#allow 1 out 10 packets on ingress of lo to randomly make it to the 
 # host A (Randomness uses the netrand generator)
 #
+---
 tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
 match u32 0 0 flowid 1:2 \
 action drop random determ ok 10\
 action mirred egress mirror dev eth0
+---
 
-------
-Example 2:
-# for packets coming from 10.0.0.9:
-#Redirect packets on egress (to ISP A) if you exceed a certain rate
-# to eth1 (to ISP B) if you exceed a certain rate
+4)
+# for packets from 10.0.0.9 going out on eth0 (could be local 
+# IP or something # we are forwarding) - 
+# if exceeding a 100Kbps rate, then redirect to eth1 
 #
 
+---
 tc qdisc add dev eth0 handle 1:0 root prio
-
 tc filter add dev eth0 parent 1:0 protocol ip prio 6 u32 \
 match ip src 10.0.0.9/32 flowid 1:16 \
 action police rate 100kbit burst 90k ok \
 action mirred egress mirror dev eth1
-
 ---
 
 A more interesting example is when you mirror flows to a dummy device
 so you could tcpdump them (dummy by defaults drops all packets it sees).
 This is a very useful debug feature.
 
+Lets say you are policing packets from alias 192.168.200.200/32
+you dont want those to exceed 100kbps going out.
+
+---
+tc qdisc add dev eth0 handle 1:0 root prio
+tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
+match ip src 192.168.200.200/32 flowid 1:2 \
+action police rate 100kbit burst 90k drop
+---
+
+If you run tcpdump on eth0 you will see all packets going out
+with src 192.168.200.200/32 dropped or not (since tcpdump shows
+all packets being egressed).
+Extend the rule a little to see only the packets making it out.
+
+---
+tc qdisc add dev eth0 handle 1:0 root prio
+tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
+match ip src 192.168.200.200/32 flowid 1:2 \
+action police rate 10kbit burst 90k drop \
+action mirred egress mirror dev dummy0
+---
+
+Now fire tcpdump on dummy0 to see only those packets ..
+tcpdump -n -i dummy0 -x -e -t
+
+Essentially a good debugging/logging interface (sort of like
+BSDs speacialized log device does without needing one).
+
+If you replace mirror with redirect, those packets will be
+blackholed and will never make it out. 
+
+cheers,
+jamal
old mode 100755 (executable)
new mode 100644 (file)
index 5eaa4a8..bb4eb78 100644 (file)
@@ -294,13 +294,17 @@ broadcast address will break networking.
 Do not use it, if you do not understand what this operation really does.
 \end{NB}
 
+\item \verb|netns PID|
+
+--- move the device to the network namespace associated with the process PID.
+
 \end{itemize}
 
 \vskip 1mm
 \begin{NB}
-The {\tt ip} utility does not change the \verb|PROMISC| 
-or \verb|ALLMULTI| flags. These flags are considered
-obsolete and should not be changed administratively.
+The \verb|PROMISC| and \verb|ALLMULTI| flags are considered
+obsolete and should not be changed administratively, though
+the {\tt ip} utility will allow that.
 \end{NB}
 
 \paragraph{Warning:} If multiple parameter changes are requested,
@@ -450,13 +454,6 @@ or not implemented (\verb|DEBUG|) or specific to some devices
 (\verb|MASTER|, \verb|AUTOMEDIA| and \verb|PORTSEL|). We do not discuss
 them here.
 \end{NB}
-\begin{NB}
-The values of \verb|PROMISC| and \verb|ALLMULTI| flags
-shown by the \verb|ifconfig| utility and by the \verb|ip| utility
-are {\em different\/}. \verb|ip link ls| shows the true device state,
-while \verb|ifconfig| shows the virtual state which was set with
-\verb|ifconfig| itself.
-\end{NB}
 
 
 The second line contains information on the link layer addresses
@@ -758,6 +755,11 @@ An IP address becomes secondary if another address with the same
 prefix bits already exists. The first address is primary.
 It is the leader of the group of all secondary addresses. When the leader
 is deleted, all secondaries are purged too.
+There is a tweak in \verb|/proc/sys/net/ipv4/conf/<dev>/promote_secondaries|
+which activate secondaries promotion when a primary is deleted.
+To permanently enable this feature on all devices add
+\verb|net.ipv4.conf.all.promote_secondaries=1| to \verb|/etc/sysctl.conf|.
+This tweak is available in linux 2.6.15 and later.
 
 
 \item \verb|dynamic|
index 110061a..496ef66 100644 (file)
@@ -1,3 +1,4 @@
+0x00   default
 0x10   lowdelay
 0x08   throughput
 0x04   reliability
 0xa0   critical
 0xc0   internet
 0xe0   network
+# Newer RFC2597 values
+0x28   AF11
+0x30   AF12
+0x38   AF13
+0x48   AF21
+0x50   AF22
+0x58   AF23
+0x68   AF31
+0x70   AF32
+0x78   AF33
+0x88   AF41
+0x90   AF42
+0x98   AF43
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/genl/.gitignore b/genl/.gitignore
new file mode 100644 (file)
index 0000000..383ef04
--- /dev/null
@@ -0,0 +1 @@
+genl
diff --git a/genl/Makefile b/genl/Makefile
new file mode 100644 (file)
index 0000000..6435875
--- /dev/null
@@ -0,0 +1,23 @@
+GENLOBJ=genl.o
+
+include ../Config
+
+GENLMODULES :=
+GENLMODULES += ctrl.o
+
+GENLOBJ += $(GENLMODULES)
+
+GENLLIB :=
+
+LDFLAGS += -Wl,-export-dynamic
+LDLIBS  += -lm -ldl
+
+all: genl
+
+genl: $(GENLOBJ) $(LIBNETLINK) $(LIBUTIL) $(GENLLIB)
+
+install: all
+       install -m 0755 genl $(DESTDIR)$(SBINDIR)
+
+clean:
+       rm -f $(GENLOBJ) $(GENLLIB) genl
diff --git a/genl/ctrl.c b/genl/ctrl.c
new file mode 100644 (file)
index 0000000..30ea4d7
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * ctrl.c      generic netlink controller
+ *
+ *             This program is free software; you can distribute 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.
+ *
+ * Authors:    J Hadi Salim (hadi@cyberus.ca)
+ *             Johannes Berg (johannes@sipsolutions.net)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "genl_utils.h"
+
+#define GENL_MAX_FAM_OPS       256
+#define GENL_MAX_FAM_GRPS      256
+
+static int usage(void)
+{
+       fprintf(stderr,"Usage: ctrl <CMD>\n" \
+                      "CMD   := get <PARMS> | list | monitor\n" \
+                      "PARMS := name <name> | id <id>\n" \
+                      "Examples:\n" \
+                      "\tctrl ls\n" \
+                      "\tctrl monitor\n" \
+                      "\tctrl get name foobar\n" \
+                      "\tctrl get id 0xF\n");
+       return -1;
+}
+
+int genl_ctrl_resolve_family(const char *family)
+{
+       struct rtnl_handle rth;
+       struct nlmsghdr *nlh;
+       struct genlmsghdr *ghdr;
+       int ret = 0;
+       struct {
+               struct nlmsghdr         n;
+               char                    buf[4096];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       nlh = &req.n;
+       nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       nlh->nlmsg_type = GENL_ID_CTRL;
+
+       ghdr = NLMSG_DATA(&req.n);
+       ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+       if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+               fprintf(stderr, "Cannot open generic netlink socket\n");
+               exit(1);
+       }
+
+       addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
+
+       if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
+               fprintf(stderr, "Error talking to the kernel\n");
+               goto errout;
+       }
+
+       {
+               struct rtattr *tb[CTRL_ATTR_MAX + 1];
+               struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
+               int len = nlh->nlmsg_len;
+               struct rtattr *attrs;
+
+               if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
+                       fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+                               "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
+                       goto errout;
+               }
+
+               if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
+                       fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+                       goto errout;
+               }
+
+               len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+               if (len < 0) {
+                       fprintf(stderr, "wrong controller message len %d\n", len);
+                       return -1;
+               }
+
+               attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+               parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+               if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+                       fprintf(stderr, "Missing family id TLV\n");
+                       goto errout;
+               }
+
+               ret = *(__u16 *) RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+       }
+
+errout:
+       rtnl_close(&rth);
+       return ret;
+}
+
+void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
+{
+       fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
+       if (!fl) {
+               fprintf(fp, "\n");
+               return;
+       }
+       fprintf(fp, "\t\t ");
+
+       if (fl & GENL_ADMIN_PERM)
+               fprintf(fp, " requires admin permission;");
+       if (fl & GENL_CMD_CAP_DO)
+               fprintf(fp, " can doit;");
+       if (fl & GENL_CMD_CAP_DUMP)
+               fprintf(fp, " can dumpit;");
+       if (fl & GENL_CMD_CAP_HASPOL)
+               fprintf(fp, " has policy");
+
+       fprintf(fp, "\n");
+}
+       
+static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+       struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
+       if (tb[CTRL_ATTR_OP_ID]) {
+               __u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
+               fprintf(fp, " ID-0x%x ",*id);
+       }
+       /* we are only gonna do this for newer version of the controller */
+       if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
+               __u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
+               print_ctrl_cmd_flags(fp, *fl);
+       }
+       return 0;
+
+}
+
+static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+       struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
+       if (tb[2]) {
+               __u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
+               fprintf(fp, " ID-0x%x ",*id);
+       }
+       if (tb[1]) {
+               char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+               fprintf(fp, " name: %s ", name);
+       }
+       return 0;
+
+}
+
+/*
+ * The controller sends one nlmsg per family
+*/
+static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
+                     void *arg)
+{
+       struct rtattr *tb[CTRL_ATTR_MAX + 1];
+       struct genlmsghdr *ghdr = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr *attrs;
+       FILE *fp = (FILE *) arg;
+       __u32 ctrl_v = 0x1;
+
+       if (n->nlmsg_type !=  GENL_ID_CTRL) {
+               fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+                       "nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
+               return 0;
+       }
+
+       if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
+           ghdr->cmd != CTRL_CMD_DELFAMILY &&
+           ghdr->cmd != CTRL_CMD_NEWFAMILY &&
+           ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
+           ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
+               fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+               return 0;
+       }
+
+       len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+       if (len < 0) {
+               fprintf(stderr, "wrong controller message len %d\n", len);
+               return -1;
+       }
+
+       attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+       parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+       if (tb[CTRL_ATTR_FAMILY_NAME]) {
+               char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
+               fprintf(fp, "\nName: %s\n",name);
+       }
+       if (tb[CTRL_ATTR_FAMILY_ID]) {
+               __u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+               fprintf(fp, "\tID: 0x%x ",*id);
+       }
+       if (tb[CTRL_ATTR_VERSION]) {
+               __u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
+               fprintf(fp, " Version: 0x%x ",*v);
+               ctrl_v = *v;
+       }
+       if (tb[CTRL_ATTR_HDRSIZE]) {
+               __u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
+               fprintf(fp, " header size: %d ",*h);
+       }
+       if (tb[CTRL_ATTR_MAXATTR]) {
+               __u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
+               fprintf(fp, " max attribs: %d ",*ma);
+       }
+       /* end of family definitions .. */
+       fprintf(fp,"\n");
+       if (tb[CTRL_ATTR_OPS]) {
+               struct rtattr *tb2[GENL_MAX_FAM_OPS];
+               int i=0;
+               parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
+               fprintf(fp, "\tcommands supported: \n");
+               for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
+                       if (tb2[i]) {
+                               fprintf(fp, "\t\t#%d: ", i);
+                               if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
+                                       fprintf(fp, "Error printing command\n");
+                               }
+                               /* for next command */
+                               fprintf(fp,"\n");
+                       }
+               }
+
+               /* end of family::cmds definitions .. */
+               fprintf(fp,"\n");
+       }
+
+       if (tb[CTRL_ATTR_MCAST_GROUPS]) {
+               struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
+               int i;
+
+               parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
+                                   tb[CTRL_ATTR_MCAST_GROUPS]);
+               fprintf(fp, "\tmulticast groups:\n");
+
+               for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
+                       if (tb2[i]) {
+                               fprintf(fp, "\t\t#%d: ", i);
+                               if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
+                                       fprintf(fp, "Error printing group\n");
+                               /* for next group */
+                               fprintf(fp,"\n");
+                       }
+               }
+
+               /* end of family::groups definitions .. */
+               fprintf(fp,"\n");
+       }
+
+       fflush(fp);
+       return 0;
+}
+
+static int ctrl_list(int cmd, int argc, char **argv)
+{
+       struct rtnl_handle rth;
+       struct nlmsghdr *nlh;
+       struct genlmsghdr *ghdr;
+       int ret = -1;
+       char d[GENL_NAMSIZ];
+       struct {
+               struct nlmsghdr         n;
+               char                    buf[4096];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       nlh = &req.n;
+       nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       nlh->nlmsg_type = GENL_ID_CTRL;
+
+       ghdr = NLMSG_DATA(&req.n);
+       ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+       if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+               fprintf(stderr, "Cannot open generic netlink socket\n");
+               exit(1);
+       }
+
+       if (cmd == CTRL_CMD_GETFAMILY) {
+               if (argc != 2) {
+                       fprintf(stderr, "Wrong number of params\n");
+                       return -1;
+               }
+
+               if (matches(*argv, "name") == 0) {
+                       NEXT_ARG();
+                       strncpy(d, *argv, sizeof (d) - 1);
+                       addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
+                                 d, strlen(d) + 1);
+               } else if (matches(*argv, "id") == 0) {
+                       __u16 id;
+                       NEXT_ARG();
+                       if (get_u16(&id, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"id\"\n");
+                               goto ctrl_done;
+                       }
+
+                       addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
+
+               } else {
+                       fprintf(stderr, "Wrong params\n");
+                       goto ctrl_done;
+               }
+
+               if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
+                       fprintf(stderr, "Error talking to the kernel\n");
+                       goto ctrl_done;
+               }
+
+               if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
+                       fprintf(stderr, "Dump terminated\n");
+                       goto ctrl_done;
+               }
+
+       }
+
+       if (cmd == CTRL_CMD_UNSPEC) {
+               nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+               nlh->nlmsg_seq = rth.dump = ++rth.seq;
+
+               if (rtnl_send(&rth, (const char *) nlh, nlh->nlmsg_len) < 0) {
+                       perror("Failed to send dump request\n");
+                       goto ctrl_done;
+               }
+
+               rtnl_dump_filter(&rth, print_ctrl, stdout, NULL, NULL);
+
+        }
+
+       ret = 0;
+ctrl_done:
+       rtnl_close(&rth);
+       return ret;
+}
+
+static int ctrl_listen(int argc, char **argv)
+{
+       struct rtnl_handle rth;
+
+       if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
+               fprintf(stderr, "Canot open generic netlink socket\n");
+               return -1;
+       }
+
+       if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int parse_ctrl(struct genl_util *a, int argc, char **argv)
+{
+       argv++;
+       if (--argc <= 0) {
+               fprintf(stderr, "wrong controller params\n");
+               return -1;
+       }
+
+       if (matches(*argv, "monitor") == 0)
+               return ctrl_listen(argc-1, argv+1);
+       if (matches(*argv, "get") == 0)
+               return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
+       if (matches(*argv, "list") == 0 ||
+           matches(*argv, "show") == 0 ||
+           matches(*argv, "lst") == 0)
+               return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
+       if (matches(*argv, "help") == 0)
+               return usage();
+
+       fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl -help\".\n",
+               *argv);
+
+       return -1;
+}
+
+struct genl_util ctrl_genl_util = {
+       .name = "ctrl",
+       .parse_genlopt = parse_ctrl,
+       .print_genlopt = print_ctrl,
+};
diff --git a/genl/genl.c b/genl/genl.c
new file mode 100644 (file)
index 0000000..3ae75ae
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * genl.c              "genl" utility frontend.
+ *
+ *             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.
+ *
+ * Authors:    Jamal Hadi Salim
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h> /* until we put our own header */
+#include "SNAPSHOT.h"
+#include "utils.h"
+#include "genl_utils.h"
+
+int show_stats = 0;
+int show_details = 0;
+int show_raw = 0;
+int resolve_hosts = 0;
+
+static void *BODY;
+static struct genl_util * genl_list;
+
+
+static int print_nofopt(const struct sockaddr_nl *who, struct nlmsghdr *n,
+                       void *arg)
+{
+       fprintf((FILE *) arg, "unknown genl type ..\n");
+       return 0;
+}
+
+static int parse_nofopt(struct genl_util *f, int argc, char **argv)
+{
+       if (argc) {
+               fprintf(stderr, "Unknown genl \"%s\", hence option \"%s\" "
+                       "is unparsable\n", f->name, *argv);
+               return -1;
+       }
+
+       return 0;
+}
+
+static struct genl_util *get_genl_kind(char *str)
+{
+       void *dlh;
+       char buf[256];
+       struct genl_util *f;
+
+       for (f = genl_list; f; f = f->next)
+               if (strcmp(f->name, str) == 0)
+                       return f;
+
+       snprintf(buf, sizeof(buf), "%s.so", str);
+       dlh = dlopen(buf, RTLD_LAZY);
+       if (dlh == NULL) {
+               dlh = BODY;
+               if (dlh == NULL) {
+                       dlh = BODY = dlopen(NULL, RTLD_LAZY);
+                       if (dlh == NULL)
+                               goto noexist;
+               }
+       }
+
+       snprintf(buf, sizeof(buf), "%s_genl_util", str);
+
+       f = dlsym(dlh, buf);
+       if (f == NULL)
+               goto noexist;
+reg:
+       f->next = genl_list;
+       genl_list = f;
+       return f;
+
+noexist:
+       f = malloc(sizeof(*f));
+       if (f) {
+               memset(f, 0, sizeof(*f));
+               strncpy(f->name, str, 15);
+               f->parse_genlopt = parse_nofopt;
+               f->print_genlopt = print_nofopt;
+               goto reg;
+       }
+       return f;
+}
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: genl [ OPTIONS ] OBJECT | help }\n"
+                       "where  OBJECT := { ctrl etc }\n"
+                       "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }\n");
+       exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+       char *basename;
+
+       basename = strrchr(argv[0], '/');
+       if (basename == NULL)
+               basename = argv[0];
+       else
+               basename++;
+
+       while (argc > 1) {
+               if (argv[1][0] != '-')
+                       break;
+               if (matches(argv[1], "-stats") == 0 ||
+                   matches(argv[1], "-statistics") == 0) {
+                       ++show_stats;
+               } else if (matches(argv[1], "-details") == 0) {
+                       ++show_details;
+               } else if (matches(argv[1], "-raw") == 0) {
+                       ++show_raw;
+               } else if (matches(argv[1], "-Version") == 0) {
+                       printf("genl utility, iproute2-ss%s\n", SNAPSHOT);
+                       exit(0);
+               } else if (matches(argv[1], "-help") == 0) {
+                       usage();
+               } else {
+                       fprintf(stderr, "Option \"%s\" is unknown, try "
+                               "\"genl -help\".\n", argv[1]);
+                       exit(-1);
+               }
+               argc--; argv++;
+       }
+
+       if (argc > 1) {
+               int ret;
+               struct genl_util *a = NULL;
+               a = get_genl_kind(argv[1]);
+               if (NULL == a) {
+                       fprintf(stderr,"bad genl %s\n",argv[1]);
+               }
+
+               ret = a->parse_genlopt(a, argc-1, argv+1);
+               return ret;
+
+               if (matches(argv[1], "help") == 0)
+                       usage();
+               fprintf(stderr, "Object \"%s\" is unknown, try \"genl "
+                       "-help\".\n", argv[1]);
+               exit(-1);
+       }
+
+       usage();
+}
diff --git a/genl/genl_utils.h b/genl/genl_utils.h
new file mode 100644 (file)
index 0000000..85b5183
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _TC_UTIL_H_
+#define _TC_UTIL_H_ 1
+
+#include "utils.h"
+#include "linux/genetlink.h"
+
+struct genl_util
+{
+       struct  genl_util *next;
+       char    name[16];
+       int     (*parse_genlopt)(struct genl_util *fu, int argc, char **argv);
+       int     (*print_genlopt)(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+};
+
+extern int genl_ctrl_resolve_family(const char *family);
+
+#endif
index 9438c0f..f97113f 100644 (file)
@@ -1 +1 @@
-static char SNAPSHOT[] = "060323";
+static const char SNAPSHOT[] = "090115";
index 8360617..1050593 100644 (file)
@@ -65,7 +65,7 @@ struct ip6tables_match
 struct ip6tables_target
 {
        struct ip6tables_target *next;
-       
+
        ip6t_chainlabel name;
 
        const char *version;
@@ -87,7 +87,7 @@ struct ip6tables_target
        int (*parse)(int c, char **argv, int invert, unsigned int *flags,
                     const struct ip6t_entry *entry,
                     struct ip6t_entry_target **target);
-       
+
        /* Final check; exit if not ok. */
        void (*final_check)(unsigned int flags);
 
index 25f36ae..dd844c1 100644 (file)
@@ -170,7 +170,7 @@ extern struct iptables_match *find_match(const char *name, enum ipt_tryload, str
 
 extern int delete_chain(const ipt_chainlabel chain, int verbose,
                        iptc_handle_t *handle);
-extern int flush_entries(const ipt_chainlabel chain, int verbose, 
+extern int flush_entries(const ipt_chainlabel chain, int verbose,
                        iptc_handle_t *handle);
 extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
                int verbose, int builtinstoo, iptc_handle_t *handle);
index ed5b9c0..9099667 100644 (file)
@@ -5,8 +5,13 @@
 enum exittype {
        OTHER_PROBLEM = 1,
        PARAMETER_PROBLEM,
-       VERSION_PROBLEM
+       VERSION_PROBLEM,
+       RESOURCE_PROBLEM
 };
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
 extern void exit_printhelp(void) __attribute__((noreturn));
 extern void exit_tryhelp(int) __attribute__((noreturn));
 int check_inverse(const char option[], int *invert, int *optind, int argc);
@@ -23,16 +28,24 @@ extern int string_to_number_ll(const char *,
                            unsigned long long int,
                            unsigned long long *);
 extern int iptables_insmod(const char *modname, const char *modprobe);
+extern int load_iptables_ko(const char *modprobe);
 void exit_error(enum exittype, char *, ...)__attribute__((noreturn,
                                                          format(printf,2,3)));
 extern const char *program_name, *program_version;
 extern char *lib_dir;
 
+#define _init __attribute__((constructor)) my_init
 #ifdef NO_SHARED_LIBS
 # ifdef _INIT
+#  undef _init
 #  define _init _INIT
 # endif
   extern void init_extensions(void);
 #endif
 
+#define __be32 u_int32_t
+#define __le32 u_int32_t
+#define __be16 u_int16_t
+#define __le16 u_int16_t
+
 #endif /*_IPTABLES_COMMON_H*/
index 18861fe..7e87828 100644 (file)
@@ -11,7 +11,6 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
-#include <net/if.h>
 #include <sys/types.h>
 #else /* libc5 */
 #include <sys/socket.h>
index 63cc3c8..0e02468 100644 (file)
@@ -4,6 +4,9 @@
 #include <asm/types.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
 
 struct rtnl_handle
 {
@@ -20,7 +23,7 @@ extern void rtnl_close(struct rtnl_handle *rth);
 extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
 
-typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, 
+typedef int (*rtnl_filter_t)(const struct sockaddr_nl *,
                             struct nlmsghdr *n, void *);
 extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter,
                            void *arg1,
@@ -31,21 +34,30 @@ extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
                     rtnl_filter_t junk,
                     void *jarg);
 extern int rtnl_send(struct rtnl_handle *rth, const char *buf, int);
-
+extern int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int);
 
 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen);
 extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len);
+extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type);
+extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest);
+extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len);
+extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest);
 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
 extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen);
 
 extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
 extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len);
 
 #define parse_rtattr_nested(tb, max, rta) \
        (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
 
-extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, 
+#define parse_rtattr_nested_compat(tb, max, rta, data, len) \
+({     data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
+       __parse_rtattr_nested_compat(tb, max, rta, len); })
+
+extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler,
                       void *jarg);
 extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
                       void *jarg);
@@ -53,5 +65,37 @@ extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
 #define NLMSG_TAIL(nmsg) \
        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
 
+#ifndef IFA_RTA
+#define IFA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#endif
+#ifndef IFA_PAYLOAD
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+#endif
+
+#ifndef IFLA_RTA
+#define IFLA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#endif
+#ifndef IFLA_PAYLOAD
+#define IFLA_PAYLOAD(n)        NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+#endif
+
+#ifndef NDA_RTA
+#define NDA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#endif
+#ifndef NDA_PAYLOAD
+#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+#endif
+
+#ifndef NDTA_RTA
+#define NDTA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg))))
+#endif
+#ifndef NDTA_PAYLOAD
+#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
+#endif
+
 #endif /* __LIBNETLINK_H__ */
 
diff --git a/include/linux/atm.h b/include/linux/atm.h
new file mode 100644 (file)
index 0000000..6de1627
--- /dev/null
@@ -0,0 +1,240 @@
+/* atm.h - general ATM declarations */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
+
+/*
+ * WARNING: User-space programs should not #include <linux/atm.h> directly.
+ *          Instead, #include <atm.h>
+ */
+
+#ifndef _LINUX_ATM_H
+#define _LINUX_ATM_H
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+
+#include <linux/atmapi.h>
+#include <linux/atmsap.h>
+#include <linux/atmioc.h>
+#include <linux/types.h>
+
+
+/* general ATM constants */
+#define ATM_CELL_SIZE              53  /* ATM cell size incl. header */
+#define ATM_CELL_PAYLOAD           48  /* ATM payload size */
+#define ATM_AAL0_SDU               52  /* AAL0 SDU size */
+#define ATM_MAX_AAL34_PDU       65535  /* maximum AAL3/4 PDU payload */
+#define ATM_AAL5_TRAILER            8  /* AAL5 trailer size */
+#define ATM_MAX_AAL5_PDU        65535  /* maximum AAL5 PDU payload */
+#define ATM_MAX_CDV              9999  /* maximum (default) CDV */
+#define ATM_NOT_RSV_VCI                    32  /* first non-reserved VCI value */
+
+#define ATM_MAX_VPI               255  /* maximum VPI at the UNI */
+#define ATM_MAX_VPI_NNI                  4096  /* maximum VPI at the NNI */
+#define ATM_MAX_VCI             65535  /* maximum VCI */
+
+
+/* "protcol" values for the socket system call */
+#define ATM_NO_AAL     0               /* AAL not specified */
+#define ATM_AAL0       13              /* "raw" ATM cells */
+#define ATM_AAL1       1               /* AAL1 (CBR) */
+#define ATM_AAL2       2               /* AAL2 (VBR) */
+#define ATM_AAL34      3               /* AAL3/4 (data) */
+#define ATM_AAL5       5               /* AAL5 (data) */
+
+/*
+ * socket option name coding functions
+ *
+ * Note that __SO_ENCODE and __SO_LEVEL are somewhat a hack since the
+ * << 22 only reserves 9 bits for the level.  On some architectures
+ * SOL_SOCKET is 0xFFFF, so that's a bit of a problem
+ */
+
+#define __SO_ENCODE(l,n,t)     ((((l) & 0x1FF) << 22) | ((n) << 16) | \
+                               sizeof(t))
+#define __SO_LEVEL_MATCH(c,m)  (((c) >> 22) == ((m) & 0x1FF))
+#define __SO_NUMBER(c)         (((c) >> 16) & 0x3f)
+#define __SO_SIZE(c)           ((c) & 0x3fff)
+
+/*
+ * ATM layer
+ */
+
+#define SO_SETCLP      __SO_ENCODE(SOL_ATM,0,int)
+                           /* set CLP bit value - TODO */
+#define SO_CIRANGE     __SO_ENCODE(SOL_ATM,1,struct atm_cirange)
+                           /* connection identifier range; socket must be
+                              bound or connected */
+#define SO_ATMQOS      __SO_ENCODE(SOL_ATM,2,struct atm_qos)
+                           /* Quality of Service setting */
+#define SO_ATMSAP      __SO_ENCODE(SOL_ATM,3,struct atm_sap)
+                           /* Service Access Point */
+#define SO_ATMPVC      __SO_ENCODE(SOL_ATM,4,struct sockaddr_atmpvc)
+                           /* "PVC" address (also for SVCs); get only */
+#define SO_MULTIPOINT  __SO_ENCODE(SOL_ATM, 5, int)
+                           /* make this vc a p2mp */
+
+
+/*
+ * Note @@@: since the socket layers don't really distinguish the control and
+ * the data plane but generally seems to be data plane-centric, any layer is
+ * about equally wrong for the SAP. If you have a better idea about this,
+ * please speak up ...
+ */
+
+
+/* ATM cell header (for AAL0) */
+
+/* BEGIN_CH */
+#define ATM_HDR_GFC_MASK       0xf0000000
+#define ATM_HDR_GFC_SHIFT      28
+#define ATM_HDR_VPI_MASK       0x0ff00000
+#define ATM_HDR_VPI_SHIFT      20
+#define ATM_HDR_VCI_MASK       0x000ffff0
+#define ATM_HDR_VCI_SHIFT      4
+#define ATM_HDR_PTI_MASK       0x0000000e
+#define ATM_HDR_PTI_SHIFT      1
+#define ATM_HDR_CLP            0x00000001
+/* END_CH */
+
+
+/* PTI codings */
+
+/* BEGIN_PTI */
+#define ATM_PTI_US0    0  /* user data cell, congestion not exp, SDU-type 0 */
+#define ATM_PTI_US1    1  /* user data cell, congestion not exp, SDU-type 1 */
+#define ATM_PTI_UCES0  2  /* user data cell, cong. experienced, SDU-type 0 */
+#define ATM_PTI_UCES1  3  /* user data cell, cong. experienced, SDU-type 1 */
+#define ATM_PTI_SEGF5  4  /* segment OAM F5 flow related cell */
+#define ATM_PTI_E2EF5  5  /* end-to-end OAM F5 flow related cell */
+#define ATM_PTI_RSV_RM 6  /* reserved for traffic control/resource mgmt */
+#define ATM_PTI_RSV    7  /* reserved */
+/* END_PTI */
+
+
+/*
+ * The following items should stay in linux/atm.h, which should be linked to
+ * netatm/atm.h
+ */
+
+/* Traffic description */
+
+#define ATM_NONE       0               /* no traffic */
+#define ATM_UBR                1
+#define ATM_CBR                2
+#define ATM_VBR                3
+#define ATM_ABR                4
+#define ATM_ANYCLASS   5               /* compatible with everything */
+
+#define ATM_MAX_PCR    -1              /* maximum available PCR */
+
+struct atm_trafprm {
+       unsigned char   traffic_class;  /* traffic class (ATM_UBR, ...) */
+       int             max_pcr;        /* maximum PCR in cells per second */
+       int             pcr;            /* desired PCR in cells per second */
+       int             min_pcr;        /* minimum PCR in cells per second */
+       int             max_cdv;        /* maximum CDV in microseconds */
+       int             max_sdu;        /* maximum SDU in bytes */
+        /* extra params for ABR */
+        unsigned int   icr;            /* Initial Cell Rate (24-bit) */
+        unsigned int   tbe;            /* Transient Buffer Exposure (24-bit) */ 
+        unsigned int   frtt : 24;      /* Fixed Round Trip Time (24-bit) */
+        unsigned int   rif  : 4;       /* Rate Increment Factor (4-bit) */
+        unsigned int   rdf  : 4;       /* Rate Decrease Factor (4-bit) */
+        unsigned int nrm_pres  :1;      /* nrm present bit */
+        unsigned int trm_pres  :1;             /* rm present bit */
+        unsigned int adtf_pres :1;             /* adtf present bit */
+        unsigned int cdf_pres  :1;     /* cdf present bit*/
+        unsigned int nrm       :3;             /* Max # of Cells for each forward RM cell (3-bit) */
+        unsigned int trm       :3;     /* Time between forward RM cells (3-bit) */    
+       unsigned int adtf      :10;     /* ACR Decrease Time Factor (10-bit) */
+       unsigned int cdf       :3;      /* Cutoff Decrease Factor (3-bit) */
+        unsigned int spare     :9;      /* spare bits */ 
+};
+
+struct atm_qos {
+       struct atm_trafprm txtp;        /* parameters in TX direction */
+       struct atm_trafprm rxtp __ATM_API_ALIGN;
+                                       /* parameters in RX direction */
+       unsigned char aal __ATM_API_ALIGN;
+};
+
+/* PVC addressing */
+
+#define ATM_ITF_ANY    -1              /* "magic" PVC address values */
+#define ATM_VPI_ANY    -1
+#define ATM_VCI_ANY    -1
+#define ATM_VPI_UNSPEC -2
+#define ATM_VCI_UNSPEC -2
+
+
+struct sockaddr_atmpvc {
+       unsigned short  sap_family;     /* address family, AF_ATMPVC  */
+       struct {                        /* PVC address */
+               short   itf;            /* ATM interface */
+               short   vpi;            /* VPI (only 8 bits at UNI) */
+               int     vci;            /* VCI (only 16 bits at UNI) */
+       } sap_addr __ATM_API_ALIGN;     /* PVC address */
+};
+
+/* SVC addressing */
+
+#define        ATM_ESA_LEN     20              /* ATM End System Address length */
+#define ATM_E164_LEN   12              /* maximum E.164 number length */
+
+#define ATM_AFI_DCC    0x39            /* DCC ATM Format */
+#define ATM_AFI_ICD    0x47            /* ICD ATM Format */
+#define ATM_AFI_E164   0x45            /* E.164 ATM Format */
+#define ATM_AFI_LOCAL  0x49            /* Local ATM Format */ 
+
+#define ATM_AFI_DCC_GROUP      0xBD    /* DCC ATM Group Format */
+#define ATM_AFI_ICD_GROUP      0xC5    /* ICD ATM Group Format */
+#define ATM_AFI_E164_GROUP     0xC3    /* E.164 ATM Group Format */
+#define ATM_AFI_LOCAL_GROUP    0xC7    /* Local ATM Group Format */
+
+#define ATM_LIJ_NONE   0               /* no leaf-initiated join */
+#define ATM_LIJ                1               /* request joining */
+#define ATM_LIJ_RPJ    2               /* set to root-prompted join */
+#define ATM_LIJ_NJ     3               /* set to network join */
+
+
+struct sockaddr_atmsvc {
+    unsigned short     sas_family;     /* address family, AF_ATMSVC */
+    struct {                           /* SVC address */
+        unsigned char  prv[ATM_ESA_LEN];/* private ATM address */
+        char           pub[ATM_E164_LEN+1]; /* public address (E.164) */
+                                       /* unused addresses must be bzero'ed */
+       char            lij_type;       /* role in LIJ call; one of ATM_LIJ* */
+       __u32   lij_id;         /* LIJ call identifier */
+    } sas_addr __ATM_API_ALIGN;                /* SVC address */
+};
+
+
+static __inline__ int atmsvc_addr_in_use(struct sockaddr_atmsvc addr)
+{
+       return *addr.sas_addr.prv || *addr.sas_addr.pub;
+}
+
+
+static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr)
+{
+       return addr.sap_addr.itf || addr.sap_addr.vpi || addr.sap_addr.vci;
+}
+
+
+/*
+ * Some stuff for linux/sockios.h
+ */
+
+struct atmif_sioc {
+    int number;
+    int length;
+    void *arg;
+};
+
+typedef unsigned short atm_backend_t;
+#endif
diff --git a/include/linux/atmapi.h b/include/linux/atmapi.h
new file mode 100644 (file)
index 0000000..8fe54d9
--- /dev/null
@@ -0,0 +1,29 @@
+/* atmapi.h - ATM API user space/kernel compatibility */
+/* Written 1999,2000 by Werner Almesberger, EPFL ICA */
+
+#ifndef _LINUX_ATMAPI_H
+#define _LINUX_ATMAPI_H
+
+#if defined(__sparc__) || defined(__ia64__)
+/* such alignment is not required on 32 bit sparcs, but we can't
+   figure that we are on a sparc64 while compiling user-space programs. */
+#define __ATM_API_ALIGN        __attribute__((aligned(8)))
+#else
+#define __ATM_API_ALIGN
+#endif
+
+
+/*
+ * Opaque type for kernel pointers. Note that _ is never accessed. We need
+ * the struct in order hide the array, so that we can make simple assignments
+ * instead of being forced to use memcpy. It also improves error reporting for
+ * code that still assumes that we're passing unsigned longs.
+ *
+ * Convention: NULL pointers are passed as a field of all zeroes.
+ */
+typedef struct { unsigned char _[8]; } __ATM_API_ALIGN atm_kptr_t;
+
+#endif
diff --git a/include/linux/atmioc.h b/include/linux/atmioc.h
new file mode 100644 (file)
index 0000000..37f67aa
--- /dev/null
@@ -0,0 +1,41 @@
+/* atmioc.h - ranges for ATM-related ioctl numbers */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+/*
+ * See http://icawww1.epfl.ch/linux-atm/magic.html for the complete list of
+ * "magic" ioctl numbers.
+ */
+
+
+#ifndef _LINUX_ATMIOC_H
+#define _LINUX_ATMIOC_H
+
+#include <asm/ioctl.h>
+               /* everybody including atmioc.h will also need _IO{,R,W,WR} */
+
+#define ATMIOC_PHYCOM    0x00 /* PHY device common ioctls, globally unique */
+#define ATMIOC_PHYCOM_END 0x0f
+#define ATMIOC_PHYTYP    0x10 /* PHY dev type ioctls, unique per PHY type */
+#define ATMIOC_PHYTYP_END 0x2f
+#define ATMIOC_PHYPRV    0x30 /* PHY dev private ioctls, unique per driver */
+#define ATMIOC_PHYPRV_END 0x4f
+#define ATMIOC_SARCOM    0x50 /* SAR device common ioctls, globally unique */
+#define ATMIOC_SARCOM_END 0x50
+#define ATMIOC_SARPRV    0x60 /* SAR dev private ioctls, unique per driver */
+#define ATMIOC_SARPRV_END 0x7f
+#define ATMIOC_ITF       0x80 /* Interface ioctls, globally unique */
+#define ATMIOC_ITF_END   0x8f
+#define ATMIOC_BACKEND   0x90 /* ATM generic backend ioctls, u. per backend */
+#define ATMIOC_BACKEND_END 0xaf
+/* 0xb0-0xbf: Reserved for future use */
+#define ATMIOC_AREQUIPA          0xc0 /* Application requested IP over ATM, glob. u. */
+#define ATMIOC_LANE      0xd0 /* LAN Emulation, globally unique */
+#define ATMIOC_MPOA       0xd8 /* MPOA, globally unique */
+#define        ATMIOC_CLIP       0xe0 /* Classical IP over ATM control, globally u. */
+#define        ATMIOC_CLIP_END   0xef
+#define        ATMIOC_SPECIAL    0xf0 /* Special-purpose controls, globally unique */
+#define        ATMIOC_SPECIAL_END 0xff
+
+#endif
diff --git a/include/linux/atmsap.h b/include/linux/atmsap.h
new file mode 100644 (file)
index 0000000..799b104
--- /dev/null
@@ -0,0 +1,162 @@
+/* atmsap.h - ATM Service Access Point addressing definitions */
+
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+#ifndef _LINUX_ATMSAP_H
+#define _LINUX_ATMSAP_H
+
+#include <linux/atmapi.h>
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+
+/*
+ * Layer 2 protocol identifiers
+ */
+
+/* BEGIN_L2 */
+#define ATM_L2_NONE    0       /* L2 not specified */
+#define ATM_L2_ISO1745  0x01   /* Basic mode ISO 1745 */
+#define ATM_L2_Q291    0x02    /* ITU-T Q.291 (Rec. I.441) */
+#define ATM_L2_X25_LL  0x06    /* ITU-T X.25, link layer */
+#define ATM_L2_X25_ML  0x07    /* ITU-T X.25, multilink */
+#define ATM_L2_LAPB    0x08    /* Extended LAPB, half-duplex (Rec. T.71) */
+#define ATM_L2_HDLC_ARM        0x09    /* HDLC ARM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_NRM        0x0a    /* HDLC NRM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_ABM        0x0b    /* HDLC ABM (ISO/IEC 4335) */
+#define ATM_L2_ISO8802 0x0c    /* LAN LLC (ISO/IEC 8802/2) */
+#define ATM_L2_X75     0x0d    /* ITU-T X.75, SLP */
+#define ATM_L2_Q922    0x0e    /* ITU-T Q.922 */
+#define ATM_L2_USER    0x10    /* user-specified */
+#define ATM_L2_ISO7776 0x11    /* ISO 7776 DTE-DTE */
+/* END_L2 */
+
+
+/*
+ * Layer 3 protocol identifiers
+ */
+
+/* BEGIN_L3 */
+#define ATM_L3_NONE    0       /* L3 not specified */
+#define ATM_L3_X25     0x06    /* ITU-T X.25, packet layer */
+#define ATM_L3_ISO8208 0x07    /* ISO/IEC 8208 */
+#define ATM_L3_X223    0x08    /* ITU-T X.223 | ISO/IEC 8878 */
+#define ATM_L3_ISO8473 0x09    /* ITU-T X.233 | ISO/IEC 8473 */
+#define ATM_L3_T70     0x0a    /* ITU-T T.70 minimum network layer */
+#define ATM_L3_TR9577  0x0b    /* ISO/IEC TR 9577 */
+#define ATM_L3_H310    0x0c    /* ITU-T Recommendation H.310 */
+#define ATM_L3_H321    0x0d    /* ITU-T Recommendation H.321 */
+#define ATM_L3_USER    0x10    /* user-specified */
+/* END_L3 */
+
+
+/*
+ * High layer identifiers
+ */
+
+/* BEGIN_HL */
+#define ATM_HL_NONE    0       /* HL not specified */
+#define ATM_HL_ISO     0x01    /* ISO */
+#define ATM_HL_USER    0x02    /* user-specific */
+#define ATM_HL_HLP     0x03    /* high layer profile - UNI 3.0 only */
+#define ATM_HL_VENDOR  0x04    /* vendor-specific application identifier */
+/* END_HL */
+
+
+/*
+ * ITU-T coded mode of operation
+ */
+
+/* BEGIN_IMD */
+#define ATM_IMD_NONE    0      /* mode not specified */
+#define ATM_IMD_NORMAL  1      /* normal mode of operation */
+#define ATM_IMD_EXTENDED 2     /* extended mode of operation */
+/* END_IMD */
+
+/*
+ * H.310 code points
+ */
+
+#define ATM_TT_NONE    0       /* terminal type not specified */
+#define ATM_TT_RX      1       /* receive only */
+#define ATM_TT_TX      2       /* send only */
+#define ATM_TT_RXTX    3       /* receive and send */
+
+#define ATM_MC_NONE    0       /* no multiplexing */
+#define ATM_MC_TS      1       /* transport stream (TS) */
+#define ATM_MC_TS_FEC  2       /* transport stream with forward error corr. */
+#define ATM_MC_PS      3       /* program stream (PS) */
+#define ATM_MC_PS_FEC  4       /* program stream with forward error corr. */
+#define ATM_MC_H221    5       /* ITU-T Rec. H.221 */
+
+/*
+ * SAP structures
+ */
+
+#define ATM_MAX_HLI    8       /* maximum high-layer information length */
+
+
+struct atm_blli {
+    unsigned char l2_proto;    /* layer 2 protocol */
+    union {
+       struct {
+           unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */
+                               /* absent */
+           unsigned char window; /* window size (k), 1-127 (0 to omit) */
+       } itu;                  /* ITU-T encoding */
+       unsigned char user;     /* user-specified l2 information */
+    } l2;
+    unsigned char l3_proto;    /* layer 3 protocol */
+    union {
+       struct {
+           unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */
+                               /* absent */
+           unsigned char def_size; /* default packet size (log2), 4-12 (0 to */
+                                   /* omit) */
+           unsigned char window;/* packet window size, 1-127 (0 to omit) */
+       } itu;                  /* ITU-T encoding */
+       unsigned char user;     /* user specified l3 information */
+       struct {                      /* if l3_proto = ATM_L3_H310 */
+           unsigned char term_type;  /* terminal type */
+           unsigned char fw_mpx_cap; /* forward multiplexing capability */
+                                     /* only if term_type != ATM_TT_NONE */
+           unsigned char bw_mpx_cap; /* backward multiplexing capability */
+                                     /* only if term_type != ATM_TT_NONE */
+       } h310;
+       struct {                  /* if l3_proto = ATM_L3_TR9577 */
+           unsigned char ipi;    /* initial protocol id */
+           unsigned char snap[5];/* IEEE 802.1 SNAP identifier */
+                                 /* (only if ipi == NLPID_IEEE802_1_SNAP) */
+       } tr9577;
+    } l3;
+} __ATM_API_ALIGN;
+
+
+struct atm_bhli {
+    unsigned char hl_type;     /* high layer information type */
+    unsigned char hl_length;   /* length (only if hl_type == ATM_HL_USER || */
+                               /* hl_type == ATM_HL_ISO) */
+    unsigned char hl_info[ATM_MAX_HLI];/* high layer information */
+};
+
+
+#define ATM_MAX_BLLI   3               /* maximum number of BLLI elements */
+
+
+struct atm_sap {
+       struct atm_bhli bhli;           /* local SAP, high-layer information */
+       struct atm_blli blli[ATM_MAX_BLLI] __ATM_API_ALIGN;
+                                       /* local SAP, low-layer info */
+};
+
+
+static __inline__ int blli_in_use(struct atm_blli blli)
+{
+       return blli.l2_proto || blli.l3_proto;
+}
+
+#endif
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
new file mode 100644 (file)
index 0000000..87b606b
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+#include <linux/types.h>
+#include <linux/rtnetlink.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_DEV_DETACHED  0x00000008
+
+/* 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_IFNAME,     /* interface name */
+       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_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/include/linux/genetlink.h b/include/linux/genetlink.h
new file mode 100644 (file)
index 0000000..7da02c9
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __LINUX_GENERIC_NETLINK_H
+#define __LINUX_GENERIC_NETLINK_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/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h
new file mode 100644 (file)
index 0000000..5839723
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef __HDLC_IOCTL_H__
+#define __HDLC_IOCTL_H__
+
+
+#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
+
+#define CLOCK_DEFAULT   0      /* Default setting */
+#define CLOCK_EXT      1       /* External TX and RX clock - DTE */
+#define CLOCK_INT      2       /* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT    3       /* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX 4       /* TX clock derived from external RX clock */
+
+
+#define ENCODING_DEFAULT       0 /* Default setting */
+#define ENCODING_NRZ           1
+#define ENCODING_NRZI          2
+#define ENCODING_FM_MARK       3
+#define ENCODING_FM_SPACE      4
+#define ENCODING_MANCHESTER    5
+
+
+#define PARITY_DEFAULT         0 /* Default setting */
+#define PARITY_NONE            1 /* No parity */
+#define PARITY_CRC16_PR0       2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1       3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT            0 /* Default setting */
+#define LMI_NONE               1 /* No LMI, all PVCs are static */
+#define LMI_ANSI               2 /* ANSI Annex D */
+#define LMI_CCITT              3 /* ITU-T Annex A */
+#define LMI_CISCO              4 /* The "original" LMI, aka Gang of Four */
+
+typedef struct { 
+       unsigned int clock_rate; /* bits per second */
+       unsigned int clock_type; /* internal, external, TX-internal etc. */
+       unsigned short loopback;
+} sync_serial_settings;          /* V.35, V.24, X.21 */
+
+typedef struct { 
+       unsigned int clock_rate; /* bits per second */
+       unsigned int clock_type; /* internal, external, TX-internal etc. */
+       unsigned short loopback;
+       unsigned int slot_map;
+} te1_settings;                  /* T1, E1 */
+
+typedef struct {
+       unsigned short encoding;
+       unsigned short parity;
+} raw_hdlc_proto;
+
+typedef struct {
+       unsigned int t391;
+       unsigned int t392;
+       unsigned int n391;
+       unsigned int n392;
+       unsigned int n393;
+       unsigned short lmi;
+       unsigned short dce; /* 1 for DCE (network side) operation */
+} fr_proto;
+
+typedef struct {
+       unsigned int dlci;
+} fr_proto_pvc;          /* for creating/deleting FR PVCs */
+
+typedef struct {
+       unsigned int dlci;
+       char master[IFNAMSIZ];  /* Name of master FRAD device */
+}fr_proto_pvc_info;            /* for returning PVC information only */
+
+typedef struct {
+    unsigned int interval;
+    unsigned int timeout;
+} cisco_proto;
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
+#endif /* __HDLC_IOCTL_H__ */
diff --git a/include/linux/if.h b/include/linux/if.h
new file mode 100644 (file)
index 0000000..2c3ccc7
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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@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
+
+#include <linux/types.h>               /* for "__kernel_caddr_t" et al */
+#include <linux/socket.h>              /* for "struct sockaddr" et al  */
+               /* for "__user" et al           */
+
+#define        IFNAMSIZ        16
+#define        IFALIASZ        256
+#include <linux/hdlc/ioctl.h>
+
+/* 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 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 */
+};
+
+struct if_settings
+{
+       unsigned int type;      /* Type of physical device or protocol */
+       unsigned int size;      /* Size of the data allocated by the caller */
+       union {
+               /* {atm/eth/dsl}_settings anyone ? */
+               raw_hdlc_proto          *raw_hdlc;
+               cisco_proto             *cisco;
+               fr_proto                *fr;
+               fr_proto_pvc            *fr_pvc;
+               fr_proto_pvc_info       *fr_pvc_info;
+
+               /* interface settings */
+               sync_serial_settings    *sync;
+               te1_settings            *te1;
+       } ifs_ifsu;
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's.  All interface ioctl's must have parameter
+ * definitions which begin with ifr_name.  The
+ * remainder may be interface specific.
+ */
+
+struct ifreq 
+{
+#define IFHWADDRLEN    6
+       union
+       {
+               char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+       } ifr_ifrn;
+       
+       union {
+               struct  sockaddr ifru_addr;
+               struct  sockaddr ifru_dstaddr;
+               struct  sockaddr ifru_broadaddr;
+               struct  sockaddr ifru_netmask;
+               struct  sockaddr ifru_hwaddr;
+               short   ifru_flags;
+               int     ifru_ivalue;
+               int     ifru_mtu;
+               struct  ifmap ifru_map;
+               char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+               char    ifru_newname[IFNAMSIZ];
+               void *  ifru_data;
+               struct  if_settings ifru_settings;
+       } ifr_ifru;
+};
+
+#define ifr_name       ifr_ifrn.ifrn_name      /* interface name       */
+#define ifr_hwaddr     ifr_ifru.ifru_hwaddr    /* MAC address          */
+#define        ifr_addr        ifr_ifru.ifru_addr      /* address              */
+#define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-p lnk */
+#define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address    */
+#define        ifr_netmask     ifr_ifru.ifru_netmask   /* interface net mask   */
+#define        ifr_flags       ifr_ifru.ifru_flags     /* flags                */
+#define        ifr_metric      ifr_ifru.ifru_ivalue    /* metric               */
+#define        ifr_mtu         ifr_ifru.ifru_mtu       /* mtu                  */
+#define ifr_map                ifr_ifru.ifru_map       /* device map           */
+#define ifr_slave      ifr_ifru.ifru_slave     /* slave device         */
+#define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
+#define ifr_ifindex    ifr_ifru.ifru_ivalue    /* interface index      */
+#define ifr_bandwidth  ifr_ifru.ifru_ivalue    /* link bandwidth       */
+#define ifr_qlen       ifr_ifru.ifru_ivalue    /* Queue length         */
+#define ifr_newname    ifr_ifru.ifru_newname   /* New name             */
+#define ifr_settings   ifr_ifru.ifru_settings  /* Device/proto settings*/
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+
+struct ifconf 
+{
+       int     ifc_len;                        /* size of buffer       */
+       union 
+       {
+               char *ifcu_buf;
+               struct ifreq *ifcu_req;
+       } ifc_ifcu;
+};
+#define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address       */
+#define        ifc_req ifc_ifcu.ifcu_req               /* array of structures  */
+
+#endif /* _LINUX_IF_H */
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
new file mode 100644 (file)
index 0000000..befcb3c
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_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_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 */
+};
+
+/* backwards compatibility for userspace */
+#define IFA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
diff --git a/include/linux/if_addrlabel.h b/include/linux/if_addrlabel.h
new file mode 100644 (file)
index 0000000..9fe79c9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * if_addrlabel.h - netlink interface for address labels
+ *
+ * Copyright (C)2007 USAGI/WIDE Project,  All Rights Reserved.
+ *
+ * Authors:
+ *     YOSHIFUJI Hideaki @ USAGI/WIDE <yoshfuji@linux-ipv6.org>
+ */
+
+#ifndef __LINUX_IF_ADDRLABEL_H
+#define __LINUX_IF_ADDRLABEL_H
+
+struct ifaddrlblmsg
+{
+       __u8            ifal_family;            /* Address family */
+       __u8            __ifal_reserved;        /* Reserved */
+       __u8            ifal_prefixlen;         /* Prefix length */
+       __u8            ifal_flags;             /* Flags */
+       __u32           ifal_index;             /* Link index */
+       __u32           ifal_seq;               /* sequence number */
+};
+
+enum
+{
+       IFAL_ADDRESS = 1,
+       IFAL_LABEL = 2,
+       __IFAL_MAX
+};
+
+#define IFAL_MAX       (__IFAL_MAX - 1)
+
+#endif
index 9b3382d..977c4de 100644 (file)
@@ -9,7 +9,7 @@
  *
  * Author:     Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Donald Becker, <becker@super.org>
- *             Alan Cox, <alan@redhat.com>
+ *             Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *             Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *
  *             This program is free software; you can redistribute it and/or
@@ -56,7 +56,7 @@
 #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_ETH       0x6558          /* Ethernet in Ethernet, for EGRE */
+#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_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_EDSA     0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
 
 /*
  *     Non DIX types. Won't clash for 1500 types.
@@ -91,6 +93,7 @@
 #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@cafe.net)       */
 #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          */
 
 /*
  *     This is an Ethernet frame header.
@@ -110,17 +116,5 @@ struct ethhdr {
        __be16          h_proto;                /* packet type ID field */
 } __attribute__((packed));
 
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
-static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
-{
-       return (struct ethhdr *)skb_mac_header(skb);
-}
-
-#ifdef CONFIG_SYSCTL
-extern struct ctl_table ether_table[];
-#endif
-#endif
 
 #endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
new file mode 100644 (file)
index 0000000..c1fd1a8
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/netlink.h>
+
+/* The struct should be in sync with struct net_device_stats */
+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 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;
+};
+
+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_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+/* backwards compatibility for userspace */
+#define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+/* 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;
+};
+
+#endif /* _LINUX_IF_LINK_H */
index 53435b9..aeab2cb 100644 (file)
@@ -2,11 +2,16 @@
 #define _IF_TUNNEL_H_
 
 #include <linux/types.h>
+#include <linux/ip.h>
 
 #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
 #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
 #define SIOCDELTUNNEL   (SIOCDEVPRIVATE + 2)
 #define SIOCCHGTUNNEL   (SIOCDEVPRIVATE + 3)
+#define SIOCGETPRL      (SIOCDEVPRIVATE + 4)
+#define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
+#define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
+#define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
 
 #define GRE_CSUM       __constant_htons(0x8000)
 #define GRE_ROUTING    __constant_htons(0x4000)
@@ -25,8 +30,40 @@ struct ip_tunnel_parm
        __be16                  o_flags;
        __be32                  i_key;
        __be32                  o_key;
-        __be16                  proto_type;   /* Added for EGRE */
        struct iphdr            iph;
 };
 
+/* SIT-mode i_flags */
+#define        SIT_ISATAP      0x0001
+
+struct ip_tunnel_prl {
+       __be32                  addr;
+       __u16                   flags;
+       __u16                   __reserved;
+       __u32                   datalen;
+       __u32                   __reserved2;
+       /* data follows */
+};
+
+/* PRL flags */
+#define        PRL_DEFAULT             0x0001
+
+enum
+{
+       IFLA_GRE_UNSPEC,
+       IFLA_GRE_LINK,
+       IFLA_GRE_IFLAGS,
+       IFLA_GRE_OFLAGS,
+       IFLA_GRE_IKEY,
+       IFLA_GRE_OKEY,
+       IFLA_GRE_LOCAL,
+       IFLA_GRE_REMOTE,
+       IFLA_GRE_TTL,
+       IFLA_GRE_TOS,
+       IFLA_GRE_PMTUDISC,
+       __IFLA_GRE_MAX,
+};
+
+#define IFLA_GRE_MAX   (__IFLA_GRE_MAX - 1)
+
 #endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
new file mode 100644 (file)
index 0000000..2dc4a57
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * VLAN                An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:    Ben Greear <greearb@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,
+};
+
+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_) */
index 85d456d..1ae9303 100644 (file)
@@ -9,10 +9,10 @@
 
 /* Socket identity */
 struct inet_diag_sockid {
-       __u16   idiag_sport;
-       __u16   idiag_dport;
-       __u32   idiag_src[4];
-       __u32   idiag_dst[4];
+       __be16  idiag_sport;
+       __be16  idiag_dport;
+       __be32  idiag_src[4];
+       __be32  idiag_dst[4];
        __u32   idiag_if;
        __u32   idiag_cookie[2];
 #define INET_DIAG_NOCOOKIE (~0U)
@@ -67,7 +67,7 @@ struct inet_diag_hostcond {
        __u8    family;
        __u8    prefix_len;
        int     port;
-       __u32   addr[0];
+       __be32  addr[0];
 };
 
 /* Base info structure. It contains socket identity (addrs/ports/cookie)
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
new file mode 100644 (file)
index 0000000..1e7cc4a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _IP6_TUNNEL_H
+#define _IP6_TUNNEL_H
+
+#define IPV6_TLV_TNL_ENCAP_LIMIT 4
+#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
+
+/* don't add encapsulation limit if one isn't present in inner packet */
+#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
+/* copy the traffic class field from the inner packet */
+#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
+/* copy the flowlabel from the inner packet */
+#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
+/* being used for Mobile IPv6 */
+#define IP6_TNL_F_MIP6_DEV 0x8
+/* copy DSCP from the outer packet */
+#define IP6_TNL_F_RCV_DSCP_COPY 0x10
+
+struct ip6_tnl_parm {
+       char name[IFNAMSIZ];    /* name of tunnel device */
+       int link;               /* ifindex of underlying L2 interface */
+       __u8 proto;             /* tunnel protocol */
+       __u8 encap_limit;       /* encapsulation limit for tunnel */
+       __u8 hop_limit;         /* hop limit for tunnel */
+       __be32 flowinfo;        /* traffic class and flowlabel for tunnel */
+       __u32 flags;            /* tunnel flags */
+       struct in6_addr laddr;  /* local tunnel end-point address */
+       struct in6_addr raddr;  /* remote tunnel end-point address */
+};
+
+#endif
diff --git a/include/linux/ip_mp_alg.h b/include/linux/ip_mp_alg.h
deleted file mode 100644 (file)
index e234e20..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@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/include/linux/neighbour.h b/include/linux/neighbour.h
new file mode 100644 (file)
index 0000000..bd3bbf6
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_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_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/include/linux/netfilter.h b/include/linux/netfilter.h
new file mode 100644 (file)
index 0000000..2eb00b6
--- /dev/null
@@ -0,0 +1,59 @@
+#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)
+
+/* only for userspace compatibility */
+/* 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/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
new file mode 100644 (file)
index 0000000..89eae5c
--- /dev/null
@@ -0,0 +1,173 @@
+#ifndef _X_TABLES_H
+#define _X_TABLES_H
+
+#define XT_FUNCTION_MAXNAMELEN 30
+#define XT_TABLE_MAXNAMELEN 32
+
+struct xt_entry_match
+{
+       union {
+               struct {
+                       u_int16_t match_size;
+
+                       /* Used by userspace */
+                       char name[XT_FUNCTION_MAXNAMELEN-1];
+
+                       u_int8_t revision;
+               } user;
+               struct {
+                       u_int16_t match_size;
+
+                       /* Used inside the kernel */
+                       struct xt_match *match;
+               } kernel;
+
+               /* Total length */
+               u_int16_t match_size;
+       } u;
+
+       unsigned char data[0];
+};
+
+struct xt_entry_target
+{
+       union {
+               struct {
+                       u_int16_t target_size;
+
+                       /* Used by userspace */
+                       char name[XT_FUNCTION_MAXNAMELEN-1];
+
+                       u_int8_t revision;
+               } user;
+               struct {
+                       u_int16_t target_size;
+
+                       /* Used inside the kernel */
+                       struct xt_target *target;
+               } kernel;
+
+               /* Total length */
+               u_int16_t target_size;
+       } u;
+
+       unsigned char data[0];
+};
+
+#define XT_TARGET_INIT(__name, __size)                                        \
+{                                                                             \
+       .target.u.user = {                                                     \
+               .target_size    = XT_ALIGN(__size),                            \
+               .name           = __name,                                      \
+       },                                                                     \
+}
+
+struct xt_standard_target
+{
+       struct xt_entry_target target;
+       int verdict;
+};
+
+/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
+ * kernel supports, if >= revision. */
+struct xt_get_revision
+{
+       char name[XT_FUNCTION_MAXNAMELEN-1];
+
+       u_int8_t revision;
+};
+
+/* CONTINUE verdict for targets */
+#define XT_CONTINUE 0xFFFFFFFF
+
+/* For standard target */
+#define XT_RETURN (-NF_REPEAT - 1)
+
+/* this is a dummy structure to find out the alignment requirement for a struct
+ * containing all the fundamental data types that are used in ipt_entry,
+ * ip6t_entry and arpt_entry.  This sucks, and it is a hack.  It will be my
+ * personal pleasure to remove it -HW
+ */
+struct _xt_align
+{
+       u_int8_t u8;
+       u_int16_t u16;
+       u_int32_t u32;
+       u_int64_t u64;
+};
+
+#define XT_ALIGN(s) (((s) + (__alignof__(struct _xt_align)-1))         \
+                       & ~(__alignof__(struct _xt_align)-1))
+
+/* Standard return verdict, or do jump. */
+#define XT_STANDARD_TARGET ""
+/* Error verdict. */
+#define XT_ERROR_TARGET "ERROR"
+
+#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
+#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
+
+struct xt_counters
+{
+       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
+};
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+struct xt_counters_info
+{
+       /* Which table. */
+       char name[XT_TABLE_MAXNAMELEN];
+
+       unsigned int num_counters;
+
+       /* The counters (actually `number' of these). */
+       struct xt_counters counters[0];
+};
+
+#define XT_INV_PROTO           0x40    /* Invert the sense of PROTO. */
+
+/* fn returns 0 to continue iteration */
+#define XT_MATCH_ITERATE(type, e, fn, args...)                 \
+({                                                             \
+       unsigned int __i;                                       \
+       int __ret = 0;                                          \
+       struct xt_entry_match *__m;                             \
+                                                               \
+       for (__i = sizeof(type);                                \
+            __i < (e)->target_offset;                          \
+            __i += __m->u.match_size) {                        \
+               __m = (void *)e + __i;                          \
+                                                               \
+               __ret = fn(__m , ## args);                      \
+               if (__ret != 0)                                 \
+                       break;                                  \
+       }                                                       \
+       __ret;                                                  \
+})
+
+/* fn returns 0 to continue iteration */
+#define XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
+({                                                             \
+       unsigned int __i, __n;                                  \
+       int __ret = 0;                                          \
+       type *__entry;                                          \
+                                                               \
+       for (__i = 0, __n = 0; __i < (size);                    \
+            __i += __entry->next_offset, __n++) {              \
+               __entry = (void *)(entries) + __i;              \
+               if (__n < n)                                    \
+                       continue;                               \
+                                                               \
+               __ret = fn(__entry , ## args);                  \
+               if (__ret != 0)                                 \
+                       break;                                  \
+       }                                                       \
+       __ret;                                                  \
+})
+
+/* fn returns 0 to continue iteration */
+#define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
+       XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)
+
+
+#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter/xt_tcpudp.h b/include/linux/netfilter/xt_tcpudp.h
new file mode 100644 (file)
index 0000000..78bc65f
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _XT_TCPUDP_H
+#define _XT_TCPUDP_H
+
+/* TCP matching stuff */
+struct xt_tcp
+{
+       u_int16_t spts[2];                      /* Source port range. */
+       u_int16_t dpts[2];                      /* Destination port range. */
+       u_int8_t option;                        /* TCP Option iff non-zero*/
+       u_int8_t flg_mask;                      /* TCP flags mask byte */
+       u_int8_t flg_cmp;                       /* TCP flags compare byte */
+       u_int8_t invflags;                      /* Inverse flags */
+};
+
+/* Values for "inv" field in struct ipt_tcp. */
+#define XT_TCP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
+#define XT_TCP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
+#define XT_TCP_INV_FLAGS       0x04    /* Invert the sense of TCP flags. */
+#define XT_TCP_INV_OPTION      0x08    /* Invert the sense of option test. */
+#define XT_TCP_INV_MASK                0x0F    /* All possible flags. */
+
+/* UDP matching stuff */
+struct xt_udp
+{
+       u_int16_t spts[2];                      /* Source port range. */
+       u_int16_t dpts[2];                      /* Destination port range. */
+       u_int8_t invflags;                      /* Inverse flags */
+};
+
+/* Values for "invflags" field in struct ipt_udp. */
+#define XT_UDP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
+#define XT_UDP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
+#define XT_UDP_INV_MASK        0x03    /* All possible flags. */
+
+
+#endif
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
new file mode 100644 (file)
index 0000000..4d7ba3e
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __LINUX_IP_NETFILTER_H
+#define __LINUX_IP_NETFILTER_H
+
+/* IPv4-specific defines for netfilter. 
+ * (C)1998 Rusty Russell -- This code is GPL.
+ */
+
+#include <linux/netfilter.h>
+
+/* only for userspace compatibility */
+/* IP Cache bits. */
+/* Src IP address. */
+#define NFC_IP_SRC             0x0001
+/* Dest IP address. */
+#define NFC_IP_DST             0x0002
+/* Input device. */
+#define NFC_IP_IF_IN           0x0004
+/* Output device. */
+#define NFC_IP_IF_OUT          0x0008
+/* TOS. */
+#define NFC_IP_TOS             0x0010
+/* Protocol. */
+#define NFC_IP_PROTO           0x0020
+/* IP options. */
+#define NFC_IP_OPTIONS         0x0040
+/* Frag & flags. */
+#define NFC_IP_FRAG            0x0080
+
+/* Per-protocol information: only matters if proto match. */
+/* TCP flags. */
+#define NFC_IP_TCPFLAGS                0x0100
+/* Source port. */
+#define NFC_IP_SRC_PT          0x0200
+/* Dest port. */
+#define NFC_IP_DST_PT          0x0400
+/* Something else about the proto */
+#define NFC_IP_PROTO_UNKNOWN   0x2000
+
+/* IP Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_IP_PRE_ROUTING      0
+/* If the packet is destined for this box. */
+#define NF_IP_LOCAL_IN         1
+/* If the packet is destined for another interface. */
+#define NF_IP_FORWARD          2
+/* Packets coming from a local process. */
+#define NF_IP_LOCAL_OUT                3
+/* Packets about to hit the wire. */
+#define NF_IP_POST_ROUTING     4
+#define NF_IP_NUMHOOKS         5
+
+enum nf_ip_hook_priorities {
+       NF_IP_PRI_FIRST = INT_MIN,
+       NF_IP_PRI_CONNTRACK_DEFRAG = -400,
+       NF_IP_PRI_RAW = -300,
+       NF_IP_PRI_SELINUX_FIRST = -225,
+       NF_IP_PRI_CONNTRACK = -200,
+       NF_IP_PRI_MANGLE = -150,
+       NF_IP_PRI_NAT_DST = -100,
+       NF_IP_PRI_FILTER = 0,
+       NF_IP_PRI_SECURITY = 50,
+       NF_IP_PRI_NAT_SRC = 100,
+       NF_IP_PRI_SELINUX_LAST = 225,
+       NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
+       NF_IP_PRI_LAST = INT_MAX,
+};
+
+/* Arguments for setsockopt SOL_IP: */
+/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */
+/* 2.2 firewalling (+ masq) went from 64 through 76 */
+/* 2.4 firewalling went 64 through 67. */
+#define SO_ORIGINAL_DST 80
+
+
+#endif /*__LINUX_IP_NETFILTER_H*/
index 17d8eff..a9f21c9 100644 (file)
 #ifndef _IPTABLES_H
 #define _IPTABLES_H
 
+#include <linux/types.h>
+
 #include <linux/netfilter_ipv4.h>
 
-#define IPT_FUNCTION_MAXNAMELEN 30
-#define IPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
 
 /* Yes, Virginia, you have to zero the padding. */
 struct ipt_ip {
@@ -38,70 +46,16 @@ struct ipt_ip {
        u_int8_t invflags;
 };
 
-struct ipt_entry_match
-{
-       union {
-               struct {
-                       u_int16_t match_size;
-
-                       /* Used by userspace */
-                       char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-                       u_int8_t revision;
-               } user;
-               struct {
-                       u_int16_t match_size;
-
-                       /* Used inside the kernel */
-                       struct ipt_match *match;
-               } kernel;
-
-               /* Total length */
-               u_int16_t match_size;
-       } u;
-
-       unsigned char data[0];
-};
-
-struct ipt_entry_target
-{
-       union {
-               struct {
-                       u_int16_t target_size;
-
-                       /* Used by userspace */
-                       char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-                       u_int8_t revision;
-               } user;
-               struct {
-                       u_int16_t target_size;
-
-                       /* Used inside the kernel */
-                       struct ipt_target *target;
-               } kernel;
-
-               /* Total length */
-               u_int16_t target_size;
-       } u;
-
-       unsigned char data[0];
-};
-
-struct ipt_standard_target
-{
-       struct ipt_entry_target target;
-       int verdict;
-};
+#define ipt_entry_match xt_entry_match
+#define ipt_entry_target xt_entry_target
+#define ipt_standard_target xt_standard_target
 
-struct ipt_counters
-{
-       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
-};
+#define ipt_counters xt_counters
 
 /* Values for "flag" field in struct ipt_ip (general ip structure). */
 #define IPT_F_FRAG             0x01    /* Set if rule is a fragment rule */
-#define IPT_F_MASK             0x01    /* All possible flag bits mask. */
+#define IPT_F_GOTO             0x02    /* Set if jump is a goto */
+#define IPT_F_MASK             0x03    /* All possible flag bits mask. */
 
 /* Values for "inv" field in struct ipt_ip. */
 #define IPT_INV_VIA_IN         0x01    /* Invert the sense of IN IFACE. */
@@ -110,7 +64,7 @@ struct ipt_counters
 #define IPT_INV_SRCIP          0x08    /* Invert the sense of SRC IP. */
 #define IPT_INV_DSTIP          0x10    /* Invert the sense of DST OP. */
 #define IPT_INV_FRAG           0x20    /* Invert the sense of FRAG. */
-#define IPT_INV_PROTO          0x40    /* Invert the sense of PROTO. */
+#define IPT_INV_PROTO          XT_INV_PROTO
 #define IPT_INV_MASK           0x7F    /* All possible flag bits mask. */
 
 /* This structure defines each of the firewall rules.  Consists of 3
@@ -132,7 +86,7 @@ struct ipt_entry
        unsigned int comefrom;
 
        /* Packet and byte counters. */
-       struct ipt_counters counters;
+       struct xt_counters counters;
 
        /* The matches (if any), then the target. */
        unsigned char elems[0];
@@ -141,8 +95,11 @@ struct ipt_entry
 /*
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use a raw
- * socket for this. Instead we check rights in the calls. */
-#define IPT_BASE_CTL           64      /* base for firewall socket options */
+ * socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in.h before adding new number here.
+ */
+#define IPT_BASE_CTL           64
 
 #define IPT_SO_SET_REPLACE     (IPT_BASE_CTL)
 #define IPT_SO_SET_ADD_COUNTERS        (IPT_BASE_CTL + 1)
@@ -154,42 +111,22 @@ struct ipt_entry
 #define IPT_SO_GET_REVISION_TARGET     (IPT_BASE_CTL + 3)
 #define IPT_SO_GET_MAX                 IPT_SO_GET_REVISION_TARGET
 
-/* CONTINUE verdict for targets */
-#define IPT_CONTINUE 0xFFFFFFFF
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
 
-/* For standard target */
-#define IPT_RETURN (-NF_MAX_VERDICT - 1)
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
 
-/* TCP matching stuff */
-struct ipt_tcp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t option;                        /* TCP Option iff non-zero*/
-       u_int8_t flg_mask;                      /* TCP flags mask byte */
-       u_int8_t flg_cmp;                       /* TCP flags compare byte */
-       u_int8_t invflags;                      /* Inverse flags */
-};
+#define IPT_TCP_INV_SRCPT      XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT      XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS      XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION     XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK       XT_TCP_INV_MASK
 
-/* Values for "inv" field in struct ipt_tcp. */
-#define IPT_TCP_INV_SRCPT      0x01    /* Invert the sense of source ports. */
-#define IPT_TCP_INV_DSTPT      0x02    /* Invert the sense of dest ports. */
-#define IPT_TCP_INV_FLAGS      0x04    /* Invert the sense of TCP flags. */
-#define IPT_TCP_INV_OPTION     0x08    /* Invert the sense of option test. */
-#define IPT_TCP_INV_MASK       0x0F    /* All possible flags. */
-
-/* UDP matching stuff */
-struct ipt_udp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t invflags;                      /* Inverse flags */
-};
-
-/* Values for "invflags" field in struct ipt_udp. */
-#define IPT_UDP_INV_SRCPT      0x01    /* Invert the sense of source ports. */
-#define IPT_UDP_INV_DSTPT      0x02    /* Invert the sense of dest ports. */
-#define IPT_UDP_INV_MASK       0x03    /* All possible flags. */
+#define IPT_UDP_INV_SRCPT      XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT      XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK       XT_UDP_INV_MASK
 
 /* ICMP matching stuff */
 struct ipt_icmp
@@ -213,10 +150,10 @@ struct ipt_getinfo
        unsigned int valid_hooks;
 
        /* Hook entry points: one per netfilter hook. */
-       unsigned int hook_entry[NF_IP_NUMHOOKS];
+       unsigned int hook_entry[NF_INET_NUMHOOKS];
 
        /* Underflow points. */
-       unsigned int underflow[NF_IP_NUMHOOKS];
+       unsigned int underflow[NF_INET_NUMHOOKS];
 
        /* Number of entries */
        unsigned int num_entries;
@@ -242,33 +179,23 @@ struct ipt_replace
        unsigned int size;
 
        /* Hook entry points. */
-       unsigned int hook_entry[NF_IP_NUMHOOKS];
+       unsigned int hook_entry[NF_INET_NUMHOOKS];
 
        /* Underflow points. */
-       unsigned int underflow[NF_IP_NUMHOOKS];
+       unsigned int underflow[NF_INET_NUMHOOKS];
 
        /* Information about old entries: */
        /* Number of counters (must be equal to current number of entries). */
        unsigned int num_counters;
-
        /* The old entries' counters. */
-       struct ipt_counters  *counters;
+       struct xt_counters *counters;
 
        /* The entries (hang off end: not really an array). */
        struct ipt_entry entries[0];
 };
 
 /* The argument to IPT_SO_ADD_COUNTERS. */
-struct ipt_counters_info
-{
-       /* Which table. */
-       char name[IPT_TABLE_MAXNAMELEN];
-
-       unsigned int num_counters;
-
-       /* The counters (actually `number' of these). */
-       struct ipt_counters counters[0];
-};
+#define ipt_counters_info xt_counters_info
 
 /* The argument to IPT_SO_GET_ENTRIES. */
 struct ipt_get_entries
@@ -283,19 +210,10 @@ struct ipt_get_entries
        struct ipt_entry entrytable[0];
 };
 
-/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct ipt_get_revision
-{
-       char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define IPT_STANDARD_TARGET ""
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define IPT_ERROR_TARGET "ERROR"
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct ipt_entry_target *
@@ -305,40 +223,12 @@ ipt_get_target(struct ipt_entry *e)
 }
 
 /* fn returns 0 to continue iteration */
-#define IPT_MATCH_ITERATE(e, fn, args...)      \
-({                                             \
-       unsigned int __i;                       \
-       int __ret = 0;                          \
-       struct ipt_entry_match *__match;        \
-                                               \
-       for (__i = sizeof(struct ipt_entry);    \
-            __i < (e)->target_offset;          \
-            __i += __match->u.match_size) {    \
-               __match = (void *)(e) + __i;    \
-                                               \
-               __ret = fn(__match , ## args);  \
-               if (__ret != 0)                 \
-                       break;                  \
-       }                                       \
-       __ret;                                  \
-})
+#define IPT_MATCH_ITERATE(e, fn, args...) \
+       XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
 
 /* fn returns 0 to continue iteration */
-#define IPT_ENTRY_ITERATE(entries, size, fn, args...)          \
-({                                                             \
-       unsigned int __i;                                       \
-       int __ret = 0;                                          \
-       struct ipt_entry *__entry;                              \
-                                                               \
-       for (__i = 0; __i < (size); __i += __entry->next_offset) { \
-               __entry = (void *)(entries) + __i;              \
-                                                               \
-               __ret = fn(__entry , ## args);                  \
-               if (__ret != 0)                                 \
-                       break;                                  \
-       }                                                       \
-       __ret;                                                  \
-})
+#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
+       XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
 
 /*
  *     Main firewall chains definitions and global var's definitions.
index 24a38ae..5593f05 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/types.h>
 
 #define NETLINK_ROUTE          0       /* Routing/device hook                          */
-#define NETLINK_W1             1       /* 1-wire subsystem                             */
+#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_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 MAX_LINKS 32           
 
+struct net;
+
 struct sockaddr_nl
 {
        sa_family_t     nl_family;      /* AF_NETLINK   */
        unsigned short  nl_pad;         /* zero         */
-       __u32           nl_pid;         /* process pid  */
+       __u32           nl_pid;         /* port ID      */
                __u32           nl_groups;      /* multicast groups mask */
 };
 
@@ -38,7 +43,7 @@ struct nlmsghdr
        __u16           nlmsg_type;     /* Message content */
        __u16           nlmsg_flags;    /* Additional flags */
        __u32           nlmsg_seq;      /* Sequence number */
-       __u32           nlmsg_pid;      /* Sending process PID */
+       __u32           nlmsg_pid;      /* Sending process port ID */
 };
 
 /* Flags values */
@@ -126,6 +131,20 @@ struct nlattr
        __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)))
index bd2c5a2..7cf7824 100644 (file)
@@ -201,8 +201,8 @@ enum
 
 struct tc_u32_key
 {
-       __u32           mask;
-       __u32           val;
+       __be32          mask;
+       __be32          val;
        int             off;
        int             offmask;
 };
@@ -213,12 +213,12 @@ struct tc_u32_sel
        unsigned char           offshift;
        unsigned char           nkeys;
 
-       __u16                   offmask;
+       __be16                  offmask;
        __u16                   off;
        short                   offoff;
 
        short                   hoff;
-       __u32                   hmask;
+       __be32                  hmask;
        struct tc_u32_key       keys[0];
 };
 
@@ -305,6 +305,7 @@ enum
        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
 };
 
@@ -327,6 +328,58 @@ enum
 
 #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_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
@@ -402,16 +455,14 @@ enum
  *   1..32767          Reserved for ematches inside kernel tree
  *   32768..65535      Free to use, not reliable
  */
-enum
-{
-       TCF_EM_CONTAINER,
-       TCF_EM_CMP,
-       TCF_EM_NBYTE,
-       TCF_EM_U32,
-       TCF_EM_META,
-       TCF_EM_TEXT,
-       __TCF_EM_MAX
-};
+#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
 {
index d10f353..5d921fa 100644 (file)
@@ -77,12 +77,34 @@ struct tc_ratespec
 {
        unsigned char   cell_log;
        unsigned char   __reserved;
-       unsigned short  feature;
-       short           addend;
+       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
@@ -101,6 +123,13 @@ struct tc_prio_qopt
        __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
@@ -139,6 +168,11 @@ struct tc_sfq_qopt
        unsigned        flows;          /* Maximal number of flows  */
 };
 
+struct tc_sfq_xstats
+{
+       __s32           allot;
+};
+
 /*
  *  NOTE: limit, divisor and flows are hardwired to code at the moment.
  *
index 7504618..f43140a 100644 (file)
@@ -2,6 +2,9 @@
 #define __LINUX_RTNETLINK_H
 
 #include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
 
 /****
  *             Routing/neighbour discovery messages.
@@ -80,8 +83,6 @@ enum {
 
        RTM_NEWPREFIX   = 52,
 #define RTM_NEWPREFIX  RTM_NEWPREFIX
-       RTM_GETPREFIX   = 54,
-#define RTM_GETPREFIX  RTM_GETPREFIX
 
        RTM_GETMULTICAST = 58,
 #define RTM_GETMULTICAST RTM_GETMULTICAST
@@ -96,6 +97,16 @@ enum {
        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_NEWADDRLABEL RTM_NEWADDRLABEL
+       RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
        __RTM_MAX,
 #define RTM_MAX                (((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -235,13 +246,12 @@ 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
+       RT_TABLE_MAX=0xFFFFFFFF
 };
-#define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
-
 
 
 /* Routing message attributes */
@@ -258,11 +268,12 @@ enum rtattr_type_t
        RTA_PREFSRC,
        RTA_METRICS,
        RTA_MULTIPATH,
-       RTA_PROTOINFO,
+       RTA_PROTOINFO, /* no longer used */
        RTA_FLOW,
        RTA_CACHEINFO,
-       RTA_SESSION,
-       RTA_MP_ALGO,
+       RTA_SESSION, /* no longer used */
+       RTA_MP_ALGO, /* no longer used */
+       RTA_TABLE,
        __RTA_MAX
 };
 
@@ -351,6 +362,8 @@ enum
 #define RTAX_INITCWND RTAX_INITCWND
        RTAX_FEATURES,
 #define RTAX_FEATURES RTAX_FEATURES
+       RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
        __RTAX_MAX
 };
 
@@ -383,226 +396,6 @@ struct rta_session
        } u;
 };
 
-
-/*********************************************************
- *             Interface address.
- ****/
-
-struct ifaddrmsg
-{
-       unsigned char   ifa_family;
-       unsigned char   ifa_prefixlen;  /* The prefix length            */
-       unsigned char   ifa_flags;      /* Flags                        */
-       unsigned char   ifa_scope;      /* See above                    */
-       int             ifa_index;      /* Link index                   */
-};
-
-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_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 */
-};
-
-
-#define IFA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
-#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
-
-/*
-   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.
- */
-
-/**************************************************************
- *             Neighbour discovery.
- ****/
-
-struct ndmsg
-{
-       unsigned char   ndm_family;
-       unsigned char   ndm_pad1;
-       unsigned short  ndm_pad2;
-       int             ndm_ifindex;    /* Link index                   */
-       __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)
-
-#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
-#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
-
-/*
- *     Neighbor Cache Entry Flags
- */
-
-#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
-
-
-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)
-
-#define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \
-                    NLMSG_ALIGN(sizeof(struct ndtmsg))))
-#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
-
-
 /****
  *             General form of address family dependent message.
  ****/
@@ -663,136 +456,6 @@ struct prefix_cacheinfo
        __u32   valid_time;
 };
 
-/* The struct should be in sync with struct net_device_stats */
-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 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;
-};
-
-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_MAX
-};
-
-
-#define IFLA_MAX (__IFLA_MAX - 1)
-
-#define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
-#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
-
-/* 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_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;
-};
 
 /*****************************************************************
  *             Traffic control messages.
@@ -819,6 +482,7 @@ enum
        TCA_RATE,
        TCA_FCNT,
        TCA_STATS2,
+       TCA_STAB,
        __TCA_MAX
 };
 
@@ -827,6 +491,32 @@ enum
 #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)
+
 /* RTnetlink multicast groups - backwards compatibility for userspace */
 #define RTMGRP_LINK            1
 #define RTMGRP_NOTIFY          2
@@ -836,6 +526,7 @@ enum
 #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
@@ -865,7 +556,8 @@ enum rtnetlink_groups {
 #define        RTNLGRP_IPV4_MROUTE     RTNLGRP_IPV4_MROUTE
        RTNLGRP_IPV4_ROUTE,
 #define RTNLGRP_IPV4_ROUTE     RTNLGRP_IPV4_ROUTE
-       RTNLGRP_NOP1,
+       RTNLGRP_IPV4_RULE,
+#define RTNLGRP_IPV4_RULE      RTNLGRP_IPV4_RULE
        RTNLGRP_IPV6_IFADDR,
 #define RTNLGRP_IPV6_IFADDR    RTNLGRP_IPV6_IFADDR
        RTNLGRP_IPV6_MROUTE,
@@ -879,10 +571,19 @@ enum rtnetlink_groups {
        RTNLGRP_NOP2,
        RTNLGRP_DECnet_ROUTE,
 #define RTNLGRP_DECnet_ROUTE   RTNLGRP_DECnet_ROUTE
-       RTNLGRP_NOP3,
+       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)
index dc979c0..0a2418d 100644 (file)
@@ -1 +1,304 @@
-#include <sys/socket.h>
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE  128     /* Implementation specific max size */
+#define _K_SS_ALIGNSIZE        (__alignof__ (struct sockaddr *))
+                               /* Implementation specific desired alignment */
+
+struct __kernel_sockaddr_storage {
+       unsigned short  ss_family;              /* address family */
+       /* Following field(s) are implementation specific */
+       char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+                               /* space to achieve desired size, */
+                               /* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_K_SS_ALIGNSIZE)));  /* force desired alignment */
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#include <asm/socket.h>                        /* arch-dependent defines       */
+#include <linux/sockios.h>             /* the SIOCxxx I/O controls     */
+#include <linux/uio.h>                 /* iovec support                */
+#include <linux/types.h>               /* pid_t                        */
+               /*              */
+
+#ifdef CONFIG_PROC_FS
+struct seq_file;
+extern void socket_seq_show(struct seq_file *seq);
+#endif
+
+typedef unsigned short sa_family_t;
+
+/*
+ *     1003.1g requires sa_family_t and that sa_data is char.
+ */
+struct sockaddr {
+       sa_family_t     sa_family;      /* address family, AF_xxx       */
+       char            sa_data[14];    /* 14 bytes of protocol address */
+};
+
+struct linger {
+       int             l_onoff;        /* Linger active                */
+       int             l_linger;       /* How long to linger for       */
+};
+
+#define sockaddr_storage __kernel_sockaddr_storage
+
+/*
+ *     As we do 4.4BSD message passing we use a 4.4BSD message passing
+ *     system, not 4.3. Thus msg_accrights(len) are now missing. They
+ *     belong in an obscure libc emulation or the bin.
+ */
+struct msghdr {
+       void    *       msg_name;       /* Socket name                  */
+       int             msg_namelen;    /* Length of name               */
+       struct iovec *  msg_iov;        /* Data blocks                  */
+       __kernel_size_t msg_iovlen;     /* Number of blocks             */
+       void    *       msg_control;    /* Per protocol magic (eg BSD file descriptor passing) */
+       __kernel_size_t msg_controllen; /* Length of cmsg list */
+       unsigned        msg_flags;
+};
+
+/*
+ *     POSIX 1003.1g - ancillary data object information
+ *     Ancillary data consits of a sequence of pairs of
+ *     (cmsghdr, cmsg_data[])
+ */
+
+struct cmsghdr {
+       __kernel_size_t cmsg_len;       /* data byte count, including hdr */
+        int            cmsg_level;     /* originating protocol */
+        int            cmsg_type;      /* protocol-specific type */
+};
+
+/*
+ *     Ancilliary data object information MACROS
+ *     Table 5-14 of POSIX 1003.1g
+ */
+
+#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+
+#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
+
+#define CMSG_DATA(cmsg)        ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
+                                 (struct cmsghdr *)(ctl) : \
+                                 (struct cmsghdr *)NULL)
+#define CMSG_FIRSTHDR(msg)     __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+                            (cmsg)->cmsg_len <= (unsigned long) \
+                            ((mhdr)->msg_controllen - \
+                             ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
+
+/*
+ *     This mess will go away with glibc
+ */
+#if    defined(__GNUC__) 
+#define __KINLINE static __inline__
+#elif defined(__cplusplus)
+#define __KINLINE static inline
+#else
+#define __KINLINE static
+#endif
+
+
+/*
+ *     Get the next cmsg header
+ *
+ *     PLEASE, do not touch this function. If you think, that it is
+ *     incorrect, grep kernel sources and think about consequences
+ *     before trying to improve it.
+ *
+ *     Now it always returns valid, not truncated ancillary object
+ *     HEADER. But caller still MUST check, that cmsg->cmsg_len is
+ *     inside range, given by msg->msg_controllen before using
+ *     ancillary object DATA.                          --ANK (980731)
+ */
+__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+                                              struct cmsghdr *__cmsg)
+{
+       struct cmsghdr * __ptr;
+
+       __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) +  CMSG_ALIGN(__cmsg->cmsg_len));
+       if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+               return (struct cmsghdr *)0;
+
+       return __ptr;
+}
+
+__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+       return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+/* "Socket"-level control message types: */
+
+#define        SCM_RIGHTS      0x01            /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02           /* rw: struct ucred             */
+#define SCM_SECURITY   0x03            /* rw: security label           */
+
+struct ucred {
+       __u32   pid;
+       __u32   uid;
+       __u32   gid;
+};
+
+/* Supported address families. */
+#define AF_UNSPEC      0
+#define AF_UNIX                1       /* Unix domain sockets          */
+#define AF_LOCAL       1       /* POSIX name for AF_UNIX       */
+#define AF_INET                2       /* Internet IP Protocol         */
+#define AF_AX25                3       /* Amateur Radio AX.25          */
+#define AF_IPX         4       /* Novell IPX                   */
+#define AF_APPLETALK   5       /* AppleTalk DDP                */
+#define AF_NETROM      6       /* Amateur Radio NET/ROM        */
+#define AF_BRIDGE      7       /* Multiprotocol bridge         */
+#define AF_ATMPVC      8       /* ATM PVCs                     */
+#define AF_X25         9       /* Reserved for X.25 project    */
+#define AF_INET6       10      /* IP version 6                 */
+#define AF_ROSE                11      /* Amateur Radio X.25 PLP       */
+#define AF_DECnet      12      /* Reserved for DECnet project  */
+#define AF_NETBEUI     13      /* Reserved for 802.2LLC project*/
+#define AF_SECURITY    14      /* Security callback pseudo AF */
+#define AF_KEY         15      /* PF_KEY key management API */
+#define AF_NETLINK     16
+#define AF_ROUTE       AF_NETLINK /* Alias to emulate 4.4BSD */
+#define AF_PACKET      17      /* Packet family                */
+#define AF_ASH         18      /* Ash                          */
+#define AF_ECONET      19      /* Acorn Econet                 */
+#define AF_ATMSVC      20      /* ATM SVCs                     */
+#define AF_SNA         22      /* Linux SNA Project (nutters!) */
+#define AF_IRDA                23      /* IRDA sockets                 */
+#define AF_PPPOX       24      /* PPPoX sockets                */
+#define AF_WANPIPE     25      /* Wanpipe API Sockets */
+#define AF_LLC         26      /* Linux LLC                    */
+#define AF_CAN         29      /* Controller Area Network      */
+#define AF_TIPC                30      /* TIPC sockets                 */
+#define AF_BLUETOOTH   31      /* Bluetooth sockets            */
+#define AF_IUCV                32      /* IUCV sockets                 */
+#define AF_RXRPC       33      /* RxRPC sockets                */
+#define AF_ISDN                34      /* mISDN sockets                */
+#define AF_PHONET      35      /* Phonet sockets               */
+#define AF_MAX         36      /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC      AF_UNSPEC
+#define PF_UNIX                AF_UNIX
+#define PF_LOCAL       AF_LOCAL
+#define PF_INET                AF_INET
+#define PF_AX25                AF_AX25
+#define PF_IPX         AF_IPX
+#define PF_APPLETALK   AF_APPLETALK
+#define        PF_NETROM       AF_NETROM
+#define PF_BRIDGE      AF_BRIDGE
+#define PF_ATMPVC      AF_ATMPVC
+#define PF_X25         AF_X25
+#define PF_INET6       AF_INET6
+#define PF_ROSE                AF_ROSE
+#define PF_DECnet      AF_DECnet
+#define PF_NETBEUI     AF_NETBEUI
+#define PF_SECURITY    AF_SECURITY
+#define PF_KEY         AF_KEY
+#define PF_NETLINK     AF_NETLINK
+#define PF_ROUTE       AF_ROUTE
+#define PF_PACKET      AF_PACKET
+#define PF_ASH         AF_ASH
+#define PF_ECONET      AF_ECONET
+#define PF_ATMSVC      AF_ATMSVC
+#define PF_SNA         AF_SNA
+#define PF_IRDA                AF_IRDA
+#define PF_PPPOX       AF_PPPOX
+#define PF_WANPIPE     AF_WANPIPE
+#define PF_LLC         AF_LLC
+#define PF_CAN         AF_CAN
+#define PF_TIPC                AF_TIPC
+#define PF_BLUETOOTH   AF_BLUETOOTH
+#define PF_IUCV                AF_IUCV
+#define PF_RXRPC       AF_RXRPC
+#define PF_ISDN                AF_ISDN
+#define PF_PHONET      AF_PHONET
+#define PF_MAX         AF_MAX
+
+/* Maximum queue length specifiable by listen.  */
+#define SOMAXCONN      128
+
+/* Flags we can use with send/ and recv. 
+   Added those for 1003.1g not all are supported yet
+ */
+#define MSG_OOB                1
+#define MSG_PEEK       2
+#define MSG_DONTROUTE  4
+#define MSG_TRYHARD     4       /* Synonym for MSG_DONTROUTE for DECnet */
+#define MSG_CTRUNC     8
+#define MSG_PROBE      0x10    /* Do not send. Only probe path f.e. for MTU */
+#define MSG_TRUNC      0x20
+#define MSG_DONTWAIT   0x40    /* Nonblocking io                */
+#define MSG_EOR         0x80   /* End of record */
+#define MSG_WAITALL    0x100   /* Wait for a full request */
+#define MSG_FIN         0x200
+#define MSG_SYN                0x400
+#define MSG_CONFIRM    0x800   /* Confirm path validity */
+#define MSG_RST                0x1000
+#define MSG_ERRQUEUE   0x2000  /* Fetch message from error queue */
+#define MSG_NOSIGNAL   0x4000  /* Do not generate SIGPIPE */
+#define MSG_MORE       0x8000  /* Sender will send more */
+
+#define MSG_EOF         MSG_FIN
+
+#define MSG_CMSG_CLOEXEC 0x40000000    /* Set close_on_exit for file
+                                          descriptor received through
+                                          SCM_RIGHTS */
+#if defined(CONFIG_COMPAT)
+#define MSG_CMSG_COMPAT        0x80000000      /* This message needs 32 bit fixups */
+#else
+#define MSG_CMSG_COMPAT        0               /* We never have 32 bit fixups */
+#endif
+
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_IP         0
+/* #define SOL_ICMP    1       No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
+#define SOL_TCP                6
+#define SOL_UDP                17
+#define SOL_IPV6       41
+#define SOL_ICMPV6     58
+#define SOL_SCTP       132
+#define SOL_UDPLITE    136     /* UDP-Lite (RFC 3828) */
+#define SOL_RAW                255
+#define SOL_IPX                256
+#define SOL_AX25       257
+#define SOL_ATALK      258
+#define SOL_NETROM     259
+#define SOL_ROSE       260
+#define SOL_DECNET     261
+#define        SOL_X25         262
+#define SOL_PACKET     263
+#define SOL_ATM                264     /* ATM layer (cell level) */
+#define SOL_AAL                265     /* ATM Adaption Layer (packet level) */
+#define SOL_IRDA        266
+#define SOL_NETBEUI    267
+#define SOL_LLC                268
+#define SOL_DCCP       269
+#define SOL_NETLINK    270
+#define SOL_TIPC       271
+#define SOL_RXRPC      272
+#define SOL_PPPOL2TP   273
+#define SOL_BLUETOOTH  274
+#define SOL_PNPIPE     275
+
+/* IPX options */
+#define IPX_TYPE       1
+
+#endif /* not kernel and not glibc */
+#endif /* _LINUX_SOCKET_H */
diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h
deleted file mode 100644 (file)
index 964f473..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __LINUX_TC_DEF_H
-#define __LINUX_TC_DEF_H
-
-#include <linux/pkt_cls.h>
-
-struct tc_defact
-{
-       tc_gen;
-};
-                                                                                
-enum
-{
-       TCA_DEF_UNSPEC,
-       TCA_DEF_TM,
-       TCA_DEF_PARMS,
-       TCA_DEF_DATA,
-       __TCA_DEF_MAX
-};
-#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
-
-#endif
diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h
new file mode 100644 (file)
index 0000000..e7cf31e
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __LINUX_TC_NAT_H
+#define __LINUX_TC_NAT_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#define TCA_ACT_NAT 9
+
+enum
+{
+       TCA_NAT_UNSPEC,
+       TCA_NAT_PARMS,
+       TCA_NAT_TM,
+       __TCA_NAT_MAX
+};
+#define TCA_NAT_MAX (__TCA_NAT_MAX - 1)
+
+#define TCA_NAT_FLAG_EGRESS 1
+
+struct tc_nat
+{
+       tc_gen;
+       __be32 old_addr;
+       __be32 new_addr;
+       __be32 mask;
+       __u32 flags;
+};
+
+#endif
diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h
new file mode 100644 (file)
index 0000000..a14e461
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#ifndef __LINUX_TC_SKBEDIT_H
+#define __LINUX_TC_SKBEDIT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_SKBEDIT 11
+
+#define SKBEDIT_F_PRIORITY             0x1
+#define SKBEDIT_F_QUEUE_MAPPING                0x2
+
+struct tc_skbedit {
+       tc_gen;
+};
+
+enum {
+       TCA_SKBEDIT_UNSPEC,
+       TCA_SKBEDIT_TM,
+       TCA_SKBEDIT_PARMS,
+       TCA_SKBEDIT_PRIORITY,
+       TCA_SKBEDIT_QUEUE_MAPPING,
+       __TCA_SKBEDIT_MAX
+};
+#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
+
+#endif
index e21937c..c50d2ba 100644 (file)
@@ -81,6 +81,7 @@ enum
        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_MAX
 };
 #define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
deleted file mode 100644 (file)
index b4d74eb..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.
- *
- *             Definitions for the TCP protocol.
- *
- * Version:    @(#)tcp.h       1.0.2   04/28/93
- *
- * Author:     Fred N. van Kempen, <waltje@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_TCP_H
-#define _LINUX_TCP_H
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-struct tcphdr {
-       __u16   source;
-       __u16   dest;
-       __u32   seq;
-       __u32   ack_seq;
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u16   res1:4,
-               doff:4,
-               fin:1,
-               syn:1,
-               rst:1,
-               psh:1,
-               ack:1,
-               urg:1,
-               ece:1,
-               cwr:1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u16   doff:4,
-               res1:4,
-               cwr:1,
-               ece:1,
-               urg:1,
-               ack:1,
-               psh:1,
-               rst:1,
-               syn:1,
-               fin:1;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif 
-       __u16   window;
-       __u16   check;
-       __u16   urg_ptr;
-};
-
-/*
- *     The union cast uses a gcc extension to avoid aliasing problems
- *  (union is compatible to any of its members)
- *  This means this part of the code is -fstrict-aliasing safe now.
- */
-union tcp_word_hdr { 
-       struct tcphdr hdr;
-       __u32             words[5];
-}; 
-
-#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) 
-
-enum { 
-       TCP_FLAG_CWR = __constant_htonl(0x00800000), 
-       TCP_FLAG_ECE = __constant_htonl(0x00400000), 
-       TCP_FLAG_URG = __constant_htonl(0x00200000), 
-       TCP_FLAG_ACK = __constant_htonl(0x00100000), 
-       TCP_FLAG_PSH = __constant_htonl(0x00080000), 
-       TCP_FLAG_RST = __constant_htonl(0x00040000), 
-       TCP_FLAG_SYN = __constant_htonl(0x00020000), 
-       TCP_FLAG_FIN = __constant_htonl(0x00010000),
-       TCP_RESERVED_BITS = __constant_htonl(0x0F000000),
-       TCP_DATA_OFFSET = __constant_htonl(0xF0000000)
-}; 
-
-/* TCP socket options */
-#define TCP_NODELAY            1       /* Turn off Nagle's algorithm. */
-#define TCP_MAXSEG             2       /* Limit MSS */
-#define TCP_CORK               3       /* Never send partially complete segments */
-#define TCP_KEEPIDLE           4       /* Start keeplives after this period */
-#define TCP_KEEPINTVL          5       /* Interval between keepalives */
-#define TCP_KEEPCNT            6       /* Number of keepalives before death */
-#define TCP_SYNCNT             7       /* Number of SYN retransmits */
-#define TCP_LINGER2            8       /* Life time of orphaned FIN-WAIT-2 state */
-#define TCP_DEFER_ACCEPT       9       /* Wake up listener only when data arrive */
-#define TCP_WINDOW_CLAMP       10      /* Bound advertised window */
-#define TCP_INFO               11      /* Information about this connection. */
-#define TCP_QUICKACK           12      /* Block/reenable quick acks */
-#define TCP_CONGESTION         13      /* Congestion control algorithm */
-
-#define TCPI_OPT_TIMESTAMPS    1
-#define TCPI_OPT_SACK          2
-#define TCPI_OPT_WSCALE                4
-#define TCPI_OPT_ECN           8
-
-enum tcp_ca_state
-{
-       TCP_CA_Open = 0,
-#define TCPF_CA_Open   (1<<TCP_CA_Open)
-       TCP_CA_Disorder = 1,
-#define TCPF_CA_Disorder (1<<TCP_CA_Disorder)
-       TCP_CA_CWR = 2,
-#define TCPF_CA_CWR    (1<<TCP_CA_CWR)
-       TCP_CA_Recovery = 3,
-#define TCPF_CA_Recovery (1<<TCP_CA_Recovery)
-       TCP_CA_Loss = 4
-#define TCPF_CA_Loss   (1<<TCP_CA_Loss)
-};
-
-struct tcp_info
-{
-       __u8    tcpi_state;
-       __u8    tcpi_ca_state;
-       __u8    tcpi_retransmits;
-       __u8    tcpi_probes;
-       __u8    tcpi_backoff;
-       __u8    tcpi_options;
-       __u8    tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
-
-       __u32   tcpi_rto;
-       __u32   tcpi_ato;
-       __u32   tcpi_snd_mss;
-       __u32   tcpi_rcv_mss;
-
-       __u32   tcpi_unacked;
-       __u32   tcpi_sacked;
-       __u32   tcpi_lost;
-       __u32   tcpi_retrans;
-       __u32   tcpi_fackets;
-
-       /* Times. */
-       __u32   tcpi_last_data_sent;
-       __u32   tcpi_last_ack_sent;     /* Not remembered, sorry. */
-       __u32   tcpi_last_data_recv;
-       __u32   tcpi_last_ack_recv;
-
-       /* Metrics. */
-       __u32   tcpi_pmtu;
-       __u32   tcpi_rcv_ssthresh;
-       __u32   tcpi_rtt;
-       __u32   tcpi_rttvar;
-       __u32   tcpi_snd_ssthresh;
-       __u32   tcpi_snd_cwnd;
-       __u32   tcpi_advmss;
-       __u32   tcpi_reordering;
-
-       __u32   tcpi_rcv_rtt;
-       __u32   tcpi_rcv_space;
-
-       __u32   tcpi_total_retrans;
-};
-
-
-#endif /* _LINUX_TCP_H */
diff --git a/include/linux/types.h b/include/linux/types.h
new file mode 100644 (file)
index 0000000..d17027a
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+
+typedef __u32 __kernel_dev_t;
+
+typedef __kernel_fd_set                fd_set;
+typedef __kernel_dev_t         dev_t;
+typedef __kernel_ino_t         ino_t;
+typedef __kernel_mode_t                mode_t;
+typedef __kernel_nlink_t       nlink_t;
+typedef __kernel_off_t         off_t;
+typedef __kernel_pid_t         pid_t;
+typedef __kernel_daddr_t       daddr_t;
+typedef __kernel_key_t         key_t;
+typedef __kernel_suseconds_t   suseconds_t;
+typedef __kernel_timer_t       timer_t;
+typedef __kernel_clockid_t     clockid_t;
+typedef __kernel_mqd_t         mqd_t;
+
+typedef __kernel_uid_t         uid_t;
+typedef __kernel_gid_t         gid_t;
+
+#if defined(__GNUC__)
+typedef __kernel_loff_t                loff_t;
+#endif
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t                size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t       ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t     ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t                time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t       clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t       caddr_t;
+#endif
+
+/* bsd */
+typedef unsigned char          u_char;
+typedef unsigned short         u_short;
+typedef unsigned int           u_int;
+typedef unsigned long          u_long;
+
+/* sysv */
+typedef unsigned char          unchar;
+typedef unsigned short         ushort;
+typedef unsigned int           uint;
+typedef unsigned long          ulong;
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef                __u8            u_int8_t;
+typedef                __s8            int8_t;
+typedef                __u16           u_int16_t;
+typedef                __s16           int16_t;
+typedef                __u32           u_int32_t;
+typedef                __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+typedef                __u8            uint8_t;
+typedef                __u16           uint16_t;
+typedef                __u32           uint32_t;
+
+#if defined(__GNUC__)
+typedef                __u64           uint64_t;
+typedef                __u64           u_int64_t;
+typedef                __s64           int64_t;
+#endif
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 __u64 __attribute__((aligned(8)))
+#define aligned_be64 __be64 __attribute__((aligned(8)))
+#define aligned_le64 __le64 __attribute__((aligned(8)))
+
+/**
+ * The type used for indexing onto a disc or disc partition.
+ *
+ * Linux always considers sectors to be 512 bytes long independently
+ * of the devices real block size.
+ */
+#ifdef CONFIG_LBD
+typedef u64 sector_t;
+#else
+typedef unsigned long sector_t;
+#endif
+
+/*
+ * The type of the inode's block count.
+ */
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#else
+typedef unsigned long blkcnt_t;
+#endif
+
+/*
+ * The type of an index into the pagecache.  Use a #define so asm/types.h
+ * can override it.
+ */
+#ifndef pgoff_t
+#define pgoff_t unsigned long
+#endif
+
+#endif /* __KERNEL_STRICT_NAMES */
+
+/*
+ * Below are truly Linux-specific types that should never collide with
+ * any application/library that wants linux/types.h.
+ */
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+#if defined(__GNUC__)
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+#endif
+typedef __u16 __bitwise __sum16;
+typedef __u32 __bitwise __wsum;
+
+
+#endif /* _LINUX_TYPES_H */
diff --git a/include/linux/veth.h b/include/linux/veth.h
new file mode 100644 (file)
index 0000000..3354c1e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __NET_VETH_H_
+#define __NET_VETH_H_
+
+enum {
+       VETH_INFO_UNSPEC,
+       VETH_INFO_PEER,
+
+       __VETH_INFO_MAX
+#define VETH_INFO_MAX  (__VETH_INFO_MAX - 1)
+};
+
+#endif
index f2bbf4b..da2f1fe 100644 (file)
@@ -12,8 +12,8 @@
  */
 typedef union
 {
-       __u32           a4;
-       __u32           a6[4];
+       __be32          a4;
+       __be32          a6[4];
 } xfrm_address_t;
 
 /* Ident of a specific xfrm_state. It is used on input to lookup
@@ -23,7 +23,7 @@ typedef union
 struct xfrm_id
 {
        xfrm_address_t  daddr;
-       __u32           spi;
+       __be32          spi;
        __u8            proto;
 };
 
@@ -49,10 +49,10 @@ struct xfrm_selector
 {
        xfrm_address_t  daddr;
        xfrm_address_t  saddr;
-       __u16   dport;
-       __u16   dport_mask;
-       __u16   sport;
-       __u16   sport_mask;
+       __be16  dport;
+       __be16  dport_mask;
+       __be16  sport;
+       __be16  sport_mask;
        __u16   family;
        __u8    prefixlen_d;
        __u8    prefixlen_s;
@@ -91,9 +91,16 @@ struct xfrm_replay_state
 };
 
 struct xfrm_algo {
-       char    alg_name[64];
-       int     alg_key_len;    /* in bits */
-       char    alg_key[0];
+       char            alg_name[64];
+       unsigned int    alg_key_len;    /* in bits */
+       char            alg_key[0];
+};
+
+struct xfrm_algo_aead {
+       char            alg_name[64];
+       unsigned int    alg_key_len;    /* in bits */
+       unsigned int    alg_icv_len;    /* in bits */
+       char            alg_key[0];
 };
 
 struct xfrm_stats {
@@ -102,11 +109,20 @@ struct xfrm_stats {
        __u32   integrity_failed;
 };
 
+enum
+{
+       XFRM_POLICY_TYPE_MAIN   = 0,
+       XFRM_POLICY_TYPE_SUB    = 1,
+       XFRM_POLICY_TYPE_MAX    = 2,
+       XFRM_POLICY_TYPE_ANY    = 255
+};
+
 enum
 {
        XFRM_POLICY_IN  = 0,
        XFRM_POLICY_OUT = 1,
        XFRM_POLICY_FWD = 2,
+       XFRM_POLICY_MASK = 3,
        XFRM_POLICY_MAX = 3
 };
 
@@ -118,6 +134,13 @@ enum
        XFRM_SHARE_UNIQUE       /* Use once */
 };
 
+#define XFRM_MODE_TRANSPORT 0
+#define XFRM_MODE_TUNNEL 1
+#define XFRM_MODE_ROUTEOPTIMIZATION 2
+#define XFRM_MODE_IN_TRIGGER 3
+#define XFRM_MODE_BEET 4
+#define XFRM_MODE_MAX 5
+
 /* Netlink configuration messages.  */
 enum {
        XFRM_MSG_BASE = 0x10,
@@ -156,6 +179,26 @@ enum {
        XFRM_MSG_FLUSHPOLICY,
 #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
 
+       XFRM_MSG_NEWAE,
+#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE
+       XFRM_MSG_GETAE,
+#define XFRM_MSG_GETAE XFRM_MSG_GETAE
+
+       XFRM_MSG_REPORT,
+#define XFRM_MSG_REPORT XFRM_MSG_REPORT
+
+       XFRM_MSG_MIGRATE,
+#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE
+
+       XFRM_MSG_NEWSADINFO,
+#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO
+       XFRM_MSG_GETSADINFO,
+#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO
+
+       XFRM_MSG_NEWSPDINFO,
+#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
+       XFRM_MSG_GETSPDINFO,
+#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
        __XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -189,11 +232,32 @@ struct xfrm_user_tmpl {
 
 struct xfrm_encap_tmpl {
        __u16           encap_type;
-       __u16           encap_sport;
-       __u16           encap_dport;
+       __be16          encap_sport;
+       __be16          encap_dport;
        xfrm_address_t  encap_oa;
 };
 
+/* AEVENT flags  */
+enum xfrm_ae_ftype_t {
+       XFRM_AE_UNSPEC,
+       XFRM_AE_RTHR=1, /* replay threshold*/
+       XFRM_AE_RVAL=2, /* replay value */
+       XFRM_AE_LVAL=4, /* lifetime value */
+       XFRM_AE_ETHR=8, /* expiry timer threshold */
+       XFRM_AE_CR=16, /* Event cause is replay update */
+       XFRM_AE_CE=32, /* Event cause is timer expiry */
+       XFRM_AE_CU=64, /* Event cause is policy update */
+       __XFRM_AE_MAX
+
+#define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
+};
+
+struct xfrm_userpolicy_type {
+       __u8            type;
+       __u16           reserved1;
+       __u8            reserved2;
+};
+
 /* Netlink message attributes.  */
 enum xfrm_attr_type_t {
        XFRMA_UNSPEC,
@@ -205,11 +269,59 @@ enum xfrm_attr_type_t {
        XFRMA_SA,
        XFRMA_POLICY,
        XFRMA_SEC_CTX,          /* struct xfrm_sec_ctx */
+       XFRMA_LTIME_VAL,
+       XFRMA_REPLAY_VAL,
+       XFRMA_REPLAY_THRESH,
+       XFRMA_ETIMER_THRESH,
+       XFRMA_SRCADDR,          /* xfrm_address_t */
+       XFRMA_COADDR,           /* xfrm_address_t */
+       XFRMA_LASTUSED,
+       XFRMA_POLICY_TYPE,      /* struct xfrm_userpolicy_type */
+       XFRMA_MIGRATE,
+       XFRMA_ALG_AEAD,         /* struct xfrm_algo_aead */
+       XFRMA_KMADDRESS,        /* struct xfrm_user_kmaddress */
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
 };
 
+enum xfrm_sadattr_type_t {
+       XFRMA_SAD_UNSPEC,
+       XFRMA_SAD_CNT,
+       XFRMA_SAD_HINFO,
+       __XFRMA_SAD_MAX
+
+#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1)
+};
+
+struct xfrmu_sadhinfo {
+       __u32 sadhcnt; /* current hash bkts */
+       __u32 sadhmcnt; /* max allowed hash bkts */
+};
+
+enum xfrm_spdattr_type_t {
+       XFRMA_SPD_UNSPEC,
+       XFRMA_SPD_INFO,
+       XFRMA_SPD_HINFO,
+       __XFRMA_SPD_MAX
+
+#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
+};
+
+struct xfrmu_spdinfo {
+       __u32 incnt;
+       __u32 outcnt;
+       __u32 fwdcnt;
+       __u32 inscnt;
+       __u32 outscnt;
+       __u32 fwdscnt;
+};
+
+struct xfrmu_spdhinfo {
+       __u32 spdhcnt;
+       __u32 spdhmcnt;
+};
+
 struct xfrm_usersa_info {
        struct xfrm_selector            sel;
        struct xfrm_id                  id;
@@ -220,21 +332,31 @@ struct xfrm_usersa_info {
        __u32                           seq;
        __u32                           reqid;
        __u16                           family;
-       __u8                            mode; /* 0=transport,1=tunnel */
+       __u8                            mode;           /* XFRM_MODE_xxx */
        __u8                            replay_window;
        __u8                            flags;
 #define XFRM_STATE_NOECN       1
 #define XFRM_STATE_DECAP_DSCP  2
 #define XFRM_STATE_NOPMTUDISC  4
+#define XFRM_STATE_WILDRECV    8
+#define XFRM_STATE_ICMP                16
+#define XFRM_STATE_AF_UNSPEC   32
 };
 
 struct xfrm_usersa_id {
        xfrm_address_t                  daddr;
-       __u32                           spi;
+       __be32                          spi;
        __u16                           family;
        __u8                            proto;
 };
 
+struct xfrm_aevent_id {
+       struct xfrm_usersa_id           sa_id;
+       xfrm_address_t                  saddr;
+       __u32                           flags;
+       __u32                           reqid;
+};
+
 struct xfrm_userspi_info {
        struct xfrm_usersa_info         info;
        __u32                           min;
@@ -253,6 +375,8 @@ struct xfrm_userpolicy_info {
 #define XFRM_POLICY_BLOCK      1
        __u8                            flags;
 #define XFRM_POLICY_LOCALOK    1       /* Allow user to override global policy */
+       /* Automatically expand selector to include matching ICMP payloads. */
+#define XFRM_POLICY_ICMP       2
        __u8                            share;
 };
 
@@ -287,11 +411,39 @@ struct xfrm_usersa_flush {
        __u8                            proto;
 };
 
+struct xfrm_user_report {
+       __u8                            proto;
+       struct xfrm_selector            sel;
+};
+
+/* Used by MIGRATE to pass addresses IKE should use to perform
+ * SA negotiation with the peer */
+struct xfrm_user_kmaddress {
+       xfrm_address_t                  local;
+       xfrm_address_t                  remote;
+       __u32                           reserved;
+       __u16                           family;
+};
+
+struct xfrm_user_migrate {
+       xfrm_address_t                  old_daddr;
+       xfrm_address_t                  old_saddr;
+       xfrm_address_t                  new_daddr;
+       xfrm_address_t                  new_saddr;
+       __u8                            proto;
+       __u8                            mode;
+       __u16                           reserved;
+       __u32                           reqid;
+       __u16                           old_family;
+       __u16                           new_family;
+};
+
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE                1
 #define XFRMGRP_EXPIRE         2
 #define XFRMGRP_SA             4
 #define XFRMGRP_POLICY         8
+#define XFRMGRP_REPORT         0x20
 
 enum xfrm_nlgroups {
        XFRMNLGRP_NONE,
@@ -304,6 +456,12 @@ enum xfrm_nlgroups {
 #define XFRMNLGRP_SA           XFRMNLGRP_SA
        XFRMNLGRP_POLICY,
 #define XFRMNLGRP_POLICY       XFRMNLGRP_POLICY
+       XFRMNLGRP_AEVENTS,
+#define XFRMNLGRP_AEVENTS      XFRMNLGRP_AEVENTS
+       XFRMNLGRP_REPORT,
+#define XFRMNLGRP_REPORT       XFRMNLGRP_REPORT
+       XFRMNLGRP_MIGRATE,
+#define XFRMNLGRP_MIGRATE      XFRMNLGRP_MIGRATE
        __XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX  (__XFRMNLGRP_MAX - 1)
index d085813..c4d5c6d 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __LL_MAP_H__
 #define __LL_MAP_H__ 1
 
-extern int ll_remember_index(const struct sockaddr_nl *who, 
+extern int ll_remember_index(const struct sockaddr_nl *who,
                             struct nlmsghdr *n, void *arg);
 extern int ll_init_map(struct rtnl_handle *rth);
 extern unsigned ll_name_to_index(const char *name);
diff --git a/include/net/tcp_states.h b/include/net/tcp_states.h
deleted file mode 100644 (file)
index b0b6459..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- *
- *             Definitions for the TCP protocol sk_state field.
- *
- *             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_TCP_STATES_H
-#define _LINUX_TCP_STATES_H
-
-enum {
-       TCP_ESTABLISHED = 1,
-       TCP_SYN_SENT,
-       TCP_SYN_RECV,
-       TCP_FIN_WAIT1,
-       TCP_FIN_WAIT2,
-       TCP_TIME_WAIT,
-       TCP_CLOSE,
-       TCP_CLOSE_WAIT,
-       TCP_LAST_ACK,
-       TCP_LISTEN,
-       TCP_CLOSING,    /* Now a valid state */
-
-       TCP_MAX_STATES  /* Leave at the end! */
-};
-
-#define TCP_STATE_MASK 0xF
-
-#define TCP_ACTION_FIN (1 << 7)
-
-enum {
-       TCPF_ESTABLISHED = (1 << 1),
-       TCPF_SYN_SENT    = (1 << 2),
-       TCPF_SYN_RECV    = (1 << 3),
-       TCPF_FIN_WAIT1   = (1 << 4),
-       TCPF_FIN_WAIT2   = (1 << 5),
-       TCPF_TIME_WAIT   = (1 << 6),
-       TCPF_CLOSE       = (1 << 7),
-       TCPF_CLOSE_WAIT  = (1 << 8),
-       TCPF_LAST_ACK    = (1 << 9),
-       TCPF_LISTEN      = (1 << 10),
-       TCPF_CLOSING     = (1 << 11) 
-};
-
-#endif /* _LINUX_TCP_STATES_H */
diff --git a/include/netinet/tcp.h b/include/netinet/tcp.h
new file mode 100644 (file)
index 0000000..282b29c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp.h       8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H 1
+
+#include <features.h>
+
+/*
+ * User-settable options (used with setsockopt).
+ */
+#define        TCP_NODELAY      1      /* Don't delay send to coalesce packets  */
+#define        TCP_MAXSEG       2      /* Set maximum segment size  */
+#define TCP_CORK        3      /* Control sending of partial frames  */
+#define TCP_KEEPIDLE    4      /* Start keeplives after this period */
+#define TCP_KEEPINTVL   5      /* Interval between keepalives */
+#define TCP_KEEPCNT     6      /* Number of keepalives before death */
+#define TCP_SYNCNT      7      /* Number of SYN retransmits */
+#define TCP_LINGER2     8      /* Life time of orphaned FIN-WAIT-2 state */
+#define TCP_DEFER_ACCEPT 9     /* Wake up listener only when data arrive */
+#define TCP_WINDOW_CLAMP 10    /* Bound advertised window */
+#define TCP_INFO        11     /* Information about this connection. */
+#define        TCP_QUICKACK     12     /* Bock/reenable quick ACKs.  */
+#define TCP_CONGESTION  13     /* Congestion control algorithm.  */
+
+#ifdef __USE_MISC
+# include <sys/types.h>
+
+# ifdef __FAVOR_BSD
+typedef        u_int32_t tcp_seq;
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+struct tcphdr
+  {
+    u_int16_t th_sport;                /* source port */
+    u_int16_t th_dport;                /* destination port */
+    tcp_seq th_seq;            /* sequence number */
+    tcp_seq th_ack;            /* acknowledgement number */
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int8_t th_x2:4;          /* (unused) */
+    u_int8_t th_off:4;         /* data offset */
+#  endif
+#  if __BYTE_ORDER == __BIG_ENDIAN
+    u_int8_t th_off:4;         /* data offset */
+    u_int8_t th_x2:4;          /* (unused) */
+#  endif
+    u_int8_t th_flags;
+#  define TH_FIN       0x01
+#  define TH_SYN       0x02
+#  define TH_RST       0x04
+#  define TH_PUSH      0x08
+#  define TH_ACK       0x10
+#  define TH_URG       0x20
+    u_int16_t th_win;          /* window */
+    u_int16_t th_sum;          /* checksum */
+    u_int16_t th_urp;          /* urgent pointer */
+};
+
+# else /* !__FAVOR_BSD */
+struct tcphdr
+  {
+    u_int16_t source;
+    u_int16_t dest;
+    u_int32_t seq;
+    u_int32_t ack_seq;
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int16_t res1:4;
+    u_int16_t doff:4;
+    u_int16_t fin:1;
+    u_int16_t syn:1;
+    u_int16_t rst:1;
+    u_int16_t psh:1;
+    u_int16_t ack:1;
+    u_int16_t urg:1;
+    u_int16_t res2:2;
+#  elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int16_t doff:4;
+    u_int16_t res1:4;
+    u_int16_t res2:2;
+    u_int16_t urg:1;
+    u_int16_t ack:1;
+    u_int16_t psh:1;
+    u_int16_t rst:1;
+    u_int16_t syn:1;
+    u_int16_t fin:1;
+#  else
+#   error "Adjust your <bits/endian.h> defines"
+#  endif
+    u_int16_t window;
+    u_int16_t check;
+    u_int16_t urg_ptr;
+};
+# endif /* __FAVOR_BSD */
+
+enum
+{
+  TCP_ESTABLISHED = 1,
+  TCP_SYN_SENT,
+  TCP_SYN_RECV,
+  TCP_FIN_WAIT1,
+  TCP_FIN_WAIT2,
+  TCP_TIME_WAIT,
+  TCP_CLOSE,
+  TCP_CLOSE_WAIT,
+  TCP_LAST_ACK,
+  TCP_LISTEN,
+  TCP_CLOSING   /* now a valid state */
+};
+
+# define TCPOPT_EOL            0
+# define TCPOPT_NOP            1
+# define TCPOPT_MAXSEG         2
+# define TCPOLEN_MAXSEG                4
+# define TCPOPT_WINDOW         3
+# define TCPOLEN_WINDOW                3
+# define TCPOPT_SACK_PERMITTED 4               /* Experimental */
+# define TCPOLEN_SACK_PERMITTED        2
+# define TCPOPT_SACK           5               /* Experimental */
+# define TCPOPT_TIMESTAMP      8
+# define TCPOLEN_TIMESTAMP     10
+# define TCPOLEN_TSTAMP_APPA   (TCPOLEN_TIMESTAMP+2) /* appendix A */
+
+# define TCPOPT_TSTAMP_HDR     \
+    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ */
+# define TCP_MSS       512
+
+# define TCP_MAXWIN    65535   /* largest value for (unscaled) window */
+
+# define TCP_MAX_WINSHIFT      14      /* maximum window shift */
+
+# define SOL_TCP               6       /* TCP level */
+
+
+# define TCPI_OPT_TIMESTAMPS   1
+# define TCPI_OPT_SACK         2
+# define TCPI_OPT_WSCALE       4
+# define TCPI_OPT_ECN          8
+
+/* Values for tcpi_state.  */
+enum tcp_ca_state
+{
+  TCP_CA_Open = 0,
+  TCP_CA_Disorder = 1,
+  TCP_CA_CWR = 2,
+  TCP_CA_Recovery = 3,
+  TCP_CA_Loss = 4
+};
+
+struct tcp_info
+{
+  u_int8_t     tcpi_state;
+  u_int8_t     tcpi_ca_state;
+  u_int8_t     tcpi_retransmits;
+  u_int8_t     tcpi_probes;
+  u_int8_t     tcpi_backoff;
+  u_int8_t     tcpi_options;
+  u_int8_t     tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+
+  u_int32_t    tcpi_rto;
+  u_int32_t    tcpi_ato;
+  u_int32_t    tcpi_snd_mss;
+  u_int32_t    tcpi_rcv_mss;
+
+  u_int32_t    tcpi_unacked;
+  u_int32_t    tcpi_sacked;
+  u_int32_t    tcpi_lost;
+  u_int32_t    tcpi_retrans;
+  u_int32_t    tcpi_fackets;
+
+  /* Times. */
+  u_int32_t    tcpi_last_data_sent;
+  u_int32_t    tcpi_last_ack_sent;     /* Not remembered, sorry.  */
+  u_int32_t    tcpi_last_data_recv;
+  u_int32_t    tcpi_last_ack_recv;
+
+  /* Metrics. */
+  u_int32_t    tcpi_pmtu;
+  u_int32_t    tcpi_rcv_ssthresh;
+  u_int32_t    tcpi_rtt;
+  u_int32_t    tcpi_rttvar;
+  u_int32_t    tcpi_snd_ssthresh;
+  u_int32_t    tcpi_snd_cwnd;
+  u_int32_t    tcpi_advmss;
+  u_int32_t    tcpi_reordering;
+  u_int32_t    tcpi_rcv_rtt;
+  u_int32_t    tcpi_rcv_space;
+  u_int32_t    tcpi_total_retrans;
+
+};
+
+#endif /* Misc.  */
+
+#endif /* netinet/tcp.h */
index 2d9ef10..07a10e0 100644 (file)
@@ -5,7 +5,7 @@
 
 char* rtnl_rtprot_n2a(int id, char *buf, int len);
 char* rtnl_rtscope_n2a(int id, char *buf, int len);
-char* rtnl_rttable_n2a(int id, char *buf, int len);
+char* rtnl_rttable_n2a(__u32 id, char *buf, int len);
 char* rtnl_rtrealm_n2a(int id, char *buf, int len);
 char* rtnl_dsfield_n2a(int id, char *buf, int len);
 int rtnl_rtprot_a2n(__u32 *id, char *arg);
index 0f1d1f6..f7ef939 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <asm/types.h>
 #include <resolv.h>
+#include <stdlib.h>
 
 #include "libnetlink.h"
 #include "ll_map.h"
@@ -45,7 +46,7 @@ typedef struct
        __u8 bytelen;
        __s16 bitlen;
        __u32 flags;
-       __u32 data[4];
+       __u32 data[8];
 } inet_prefix;
 
 #define PREFIXLEN_SPECIFIED 1
@@ -55,7 +56,7 @@ typedef struct
 #define AF_DECnet 12
 #endif
 
-struct dn_naddr 
+struct dn_naddr
 {
         unsigned short          a_len;
         unsigned char a_addr[DN_MAXADDL];
@@ -73,9 +74,11 @@ extern int get_addr_1(inet_prefix *dst, const char *arg, int family);
 extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
 extern int get_addr(inet_prefix *dst, const char *arg, int family);
 extern int get_prefix(inet_prefix *dst, char *arg, int family);
+extern int mask2bits(__u32 netmask);
 
 extern int get_integer(int *val, const char *arg, int base);
 extern int get_unsigned(unsigned *val, const char *arg, int base);
+extern int get_jiffies(unsigned *val, const char *arg, int base, int *raw);
 #define get_byte get_u8
 #define get_ushort get_u16
 #define get_short get_s16
@@ -89,9 +92,9 @@ extern int get_s8(__s8 *val, const char *arg, int base);
 extern char* hexstring_n2a(const __u8 *str, int len, char *buf, int blen);
 extern __u8* hexstring_a2n(const char *str, __u8 *buf, int blen);
 
-extern const char *format_host(int af, int len, const void *addr, 
+extern const char *format_host(int af, int len, const void *addr,
                               char *buf, int buflen);
-extern const char *rt_addr_n2a(int af, int len, const void *addr, 
+extern const char *rt_addr_n2a(int af, int len, const void *addr,
                               char *buf, int buflen);
 
 void missarg(const char *) __attribute__((noreturn));
@@ -127,12 +130,25 @@ static __inline__ int get_user_hz(void)
        return __iproute2_user_hz_internal;
 }
 
+static inline __u32 nl_mgrp(__u32 group)
+{
+       if (group > 31 ) {
+               fprintf(stderr, "Use setsockopt for this group %d\n", group);
+               exit(-1);
+       }
+       return group ? (1 << (group - 1)) : 0;
+}
+
+
 int print_timestamp(FILE *fp);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
 extern int cmdlineno;
-extern size_t getcmdline(char **line, size_t *len, FILE *in);
+extern ssize_t getcmdline(char **line, size_t *len, FILE *in);
 extern int makeargs(char *line, char *argv[], int maxargs);
 
+struct iplink_req;
+int iplink_parse(int argc, char **argv, struct iplink_req *req,
+               char **name, char **type, char **link, char **dev);
 #endif /* __UTILS_H__ */
diff --git a/ip.8 b/ip.8
deleted file mode 100644 (file)
index 50e4419..0000000
--- a/ip.8
+++ /dev/null
@@ -1,1809 +0,0 @@
-.TH IP 8 "17 January 2002" "iproute2" "Linux"
-.SH NAME
-ip \- show / manipulate routing, devices, policy routing and tunnels
-.SH SYNOPSIS
-
-.ad l
-.in +8
-.ti -8
-.B ip
-.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
-.BR help " }"
-.sp
-
-.ti -8
-.IR OBJECT " := { "
-.BR link " | " addr " | " route " | " rule " | " neigh " | " tunnel " | "\
-maddr " | "  mroute " | " monitor " }"
-.sp
-
-.ti -8
-.IR OPTIONS " := { " 
-\fB\-V\fR[\fIersion\fR] |
-\fB\-s\fR[\fItatistics\fR] |
-\fB\-r\fR[\fIesolve\fR] |
-\fB\-f\fR[\fIamily\fR] {
-.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
-\fB\-o\fR[\fIneline\fR] }
-
-.ti -8
-.BI "ip link set " DEVICE
-.RB "{ " up " | " down " | " arp " { " on " | " off " } |"
-.br
-.BR promisc " { " on " | " off " } |"
-.br
-.BR allmulti " { " on " | " off " } |"
-.br
-.BR dynamic " { " on " | " off " } |"
-.br
-.BR multicast " { " on " | " off " } |"
-.br
-.B  txqueuelen
-.IR PACKETS " |"
-.br
-.B  name
-.IR NEWNAME " |"
-.br
-.B  address
-.IR LLADDR " |"
-.B  broadcast 
-.IR LLADDR " |"
-.br
-.B  mtu
-.IR MTU " }"
-
-.ti -8
-.B ip link show
-.RI "[ " DEVICE " ]"
-
-.ti -8
-.BR "ip addr" " { " add " | " del " } " 
-.IB IFADDR " dev " STRING
-
-.ti -8
-.BR "ip addr" " { " show " | " flush " } [ " dev
-.IR STRING " ] [ "
-.B  scope
-.IR SCOPE-ID " ] [ "
-.B  to 
-.IR PREFIX " ] [ " FLAG-LIST " ] [ "
-.B  label
-.IR PATTERN " ]"
-
-.ti -8
-.IR IFADDR " := " PREFIX " | " ADDR
-.B  peer
-.IR PREFIX " [ "
-.B  broadcast
-.IR ADDR " ] [ "
-.B  anycast
-.IR ADDR " ] [ "
-.B  label
-.IR STRING " ] [ "
-.B  scope
-.IR SCOPE-ID " ]"
-
-.ti -8
-.IR SCOPE-ID " := "
-.RB "[ " host " | " link " | " global " | "
-.IR NUMBER " ]"
-
-.ti -8
-.IR FLAG-LIST " := [ "  FLAG-LIST " ] " FLAG
-
-.ti -8
-.IR FLAG " := "
-.RB "[ " permanent " | " dynamic " | " secondary " | " primary " | "\
-tentative " | " deprecated " ]"
-
-.ti -8
-.BR "ip route" " { "
-.BR list " | " flush " } "
-.I  SELECTOR
-
-.ti -8
-.B  ip route get 
-.IR ADDRESS " [ "
-.BI from " ADDRESS " iif " STRING"
-.RB " ] [ " oif 
-.IR STRING " ] [ "
-.B  tos
-.IR TOS " ]"
-
-.ti -8
-.BR "ip route" " { " add " | " del " | " change " | " append " | "\
-replace " | " monitor " } "
-.I  ROUTE
-
-.ti -8
-.IR SELECTOR " := "
-.RB "[ " root
-.IR PREFIX " ] [ "
-.B  match
-.IR PREFIX " ] [ "
-.B  exact
-.IR PREFIX " ] [ "
-.B  table
-.IR TABLE_ID " ] [ "
-.B  proto
-.IR RTPROTO " ] [ "
-.B  type
-.IR TYPE " ] [ "
-.B  scope
-.IR SCOPE " ]"
-
-.ti -8
-.IR ROUTE " := " NODE_SPEC " [ " INFO_SPEC " ]"
-
-.ti -8
-.IR NODE_SPEC " := [ " TYPE " ] " PREFIX " ["
-.B  tos
-.IR TOS " ] [ "
-.B  table
-.IR TABLE_ID " ] [ "
-.B  proto
-.IR RTPROTO " ] [ "
-.B  scope
-.IR SCOPE " ] [ "
-.B  metric
-.IR METRIC " ]"
-
-.ti -8
-.IR INFO_SPEC " := " "NH OPTIONS FLAGS" " ["
-.B  nexthop
-.IR NH " ] ..."
-
-.ti -8
-.IR NH " := [ "
-.B  via
-.IR ADDRESS " ] [ "
-.B  dev
-.IR STRING " ] [ "
-.B  weight
-.IR NUMBER " ] " NHFLAGS
-
-.ti -8
-.IR OPTIONS " := " FLAGS " [ "
-.B  mtu
-.IR NUMBER " ] [ "
-.B  advmss
-.IR NUMBER " ] [ "
-.B  rtt
-.IR NUMBER " ] [ "
-.B  rttvar
-.IR NUMBER " ] [ "
-.B  window
-.IR NUMBER " ] [ "
-.B  cwnd
-.IR NUMBER " ] [ "
-.B  ssthresh
-.IR REALM " ] [ "
-.B  realms
-.IR REALM " ]"
-
-.ti -8
-.IR TYPE " := [ "
-.BR unicast " | " local " | " broadcast " | " multicast " | "\
-throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
-
-.ti -8
-.IR TABLE_ID " := [ "
-.BR local "| " main " | " default " | " all " |"
-.IR NUMBER " ]"
-
-.ti -8
-.IR SCOPE " := [ "
-.BR host " | " link " | " global " |"
-.IR NUMBER " ]"
-
-.ti -8
-.IR FLAGS " := [ "
-.BR equalize " ]"
-
-.ti -8
-.IR NHFLAGS " := [ "
-.BR onlink " | " pervasive " ]"
-
-.ti -8
-.IR RTPROTO " := [ "
-.BR kernel " | " boot " | " static " |"
-.IR NUMBER " ]"
-
-.ti -8
-.B  ip rule
-.RB " [ " list " | " add " | " del " ]"
-.I  SELECTOR ACTION
-
-.ti -8
-.IR SELECTOR " := [ "
-.B  from
-.IR PREFIX " ] [ "
-.B  to
-.IR PREFIX " ] [ "
-.B  tos
-.IR TOS " ] [ "
-.B  fwmark
-.IR FWMARK " ] [ "
-.B  dev
-.IR STRING " ] [ "
-.B  pref
-.IR NUMBER " ]"
-
-.ti -8
-.IR ACTION " := [ "
-.B  table
-.IR TABLE_ID " ] [ "
-.B  nat
-.IR ADDRESS " ] [ "
-.BR prohibit " | " reject " | " unreachable " ] [ " realms
-.RI "[" SRCREALM "/]" DSTREALM " ]"
-
-.ti -8
-.IR TABLE_ID " := [ "
-.BR local " | " main " | " default " |"
-.IR NUMBER " ]"
-
-.ti -8
-.BR "ip neigh" " { " add " | " del " | " change " | " replace " } { "
-.IR ADDR " [ "
-.B  lladdr
-.IR LLADDR " ] [ "
-.BR nud " { " permanent " | " noarp " | " stale " | " reachable " } ] | " proxy
-.IR ADDR " } [ "
-.B  dev
-.IR DEV " ]"
-
-.ti -8
-.BR "ip neigh" " { " show " | " flush " } [ " to
-.IR PREFIX " ] [ "
-.B  dev
-.IR DEV " ] [ "
-.B  nud
-.IR STATE " ]"
-
-.ti -8
-.BR "ip tunnel" " { " add " | " change " | " del " | " show " }"
-.RI "[ " NAME " ]"
-.br
-.RB "[ " mode " { " ipip " | " gre " | " sit " } ]"
-.br
-.RB "[ " remote
-.IR ADDR " ] [ "
-.B  local
-.IR ADDR " ]"
-.br
-.RB "[ [" i "|" o "]" seq " ] [ [" i "|" o "]" key
-.IR KEY " ] [ "
-.RB "[" i "|" o "]" csum " ] ]"
-.br
-.RB "[ " ttl
-.IR TTL " ] [ "
-.B  tos
-.IR TOS " ] [ "
-.RB "[" no "]" pmtudisc " ]"
-.br
-.RB "[ " dev
-.IR PHYS_DEV " ]"
-
-.ti -8
-.IR ADDR " := { " IP_ADDRESS " |"
-.BR any " }"
-
-.ti -8
-.IR TOS " := { " NUMBER " |"
-.BR inherit " }"
-
-.ti -8
-.IR TTL " := { " 1 ".." 255 " | "
-.BR inherit " }"
-
-.ti -8
-.IR KEY " := { " DOTTED_QUAD " | " NUMBER " }"
-
-.ti -8
-.BR "ip maddr" " [ " add " | " del " ]"
-.IB MULTIADDR " dev " STRING
-
-.ti -8
-.BR "ip maddr show" " [ " dev
-.IR STRING " ]"
-
-.ti -8
-.BR "ip mroute show" " ["
-.IR PREFIX " ] [ "
-.B  from
-.IR PREFIX " ] [ "
-.B  iif
-.IR DEVICE " ]"
-
-.ti -8
-.BR "ip monitor" " [ " all " |"
-.IR LISTofOBJECTS " ]"
-.in -8
-.ad b
-
-.SH OPTIONS
-
-.TP
-.BR "\-V" , " -Version"
-print the version of the
-.B ip
-utility and exit.
-
-.TP
-.BR "\-s" , " \-stats", " \-statistics"
-output more information.  If the option
-appears twice or more, the amount of information increases.
-As a rule, the information is statistics or some time values.
-
-.TP
-.BR "\-f" , " \-family"
-followed by protocol family identifier:
-.BR "inet" , " inet6"
-or
-.B link
-,enforce the protocol family to use.  If the option is not present,
-the protocol family is guessed from other arguments.  If the rest 
-of the command line does not give enough information to guess the
-family,
-.B ip
-falls back to the default one, usually
-.B inet
-or
-.BR "any" .
-.B link
-is a special family identifier meaning that no networking protocol
-is involved.
-
-.TP
-.B \-4
-shortcut for
-.BR "-family inet" .
-
-.TP
-.B \-6
-shortcut for
-.BR "\-family inet6" .
-
-.TP
-.B \-0
-shortcut for
-.BR "\-family link" .
-
-.TP
-.BR "\-o" , " \-oneline"
-output each record on a single line, replacing line feeds
-with the
-.B '\'
-character. This is convenient when you want to count records 
-with
-.BR wc (1)
- or to
-.BR grep (1)
-the output.
-
-.TP
-.BR "\-r" , " \-resolve"
-use the system's name resolver to print DNS names instead of
-host addresses.
-
-.SH IP - COMMAND SYNTAX
-
-.SS
-.I OBJECT
-
-.TP
-.B link
-- network device.
-
-.TP
-.B address
-- protocol (IP or IPv6) address on a device.
-.TP
-.B neighbour
-- ARP or NDISC cache entry.
-
-.TP
-.B route
-- routing table entry.
-
-.TP
-.B rule
-- rule in routing policy database.
-
-.TP
-.B maddress
-- multicast address.
-
-.TP
-.B mroute
-- multicast routing cache entry.
-
-.TP
-.B tunnel
-- tunnel over IP.
-
-.PP
-The names of all objects may be written in full or
-abbreviated form, f.e.
-.B address
-is abbreviated as
-.B addr
-or just
-.B a.
-
-.SS
-.I COMMAND
-
-Specifies the action to perform on the object.
-The set of possible actions depends on the object type.
-As a rule, it is possible to
-.BR "add" , " delete"
-and
-.B show
-(or
-.B list
-) objects, but some objects do not allow all of these operations
-or have some additional commands.  The
-.B help
-command is available for all objects.  It prints
-out a list of available commands and argument syntax conventions.
-.sp
-If no command is given, some default command is assumed.
-Usually it is
-.B list
-or, if the objects of this class cannot be listed,
-.BR "help" .
-
-.SH ip link - network device configuration
-
-.B link
-is a network device and the corresponding commands
-display and change the state of devices.
-
-.SS ip link set - change device attributes
-
-.TP
-.BI dev " NAME " (default)
-.I NAME
-specifies network device to operate on.
-
-.TP
-.BR up " and " down
-change the state of the device to
-.B UP
-or
-.BR "DOWN" .
-
-.TP
-.BR "arp on " or " arp off"
-change the
-.B NOARP
-flag on the device.
-
-.TP
-.BR "multicast on " or " multicast off"
-change the
-.B MULTICAST
-flag on the device.
-
-.TP
-.BR "dynamic on " or " dynamic off"
-change the
-.B DYNAMIC
-flag on the device.
-
-.TP
-.BI name " NAME"
-change the name of the device.  This operation is not
-recommended if the device is running or has some addresses
-already configured.
-
-.TP
-.BI txqueuelen " NUMBER"
-.TP 
-.BI txqlen " NUMBER"
-change the transmit queue length of the device.
-
-.TP
-.BI mtu " NUMBER"
-change the 
-.I MTU
-of the device.
-
-.TP
-.BI address " LLADDRESS"
-change the station address of the interface.
-
-.TP
-.BI broadcast " LLADDRESS"
-.TP
-.BI brd " LLADDRESS"
-.TP
-.BI peer " LLADDRESS"
-change the link layer broadcast address or the peer address when
-the interface is
-.IR "POINTOPOINT" .
-
-.PP
-.B Warning:
-If multiple parameter changes are requested,
-.B ip
-aborts immediately after any of the changes have failed.
-This is the only case when
-.B ip
-can move the system to an unpredictable state.  The solution
-is to avoid changing several parameters with one
-.B ip link set
-call.
-
-.SS  ip link show - display device attributes
-
-.TP
-.BI dev " NAME " (default)
-.I NAME
-specifies the network device to show.
-If this argument is omitted all devices are listed.
-
-.TP
-.B up
-only display running interfaces.
-
-.SH ip address - protocol address management.
-
-The
-.B address
-is a protocol (IP or IPv6) address attached
-to a network device.  Each device must have at least one address
-to use the corresponding protocol.  It is possible to have several
-different addresses attached to one device.  These addresses are not
-discriminated, so that the term
-.B alias
-is not quite appropriate for them and we do not use it in this document.
-.sp
-The
-.B ip addr
-command displays addresses and their properties, adds new addresses
-and deletes old ones.
-
-.SS ip address add - add new protocol address.
-
-.TP
-.BI dev " NAME"
-the name of the device to add the address to.
-
-.TP
-.BI local " ADDRESS " (default)
-the address of the interface. The format of the address depends
-on the protocol. It is a dotted quad for IP and a sequence of
-hexadecimal halfwords separated by colons for IPv6.  The
-.I ADDRESS
-may be followed by a slash and a decimal number which encodes
-the network prefix length.
-
-.TP
-.BI peer " ADDRESS"
-the address of the remote endpoint for pointopoint interfaces.
-Again, the
-.I ADDRESS
-may be followed by a slash and a decimal number, encoding the network
-prefix length.  If a peer address is specified, the local address
-cannot have a prefix length.  The network prefix is associated
-with the peer rather than with the local address.
-
-.TP
-.BI broadcast " ADDRESS"
-the broadcast address on the interface.
-.sp
-It is possible to use the special symbols
-.B '+'
-and
-.B '-'
-instead of the broadcast address.  In this case, the broadcast address
-is derived by setting/resetting the host bits of the interface prefix.
-
-.TP
-.BI label " NAME"
-Each address may be tagged with a label string.
-In order to preserve compatibility with Linux-2.0 net aliases,
-this string must coincide with the name of the device or must be prefixed
-with the device name followed by colon.
-
-.TP
-.BI scope " SCOPE_VALUE"
-the scope of the area where this address is valid.
-The available scopes are listed in file
-.BR "/etc/iproute2/rt_scopes" .
-Predefined scope values are:
-
-.in +8
-.B global
-- the address is globally valid.
-.sp
-.B site
-- (IPv6 only) the address is site local, i.e. it is
-valid inside this site.
-.sp
-.B link
-- the address is link local, i.e. it is valid only on this device.
-.sp
-.B host
-- the address is valid only inside this host.
-.in -8
-
-.SS ip address delete - delete protocol address
-.B Arguments:
-coincide with the arguments of
-.B ip addr add.
-The device name is a required argument.  The rest are optional.
-If no arguments are given, the first address is deleted.
-
-.SS ip address show - look at protocol addresses
-
-.TP
-.BI dev " NAME " (default)
-name of device.
-
-.TP
-.BI scope " SCOPE_VAL"
-only list addresses with this scope.
-
-.TP
-.BI to " PREFIX"
-only list addresses matching this prefix.
-
-.TP
-.BI label " PATTERN"
-only list addresses with labels matching the
-.IR "PATTERN" .
-.I PATTERN
-is a usual shell style pattern.
-
-.TP
-.BR dynamic " and " permanent
-(IPv6 only) only list addresses installed due to stateless
-address configuration or only list permanent (not dynamic)
-addresses.
-
-.TP
-.B tentative
-(IPv6 only) only list addresses which did not pass duplicate
-address detection.
-
-.TP
-.B deprecated
-(IPv6 only) only list deprecated addresses.
-
-.TP
-.BR primary " and " secondary
-only list primary (or secondary) addresses.
-
-.SS ip address flush - flush protocol addresses
-This command flushes the protocol addresses selected by some criteria.
-
-.PP
-This command has the same arguments as
-.B show.
-The difference is that it does not run when no arguments are given.
-
-.PP
-.B Warning:
-This command (and other
-.B flush
-commands described below) is pretty dangerous.  If you make a mistake,
-it will not forgive it, but will cruelly purge all the addresses.
-
-.PP
-With the
-.B -statistics
-option, the command becomes verbose. It prints out the number of deleted
-addresses and the number of rounds made to flush the address list.  If
-this option is given twice,
-.B ip addr flush
-also dumps all the deleted addresses in the format described in the
-previous subsection.
-
-.SH ip neighbour - neighbour/arp tables management.
-
-.B neighbour
-objects establish bindings between protocol addresses and
-link layer addresses for hosts sharing the same link.
-Neighbour entries are organized into tables. The IPv4 neighbour table
-is known by another name - the ARP table.
-
-.P
-The corresponding commands display neighbour bindings
-and their properties, add new neighbour entries and delete old ones.
-
-.SS ip neighbour add - add a new neighbour entry
-.SS ip neighbour change - change an existing entry
-.SS ip neighbour replace - add a new entry or change an existing one
-
-These commands create new neighbour records or update existing ones.
-
-.TP
-.BI to " ADDRESS " (default)
-the protocol address of the neighbour. It is either an IPv4 or IPv6 address.
-
-.TP
-.BI dev " NAME"
-the interface to which this neighbour is attached.
-
-.TP
-.BI lladdr " LLADDRESS"
-the link layer address of the neighbour.
-.I LLADDRESS
-can also be
-.BR "null" .
-
-.TP
-.BI nud " NUD_STATE"
-the state of the neighbour entry.
-.B nud
-is an abbreviation for 'Neigh bour Unreachability Detection'.
-The state can take one of the following values:
-
-.in +8
-.B permanent
-- the neighbour entry is valid forever and can be only
-be removed administratively.
-.sp
-
-.B noarp
-- the neighbour entry is valid. No attempts to validate
-this entry will be made but it can be removed when its lifetime expires.
-.sp
-
-.B reachable
-- the neighbour entry is valid until the reachability
-timeout expires.
-.sp
-
-.B stale
-- the neighbour entry is valid but suspicious.
-This option to
-.B ip neigh
-does not change the neighbour state if it was valid and the address
-is not changed by this command.
-.in -8
-
-.SS ip neighbour delete - delete a neighbour entry
-This command invalidates a neighbour entry.
-
-.PP
-The arguments are the same as with
-.BR "ip neigh add" ,
-except that
-.B lladdr
-and
-.B nud
-are ignored.
-
-.PP
-.B Warning:
-Attempts to delete or manually change a
-.B noarp
-entry created by the kernel may result in unpredictable behaviour.
-Particularly, the kernel may try to resolve this address even
-on a
-.B NOARP
-interface or if the address is multicast or broadcast.
-
-.SS ip neighbour show - list neighbour entries
-
-This commands displays neighbour tables.
-
-.TP
-.BI to " ADDRESS " (default)
-the prefix selecting the neighbours to list.
-
-.TP
-.BI dev " NAME"
-only list the neighbours attached to this device.
-
-.TP
-.B unused
-only list neighbours which are not currently in use.
-
-.TP
-.BI nud " NUD_STATE"
-only list neighbour entries in this state.
-.I NUD_STATE
-takes values listed below or the special value
-.B all
-which means all states.  This option may occur more than once.
-If this option is absent,
-.B ip
-lists all entries except for
-.B none
-and
-.BR "noarp" .
-
-.SS ip neighbour flush - flush neighbour entries
-This command flushes neighbour tables, selecting
-entries to flush by some criteria.
-
-.PP
-This command has the same arguments as
-.B show.
-The differences are that it does not run when no arguments are given,
-and that the default neighbour states to be flushed do not include
-.B permanent
-and
-.BR "noarp" .
-
-.PP
-With the
-.B -statistics
-option, the command becomes verbose.  It prints out the number of
-deleted neighbours and the number of rounds made to flush the
-neighbour table.  If the option is given
-twice,
-.B ip neigh flush
-also dumps all the deleted neighbours.
-
-.SH ip route - routing table management
-Manipulate route entries in the kernel routing tables keep
-information about paths to other networked nodes.
-.sp
-.B Route types:
-
-.in +8
-.B unicast
-- the route entry describes real paths to the destinations covered
-by the route prefix.
-
-.sp
-.B unreachable
-- these destinations are unreachable.  Packets are discarded and the
-ICMP message
-.I host unreachable
-is generated.
-The local senders get an
-.I EHOSTUNREACH
-error.
-
-.sp
-.B blackhole
-- these destinations are unreachable.  Packets are discarded silently.
-The local senders get an
-.I EINVAL
-error.
-
-.sp
-.B prohibit
-- these destinations are unreachable.  Packets are discarded and the
-ICMP message
-.I communication administratively prohibited
-is generated.  The local senders get an
-.I EACCES
-error.
-
-.sp
-.B local
-- the destinations are assigned to this host.  The packets are looped
-back and delivered locally.
-
-.sp
-.B broadcast
-- the destinations are broadcast addresses.  The packets are sent as
-link broadcasts.
-
-.sp
-.B throw
-- a special control route used together with policy rules. If such a
-route is selected, lookup in this table is terminated pretending that
-no route was found.  Without policy routing it is equivalent to the
-absence of the route in the routing table.  The packets are dropped
-and the ICMP message
-.I net unreachable
-is generated.  The local senders get an
-.I ENETUNREACH
-error.
-
-.sp
-.B nat
-- a special NAT route.  Destinations covered by the prefix
-are considered to be dummy (or external) addresses which require translation
-to real (or internal) ones before forwarding.  The addresses to translate to
-are selected with the attribute
-.BR "via" .
-
-.sp
-.B anycast
-.RI "- " "not implemented"
-the destinations are
-.I anycast
-addresses assigned to this host.  They are mainly equivalent
-to
-.B local
-with one difference: such addresses are invalid when used
-as the source address of any packet.
-
-.sp
-.B multicast
-- a special type used for multicast routing.  It is not present in
-normal routing tables.
-.in -8
-
-.P
-.B Route tables:
-Linux-2.x can pack routes into several routing
-tables identified by a number in the range from 1 to 255 or by
-name from the file
-.B /etc/iproute2/rt_tables
-. By default all normal routes are inserted into the
-.B main
-table (ID 254) and the kernel only uses this table when calculating routes.
-
-.sp
-Actually, one other table always exists, which is invisible but
-even more important.  It is the
-.B local
-table (ID 255).  This table
-consists of routes for local and broadcast addresses.  The kernel maintains
-this table automatically and the administrator usually need not modify it
-or even look at it.
-
-The multiple routing tables enter the game when
-.I policy routing
-is used.
-
-.SS ip route add - add new route
-.SS ip route change - change route
-.SS ip route replace - change or add new one
-
-.TP
-.BI to " TYPE PREFIX " (default)
-the destination prefix of the route.  If
-.I TYPE
-is omitted,
-.B ip
-assumes type
-.BR "unicast" .
-Other values of
-.I TYPE
-are listed above.
-.I PREFIX
-is an IP or IPv6 address optionally followed by a slash and the
-prefix length.  If the length of the prefix is missing,
-.B ip
-assumes a full-length host route.  There is also a special
-.I PREFIX
-.B default
-- which is equivalent to IP
-.B 0/0
-or to IPv6
-.BR "::/0" .
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-the Type Of Service (TOS) key.  This key has no associated mask and
-the longest match is understood as: First, compare the TOS
-of the route and of the packet.  If they are not equal, then the packet
-may still match a route with a zero TOS.
-.I TOS
-is either an 8 bit hexadecimal number or an identifier
-from
-.BR "/etc/iproute2/rt_dsfield" .
-
-.TP
-.BI metric " NUMBER"
-.TP
-.BI preference " NUMBER"
-the preference value of the route.
-.I NUMBER
-is an arbitrary 32bit number.
-
-.TP
-.BI table " TABLEID"
-the table to add this route to.
-.I TABLEID
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_tables" .
-If this parameter is omitted,
-.B ip
-assumes the
-.B main
-table, with the exception of
-.BR local " , " broadcast " and " nat
-routes, which are put into the
-.B local
-table by default.
-
-.TP
-.BI dev " NAME"
-the output device name.
-
-.TP
-.BI via " ADDRESS"
-the address of the nexthop router.  Actually, the sense of this field
-depends on the route type.  For normal
-.B unicast
-routes it is either the true next hop router or, if it is a direct
-route installed in BSD compatibility mode, it can be a local address
-of the interface.  For NAT routes it is the first address of the block
-of translated IP destinations.
-
-.TP
-.BI src " ADDRESS"
-the source address to prefer when sending to the destinations
-covered by the route prefix.
-
-.TP
-.BI realm " REALMID"
-the realm to which this route is assigned.
-.I REALMID
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_realms" .
-
-.TP
-.BI mtu " MTU"
-.TP
-.BI "mtu lock" " MTU"
-the MTU along the path to the destination.  If the modifier
-.B lock
-is not used, the MTU may be updated by the kernel due to
-Path MTU Discovery.  If the modifier
-.B lock
-is used, no path MTU discovery will be tried, all packets
-will be sent without the DF bit in IPv4 case or fragmented
-to MTU for IPv6.
-
-.TP
-.BI window " NUMBER"
-the maximal window for TCP to advertise to these destinations,
-measured in bytes.  It limits maximal data bursts that our TCP
-peers are allowed to send to us.
-
-.TP
-.BI rtt " NUMBER"
-the initial RTT ('Round Trip Time') estimate.
-
-.TP
-.BI rttvar " NUMBER " "(2.3.15+ only)"
-the initial RTT variance estimate.
-
-.TP
-.BI ssthresh " NUMBER " "(2.3.15+ only)"
-an estimate for the initial slow start threshold.
-
-.TP
-.BI cwnd " NUMBER " "(2.3.15+ only)"
-the clamp for congestion window.  It is ignored if the
-.B lock
-flag is not used.
-
-.TP
-.BI advmss " NUMBER " "(2.3.15+ only)"
-the MSS ('Maximal Segment Size') to advertise to these
-destinations when establishing TCP connections.  If it is not given,
-Linux uses a default value calculated from the first hop device MTU.
-(If the path to these destination is asymmetric, this guess may be wrong.)
-
-.TP
-.BI reordering " NUMBER " "(2.3.15+ only)"
-Maximal reordering on the path to this destination.
-If it is not given, Linux uses the value selected with
-.B sysctl
-variable
-.BR "net/ipv4/tcp_reordering" .
-
-.TP
-.BI nexthop " NEXTHOP"
-the nexthop of a multipath route.
-.I NEXTHOP
-is a complex value with its own syntax similar to the top level
-argument lists:
-
-.in +8
-.BI via " ADDRESS"
-- is the nexthop router.
-.sp
-
-.BI dev " NAME"
-- is the output device.
-.sp
-
-.BI weight " NUMBER"
-- is a weight for this element of a multipath
-route reflecting its relative bandwidth or quality.
-.in -8
-
-.TP
-.BI scope " SCOPE_VAL"
-the scope of the destinations covered by the route prefix.
-.I SCOPE_VAL
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_scopes" .
-If this parameter is omitted,
-.B ip
-assumes scope
-.B global
-for all gatewayed
-.B unicast
-routes, scope
-.B link
-for direct
-.BR unicast " and " broadcast
-routes and scope
-.BR host " for " local
-routes.
-
-.TP
-.BI protocol " RTPROTO"
-the routing protocol identifier of this route.
-.I RTPROTO
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_protos" .
-If the routing protocol ID is not given,
-.B ip assumes protocol
-.B boot
-(i.e. it assumes the route was added by someone who doesn't
-understand what they are doing).  Several protocol values have
-a fixed interpretation.
-Namely:
-
-.in +8
-.B redirect
-- the route was installed due to an ICMP redirect.
-.sp
-
-.B kernel
-- the route was installed by the kernel during autoconfiguration.
-.sp
-
-.B boot
-- the route was installed during the bootup sequence.
-If a routing daemon starts, it will purge all of them.
-.sp
-
-.B static
-- the route was installed by the administrator
-to override dynamic routing. Routing daemon will respect them
-and, probably, even advertise them to its peers.
-.sp
-
-.B ra
-- the route was installed by Router Discovery protocol.
-.in -8
-
-.sp
-The rest of the values are not reserved and the administrator is free
-to assign (or not to assign) protocol tags.
-
-.TP
-.B onlink
-pretend that the nexthop is directly attached to this link,
-even if it does not match any interface prefix.
-
-.TP
-.B equalize
-allow packet by packet randomization on multipath routes.
-Without this modifier, the route will be frozen to one selected
-nexthop, so that load splitting will only occur on per-flow base.
-.B equalize
-only works if the kernel is patched.
-
-.SS ip route delete - delete route
-
-.B ip route del
-has the same arguments as
-.BR "ip route add" ,
-but their semantics are a bit different.
-
-Key values
-.RB "(" to ", " tos ", " preference " and " table ")"
-select the route to delete.  If optional attributes are present,
-.B ip
-verifies that they coincide with the attributes of the route to delete.
-If no route with the given key and attributes was found,
-.B ip route del
-fails.
-
-.SS ip route show - list routes
-the command displays the contents of the routing tables or the route(s)
-selected by some criteria.
-
-.TP
-.BI to " SELECTOR " (default)
-only select routes from the given range of destinations.
-.I SELECTOR
-consists of an optional modifier
-.RB "(" root ", " match " or " exact ")"
-and a prefix.
-.BI root " PREFIX"
-selects routes with prefixes not shorter than
-.IR PREFIX "."
-F.e.
-.BI root " 0/0"
-selects the entire routing table.
-.BI match " PREFIX"
-selects routes with prefixes not longer than
-.IR PREFIX "."
-F.e.
-.BI match " 10.0/16"
-selects
-.IR 10.0/16 ","
-.IR 10/8 " and " 0/0 ,
-but it does not select
-.IR 10.1/16 " and " 10.0.0/24 .
-And
-.BI exact " PREFIX"
-(or just
-.IR PREFIX ")"
-selects routes with this exact prefix. If neither of these options
-are present,
-.B ip
-assumes
-.BI root " 0/0"
-i.e. it lists the entire table.
-
-.TP
-.BI tos " TOS"
-.BI dsfield " TOS"
-only select routes with the given TOS.
-
-.TP
-.BI table " TABLEID"
-show the routes from this table(s).  The default setting is to show
-.BR table main "."
-.I TABLEID
-may either be the ID of a real table or one of the special values:
-.sp
-.in +8
-.B all
-- list all of the tables.
-.sp
-.B cache
-- dump the routing cache.
-.in -8
-
-.TP
-.B cloned
-.TP
-.B cached
-list cloned routes i.e. routes which were dynamically forked from
-other routes because some route attribute (f.e. MTU) was updated.
-Actually, it is equivalent to
-.BR "table cache" "."
-
-.TP
-.BI from " SELECTOR"
-the same syntax as for
-.BR to ","
-but it binds the source address range rather than destinations.
-Note that the
-.B from
-option only works with cloned routes.
-
-.TP
-.BI protocol " RTPROTO"
-only list routes of this protocol.
-
-.TP
-.BI scope " SCOPE_VAL"
-only list routes with this scope.
-
-.TP
-.BI type " TYPE"
-only list routes of this type.
-
-.TP
-.BI dev " NAME"
-only list routes going via this device.
-
-.TP
-.BI via " PREFIX"
-only list routes going via the nexthop routers selected by
-.IR PREFIX "."
-
-.TP
-.BI src " PREFIX"
-only list routes with preferred source addresses selected
-by
-.IR PREFIX "."
-
-.TP
-.BI realm " REALMID"
-.TP
-.BI realms " FROMREALM/TOREALM"
-only list routes with these realms.
-
-.SS ip route flush - flush routing tables
-this command flushes routes selected by some criteria.
-
-.sp
-The arguments have the same syntax and semantics as the arguments of
-.BR "ip route show" ,
-but routing tables are not listed but purged.  The only difference is
-the default action:
-.B show
-dumps all the IP main routing table but
-.B flush
-prints the helper page.
-
-.sp
-With the
-.B -statistics
-option, the command becomes verbose. It prints out the number of
-deleted routes and the number of rounds made to flush the routing
-table. If the option is given
-twice,
-.B ip route flush
-also dumps all the deleted routes in the format described in the
-previous subsection.
-
-.SS ip route get - get a single route
-this command gets a single route to a destination and prints its
-contents exactly as the kernel sees it.
-
-.TP
-.BI to " ADDRESS " (default)
-the destination address.
-
-.TP
-.BI from " ADDRESS"
-the source address.
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-the Type Of Service.
-
-.TP
-.BI iif " NAME"
-the device from which this packet is expected to arrive.
-
-.TP
-.BI oif " NAME"
-force the output device on which this packet will be routed.
-
-.TP
-.B connected
-if no source address 
-.RB "(option " from ")"
-was given, relookup the route with the source set to the preferred
-address received from the first lookup.
-If policy routing is used, it may be a different route.
-
-.P
-Note that this operation is not equivalent to
-.BR "ip route show" .
-.B show
-shows existing routes.
-.B get
-resolves them and creates new clones if necessary.  Essentially,
-.B get
-is equivalent to sending a packet along this path.
-If the
-.B iif
-argument is not given, the kernel creates a route
-to output packets towards the requested destination.
-This is equivalent to pinging the destination
-with a subsequent
-.BR "ip route ls cache" ,
-however, no packets are actually sent.  With the
-.B iif
-argument, the kernel pretends that a packet arrived from this interface
-and searches for a path to forward the packet.
-
-.SH ip rule - routing policy database management
-
-.BR "Rule" s
-in the routing policy database control the route selection algorithm.
-
-.P
-Classic routing algorithms used in the Internet make routing decisions
-based only on the destination address of packets (and in theory,
-but not in practice, on the TOS field).
-
-.P
-In some circumstances we want to route packets differently depending not only
-on destination addresses, but also on other packet fields: source address,
-IP protocol, transport protocol ports or even packet payload.
-This task is called 'policy routing'.
-
-.P
-To solve this task, the conventional destination based routing table, ordered
-according to the longest match rule, is replaced with a 'routing policy
-database' (or RPDB), which selects routes by executing some set of rules.
-
-.P
-Each policy routing rule consists of a
-.B selector
-and an
-.B action predicate.
-The RPDB is scanned in the order of increasing priority. The selector
-of each rule is applied to {source address, destination address, incoming
-interface, tos, fwmark} and, if the selector matches the packet,
-the action is performed.  The action predicate may return with success.
-In this case, it will either give a route or failure indication
-and the RPDB lookup is terminated. Otherwise, the RPDB program
-continues on the next rule.
-
-.P
-Semantically, natural action is to select the nexthop and the output device.
-
-.P
-At startup time the kernel configures the default RPDB consisting of three
-rules:
-
-.TP
-1.
-Priority: 0, Selector: match anything, Action: lookup routing
-table
-.B local
-(ID 255).
-The
-.B local
-table is a special routing table containing
-high priority control routes for local and broadcast addresses.
-.sp
-Rule 0 is special. It cannot be deleted or overridden.
-
-.TP
-2.
-Priority: 32766, Selector: match anything, Action: lookup routing
-table
-.B main
-(ID 254).
-The
-.B main
-table is the normal routing table containing all non-policy
-routes. This rule may be deleted and/or overridden with other
-ones by the administrator.
-
-.TP
-3.
-Priority: 32767, Selector: match anything, Action: lookup routing
-table
-.B default
-(ID 253).
-The
-.B default
-table is empty.  It is reserved for some post-processing if no previous
-default rules selected the packet.
-This rule may also be deleted.
-
-.P
-Each RPDB entry has additional
-attributes.  F.e. each rule has a pointer to some routing
-table.  NAT and masquerading rules have an attribute to select new IP
-address to translate/masquerade.  Besides that, rules have some
-optional attributes, which routes have, namely
-.BR "realms" .
-These values do not override those contained in the routing tables.  They
-are only used if the route did not select any attributes.
-
-.sp
-The RPDB may contain rules of the following types:
-
-.in +8
-.B unicast
-- the rule prescribes to return the route found
-in the routing table referenced by the rule.
-
-.B blackhole
-- the rule prescribes to silently drop the packet.
-
-.B unreachable
-- the rule prescribes to generate a 'Network is unreachable' error.
-
-.B prohibit
-- the rule prescribes to generate 'Communication is administratively
-prohibited' error.
-
-.B nat
-- the rule prescribes to translate the source address
-of the IP packet into some other value.
-.in -8
-
-.SS ip rule add - insert a new rule
-.SS ip rule delete - delete a rule
-
-.TP
-.BI type " TYPE " (default)
-the type of this rule.  The list of valid types was given in the previous
-subsection.
-
-.TP
-.BI from " PREFIX"
-select the source prefix to match.
-
-.TP
-.BI to " PREFIX"
-select the destination prefix to match.
-
-.TP
-.BI iif " NAME"
-select the incoming device to match.  If the interface is loopback,
-the rule only matches packets originating from this host.  This means
-that you may create separate routing tables for forwarded and local
-packets and, hence, completely segregate them.
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-select the TOS value to match.
-
-.TP
-.BI fwmark " MARK"
-select the
-.B fwmark
-value to match.
-
-.TP
-.BI priority " PREFERENCE"
-the priority of this rule.  Each rule should have an explicitly
-set
-.I unique
-priority value.
-
-.TP
-.BI table " TABLEID"
-the routing table identifier to lookup if the rule selector matches.
-
-.TP
-.BI realms " FROM/TO"
-Realms to select if the rule matched and the routing table lookup
-succeeded.  Realm 
-.I TO
-is only used if the route did not select any realm.
-
-.TP
-.BI nat " ADDRESS"
-The base of the IP address block to translate (for source addresses).
-The 
-.I ADDRESS
-may be either the start of the block of NAT addresses (selected by NAT
-routes) or a local host address (or even zero).
-In the last case the router does not translate the packets, but
-masquerades them to this address.
-
-.B Warning:
-Changes to the RPDB made with these commands do not become active
-immediately.  It is assumed that after a script finishes a batch of
-updates, it flushes the routing cache with
-.BR "ip route flush cache" .
-
-.SS ip rule show - list rules
-This command has no arguments.
-
-.SH ip maddress - multicast addresses management
-
-.B maddress
-objects are multicast addresses.
-
-.SS ip maddress show - list multicast addresses
-
-.TP
-.BI dev " NAME " (default)
-the device name.
-
-.SS ip maddress add - add a multicast address
-.SS ip maddress delete - delete a multicast address
-these commands attach/detach a static link layer multicast address
-to listen on the interface.
-Note that it is impossible to join protocol multicast groups
-statically.  This command only manages link layer addresses.
-
-.TP
-.BI address " LLADDRESS " (default)
-the link layer multicast address.
-
-.TP
-.BI dev " NAME"
-the device to join/leave this multicast address.
-
-.SH ip mroute - multicast routing cache management
-.B mroute
-objects are multicast routing cache entries created by a user level
-mrouting daemon (f.e.
-.B pimd
-or
-.B mrouted
-).
-
-Due to the limitations of the current interface to the multicast routing
-engine, it is impossible to change
-.B mroute
-objects administratively, so we may only display them.  This limitation
-will be removed in the future.
-
-.SS ip mroute show - list mroute cache entries
-
-.TP
-.BI to " PREFIX " (default)
-the prefix selecting the destination multicast addresses to list.
-
-.TP
-.BI iif " NAME"
-the interface on which multicast packets are received.
-
-.TP
-.BI from " PREFIX"
-the prefix selecting the IP source addresses of the multicast route.
-
-.SH ip tunnel - tunnel configuration
-.B tunnel
-objects are tunnels, encapsulating packets in IPv4 packets and then
-sending them over the IP infrastructure.
-
-.SS ip tunnel add - add a new tunnel
-.SS ip tunnel change - change an existing tunnel
-.SS ip tunnel delete - destroy a tunnel
-
-.TP
-.BI name " NAME " (default)
-select the tunnel device name.
-
-.TP
-.BI mode " MODE"
-set the tunnel mode.  Three modes are currently available:
-.BR ipip ", " sit " and " gre "."
-
-.TP
-.BI remote " ADDRESS"
-set the remote endpoint of the tunnel.
-
-.TP
-.BI local " ADDRESS"
-set the fixed local address for tunneled packets.
-It must be an address on another interface of this host.
-
-.TP
-.BI ttl " N"
-set a fixed TTL 
-.I N
-on tunneled packets.
-.I N
-is a number in the range 1--255. 0 is a special value
-meaning that packets inherit the TTL value. 
-The default value is:
-.BR "inherit" .
-
-.TP
-.BI tos " T"
-.TP
-.BI dsfield " T"
-set a fixed TOS
-.I T
-on tunneled packets.
-The default value is:
-.BR "inherit" .
-
-.TP
-.BI dev " NAME" 
-bind the tunnel to the device
-.I NAME
-so that tunneled packets will only be routed via this device and will
-not be able to escape to another device when the route to endpoint
-changes.
-
-.TP
-.B nopmtudisc
-disable Path MTU Discovery on this tunnel.
-It is enabled by default.  Note that a fixed ttl is incompatible
-with this option: tunnelling with a fixed ttl always makes pmtu
-discovery.
-
-.TP
-.BI key " K"
-.TP
-.BI ikey " K"
-.TP
-.BI okey " K"
-.RB ( " only GRE tunnels " )
-use keyed GRE with key
-.IR K ". " K
-is either a number or an IP address-like dotted quad.
-The
-.B key
-parameter sets the key to use in both directions.
-The
-.BR ikey " and " okey
-parameters set different keys for input and output.
-   
-.TP
-.BR csum ", " icsum ", " ocsum
-.RB ( " only GRE tunnels " )
-generate/require checksums for tunneled packets.
-The 
-.B ocsum
-flag calculates checksums for outgoing packets.
-The
-.B icsum
-flag requires that all input packets have the correct
-checksum.  The
-.B csum
-flag is equivalent to the combination
-.BR "icsum ocsum" .
-
-.TP
-.BR seq ", " iseq ", " oseq
-.RB ( " only GRE tunnels " )
-serialize packets.
-The
-.B oseq
-flag enables sequencing of outgoing packets.
-The
-.B iseq
-flag requires that all input packets are serialized.
-The
-.B  seq
-flag is equivalent to the combination 
-.BR "iseq oseq" .
-.B It isn't work. Don't use it.
-
-.SS ip tunnel show - list tunnels
-This command has no arguments.
-
-.SH ip monitor and rtmon - state monitoring
-
-The
-.B ip
-utility can monitor the state of devices, addresses
-and routes continuously.  This option has a slightly different format.
-Namely, the
-.B monitor
-command is the first in the command line and then the object list follows:
-
-.BR "ip monitor" " [ " all " |"
-.IR LISTofOBJECTS " ]"
-
-.I OBJECT-LIST
-is the list of object types that we want to monitor.
-It may contain
-.BR link ", " address " and " route "."
-If no
-.B file
-argument is given,
-.B ip
-opens RTNETLINK, listens on it and dumps state changes in the format
-described in previous sections.
-
-.P
-If a file name is given, it does not listen on RTNETLINK,
-but opens the file containing RTNETLINK messages saved in binary format
-and dumps them.  Such a history file can be generated with the
-.B rtmon
-utility.  This utility has a command line syntax similar to
-.BR "ip monitor" .
-Ideally,
-.B rtmon
-should be started before the first network configuration command
-is issued. F.e. if you insert:
-.sp
-.in +8
-rtmon file /var/log/rtmon.log
-.in -8
-.sp
-in a startup script, you will be able to view the full history
-later.
-
-.P
-Certainly, it is possible to start
-.B rtmon
-at any time.
-It prepends the history with the state snapshot dumped at the moment
-of starting.
-
-.SH HISTORY
-
-.B ip
-was written by Alexey N. Kuznetsov and added in Linux 2.2.
-.SH SEE ALSO
-.BR tc (8)
-.br
-.RB "IP Command reference " ip-cref.ps
-.br
-.RB "IP tunnels " ip-cref.ps
-
-.SH AUTHOR
-
-Manpage maintained by Michail Litvak <mci@owl.openwall.com>
diff --git a/ip/.gitignore b/ip/.gitignore
new file mode 100644 (file)
index 0000000..b95b232
--- /dev/null
@@ -0,0 +1,2 @@
+ip
+rtmon
index 3383c72..98ba876 100644 (file)
@@ -1,7 +1,8 @@
-IPOBJ=ip.o ipaddress.o iproute.o iprule.o \
-    rtm_map.o iptunnel.o ipneigh.o ipntable.o iplink.o \
+IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o \
+    rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
-    ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o
+    ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
+    iplink_vlan.o link_veth.o link_gre.o
 
 RTMONOBJ=rtmon.o
 
@@ -9,16 +10,19 @@ ALLOBJ=$(IPOBJ) $(RTMONOBJ)
 SCRIPTS=ifcfg rtpr routel routef
 TARGETS=ip rtmon
 
-all: $(TARGETS) $(SCRIPTS)
+all: $(TARGETS) $(SCRIPTS) $(LIBS)
 
 ip: $(IPOBJ) $(LIBNETLINK) $(LIBUTIL)
 
 rtmon: $(RTMONOBJ) $(LIBNETLINK)
 
 install: all
-       install -m 0755 -s $(TARGETS) $(DESTDIR)$(SBINDIR)
+       install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
        install -m 0755 $(SCRIPTS) $(DESTDIR)$(SBINDIR)
 
 clean:
        rm -f $(ALLOBJ) $(TARGETS)
 
+LDLIBS += -ldl
+
+LDFLAGS += -Wl,-export-dynamic
old mode 100755 (executable)
new mode 100644 (file)
index ed6960f..083d9df
--- a/ip/ifcfg
+++ b/ip/ifcfg
@@ -86,6 +86,10 @@ if [ "$peer" != "" ]; then
   fi
   pfx="$ipaddr peer $peer"
 else
+  if [ "$ipaddr" = "" ]; then
+    echo "Missing IP address argument." 1>&2
+    exit 1
+  fi
   if [ "$pfxlen" = "" ]; then
     ABCMaskLen $ipaddr
     pfxlen=$?
@@ -125,7 +129,7 @@ noarp=$?
 ( sleep 2 ;
   arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
 
-ip route add unreachable 224.0.0.0/24 >& /dev/null 
+ip route add unreachable 224.0.0.0/24 >& /dev/null
 ip route add unreachable 255.255.255.255 >& /dev/null
 if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
   ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
diff --git a/ip/ip.c b/ip/ip.c
index c29d2f3..c4c773f 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
 
 int preferred_family = AF_UNSPEC;
 int show_stats = 0;
+int show_details = 0;
 int resolve_hosts = 0;
 int oneline = 0;
 int timestamp = 0;
 char * _SL_ = NULL;
 char *batch_file = NULL;
 int force = 0;
-struct rtnl_handle rth;
+struct rtnl_handle rth = { .fd = -1 };
 
 static void usage(void) __attribute__((noreturn));
 
@@ -45,9 +46,9 @@ static void usage(void)
        fprintf(stderr,
 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
 "       ip [ -force ] [-batch filename\n"
-"where  OBJECT := { link | addr | route | rule | neigh | ntable | tunnel |\n"
-"                   maddr | mroute | monitor | xfrm }\n"
-"       OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] |\n"
+"where  OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
+"                   tunnel | maddr | mroute | monitor | xfrm }\n"
+"       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
 "                    -o[neline] | -t[imestamp] }\n");
        exit(-1);
@@ -63,6 +64,7 @@ static const struct cmd {
        int (*func)(int argc, char **argv);
 } cmds[] = {
        { "address",    do_ipaddr },
+       { "addrlabel",  do_ipaddrlabel },
        { "maddress",   do_multiaddr },
        { "route",      do_iproute },
        { "rule",       do_iprule },
@@ -102,7 +104,7 @@ static int batch(const char *name)
 
        if (name && strcmp(name, "-") != 0) {
                if (freopen(name, "r", stdin) == NULL) {
-                       fprintf(stderr, "Cannot open file \"%s\" for reading: %s=n",
+                       fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
                                name, strerror(errno));
                        return -1;
                }
@@ -145,7 +147,7 @@ int main(int argc, char **argv)
                basename = argv[0];
        else
                basename++;
-       
+
        while (argc > 1) {
                char *opt = argv[1];
                if (strcmp(opt,"--") == 0) {
@@ -188,6 +190,8 @@ int main(int argc, char **argv)
                } else if (matches(opt, "-stats") == 0 ||
                           matches(opt, "-statistics") == 0) {
                        ++show_stats;
+               } else if (matches(opt, "-details") == 0) {
+                       ++show_details;
                } else if (matches(opt, "-resolve") == 0) {
                        ++resolve_hosts;
                } else if (matches(opt, "-oneline") == 0) {
@@ -220,16 +224,16 @@ int main(int argc, char **argv)
 
        _SL_ = oneline ? "\\" : "\n" ;
 
-       if (batch_file) 
+       if (batch_file)
                return batch(batch_file);
-               
+
        if (rtnl_open(&rth, 0) < 0)
                exit(1);
 
-       if (strlen(basename) > 2) 
+       if (strlen(basename) > 2)
                return do_cmd(basename+2, argc, argv);
 
-       if (argc > 1) 
+       if (argc > 1)
                return do_cmd(argv[1], argc-1, argv+1);
 
        rtnl_close(&rth);
diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
new file mode 100644 (file)
index 0000000..8421983
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * based on:
+ * $Id: s.ipv6tunnel.c 1.7 02/12/11 11:21:51+02:00 antti@traci.mipl.mediapoli.com $
+ *
+ */
+/*
+ * Author:
+ *     Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <linux/ip.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+
+#define IP6_FLOWINFO_TCLASS    htonl(0x0FF00000)
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
+
+#define DEFAULT_TNL_HOP_LIMIT  (64)
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
+       fprintf(stderr, "          [ mode { ip6ip6 | ipip6 | any } ]\n");
+       fprintf(stderr, "          [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
+       fprintf(stderr, "          [ encaplimit ELIM ]\n");
+       fprintf(stderr ,"          [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+       fprintf(stderr, "          [ dscp inherit ]\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Where: NAME      := STRING\n");
+       fprintf(stderr, "       ADDR      := IPV6_ADDRESS\n");
+       fprintf(stderr, "       ELIM      := { none | 0..255 }(default=%d)\n",
+               IPV6_DEFAULT_TNL_ENCAP_LIMIT);
+       fprintf(stderr, "       TTL       := 0..255 (default=%d)\n",
+               DEFAULT_TNL_HOP_LIMIT);
+       fprintf(stderr, "       TOS       := { 0x0..0xff | inherit }\n");
+       fprintf(stderr, "       FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+       exit(-1);
+}
+
+static void print_tunnel(struct ip6_tnl_parm *p)
+{
+       char remote[64];
+       char local[64];
+
+       inet_ntop(AF_INET6, &p->raddr, remote, sizeof(remote));
+       inet_ntop(AF_INET6, &p->laddr, local, sizeof(local));
+
+       printf("%s: %s/ipv6 remote %s local %s",
+              p->name, tnl_strproto(p->proto), remote, local);
+       if (p->link) {
+               char *n = tnl_ioctl_get_ifname(p->link);
+               if (n)
+                       printf(" dev %s", n);
+       }
+
+       if (p->flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
+               printf(" encaplimit none");
+       else
+               printf(" encaplimit %u", p->encap_limit);
+
+       printf(" hoplimit %u", p->hop_limit);
+
+       if (p->flags & IP6_TNL_F_USE_ORIG_TCLASS)
+               printf(" tclass inherit");
+       else {
+               __u32 val = ntohl(p->flowinfo & IP6_FLOWINFO_TCLASS);
+               printf(" tclass 0x%02x", (__u8)(val >> 20));
+       }
+
+       if (p->flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+               printf(" flowlabel inherit");
+       else
+               printf(" flowlabel 0x%05x", ntohl(p->flowinfo & IP6_FLOWINFO_FLOWLABEL));
+
+       printf(" (flowinfo 0x%08x)", ntohl(p->flowinfo));
+
+       if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
+               printf(" dscp inherit");
+}
+
+static int parse_args(int argc, char **argv, struct ip6_tnl_parm *p)
+{
+       char medium[IFNAMSIZ];
+
+       memset(medium, 0, sizeof(medium));
+
+       while (argc > 0) {
+               if (strcmp(*argv, "mode") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "ipv6/ipv6") == 0 ||
+                           strcmp(*argv, "ip6ip6") == 0)
+                               p->proto = IPPROTO_IPV6;
+                       else if (strcmp(*argv, "ip/ipv6") == 0 ||
+                                strcmp(*argv, "ipv4/ipv6") == 0 ||
+                                strcmp(*argv, "ipip6") == 0 ||
+                                strcmp(*argv, "ip4ip6") == 0)
+                               p->proto = IPPROTO_IPIP;
+                       else if (strcmp(*argv, "any/ipv6") == 0 ||
+                                strcmp(*argv, "any") == 0)
+                               p->proto = 0;
+                       else {
+                                fprintf(stderr,"Cannot guess tunnel mode.\n");
+                                exit(-1);
+                        }
+                } else if (strcmp(*argv, "remote") == 0) {
+                       inet_prefix raddr;
+                       NEXT_ARG();
+                       get_prefix(&raddr, *argv, preferred_family);
+                       if (raddr.family == AF_UNSPEC)
+                               invarg("\"remote\" address family is AF_UNSPEC", *argv);
+                       memcpy(&p->raddr, &raddr.data, sizeof(p->raddr));
+               } else if (strcmp(*argv, "local") == 0) {
+                       inet_prefix laddr;
+                       NEXT_ARG();
+                       get_prefix(&laddr, *argv, preferred_family);
+                       if (laddr.family == AF_UNSPEC)
+                               invarg("\"local\" address family is AF_UNSPEC", *argv);
+                       memcpy(&p->laddr, &laddr.data, sizeof(p->laddr));
+               } else if (strcmp(*argv, "dev") == 0) {
+                       NEXT_ARG();
+                       strncpy(medium, *argv, IFNAMSIZ - 1);
+               } else if (strcmp(*argv, "encaplimit") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "none") == 0) {
+                               p->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
+                       } else {
+                               __u8 uval;
+                               if (get_u8(&uval, *argv, 0) < -1)
+                                       invarg("invalid ELIM", *argv);
+                               p->encap_limit = uval;
+                       }
+               } else if (strcmp(*argv, "hoplimit") == 0 ||
+                          strcmp(*argv, "ttl") == 0 ||
+                          strcmp(*argv, "hlim") == 0) {
+                       __u8 uval;
+                       NEXT_ARG();
+                       if (get_u8(&uval, *argv, 0))
+                               invarg("invalid TTL", *argv);
+                       p->hop_limit = uval;
+               } else if (strcmp(*argv, "tclass") == 0 ||
+                          strcmp(*argv, "tc") == 0 ||
+                          strcmp(*argv, "tos") == 0 ||
+                          matches(*argv, "dsfield") == 0) {
+                       __u8 uval;
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") == 0)
+                               p->flags |= IP6_TNL_F_USE_ORIG_TCLASS;
+                       else {
+                               if (get_u8(&uval, *argv, 16))
+                                       invarg("invalid TClass", *argv);
+                               p->flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
+                               p->flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
+                       }
+               } else if (strcmp(*argv, "flowlabel") == 0 ||
+                          strcmp(*argv, "fl") == 0) {
+                       __u32 uval;
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") == 0)
+                               p->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+                       else {
+                               if (get_u32(&uval, *argv, 16))
+                                       invarg("invalid Flowlabel", *argv);
+                               if (uval > 0xFFFFF)
+                                       invarg("invalid Flowlabel", *argv);
+                               p->flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
+                               p->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+                       }
+               } else if (strcmp(*argv, "dscp") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") != 0)
+                               invarg("not inherit", *argv);
+                       p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+               } else {
+                       if (strcmp(*argv, "name") == 0) {
+                               NEXT_ARG();
+                       }
+                       if (matches(*argv, "help") == 0)
+                               usage();
+                       if (p->name[0])
+                               duparg2("name", *argv);
+                       strncpy(p->name, *argv, IFNAMSIZ - 1);
+               }
+               argc--; argv++;
+       }
+       if (medium[0]) {
+               p->link = tnl_ioctl_get_ifindex(medium);
+               if (p->link == 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
+{
+       memset(p, 0, sizeof(*p));
+       p->proto = IPPROTO_IPV6;
+       if (apply_default) {
+               p->hop_limit = DEFAULT_TNL_HOP_LIMIT;
+               p->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+       }
+}
+
+/*
+ * @p1: user specified parameter
+ * @p2: database entry
+ */
+static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
+                             const struct ip6_tnl_parm *p2)
+{
+       return ((!p1->link || p1->link == p2->link) &&
+               (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+               (memcmp(&p1->laddr, &in6addr_any, sizeof(p1->laddr)) == 0 ||
+                memcmp(&p1->laddr, &p2->laddr, sizeof(p1->laddr)) == 0) &&
+               (memcmp(&p1->raddr, &in6addr_any, sizeof(p1->raddr)) == 0 ||
+                memcmp(&p1->raddr, &p2->raddr, sizeof(p1->raddr)) == 0) &&
+               (!p1->proto || !p2->proto || p1->proto == p2->proto) &&
+               (!p1->encap_limit || p1->encap_limit == p2->encap_limit) &&
+               (!p1->hop_limit || p1->hop_limit == p2->hop_limit) &&
+               (!(p1->flowinfo & IP6_FLOWINFO_TCLASS) ||
+                !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_TCLASS)) &&
+               (!(p1->flowinfo & IP6_FLOWINFO_FLOWLABEL) ||
+                !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_FLOWLABEL)) &&
+               (!p1->flags || (p1->flags & p2->flags)));
+}
+
+static int do_tunnels_list(struct ip6_tnl_parm *p)
+{
+       char buf[512];
+       int err = -1;
+       FILE *fp = fopen("/proc/net/dev", "r");
+       if (fp == NULL) {
+               perror("fopen");
+               goto end;
+       }
+
+       /* skip two lines at the begenning of the file */
+       fgets(buf, sizeof(buf), fp);
+       fgets(buf, sizeof(buf), fp);
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               char name[IFNAMSIZ];
+               int type;
+               unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+                       rx_fifo, rx_frame,
+                       tx_bytes, tx_packets, tx_errs, tx_drops,
+                       tx_fifo, tx_colls, tx_carrier, rx_multi;
+               struct ip6_tnl_parm p1;
+               char *ptr;
+
+               buf[sizeof(buf) - 1] = '\0';
+               if ((ptr = strchr(buf, ':')) == NULL ||
+                   (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
+                       fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
+                       goto end;
+               }
+               if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+                          &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+                          &rx_fifo, &rx_frame, &rx_multi,
+                          &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+                          &tx_fifo, &tx_colls, &tx_carrier) != 14)
+                       continue;
+               if (p->name[0] && strcmp(p->name, name))
+                       continue;
+               type = tnl_ioctl_get_iftype(name);
+               if (type == -1) {
+                       fprintf(stderr, "Failed to get type of [%s]\n", name);
+                       continue;
+               }
+               if (type != ARPHRD_TUNNEL6)
+                       continue;
+               memset(&p1, 0, sizeof(p1));
+               ip6_tnl_parm_init(&p1, 0);
+               strcpy(p1.name, name);
+               p1.link = tnl_ioctl_get_ifindex(p1.name);
+               if (p1.link == 0)
+                       continue;
+               if (tnl_get_ioctl(p1.name, &p1))
+                       continue;
+               if (!ip6_tnl_parm_match(p, &p1))
+                       continue;
+               print_tunnel(&p1);
+               if (show_stats) {
+                       printf("%s", _SL_);
+                       printf("RX: Packets    Bytes        Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
+                       printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
+                              rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+                       printf("TX: Packets    Bytes        Errors DeadLoop NoRoute  NoBufs%s", _SL_);
+                       printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
+                              tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+               }
+               printf("\n");
+       }
+       err = 0;
+
+ end:
+       if (fp)
+               fclose(fp);
+       return err;
+}
+
+static int do_show(int argc, char **argv)
+{
+        struct ip6_tnl_parm p;
+
+       ip6_tnl_parm_init(&p, 0);
+
+        if (parse_args(argc, argv, &p) < 0)
+                return -1;
+
+       if (!p.name[0] || show_stats)
+               do_tunnels_list(&p);
+       else {
+               if (tnl_get_ioctl(p.name, &p))
+                       return -1;
+               print_tunnel(&p);
+               printf("\n");
+       }
+
+        return 0;
+}
+
+static int do_add(int cmd, int argc, char **argv)
+{
+       struct ip6_tnl_parm p;
+
+       ip6_tnl_parm_init(&p, 1);
+
+       if (parse_args(argc, argv, &p) < 0)
+               return -1;
+
+       return tnl_add_ioctl(cmd,
+                            cmd == SIOCCHGTUNNEL && p.name[0] ?
+                            p.name : "ip6tnl0", p.name, &p);
+}
+
+static int do_del(int argc, char **argv)
+{
+       struct ip6_tnl_parm p;
+
+       ip6_tnl_parm_init(&p, 1);
+
+       if (parse_args(argc, argv, &p) < 0)
+               return -1;
+
+       return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
+}
+
+int do_ip6tunnel(int argc, char **argv)
+{
+       switch (preferred_family) {
+       case AF_UNSPEC:
+               preferred_family = AF_INET6;
+               break;
+       case AF_INET6:
+               break;
+       default:
+               fprintf(stderr, "Unsupported family:%d\n", preferred_family);
+               exit(-1);
+       }
+
+       if (argc > 0) {
+               if (matches(*argv, "add") == 0)
+                       return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
+               if (matches(*argv, "change") == 0)
+                       return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
+               if (matches(*argv, "del") == 0)
+                       return do_del(argc - 1, argv + 1);
+               if (matches(*argv, "show") == 0 ||
+                   matches(*argv, "lst") == 0 ||
+                   matches(*argv, "list") == 0)
+                       return do_show(argc - 1, argv + 1);
+               if (matches(*argv, "help") == 0)
+                       usage();
+       } else
+               return do_show(0, NULL);
+
+       fprintf(stderr, "Command \"%s\" is unknown, try \"ip -f inet6 tunnel help\".\n", *argv);
+       exit(-1);
+}
index 1fe4a69..273065f 100644 (file)
@@ -1,9 +1,11 @@
-extern int print_linkinfo(const struct sockaddr_nl *who, 
-                         struct nlmsghdr *n, 
+extern int print_linkinfo(const struct sockaddr_nl *who,
+                         struct nlmsghdr *n,
                          void *arg);
 extern int print_addrinfo(const struct sockaddr_nl *who,
-                         struct nlmsghdr *n, 
+                         struct nlmsghdr *n,
                          void *arg);
+extern int print_addrlabel(const struct sockaddr_nl *who,
+                          struct nlmsghdr *n, void *arg);
 extern int print_neigh(const struct sockaddr_nl *who,
                       struct nlmsghdr *n, void *arg);
 extern int print_ntable(const struct sockaddr_nl *who,
@@ -16,20 +18,51 @@ extern void iproute_reset_filter(void);
 extern void ipaddr_reset_filter(int);
 extern void ipneigh_reset_filter(void);
 extern void ipntable_reset_filter(void);
-extern int print_route(const struct sockaddr_nl *who, 
+extern int print_route(const struct sockaddr_nl *who,
                       struct nlmsghdr *n, void *arg);
 extern int print_prefix(const struct sockaddr_nl *who,
                        struct nlmsghdr *n, void *arg);
+extern int print_rule(const struct sockaddr_nl *who,
+                     struct nlmsghdr *n, void *arg);
 extern int do_ipaddr(int argc, char **argv);
+extern int do_ipaddrlabel(int argc, char **argv);
 extern int do_iproute(int argc, char **argv);
 extern int do_iprule(int argc, char **argv);
 extern int do_ipneigh(int argc, char **argv);
 extern int do_ipntable(int argc, char **argv);
 extern int do_iptunnel(int argc, char **argv);
+extern int do_ip6tunnel(int argc, char **argv);
 extern int do_iplink(int argc, char **argv);
 extern int do_ipmonitor(int argc, char **argv);
 extern int do_multiaddr(int argc, char **argv);
 extern int do_multiroute(int argc, char **argv);
 extern int do_xfrm(int argc, char **argv);
 
+static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
+{
+       __u32 table = r->rtm_table;
+       if (tb[RTA_TABLE])
+               table = *(__u32*) RTA_DATA(tb[RTA_TABLE]);
+       return table;
+}
+
 extern struct rtnl_handle rth;
+
+struct link_util
+{
+       struct link_util        *next;
+       const char              *id;
+       int                     maxattr;
+       int                     (*parse_opt)(struct link_util *, int, char **,
+                                            struct nlmsghdr *);
+       void                    (*print_opt)(struct link_util *, FILE *,
+                                            struct rtattr *[]);
+       void                    (*print_xstats)(struct link_util *, FILE *,
+                                            struct rtattr *);
+};
+
+struct link_util *get_link_kind(const char *kind);
+
+#ifndef        INFINITY_LIFE_TIME
+#define     INFINITY_LIFE_TIME      0xFFFFFFFFU
+#endif
index cb164c0..a732d80 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <sys/errno.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
@@ -34,6 +35,8 @@
 #include "ll_map.h"
 #include "ip_common.h"
 
+#define MAX_ROUNDS 10
+
 static struct
 {
        int ifindex;
@@ -60,7 +63,9 @@ static void usage(void)
        if (do_link) {
                iplink_usage();
        }
-       fprintf(stderr, "Usage: ip addr {add|del} IFADDR dev STRING\n");
+       fprintf(stderr, "Usage: ip addr {add|change|replace} IFADDR dev STRING [ LIFETIME ]\n");
+       fprintf(stderr, "                                                      [ CONFFLAG-LIST]\n");
+       fprintf(stderr, "       ip addr del IFADDR dev STRING\n");
        fprintf(stderr, "       ip addr {show|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
        fprintf(stderr, "                            [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ]\n");
        fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n");
@@ -69,7 +74,12 @@ static void usage(void)
        fprintf(stderr, "SCOPE-ID := [ host | link | global | NUMBER ]\n");
        fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
        fprintf(stderr, "FLAG  := [ permanent | dynamic | secondary | primary |\n");
-       fprintf(stderr, "           tentative | deprecated ]\n");
+       fprintf(stderr, "           tentative | deprecated | CONFFLAG-LIST ]\n");
+       fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
+       fprintf(stderr, "CONFFLAG  := [ home | nodad ]\n");
+       fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
+       fprintf(stderr, "LFT := forever | SECONDS\n");
+
        exit(-1);
 }
 
@@ -97,6 +107,8 @@ void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
        _PF(PORTSEL);
        _PF(NOTRAILERS);
        _PF(UP);
+       _PF(LOWER_UP);
+       _PF(DORMANT);
 #undef _PF
         if (flags)
                fprintf(fp, "%x", flags);
@@ -105,7 +117,20 @@ void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
        fprintf(fp, "> ");
 }
 
-void print_queuelen(char *name)
+static const char *oper_states[] = {
+       "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN", 
+       "TESTING", "DORMANT",    "UP"
+};
+
+static void print_operstate(FILE *f, __u8 state)
+{
+       if (state >= sizeof(oper_states)/sizeof(oper_states[0]))
+               fprintf(f, "state %#x ", state);
+       else
+               fprintf(f, "state %s ", oper_states[state]);
+}
+
+static void print_queuelen(FILE *f, const char *name)
 {
        struct ifreq ifr;
        int s;
@@ -116,18 +141,53 @@ void print_queuelen(char *name)
 
        memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, name);
-       if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { 
-               perror("SIOCGIFXQLEN");
+       if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
+               fprintf(f, "ioctl(SIOCGIFXQLEN) failed: %s\n", strerror(errno));
                close(s);
                return;
        }
        close(s);
 
        if (ifr.ifr_qlen)
-               printf("qlen %d", ifr.ifr_qlen);
+               fprintf(f, "qlen %d", ifr.ifr_qlen);
+}
+
+static void print_linktype(FILE *fp, struct rtattr *tb)
+{
+       struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+       struct link_util *lu;
+       char *kind;
+
+       parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+
+       if (!linkinfo[IFLA_INFO_KIND])
+               return;
+       kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
+
+       fprintf(fp, "%s", _SL_);
+       fprintf(fp, "    %s ", kind);
+
+       lu = get_link_kind(kind);
+       if (!lu || !lu->print_opt)
+               return;
+
+       if (1) {
+               struct rtattr *attr[lu->maxattr+1], **data = NULL;
+
+               if (linkinfo[IFLA_INFO_DATA]) {
+                       parse_rtattr_nested(attr, lu->maxattr,
+                                           linkinfo[IFLA_INFO_DATA]);
+                       data = attr;
+               }
+               lu->print_opt(lu, fp, data);
+
+               if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
+                   lu->print_xstats)
+                       lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
+       }
 }
 
-int print_linkinfo(const struct sockaddr_nl *who, 
+int print_linkinfo(const struct sockaddr_nl *who,
                   struct nlmsghdr *n, void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -189,9 +249,12 @@ int print_linkinfo(const struct sockaddr_nl *who,
                fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
        }
 #endif
+       if (tb[IFLA_OPERSTATE])
+               print_operstate(fp, *(__u8 *)RTA_DATA(tb[IFLA_OPERSTATE]));
+               
        if (filter.showqueue)
-               print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
-       
+               print_queuelen(fp, (char*)RTA_DATA(tb[IFLA_IFNAME]));
+
        if (!filter.family || filter.family == AF_PACKET) {
                SPRINT_BUF(b1);
                fprintf(fp, "%s", _SL_);
@@ -214,6 +277,10 @@ int print_linkinfo(const struct sockaddr_nl *who,
                                                      b1, sizeof(b1)));
                }
        }
+
+       if (do_link && tb[IFLA_LINKINFO] && show_details)
+               print_linktype(fp, tb[IFLA_LINKINFO]);
+
        if (do_link && tb[IFLA_STATS] && show_stats) {
                struct rtnl_link_stats slocal;
                struct rtnl_link_stats *s = RTA_DATA(tb[IFLA_STATS]);
@@ -268,20 +335,31 @@ int print_linkinfo(const struct sockaddr_nl *who,
 
 static int flush_update(void)
 {
-       if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) {
-               perror("Failed to send flush request\n");
+       if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+               perror("Failed to send flush request");
                return -1;
        }
        filter.flushp = 0;
        return 0;
 }
 
-int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, 
+static int set_lifetime(unsigned int *lifetime, char *argv)
+{
+       if (strcmp(argv, "forever") == 0)
+               *lifetime = INFINITY_LIFE_TIME;
+       else if (get_u32(lifetime, argv, 0))
+               return -1;
+
+       return 0;
+}
+
+int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
                   void *arg)
 {
        FILE *fp = (FILE*)arg;
        struct ifaddrmsg *ifa = NLMSG_DATA(n);
        int len = n->nlmsg_len;
+       int deprecated = 0;
        struct rtattr * rta_tb[IFA_MAX+1];
        char abuf[256];
        SPRINT_BUF(b1);
@@ -411,8 +489,17 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
        }
        if (ifa->ifa_flags&IFA_F_DEPRECATED) {
                ifa->ifa_flags &= ~IFA_F_DEPRECATED;
+               deprecated = 1;
                fprintf(fp, "deprecated ");
        }
+       if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
+               ifa->ifa_flags &= ~IFA_F_HOMEADDRESS;
+               fprintf(fp, "home ");
+       }
+       if (ifa->ifa_flags&IFA_F_NODAD) {
+               ifa->ifa_flags &= ~IFA_F_NODAD;
+               fprintf(fp, "nodad ");
+       }
        if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
                fprintf(fp, "dynamic ");
        } else
@@ -425,14 +512,20 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
                struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
                char buf[128];
                fprintf(fp, "%s", _SL_);
-               if (ci->ifa_valid == 0xFFFFFFFFU)
+               if (ci->ifa_valid == INFINITY_LIFE_TIME)
                        sprintf(buf, "valid_lft forever");
                else
-                       sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
-               if (ci->ifa_prefered == 0xFFFFFFFFU)
+                       sprintf(buf, "valid_lft %usec", ci->ifa_valid);
+               if (ci->ifa_prefered == INFINITY_LIFE_TIME)
                        sprintf(buf+strlen(buf), " preferred_lft forever");
-               else
-                       sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
+               else {
+                       if (deprecated)
+                               sprintf(buf+strlen(buf), " preferred_lft %dsec",
+                                       ci->ifa_prefered);
+                       else
+                               sprintf(buf+strlen(buf), " preferred_lft %usec",
+                                       ci->ifa_prefered);
+               }
                fprintf(fp, "       %s", buf);
        }
        fprintf(fp, "\n");
@@ -447,7 +540,7 @@ struct nlmsg_list
        struct nlmsghdr   h;
 };
 
-int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
+static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
 {
        for ( ;ainfo ;  ainfo = ainfo->next) {
                struct nlmsghdr *n = &ainfo->h;
@@ -459,7 +552,7 @@ int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
                if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
                        return -1;
 
-               if (ifa->ifa_index != ifindex || 
+               if (ifa->ifa_index != ifindex ||
                    (filter.family && filter.family != ifa->ifa_family))
                        continue;
 
@@ -469,7 +562,7 @@ int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
 }
 
 
-static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, 
+static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                       void *arg)
 {
        struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
@@ -490,7 +583,7 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
        return 0;
 }
 
-int ipaddr_list_or_flush(int argc, char **argv, int flush)
+static int ipaddr_list_or_flush(int argc, char **argv, int flush)
 {
        struct nlmsg_list *linfo = NULL;
        struct nlmsg_list *ainfo = NULL;
@@ -552,6 +645,12 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
                } else if (strcmp(*argv, "deprecated") == 0) {
                        filter.flags |= IFA_F_DEPRECATED;
                        filter.flagmask |= IFA_F_DEPRECATED;
+               } else if (strcmp(*argv, "home") == 0) {
+                       filter.flags |= IFA_F_HOMEADDRESS;
+                       filter.flagmask |= IFA_F_HOMEADDRESS;
+               } else if (strcmp(*argv, "nodad") == 0) {
+                       filter.flags |= IFA_F_NODAD;
+                       filter.flagmask |= IFA_F_NODAD;
                } else if (strcmp(*argv, "label") == 0) {
                        NEXT_ARG();
                        filter.label = *argv;
@@ -594,7 +693,7 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
                filter.flushp = 0;
                filter.flushe = sizeof(flushb);
 
-               for (;;) {
+               while (round < MAX_ROUNDS) {
                        if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
                                perror("Cannot send dump request");
                                exit(1);
@@ -605,10 +704,12 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
                                exit(1);
                        }
                        if (filter.flushed == 0) {
-                               if (round == 0) {
-                                       fprintf(stderr, "Nothing to flush.\n");
-                               } else if (show_stats)
-                                       printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               if (show_stats) {
+                                       if (round == 0)
+                                               printf("Nothing to flush.\n");
+                                       else 
+                                               printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               }
                                fflush(stdout);
                                return 0;
                        }
@@ -621,6 +722,8 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
                                fflush(stdout);
                        }
                }
+               fprintf(stderr, "*** Flush remains incomplete after %d rounds. ***\n", MAX_ROUNDS); fflush(stderr);
+               return 1;
        }
 
        if (filter.family != AF_PACKET) {
@@ -652,7 +755,7 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
                                struct nlmsghdr *n = &a->h;
                                struct ifaddrmsg *ifa = NLMSG_DATA(n);
 
-                               if (ifa->ifa_index != ifi->ifi_index || 
+                               if (ifa->ifa_index != ifi->ifi_index ||
                                    (filter.family && filter.family != ifa->ifa_family))
                                        continue;
                                if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
@@ -722,7 +825,7 @@ void ipaddr_reset_filter(int oneline)
        filter.oneline = oneline;
 }
 
-int default_scope(inet_prefix *lcl)
+static int default_scope(inet_prefix *lcl)
 {
        if (lcl->family == AF_INET) {
                if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
@@ -731,7 +834,7 @@ int default_scope(inet_prefix *lcl)
        return 0;
 }
 
-int ipaddr_modify(int cmd, int argc, char **argv)
+static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
 {
        struct {
                struct nlmsghdr         n;
@@ -741,6 +844,8 @@ int ipaddr_modify(int cmd, int argc, char **argv)
        char  *d = NULL;
        char  *l = NULL;
        char  *lcl_arg = NULL;
+       char  *valid_lftp = NULL;
+       char  *preferred_lftp = NULL;
        inet_prefix lcl;
        inet_prefix peer;
        int local_len = 0;
@@ -748,11 +853,14 @@ int ipaddr_modify(int cmd, int argc, char **argv)
        int brd_len = 0;
        int any_len = 0;
        int scoped = 0;
+       __u32 preferred_lft = INFINITY_LIFE_TIME;
+       __u32 valid_lft = INFINITY_LIFE_TIME;
+       struct ifa_cacheinfo cinfo;
 
        memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_flags = NLM_F_REQUEST | flags;
        req.n.nlmsg_type = cmd;
        req.ifa.ifa_family = preferred_family;
 
@@ -810,6 +918,24 @@ int ipaddr_modify(int cmd, int argc, char **argv)
                        NEXT_ARG();
                        l = *argv;
                        addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
+               } else if (matches(*argv, "valid_lft") == 0) {
+                       if (valid_lftp)
+                               duparg("valid_lft", *argv);
+                       NEXT_ARG();
+                       valid_lftp = *argv;
+                       if (set_lifetime(&valid_lft, *argv))
+                               invarg("valid_lft value", *argv);
+               } else if (matches(*argv, "preferred_lft") == 0) {
+                       if (preferred_lftp)
+                               duparg("preferred_lft", *argv);
+                       NEXT_ARG();
+                       preferred_lftp = *argv;
+                       if (set_lifetime(&preferred_lft, *argv))
+                               invarg("preferred_lft value", *argv);
+               } else if (strcmp(*argv, "home") == 0) {
+                       req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
+               } else if (strcmp(*argv, "nodad") == 0) {
+                       req.ifa.ifa_flags |= IFA_F_NODAD;
                } else {
                        if (strcmp(*argv, "local") == 0) {
                                NEXT_ARG();
@@ -880,6 +1006,23 @@ int ipaddr_modify(int cmd, int argc, char **argv)
                return -1;
        }
 
+       if (valid_lftp || preferred_lftp) {
+               if (!valid_lft) {
+                       fprintf(stderr, "valid_lft is zero\n");
+                       return -1;
+               }
+               if (valid_lft < preferred_lft) {
+                       fprintf(stderr, "preferred_lft is greater than valid_lft\n");
+                       return -1;
+               }
+
+               memset(&cinfo, 0, sizeof(cinfo));
+               cinfo.ifa_prefered = preferred_lft;
+               cinfo.ifa_valid = valid_lft;
+               addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
+                         sizeof(cinfo));
+       }
+
        if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
                exit(2);
 
@@ -891,9 +1034,14 @@ int do_ipaddr(int argc, char **argv)
        if (argc < 1)
                return ipaddr_list_or_flush(0, NULL, 0);
        if (matches(*argv, "add") == 0)
-               return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
+               return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+       if (matches(*argv, "change") == 0 ||
+               strcmp(*argv, "chg") == 0)
+               return ipaddr_modify(RTM_NEWADDR, NLM_F_REPLACE, argc-1, argv+1);
+       if (matches(*argv, "replace") == 0)
+               return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
        if (matches(*argv, "delete") == 0)
-               return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
+               return ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1);
        if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
            || matches(*argv, "lst") == 0)
                return ipaddr_list_or_flush(argc-1, argv+1, 0);
@@ -901,7 +1049,7 @@ int do_ipaddr(int argc, char **argv)
                return ipaddr_list_or_flush(argc-1, argv+1, 1);
        if (matches(*argv, "help") == 0)
                usage();
-       fprintf(stderr, "Command \"%s\" is unknown, try \"ip address help\".\n", *argv);
+       fprintf(stderr, "Command \"%s\" is unknown, try \"ip addr help\".\n", *argv);
        exit(-1);
 }
 
diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
new file mode 100644 (file)
index 0000000..cf438d6
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * ipaddrlabel.c       "ip addrlabel"
+ *
+ * Copyright (C)2007 USAGI/WIDE Project
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * Based on iprule.c.
+ *
+ * Authors:    YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/types.h>
+#include <linux/if_addrlabel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define IFAL_RTA(r)    ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
+#define IFAL_PAYLOAD(n)        NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
+
+extern struct rtnl_handle rth;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
+       exit(-1);
+}
+
+int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       int host_len = -1;
+       struct rtattr *tb[IFAL_MAX+1];
+       char abuf[256];
+
+       if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
+               return 0;
+
+       len -= NLMSG_LENGTH(sizeof(*ifal));
+       if (len < 0)
+               return -1;
+
+       parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
+
+       if (ifal->ifal_family == AF_INET)
+               host_len = 32;
+       else if (ifal->ifal_family == AF_INET6)
+               host_len = 128;
+
+       if (n->nlmsg_type == RTM_DELADDRLABEL)
+               fprintf(fp, "Deleted ");
+
+       if (tb[IFAL_ADDRESS]) {
+               fprintf(fp, "prefix %s/%u ",
+                       format_host(ifal->ifal_family,
+                                   RTA_PAYLOAD(tb[IFAL_ADDRESS]),
+                                   RTA_DATA(tb[IFAL_ADDRESS]),
+                                   abuf, sizeof(abuf)),
+                       ifal->ifal_prefixlen);
+       }
+
+       if (ifal->ifal_index)
+               fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
+
+       if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
+               int32_t label;
+               memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
+               fprintf(fp, "label %d ", label);
+       }
+
+       fprintf(fp, "\n");
+       fflush(fp);
+       return 0;
+}
+
+static int ipaddrlabel_list(int argc, char **argv)
+{
+       int af = preferred_family;
+
+       if (af == AF_UNSPEC)
+               af = AF_INET6;
+
+       if (argc > 0) {
+               fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
+               return -1;
+       }
+
+       if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+               perror("Cannot send dump request");
+               return 1;
+       }
+
+       if (rtnl_dump_filter(&rth, print_addrlabel, stdout, NULL, NULL) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static int ipaddrlabel_modify(int cmd, int argc, char **argv)
+{
+       struct {
+               struct nlmsghdr         n;
+               struct ifaddrlblmsg     ifal;
+               char                    buf[1024];
+       } req;
+
+       inet_prefix prefix;
+       uint32_t label = 0xffffffffUL;
+       char *p = NULL;
+       char *l = NULL;        
+
+       memset(&req, 0, sizeof(req));
+       memset(&prefix, 0, sizeof(prefix));
+
+       req.n.nlmsg_type = cmd;
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.ifal.ifal_family = preferred_family;
+       req.ifal.ifal_prefixlen = 0;
+       req.ifal.ifal_index = 0;
+
+       if (cmd == RTM_NEWADDRLABEL) {
+               req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+       }
+
+       while (argc > 0) {
+               if (strcmp(*argv, "prefix") == 0) {
+                       NEXT_ARG();
+                       p = *argv;
+                       get_prefix(&prefix, *argv, preferred_family);
+               } else if (strcmp(*argv, "dev") == 0) {
+                       NEXT_ARG();
+                       if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
+                               invarg("dev is invalid\n", *argv);
+               } else if (strcmp(*argv, "label") == 0) {
+                       NEXT_ARG();
+                       l = *argv;
+                       if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
+                               invarg("label is invalid\n", *argv);
+               }
+               argc--;
+               argv++;
+       }
+       if (p == NULL) {
+               fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
+               return -1;
+       }
+       if (l == NULL) {
+               fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
+               return -1;
+       }
+       addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
+       addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
+       req.ifal.ifal_prefixlen = prefix.bitlen;
+
+       if (req.ifal.ifal_family == AF_UNSPEC)
+               req.ifal.ifal_family = AF_INET6;
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+               return 2;
+
+       return 0;
+}
+
+
+static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+       struct rtnl_handle rth2;
+       struct rtmsg *r = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr * tb[IFAL_MAX+1];
+
+       len -= NLMSG_LENGTH(sizeof(*r));
+       if (len < 0)
+               return -1;
+
+       parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
+
+       if (tb[IFAL_ADDRESS]) {
+               n->nlmsg_type = RTM_DELADDRLABEL;
+               n->nlmsg_flags = NLM_F_REQUEST;
+
+               if (rtnl_open(&rth2, 0) < 0)
+                       return -1;
+
+               if (rtnl_talk(&rth2, n, 0, 0, NULL, NULL, NULL) < 0)
+                       return -2;
+
+               rtnl_close(&rth2);
+       }
+
+       return 0;
+}
+
+static int ipaddrlabel_flush(int argc, char **argv)
+{
+       int af = preferred_family;
+
+       if (af == AF_UNSPEC)
+               af = AF_INET6;
+
+       if (argc > 0) {
+               fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
+               return -1;
+       }
+
+       if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+               perror("Cannot send dump request");
+               return 1;
+       }
+
+       if (rtnl_dump_filter(&rth, flush_addrlabel, NULL, NULL, NULL) < 0) {
+               fprintf(stderr, "Flush terminated\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+int do_ipaddrlabel(int argc, char **argv)
+{
+       if (argc < 1) {
+               return ipaddrlabel_list(0, NULL);
+       } else if (matches(argv[0], "list") == 0 ||
+                  matches(argv[0], "show") == 0) {
+               return ipaddrlabel_list(argc-1, argv+1);
+       } else if (matches(argv[0], "add") == 0) {
+               return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
+       } else if (matches(argv[0], "delete") == 0) {
+               return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
+       } else if (matches(argv[0], "flush") == 0) {
+               return ipaddrlabel_flush(argc-1, argv+1);
+       } else if (matches(argv[0], "help") == 0)
+               usage();
+
+       fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
+       exit(-1);
+}
+
index ffc9f06..fd23db1 100644 (file)
@@ -15,6 +15,7 @@
 #include <unistd.h>
 #include <syslog.h>
 #include <fcntl.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <linux/if.h>
 #include "utils.h"
 #include "ip_common.h"
 
+#define IPLINK_IOCTL_COMPAT    1
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
 
 static void usage(void) __attribute__((noreturn));
+static int iplink_have_newlink(void);
 
 void iplink_usage(void)
 {
-       fprintf(stderr, "Usage: ip link set DEVICE { up | down |\n");
-       fprintf(stderr, "                            arp { on | off } |\n");
-       fprintf(stderr, "                            dynamic { on | off } |\n");
-       fprintf(stderr, "                            multicast { on | off } |\n");
-       fprintf(stderr, "                            allmulticast { on | off } |\n");
-       fprintf(stderr, "                            promisc { on | off } |\n");
-       fprintf(stderr, "                            trailers { on | off } |\n");
-       fprintf(stderr, "                            txqueuelen PACKETS |\n");
-       fprintf(stderr, "                            name NEWNAME |\n");
-       fprintf(stderr, "                            address LLADDR | broadcast LLADDR |\n");
-       fprintf(stderr, "                            mtu MTU }\n");
+       if (iplink_have_newlink()) {
+               fprintf(stderr, "Usage: ip link add link DEV [ name ] NAME\n");
+               fprintf(stderr, "                   [ txqueuelen PACKETS ]\n");
+               fprintf(stderr, "                   [ address LLADDR ]\n");
+               fprintf(stderr, "                   [ broadcast LLADDR ]\n");
+               fprintf(stderr, "                   [ mtu MTU ]\n");
+               fprintf(stderr, "                   type TYPE [ ARGS ]\n");
+               fprintf(stderr, "       ip link delete DEV type TYPE [ ARGS ]\n");
+               fprintf(stderr, "\n");
+               fprintf(stderr, "       ip link set DEVICE [ { up | down } ]\n");
+       } else
+               fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
+
+       fprintf(stderr, "                         [ arp { on | off } ]\n");
+       fprintf(stderr, "                         [ dynamic { on | off } ]\n");
+       fprintf(stderr, "                         [ multicast { on | off } ]\n");
+       fprintf(stderr, "                         [ allmulticast { on | off } ]\n");
+       fprintf(stderr, "                         [ promisc { on | off } ]\n");
+       fprintf(stderr, "                         [ trailers { on | off } ]\n");
+       fprintf(stderr, "                         [ txqueuelen PACKETS ]\n");
+       fprintf(stderr, "                         [ name NEWNAME ]\n");
+       fprintf(stderr, "                         [ address LLADDR ]\n");
+       fprintf(stderr, "                         [ broadcast LLADDR ]\n");
+       fprintf(stderr, "                         [ mtu MTU ]\n");
+       fprintf(stderr, "                         [ netns PID ]\n");
        fprintf(stderr, "       ip link show [ DEVICE ]\n");
+
+       if (iplink_have_newlink()) {
+               fprintf(stderr, "\n");
+               fprintf(stderr, "TYPE := { vlan | veth | dummy | ifb | macvlan }\n");
+       }
        exit(-1);
 }
 
@@ -62,6 +87,326 @@ static int on_off(char *msg)
        return -1;
 }
 
+static void *BODY;             /* cached dlopen(NULL) handle */
+static struct link_util *linkutil_list;
+
+struct link_util *get_link_kind(const char *id)
+{
+       void *dlh;
+       char buf[256];
+       struct link_util *l;
+
+       for (l = linkutil_list; l; l = l->next)
+               if (strcmp(l->id, id) == 0)
+                       return l;
+
+       snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
+       dlh = dlopen(buf, RTLD_LAZY);
+       if (dlh == NULL) {
+               /* look in current binary, only open once */
+               dlh = BODY;
+               if (dlh == NULL) {
+                       dlh = BODY = dlopen(NULL, RTLD_LAZY);
+                       if (dlh == NULL)
+                               return NULL;
+               }
+       }
+
+       snprintf(buf, sizeof(buf), "%s_link_util", id);
+       l = dlsym(dlh, buf);
+       if (l == NULL)
+               return NULL;
+
+       l->next = linkutil_list;
+       linkutil_list = l;
+       return l;
+}
+
+#if IPLINK_IOCTL_COMPAT
+static int have_rtnl_newlink = -1;
+
+static int accept_msg(const struct sockaddr_nl *who,
+                     struct nlmsghdr *n, void *arg)
+{
+       struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+
+       if (n->nlmsg_type == NLMSG_ERROR &&
+           (err->error == -EOPNOTSUPP || err->error == -EINVAL))
+               have_rtnl_newlink = 0;
+       else
+               have_rtnl_newlink = 1;
+       return -1;
+}
+
+static int iplink_have_newlink(void)
+{
+       struct {
+               struct nlmsghdr         n;
+               struct ifinfomsg        i;
+               char                    buf[1024];
+       } req;
+
+       if (have_rtnl_newlink < 0) {
+               memset(&req, 0, sizeof(req));
+
+               req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+               req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+               req.n.nlmsg_type = RTM_NEWLINK;
+               req.i.ifi_family = AF_UNSPEC;
+
+               rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
+               rtnl_listen(&rth, accept_msg, NULL);
+       }
+       return have_rtnl_newlink;
+}
+#else /* IPLINK_IOCTL_COMPAT */
+static int iplink_have_newlink(void)
+{
+       return 1;
+}
+#endif /* ! IPLINK_IOCTL_COMPAT */
+
+struct iplink_req {
+       struct nlmsghdr         n;
+       struct ifinfomsg        i;
+       char                    buf[1024];
+};
+
+int iplink_parse(int argc, char **argv, struct iplink_req *req,
+               char **name, char **type, char **link, char **dev)
+{
+       int ret, len;
+       char abuf[32];
+       int qlen = -1;
+       int mtu = -1;
+       int netns = -1;
+
+       ret = argc;
+
+       while (argc > 0) {
+               if (strcmp(*argv, "up") == 0) {
+                       req->i.ifi_change |= IFF_UP;
+                       req->i.ifi_flags |= IFF_UP;
+               } else if (strcmp(*argv, "down") == 0) {
+                       req->i.ifi_change |= IFF_UP;
+                       req->i.ifi_flags &= ~IFF_UP;
+               } else if (strcmp(*argv, "name") == 0) {
+                       NEXT_ARG();
+                       *name = *argv;
+               } else if (matches(*argv, "link") == 0) {
+                       NEXT_ARG();
+                       *link = *argv;
+               } else if (matches(*argv, "address") == 0) {
+                       NEXT_ARG();
+                       len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
+                       addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
+               } else if (matches(*argv, "broadcast") == 0 ||
+                               strcmp(*argv, "brd") == 0) {
+                       NEXT_ARG();
+                       len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
+                       addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
+               } else if (matches(*argv, "txqueuelen") == 0 ||
+                               strcmp(*argv, "qlen") == 0 ||
+                               matches(*argv, "txqlen") == 0) {
+                       NEXT_ARG();
+                       if (qlen != -1)
+                               duparg("txqueuelen", *argv);
+                       if (get_integer(&qlen,  *argv, 0))
+                               invarg("Invalid \"txqueuelen\" value\n", *argv);
+                       addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
+               } else if (strcmp(*argv, "mtu") == 0) {
+                       NEXT_ARG();
+                       if (mtu != -1)
+                               duparg("mtu", *argv);
+                       if (get_integer(&mtu, *argv, 0))
+                               invarg("Invalid \"mtu\" value\n", *argv);
+                       addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
+                } else if (strcmp(*argv, "netns") == 0) {
+                        NEXT_ARG();
+                        if (netns != -1)
+                                duparg("netns", *argv);
+                        if (get_integer(&netns, *argv, 0))
+                                invarg("Invalid \"netns\" value\n", *argv);
+                        addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
+               } else if (strcmp(*argv, "multicast") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_MULTICAST;
+                       if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags |= IFF_MULTICAST;
+                       } else if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags &= ~IFF_MULTICAST;
+                       } else
+                               return on_off("multicast");
+               } else if (strcmp(*argv, "allmulticast") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_ALLMULTI;
+                       if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags |= IFF_ALLMULTI;
+                       } else if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags &= ~IFF_ALLMULTI;
+                       } else
+                               return on_off("allmulticast");
+               } else if (strcmp(*argv, "promisc") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_PROMISC;
+                       if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags |= IFF_PROMISC;
+                       } else if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags &= ~IFF_PROMISC;
+                       } else
+                               return on_off("promisc");
+               } else if (strcmp(*argv, "trailers") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_NOTRAILERS;
+                       if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags |= IFF_NOTRAILERS;
+                       } else if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags &= ~IFF_NOTRAILERS;
+                       } else
+                               return on_off("trailers");
+               } else if (strcmp(*argv, "arp") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_NOARP;
+                       if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags &= ~IFF_NOARP;
+                       } else if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags |= IFF_NOARP;
+                       } else
+                               return on_off("noarp");
+#ifdef IFF_DYNAMIC
+               } else if (matches(*argv, "dynamic") == 0) {
+                       NEXT_ARG();
+                       req->i.ifi_change |= IFF_DYNAMIC;
+                       if (strcmp(*argv, "on") == 0) {
+                               req->i.ifi_flags |= IFF_DYNAMIC;
+                       } else if (strcmp(*argv, "off") == 0) {
+                               req->i.ifi_flags &= ~IFF_DYNAMIC;
+                       } else
+                               return on_off("dynamic");
+#endif
+               } else if (matches(*argv, "type") == 0) {
+                       NEXT_ARG();
+                       *type = *argv;
+                       argc--; argv++;
+                       break;
+               } else {
+                       if (strcmp(*argv, "dev") == 0) {
+                               NEXT_ARG();
+                       }
+                       if (matches(*argv, "help") == 0)
+                               usage();
+                       if (*dev)
+                               duparg2("dev", *argv);
+                       *dev = *argv;
+               }
+               argc--; argv++;
+       }
+
+       return ret - argc;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+       int len;
+       char *dev = NULL;
+       char *name = NULL;
+       char *link = NULL;
+       char *type = NULL;
+       struct link_util *lu = NULL;
+       struct iplink_req req;
+       int ret;
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+       req.n.nlmsg_type = cmd;
+       req.i.ifi_family = preferred_family;
+
+       ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev);
+       if (ret < 0)
+               return ret;
+
+       argc -= ret;
+       argv += ret;
+       ll_init_map(&rth);
+
+       if (type) {
+               struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
+               addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
+               addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
+                        strlen(type));
+
+               lu = get_link_kind(type);
+               if (lu && argc) {
+                       struct rtattr * data = NLMSG_TAIL(&req.n);
+                       addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
+
+                       if (lu->parse_opt &&
+                           lu->parse_opt(lu, argc, argv, &req.n))
+                               return -1;
+
+                       data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+               } else if (argc) {
+                       if (matches(*argv, "help") == 0)
+                               usage();
+                       fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
+                                       "Try \"ip link help\".\n", *argv);
+                       return -1;
+               }
+               linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
+       } else if (flags & NLM_F_CREATE) {
+               fprintf(stderr, "Not enough information: \"type\" argument "
+                               "is required\n");
+               return -1;
+       }
+
+       if (!(flags & NLM_F_CREATE)) {
+               if (!dev) {
+                       fprintf(stderr, "Not enough information: \"dev\" "
+                                       "argument is required.\n");
+                       exit(-1);
+               }
+
+               req.i.ifi_index = ll_name_to_index(dev);
+               if (req.i.ifi_index == 0) {
+                       fprintf(stderr, "Cannot find device \"%s\"\n", dev);
+                       return -1;
+               }
+       } else {
+               /* Allow "ip link add dev" and "ip link add name" */
+               if (!name)
+                       name = dev;
+
+               if (link) {
+                       int ifindex;
+
+                       ifindex = ll_name_to_index(link);
+                       if (ifindex == 0) {
+                               fprintf(stderr, "Cannot find device \"%s\"\n",
+                                       link);
+                               return -1;
+                       }
+                       addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+               }
+       }
+
+       if (name) {
+               len = strlen(name) + 1;
+               if (len == 1)
+                       invarg("\"\" is not a valid device identifier\n", "name");
+               if (len > IFNAMSIZ)
+                       invarg("\"name\" too long\n", name);
+               addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
+       }
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+               exit(2);
+
+       return 0;
+}
+
+#if IPLINK_IOCTL_COMPAT
 static int get_ctl_fd(void)
 {
        int s_errno;
@@ -140,8 +485,8 @@ static int set_qlen(const char *dev, int qlen)
                return -1;
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ); 
-       ifr.ifr_qlen = qlen; 
+       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       ifr.ifr_qlen = qlen;
        if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
                perror("SIOCSIFXQLEN");
                close(s);
@@ -149,7 +494,7 @@ static int set_qlen(const char *dev, int qlen)
        }
        close(s);
 
-       return 0; 
+       return 0;
 }
 
 static int set_mtu(const char *dev, int mtu)
@@ -162,8 +507,8 @@ static int set_mtu(const char *dev, int mtu)
                return -1;
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ); 
-       ifr.ifr_mtu = mtu; 
+       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       ifr.ifr_mtu = mtu;
        if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
                perror("SIOCSIFMTU");
                close(s);
@@ -171,7 +516,7 @@ static int set_mtu(const char *dev, int mtu)
        }
        close(s);
 
-       return 0; 
+       return 0;
 }
 
 static int get_address(const char *dev, int *htype)
@@ -182,7 +527,7 @@ static int get_address(const char *dev, int *htype)
        int s;
 
        s = socket(PF_PACKET, SOCK_DGRAM, 0);
-       if (s < 0) { 
+       if (s < 0) {
                perror("socket(PF_PACKET)");
                return -1;
        }
@@ -216,7 +561,7 @@ static int get_address(const char *dev, int *htype)
        return me.sll_halen;
 }
 
-static int parse_address(const char *dev, int hatype, int halen, 
+static int parse_address(const char *dev, int hatype, int halen,
                char *lla, struct ifreq *ifr)
 {
        int alen;
@@ -231,7 +576,7 @@ static int parse_address(const char *dev, int hatype, int halen,
                fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
                return -1;
        }
-       return 0; 
+       return 0;
 }
 
 static int set_address(struct ifreq *ifr, int brd)
@@ -247,7 +592,7 @@ static int set_address(struct ifreq *ifr, int brd)
                return -1;
        }
        close(s);
-       return 0; 
+       return 0;
 }
 
 
@@ -379,27 +724,29 @@ static int do_set(int argc, char **argv)
                }
                if (newbrd) {
                        if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
-                               return -1; 
+                               return -1;
                }
        }
 
        if (newname && strcmp(dev, newname)) {
+               if (strlen(newname) == 0)
+                       invarg("\"\" is not a valid device identifier\n", "name");
                if (do_changename(dev, newname) < 0)
                        return -1;
                dev = newname;
        }
-       if (qlen != -1) { 
+       if (qlen != -1) {
                if (set_qlen(dev, qlen) < 0)
-                       return -1; 
+                       return -1;
        }
-       if (mtu != -1) { 
+       if (mtu != -1) {
                if (set_mtu(dev, mtu) < 0)
-                       return -1; 
+                       return -1;
        }
        if (newaddr || newbrd) {
                if (newbrd) {
                        if (set_address(&ifr1, 1) < 0)
-                               return -1; 
+                               return -1;
                }
                if (newaddr) {
                        if (set_address(&ifr0, 0) < 0)
@@ -410,12 +757,33 @@ static int do_set(int argc, char **argv)
                return do_chflags(dev, flags, mask);
        return 0;
 }
+#endif /* IPLINK_IOCTL_COMPAT */
 
 int do_iplink(int argc, char **argv)
 {
        if (argc > 0) {
-               if (matches(*argv, "set") == 0)
-                       return do_set(argc-1, argv+1);
+               if (iplink_have_newlink()) {
+                       if (matches(*argv, "add") == 0)
+                               return iplink_modify(RTM_NEWLINK,
+                                                    NLM_F_CREATE|NLM_F_EXCL,
+                                                    argc-1, argv+1);
+                       if (matches(*argv, "set") == 0 ||
+                           matches(*argv, "change") == 0)
+                               return iplink_modify(RTM_NEWLINK, 0,
+                                                    argc-1, argv+1);
+                       if (matches(*argv, "replace") == 0)
+                               return iplink_modify(RTM_NEWLINK,
+                                                    NLM_F_CREATE|NLM_F_REPLACE,
+                                                    argc-1, argv+1);
+                       if (matches(*argv, "delete") == 0)
+                               return iplink_modify(RTM_DELLINK, 0,
+                                                    argc-1, argv+1);
+               } else {
+#if IPLINK_IOCTL_COMPAT
+                       if (matches(*argv, "set") == 0)
+                               return do_set(argc-1, argv+1);
+#endif
+               }
                if (matches(*argv, "show") == 0 ||
                    matches(*argv, "lst") == 0 ||
                    matches(*argv, "list") == 0)
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
new file mode 100644 (file)
index 0000000..9724482
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * iplink_vlan.c       VLAN device support
+ *
+ *              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.
+ *
+ * Authors:     Patrick McHardy <kaber@trash.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/if_vlan.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+       fprintf(stderr,
+               "Usage: ... vlan id VLANID [ FLAG-LIST ]\n"
+               "                          [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
+               "\n"
+               "VLANID := 0-4095\n"
+               "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
+               "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+               "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
+               "QOS-MAPPING := FROM:TO\n"
+       );
+}
+
+static int on_off(char *msg)
+{
+       fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
+       return -1;
+}
+
+static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
+                             int attrtype)
+{
+       int argc = *argcp;
+       char **argv = *argvp;
+       struct ifla_vlan_qos_mapping m;
+       struct rtattr *tail;
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, 1024, attrtype, NULL, 0);
+
+       while (argc > 0) {
+               char *colon = strchr(*argv, ':');
+
+               if (!colon)
+                       break;
+               *colon = '\0';
+
+               if (get_u32(&m.from, *argv, 0))
+                       return 1;
+               if (get_u32(&m.to, colon + 1, 0))
+                       return 1;
+               argc--, argv++;
+
+               addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
+       }
+
+       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+
+       *argcp = argc;
+       *argvp = argv;
+       return 0;
+}
+
+static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
+                         struct nlmsghdr *n)
+{
+       struct ifla_vlan_flags flags = { 0 };
+       __u16 id;
+
+       while (argc > 0) {
+               if (matches(*argv, "id") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&id, *argv, 0))
+                               invarg("id is invalid", *argv);
+                       addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
+               } else if (matches(*argv, "reorder_hdr") == 0) {
+                       NEXT_ARG();
+                       flags.mask |= VLAN_FLAG_REORDER_HDR;
+                       if (strcmp(*argv, "on") == 0)
+                               flags.flags |= VLAN_FLAG_REORDER_HDR;
+                       else if (strcmp(*argv, "off") == 0)
+                               flags.flags &= ~VLAN_FLAG_REORDER_HDR;
+                       else
+                               return on_off("reorder_hdr");
+               } else if (matches(*argv, "gvrp") == 0) {
+                       NEXT_ARG();
+                       flags.mask |= VLAN_FLAG_GVRP;
+                       if (strcmp(*argv, "on") == 0)
+                               flags.flags |= VLAN_FLAG_GVRP;
+                       else if (strcmp(*argv, "off") == 0)
+                               flags.flags &= ~VLAN_FLAG_GVRP;
+                       else
+                               return on_off("gvrp");
+               } else if (matches(*argv, "ingress-qos-map") == 0) {
+                       NEXT_ARG();
+                       if (vlan_parse_qos_map(&argc, &argv, n,
+                                              IFLA_VLAN_INGRESS_QOS))
+                               invarg("invalid ingress-qos-map", *argv);
+                       continue;
+               } else if (matches(*argv, "egress-qos-map") == 0) {
+                       NEXT_ARG();
+                       if (vlan_parse_qos_map(&argc, &argv, n,
+                                              IFLA_VLAN_EGRESS_QOS))
+                               invarg("invalid egress-qos-map", *argv);
+                       continue;
+               } else if (matches(*argv, "help") == 0) {
+                       explain();
+                       return -1;
+               } else {
+                       fprintf(stderr, "vlan: what is \"%s\"?\n", *argv);
+                       explain();
+                       return -1;
+               }
+               argc--, argv++;
+       }
+
+       if (flags.mask)
+               addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+
+       return 0;
+}
+
+static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+{
+       struct ifla_vlan_qos_mapping *m;
+       struct rtattr *i;
+       int rem;
+
+       fprintf(f, "\n      %s { ", name);
+
+       rem = RTA_PAYLOAD(attr);
+       for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+               m = RTA_DATA(i);
+               fprintf(f, "%u:%u ", m->from, m->to);
+       }
+       fprintf(f, "} ");
+}
+
+static void vlan_print_flags(FILE *fp, __u32 flags)
+{
+       fprintf(fp, "<");
+#define _PF(f) if (flags & VLAN_FLAG_##f) { \
+                       flags &= ~ VLAN_FLAG_##f; \
+                       fprintf(fp, #f "%s", flags ? "," : ""); \
+               }
+       _PF(REORDER_HDR);
+       _PF(GVRP);
+#undef _PF
+       if (flags)
+               fprintf(fp, "%x", flags);
+       fprintf(fp, "> ");
+}
+
+static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+       struct ifla_vlan_flags *flags;
+       if (!tb)
+               return;
+
+       if (!tb[IFLA_VLAN_ID] ||
+           RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
+               return;
+
+       fprintf(f, "id %u ", *(__u16 *)RTA_DATA(tb[IFLA_VLAN_ID]));
+
+       if (tb[IFLA_VLAN_FLAGS]) {
+               if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
+                       return;
+               flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
+               vlan_print_flags(f, flags->flags);
+       }
+       if (tb[IFLA_VLAN_INGRESS_QOS])
+               vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+       if (tb[IFLA_VLAN_EGRESS_QOS])
+               vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+}
+
+struct link_util vlan_link_util = {
+       .id             = "vlan",
+       .maxattr        = IFLA_VLAN_MAX,
+       .parse_opt      = vlan_parse_opt,
+       .print_opt      = vlan_print_opt,
+};
index e6bd625..44ffdfc 100644 (file)
@@ -43,11 +43,11 @@ static void usage(void)
        exit(-1);
 }
 
-static int parse_hex(char *str, unsigned char *addr)
+static int parse_hex(char *str, unsigned char *addr, size_t size)
 {
        int len=0;
 
-       while (*str) {
+       while (*str && (len < 2 * size)) {
                int tmp;
                if (str[1] == 0)
                        return -1;
@@ -104,7 +104,7 @@ void read_dev_mcast(struct ma_info **result_p)
 
                m.addr.family = AF_PACKET;
 
-               len = parse_hex(hexa, (unsigned char*)&m.addr.data);
+               len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data));
                if (len >= 0) {
                        struct ma_info *ma = malloc(sizeof(m));
 
@@ -176,7 +176,7 @@ void read_igmp6(struct ma_info **result_p)
 
                m.addr.family = AF_INET6;
 
-               len = parse_hex(hexa, (unsigned char*)&m.addr.data);
+               len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data));
                if (len >= 0) {
                        struct ma_info *ma = malloc(sizeof(m));
 
@@ -212,7 +212,7 @@ static void print_maddr(FILE *fp, struct ma_info *list)
                        fprintf(fp, "family %d ", list->addr.family);
                        break;
                }
-               fprintf(fp, "%s", 
+               fprintf(fp, "%s",
                        format_host(list->addr.family,
                                    -1,
                                    list->addr.data,
@@ -298,7 +298,7 @@ int multiaddr_modify(int cmd, int argc, char **argv)
                                usage();
                        if (ifr.ifr_hwaddr.sa_data[0])
                                duparg("address", *argv);
-                       if (ll_addr_a2n(ifr.ifr_hwaddr.sa_data, 
+                       if (ll_addr_a2n(ifr.ifr_hwaddr.sa_data,
                                        14, *argv) < 0) {
                                fprintf(stderr, "Error: \"%s\" is not a legal ll address.\n", *argv);
                                exit(1);
index 50b6327..df0fd91 100644 (file)
@@ -54,6 +54,10 @@ int accept_msg(const struct sockaddr_nl *who,
                print_addrinfo(who, n, arg);
                return 0;
        }
+       if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
+               print_addrlabel(who, n, arg);
+               return 0;
+       }
        if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH) {
                print_neigh(who, n, arg);
                return 0;
@@ -62,6 +66,10 @@ int accept_msg(const struct sockaddr_nl *who,
                print_prefix(who, n, arg);
                return 0;
        }
+       if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
+               print_rule(who, n, arg);
+               return 0;
+       }
        if (n->nlmsg_type == 15) {
                char *tstr;
                time_t secs = ((__u32*)NLMSG_DATA(n))[0];
@@ -128,22 +136,22 @@ int do_ipmonitor(int argc, char **argv)
        }
 
        if (llink)
-               groups |= RTMGRP_LINK;
+               groups |= nl_mgrp(RTNLGRP_LINK);
        if (laddr) {
                if (!preferred_family || preferred_family == AF_INET)
-                       groups |= RTMGRP_IPV4_IFADDR;
+                       groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
                if (!preferred_family || preferred_family == AF_INET6)
-                       groups |= RTMGRP_IPV6_IFADDR;
+                       groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
        }
        if (lroute) {
                if (!preferred_family || preferred_family == AF_INET)
-                       groups |= RTMGRP_IPV4_ROUTE;
+                       groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
                if (!preferred_family || preferred_family == AF_INET6)
-                       groups |= RTMGRP_IPV6_ROUTE;
+                       groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
        }
        if (lprefix) {
                if (!preferred_family || preferred_family == AF_INET6)
-                       groups |= RTMGRP_IPV6_PREFIX;
+                       groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
        }
 
        if (file) {
index 951a54f..8f4b061 100644 (file)
@@ -66,7 +66,7 @@ static void read_viftable(void)
 
                if (sscanf(buf, "%d%s", &vifi, dev) < 2)
                        continue;
-               
+
                if (vifi<0 || vifi>31)
                        continue;
 
@@ -109,7 +109,7 @@ static void read_mroute_list(FILE *ofp)
                if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen))
                        continue;
 
-               snprintf(obuf, sizeof(obuf), "(%s, %s)", 
+               snprintf(obuf, sizeof(obuf), "(%s, %s)",
                         format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)),
                         format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf)));
 
index 249ee68..30c7c72 100644 (file)
@@ -21,7 +21,6 @@
 #include <fcntl.h>
 #include <string.h>
 #include <sys/time.h>
-#include <net/if.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
@@ -88,8 +87,8 @@ int nud_state_a2n(unsigned *state, char *arg)
 
 static int flush_update(void)
 {
-       if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) {
-               perror("Failed to send flush request\n");
+       if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+               perror("Failed to send flush request");
                return -1;
        }
        filter.flushp = 0;
@@ -197,7 +196,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
                fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-               
+
                return 0;
        }
        len -= NLMSG_LENGTH(sizeof(*r));
@@ -254,7 +253,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        }
 
        if (tb[NDA_DST]) {
-               fprintf(fp, "%s ", 
+               fprintf(fp, "%s ",
                        format_host(r->ndm_family,
                                    RTA_PAYLOAD(tb[NDA_DST]),
                                    RTA_DATA(tb[NDA_DST]),
@@ -273,10 +272,9 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                fprintf(fp, " router");
        }
        if (tb[NDA_CACHEINFO] && show_stats) {
-               static int hz;
                struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
-               if (!hz)
-                       hz = get_hz();
+               int hz = get_user_hz();
+
                if (ci->ndm_refcnt)
                        printf(" ref %d", ci->ndm_refcnt);
                fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
@@ -404,10 +402,12 @@ int do_show_or_flush(int argc, char **argv, int flush)
                                exit(1);
                        }
                        if (filter.flushed == 0) {
-                               if (round == 0) {
-                                       fprintf(stderr, "Nothing to flush.\n");
-                               } else if (show_stats)
-                                       printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               if (show_stats) {
+                                       if (round == 0)
+                                               printf("Nothing to flush.\n");
+                                       else
+                                               printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               }
                                fflush(stdout);
                                return 0;
                        }
index 5655d93..141ad42 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * Copyright (C)2006 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
index 61d12f9..cb1f582 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * Copyright (C)2005 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -78,7 +78,7 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]);
 
                memset(abuf, '\0', sizeof(abuf));
-               fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*pfx), pfx, 
+               fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*pfx), pfx,
                                              abuf, sizeof(abuf)));
        }
        fprintf(fp, "/%u ", prefix->prefix_len);
index a43c09e..6a2ea05 100644 (file)
@@ -28,7 +28,6 @@
 #include <netinet/ip.h>
 #include <arpa/inet.h>
 #include <linux/in_route.h>
-#include <linux/ip_mp_alg.h>
 
 #include "rt_names.h"
 #include "utils.h"
 #endif
 
 
+static const char *mx_names[RTAX_MAX+1] = {
+       [RTAX_MTU]      = "mtu",
+       [RTAX_WINDOW]   = "window",
+       [RTAX_RTT]      = "rtt",
+       [RTAX_RTTVAR]   = "rttvar",
+       [RTAX_SSTHRESH] = "ssthresh",
+       [RTAX_CWND]     = "cwnd",
+       [RTAX_ADVMSS]   = "advmss",
+       [RTAX_REORDERING]="reordering",
+       [RTAX_HOPLIMIT] = "hoplimit",
+       [RTAX_INITCWND] = "initcwnd",
+       [RTAX_FEATURES] = "features",
+       [RTAX_RTO_MIN]  = "rto_min",
+};
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
@@ -54,13 +67,13 @@ static void usage(void)
        fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
        fprintf(stderr, "             [ table TABLE_ID ] [ proto RTPROTO ]\n");
        fprintf(stderr, "             [ scope SCOPE ] [ metric METRIC ]\n");
-       fprintf(stderr, "             [ mpath MP_ALGO ]\n");
        fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
        fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
        fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
-       fprintf(stderr, "           [ rtt NUMBER ] [ rttvar NUMBER ]\n");
-       fprintf(stderr, "           [ window NUMBER] [ cwnd NUMBER ] [ ssthresh NUMBER ]\n");
-       fprintf(stderr, "           [ realms REALM ]\n");
+       fprintf(stderr, "           [ rtt TIME ] [ rttvar TIME ]\n");
+       fprintf(stderr, "           [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
+       fprintf(stderr, "           [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
+       fprintf(stderr, "           [ rto_min TIME ]\n");
        fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
        fprintf(stderr, "          unreachable | prohibit | blackhole | nat ]\n");
        fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
@@ -69,6 +82,7 @@ static void usage(void)
        fprintf(stderr, "MP_ALGO := { rr | drr | random | wrandom }\n");
        fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
        fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
+       fprintf(stderr, "TIME := NUMBER[s|ms|us|ns|j]\n");
        exit(-1);
 }
 
@@ -76,6 +90,7 @@ static void usage(void)
 static struct
 {
        int tb;
+       int cloned;
        int flushed;
        char *flushb;
        int flushp;
@@ -95,18 +110,10 @@ static struct
        inet_prefix msrc;
 } filter;
 
-static char *mp_alg_names[IP_MP_ALG_MAX+1] = {
-       [IP_MP_ALG_NONE] = "none",
-       [IP_MP_ALG_RR] = "rr",
-       [IP_MP_ALG_DRR] = "drr",
-       [IP_MP_ALG_RANDOM] = "random",
-       [IP_MP_ALG_WRANDOM] = "wrandom"
-};
-
 static int flush_update(void)
 {
-       if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) {
-               perror("Failed to send flush request\n");
+       if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+               perror("Failed to send flush request");
                return -1;
        }
        filter.flushp = 0;
@@ -125,8 +132,10 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        inet_prefix prefsrc;
        inet_prefix via;
        int host_len = -1;
+       static int ip6_multiple_tables;
+       __u32 table;
        SPRINT_BUF(b1);
-       
+       static int hz;
 
        if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
                fprintf(stderr, "Not a route: %08x %08x %08x\n",
@@ -150,27 +159,36 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        else if (r->rtm_family == AF_IPX)
                host_len = 80;
 
-       if (r->rtm_family == AF_INET6) {
+       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+       table = rtm_get_table(r, tb);
+
+       if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
+               ip6_multiple_tables = 1;
+
+       if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
+               if (filter.cloned) {
+                       if (!(r->rtm_flags&RTM_F_CLONED))
+                               return 0;
+               }
                if (filter.tb) {
-                       if (filter.tb < 0) {
-                               if (!(r->rtm_flags&RTM_F_CLONED))
-                                       return 0;
-                       } else {
-                               if (r->rtm_flags&RTM_F_CLONED)
+                       if (!filter.cloned && r->rtm_flags&RTM_F_CLONED)
+                               return 0;
+                       if (filter.tb == RT_TABLE_LOCAL) {
+                               if (r->rtm_type != RTN_LOCAL)
                                        return 0;
-                               if (filter.tb == RT_TABLE_LOCAL) {
-                                       if (r->rtm_type != RTN_LOCAL)
-                                               return 0;
-                               } else if (filter.tb == RT_TABLE_MAIN) {
-                                       if (r->rtm_type == RTN_LOCAL)
-                                               return 0;
-                               } else {
+                       } else if (filter.tb == RT_TABLE_MAIN) {
+                               if (r->rtm_type == RTN_LOCAL)
                                        return 0;
-                               }
+                       } else {
+                               return 0;
                        }
                }
        } else {
-               if (filter.tb > 0 && filter.tb != r->rtm_table)
+               if (filter.cloned) {
+                       if (!(r->rtm_flags&RTM_F_CLONED))
+                               return 0;
+               }
+               if (filter.tb > 0 && filter.tb != table)
                        return 0;
        }
        if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
@@ -200,8 +218,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
                return 0;
 
-       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
-
        memset(&dst, 0, sizeof(dst));
        dst.family = r->rtm_family;
        if (tb[RTA_DST])
@@ -262,7 +278,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                if ((oif^filter.oif)&filter.oifmask)
                        return 0;
        }
-       if (filter.flushb && 
+       if (filter.flushb &&
            r->rtm_family == AF_INET6 &&
            r->rtm_dst_len == 0 &&
            r->rtm_type == RTN_UNREACHABLE &&
@@ -335,16 +351,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
        }
 
-       if (tb[RTA_MP_ALGO]) {
-               __u32 mp_alg = *(__u32*) RTA_DATA(tb[RTA_MP_ALGO]);
-               if (mp_alg > IP_MP_ALG_NONE) {
-                       fprintf(fp, "mpath %s ",
-                           mp_alg < IP_MP_ALG_MAX ? mp_alg_names[mp_alg] : "unknown");
-               }
-       }
-
        if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
-               fprintf(fp, "via %s ", 
+               fprintf(fp, "via %s ",
                        format_host(r->rtm_family,
                                    RTA_PAYLOAD(tb[RTA_GATEWAY]),
                                    RTA_DATA(tb[RTA_GATEWAY]),
@@ -354,8 +362,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
 
        if (!(r->rtm_flags&RTM_F_CLONED)) {
-               if (r->rtm_table != RT_TABLE_MAIN && !filter.tb)
-                       fprintf(fp, " table %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1)));
+               if (table != RT_TABLE_MAIN && !filter.tb)
+                       fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
                if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1)
                        fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
                if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1)
@@ -365,7 +373,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                /* Do not use format_host(). It is our local addr
                   and symbolic name will not be useful.
                 */
-               fprintf(fp, " src %s ", 
+               fprintf(fp, " src %s ",
                        rt_addr_n2a(r->rtm_family,
                                    RTA_PAYLOAD(tb[RTA_PREFSRC]),
                                    RTA_DATA(tb[RTA_PREFSRC]),
@@ -427,7 +435,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        fprintf(fp, "%s%x> ", first ? "<" : "", flags);
                if (tb[RTA_CACHEINFO]) {
                        struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
-                       static int hz;
                        if (!hz)
                                hz = get_user_hz();
                        if (ci->rta_expires != 0)
@@ -454,7 +461,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                if (tb[RTA_CACHEINFO])
                        ci = RTA_DATA(tb[RTA_CACHEINFO]);
                if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
-                       static int hz;
                        if (!hz)
                                hz = get_user_hz();
                        if (r->rtm_flags & RTM_F_CLONED)
@@ -486,42 +492,32 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                if (mxrta[RTAX_LOCK])
                        mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]);
 
-               for (i=2; i<=RTAX_MAX; i++) {
-                       static char *mx_names[] = 
-                       {
-                               "mtu",
-                               "window",
-                               "rtt",
-                               "rttvar",
-                               "ssthresh",
-                               "cwnd",
-                               "advmss",
-                               "reordering",
-                       };
-                       static int hz;
+               for (i=2; i<= RTAX_MAX; i++) {
                        if (mxrta[i] == NULL)
                                continue;
                        if (!hz)
                                hz = get_hz();
-                       if (i-2 < sizeof(mx_names)/sizeof(char*))
-                               fprintf(fp, " %s", mx_names[i-2]);
+
+                       if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i])
+                               fprintf(fp, " %s", mx_names[i]);
                        else
                                fprintf(fp, " metric %d", i);
                        if (mxlock & (1<<i))
                                fprintf(fp, " lock");
 
-                       if (i != RTAX_RTT && i != RTAX_RTTVAR)
+                       if (i != RTAX_RTT && i != RTAX_RTTVAR &&
+                           i != RTAX_RTO_MIN)
                                fprintf(fp, " %u", *(unsigned*)RTA_DATA(mxrta[i]));
                        else {
-                               unsigned val = *(unsigned*)RTA_DATA(mxrta[i]);
+                               unsigned long long val = *(unsigned*)RTA_DATA(mxrta[i]);
 
                                val *= 1000;
                                if (i == RTAX_RTT)
                                        val /= 8;
-                               else
+                               else if (i == RTAX_RTTVAR)
                                        val /= 4;
                                if (val >= hz)
-                                       fprintf(fp, " %ums", val/hz);
+                                       fprintf(fp, " %llums", val/hz);
                                else
                                        fprintf(fp, " %.2fms", (float)val/hz);
                        }
@@ -551,12 +547,24 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        if (nh->rtnh_len > sizeof(*nh)) {
                                parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
                                if (tb[RTA_GATEWAY]) {
-                                       fprintf(fp, " via %s ", 
+                                       fprintf(fp, " via %s ",
                                                format_host(r->rtm_family,
                                                            RTA_PAYLOAD(tb[RTA_GATEWAY]),
                                                            RTA_DATA(tb[RTA_GATEWAY]),
                                                            abuf, sizeof(abuf)));
                                }
+                               if (tb[RTA_FLOW]) {
+                                       __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
+                                       __u32 from = to>>16;
+                                       to &= 0xFFFF;
+                                       fprintf(fp, " realm%s ", from ? "s" : "");
+                                       if (from) {
+                                               fprintf(fp, "%s/",
+                                                       rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+                                       }
+                                       fprintf(fp, "%s",
+                                               rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+                               }
                        }
                        if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
                                fprintf(fp, " %s", ll_index_to_name(nh->rtnh_ifindex));
@@ -606,6 +614,13 @@ int parse_one_nh(struct rtattr *rta, struct rtnexthop *rtnh, int *argcp, char **
                        rtnh->rtnh_hops = w - 1;
                } else if (strcmp(*argv, "onlink") == 0) {
                        rtnh->rtnh_flags |= RTNH_F_ONLINK;
+               } else if (matches(*argv, "realms") == 0) {
+                       __u32 realm;
+                       NEXT_ARG();
+                       if (get_rt_realms(&realm, *argv))
+                               invarg("\"realm\" value is invalid\n", *argv);
+                       rta_addattr32(rta, 4096, RTA_FLOW, realm);
+                       rtnh->rtnh_len += sizeof(struct rtattr) + 4;
                } else
                        break;
        }
@@ -664,6 +679,7 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
        int table_ok = 0;
        int proto_ok = 0;
        int type_ok = 0;
+       int raw = 0;
 
        memset(&req, 0, sizeof(req));
 
@@ -771,9 +787,19 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                                mxlock |= (1<<RTAX_RTT);
                                NEXT_ARG();
                        }
-                       if (get_unsigned(&rtt, *argv, 0))
+                       if (get_jiffies(&rtt, *argv, 0, &raw))
                                invarg("\"rtt\" value is invalid\n", *argv);
-                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, rtt);
+                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, 
+                               (raw) ? rtt : rtt * 8);
+               } else if (strcmp(*argv, "rto_min") == 0) {
+                       unsigned rto_min;
+                       NEXT_ARG();
+                       mxlock |= (1<<RTAX_RTO_MIN);
+                       if (get_jiffies(&rto_min, *argv, 0, &raw))
+                               invarg("\"rto_min\" value is invalid\n",
+                                      *argv);
+                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
+                                     rto_min);
                } else if (matches(*argv, "window") == 0) {
                        unsigned win;
                        NEXT_ARG();
@@ -794,6 +820,16 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                        if (get_unsigned(&win, *argv, 0))
                                invarg("\"cwnd\" value is invalid\n", *argv);
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
+               } else if (matches(*argv, "initcwnd") == 0) {
+                       unsigned win;
+                       NEXT_ARG();
+                       if (strcmp(*argv, "lock") == 0) {
+                               mxlock |= (1<<RTAX_INITCWND);
+                               NEXT_ARG();
+                       }
+                       if (get_unsigned(&win, *argv, 0))
+                               invarg("\"initcwnd\" value is invalid\n", *argv);
+                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
                } else if (matches(*argv, "rttvar") == 0) {
                        unsigned win;
                        NEXT_ARG();
@@ -801,9 +837,10 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                                mxlock |= (1<<RTAX_RTTVAR);
                                NEXT_ARG();
                        }
-                       if (get_unsigned(&win, *argv, 0))
+                       if (get_jiffies(&win, *argv, 0, &raw))
                                invarg("\"rttvar\" value is invalid\n", *argv);
-                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR, win);
+                       rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
+                               (raw) ? win : win * 4);
                } else if (matches(*argv, "ssthresh") == 0) {
                        unsigned win;
                        NEXT_ARG();
@@ -840,24 +877,17 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                        NEXT_ARG();
                        if (rtnl_rttable_a2n(&tid, *argv))
                                invarg("\"table\" value is invalid\n", *argv);
-                       req.r.rtm_table = tid;
+                       if (tid < 256)
+                               req.r.rtm_table = tid;
+                       else {
+                               req.r.rtm_table = RT_TABLE_UNSPEC;
+                               addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
+                       }
                        table_ok = 1;
                } else if (strcmp(*argv, "dev") == 0 ||
                           strcmp(*argv, "oif") == 0) {
                        NEXT_ARG();
                        d = *argv;
-               } else if (strcmp(*argv, "mpath") == 0 ||
-                          strcmp(*argv, "mp") == 0) {
-                       int i;
-                       __u32 mp_alg = IP_MP_ALG_NONE;
-
-                       NEXT_ARG();
-                       for (i = 1; i < ARRAY_SIZE(mp_alg_names); i++)
-                               if (strcmp(*argv, mp_alg_names[i]) == 0)
-                                       mp_alg = i;
-                       if (mp_alg == IP_MP_ALG_NONE)
-                               invarg("\"mpath\" value is invalid\n", *argv);
-                       addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg));
                } else {
                        int type;
                        inet_prefix dst;
@@ -980,7 +1010,7 @@ static int iproute_flush_cache(void)
        }
 
        len = strlen (buffer);
-               
+
        if ((write (flush_fd, (void *)buffer, len)) < len) {
                fprintf (stderr, "Cannot flush routing cache\n");
                return -1;
@@ -1010,19 +1040,19 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
                        NEXT_ARG();
                        if (rtnl_rttable_a2n(&tid, *argv)) {
                                if (strcmp(*argv, "all") == 0) {
-                                       tid = 0;
+                                       filter.tb = 0;
                                } else if (strcmp(*argv, "cache") == 0) {
-                                       tid = -1;
+                                       filter.cloned = 1;
                                } else if (strcmp(*argv, "help") == 0) {
                                        usage();
                                } else {
                                        invarg("table id value is invalid\n", *argv);
                                }
-                       }
-                       filter.tb = tid;
+                       } else
+                               filter.tb = tid;
                } else if (matches(*argv, "cached") == 0 ||
                           matches(*argv, "cloned") == 0) {
-                       filter.tb = -1;
+                       filter.cloned = 1;
                } else if (strcmp(*argv, "tos") == 0 ||
                           matches(*argv, "dsfield") == 0) {
                        __u32 tos;
@@ -1154,7 +1184,7 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
                char flushb[4096-512];
                time_t start = time(0);
 
-               if (filter.tb == -1) {
+               if (filter.cloned) {
                        if (do_ipv6 != AF_INET6) {
                                iproute_flush_cache();
                                if (show_stats)
@@ -1179,11 +1209,12 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
                                exit(1);
                        }
                        if (filter.flushed == 0) {
-                               if (round == 0) {
-                                       if (filter.tb != -1 || do_ipv6 == AF_INET6)
-                                               fprintf(stderr, "Nothing to flush.\n");
-                               } else if (show_stats)
-                                       printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               if (show_stats) {
+                                       if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
+                                               printf("Nothing to flush.\n");
+                                       else
+                                               printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+                               }
                                fflush(stdout);
                                return 0;
                        }
@@ -1204,7 +1235,7 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
                }
        }
 
-       if (filter.tb != -1) {
+       if (!filter.cloned) {
                if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
                        perror("Cannot send dump request");
                        exit(1);
@@ -1252,7 +1283,7 @@ int iproute_get(int argc, char **argv)
        req.r.rtm_src_len = 0;
        req.r.rtm_dst_len = 0;
        req.r.rtm_tos = 0;
-       
+
        while (argc > 0) {
                if (strcmp(*argv, "tos") == 0 ||
                    matches(*argv, "dsfield") == 0) {
@@ -1394,7 +1425,7 @@ int do_iproute(int argc, char **argv)
 {
        if (argc < 1)
                return iproute_list_or_flush(0, NULL, 0);
-       
+
        if (matches(*argv, "add") == 0)
                return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
                                      argc-1, argv+1);
index ccf699f..e1a943a 100644 (file)
 #include <netinet/ip.h>
 #include <arpa/inet.h>
 #include <string.h>
+#include <linux/fib_rules.h>
 
 #include "rt_names.h"
 #include "utils.h"
+#include "ip_common.h"
 
 extern struct rtnl_handle rth;
 
@@ -35,34 +37,35 @@ static void usage(void) __attribute__((noreturn));
 static void usage(void)
 {
        fprintf(stderr, "Usage: ip rule [ list | add | del | flush ] SELECTOR ACTION\n");
-       fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n");
+       fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n");
        fprintf(stderr, "            [ dev STRING ] [ pref NUMBER ]\n");
        fprintf(stderr, "ACTION := [ table TABLE_ID ]\n");
        fprintf(stderr, "          [ prohibit | reject | unreachable ]\n");
        fprintf(stderr, "          [ realms [SRCREALM/]DSTREALM ]\n");
+       fprintf(stderr, "          [ goto NUMBER ]\n");
        fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n");
        exit(-1);
 }
 
-static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
-                     void *arg)
+int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
        FILE *fp = (FILE*)arg;
        struct rtmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        int host_len = -1;
-       struct rtattr * tb[RTA_MAX+1];
+       __u32 table;
+       struct rtattr * tb[FRA_MAX+1];
        char abuf[256];
        SPRINT_BUF(b1);
 
-       if (n->nlmsg_type != RTM_NEWRULE)
+       if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
                return 0;
 
        len -= NLMSG_LENGTH(sizeof(*r));
        if (len < 0)
                return -1;
 
-       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+       parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
 
        if (r->rtm_family == AF_INET)
                host_len = 32;
@@ -73,23 +76,29 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
        else if (r->rtm_family == AF_IPX)
                host_len = 80;
 
-       if (tb[RTA_PRIORITY])
-               fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY]));
+       if (n->nlmsg_type == RTM_DELRULE)
+               fprintf(fp, "Deleted ");
+
+       if (tb[FRA_PRIORITY])
+               fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY]));
        else
                fprintf(fp, "0:\t");
 
-       if (tb[RTA_SRC]) {
+       if (r->rtm_flags & FIB_RULE_INVERT)
+               fprintf(fp, "not ");
+
+       if (tb[FRA_SRC]) {
                if (r->rtm_src_len != host_len) {
                        fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
-                                                        RTA_PAYLOAD(tb[RTA_SRC]),
-                                                        RTA_DATA(tb[RTA_SRC]),
+                                                        RTA_PAYLOAD(tb[FRA_SRC]),
+                                                        RTA_DATA(tb[FRA_SRC]),
                                                         abuf, sizeof(abuf)),
                                r->rtm_src_len
                                );
                } else {
                        fprintf(fp, "from %s ", format_host(r->rtm_family,
-                                                      RTA_PAYLOAD(tb[RTA_SRC]),
-                                                      RTA_DATA(tb[RTA_SRC]),
+                                                      RTA_PAYLOAD(tb[FRA_SRC]),
+                                                      RTA_DATA(tb[FRA_SRC]),
                                                       abuf, sizeof(abuf))
                                );
                }
@@ -99,18 +108,18 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
                fprintf(fp, "from all ");
        }
 
-       if (tb[RTA_DST]) {
+       if (tb[FRA_DST]) {
                if (r->rtm_dst_len != host_len) {
                        fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
-                                                        RTA_PAYLOAD(tb[RTA_DST]),
-                                                        RTA_DATA(tb[RTA_DST]),
+                                                        RTA_PAYLOAD(tb[FRA_DST]),
+                                                        RTA_DATA(tb[FRA_DST]),
                                                         abuf, sizeof(abuf)),
                                r->rtm_dst_len
                                );
                } else {
                        fprintf(fp, "to %s ", format_host(r->rtm_family,
-                                                      RTA_PAYLOAD(tb[RTA_DST]),
-                                                      RTA_DATA(tb[RTA_DST]),
+                                                      RTA_PAYLOAD(tb[FRA_DST]),
+                                                      RTA_DATA(tb[FRA_DST]),
                                                       abuf, sizeof(abuf)));
                }
        } else if (r->rtm_dst_len) {
@@ -121,19 +130,32 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
                SPRINT_BUF(b1);
                fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
        }
-       if (tb[RTA_PROTOINFO]) {
-               fprintf(fp, "fwmark %#x ", *(__u32*)RTA_DATA(tb[RTA_PROTOINFO]));
+
+       if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
+               __u32 mark = 0, mask = 0;
+
+               if (tb[FRA_FWMARK])
+                       mark = *(__u32*)RTA_DATA(tb[FRA_FWMARK]);
+
+               if (tb[FRA_FWMASK] &&
+                   (mask = *(__u32*)RTA_DATA(tb[FRA_FWMASK])) != 0xFFFFFFFF)
+                       fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
+               else
+                       fprintf(fp, "fwmark 0x%x ", mark);
        }
 
-       if (tb[RTA_IIF]) {
-               fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
+       if (tb[FRA_IFNAME]) {
+               fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[FRA_IFNAME]));
+               if (r->rtm_flags & FIB_RULE_DEV_DETACHED)
+                       fprintf(fp, "[detached] ");
        }
 
-       if (r->rtm_table)
-               fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1)));
+       table = rtm_get_table(r, tb);
+       if (table)
+               fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
 
-       if (tb[RTA_FLOW]) {
-               __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
+       if (tb[FRA_FLOW]) {
+               __u32 to = *(__u32*)RTA_DATA(tb[FRA_FLOW]);
                __u32 from = to>>16;
                to &= 0xFFFF;
                if (from) {
@@ -146,14 +168,24 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        if (r->rtm_type == RTN_NAT) {
                if (tb[RTA_GATEWAY]) {
-                       fprintf(fp, "map-to %s ", 
+                       fprintf(fp, "map-to %s ",
                                format_host(r->rtm_family,
                                            RTA_PAYLOAD(tb[RTA_GATEWAY]),
                                            RTA_DATA(tb[RTA_GATEWAY]),
                                            abuf, sizeof(abuf)));
                } else
                        fprintf(fp, "masquerade");
-       } else if (r->rtm_type != RTN_UNICAST)
+       } else if (r->rtm_type == FR_ACT_GOTO) {
+               fprintf(fp, "goto ");
+               if (tb[FRA_GOTO])
+                       fprintf(fp, "%u", *(__u32 *) RTA_DATA(tb[FRA_GOTO]));
+               else
+                       fprintf(fp, "none");
+               if (r->rtm_flags & FIB_RULE_UNRESOLVED)
+                       fprintf(fp, " [unresolved]");
+       } else if (r->rtm_type == FR_ACT_NOP)
+               fprintf(fp, "nop");
+       else if (r->rtm_type != RTN_UNICAST)
                fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
 
        fprintf(fp, "\n");
@@ -206,6 +238,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
        req.r.rtm_scope = RT_SCOPE_UNIVERSE;
        req.r.rtm_table = 0;
        req.r.rtm_type = RTN_UNSPEC;
+       req.r.rtm_flags = 0;
 
        if (cmd == RTM_NEWRULE) {
                req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
@@ -213,18 +246,20 @@ static int iprule_modify(int cmd, int argc, char **argv)
        }
 
        while (argc > 0) {
-               if (strcmp(*argv, "from") == 0) {
+               if (strcmp(*argv, "not") == 0) {
+                       req.r.rtm_flags |= FIB_RULE_INVERT;
+               } else if (strcmp(*argv, "from") == 0) {
                        inet_prefix dst;
                        NEXT_ARG();
                        get_prefix(&dst, *argv, req.r.rtm_family);
                        req.r.rtm_src_len = dst.bitlen;
-                       addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen);
+                       addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen);
                } else if (strcmp(*argv, "to") == 0) {
                        inet_prefix dst;
                        NEXT_ARG();
                        get_prefix(&dst, *argv, req.r.rtm_family);
                        req.r.rtm_dst_len = dst.bitlen;
-                       addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
+                       addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen);
                } else if (matches(*argv, "preference") == 0 ||
                           matches(*argv, "order") == 0 ||
                           matches(*argv, "priority") == 0) {
@@ -232,7 +267,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        NEXT_ARG();
                        if (get_u32(&pref, *argv, 0))
                                invarg("preference value is invalid\n", *argv);
-                       addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
+                       addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref);
                } else if (strcmp(*argv, "tos") == 0) {
                        __u32 tos;
                        NEXT_ARG();
@@ -240,29 +275,42 @@ static int iprule_modify(int cmd, int argc, char **argv)
                                invarg("TOS value is invalid\n", *argv);
                        req.r.rtm_tos = tos;
                } else if (strcmp(*argv, "fwmark") == 0) {
-                       __u32 fwmark;
+                       char *slash;
+                       __u32 fwmark, fwmask;
                        NEXT_ARG();
+                       if ((slash = strchr(*argv, '/')) != NULL)
+                               *slash = '\0';
                        if (get_u32(&fwmark, *argv, 0))
                                invarg("fwmark value is invalid\n", *argv);
-                       addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
+                       addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
+                       if (slash) {
+                               if (get_u32(&fwmask, slash+1, 0))
+                                       invarg("fwmask value is invalid\n", slash+1);
+                               addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask);
+                       }
                } else if (matches(*argv, "realms") == 0) {
                        __u32 realm;
                        NEXT_ARG();
                        if (get_rt_realms(&realm, *argv))
                                invarg("invalid realms\n", *argv);
-                       addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
+                       addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
                } else if (matches(*argv, "table") == 0 ||
                           strcmp(*argv, "lookup") == 0) {
                        __u32 tid;
                        NEXT_ARG();
                        if (rtnl_rttable_a2n(&tid, *argv))
                                invarg("invalid table ID\n", *argv);
-                       req.r.rtm_table = tid;
+                       if (tid < 256)
+                               req.r.rtm_table = tid;
+                       else {
+                               req.r.rtm_table = RT_TABLE_UNSPEC;
+                               addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
+                       }
                        table_ok = 1;
                } else if (strcmp(*argv, "dev") == 0 ||
                           strcmp(*argv, "iif") == 0) {
                        NEXT_ARG();
-                       addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1);
+                       addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1);
                } else if (strcmp(*argv, "nat") == 0 ||
                           matches(*argv, "map-to") == 0) {
                        NEXT_ARG();
@@ -277,9 +325,19 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        }
                        if (matches(*argv, "help") == 0)
                                usage();
-                       if (rtnl_rtntype_a2n(&type, *argv))
+                       else if (matches(*argv, "goto") == 0) {
+                               __u32 target;
+                               type = FR_ACT_GOTO;
+                               NEXT_ARG();
+                               if (get_u32(&target, *argv, 0))
+                                       invarg("invalid target\n", *argv);
+                               addattr32(&req.n, sizeof(req), FRA_GOTO, target);
+                       } else if (matches(*argv, "nop") == 0)
+                               type = FR_ACT_NOP;
+                       else if (rtnl_rtntype_a2n(&type, *argv))
                                invarg("Failed to parse rule type", *argv);
                        req.r.rtm_type = type;
+                       table_ok = 1;
                }
                argc--;
                argv++;
@@ -303,15 +361,15 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *a
        struct rtnl_handle rth2;
        struct rtmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
-       struct rtattr * tb[RTA_MAX+1];
+       struct rtattr * tb[FRA_MAX+1];
 
        len -= NLMSG_LENGTH(sizeof(*r));
        if (len < 0)
                return -1;
 
-       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+       parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
 
-       if (tb[RTA_PRIORITY]) {
+       if (tb[FRA_PRIORITY]) {
                n->nlmsg_type = RTM_DELRULE;
                n->nlmsg_flags = NLM_F_REQUEST;
 
index 35b0895..0d9a17f 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <syslog.h>
-#include <fcntl.h>
+#include <sys/types.h>
 #include <sys/socket.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
-
-#ifndef __constant_htons
-#define __constant_htons(x)  htons(x)
-#endif
-
 #include <linux/if_tunnel.h>
 
 #include "rt_names.h"
 #include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
 
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
 {
        fprintf(stderr, "Usage: ip tunnel { add | change | del | show } [ NAME ]\n");
-       fprintf(stderr, "          [ mode { ipip | gre | gre/ip | gre/eth | sit } ] [ remote ADDR ] [ local ADDR ]\n");
+       fprintf(stderr, "          [ mode { ipip | gre | sit | isatap } ] [ remote ADDR ] [ local ADDR ]\n");
        fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
        fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
        fprintf(stderr, "\n");
@@ -56,117 +51,11 @@ static void usage(void)
        exit(-1);
 }
 
-static int do_ioctl_get_ifindex(const char *dev)
-{
-       struct ifreq ifr;
-       int fd;
-       int err;
-
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, SIOCGIFINDEX, &ifr);
-       if (err) {
-               perror("ioctl");
-               return 0;
-       }
-       close(fd);
-       return ifr.ifr_ifindex;
-}
-
-static int do_ioctl_get_iftype(const char *dev)
-{
-       struct ifreq ifr;
-       int fd;
-       int err;
-
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, SIOCGIFHWADDR, &ifr);
-       if (err) {
-               perror("ioctl");
-               return -1;
-       }
-       close(fd);
-       return ifr.ifr_addr.sa_family;
-}
-
-
-static char * do_ioctl_get_ifname(int idx)
-{
-       static struct ifreq ifr;
-       int fd;
-       int err;
-
-       ifr.ifr_ifindex = idx;
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, SIOCGIFNAME, &ifr);
-       if (err) {
-               perror("ioctl");
-               return NULL;
-       }
-       close(fd);
-       return ifr.ifr_name;
-}
-
-
-static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
-{
-       struct ifreq ifr;
-       int fd;
-       int err;
-
-       strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
-       ifr.ifr_ifru.ifru_data = (void*)p;
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, SIOCGETTUNNEL, &ifr);
-       if (err)
-               perror("ioctl");
-       close(fd);
-       return err;
-}
-
-static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
-{
-       struct ifreq ifr;
-       int fd;
-       int err;
-
-       if (cmd == SIOCCHGTUNNEL && p->name[0])
-               strncpy(ifr.ifr_name, p->name, IFNAMSIZ);
-       else
-               strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
-       ifr.ifr_ifru.ifru_data = (void*)p;
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, cmd, &ifr);
-       if (err)
-               perror("ioctl");
-       close(fd);
-       return err;
-}
-
-static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
-{
-       struct ifreq ifr;
-       int fd;
-       int err;
-
-       if (p->name[0])
-               strncpy(ifr.ifr_name, p->name, IFNAMSIZ);
-       else
-               strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
-       ifr.ifr_ifru.ifru_data = (void*)p;
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       err = ioctl(fd, SIOCDELTUNNEL, &ifr);
-       if (err)
-               perror("ioctl");
-       close(fd);
-       return err;
-}
-
 static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
 {
        int count = 0;
        char medium[IFNAMSIZ];
+       int isatap = 0;
 
        memset(p, 0, sizeof(*p));
        memset(&medium, 0, sizeof(medium));
@@ -189,17 +78,12 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                                }
                                p->iph.protocol = IPPROTO_IPIP;
                        } else if (strcmp(*argv, "gre") == 0 ||
-                                  strcmp(*argv, "gre/ip") == 0 ||
-                                  strcmp(*argv, "gre/eth") == 0) {
+                                  strcmp(*argv, "gre/ip") == 0) {
                                if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
                                        fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
                                        exit(-1);
                                }
                                p->iph.protocol = IPPROTO_GRE;
-                               if (strcmp(*argv,"gre/eth") == 0)
-                                       p->proto_type = ETH_P_ETH;
-                               else
-                                       p->proto_type = ETH_P_IP;
                        } else if (strcmp(*argv, "sit") == 0 ||
                                   strcmp(*argv, "ipv6/ip") == 0) {
                                if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
@@ -207,6 +91,13 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                                        exit(-1);
                                }
                                p->iph.protocol = IPPROTO_IPV6;
+                       } else if (strcmp(*argv, "isatap") == 0) {
+                               if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
+                                       fprintf(stderr, "You managed to ask for more than one tunnel mode.\n");
+                                       exit(-1);
+                               }
+                               p->iph.protocol = IPPROTO_IPV6;
+                               isatap++;
                        } else {
                                fprintf(stderr,"Cannot guess tunnel mode.\n");
                                exit(-1);
@@ -230,7 +121,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                        NEXT_ARG();
                        p->i_flags |= GRE_KEY;
                        if (strchr(*argv, '.'))
-                               p->o_key = get_addr32(*argv);
+                               p->i_key = get_addr32(*argv);
                        else {
                                if (get_unsigned(&uval, *argv, 0)<0) {
                                        fprintf(stderr, "invalid value of \"ikey\"\n");
@@ -280,7 +171,8 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                } else if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
                        strncpy(medium, *argv, IFNAMSIZ-1);
-               } else if (strcmp(*argv, "ttl") == 0) {
+               } else if (strcmp(*argv, "ttl") == 0 ||
+                          strcmp(*argv, "hoplimit") == 0) {
                        unsigned uval;
                        NEXT_ARG();
                        if (strcmp(*argv, "inherit") != 0) {
@@ -291,6 +183,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                                p->iph.ttl = uval;
                        }
                } else if (strcmp(*argv, "tos") == 0 ||
+                          strcmp(*argv, "tclass") == 0 ||
                           matches(*argv, "dsfield") == 0) {
                        __u32 uval;
                        NEXT_ARG();
@@ -303,8 +196,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                } else {
                        if (strcmp(*argv, "name") == 0) {
                                NEXT_ARG();
-                       }
-                       if (matches(*argv, "help") == 0)
+                       } else if (matches(*argv, "help") == 0)
                                usage();
                        if (p->name[0])
                                duparg2("name", *argv);
@@ -312,7 +204,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                        if (cmd == SIOCCHGTUNNEL && count == 0) {
                                struct ip_tunnel_parm old_p;
                                memset(&old_p, 0, sizeof(old_p));
-                               if (do_get_ioctl(*argv, &old_p))
+                               if (tnl_get_ioctl(*argv, &old_p))
                                        return -1;
                                *p = old_p;
                        }
@@ -329,6 +221,10 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                        p->iph.protocol = IPPROTO_IPIP;
                else if (memcmp(p->name, "sit", 3) == 0)
                        p->iph.protocol = IPPROTO_IPV6;
+               else if (memcmp(p->name, "isatap", 6) == 0) {
+                       p->iph.protocol = IPPROTO_IPV6;
+                       isatap++;
+               }
        }
 
        if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
@@ -339,7 +235,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
        }
 
        if (medium[0]) {
-               p->link = do_ioctl_get_ifindex(medium);
+               p->link = tnl_ioctl_get_ifindex(medium);
                if (p->link == 0)
                        return -1;
        }
@@ -356,6 +252,14 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
                fprintf(stderr, "Broadcast tunnel requires a source address.\n");
                return -1;
        }
+       if (isatap) {
+               if (p->iph.daddr) {
+                       fprintf(stderr, "no remote with isatap.\n");
+                       return -1;
+               }
+               p->i_flags |= SIT_ISATAP;
+       }
+
        return 0;
 }
 
@@ -371,22 +275,22 @@ static int do_add(int cmd, int argc, char **argv)
                fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
                return -1;
        }
-       
+
        switch (p.iph.protocol) {
        case IPPROTO_IPIP:
-               return do_add_ioctl(cmd, "tunl0", &p);
+               return tnl_add_ioctl(cmd, "tunl0", p.name, &p);
        case IPPROTO_GRE:
-               return do_add_ioctl(cmd, "gre0", &p);
+               return tnl_add_ioctl(cmd, "gre0", p.name, &p);
        case IPPROTO_IPV6:
-               return do_add_ioctl(cmd, "sit0", &p);
-       default:        
+               return tnl_add_ioctl(cmd, "sit0", p.name, &p);
+       default:
                fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n");
                return -1;
        }
        return -1;
 }
 
-int do_del(int argc, char **argv)
+static int do_del(int argc, char **argv)
 {
        struct ip_tunnel_parm p;
 
@@ -395,18 +299,18 @@ int do_del(int argc, char **argv)
 
        switch (p.iph.protocol) {
        case IPPROTO_IPIP:
-               return do_del_ioctl("tunl0", &p);
+               return tnl_del_ioctl("tunl0", p.name, &p);
        case IPPROTO_GRE:
-               return do_del_ioctl("gre0", &p);
+               return tnl_del_ioctl("gre0", p.name, &p);
        case IPPROTO_IPV6:
-               return do_del_ioctl("sit0", &p);
-       default:        
-               return do_del_ioctl(p.name, &p);
+               return tnl_del_ioctl("sit0", p.name, &p);
+       default:
+               return tnl_del_ioctl(p.name, p.name, &p);
        }
        return -1;
 }
 
-void print_tunnel(struct ip_tunnel_parm *p)
+static void print_tunnel(struct ip_tunnel_parm *p)
 {
        char s1[1024];
        char s2[1024];
@@ -419,17 +323,14 @@ void print_tunnel(struct ip_tunnel_parm *p)
        /* Do not use format_host() for local addr,
         * symbolic name will not be useful.
         */
-       printf("%s: %s/%s  remote %s  local %s ",
+       printf("%s: %s/ip  remote %s  local %s ",
               p->name,
-              p->iph.protocol == IPPROTO_IPIP ? "ip" :
-              (p->iph.protocol == IPPROTO_GRE ? "gre" :
-               (p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")),
-              (p->proto_type == ETH_P_ETH ? "eth" : "ip"),
+              tnl_strproto(p->iph.protocol),
               p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1))  : "any",
               p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");
 
        if (p->link) {
-               char *n = do_ioctl_get_ifname(p->link);
+               char *n = tnl_ioctl_get_ifname(p->link);
                if (n)
                        printf(" dev %s ", n);
        }
@@ -438,7 +339,7 @@ void print_tunnel(struct ip_tunnel_parm *p)
                printf(" ttl %d ", p->iph.ttl);
        else
                printf(" ttl inherit ");
-       
+
        if (p->iph.tos) {
                SPRINT_BUF(b1);
                printf(" tos");
@@ -507,7 +408,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
                        continue;
                if (p->name[0] && strcmp(p->name, name))
                        continue;
-               type = do_ioctl_get_iftype(name);
+               type = tnl_ioctl_get_iftype(name);
                if (type == -1) {
                        fprintf(stderr, "Failed to get type of [%s]\n", name);
                        continue;
@@ -515,7 +416,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
                if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
                        continue;
                memset(&p1, 0, sizeof(p1));
-               if (do_get_ioctl(name, &p1))
+               if (tnl_get_ioctl(name, &p1))
                        continue;
                if ((p->link && p1.link != p->link) ||
                    (p->name[0] && strcmp(p1.name, p->name)) ||
@@ -546,16 +447,15 @@ static int do_show(int argc, char **argv)
        if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
                return -1;
 
-       printf("NOTE: EGRE tunnels will not show up here, use ifconfig\n");
        switch (p.iph.protocol) {
-       case IPPROTO_IPIP:      
-               err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
+       case IPPROTO_IPIP:
+               err = tnl_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
                break;
        case IPPROTO_GRE:
-               err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p);
+               err = tnl_get_ioctl(p.name[0] ? p.name : "gre0", &p);
                break;
        case IPPROTO_IPV6:
-               err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p);
+               err = tnl_get_ioctl(p.name[0] ? p.name : "sit0", &p);
                break;
        default:
                do_tunnels_list(&p);
@@ -571,6 +471,24 @@ static int do_show(int argc, char **argv)
 
 int do_iptunnel(int argc, char **argv)
 {
+       switch (preferred_family) {
+       case AF_UNSPEC:
+               preferred_family = AF_INET;
+               break;
+       case AF_INET:
+               break;
+       /*
+        * This is silly enough but we have no easy way to make it
+        * protocol-independent because of unarranged structure between
+        * IPv4 and IPv6.
+        */
+       case AF_INET6:
+               return do_ip6tunnel(argc, argv);
+       default:
+               fprintf(stderr, "Unsupported family:%d\n", preferred_family);
+               exit(-1);
+       }
+
        if (argc > 0) {
                if (matches(*argv, "add") == 0)
                        return do_add(SIOCADDTUNNEL, argc-1, argv+1);
index 8baaabd..24b2114 100644 (file)
@@ -2,17 +2,17 @@
 
 /*
  * Copyright (C)2004 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -32,7 +32,6 @@
 #include <sys/socket.h>
 #include <time.h>
 #include <netdb.h>
-#include <net/if.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/xfrm.h>
@@ -59,7 +58,7 @@ static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
 {
-       fprintf(stderr, 
+       fprintf(stderr,
                "Usage: ip xfrm XFRM_OBJECT { COMMAND | help }\n"
                "where  XFRM_OBJECT := { state | policy | monitor }\n");
        exit(-1);
@@ -94,6 +93,19 @@ int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
        return 0;
 }
 
+int xfrm_xfrmproto_is_ipsec(__u8 proto)
+{
+       return (proto ==  IPPROTO_ESP ||
+               proto ==  IPPROTO_AH  ||
+               proto ==  IPPROTO_COMP);
+}
+
+int xfrm_xfrmproto_is_ro(__u8 proto)
+{
+       return (proto ==  IPPROTO_ROUTING ||
+               proto ==  IPPROTO_DSTOPTS);
+}
+
 struct typeent {
        const char *t_name;
        int t_type;
@@ -101,6 +113,8 @@ struct typeent {
 
 static const struct typeent xfrmproto_types[]= {
        { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
+       { "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS },
+       { "ipsec-any", IPSEC_PROTO_ANY },
        { NULL, -1 }
 };
 
@@ -122,6 +136,7 @@ int xfrm_xfrmproto_getbyname(char *name)
 
 const char *strxf_xfrmproto(__u8 proto)
 {
+       static char str[16];
        int i;
 
        for (i = 0; ; i++) {
@@ -133,12 +148,14 @@ const char *strxf_xfrmproto(__u8 proto)
                        return t->t_name;
        }
 
-       return NULL;
+       sprintf(str, "%u", proto);
+       return str;
 }
 
 static const struct typeent algo_types[]= {
        { "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
-       { "comp", XFRMA_ALG_COMP }, { NULL, -1 }
+       { "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD },
+       { NULL, -1 }
 };
 
 int xfrm_algotype_getbyname(char *name)
@@ -159,6 +176,7 @@ int xfrm_algotype_getbyname(char *name)
 
 const char *strxf_algotype(int type)
 {
+       static char str[32];
        int i;
 
        for (i = 0; ; i++) {
@@ -170,7 +188,8 @@ const char *strxf_algotype(int type)
                        return t->t_name;
        }
 
-       return NULL;
+       sprintf(str, "%d", type);
+       return str;
 }
 
 const char *strxf_mask8(__u8 mask)
@@ -238,6 +257,25 @@ const char *strxf_proto(__u8 proto)
        return p;
 }
 
+const char *strxf_ptype(__u8 ptype)
+{
+       static char str[16];
+
+       switch (ptype) {
+       case XFRM_POLICY_TYPE_MAIN:
+               strcpy(str, "main");
+               break;
+       case XFRM_POLICY_TYPE_SUB:
+               strcpy(str, "sub");
+               break;
+       default:
+               sprintf(str, "%u", ptype);
+               break;
+       }
+
+       return str;
+}
+
 void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
                        __u8 mode, __u32 reqid, __u16 family, int force_spi,
                        FILE *fp, const char *prefix, const char *title)
@@ -245,7 +283,7 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
        char abuf[256];
 
        if (title)
-               fprintf(fp, title);
+               fputs(title, fp);
 
        memset(abuf, '\0', sizeof(abuf));
        fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
@@ -256,7 +294,7 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
        fprintf(fp, "%s", _SL_);
 
        if (prefix)
-               fprintf(fp, prefix);
+               fputs(prefix, fp);
        fprintf(fp, "\t");
 
        fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
@@ -276,12 +314,21 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
 
        fprintf(fp, "mode ");
        switch (mode) {
-       case 0:
+       case XFRM_MODE_TRANSPORT:
                fprintf(fp, "transport");
                break;
-       case 1:
+       case XFRM_MODE_TUNNEL:
                fprintf(fp, "tunnel");
                break;
+       case XFRM_MODE_ROUTEOPTIMIZATION:
+               fprintf(fp, "ro");
+               break;
+       case XFRM_MODE_IN_TRIGGER:
+               fprintf(fp, "in_trigger");
+               break;
+       case XFRM_MODE_BEET:
+               fprintf(fp, "beet");
+               break;
        default:
                fprintf(fp, "%u", mode);
                break;
@@ -303,12 +350,12 @@ static const char *strxf_limit(__u64 limit)
 void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
 {
        if (prefix)
-               fprintf(fp, prefix);
+               fputs(prefix, fp);
        fprintf(fp, "stats:");
        fprintf(fp, "%s", _SL_);
 
        if (prefix)
-               fprintf(fp, prefix);
+               fputs(prefix, fp);
        fprintf(fp, "  ");
        fprintf(fp, "replay-window %u ", s->replay_window);
        fprintf(fp, "replay %u ", s->replay);
@@ -326,7 +373,7 @@ static const char *strxf_time(__u64 time)
                time_t t;
                struct tm *tp;
 
-               /* XXX: treat time in the same manner of kernel's 
+               /* XXX: treat time in the same manner of kernel's
                 * net/xfrm/xfrm_{user,state}.c
                 */
                t = (long)time;
@@ -344,12 +391,12 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
 {
        if (cfg) {
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "lifetime config:");
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "limit: ");
                fprintf(fp, "soft ");
@@ -360,7 +407,7 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "limit: ");
                fprintf(fp, "soft ");
@@ -371,7 +418,7 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "expire add: ");
                fprintf(fp, "soft ");
@@ -382,7 +429,7 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "expire use: ");
                fprintf(fp, "soft ");
@@ -394,19 +441,19 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
        }
        if (cur) {
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "lifetime current:");
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "%llu(bytes), ", (unsigned long long) cur->bytes);
                fprintf(fp, "%llu(packets)", (unsigned long long) cur->packets);
                fprintf(fp, "%s", _SL_);
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "  ");
                fprintf(fp, "add %s ", strxf_time(cur->add_time));
                fprintf(fp, "use %s", strxf_time(cur->use_time));
@@ -427,7 +474,7 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
                f = preferred_family;
 
        if (prefix)
-               fprintf(fp, prefix);
+               fputs(prefix, fp);
 
        memset(abuf, '\0', sizeof(abuf));
        fprintf(fp, "src %s/%u ", rt_addr_n2a(f, sizeof(sel->saddr),
@@ -460,15 +507,18 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
                if (sel->dport_mask)
                        fprintf(fp, "code %u ", ntohs(sel->dport));
                break;
+       case IPPROTO_MH:
+               if (sel->sport_mask)
+                       fprintf(fp, "type %u ", ntohs(sel->sport));
+               if (sel->dport_mask) {
+                       if (show_stats > 0)
+                               fprintf(fp, "(dport) 0x%.4x ", sel->dport);
+               }
+               break;
        }
 
-       if (sel->ifindex > 0) {
-               char buf[IFNAMSIZ];
-
-               memset(buf, '\0', sizeof(buf));
-               if_indextoname(sel->ifindex, buf);
-               fprintf(fp, "dev %s ", buf);
-       }
+       if (sel->ifindex > 0)
+               fprintf(fp, "dev %s ", ll_index_to_name(sel->ifindex));
 
        if (show_stats > 0)
                fprintf(fp, "uid %u", sel->user);
@@ -476,14 +526,14 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
        fprintf(fp, "%s", _SL_);
 }
 
-static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
-                           FILE *fp, const char *prefix)
+static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+                             FILE *fp, const char *prefix, int newline)
 {
        int keylen;
        int i;
 
        if (prefix)
-               fprintf(fp, prefix);
+               fputs(prefix, fp);
 
        fprintf(fp, "%s ", strxf_algotype(type));
 
@@ -509,6 +559,32 @@ static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
                fprintf(fp, " (%d bits)", algo->alg_key_len);
 
  fin:
+       if (newline)
+               fprintf(fp, "%s", _SL_);
+}
+
+static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+                                  FILE *fp, const char *prefix)
+{
+       return __xfrm_algo_print(algo, type, len, fp, prefix, 1);
+}
+
+static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
+                           FILE *fp, const char *prefix)
+{
+       struct {
+               struct xfrm_algo algo;
+               char key[algo->alg_key_len / 8];
+       } base;
+
+       memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
+       base.algo.alg_key_len = algo->alg_key_len;
+       memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
+
+       __xfrm_algo_print(&base.algo, XFRMA_ALG_AEAD, len, fp, prefix, 0);
+
+       fprintf(fp, " %d", algo->alg_icv_len);
+
        fprintf(fp, "%s", _SL_);
 }
 
@@ -520,7 +596,7 @@ static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
 
        if (ntmpls <= 0) {
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "(ERROR \"tmpl\" truncated)");
                fprintf(fp, "%s", _SL_);
                return;
@@ -530,14 +606,14 @@ static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
                struct xfrm_user_tmpl *tmpl = &tmpls[i];
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
 
                xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
                                   tmpl->reqid, family, 0, fp, prefix, "tmpl ");
 
                if (show_stats > 0 || tmpl->optional) {
                        if (prefix)
-                               fprintf(fp, prefix);
+                               fputs(prefix, fp);
                        fprintf(fp, "\t");
                        switch (tmpl->optional) {
                        case 0:
@@ -560,7 +636,7 @@ static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
 
                if (show_stats > 0) {
                        if (prefix)
-                               fprintf(fp, prefix);
+                               fputs(prefix, fp);
                        fprintf(fp, "\t");
                        fprintf(fp, "%s-mask %s ",
                                strxf_algotype(XFRMA_ALG_CRYPT),
@@ -586,6 +662,12 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
                                XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
        }
 
+       if (tb[XFRMA_ALG_AEAD]) {
+               struct rtattr *rta = tb[XFRMA_ALG_AEAD];
+               xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta),
+                               RTA_PAYLOAD(rta), fp, prefix);
+       }
+
        if (tb[XFRMA_ALG_CRYPT]) {
                struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
                xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
@@ -603,7 +685,7 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
                char abuf[256];
 
                if (prefix)
-                       fprintf(fp, prefix);
+                       fputs(prefix, fp);
                fprintf(fp, "encap ");
 
                if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
@@ -640,6 +722,48 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
                xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
                                RTA_PAYLOAD(rta), family, fp, prefix);
        }
+
+       if (tb[XFRMA_COADDR]) {
+               char abuf[256];
+               xfrm_address_t *coa;
+
+               if (prefix)
+                       fputs(prefix, fp);
+               fprintf(fp, "coa ");
+
+               coa = (xfrm_address_t *)RTA_DATA(tb[XFRMA_COADDR]);
+
+               if (RTA_PAYLOAD(tb[XFRMA_COADDR]) < sizeof(*coa)) {
+                       fprintf(fp, "(ERROR truncated)");
+                       fprintf(fp, "%s", _SL_);
+                       return;
+               }
+
+               memset(abuf, '\0', sizeof(abuf));
+               fprintf(fp, "%s",
+                       rt_addr_n2a(family, sizeof(*coa), coa,
+                                   abuf, sizeof(abuf)));
+               fprintf(fp, "%s", _SL_);
+       }
+
+       if (tb[XFRMA_LASTUSED]) {
+               __u64 lastused;
+
+               if (prefix)
+                       fputs(prefix, fp);
+               fprintf(fp, "lastused ");
+
+               if (RTA_PAYLOAD(tb[XFRMA_LASTUSED]) < sizeof(lastused)) {
+                       fprintf(fp, "(ERROR truncated)");
+                       fprintf(fp, "%s", _SL_);
+                       return;
+               }
+
+               lastused = *(__u64 *)RTA_DATA(tb[XFRMA_LASTUSED]);
+
+               fprintf(fp, "%s", strxf_time(lastused));
+               fprintf(fp, "%s", _SL_);
+       }
 }
 
 static int xfrm_selector_iszero(struct xfrm_selector *s)
@@ -656,18 +780,19 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
                            const char *title)
 {
        char buf[STRBUF_SIZE];
+       int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
 
        memset(buf, '\0', sizeof(buf));
 
        xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
-                          xsinfo->reqid, xsinfo->family, 1, fp, prefix,
-                          title);
+                          xsinfo->reqid, xsinfo->family, force_spi, fp,
+                          prefix, title);
 
        if (prefix)
                STRBUF_CAT(buf, prefix);
        STRBUF_CAT(buf, "\t");
 
-       fprintf(fp, buf);
+       fputs(buf, fp);
        fprintf(fp, "replay-window %u ", xsinfo->replay_window);
        if (show_stats > 0)
                fprintf(fp, "seq 0x%08u ", xsinfo->seq);
@@ -677,11 +802,13 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
                fprintf(fp, "flag ");
                XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
                XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
+               XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOPMTUDISC, "nopmtudisc");
+               XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
                if (flags)
                        fprintf(fp, "%x", flags);
-               if (show_stats > 0)
-                       fprintf(fp, " (0x%s)", strxf_mask8(flags));
        }
+       if (show_stats > 0)
+               fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags));
        fprintf(fp, "%s", _SL_);
 
        xfrm_xfrma_print(tb, xsinfo->family, fp, buf);
@@ -715,7 +842,7 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
                STRBUF_CAT(buf, prefix);
        STRBUF_CAT(buf, "\t");
 
-       fprintf(fp, buf);
+       fputs(buf, fp);
        fprintf(fp, "dir ");
        switch (xpinfo->dir) {
        case XFRM_POLICY_IN:
@@ -749,10 +876,32 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
        if (show_stats)
                fprintf(fp, "index %u ", xpinfo->index);
        fprintf(fp, "priority %u ", xpinfo->priority);
-       if (show_stats > 0) {
+
+       if (tb[XFRMA_POLICY_TYPE]) {
+               struct xfrm_userpolicy_type *upt;
+
+               fprintf(fp, "ptype ");
+
+               if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt))
+                       fprintf(fp, "(ERROR truncated)");
+
+               upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+               fprintf(fp, "%s ", strxf_ptype(upt->type));
+       }
+
+       if (show_stats > 0)
                fprintf(fp, "share %s ", strxf_share(xpinfo->share));
-               fprintf(fp, "flag 0x%s", strxf_mask8(xpinfo->flags));
+
+       if (show_stats > 0 || xpinfo->flags) {
+               __u8 flags = xpinfo->flags;
+
+               fprintf(fp, "flag ");
+               XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_LOCALOK, "localok");
+               if (flags)
+                       fprintf(fp, "%x", flags);
        }
+       if (show_stats > 0)
+               fprintf(fp, " (0x%s)", strxf_mask8(xpinfo->flags));
        fprintf(fp, "%s", _SL_);
 
        if (show_stats > 0)
@@ -854,9 +1003,15 @@ int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
        char **argv = *argvp;
 
        if (matches(*argv, "transport") == 0)
-               *mode = 0;
+               *mode = XFRM_MODE_TRANSPORT;
        else if (matches(*argv, "tunnel") == 0)
-               *mode = 1;
+               *mode = XFRM_MODE_TUNNEL;
+       else if (matches(*argv, "ro") == 0)
+               *mode = XFRM_MODE_ROUTEOPTIMIZATION;
+       else if (matches(*argv, "in_trigger") == 0)
+               *mode = XFRM_MODE_IN_TRIGGER;
+       else if (matches(*argv, "beet") == 0)
+               *mode = XFRM_MODE_BEET;
        else
                invarg("\"MODE\" is invalid", *argv);
 
@@ -1011,6 +1166,7 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
                switch (sel->proto) {
                case IPPROTO_ICMP:
                case IPPROTO_ICMPV6:
+               case IPPROTO_MH:
                        break;
                default:
                        fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
@@ -1070,7 +1226,7 @@ int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
                        if (strcmp(*argv, "none") == 0)
                                ifindex = 0;
                        else {
-                               ifindex = if_nametoindex(*argv);
+                               ifindex = ll_name_to_index(*argv);
                                if (ifindex <= 0)
                                        invarg("\"DEV\" is invalid", *argv);
                        }
diff --git a/ip/link_gre.c b/ip/link_gre.c
new file mode 100644 (file)
index 0000000..9109312
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * link_gre.c  gre driver module
+ *
+ *             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.
+ *
+ * Authors:    Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/if_tunnel.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+       fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
+       fprintf(stderr, "          type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
+       fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+       fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Where: NAME := STRING\n");
+       fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
+       fprintf(stderr, "       TOS  := { NUMBER | inherit }\n");
+       fprintf(stderr, "       TTL  := { 1..255 | inherit }\n");
+       fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
+       exit(-1);
+}
+
+static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
+                        struct nlmsghdr *n)
+{
+       struct {
+               struct nlmsghdr n;
+               struct ifinfomsg i;
+               char buf[1024];
+       } req;
+       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct rtattr *tb[IFLA_MAX + 1];
+       struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+       struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+       __u16 iflags = 0;
+       __u16 oflags = 0;
+       unsigned ikey = 0;
+       unsigned okey = 0;
+       unsigned saddr = 0;
+       unsigned daddr = 0;
+       unsigned link = 0;
+       __u8 pmtudisc = 1;
+       __u8 ttl = 0;
+       __u8 tos = 0;
+       int len;
+
+       if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               memset(&req, 0, sizeof(req));
+
+               req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+               req.n.nlmsg_flags = NLM_F_REQUEST;
+               req.n.nlmsg_type = RTM_GETLINK;
+               req.i.ifi_family = preferred_family;
+               req.i.ifi_index = ifi->ifi_index;
+
+               if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
+get_failed:
+                       fprintf(stderr,
+                               "Failed to get existing tunnel info.\n");
+                       return -1;
+               }
+
+               len = req.n.nlmsg_len;
+               len -= NLMSG_LENGTH(sizeof(*ifi));
+               if (len < 0)
+                       goto get_failed;
+
+               parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+
+               if (!tb[IFLA_LINKINFO])
+                       goto get_failed;
+
+               parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+               if (!linkinfo[IFLA_INFO_DATA])
+                       goto get_failed;
+
+               parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
+                                   linkinfo[IFLA_INFO_DATA]);
+
+               if (greinfo[IFLA_GRE_IKEY])
+                       ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
+
+               if (greinfo[IFLA_GRE_OKEY])
+                       okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
+
+               if (greinfo[IFLA_GRE_IFLAGS])
+                       iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
+
+               if (greinfo[IFLA_GRE_OFLAGS])
+                       oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
+
+               if (greinfo[IFLA_GRE_LOCAL])
+                       saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
+
+               if (greinfo[IFLA_GRE_REMOTE])
+                       daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
+
+               if (greinfo[IFLA_GRE_PMTUDISC])
+                       pmtudisc = *(__u8 *)RTA_DATA(
+                               greinfo[IFLA_GRE_PMTUDISC]);
+
+               if (greinfo[IFLA_GRE_TTL])
+                       ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
+
+               if (greinfo[IFLA_GRE_TOS])
+                       tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
+
+               if (greinfo[IFLA_GRE_LINK])
+                       link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
+       }
+
+       while (argc > 0) {
+               if (!matches(*argv, "key")) {
+                       unsigned uval;
+
+                       NEXT_ARG();
+                       iflags |= GRE_KEY;
+                       oflags |= GRE_KEY;
+                       if (strchr(*argv, '.'))
+                               uval = get_addr32(*argv);
+                       else {
+                               if (get_unsigned(&uval, *argv, 0) < 0) {
+                                       fprintf(stderr,
+                                               "Invalid value for \"key\"\n");
+                                       exit(-1);
+                               }
+                               uval = htonl(uval);
+                       }
+
+                       ikey = okey = uval;
+               } else if (!matches(*argv, "ikey")) {
+                       unsigned uval;
+
+                       NEXT_ARG();
+                       iflags |= GRE_KEY;
+                       if (strchr(*argv, '.'))
+                               uval = get_addr32(*argv);
+                       else {
+                               if (get_unsigned(&uval, *argv, 0)<0) {
+                                       fprintf(stderr, "invalid value of \"ikey\"\n");
+                                       exit(-1);
+                               }
+                               uval = htonl(uval);
+                       }
+                       ikey = uval;
+               } else if (!matches(*argv, "okey")) {
+                       unsigned uval;
+
+                       NEXT_ARG();
+                       oflags |= GRE_KEY;
+                       if (strchr(*argv, '.'))
+                               uval = get_addr32(*argv);
+                       else {
+                               if (get_unsigned(&uval, *argv, 0)<0) {
+                                       fprintf(stderr, "invalid value of \"okey\"\n");
+                                       exit(-1);
+                               }
+                               uval = htonl(uval);
+                       }
+                       okey = uval;
+               } else if (!matches(*argv, "seq")) {
+                       iflags |= GRE_SEQ;
+                       oflags |= GRE_SEQ;
+               } else if (!matches(*argv, "iseq")) {
+                       iflags |= GRE_SEQ;
+               } else if (!matches(*argv, "oseq")) {
+                       oflags |= GRE_SEQ;
+               } else if (!matches(*argv, "csum")) {
+                       iflags |= GRE_CSUM;
+                       oflags |= GRE_CSUM;
+               } else if (!matches(*argv, "icsum")) {
+                       iflags |= GRE_CSUM;
+               } else if (!matches(*argv, "ocsum")) {
+                       oflags |= GRE_CSUM;
+               } else if (!matches(*argv, "nopmtudisc")) {
+                       pmtudisc = 0;
+               } else if (!matches(*argv, "pmtudisc")) {
+                       pmtudisc = 1;
+               } else if (!matches(*argv, "remote")) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "any"))
+                               daddr = get_addr32(*argv);
+               } else if (!matches(*argv, "local")) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "any"))
+                               saddr = get_addr32(*argv);
+               } else if (!matches(*argv, "dev")) {
+                       NEXT_ARG();
+                       link = tnl_ioctl_get_ifindex(*argv);
+                       if (link == 0)
+                               exit(-1);
+               } else if (!matches(*argv, "ttl") ||
+                          !matches(*argv, "hoplimit")) {
+                       unsigned uval;
+
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") != 0) {
+                               if (get_unsigned(&uval, *argv, 0))
+                                       invarg("invalid TTL\n", *argv);
+                               if (uval > 255)
+                                       invarg("TTL must be <= 255\n", *argv);
+                               ttl = uval;
+                       }
+               } else if (!matches(*argv, "tos") ||
+                          !matches(*argv, "tclass") ||
+                          !matches(*argv, "dsfield")) {
+                       __u32 uval;
+
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") != 0) {
+                               if (rtnl_dsfield_a2n(&uval, *argv))
+                                       invarg("bad TOS value", *argv);
+                               tos = uval;
+                       } else
+                               tos = 1;
+               } else 
+                       usage();
+               argc--; argv++;
+       }
+
+       if (!ikey && IN_MULTICAST(ntohl(daddr))) {
+               ikey = daddr;
+               iflags |= GRE_KEY;
+       }
+       if (!okey && IN_MULTICAST(ntohl(daddr))) {
+               okey = daddr;
+               oflags |= GRE_KEY;
+       }
+       if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
+               fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+               return -1;
+       }
+
+       addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+       addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+       addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+       addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+       addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
+       addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
+       addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
+       if (link)
+               addattr32(n, 1024, IFLA_GRE_LINK, link);
+       addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
+       addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
+
+       return 0;
+}
+
+static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+       char s1[1024];
+       char s2[64];
+       const char *local = "any";
+       const char *remote = "any";
+       unsigned iflags = 0;
+       unsigned oflags = 0;
+
+       if (!tb)
+               return;
+
+       if (tb[IFLA_GRE_REMOTE]) {
+               unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
+
+               if (addr)
+                       remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+       }
+
+       fprintf(f, "remote %s ", remote);
+
+       if (tb[IFLA_GRE_LOCAL]) {
+               unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
+
+               if (addr)
+                       local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+       }
+
+       fprintf(f, "local %s ", local);
+
+       if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
+               unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
+               char *n = tnl_ioctl_get_ifname(link);
+
+               if (n)
+                       fprintf(f, "dev %s ", n);
+               else
+                       fprintf(f, "dev %u ", link);
+       }
+
+       if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
+               fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
+       else
+               fprintf(f, "ttl inherit ");
+
+       if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
+               int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
+
+               fputs("tos ", f);
+               if (tos == 1)
+                       fputs("inherit ", f);
+               else
+                       fprintf(f, "0x%x ", tos);
+       }
+
+       if (tb[IFLA_GRE_PMTUDISC] &&
+           !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
+               fputs("nopmtudisc ", f);
+
+       if (tb[IFLA_GRE_IFLAGS])
+               iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
+
+       if (tb[IFLA_GRE_OFLAGS])
+               oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
+
+       if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
+           *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
+               inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
+               fprintf(f, "ikey %s ", s2);
+       }
+
+       if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
+           *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
+               inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
+               fprintf(f, "ikey %s ", s2);
+       }
+
+       if (iflags & GRE_SEQ)
+               fputs("iseq ", f);
+       if (oflags & GRE_SEQ)
+               fputs("oseq ", f);
+       if (iflags & GRE_CSUM)
+               fputs("icsum ", f);
+       if (oflags & GRE_CSUM)
+               fputs("ocsum ", f);
+}
+
+struct link_util gre_link_util = {
+       .id = "gre",
+       .maxattr = IFLA_GRE_MAX,
+       .parse_opt = gre_parse_opt,
+       .print_opt = gre_print_opt,
+};
+
+struct link_util gretap_link_util = {
+       .id = "gretap",
+       .maxattr = IFLA_GRE_MAX,
+       .parse_opt = gre_parse_opt,
+       .print_opt = gre_print_opt,
+};
diff --git a/ip/link_veth.c b/ip/link_veth.c
new file mode 100644 (file)
index 0000000..9f5e871
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * link_veth.c veth driver module
+ *
+ *             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.
+ *
+ * Authors:    Pavel Emelianov <xemul@openvz.org>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/veth.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+       printf("Usage: ip link <options> type veth "
+              "[peer <options>]\nTo get <options> type "
+              "'ip link add help'\n");
+}
+
+static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
+                         struct nlmsghdr *hdr)
+{
+       char *name, *type, *link, *dev;
+       int err, len;
+       struct rtattr * data;
+
+       if (strcmp(argv[0], "peer") != 0) {
+               usage();
+               return -1;
+       }
+
+       data = NLMSG_TAIL(hdr);
+       addattr_l(hdr, 1024, VETH_INFO_PEER, NULL, 0);
+
+       hdr->nlmsg_len += sizeof(struct ifinfomsg);
+
+       err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
+                          &name, &type, &link, &dev);
+       if (err < 0)
+               return err;
+
+       if (name) {
+               len = strlen(name) + 1;
+               if (len > IFNAMSIZ)
+                       invarg("\"name\" too long\n", *argv);
+               addattr_l(hdr, 1024, IFLA_IFNAME, name, len);
+       }
+
+       data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+       return argc - 1 - err;
+}
+
+struct link_util veth_link_util = {
+       .id = "veth",
+       .parse_opt = veth_parse_opt,
+};
old mode 100755 (executable)
new mode 100644 (file)
index db43b5d..d266e2d
--- a/ip/routef
+++ b/ip/routef
@@ -1,3 +1,9 @@
 #! /bin/sh
 
-exec ip -4 ro flush  scope global  type unicast
+if [ -z "$*" ] ; then
+       exec ip -4 ro flush  scope global  type unicast
+else
+       echo "Usage: routef"
+       echo
+       echo "This script will flush the IPv4 routing table"
+fi
old mode 100755 (executable)
new mode 100644 (file)
index 5ce7731..7869b32 100644 (file)
@@ -17,7 +17,6 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/time.h>
-#include <net/if.h>
 #include <netinet/in.h>
 #include <string.h>
 
@@ -46,7 +45,7 @@ static void write_stamp(FILE *fp)
        fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp);
 }
 
-static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, 
+static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                    void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -134,18 +133,18 @@ main(int argc, char **argv)
                exit(-1);
        }
        if (llink)
-               groups |= RTMGRP_LINK;
+               groups |= nl_mgrp(RTNLGRP_LINK);
        if (laddr) {
                if (!family || family == AF_INET)
-                       groups |= RTMGRP_IPV4_IFADDR;
+                       groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
                if (!family || family == AF_INET6)
-                       groups |= RTMGRP_IPV6_IFADDR;
+                       groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
        }
        if (lroute) {
                if (!family || family == AF_INET)
-                       groups |= RTMGRP_IPV4_ROUTE;
+                       groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
                if (!family || family == AF_INET6)
-                       groups |= RTMGRP_IPV6_ROUTE;
+                       groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
        }
 
        fp = fopen(file, "w");
diff --git a/ip/rtpr b/ip/rtpr
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/ip/tunnel.c b/ip/tunnel.c
new file mode 100644 (file)
index 0000000..104340d
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * split from ip_tunnel.c
+ */
+/*
+ * Author:
+ *     Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+
+const char *tnl_strproto(__u8 proto)
+{
+       static char buf[16];
+
+       switch (proto) {
+       case IPPROTO_IPIP:
+               strcpy(buf, "ip");
+               break;
+       case IPPROTO_GRE:
+               strcpy(buf, "gre");
+               break;
+       case IPPROTO_IPV6:
+               strcpy(buf, "ipv6");
+               break;
+       case 0:
+               strcpy(buf, "any");
+               break;
+       default:
+               strcpy(buf, "unknown");
+               break;
+       }
+
+       return buf;
+}
+
+int tnl_ioctl_get_ifindex(const char *dev)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGIFINDEX, &ifr);
+       if (err) {
+               perror("ioctl");
+               return 0;
+       }
+       close(fd);
+       return ifr.ifr_ifindex;
+}
+
+int tnl_ioctl_get_iftype(const char *dev)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGIFHWADDR, &ifr);
+       if (err) {
+               perror("ioctl");
+               return -1;
+       }
+       close(fd);
+       return ifr.ifr_addr.sa_family;
+}
+
+
+char * tnl_ioctl_get_ifname(int idx)
+{
+       static struct ifreq ifr;
+       int fd;
+       int err;
+
+       ifr.ifr_ifindex = idx;
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGIFNAME, &ifr);
+       if (err) {
+               perror("ioctl");
+               return NULL;
+       }
+       close(fd);
+       return ifr.ifr_name;
+}
+
+int tnl_get_ioctl(const char *basedev, void *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+       strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+       ifr.ifr_ifru.ifru_data = (void*)p;
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGETTUNNEL, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
+
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+       if (cmd == SIOCCHGTUNNEL && name[0])
+               strncpy(ifr.ifr_name, name, IFNAMSIZ);
+       else
+               strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+       ifr.ifr_ifru.ifru_data = p;
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, cmd, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
+
+int tnl_del_ioctl(const char *basedev, const char *name, void *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+       if (name[0])
+               strncpy(ifr.ifr_name, name, IFNAMSIZ);
+       else
+               strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+       ifr.ifr_ifru.ifru_data = p;
+       fd = socket(preferred_family, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCDELTUNNEL, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
diff --git a/ip/tunnel.h b/ip/tunnel.h
new file mode 100644 (file)
index 0000000..1b58834
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * Author:
+ *     Masahide NAKAMURA @USAGI
+ */
+#ifndef __TUNNEL_H__
+#define __TUNNEL_H__ 1
+
+#include <linux/types.h>
+
+const char *tnl_strproto(__u8 proto);
+int tnl_ioctl_get_ifindex(const char *dev);
+int tnl_ioctl_get_iftype(const char *dev);
+char * tnl_ioctl_get_ifname(int idx);
+int tnl_get_ioctl(const char *basedev, void *p);
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p);
+int tnl_del_ioctl(const char *basedev, const char *name, void *p);
+
+#endif
index 4833b36..930bb3f 100644 (file)
--- a/ip/xfrm.h
+++ b/ip/xfrm.h
@@ -2,17 +2,17 @@
 
 /*
  * Copyright (C)2004 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -35,6 +35,9 @@
 #ifndef IPPPROTO_DCCP
 # define IPPROTO_DCCP  33
 #endif
+#ifndef IPPROTO_MH
+# define IPPROTO_MH    135
+#endif
 
 #define XFRMS_RTA(x)  ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_usersa_info))))
 #define XFRMS_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct xfrm_usersa_info))
@@ -52,6 +55,9 @@
 #define XFRMEXP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_expire))))
 #define XFRMPEXP_RTA(x)        ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))))
 
+#define XFRMREP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_report))))
+
+#define XFRMSAPD_RTA(x)        ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(__u32))))
 #define XFRM_FLAG_PRINT(fp, flags, f, s) \
        do { \
                if (flags & f) { \
@@ -92,6 +98,11 @@ struct xfrm_filter {
        __u32 index_mask;
        __u8 action_mask;
        __u32 priority_mask;
+       __u8 policy_flags_mask;
+
+       __u8 ptype;
+       __u8 ptype_mask;
+
 };
 #define XFRM_FILTER_MASK_FULL (~0)
 
@@ -106,6 +117,8 @@ int do_xfrm_policy(int argc, char **argv);
 int do_xfrm_monitor(int argc, char **argv);
 
 int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits);
+int xfrm_xfrmproto_is_ipsec(__u8 proto);
+int xfrm_xfrmproto_is_ro(__u8 proto);
 int xfrm_xfrmproto_getbyname(char *name);
 int xfrm_algotype_getbyname(char *name);
 const char *strxf_xfrmproto(__u8 proto);
@@ -114,6 +127,7 @@ const char *strxf_mask8(__u8 mask);
 const char *strxf_mask32(__u32 mask);
 const char *strxf_share(__u8 share);
 const char *strxf_proto(__u8 proto);
+const char *strxf_ptype(__u8 ptype);
 void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
                        __u8 mode, __u32 reqid, __u16 family, int force_spi,
                        FILE *fp, const char *prefix, const char *title);
index 153621f..dc12fca 100644 (file)
@@ -2,17 +2,17 @@
 
 /*
  * Copyright (C)2005 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -50,12 +50,6 @@ static int xfrm_acquire_print(const struct sockaddr_nl *who,
        struct rtattr * tb[XFRMA_MAX+1];
        __u16 family;
 
-       if (n->nlmsg_type != XFRM_MSG_ACQUIRE) {
-               fprintf(stderr, "Not an acquire: %08x %08x %08x\n",
-                       n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-               return 0;
-       }
-
        len -= NLMSG_LENGTH(sizeof(*xacq));
        if (len < 0) {
                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
@@ -108,6 +102,153 @@ static int xfrm_acquire_print(const struct sockaddr_nl *who,
        return 0;
 }
 
+static int xfrm_state_flush_print(const struct sockaddr_nl *who,
+                                 struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       struct xfrm_usersa_flush *xsf = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       const char *str;
+
+       len -= NLMSG_SPACE(sizeof(*xsf));
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
+
+       fprintf(fp, "Flushed state ");
+
+       str = strxf_xfrmproto(xsf->proto);
+       if (str)
+               fprintf(fp, "proto %s", str);
+       else
+               fprintf(fp, "proto %u", xsf->proto);
+       fprintf(fp, "%s", _SL_);
+
+       if (oneline)
+               fprintf(fp, "\n");
+       fflush(fp);
+
+       return 0;
+}
+
+static int xfrm_policy_flush_print(const struct sockaddr_nl *who,
+                                  struct nlmsghdr *n, void *arg)
+{
+       struct rtattr * tb[XFRMA_MAX+1];
+       FILE *fp = (FILE*)arg;
+       int len = n->nlmsg_len;
+
+       len -= NLMSG_SPACE(0);
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
+
+       fprintf(fp, "Flushed policy ");
+
+       parse_rtattr(tb, XFRMA_MAX, NLMSG_DATA(n), len);
+
+       if (tb[XFRMA_POLICY_TYPE]) {
+               struct xfrm_userpolicy_type *upt;
+
+               fprintf(fp, "ptype ");
+
+               if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt))
+                       fprintf(fp, "(ERROR truncated)");
+
+               upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+               fprintf(fp, "%s ", strxf_ptype(upt->type));
+       }
+
+       fprintf(fp, "%s", _SL_);
+
+       if (oneline)
+               fprintf(fp, "\n");
+       fflush(fp);
+
+       return 0;
+}
+
+static int xfrm_report_print(const struct sockaddr_nl *who,
+                            struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       struct xfrm_user_report *xrep = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr * tb[XFRMA_MAX+1];
+       __u16 family;
+
+       len -= NLMSG_LENGTH(sizeof(*xrep));
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
+
+       family = xrep->sel.family;
+       if (family == AF_UNSPEC)
+               family = preferred_family;
+
+       fprintf(fp, "report ");
+
+       fprintf(fp, "proto %s ", strxf_xfrmproto(xrep->proto));
+       fprintf(fp, "%s", _SL_);
+
+       xfrm_selector_print(&xrep->sel, family, fp, "  sel ");
+
+       parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len);
+
+       xfrm_xfrma_print(tb, family, fp, "  ");
+
+       if (oneline)
+               fprintf(fp, "\n");
+
+       return 0;
+}
+
+void xfrm_ae_flags_print(__u32 flags, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       fprintf(fp, " (0x%x) ", flags);
+       if (!flags)
+               return;
+       if (flags & XFRM_AE_CR)
+               fprintf(fp, " replay update ");
+       if (flags & XFRM_AE_CE)
+               fprintf(fp, " timer expired ");
+       if (flags & XFRM_AE_CU)
+               fprintf(fp, " policy updated ");
+
+}
+
+static int xfrm_ae_print(const struct sockaddr_nl *who,
+                            struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       struct xfrm_aevent_id *id = NLMSG_DATA(n);
+       char abuf[256];
+
+       fprintf(fp, "Async event ");
+       xfrm_ae_flags_print(id->flags, arg);
+       fprintf(fp,"\n\t");
+       memset(abuf, '\0', sizeof(abuf));
+       fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family,
+               sizeof(id->saddr), &id->saddr,
+               abuf, sizeof(abuf)));
+       memset(abuf, '\0', sizeof(abuf));
+       fprintf(fp, "dst %s ", rt_addr_n2a(id->sa_id.family,
+               sizeof(id->sa_id.daddr), &id->sa_id.daddr,
+               abuf, sizeof(abuf)));
+       fprintf(fp, " reqid 0x%x", id->reqid);
+       fprintf(fp, " protocol %s ", strxf_proto(id->sa_id.proto));
+       fprintf(fp, " SPI 0x%x", ntohl(id->sa_id.spi));
+
+       fprintf(fp, "\n");
+       fflush(fp);
+
+       return 0;
+}
+
 static int xfrm_accept_msg(const struct sockaddr_nl *who,
                           struct nlmsghdr *n, void *arg)
 {
@@ -116,34 +257,38 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who,
        if (timestamp)
                print_timestamp(fp);
 
-       if (n->nlmsg_type == XFRM_MSG_NEWSA ||
-           n->nlmsg_type == XFRM_MSG_DELSA ||
-           n->nlmsg_type == XFRM_MSG_UPDSA ||
-           n->nlmsg_type == XFRM_MSG_EXPIRE) {
+       switch (n->nlmsg_type) {
+       case XFRM_MSG_NEWSA:
+       case XFRM_MSG_DELSA:
+       case XFRM_MSG_UPDSA:
+       case XFRM_MSG_EXPIRE:
                xfrm_state_print(who, n, arg);
                return 0;
-       }
-       if (n->nlmsg_type == XFRM_MSG_NEWPOLICY ||
-           n->nlmsg_type == XFRM_MSG_DELPOLICY ||
-           n->nlmsg_type == XFRM_MSG_UPDPOLICY ||
-           n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
+       case XFRM_MSG_NEWPOLICY:
+       case XFRM_MSG_DELPOLICY:
+       case XFRM_MSG_UPDPOLICY:
+       case XFRM_MSG_POLEXPIRE:
                xfrm_policy_print(who, n, arg);
                return 0;
-       }
-
-       if (n->nlmsg_type == XFRM_MSG_ACQUIRE) {
+       case XFRM_MSG_ACQUIRE:
                xfrm_acquire_print(who, n, arg);
                return 0;
-       }
-       if (n->nlmsg_type == XFRM_MSG_FLUSHSA) {
-               /* XXX: Todo: show proto in xfrm_usersa_flush */
-               fprintf(fp, "Flushed state\n");
+       case XFRM_MSG_FLUSHSA:
+               xfrm_state_flush_print(who, n, arg);
                return 0;
-       }
-       if (n->nlmsg_type == XFRM_MSG_FLUSHPOLICY) {
-               fprintf(fp, "Flushed policy\n");
+       case XFRM_MSG_FLUSHPOLICY:
+               xfrm_policy_flush_print(who, n, arg);
+               return 0;
+       case XFRM_MSG_REPORT:
+               xfrm_report_print(who, n, arg);
                return 0;
+       case XFRM_MSG_NEWAE:
+               xfrm_ae_print(who, n, arg);
+               return 0;
+       default:
+               break;
        }
+
        if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
            n->nlmsg_type != NLMSG_DONE) {
                fprintf(fp, "Unknown message: %08d 0x%08x 0x%08x\n",
@@ -152,15 +297,20 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who,
        return 0;
 }
 
+extern struct rtnl_handle rth;
+
 int do_xfrm_monitor(int argc, char **argv)
 {
-       struct rtnl_handle rth;
        char *file = NULL;
        unsigned groups = ~((unsigned)0); /* XXX */
        int lacquire=0;
        int lexpire=0;
+       int laevent=0;
        int lpolicy=0;
        int lsa=0;
+       int lreport=0;
+
+       rtnl_close(&rth);
 
        while (argc > 0) {
                if (matches(*argv, "file") == 0) {
@@ -175,9 +325,15 @@ int do_xfrm_monitor(int argc, char **argv)
                } else if (matches(*argv, "SA") == 0) {
                        lsa=1;
                        groups = 0;
+               } else if (matches(*argv, "aevent") == 0) {
+                       laevent=1;
+                       groups = 0;
                } else if (matches(*argv, "policy") == 0) {
                        lpolicy=1;
                        groups = 0;
+               } else if (matches(*argv, "report") == 0) {
+                       lreport=1;
+                       groups = 0;
                } else if (matches(*argv, "help") == 0) {
                        usage();
                } else {
@@ -188,13 +344,17 @@ int do_xfrm_monitor(int argc, char **argv)
        }
 
        if (lacquire)
-               groups |= XFRMGRP_ACQUIRE;
+               groups |= nl_mgrp(XFRMNLGRP_ACQUIRE);
        if (lexpire)
-               groups |= XFRMGRP_EXPIRE;
+               groups |= nl_mgrp(XFRMNLGRP_EXPIRE);
        if (lsa)
-               groups |= XFRMGRP_SA;
+               groups |= nl_mgrp(XFRMNLGRP_SA);
        if (lpolicy)
-               groups |= XFRMGRP_POLICY;
+               groups |= nl_mgrp(XFRMNLGRP_POLICY);
+       if (laevent)
+               groups |= nl_mgrp(XFRMNLGRP_AEVENTS);
+       if (lreport)
+               groups |= nl_mgrp(XFRMNLGRP_REPORT);
 
        if (file) {
                FILE *fp;
index 433b513..11116e5 100644 (file)
@@ -2,17 +2,17 @@
 
 /*
  * Copyright (C)2004 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -53,12 +53,14 @@ static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: ip xfrm policy { add | update } dir DIR SELECTOR [ index INDEX ] \n");
-       fprintf(stderr, "        [ action ACTION ] [ priority PRIORITY ] [ LIMIT-LIST ] [ TMPL-LIST ]\n");
-       fprintf(stderr, "Usage: ip xfrm policy { delete | get } dir DIR [ SELECTOR | index INDEX ]\n");
+       fprintf(stderr, "Usage: ip xfrm policy { add | update } dir DIR SELECTOR [ index INDEX ] [ ptype PTYPE ]\n");
+       fprintf(stderr, "        [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ] [ LIMIT-LIST ] [ TMPL-LIST ]\n");
+       fprintf(stderr, "Usage: ip xfrm policy { delete | get } dir DIR [ SELECTOR | index INDEX ] [ ptype PTYPE ]\n");
        fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ dir DIR ] [ SELECTOR ]\n");
-       fprintf(stderr, "        [ index INDEX ] [ action ACTION ] [ priority PRIORITY ]\n");
-       fprintf(stderr, "Usage: ip xfrm policy flush\n");
+       fprintf(stderr, "        [ index INDEX ] [ action ACTION ] [ priority PRIORITY ]  [ flag FLAG-LIST ]\n");
+       fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
+       fprintf(stderr, "Usage: ip xfrm count\n");
+       fprintf(stderr, "PTYPE := [ main | sub ](default=main)\n");
        fprintf(stderr, "DIR := [ in | out | fwd ]\n");
 
        fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n");
@@ -72,6 +74,9 @@ static void usage(void)
 
        //fprintf(stderr, "PRIORITY - priority value(default=0)\n");
 
+       fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
+       fprintf(stderr, "FLAG := [ localok ]\n");
+
        fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
        fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
        fprintf(stderr, "         [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] NUMBER ]\n");
@@ -80,14 +85,15 @@ static void usage(void)
        fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n");
        fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
 
-       //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
        fprintf(stderr, "XFRM_PROTO := [ ");
        fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
        fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
-       fprintf(stderr, "%s", strxf_xfrmproto(IPPROTO_COMP));
-       fprintf(stderr, " ]\n");
+       fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
+       fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
+       fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS));
+       fprintf(stderr, "]\n");
 
-       fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n");
+       fprintf(stderr, "MODE := [ transport | tunnel | beet ](default=transport)\n");
        //fprintf(stderr, "REQID - number(default=0)\n");
        fprintf(stderr, "LEVEL := [ required | use ](default=required)\n");
 
@@ -114,6 +120,57 @@ static int xfrm_policy_dir_parse(__u8 *dir, int *argcp, char ***argvp)
        return 0;
 }
 
+static int xfrm_policy_ptype_parse(__u8 *ptype, int *argcp, char ***argvp)
+{
+       int argc = *argcp;
+       char **argv = *argvp;
+
+       if (strcmp(*argv, "main") == 0)
+               *ptype = XFRM_POLICY_TYPE_MAIN;
+       else if (strcmp(*argv, "sub") == 0)
+               *ptype = XFRM_POLICY_TYPE_SUB;
+       else
+               invarg("\"PTYPE\" is invalid", *argv);
+
+       *argcp = argc;
+       *argvp = argv;
+
+       return 0;
+}
+
+static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp)
+{
+       int argc = *argcp;
+       char **argv = *argvp;
+       int len = strlen(*argv);
+
+       if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
+               __u8 val = 0;
+
+               if (get_u8(&val, *argv, 16))
+                       invarg("\"FLAG\" is invalid", *argv);
+               *flags = val;
+       } else {
+               while (1) {
+                       if (strcmp(*argv, "localok") == 0)
+                               *flags |= XFRM_POLICY_LOCALOK;
+                       else {
+                               PREV_ARG(); /* back track */
+                               break;
+                       }
+
+                       if (!NEXT_ARG_OK())
+                               break;
+                       NEXT_ARG();
+               }
+       }
+
+       *argcp = argc;
+       *argvp = argv;
+
+       return 0;
+}
+
 static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl,
                           int *argcp, char ***argvp)
 {
@@ -174,10 +231,13 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
        } req;
        char *dirp = NULL;
        char *selp = NULL;
+       char *ptypep = NULL;
+       struct xfrm_userpolicy_type upt;
        char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
        int tmpls_len = 0;
 
        memset(&req, 0, sizeof(req));
+       memset(&upt, 0, sizeof(upt));
        memset(&tmpls_buf, 0, sizeof(tmpls_buf));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
@@ -198,16 +258,17 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
 
                        NEXT_ARG();
                        xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);
-
-                       filter.dir_mask = XFRM_FILTER_MASK_FULL;
-
                } else if (strcmp(*argv, "index") == 0) {
                        NEXT_ARG();
                        if (get_u32(&req.xpinfo.index, *argv, 0))
                                invarg("\"INDEX\" is invalid", *argv);
+               } else if (strcmp(*argv, "ptype") == 0) {
+                       if (ptypep)
+                               duparg("ptype", *argv);
+                       ptypep = *argv;
 
-                       filter.index_mask = XFRM_FILTER_MASK_FULL;
-
+                       NEXT_ARG();
+                       xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
                } else if (strcmp(*argv, "action") == 0) {
                        NEXT_ARG();
                        if (strcmp(*argv, "allow") == 0)
@@ -216,16 +277,14 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
                                req.xpinfo.action = XFRM_POLICY_BLOCK;
                        else
                                invarg("\"action\" value is invalid\n", *argv);
-
-                       filter.action_mask = XFRM_FILTER_MASK_FULL;
-
                } else if (strcmp(*argv, "priority") == 0) {
                        NEXT_ARG();
                        if (get_u32(&req.xpinfo.priority, *argv, 0))
                                invarg("\"PRIORITY\" is invalid", *argv);
-
-                       filter.priority_mask = XFRM_FILTER_MASK_FULL;
-
+               } else if (strcmp(*argv, "flag") == 0) {
+                       NEXT_ARG();
+                       xfrm_policy_flag_parse(&req.xpinfo.flags, &argc,
+                                              &argv);
                } else if (strcmp(*argv, "limit") == 0) {
                        NEXT_ARG();
                        xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
@@ -265,6 +324,11 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
                exit(1);
        }
 
+       if (ptypep) {
+               addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+                         (void *)&upt, sizeof(upt));
+       }
+
        if (tmpls_len > 0) {
                addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
                          (void *)tmpls_buf, tmpls_len);
@@ -284,7 +348,8 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
        return 0;
 }
 
-static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo)
+static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo,
+                                   __u8 ptype)
 {
        if (!filter.use)
                return 1;
@@ -292,6 +357,9 @@ static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo)
        if ((xpinfo->dir^filter.xpinfo.dir)&filter.dir_mask)
                return 0;
 
+       if ((ptype^filter.ptype)&filter.ptype_mask)
+               return 0;
+
        if (filter.sel_src_mask) {
                if (xfrm_addr_match(&xpinfo->sel.saddr, &filter.xpinfo.sel.saddr,
                                    filter.sel_src_mask))
@@ -329,6 +397,10 @@ static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo)
        if ((xpinfo->priority^filter.xpinfo.priority)&filter.priority_mask)
                return 0;
 
+       if (filter.policy_flags_mask)
+               if ((xpinfo->flags & filter.xpinfo.flags) == 0)
+                       return 0;
+
        return 1;
 }
 
@@ -340,6 +412,7 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
        struct xfrm_userpolicy_info *xpinfo = NULL;
        struct xfrm_user_polexpire *xpexp = NULL;
        struct xfrm_userpolicy_id *xpid = NULL;
+       __u8 ptype = XFRM_POLICY_TYPE_MAIN;
        FILE *fp = (FILE*)arg;
        int len = n->nlmsg_len;
 
@@ -354,15 +427,15 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        if (n->nlmsg_type == XFRM_MSG_DELPOLICY)  {
                xpid = NLMSG_DATA(n);
-               len -= NLMSG_LENGTH(sizeof(*xpid));
+               len -= NLMSG_SPACE(sizeof(*xpid));
        } else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
                xpexp = NLMSG_DATA(n);
                xpinfo = &xpexp->pol;
-               len -= NLMSG_LENGTH(sizeof(*xpexp));
+               len -= NLMSG_SPACE(sizeof(*xpexp));
        } else {
                xpexp = NULL;
                xpinfo = NLMSG_DATA(n);
-               len -= NLMSG_LENGTH(sizeof(*xpinfo));
+               len -= NLMSG_SPACE(sizeof(*xpinfo));
        }
 
        if (len < 0) {
@@ -370,16 +443,6 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
                return -1;
        }
 
-       if (xpinfo && !xfrm_policy_filter_match(xpinfo))
-               return 0;
-
-       if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
-               fprintf(fp, "Deleted ");
-       else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY)
-               fprintf(fp, "Updated ");
-       else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
-               fprintf(fp, "Expired ");
-
        if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
                rta = XFRMPID_RTA(xpid);
        else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
@@ -389,6 +452,27 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        parse_rtattr(tb, XFRMA_MAX, rta, len);
 
+       if (tb[XFRMA_POLICY_TYPE]) {
+               struct xfrm_userpolicy_type *upt;
+
+               if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
+                       fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
+                       return -1;
+               }
+               upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+               ptype = upt->type;
+       }
+
+       if (xpinfo && !xfrm_policy_filter_match(xpinfo, ptype))
+               return 0;
+
+       if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
+               fprintf(fp, "Deleted ");
+       else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY)
+               fprintf(fp, "Updated ");
+       else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
+               fprintf(fp, "Expired ");
+
        if (n->nlmsg_type == XFRM_MSG_DELPOLICY) {
                //xfrm_policy_id_print();
                if (!tb[XFRMA_POLICY]) {
@@ -424,12 +508,16 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
        struct {
                struct nlmsghdr                 n;
                struct xfrm_userpolicy_id       xpid;
+               char                            buf[RTA_BUF_SIZE];
        } req;
        char *dirp = NULL;
        char *selp = NULL;
        char *indexp = NULL;
+       char *ptypep = NULL;
+       struct xfrm_userpolicy_type upt;
 
        memset(&req, 0, sizeof(req));
+       memset(&upt, 0, sizeof(upt));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid));
        req.n.nlmsg_flags = NLM_F_REQUEST;
@@ -453,6 +541,14 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
                        if (get_u32(&req.xpid.index, *argv, 0))
                                invarg("\"INDEX\" is invalid", *argv);
 
+               } else if (strcmp(*argv, "ptype") == 0) {
+                       if (ptypep)
+                               duparg("ptype", *argv);
+                       ptypep = *argv;
+
+                       NEXT_ARG();
+                       xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
+
                } else {
                        if (selp)
                                invarg("unknown", *argv);
@@ -471,6 +567,10 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
                fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
                exit(1);
        }
+       if (ptypep) {
+               addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+                         (void *)&upt, sizeof(upt));
+       }
        if (!selp && !indexp) {
                fprintf(stderr, "Not enough information: either \"SELECTOR\" or \"INDEX\" is required.\n");
                exit(1);
@@ -526,6 +626,8 @@ static int xfrm_policy_keep(const struct sockaddr_nl *who,
        struct rtnl_handle *rth = xb->rth;
        struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n);
        int len = n->nlmsg_len;
+       struct rtattr *tb[XFRMA_MAX+1];
+       __u8 ptype = XFRM_POLICY_TYPE_MAIN;
        struct nlmsghdr *new_n;
        struct xfrm_userpolicy_id *xpid;
 
@@ -541,7 +643,20 @@ static int xfrm_policy_keep(const struct sockaddr_nl *who,
                return -1;
        }
 
-       if (!xfrm_policy_filter_match(xpinfo))
+       parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len);
+
+       if (tb[XFRMA_POLICY_TYPE]) {
+               struct xfrm_userpolicy_type *upt;
+
+               if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
+                       fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
+                       return -1;
+               }
+               upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+               ptype = upt->type;
+       }
+
+       if (!xfrm_policy_filter_match(xpinfo, ptype))
                return 0;
 
        if (xb->offset > xb->size) {
@@ -589,6 +704,12 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
 
                        filter.index_mask = XFRM_FILTER_MASK_FULL;
 
+               } else if (strcmp(*argv, "ptype") == 0) {
+                       NEXT_ARG();
+                       xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv);
+
+                       filter.ptype_mask = XFRM_FILTER_MASK_FULL;
+
                } else if (strcmp(*argv, "action") == 0) {
                        NEXT_ARG();
                        if (strcmp(*argv, "allow") == 0)
@@ -607,6 +728,13 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
 
                        filter.priority_mask = XFRM_FILTER_MASK_FULL;
 
+               } else if (strcmp(*argv, "flag") == 0) {
+                       NEXT_ARG();
+                       xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc,
+                                              &argv);
+
+                       filter.policy_flags_mask = XFRM_FILTER_MASK_FULL;
+
                } else {
                        if (selp)
                                invarg("unknown", *argv);
@@ -655,8 +783,8 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
                                break;
                        }
 
-                       if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
-                               perror("Failed to send delete-all request\n");
+                       if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
+                               perror("Failed to send delete-all request");
                                exit(1);
                        }
                        if (show_stats > 1)
@@ -682,19 +810,131 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
        exit(0);
 }
 
-static int xfrm_policy_flush(void)
+int print_spdinfo( struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       __u32 *f = NLMSG_DATA(n);
+       struct rtattr * tb[XFRMA_SPD_MAX+1];
+       struct rtattr * rta;
+
+       int len = n->nlmsg_len;
+
+       len -= NLMSG_LENGTH(sizeof(__u32));
+       if (len < 0) {
+               fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+               return -1;
+       }
+
+       rta = XFRMSAPD_RTA(f);
+       parse_rtattr(tb, XFRMA_SPD_MAX, rta, len);
+
+       fprintf(fp,"\t SPD");
+       if (tb[XFRMA_SPD_INFO]) {
+               struct xfrmu_spdinfo *si;
+
+               if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) {
+                       fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+                       return -1;
+               }
+               si = RTA_DATA(tb[XFRMA_SPD_INFO]);
+               fprintf(fp," IN  %d", si->incnt);
+               fprintf(fp," OUT %d", si->outcnt);
+               fprintf(fp," FWD %d", si->fwdcnt);
+
+               if (show_stats) {
+                       fprintf(fp," (Sock:");
+                       fprintf(fp," IN %d", si->inscnt);
+                       fprintf(fp," OUT %d", si->outscnt);
+                       fprintf(fp," FWD %d", si->fwdscnt);
+                       fprintf(fp,")");
+               }
+
+               fprintf(fp,"\n");
+       }
+       if (show_stats > 1) {
+               struct xfrmu_spdhinfo *sh;
+
+               if (tb[XFRMA_SPD_HINFO]) {
+                       if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) {
+                               fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+                               return -1;
+                       }
+                       sh = RTA_DATA(tb[XFRMA_SPD_HINFO]);
+                       fprintf(fp,"\t SPD buckets:");
+                       fprintf(fp," count %d", sh->spdhcnt);
+                       fprintf(fp," Max %d", sh->spdhmcnt);
+               }
+       }
+       fprintf(fp,"\n");
+
+        return 0;
+}
+
+static int xfrm_spd_getinfo(int argc, char **argv)
+{
+       struct rtnl_handle rth;
+       struct {
+               struct nlmsghdr                 n;
+               __u32                           flags;
+               char                            ans[128];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = XFRM_MSG_GETSPDINFO;
+       req.flags = 0XFFFFFFFF;
+
+       if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+               exit(1);
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
+               exit(2);
+
+       print_spdinfo(&req.n, (void*)stdout);
+
+       rtnl_close(&rth);
+
+       return 0;
+}
+
+static int xfrm_policy_flush(int argc, char **argv)
 {
        struct rtnl_handle rth;
        struct {
                struct nlmsghdr n;
+               char            buf[RTA_BUF_SIZE];
        } req;
+       char *ptypep = NULL;
+       struct xfrm_userpolicy_type upt;
 
        memset(&req, 0, sizeof(req));
+       memset(&upt, 0, sizeof(upt));
 
        req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */
        req.n.nlmsg_flags = NLM_F_REQUEST;
        req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY;
 
+       while (argc > 0) {
+               if (strcmp(*argv, "ptype") == 0) {
+                       if (ptypep)
+                               duparg("ptype", *argv);
+                       ptypep = *argv;
+
+                       NEXT_ARG();
+                       xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
+               } else
+                       invarg("unknown", *argv);
+
+               argc--; argv++;
+       }
+
+       if (ptypep) {
+               addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+                         (void *)&upt, sizeof(upt));
+       }
+
        if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
                exit(1);
 
@@ -730,7 +970,9 @@ int do_xfrm_policy(int argc, char **argv)
        if (matches(*argv, "get") == 0)
                return xfrm_policy_get(argc-1, argv+1);
        if (matches(*argv, "flush") == 0)
-               return xfrm_policy_flush();
+               return xfrm_policy_flush(argc-1, argv+1);
+       if (matches(*argv, "count") == 0)
+               return xfrm_spd_getinfo(argc, argv);
        if (matches(*argv, "help") == 0)
                usage();
        fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
index 3eefaff..b1e3f22 100644 (file)
@@ -2,17 +2,17 @@
 
 /*
  * Copyright (C)2004 USAGI/WIDE Project
- * 
+ *
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -55,38 +55,44 @@ static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
+       fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ XFRM_OPT ] [ mode MODE ]\n");
        fprintf(stderr, "        [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n");
-       fprintf(stderr, "        [ encap ENCAP ] [ sel SELECTOR ] [ LIMIT-LIST ]\n");
+       fprintf(stderr, "        [ encap ENCAP ] [ sel SELECTOR ] [ replay-seq SEQ ]\n");
+       fprintf(stderr, "        [ replay-oseq SEQ ] [ LIMIT-LIST ]\n");
        fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n");
        fprintf(stderr, "        [ min SPI max SPI ]\n");
        fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n");
        fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
-       fprintf(stderr, "        [ flag FLAG_LIST ]\n");
+       fprintf(stderr, "        [ flag FLAG-LIST ]\n");
        fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM_PROTO ]\n");
+       fprintf(stderr, "Usage: ip xfrm state count \n");
 
        fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
        //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
        fprintf(stderr, "XFRM_PROTO := [ ");
        fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
        fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
-       fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_COMP));
+       fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
+       fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
+       fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS));
        fprintf(stderr, "]\n");
 
        //fprintf(stderr, "SPI - security parameter index(default=0)\n");
 
-       fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n");
+       fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n");
        //fprintf(stderr, "REQID - number(default=0)\n");
 
        fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
-       fprintf(stderr, "FLAG := [ noecn | decap-dscp ]\n");
+       fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv ]\n");
+
         fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
         fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
 
        fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
-       fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
+       fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY "
+                       "[ ALGO_ICV_LEN ]\n");
        fprintf(stderr, "ALGO_TYPE := [ ");
+       fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AEAD));
        fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
        fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
        fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP));
@@ -109,7 +115,7 @@ static void usage(void)
 }
 
 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
-                          char *name, char *key, int max)
+                          char *name, char *key, char *buf, int max)
 {
        int len;
        int slen = strlen(key);
@@ -149,7 +155,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
                        if (get_u8(&val, vbuf, 16))
                                invarg("\"ALGOKEY\" is invalid", key);
 
-                       alg->alg_key[j] = val;
+                       buf[j] = val;
                }
        } else {
                len = slen;
@@ -157,7 +163,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
                        if (len > max)
                                invarg("\"ALGOKEY\" makes buffer overflow\n", key);
 
-                       strncpy(alg->alg_key, key, len);
+                       strncpy(buf, key, len);
                }
        }
 
@@ -200,6 +206,10 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
                                *flags |= XFRM_STATE_NOECN;
                        else if (strcmp(*argv, "decap-dscp") == 0)
                                *flags |= XFRM_STATE_DECAP_DSCP;
+                       else if (strcmp(*argv, "nopmtudisc") == 0)
+                               *flags |= XFRM_STATE_NOPMTUDISC;
+                       else if (strcmp(*argv, "wildrecv") == 0)
+                               *flags |= XFRM_STATE_WILDRECV;
                        else {
                                PREV_ARG(); /* back track */
                                break;
@@ -211,8 +221,6 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
                }
        }
 
-       filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
-
        *argcp = argc;
        *argvp = argv;
 
@@ -227,12 +235,16 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                struct xfrm_usersa_info xsinfo;
                char                    buf[RTA_BUF_SIZE];
        } req;
+       struct xfrm_replay_state replay;
        char *idp = NULL;
+       char *aeadop = NULL;
        char *ealgop = NULL;
        char *aalgop = NULL;
        char *calgop = NULL;
+       char *coap = NULL;
 
        memset(&req, 0, sizeof(req));
+       memset(&replay, 0, sizeof(replay));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
        req.n.nlmsg_flags = NLM_F_REQUEST|flags;
@@ -258,6 +270,14 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                        NEXT_ARG();
                        if (get_u8(&req.xsinfo.replay_window, *argv, 0))
                                invarg("\"replay-window\" value is invalid", *argv);
+               } else if (strcmp(*argv, "replay-seq") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&replay.seq, *argv, 0))
+                               invarg("\"replay-seq\" value is invalid", *argv);
+               } else if (strcmp(*argv, "replay-oseq") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&replay.oseq, *argv, 0))
+                               invarg("\"replay-oseq\" value is invalid", *argv);
                } else if (strcmp(*argv, "flag") == 0) {
                        NEXT_ARG();
                        xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
@@ -285,24 +305,56 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                        memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
                        addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
                                  (void *)&encap, sizeof(encap));
+               } else if (strcmp(*argv, "coa") == 0) {
+                       inet_prefix coa;
+                       xfrm_address_t xcoa;
+
+                       if (coap)
+                               duparg("coa", *argv);
+                       coap = *argv;
+
+                       NEXT_ARG();
+
+                       get_prefix(&coa, *argv, preferred_family);
+                       if (coa.family == AF_UNSPEC)
+                               invarg("\"coa\" address family is AF_UNSPEC", *argv);
+                       if (coa.bytelen > sizeof(xcoa))
+                               invarg("\"coa\" address length is too large", *argv);
+
+                       memset(&xcoa, 0, sizeof(xcoa));
+                       memcpy(&xcoa, &coa.data, coa.bytelen);
+
+                       addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
+                                 (void *)&xcoa, sizeof(xcoa));
                } else {
                        /* try to assume ALGO */
                        int type = xfrm_algotype_getbyname(*argv);
                        switch (type) {
+                       case XFRMA_ALG_AEAD:
                        case XFRMA_ALG_CRYPT:
                        case XFRMA_ALG_AUTH:
                        case XFRMA_ALG_COMP:
                        {
                                /* ALGO */
                                struct {
-                                       struct xfrm_algo alg;
+                                       union {
+                                               struct xfrm_algo alg;
+                                               struct xfrm_algo_aead aead;
+                                       } u;
                                        char buf[XFRM_ALGO_KEY_BUF_SIZE];
-                               } alg;
+                               } alg = {};
                                int len;
+                               __u32 icvlen;
                                char *name;
                                char *key;
+                               char *buf;
 
                                switch (type) {
+                               case XFRMA_ALG_AEAD:
+                                       if (aeadop)
+                                               duparg("ALGOTYPE", *argv);
+                                       aeadop = *argv;
+                                       break;
                                case XFRMA_ALG_CRYPT:
                                        if (ealgop)
                                                duparg("ALGOTYPE", *argv);
@@ -333,11 +385,27 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                                NEXT_ARG();
                                key = *argv;
 
-                               memset(&alg, 0, sizeof(alg));
+                               buf = alg.u.alg.alg_key;
+                               len = sizeof(alg.u.alg);
+
+                               if (type != XFRMA_ALG_AEAD)
+                                       goto parse_algo;
 
+                               if (!NEXT_ARG_OK())
+                                       missarg("ALGOICVLEN");
+                               NEXT_ARG();
+                               if (get_u32(&icvlen, *argv, 0))
+                                       invarg("\"aead\" ICV length is invalid",
+                                              *argv);
+                               alg.u.aead.alg_icv_len = icvlen;
+
+                               buf = alg.u.aead.alg_key;
+                               len = sizeof(alg.u.aead);
+
+parse_algo:
                                xfrm_algo_parse((void *)&alg, type, name, key,
-                                               sizeof(alg.buf));
-                               len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
+                                               buf, sizeof(alg.buf));
+                               len += alg.u.alg.alg_key_len;
 
                                addattr_l(&req.n, sizeof(req.buf), type,
                                          (void *)&alg, len);
@@ -359,23 +427,65 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                argc--; argv++;
        }
 
+       if (replay.seq || replay.oseq)
+               addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
+                         (void *)&replay, sizeof(replay));
+
        if (!idp) {
                fprintf(stderr, "Not enough information: \"ID\" is required\n");
                exit(1);
        }
 
-       if (ealgop || aalgop || calgop) {
-               if (req.xsinfo.id.proto != IPPROTO_ESP &&
-                   req.xsinfo.id.proto != IPPROTO_AH &&
-                   req.xsinfo.id.proto != IPPROTO_COMP) {
-                       fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
+       switch (req.xsinfo.mode) {
+       case XFRM_MODE_TRANSPORT:
+       case XFRM_MODE_TUNNEL:
+               if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
+                       exit(1);
+               }
+               break;
+       case XFRM_MODE_ROUTEOPTIMIZATION:
+       case XFRM_MODE_IN_TRIGGER:
+               if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
+                       exit(1);
+               }
+               if (req.xsinfo.id.spi != 0) {
+                       fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
+                       exit(1);
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (aeadop || ealgop || aalgop || calgop) {
+               if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
+                       exit(1);
+               }
+       } else {
+               if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
+                       exit (1);
+               }
+       }
+
+       if (coap) {
+               if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
                        exit(1);
                }
        } else {
-               if (req.xsinfo.id.proto == IPPROTO_ESP ||
-                   req.xsinfo.id.proto == IPPROTO_AH ||
-                   req.xsinfo.id.proto == IPPROTO_COMP) {
-                       fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
+               if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+                       fprintf(stderr, "\"coa\" is required with proto=%s\n",
+                               strxf_xfrmproto(req.xsinfo.id.proto));
                        exit (1);
                }
        }
@@ -575,15 +685,15 @@ int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
        if (n->nlmsg_type == XFRM_MSG_DELSA) {
                /* Dont blame me for this .. Herbert made me do it */
                xsid = NLMSG_DATA(n);
-               len -= NLMSG_LENGTH(sizeof(*xsid));
+               len -= NLMSG_SPACE(sizeof(*xsid));
        } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
                xexp = NLMSG_DATA(n);
                xsinfo = &xexp->state;
-               len -= NLMSG_LENGTH(sizeof(*xexp));
+               len -= NLMSG_SPACE(sizeof(*xexp));
        } else {
                xexp = NULL;
                xsinfo = NLMSG_DATA(n);
-               len -= NLMSG_LENGTH(sizeof(*xsinfo));
+               len -= NLMSG_SPACE(sizeof(*xsinfo));
        }
 
        if (len < 0) {
@@ -605,7 +715,7 @@ int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
                rta = XFRMSID_RTA(xsid);
        else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
                rta = XFRMEXP_RTA(xexp);
-       else 
+       else
                rta = XFRMS_RTA(xsinfo);
 
        parse_rtattr(tb, XFRMA_MAX, rta, len);
@@ -621,7 +731,7 @@ int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
                        fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
                        return -1;
                }
-               xsinfo = (struct xfrm_usersa_info *)RTA_DATA(tb[XFRMA_SA]);
+               xsinfo = RTA_DATA(tb[XFRMA_SA]);
        }
 
        xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
@@ -645,6 +755,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
        struct {
                struct nlmsghdr         n;
                struct xfrm_usersa_id   xsid;
+               char                    buf[RTA_BUF_SIZE];
        } req;
        struct xfrm_id id;
        char *idp = NULL;
@@ -657,12 +768,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
        req.xsid.family = preferred_family;
 
        while (argc > 0) {
-               /*
-                * XXX: Source address is not used and ignore it to follow
-                * XXX: a manner of setkey e.g. in the case of deleting/getting
-                * XXX: message of IPsec SA.
-                */
-               xfrm_address_t ignore_saddr;
+               xfrm_address_t saddr;
 
                if (idp)
                        invarg("unknown", *argv);
@@ -670,13 +776,17 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
 
                /* ID */
                memset(&id, 0, sizeof(id));
-               xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
+               memset(&saddr, 0, sizeof(saddr));
+               xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
                              &argc, &argv);
 
                memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
                req.xsid.spi = id.spi;
                req.xsid.proto = id.proto;
 
+               addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
+                         (void *)&saddr, sizeof(saddr));
+
                argc--; argv++;
        }
 
@@ -756,6 +866,9 @@ static int xfrm_state_keep(const struct sockaddr_nl *who,
        xsid->spi = xsinfo->id.spi;
        xsid->proto = xsinfo->id.proto;
 
+       addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
+                 sizeof(xsid->daddr));
+
        xb->offset += new_n->nlmsg_len;
        xb->nlmsg_count ++;
 
@@ -838,7 +951,7 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
                                break;
                        }
 
-                       if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
+                       if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
                                perror("Failed to send delete-all request\n");
                                exit(1);
                        }
@@ -866,6 +979,83 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
        exit(0);
 }
 
+int print_sadinfo(struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+       __u32 *f = NLMSG_DATA(n);
+       struct rtattr *tb[XFRMA_SAD_MAX+1];
+       struct rtattr *rta;
+       __u32 *cnt;
+
+       int len = n->nlmsg_len;
+
+       len -= NLMSG_LENGTH(sizeof(__u32));
+       if (len < 0) {
+               fprintf(stderr, "SADinfo: Wrong len %d\n", len);
+               return -1;
+       }
+
+       rta = XFRMSAPD_RTA(f);
+       parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
+
+       if (tb[XFRMA_SAD_CNT]) {
+               fprintf(fp,"\t SAD");
+               cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
+               fprintf(fp," count %d", *cnt);
+       } else {
+               fprintf(fp,"BAD SAD info returned\n");
+               return -1;
+       }
+
+       if (show_stats) {
+               if (tb[XFRMA_SAD_HINFO]) {
+                       struct xfrmu_sadhinfo *si;
+
+                       if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
+                               fprintf(fp,"BAD SAD length returned\n");
+                               return -1;
+                       }
+                               
+                       si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
+                       fprintf(fp," (buckets ");
+                       fprintf(fp,"count %d", si->sadhcnt);
+                       fprintf(fp," Max %d", si->sadhmcnt);
+                       fprintf(fp,")");
+               }
+       }
+       fprintf(fp,"\n");
+
+        return 0;
+}
+
+static int xfrm_sad_getinfo(int argc, char **argv)
+{
+       struct rtnl_handle rth;
+       struct {
+               struct nlmsghdr                 n;
+               __u32                           flags;
+               char                            ans[64];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
+       req.flags = 0XFFFFFFFF;
+
+       if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+               exit(1);
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
+               exit(2);
+
+       print_sadinfo(&req.n, (void*)stdout);
+
+       rtnl_close(&rth);
+
+       return 0;
+}
+
 static int xfrm_state_flush(int argc, char **argv)
 {
        struct rtnl_handle rth;
@@ -880,7 +1070,7 @@ static int xfrm_state_flush(int argc, char **argv)
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
        req.n.nlmsg_flags = NLM_F_REQUEST;
        req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
-       req.xsf.proto = IPSEC_PROTO_ANY;
+       req.xsf.proto = 0;
 
        while (argc > 0) {
                if (strcmp(*argv, "proto") == 0) {
@@ -908,7 +1098,6 @@ static int xfrm_state_flush(int argc, char **argv)
 
        if (show_stats > 1)
                fprintf(stderr, "Flush state proto=%s\n",
-                       (req.xsf.proto == IPSEC_PROTO_ANY) ? "any" :
                        strxf_xfrmproto(req.xsf.proto));
 
        if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
@@ -943,6 +1132,9 @@ int do_xfrm_state(int argc, char **argv)
                return xfrm_state_get_or_delete(argc-1, argv+1, 0);
        if (matches(*argv, "flush") == 0)
                return xfrm_state_flush(argc-1, argv+1);
+       if (matches(*argv, "count") == 0) {
+               return xfrm_sad_getinfo(argc, argv);
+       }
        if (matches(*argv, "help") == 0)
                usage();
        fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
diff --git a/iproute.spec b/iproute.spec
deleted file mode 100644 (file)
index 022a794..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-#
-# $Id$
-#
-%define url $URL$
-
-%define name iproute
-%define version 2.6.16
-%define taglevel 1
-
-%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
-
-Vendor: PlanetLab
-Packager: PlanetLab Central <support@planet-lab.org>
-Distribution: PlanetLab %{plrelease}
-URL: %(echo %{url} | cut -d ' ' -f 2)
-
-Summary: Advanced IP routing and network device configuration tools.
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Group: Applications/System
-#Source: http://developer.osdl.org/dev/iproute2/download/iproute2-%{version}-050314.tar.gz
-#URL:    http://developer.osdl.org/dev/iproute2/
-Source: %{name}-%{version}.tar.gz
-%define SOURCE1 ip.8
-%define SOURCE2 tc.8
-%define SOURCE3 tc-cbq.8
-%define SOURCE4 tc-cbq-details.8
-%define SOURCE5 tc-htb.8
-%define SOURCE6 tc-pbfifo.8
-%define SOURCE7 tc-pfifo_fast.8
-%define SOURCE8 tc-prio.8
-%define SOURCE9 tc-red.8
-%define SOURCE10 tc-sfq.8
-%define SOURCE11 tc-tbf.8
-License: GNU GPL
-BuildRoot: %{_tmppath}/%{name}-%{version}-root
-BuildPrereq: tetex-latex tetex-dvips psutils linuxdoc-tools db4-devel bison flex
-
-%description
-The iproute package contains networking utilities (ip and rtmon, for
-example) which are designed to use the advanced networking
-capabilities of the Linux 2.4.x and 2.6.x kernel.
-
-%prep
-%setup -q
-
-%build
-make
-make -C doc
-
-%install
-#rm -rf $RPM_BUILD_ROOT
-[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
-
-mkdir -p $RPM_BUILD_ROOT/sbin \
-        $RPM_BUILD_ROOT%{_sbindir} \
-         $RPM_BUILD_ROOT%{_mandir}/man8 \
-         $RPM_BUILD_ROOT/etc/iproute2 \
-        $RPM_BUILD_ROOT%{_libdir}/tc
-
-install -m 755 ip/ip ip/ifcfg ip/rtmon tc/tc $RPM_BUILD_ROOT/sbin
-install -m 755 misc/ss misc/nstat misc/rtacct misc/lnstat misc/arpd $RPM_BUILD_ROOT%{_sbindir}
-install -m 755 tc/q_netem.so $RPM_BUILD_ROOT%{_libdir}/tc
-install -m 644 netem/normal.dist netem/pareto.dist netem/paretonormal.dist $RPM_BUILD_ROOT%{_libdir}/tc
-install -m 644 %{SOURCE1} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE2} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE3} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE4} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE5} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE6} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE7} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE8} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE9} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE10} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE11} $RPM_BUILD_ROOT/%{_mandir}/man8
-
-cp -f etc/iproute2/* $RPM_BUILD_ROOT/etc/iproute2
-rm -rf $RPM_BUILD_ROOT/%{_libdir}/debug/*
-
-%clean
-#rm -rf $RPM_BUILD_ROOT
-[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-%dir /etc/iproute2
-%doc README.decnet README.iproute2+tc RELNOTES
-%doc doc/*.ps examples
-/sbin/*
-%{_mandir}/man8/*
-%attr(644,root,root) %config(noreplace) /etc/iproute2/*
-%{_sbindir}/*
-%{_libdir}/tc/*
-
-%changelog
-* Tue Mar 15 2005 Radek Vokal <rvokal@redhat.com> 2.6.11-1
-- update to iproute-2.6.11
-
-* Fri Mar 04 2005 Radek Vokal <rvokal@redhat.com> 2.6.10-2
-- gcc4 rebuilt
-
-* Wed Feb 16 2005 Radek Vokal <rvokal@redhat.com> 2.6.10-1
-- update to iproute-2.6.10
-
-* Thu Dec 23 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-6
-- added arpd into sbin
-
-* Mon Nov 29 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-5
-- debug info removed from makefile and from spec (#140891)
-
-* Tue Nov 16 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-4
-- source file updated from snapshot version
-- endian patch adding <endian.h> 
-
-* Sat Sep 18 2004 Joshua Blanton <jblanton@cs.ohiou.edu> 2.6.9-3
-- added installation of netem module for tc
-
-* Mon Sep 06 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-2
-- fixed possible buffer owerflow, path by Steve Grubb <linux_4ever@yahoo.com>
-
-* Wed Sep 01 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-1
-- updated to iproute-2.6.9, spec file change, patches cleared
-
-* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed May 26 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-16
-- Took tons of manpages from debian, much more complete (#123952).
-
-* Thu May 06 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-15
-- rebuilt
-
-* Thu May 06 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-13.2
-- Built security errata version for FC1.
-
-* Wed Apr 21 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-14
-- Fixed -f option for ss (#118355).
-- Small description fix (#110997).
-- Added initialization of some vars (#74961). 
-- Added patch to initialize "default" rule as well (#60693).
-
-* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed Nov 05 2003 Phil Knirsch <pknirsch@redhat.com> 2.4.7-12
-- Security errata for netlink (CAN-2003-0856).
-
-* Thu Oct 23 2003 Phil Knirsch <pknirsch@redhat.com>
-- Updated to latest version. Used by other distros, so seems stable. ;-)
-- Quite a few patches needed updating in that turn.
-- Added ss (#107363) and several other new nifty tools.
-
-* Tue Jun 17 2003 Phil Knirsch <pknirsch@redhat.com>
-- rebuilt
-
-* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
-- rebuilt
-
-* Thu Jan 16 2003 Phil Knirsch <pknirsch@redhat.com> 2.4.7-7
-- Added htb3-tc patch from http://luxik.cdi.cz/~devik/qos/htb/ (#75486).
-
-* Fri Oct 11 2002 Bill Nottingham <notting@redhat.com> 2.4.7-6
-- remove flags patch at author's request
-
-* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
-- automated rebuild
-
-* Wed Jun 19 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-4
-- Don't forcibly strip binaries
-
-* Mon May 27 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-3
-- Fixed missing diffserv and atm support in config (#57278).
-- Fixed inconsistent numeric base problem for command line (#65473).
-
-* Tue May 14 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-2
-- Added patch to fix crosscompiling by Adrian Linkins.
-
-* Fri Mar 15 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-1
-- Update to latest stable release 2.4.7-now-ss010824.
-- Added simple man page for ip.
-
-* Wed Aug  8 2001 Bill Nottingham <notting@redhat.com>
-- allow setting of allmulti & promisc flags (#48669)
-
-* Mon Jul 02 2001 Than Ngo <than@redhat.com>
-- fix build problem in beehive if kernel-sources is not installed
-
-* Fri May 25 2001 Helge Deller <hdeller@redhat.de>
-- updated to iproute2-2.2.4-now-ss001007.tar.gz 
-- bzip2 source tar file
-- "License" replaces "Copyright"
-- added "BuildPrereq: tetex-latex tetex-dvips psutils"
-- rebuilt for 7.2
-
-* Tue May  1 2001 Bill Nottingham <notting@redhat.com>
-- use the system headers - the included ones are broken
-- ETH_P_ECHO went away
-
-* Sat Jan  6 2001 Jeff Johnson <jbj@redhat.com>
-- test for specific KERNEL_INCLUDE directories.
-
-* Thu Oct 12 2000 Than Ngo <than@redhat.com>
-- rebuild for 7.1
-
-* Thu Oct 12 2000 Than Ngo <than@redhat.com>
-- add default configuration files for iproute (Bug #10549, #18887)
-
-* Tue Jul 25 2000 Jakub Jelinek <jakub@redhat.com>
-- fix include-glibc/ to cope with glibc 2.2 new resolver headers
-
-* Thu Jul 13 2000 Prospector <bugzilla@redhat.com>
-- automatic rebuild
-
-* Sun Jun 18 2000 Than Ngo <than@redhat.de>
-- rebuilt in the new build environment
-- use RPM macros
-- handle RPM_OPT_FLAGS
-
-* Sat Jun 03 2000 Than Ngo <than@redhat.de>
-- fix iproute to build with new glibc
-
-* Fri May 26 2000 Ngo Than <than@redhat.de>
-- update to 2.2.4-now-ss000305
-- add configuration files
-
-* Mon Sep 13 1999 Bill Nottingham <notting@redhat.com>
-- strip binaries
-
-* Mon Aug 16 1999 Cristian Gafton <gafton@redhat.com>
-- first build
index b2d6790..7b6d728 100644 (file)
@@ -38,7 +38,7 @@ static const char *ipx_ntop1(const struct ipx_addr *addr, char *str, size_t len)
 
        *(str + pos) = '.';
        pos++;
-       
+
        for(i = 0; i < 6; i++) {
                if (do_digit(str + pos, addr->ipx_node[i], 1, &pos, len))
                        return str;
index 67951fe..5ae64f7 100644 (file)
 
 void rtnl_close(struct rtnl_handle *rth)
 {
-       close(rth->fd);
+       if (rth->fd >= 0) {
+               close(rth->fd);
+               rth->fd = -1;
+       }
 }
 
 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
@@ -37,7 +40,7 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
        int sndbuf = 32768;
        int rcvbuf = 32768;
 
-       memset(rth, 0, sizeof(rth));
+       memset(rth, 0, sizeof(*rth));
 
        rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
        if (rth->fd < 0) {
@@ -91,10 +94,6 @@ int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
                struct nlmsghdr nlh;
                struct rtgenmsg g;
        } req;
-       struct sockaddr_nl nladdr;
-
-       memset(&nladdr, 0, sizeof(nladdr));
-       nladdr.nl_family = AF_NETLINK;
 
        memset(&req, 0, sizeof(req));
        req.nlh.nlmsg_len = sizeof(req);
@@ -104,18 +103,45 @@ int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
        req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
        req.g.rtgen_family = family;
 
-       return sendto(rth->fd, (void*)&req, sizeof(req), 0,
-                     (struct sockaddr*)&nladdr, sizeof(nladdr));
+       return send(rth->fd, (void*)&req, sizeof(req), 0);
 }
 
 int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
 {
-       struct sockaddr_nl nladdr;
+       return send(rth->fd, buf, len, 0);
+}
 
-       memset(&nladdr, 0, sizeof(nladdr));
-       nladdr.nl_family = AF_NETLINK;
+int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
+{
+       struct nlmsghdr *h;
+       int status;
+       char resp[1024];
+
+       status = send(rth->fd, buf, len, 0);
+       if (status < 0)
+               return status;
 
-       return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
+       /* Check for errors */
+       status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
+       if (status < 0) {
+               if (errno == EAGAIN)
+                       return 0;
+               return -1;
+       }
+
+       for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
+            h = NLMSG_NEXT(h, status)) {
+               if (h->nlmsg_type == NLMSG_ERROR) {
+                       struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                       if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                               fprintf(stderr, "ERROR truncated\n");
+                       else 
+                               errno = -err->error;
+               }
+               return -1;
+       }
+
+       return 0;
 }
 
 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
@@ -170,10 +196,11 @@ int rtnl_dump_filter(struct rtnl_handle *rth,
                status = recvmsg(rth->fd, &msg, 0);
 
                if (status < 0) {
-                       if (errno == EINTR)
+                       if (errno == EINTR || errno == EAGAIN)
                                continue;
-                       perror("OVERRUN");
-                       continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
                }
 
                if (status == 0) {
@@ -273,10 +300,11 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
                status = recvmsg(rtnl->fd, &msg, 0);
 
                if (status < 0) {
-                       if (errno == EINTR)
+                       if (errno == EINTR || errno == EAGAIN)
                                continue;
-                       perror("OVERRUN");
-                       continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
                }
                if (status == 0) {
                        fprintf(stderr, "EOF on netlink\n");
@@ -377,10 +405,11 @@ int rtnl_listen(struct rtnl_handle *rtnl,
                status = recvmsg(rtnl->fd, &msg, 0);
 
                if (status < 0) {
-                       if (errno == EINTR)
+                       if (errno == EINTR || errno == EAGAIN)
                                continue;
-                       perror("OVERRUN");
-                       continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
                }
                if (status == 0) {
                        fprintf(stderr, "EOF on netlink\n");
@@ -524,6 +553,39 @@ int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
        return 0;
 }
 
+struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
+{
+       struct rtattr *nest = NLMSG_TAIL(n);
+
+       addattr_l(n, maxlen, type, NULL, 0);
+       return nest;
+}
+
+int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
+{
+       nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
+       return n->nlmsg_len;
+}
+
+struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
+                                  const void *data, int len)
+{
+       struct rtattr *start = NLMSG_TAIL(n);
+
+       addattr_l(n, maxlen, type, data, len);
+       addattr_nest(n, maxlen, type);
+       return start;
+}
+
+int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
+{
+       struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
+
+       start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
+       addattr_nest_end(n, nest);
+       return n->nlmsg_len;
+}
+
 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
 {
        int len = RTA_LENGTH(4);
@@ -586,3 +648,16 @@ int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int l
                fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
        return i;
 }
+
+int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
+                                int len)
+{
+       if (RTA_PAYLOAD(rta) < len)
+               return -1;
+       if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
+               rta = RTA_DATA(rta) + RTA_ALIGN(len);
+               return parse_rtattr_nested(tb, max, rta);
+       }
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+       return 0;
+}
index 581487d..f558050 100644 (file)
@@ -38,6 +38,9 @@ const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int
            (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
                return inet_ntop(AF_INET, addr, buf, blen);
        }
+       if (alen == 16 && type == ARPHRD_TUNNEL6) {
+               return inet_ntop(AF_INET6, addr, buf, blen);
+       }
        l = 0;
        for (i=0; i<alen; i++) {
                if (i==0) {
index 1acbf8f..c1d61a9 100644 (file)
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <net/if.h>
 #include <string.h>
 
 #include "libnetlink.h"
 #include "ll_map.h"
 
+extern unsigned int if_nametoindex (const char *);
+
 struct idxmap
 {
        struct idxmap * next;
@@ -36,7 +37,7 @@ struct idxmap
 
 static struct idxmap *idxmap[16];
 
-int ll_remember_index(const struct sockaddr_nl *who, 
+int ll_remember_index(const struct sockaddr_nl *who,
                      struct nlmsghdr *n, void *arg)
 {
        int h;
index 98c67fe..1057ee3 100644 (file)
@@ -35,63 +35,66 @@ static struct {
        const char *name;
 } llproto_names[] = {
 __PF(LOOP,loop)
-__PF(PUP,pup)  
+__PF(PUP,pup)
 #ifdef ETH_P_PUPAT
 __PF(PUPAT,pupat)
-#endif    
+#endif
 __PF(IP,ip)
 __PF(X25,x25)
 __PF(ARP,arp)
 __PF(BPQ,bpq)
 #ifdef ETH_P_IEEEPUP
 __PF(IEEEPUP,ieeepup)
-#endif  
+#endif
 #ifdef ETH_P_IEEEPUPAT
 __PF(IEEEPUPAT,ieeepupat)
-#endif  
-__PF(DEC,dec)       
-__PF(DNA_DL,dna_dl)    
-__PF(DNA_RC,dna_rc)    
-__PF(DNA_RT,dna_rt)    
-__PF(LAT,lat)       
-__PF(DIAG,diag)      
-__PF(CUST,cust)      
-__PF(SCA,sca)       
-__PF(RARP,rarp)      
-__PF(ATALK,atalk)     
-__PF(AARP,aarp)      
-__PF(IPX,ipx)       
-__PF(IPV6,ipv6)      
+#endif
+__PF(DEC,dec)
+__PF(DNA_DL,dna_dl)
+__PF(DNA_RC,dna_rc)
+__PF(DNA_RT,dna_rt)
+__PF(LAT,lat)
+__PF(DIAG,diag)
+__PF(CUST,cust)
+__PF(SCA,sca)
+__PF(RARP,rarp)
+__PF(ATALK,atalk)
+__PF(AARP,aarp)
+__PF(IPX,ipx)
+__PF(IPV6,ipv6)
 #ifdef ETH_P_PPP_DISC
 __PF(PPP_DISC,ppp_disc)
-#endif      
+#endif
 #ifdef ETH_P_PPP_SES
 __PF(PPP_SES,ppp_ses)
-#endif      
+#endif
 #ifdef ETH_P_ATMMPOA
 __PF(ATMMPOA,atmmpoa)
 #endif
 #ifdef ETH_P_ATMFATE
 __PF(ATMFATE,atmfate)
-#endif      
+#endif
 
-__PF(802_3,802_3)     
-__PF(AX25,ax25)      
-__PF(ALL,all)       
-__PF(802_2,802_2)     
-__PF(SNAP,snap)      
-__PF(DDCMP,ddcmp)     
-__PF(WAN_PPP,wan_ppp)   
-__PF(PPP_MP,ppp_mp)    
-__PF(LOCALTALK,localtalk) 
-__PF(PPPTALK,ppptalk)   
-__PF(TR_802_2,tr_802_2)  
-__PF(MOBITEX,mobitex)   
-__PF(CONTROL,control)   
-__PF(IRDA,irda)      
+__PF(802_3,802_3)
+__PF(AX25,ax25)
+__PF(ALL,all)
+__PF(802_2,802_2)
+__PF(SNAP,snap)
+__PF(DDCMP,ddcmp)
+__PF(WAN_PPP,wan_ppp)
+__PF(PPP_MP,ppp_mp)
+__PF(LOCALTALK,localtalk)
+__PF(PPPTALK,ppptalk)
+__PF(TR_802_2,tr_802_2)
+__PF(MOBITEX,mobitex)
+__PF(CONTROL,control)
+__PF(IRDA,irda)
 #ifdef ETH_P_ECONET
 __PF(ECONET,econet)
-#endif      
+#endif
+__PF(TIPC,tipc)
+__PF(AOE,aoe)
+__PF(CAN,can)
 
 { 0x8100, "802.1Q" },
 { ETH_P_IP, "ipv4" },
index 5b0f106..d47dee7 100644 (file)
@@ -118,6 +118,12 @@ __PF(IEEE802_TR,tr)
 #ifdef ARPHRD_IEEE80211
 __PF(IEEE80211,ieee802.11)
 #endif
+#ifdef ARPHRD_IEEE80211_PRISM
+__PF(IEEE80211_PRISM,ieee802.11/prism)
+#endif
+#ifdef ARPHRD_IEEE80211_RADIOTAP
+__PF(IEEE80211_RADIOTAP,ieee802.11/radiotap)
+#endif
 #ifdef ARPHRD_VOID
 __PF(VOID,void)
 #endif
index 05046c2..8d019a0 100644 (file)
 
 #include "rt_names.h"
 
+struct rtnl_hash_entry {
+       struct rtnl_hash_entry *next;
+       char *                  name;
+       unsigned int            id;
+};
+
+static void
+rtnl_hash_initialize(char *file, struct rtnl_hash_entry **hash, int size)
+{
+       struct rtnl_hash_entry *entry;
+       char buf[512];
+       FILE *fp;
+
+       fp = fopen(file, "r");
+       if (!fp)
+               return;
+       while (fgets(buf, sizeof(buf), fp)) {
+               char *p = buf;
+               int id;
+               char namebuf[512];
+
+               while (*p == ' ' || *p == '\t')
+                       p++;
+               if (*p == '#' || *p == '\n' || *p == 0)
+                       continue;
+               if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 &&
+                   sscanf(p, "0x%x %s #", &id, namebuf) != 2 &&
+                   sscanf(p, "%d %s\n", &id, namebuf) != 2 &&
+                   sscanf(p, "%d %s #", &id, namebuf) != 2) {
+                       fprintf(stderr, "Database %s is corrupted at %s\n",
+                               file, p);
+                       return;
+               }
+
+               if (id<0)
+                       continue;
+               entry = malloc(sizeof(*entry));
+               entry->id   = id;
+               entry->name = strdup(namebuf);
+               entry->next = hash[id & (size - 1)];
+               hash[id & (size - 1)] = entry;
+       }
+       fclose(fp);
+}
+
 static void rtnl_tab_initialize(char *file, char **tab, int size)
 {
        char buf[512];
@@ -57,7 +102,6 @@ static void rtnl_tab_initialize(char *file, char **tab, int size)
        fclose(fp);
 }
 
-
 static char * rtnl_rtprot_tab[256] = {
        [RTPROT_UNSPEC] = "none",
        [RTPROT_REDIRECT] ="redirect",
@@ -266,9 +310,14 @@ int rtnl_rtrealm_a2n(__u32 *id, char *arg)
 }
 
 
+static struct rtnl_hash_entry dflt_table_entry  = { .id = 253, .name = "default" };
+static struct rtnl_hash_entry main_table_entry  = { .id = 254, .name = "main" };
+static struct rtnl_hash_entry local_table_entry = { .id = 255, .name = "local" };
 
-static char * rtnl_rttable_tab[256] = {
-       "unspec",
+static struct rtnl_hash_entry * rtnl_rttable_hash[256] = {
+       [253] = &dflt_table_entry,
+       [254] = &main_table_entry,
+       [255] = &local_table_entry,
 };
 
 static int rtnl_rttable_init;
@@ -276,26 +325,26 @@ static int rtnl_rttable_init;
 static void rtnl_rttable_initialize(void)
 {
        rtnl_rttable_init = 1;
-       rtnl_rttable_tab[255] = "local";
-       rtnl_rttable_tab[254] = "main";
-       rtnl_rttable_tab[253] = "default";
-       rtnl_tab_initialize("/etc/iproute2/rt_tables",
-                           rtnl_rttable_tab, 256);
+       rtnl_hash_initialize("/etc/iproute2/rt_tables",
+                            rtnl_rttable_hash, 256);
 }
 
-char * rtnl_rttable_n2a(int id, char *buf, int len)
+char * rtnl_rttable_n2a(__u32 id, char *buf, int len)
 {
-       if (id<0 || id>=256) {
-               snprintf(buf, len, "%d", id);
+       struct rtnl_hash_entry *entry;
+
+       if (id > RT_TABLE_MAX) {
+               snprintf(buf, len, "%u", id);
                return buf;
        }
-       if (!rtnl_rttable_tab[id]) {
-               if (!rtnl_rttable_init)
-                       rtnl_rttable_initialize();
-       }
-       if (rtnl_rttable_tab[id])
-               return rtnl_rttable_tab[id];
-       snprintf(buf, len, "%d", id);
+       if (!rtnl_rttable_init)
+               rtnl_rttable_initialize();
+       entry = rtnl_rttable_hash[id & 255];
+       while (entry && entry->id != id)
+               entry = entry->next;
+       if (entry)
+               return entry->name;
+       snprintf(buf, len, "%u", id);
        return buf;
 }
 
@@ -303,8 +352,9 @@ int rtnl_rttable_a2n(__u32 *id, char *arg)
 {
        static char *cache = NULL;
        static unsigned long res;
+       struct rtnl_hash_entry *entry;
        char *end;
-       int i;
+       __u32 i;
 
        if (cache && strcmp(cache, arg) == 0) {
                *id = res;
@@ -315,17 +365,19 @@ int rtnl_rttable_a2n(__u32 *id, char *arg)
                rtnl_rttable_initialize();
 
        for (i=0; i<256; i++) {
-               if (rtnl_rttable_tab[i] &&
-                   strcmp(rtnl_rttable_tab[i], arg) == 0) {
-                       cache = rtnl_rttable_tab[i];
-                       res = i;
+               entry = rtnl_rttable_hash[i];
+               while (entry && strcmp(entry->name, arg))
+                       entry = entry->next;
+               if (entry) {
+                       cache = entry->name;
+                       res = entry->id;
                        *id = res;
                        return 0;
                }
        }
 
        i = strtoul(arg, &end, 0);
-       if (!end || end == arg || *end || i > 255)
+       if (!end || end == arg || *end || i > RT_TABLE_MAX)
                return -1;
        *id = i;
        return 0;
index 4bdda71..0bb0832 100644 (file)
@@ -47,6 +47,41 @@ int get_integer(int *val, const char *arg, int base)
        return 0;
 }
 
+int mask2bits(__u32 netmask)
+{
+       unsigned bits = 0;
+       __u32 mask = ntohl(netmask);
+       __u32 host = ~mask;
+
+       /* a valid netmask must be 2^n - 1 */
+       if ((host & (host + 1)) != 0)
+               return -1;
+
+       for (; mask; mask <<= 1)
+               ++bits;
+       return bits;
+}
+
+static int get_netmask(unsigned *val, const char *arg, int base)
+{
+       inet_prefix addr;
+
+       if (!get_unsigned(val, arg, base))
+               return 0;
+
+       /* try coverting dotted quad to CIDR */
+       if (!get_addr_1(&addr, arg, AF_INET) && addr.family == AF_INET) {
+               int b = mask2bits(addr.data[0]);
+               
+               if (b >= 0) {
+                       *val = b;
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
 int get_unsigned(unsigned *val, const char *arg, int base)
 {
        unsigned long res;
@@ -61,6 +96,70 @@ int get_unsigned(unsigned *val, const char *arg, int base)
        return 0;
 }
 
+/*
+ * get_jiffies is "translated" from a similar routine "get_time" in
+ * tc_util.c.  we don't use the exact same routine because tc passes
+ * microseconds to the kernel and the callers of get_jiffies want 
+ * to pass jiffies, and have a different assumption for the units of
+ * a "raw" number.
+ */
+
+int get_jiffies(unsigned *jiffies, const char *arg, int base, int *raw)
+{
+       double t;
+       unsigned long res;
+       char *p;
+
+       if (strchr(arg,'.') != NULL) {
+               t = strtod(arg,&p);
+               if (t < 0.0)
+                       return -1;
+       }
+       else {
+               res = strtoul(arg,&p,base);
+               if (res > UINT_MAX)
+                       return -1;
+               t = (double)res;
+       }
+       if (p == arg)
+               return -1;
+
+       if (__iproute2_hz_internal == 0)
+                __iproute2_hz_internal = __get_hz();
+       
+       *raw = 1;
+
+       if (*p) {
+               *raw = 0;
+                if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
+                    strcasecmp(p, "secs")==0)
+                        t *= __iproute2_hz_internal;
+                else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
+                         strcasecmp(p, "msecs") == 0)
+                        t *= __iproute2_hz_internal/1000.0;
+                else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
+                         strcasecmp(p, "usecs") == 0)
+                        t *= __iproute2_hz_internal/1000000.0;
+                else if (strcasecmp(p, "ns") == 0 || strcasecmp(p, "nsec")==0 ||
+                         strcasecmp(p, "nsecs") == 0)
+                        t *= __iproute2_hz_internal/1000000000.0;
+               else if (strcasecmp(p, "j") == 0 || strcasecmp(p, "hz") == 0 ||
+                        strcasecmp(p,"jiffies") == 0)
+                       t *= 1.0; /* allow suffix, do nothing */
+                else
+                        return -1;
+        }
+
+       /* emulate ceil() without having to bring-in -lm and always be >= 1 */
+
+       *jiffies = t;
+       if (*jiffies < t)
+               *jiffies += 1;
+       
+        return 0;
+
+}
+
 int get_u64(__u64 *val, const char *arg, int base)
 {
        unsigned long long res;
@@ -145,12 +244,39 @@ int get_s8(__s8 *val, const char *arg, int base)
        return 0;
 }
 
-int get_addr_1(inet_prefix *addr, const char *name, int family)
+/* This uses a non-standard parsing (ie not inet_aton, or inet_pton)
+ * because of legacy choice to parse 10.8 as 10.8.0.0 not 10.0.0.8
+ */
+static int get_addr_ipv4(__u8 *ap, const char *cp)
 {
-       const char *cp;
-       unsigned char *ap = (unsigned char*)addr->data;
        int i;
 
+       for (i = 0; i < 4; i++) {
+               unsigned long n;
+               char *endp;
+               
+               n = strtoul(cp, &endp, 0);
+               if (n > 255)
+                       return -1;      /* bogus network value */
+
+               if (endp == cp) /* no digits */
+                       return -1;
+
+               ap[i] = n;
+
+               if (*endp == '\0')
+                       break;
+
+               if (i == 3 || *endp != '.')
+                       return -1;      /* extra characters */
+               cp = endp + 1;
+       }
+
+       return 1;
+}
+
+int get_addr_1(inet_prefix *addr, const char *name, int family)
+{
        memset(addr, 0, sizeof(*addr));
 
        if (strcmp(name, "default") == 0 ||
@@ -189,17 +315,12 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
        addr->family = AF_INET;
        if (family != AF_UNSPEC && family != AF_INET)
                return -1;
+
+       if (get_addr_ipv4((__u8 *)addr->data, name) <= 0)
+               return -1;
+
        addr->bytelen = 4;
        addr->bitlen = -1;
-       for (cp=name, i=0; *cp; cp++) {
-               if (*cp <= '9' && *cp >= '0') {
-                       ap[i] = 10*ap[i] + (*cp-'0');
-                       continue;
-               }
-               if (*cp == '.' && ++i <= 3)
-                       continue;
-               return -1;
-       }
        return 0;
 }
 
@@ -240,7 +361,8 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family)
                                dst->bitlen = 32;
                }
                if (slash) {
-                       if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) {
+                       if (get_netmask(&plen, slash+1, 0)
+                                       || plen > dst->bitlen) {
                                err = -1;
                                goto done;
                        }
@@ -330,8 +452,8 @@ int matches(const char *cmd, const char *pattern)
 
 int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
 {
-       __u32 *a1 = a->data;
-       __u32 *a2 = b->data;
+       const __u32 *a1 = a->data;
+       const __u32 *a2 = b->data;
        int words = bits >> 0x05;
 
        bits &= 0x1f;
@@ -418,13 +540,14 @@ const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen
 struct namerec
 {
        struct namerec *next;
+       const char *name;
        inet_prefix addr;
-       char        *name;
 };
 
-static struct namerec *nht[256];
+#define NHASH 257
+static struct namerec *nht[NHASH];
 
-char *resolve_address(const char *addr, int len, int af)
+static const char *resolve_address(const void *addr, int len, int af)
 {
        struct namerec *n;
        struct hostent *h_ent;
@@ -439,7 +562,7 @@ char *resolve_address(const char *addr, int len, int af)
                len = 4;
        }
 
-       hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4];
+       hash = *(__u32 *)(addr + len - 4) % NHASH;
 
        for (n = nht[hash]; n; n = n->next) {
                if (n->addr.family == af &&
@@ -473,7 +596,8 @@ const char *format_host(int af, int len, const void *addr,
 {
 #ifdef RESOLVE_HOSTNAMES
        if (resolve_hosts) {
-               char *n;
+               const char *n;
+
                if (len <= 0) {
                        switch (af) {
                        case AF_INET:
@@ -578,19 +702,19 @@ int print_timestamp(FILE *fp)
 int cmdlineno;
 
 /* Like glibc getline but handle continuation lines and comments */
-size_t getcmdline(char **linep, size_t *lenp, FILE *in)
+ssize_t getcmdline(char **linep, size_t *lenp, FILE *in)
 {
-       size_t cc;
+       ssize_t cc;
        char *cp;
-               
+
        if ((cc = getline(linep, lenp, in)) < 0)
                return cc;      /* eof or error */
        ++cmdlineno;
 
        cp = strchr(*linep, '#');
-       if (cp) 
+       if (cp)
                *cp = '\0';
-       
+
        while ((cp = strstr(*linep, "\\\n")) != NULL) {
                char *line1 = NULL;
                size_t len1 = 0;
@@ -605,12 +729,14 @@ size_t getcmdline(char **linep, size_t *lenp, FILE *in)
                *cp = 0;
 
                cp = strchr(line1, '#');
-               if (cp) 
+               if (cp)
                        *cp = '\0';
 
-               *linep = realloc(*linep, strlen(*linep) + strlen(line1) + 1);
+               *lenp = strlen(*linep) + strlen(line1) + 1;
+               *linep = realloc(*linep, *lenp);
                if (!*linep) {
                        fprintf(stderr, "Out of memory\n");
+                       *lenp = 0;
                        return -1;
                }
                cc += cc1 - 2;
index 145f38d..15a478a 100644 (file)
@@ -187,7 +187,7 @@ The functions sometimes use fprintf and exit when a fatal error occurs.
 This library should be named librtnetlink.
 
 .SH AUTHORS
-netlink/rtnetlink was designed and writen by Alexey Kuznetsov.
+netlink/rtnetlink was designed and written by Alexey Kuznetsov.
 Andi Kleen wrote the man page.
 
 .SH SEE ALSO
diff --git a/man/man8/arpd.8 b/man/man8/arpd.8
new file mode 100644 (file)
index 0000000..d172600
--- /dev/null
@@ -0,0 +1,66 @@
+.TH ARPD 8 "28 June, 2007"
+
+.SH NAME
+arpd \- userspace arp daemon.
+
+.SH SYNOPSIS
+Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]
+
+.SH DESCRIPTION
+The
+.B arpd
+daemon collects gratuitous ARP information, saving it on local disk and feeding it to kernel on demand to avoid redundant broadcasting due to limited size of kernel ARP cache.
+
+.SH OPTIONS
+.TP
+-h -?
+Print help
+.TP
+-l
+Dump arpd database to stdout and exit. Output consists of three columns: interface index, IP address and MAC address. Negative entries for dead hosts are also shown, in this case MAC address is replaced by word FAILED followed by colon and time when the fact that host is dead was proven the last time.
+.TP
+-f <FILE>
+Read and load arpd database from FILE in text format similar dumped by option -l. Exit after load, probably listing resulting database, if option -l is also given. If FILE is -, stdin is read to get ARP table.
+.TP
+-b <DATABASE>
+location of database file. Default location is /var/lib/arpd/arpd.db
+.TP
+-a <NUMBER>
+arpd not only passively listens ARP on wire, but also send brodcast queries itself. NUMBER is number of such queries to make before destination is considered as dead. When arpd is started as kernel helper (i.e. with app_solicit enabled in sysctl or even with option -k) without this option and still did not learn enough information, you can observe 1 second gaps in service. Not fatal, but not good.
+.TP
+-k
+Suppress sending broadcast queries by kernel. It takes sense together with option -a.
+.TP
+-n <TIME>
+Timeout of negative cache. When resolution fails arpd suppresses further attempts to resolve for this period. It makes sense only together with option -k This timeout should not be too much longer than boot time of a typical host not supporting gratuitous ARP. Default value is 60 seconds.
+.TP
+-r <RATE>
+Maximal steady rate of broadcasts sent by arpd in packets per second. Default value is 1.
+.TP
+-B <NUMBER>
+Number of broadcasts sent by <tt/arpd/ back to back. Default value is 3. Together with option <tt/-R/ this option allows to police broadcasting not to exceed B+R*T over any interval of time T.
+.P
+<INTERFACE> is the name of networking interface to watch. If no interfaces given, arpd monitors all the interfaces. In this case arpd does not adjust sysctl parameters, it is supposed user does this himself after arpd is started.
+.P
+Signals
+.br
+arpd exits gracefully syncing database and restoring adjusted sysctl parameters, when receives SIGINT or SIGTERM. SIGHUP syncs database to disk. SIGUSR1 sends some statistics to syslog. Effect of another signals is undefined, they may corrupt database and leave sysctl praameters in an unpredictable state.
+.P
+Note
+.br
+In order for arpd to be able to serve as ARP resolver, kernel must be compiled with the option CONFIG_ARPD and, in the case when interface list in not given on command line, variable app_solicit on interfaces of interest should be in /proc/sys/net/ipv4/neigh/*. If this is not made arpd still collects gratuitous ARP information in its database.
+.SH EXAMPLES
+.TP
+arpd -b /var/tmp/arpd.db
+Start arpd to collect gratuitous ARP, but not messing with kernel functionality.
+.TP
+killall arpd ; arpd -l -b /var/tmp/arpd.db
+Look at result after some time.
+.TP
+arpd -b /var/tmp/arpd.db -a 1 eth0 eth1
+Enable kernel helper, leaving leading role to kernel.
+.TP
+arpd -b /var/tmp/arpd.db -a 3 -k eth0 eth1
+Completely replace kernel resolution on interfaces eth0 and eth1. In this case kernel still does unicast probing to validate entries, but all the broadcast activity is suppressed and made under authority of arpd.
+.PP
+This is mode which arpd is supposed to work normally. It is not default just to prevent occasional enabling of too aggressive mode occasionally.
index 12da6d5..e948d03 100644 (file)
@@ -13,12 +13,12 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
 
 .ti -8
 .IR OBJECT " := { "
-.BR link " | " addr " | " route " | " rule " | " neigh " | " tunnel " | "\
-maddr " | "  mroute " | " monitor " }"
+.BR link " | " addr " | " addrlabel " | " route " | " rule " | " neigh " | "\
+ tunnel " | " maddr " | "  mroute " | " monitor " }"
 .sp
 
 .ti -8
-.IR OPTIONS " := { " 
+.IR OPTIONS " := { "
 \fB\-V\fR[\fIersion\fR] |
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-r\fR[\fIesolve\fR] |
@@ -32,7 +32,7 @@ maddr " | "  mroute " | " monitor " }"
 .br
 .BR promisc " { " on " | " off " } |"
 .br
-.BR allmulti " { " on " | " off " } |"
+.BR allmulticast " { " on " | " off " } |"
 .br
 .BR dynamic " { " on " | " off " } |"
 .br
@@ -46,18 +46,21 @@ maddr " | "  mroute " | " monitor " }"
 .br
 .B  address
 .IR LLADDR " |"
-.B  broadcast 
+.B  broadcast
 .IR LLADDR " |"
 .br
 .B  mtu
-.IR MTU " }"
+.IR MTU " |"
+.br
+.B  netns
+.IR PID " }"
 
 .ti -8
 .B ip link show
 .RI "[ " DEVICE " ]"
 
 .ti -8
-.BR "ip addr" " { " add " | " del " } " 
+.BR "ip addr" " { " add " | " del " } "
 .IB IFADDR " dev " STRING
 
 .ti -8
@@ -65,7 +68,7 @@ maddr " | "  mroute " | " monitor " }"
 .IR STRING " ] [ "
 .B  scope
 .IR SCOPE-ID " ] [ "
-.B  to 
+.B  to
 .IR PREFIX " ] [ " FLAG-LIST " ] [ "
 .B  label
 .IR PATTERN " ]"
@@ -96,16 +99,27 @@ maddr " | "  mroute " | " monitor " }"
 .RB "[ " permanent " | " dynamic " | " secondary " | " primary " | "\
 tentative " | " deprecated " ]"
 
+.ti -8
+.BR "ip addrlabel" " { " add " | " del " } " prefix
+.BR PREFIX " [ "
+.B dev
+.IR DEV " ] [ "
+.B label
+.IR NUMBER " ]"
+
+.ti -8
+.BR "ip addrlabel" " { " list " | " flush " }"
+
 .ti -8
 .BR "ip route" " { "
 .BR list " | " flush " } "
 .I  SELECTOR
 
 .ti -8
-.B  ip route get 
+.B  ip route get
 .IR ADDRESS " [ "
 .BI from " ADDRESS " iif " STRING"
-.RB " ] [ " oif 
+.RB " ] [ " oif
 .IR STRING " ] [ "
 .B  tos
 .IR TOS " ]"
@@ -169,9 +183,9 @@ replace " | " monitor " } "
 .B  advmss
 .IR NUMBER " ] [ "
 .B  rtt
-.IR NUMBER " ] [ "
+.IR TIME " ] [ "
 .B  rttvar
-.IR NUMBER " ] [ "
+.IR TIME " ] [ "
 .B  window
 .IR NUMBER " ] [ "
 .B  cwnd
@@ -179,7 +193,9 @@ replace " | " monitor " } "
 .B  ssthresh
 .IR REALM " ] [ "
 .B  realms
-.IR REALM " ]"
+.IR REALM " ] [ "
+.B  rto_min
+.IR TIME " ]"
 
 .ti -8
 .IR TYPE " := [ "
@@ -223,7 +239,7 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .B  tos
 .IR TOS " ] [ "
 .B  fwmark
-.IR FWMARK " ] [ "
+.IR FWMARK[/MASK] " ] [ "
 .B  dev
 .IR STRING " ] [ "
 .B  pref
@@ -265,9 +281,9 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .BR "ip tunnel" " { " add " | " change " | " del " | " show " }"
 .RI "[ " NAME " ]"
 .br
-.RB "[ " mode " { " ipip " | " gre " | " sit " } ]"
-.br
-.RB "[ " remote
+.RB "[ " mode
+.IR MODE " ] [ "
+.B remote
 .IR ADDR " ] [ "
 .B  local
 .IR ADDR " ]"
@@ -276,14 +292,24 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .IR KEY " ] [ "
 .RB "[" i "|" o "]" csum " ] ]"
 .br
+.RB "[ " encaplimit
+.IR ELIM " ]"
 .RB "[ " ttl
-.IR TTL " ] [ "
-.B  tos
+.IR TTL " ]"
+.br
+.RB "[ " tos
 .IR TOS " ] [ "
-.RB "[" no "]" pmtudisc " ]"
+.B flowlabel
+.IR FLOWLABEL " ]"
 .br
+.RB "[ [" no "]" pmtudisc " ]"
 .RB "[ " dev
 .IR PHYS_DEV " ]"
+.RB "[ " "dscp inherit" " ]"
+
+.ti -8
+.IR MODE " := "
+.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | " any " }"
 
 .ti -8
 .IR ADDR " := { " IP_ADDRESS " |"
@@ -293,6 +319,12 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .IR TOS " := { " NUMBER " |"
 .BR inherit " }"
 
+.ti -8
+.IR ELIM " := {
+.BR none " | "
+.IR 0 ".." 255 " }"
+
+.ti -8
 .ti -8
 .IR TTL " := { " 1 ".." 255 " | "
 .BR inherit " }"
@@ -300,6 +332,9 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .ti -8
 .IR KEY " := { " DOTTED_QUAD " | " NUMBER " }"
 
+.ti -8
+.IR TIME " := " NUMBER "[s|ms|us|ns|j]"
+
 .ti -8
 .BR "ip maddr" " [ " add " | " del " ]"
 .IB MULTIADDR " dev " STRING
@@ -319,6 +354,313 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .ti -8
 .BR "ip monitor" " [ " all " |"
 .IR LISTofOBJECTS " ]"
+
+.ti -8
+.BR "ip xfrm"
+.IR XFRM_OBJECT " { " COMMAND " }"
+
+.ti -8
+.IR XFRM_OBJECT " := { " state " | " policy " | " monitor " } "
+
+.ti -8
+.BR "ip xfrm state " { " add " | " update " } "
+.IR ID " [ "
+.IR XFRM_OPT " ] "
+.RB " [ " mode
+.IR MODE " ] "
+.br
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " seq
+.IR SEQ " ] "
+.RB " [ " replay-window
+.IR SIZE " ] "
+.br
+.RB " [ " flag
+.IR FLAG-LIST " ] "
+.RB " [ " encap
+.IR ENCAP " ] "
+.RB " [ " sel
+.IR SELECTOR " ] "
+.br
+.RB " [ "
+.IR LIMIT-LIST " ] "
+
+.ti -8
+.BR "ip xfrm state allocspi "
+.IR ID
+.RB " [ " mode
+.IR MODE " ] "
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " seq
+.IR SEQ " ] "
+.RB " [ " min
+.IR SPI
+.B max
+.IR SPI " ] "
+
+.ti -8
+.BR "ip xfrm state" " { " delete " | " get " } "
+.IR ID
+
+.ti -8
+.BR "ip xfrm state" " { " deleteall " | " list " } [ "
+.IR ID " ] "
+.RB " [ " mode
+.IR MODE " ] "
+.br
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " flag
+.IR FLAG_LIST " ] "
+
+.ti -8
+.BR "ip xfrm state flush" " [ " proto
+.IR XFRM_PROTO " ] "
+
+.ti -8
+.BR "ip xfrm state count"
+
+.ti -8
+.IR ID " := "
+.RB " [ " src
+.IR ADDR " ] "
+.RB " [ " dst
+.IR ADDR " ] "
+.RB " [ " proto
+.IR XFRM_PROTO " ] "
+.RB " [ " spi
+.IR SPI " ] "
+
+.ti -8
+.IR XFRM_PROTO " := "
+.RB " [ " esp " | " ah " | " comp " | " route2 " | " hao " ] "
+
+.ti -8
+.IR MODE " := "
+.RB " [ " transport " | " tunnel " | " ro " | " beet " ] "
+.B (default=transport)
+
+.ti -8
+.IR FLAG-LIST " := "
+.RI " [ " FLAG-LIST " ] " FLAG
+
+.ti -8
+.IR FLAG " := "
+.RB " [ " noecn " | " decap-dscp " | " wildrecv " ] "
+
+.ti -8
+.IR ENCAP " := " ENCAP-TYPE " " SPORT " " DPORT " " OADDR
+
+.ti -8
+.IR ENCAP-TYPE " := "
+.B espinudp
+.RB " | "
+.B espinudp-nonike
+
+.ti -8
+.IR ALGO-LIST " := [ "
+.IR ALGO-LIST " ] | [ "
+.IR ALGO " ] "
+
+.ti -8
+.IR ALGO " := "
+.IR ALGO_TYPE
+.IR ALGO_NAME
+.IR ALGO_KEY
+
+.ti -8
+.IR ALGO_TYPE " := "
+.RB " [ " enc " | " auth " | " comp " ] "
+
+.ti -8
+.IR SELECTOR " := "
+.B src
+.IR ADDR "[/" PLEN "]"
+.B dst
+.IR ADDR "[/" PLEN "]"
+.RI " [ " UPSPEC " ] "
+.RB " [ " dev
+.IR DEV " ] "
+
+.ti -8
+.IR UPSPEC " := "
+.B proto
+.IR PROTO " [[ "
+.B sport
+.IR PORT " ] "
+.RB " [ " dport
+.IR PORT " ] | "
+.br
+.RB " [ " type
+.IR NUMBER " ] "
+.RB " [ " code
+.IR NUMBER " ]] "
+
+.ti -8
+.IR LIMIT-LIST " := [ " LIMIT-LIST " ] |"
+.RB " [ "limit
+.IR LIMIT " ] "
+
+.ti -8
+.IR LIMIT " := "
+.RB " [ [" time-soft "|" time-hard "|" time-use-soft "|" time-use-hard "]"
+.IR SECONDS " ] | "
+.RB "[ ["byte-soft "|" byte-hard "]"
+.IR SIZE " ] | "
+.br
+.RB " [ ["packet-soft "|" packet-hard "]"
+.IR COUNT " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " add " | " update " } " " dir "
+.IR DIR
+.IR SELECTOR " [ "
+.BR index
+.IR INDEX " ] "
+.br
+.RB " [ " ptype
+.IR PTYPE " ] "
+.RB " [ " action
+.IR ACTION " ] "
+.RB " [ " priority
+.IR PRIORITY " ] "
+.br
+.RI " [ " LIMIT-LIST " ] [ "
+.IR TMPL-LIST " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " delete " | " get " } " " dir "
+.IR DIR " [ " SELECTOR " | "
+.BR index
+.IR INDEX
+.RB " ] "
+.br
+.RB " [ " ptype
+.IR PTYPE " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " deleteall " | " list " } "
+.RB " [ " dir
+.IR DIR " ] [ "
+.IR SELECTOR " ] "
+.br
+.RB " [ " index
+.IR INDEX " ] "
+.RB " [ " action
+.IR ACTION " ] "
+.RB " [ " priority
+.IR PRIORITY " ] "
+
+.ti -8
+.B "ip xfrm policy flush"
+.RB " [ " ptype
+.IR PTYPE " ] "
+
+.ti -8
+.B "ip xfrm count"
+
+.ti -8
+.IR PTYPE " := "
+.RB " [ " main " | " sub " ] "
+.B (default=main)
+
+.ti -8
+.IR DIR " := "
+.RB " [ " in " | " out " | " fwd " ] "
+
+.ti -8
+.IR SELECTOR " := "
+.B src
+.IR ADDR "[/" PLEN "]"
+.B dst
+.IR ADDR "[/" PLEN] " [ " UPSPEC
+.RB " ] [ " dev
+.IR DEV " ] "
+
+.ti -8
+.IR UPSPEC " := "
+.B proto
+.IR PROTO " [ "
+.RB " [ " sport
+.IR PORT " ] "
+.RB " [ " dport
+.IR PORT " ] | "
+.br
+.RB " [ " type
+.IR NUMBER " ] "
+.RB " [ " code
+.IR NUMBER " ] ] "
+
+.ti -8
+.IR ACTION " := "
+.RB " [ " allow " | " block " ]"
+.B (default=allow)
+
+.ti -8
+.IR LIMIT-LIST " := "
+.RB " [ "
+.IR LIMIT-LIST " ] | "
+.RB " [ " limit
+.IR LIMIT " ] "
+
+.ti -8
+.IR LIMIT " := "
+.RB " [ [" time-soft "|" time-hard "|" time-use-soft "|" time-use-hard "]"
+.IR SECONDS " ] | "
+.RB " [ [" byte-soft "|" byte-hard "]"
+.IR SIZE " ] | "
+.br [ "
+.RB "[" packet-soft "|" packet-hard "]"
+.IR NUMBER " ] "
+
+.ti -8
+.IR TMPL-LIST " := "
+.B " [ "
+.IR TMPL-LIST " ] | "
+.RB " [ " tmpl
+.IR TMPL " ] "
+
+.ti -8
+.IR TMPL " := "
+.IR ID " [ "
+.B mode
+.IR MODE " ] "
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " level
+.IR LEVEL " ] "
+
+.ti -8
+.IR ID " := "
+.RB " [ " src
+.IR ADDR " ] "
+.RB " [ " dst
+.IR ADDR " ] "
+.RB " [ " proto
+.IR XFRM_PROTO " ] "
+.RB " [ " spi
+.IR SPI " ] "
+
+.ti -8
+.IR XFRM_PROTO " := "
+.RB " [ " esp " | " ah " | " comp " | " route2 " | " hao " ] "
+
+.ti -8
+.IR MODE " := "
+.RB " [ " transport " | " tunnel " | " beet " ] "
+.B (default=transport)
+
+.ti -8
+.IR LEVEL " := "
+.RB " [ " required " | " use " ] "
+.B (default=required)
+
+.ti -8
+.BR "ip xfrm monitor" " [ " all " | "
+.IR LISTofOBJECTS " ] "
+
 .in -8
 .ad b
 
@@ -343,7 +685,7 @@ followed by protocol family identifier:
 or
 .B link
 ,enforce the protocol family to use.  If the option is not present,
-the protocol family is guessed from other arguments.  If the rest 
+the protocol family is guessed from other arguments.  If the rest
 of the command line does not give enough information to guess the
 family,
 .B ip
@@ -374,8 +716,8 @@ shortcut for
 .BR "\-o" , " \-oneline"
 output each record on a single line, replacing line feeds
 with the
-.B '\'
-character. This is convenient when you want to count records 
+.B '\e\'
+character. This is convenient when you want to count records
 with
 .BR wc (1)
  or to
@@ -399,6 +741,11 @@ host addresses.
 .TP
 .B address
 - protocol (IP or IPv6) address on a device.
+
+.TP
+.B addrlabel
+- label configuration for protocol address selection.
+
 .TP
 .B neighbour
 - ARP or NDISC cache entry.
@@ -423,6 +770,10 @@ host addresses.
 .B tunnel
 - tunnel over IP.
 
+.TP
+.B xfrm
+- framework for IPsec protocol.
+
 .PP
 The names of all objects may be written in full or
 abbreviated form, f.e.
@@ -501,13 +852,13 @@ already configured.
 
 .TP
 .BI txqueuelen " NUMBER"
-.TP 
+.TP
 .BI txqlen " NUMBER"
 change the transmit queue length of the device.
 
 .TP
 .BI mtu " NUMBER"
-change the 
+change the
 .I MTU
 of the device.
 
@@ -525,6 +876,11 @@ change the link layer broadcast address or the peer address when
 the interface is
 .IR "POINTOPOINT" .
 
+.TP
+.BI netns " PID"
+move the device to the network namespace associated with the process
+.IR "PID" .
+
 .PP
 .B Warning:
 If multiple parameter changes are requested,
@@ -703,6 +1059,33 @@ this option is given twice,
 also dumps all the deleted addresses in the format described in the
 previous subsection.
 
+.SH ip addrlabel - protocol address label management.
+
+IPv6 address label is used for address selection
+described in RFC 3484.  Precedence is managed by userspace,
+and only label is stored in kernel.
+
+.SS ip addrlabel add - add an address label
+the command adds an address label entry to the kernel.
+.TP
+.BI prefix " PREFIX"
+.TP
+.BI dev " DEV"
+the outgoing interface.
+.TP
+.BI label " NUMBER"
+the label for the prefix.
+0xffffffff is reserved.
+.SS ip addrlabel del - delete an address label
+the command deletes an address label entry in the kernel.
+.B Arguments:
+coincide with the arguments of
+.B ip addrlabel add
+but label is not required.
+.SS ip addrlabel list - list address labels
+the command show contents of address labels.
+.SS ip addrlabel flush - flush address labels
+the commoand flushes the contents of address labels and it does not restore default settings.
 .SH ip neighbour - neighbour/arp tables management.
 
 .B neighbour
@@ -935,7 +1318,7 @@ Linux-2.x can pack routes into several routing
 tables identified by a number in the range from 1 to 255 or by
 name from the file
 .B /etc/iproute2/rt_tables
-By default all normal routes are inserted into the
+By default all normal routes are inserted into the
 .B main
 table (ID 254) and the kernel only uses this table when calculating routes.
 
@@ -1062,12 +1445,29 @@ measured in bytes.  It limits maximal data bursts that our TCP
 peers are allowed to send to us.
 
 .TP
-.BI rtt " NUMBER"
-the initial RTT ('Round Trip Time') estimate.
+.BI rtt " TIME"
+the initial RTT ('Round Trip Time') estimate. If no suffix is
+specified the units are raw values passed directly to the
+routing code to maintain compatability with previous releases.
+Otherwise if a suffix of s, sec or secs is used to specify
+seconds; ms, msec or msecs to specify milliseconds; us, usec
+or usecs to specify microseconds; ns, nsec or nsecs to specify
+nanoseconds; j, hz or jiffies to specify jiffies, the value is
+converted to what the routing code expects.
+
 
 .TP
-.BI rttvar " NUMBER " "(2.3.15+ only)"
-the initial RTT variance estimate.
+.BI rttvar " TIME " "(2.3.15+ only)"
+the initial RTT variance estimate. Values are specified as with
+.BI rtt
+above.
+
+.TP
+.BI rto_min " TIME " "(2.6.23+ only)"
+the minimum TCP Retransmission TimeOut to use when communicating with this
+destination.  Values are specified as with
+.BI rtt
+above.
 
 .TP
 .BI ssthresh " NUMBER " "(2.3.15+ only)"
@@ -1367,7 +1767,7 @@ force the output device on which this packet will be routed.
 
 .TP
 .B connected
-if no source address 
+if no source address
 .RB "(option " from ")"
 was given, relookup the route with the source set to the preferred
 address received from the first lookup.
@@ -1546,27 +1946,30 @@ the priority of this rule.  Each rule should have an explicitly
 set
 .I unique
 priority value.
+The options preference and order are synonyms with priority.
 
 .TP
 .BI table " TABLEID"
 the routing table identifier to lookup if the rule selector matches.
+It is also possible to use lookup instead of table.
 
 .TP
 .BI realms " FROM/TO"
 Realms to select if the rule matched and the routing table lookup
-succeeded.  Realm 
+succeeded.  Realm
 .I TO
 is only used if the route did not select any realm.
 
 .TP
 .BI nat " ADDRESS"
 The base of the IP address block to translate (for source addresses).
-The 
+The
 .I ADDRESS
 may be either the start of the block of NAT addresses (selected by NAT
 routes) or a local host address (or even zero).
 In the last case the router does not translate the packets, but
 masquerades them to this address.
+Using map-to instead of nat means the same thing.
 
 .B Warning:
 Changes to the RPDB made with these commands do not become active
@@ -1579,6 +1982,7 @@ This command has no arguments.
 
 .SS ip rule show - list rules
 This command has no arguments.
+The options list or lst are synonyms with show.
 
 .SH ip maddress - multicast addresses management
 
@@ -1637,8 +2041,11 @@ the prefix selecting the IP source addresses of the multicast route.
 
 .SH ip tunnel - tunnel configuration
 .B tunnel
-objects are tunnels, encapsulating packets in IPv4 packets and then
+objects are tunnels, encapsulating packets in IP packets and then
 sending them over the IP infrastructure.
+The encapulating (or outer) address family is specified by the
+.B -f
+option.  The default is IPv4.
 
 .SS ip tunnel add - add a new tunnel
 .SS ip tunnel change - change an existing tunnel
@@ -1650,8 +2057,13 @@ select the tunnel device name.
 
 .TP
 .BI mode " MODE"
-set the tunnel mode.  Three modes are currently available:
-.BR ipip ", " sit " and " gre "."
+set the tunnel mode. Available modes depend on the encapsulating address family.
+.br
+Modes for IPv4 encapsulation available:
+.BR ipip ", " sit ", " isatap " and " gre "."
+.br
+Modes for IPv6 encapsulation available:
+.BR ip6ip6 ", " ipip6 " and " any "."
 
 .TP
 .BI remote " ADDRESS"
@@ -1664,27 +2076,32 @@ It must be an address on another interface of this host.
 
 .TP
 .BI ttl " N"
-set a fixed TTL 
+set a fixed TTL
 .I N
 on tunneled packets.
 .I N
 is a number in the range 1--255. 0 is a special value
-meaning that packets inherit the TTL value. 
-The default value is:
+meaning that packets inherit the TTL value.
+The default value for IPv4 tunnels is:
 .BR "inherit" .
+The default value for IPv6 tunnels is:
+.BR "64" .
+
 
 .TP
 .BI tos " T"
 .TP
 .BI dsfield " T"
-set a fixed TOS
+.TP
+.BI tclass " T"
+set a fixed TOS (or traffic class in IPv6)
 .I T
 on tunneled packets.
 The default value is:
 .BR "inherit" .
 
 .TP
-.BI dev " NAME" 
+.BI dev " NAME"
 bind the tunnel to the device
 .I NAME
 so that tunneled packets will only be routed via this device and will
@@ -1714,12 +2131,12 @@ parameter sets the key to use in both directions.
 The
 .BR ikey " and " okey
 parameters set different keys for input and output.
-   
+
 .TP
 .BR csum ", " icsum ", " ocsum
 .RB ( " only GRE tunnels " )
 generate/require checksums for tunneled packets.
-The 
+The
 .B ocsum
 flag calculates checksums for outgoing packets.
 The
@@ -1742,10 +2159,25 @@ The
 flag requires that all input packets are serialized.
 The
 .B  seq
-flag is equivalent to the combination 
+flag is equivalent to the combination
 .BR "iseq oseq" .
 .B It isn't work. Don't use it.
 
+.TP
+.BR "dscp inherit"
+.RB ( " only IPv6 tunnels " )
+Inherit DS field between inner and outer header.
+
+.TP
+.BI encaplim " ELIM"
+.RB ( " only IPv6 tunnels " )
+set a fixed encapsulation limit.  Default is 4.
+
+.TP
+.BI flowlabel " FLOWLABEL"
+.RB ( " only IPv6 tunnels " )
+set a fixed flowlabel.
+
 .SS ip tunnel show - list tunnels
 This command has no arguments.
 
@@ -1799,6 +2231,169 @@ at any time.
 It prepends the history with the state snapshot dumped at the moment
 of starting.
 
+.SH ip xfrm - setting xfrm
+xfrm is an IP framework, which can transform format of the datagrams,
+.br
+i.e. encrypt the packets with some algorithm. xfrm policy and xfrm state
+are associated through templates
+.IR TMPL_LIST "."
+This framework is used as a part of IPsec protocol.
+
+.SS ip xfrm state add - add new state into xfrm
+
+.SS ip xfrm state update - update existing xfrm state
+
+.SS ip xfrm state allocspi - allocate SPI value
+
+.TP
+.I MODE
+is set as default to
+.BR transport ","
+but it could be set to
+.BR tunnel "," ro " or " beet "."
+
+.TP
+.I FLAG-LIST
+contains one or more flags.
+
+.TP
+.I FLAG
+could be set to
+.BR noecn ", " decap-dscp " or " wildrecv "."
+
+.TP
+.I ENCAP
+encapsulation is set to encapsulation type
+.IR ENCAP-TYPE ", source port " SPORT ", destination port "  DPORT " and " OADDR "."
+
+.TP
+.I ENCAP-TYPE
+could be set to
+.BR espinudp " or " espinudp-nonike "."
+
+.TP
+.I ALGO-LIST
+contains one or more algorithms
+.I ALGO
+which depend on the type of algorithm set by
+.IR ALGO_TYPE "."
+It can be used these algoritms
+.BR enc ", " auth " or " comp "."
+
+.SS ip xfrm policy add - add a new policy
+
+.SS ip xfrm policy update - update an existing policy
+
+.SS ip xfrm policy delete - delete existing policy
+
+.SS ip xfrm policy get - get existing policy
+
+.SS ip xfrm policy deleteall - delete all existing xfrm policy
+
+.SS ip xfrm policy list - print out the list of xfrm policy
+
+.SS ip xfrm policy flush - flush policies
+It can be flush
+.BR all
+policies or only those specified with
+.BR ptype "."
+
+.TP
+.BI dir " DIR "
+directory could be one of these:
+.BR "inp", " out " or " fwd".
+
+.TP
+.IR SELECTOR
+selects for which addresses will be set up the policy. The selector
+is defined by source and destination address.
+
+.TP
+.IR UPSPEC
+is defined by source port
+.BR sport ", "
+destination port
+.BR dport ", " type
+as number and
+.B code
+also number.
+
+.TP
+.BI dev " DEV "
+specify network device.
+
+.TP
+.BI index " INDEX "
+the number of indexed policy.
+
+.TP
+.BI ptype " PTYPE "
+type is set as default on
+.BR "main" ,
+could be switch on
+.BR "sub" .
+
+.TP
+.BI action " ACTION "
+is set as default on
+.BR "allow".
+It could be switch on
+.BR "block".
+
+.TP
+.BI priority " PRIORITY "
+priority is a number. Default priority is set on zero.
+
+.TP
+.IR LIMIT-LIST
+limits are set in seconds, bytes or numbers of packets.
+
+.TP
+.IR TMPL-LIST
+template list is based on
+.IR ID ","
+.BR mode ", " reqid " and " level ". "
+
+.TP
+.IR ID
+is specified by source address, destination address,
+.I proto
+and value of
+.IR spi "."
+
+.TP
+.IR XFRM_PROTO
+values:
+.BR esp ", " ah ", " comp ", " route2 " or " hao "."
+
+.TP
+.IR MODE
+is set as default on
+.BR transport ","
+but it could be set on
+.BR tunnel " or " beet "."
+
+.TP
+.IR LEVEL
+is set as default on
+.BR required
+and the other choice is
+.BR use "."
+
+.TP
+.IR UPSPEC
+is specified by
+.BR sport ", "
+.BR dport ", " type
+and
+.B code
+(NUMBER).
+
+.SS ip xfrm monitor - is used for listing all objects or defined group of them.
+The
+.B xfrm monitor
+can monitor the policies for all objects or defined group of them.
+
 .SH HISTORY
 .B ip
 was written by Alexey N. Kuznetsov and added in Linux 2.2.
@@ -1808,6 +2403,8 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
 .RB "IP Command reference " ip-cref.ps
 .br
 .RB "IP tunnels " ip-cref.ps
+.br
+.RB "User documentation at " http://lartc.org/ ", but please direct bugreports and patches to: " <netdev@vger.kernel.org>
 
 .SH AUTHOR
 Original Manpage  by Michail Litvak <mci@owl.openwall.com>
diff --git a/man/man8/lnstat.8 b/man/man8/lnstat.8
new file mode 100644 (file)
index 0000000..315a8e5
--- /dev/null
@@ -0,0 +1,75 @@
+.TH LNSTAT 8
+.SH NAME
+lnstat \- unified linux network statistics
+.SH SYNOPSIS
+.B lnstat
+.RI [ options ]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B lnstat
+command.
+.PP
+\fBlnstat\fP is a generalized and more feature-complete replacement for the old rtstat program.
+In addition to routing cache statistics, it supports any kind of statistics the linux kernel
+exports via a file in /proc/net/stat/.
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+lnstat supports the following options.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-V, \-\-version
+Show version of program.
+.TP
+.B \-c, \-\-count <count>
+Print <count> number of intervals.
+.TP
+.B \-d, \-\-dump
+Dump list of available files/keys.
+.TP
+.B \-f, \-\-file <file>
+Statistics file to use.
+.TP
+.B \-i, \-\-interval <intv>
+Set interval to 'intv' seconds.
+.TP
+.B \-k, \-\-keys k,k,k,...
+Display only keys specified.
+.TP
+.B \-s, \-\-subject [0-2]
+Specify display of subject/header. '0' means no header at all, '1' prints a header only at start of the program and '2' prints a header every 20 lines.
+.TP
+.B \-w, \-\-width n,n,n,...
+Width for each field.
+.SH USAGE EXAMPLES
+.TP
+.B # lnstat -d
+Get a list of supported statistics files.
+.TP
+.B # lnstat -k arp_cache:entries,rt_cache:in_hit,arp_cache:destroys
+Select the specified files and keys.
+.TP
+.B # lnstat -i 10
+Use an interval of 10 seconds.
+.TP
+.B # lnstat -f ip_conntrack
+Use only the specified file for statistics.
+.TP
+.B # lnstat -s 0
+Do not print a header at all.
+.TP
+.B # lnstat -s 20
+Print a header at start and every 20 lines.
+.TP
+.B # lnstat -c -1 -i 1 -f rt_cache -k entries,in_hit,in_slow_tot
+Display statistics for keys entries, in_hit and in_slow_tot of field rt_cache every second.
+.SH SEE ALSO
+.BR ip (8),
+and /usr/share/doc/iproute-doc/README.lnstat (package iproute-doc on Debian)
+.br
+.SH AUTHOR
+lnstat was written by Harald Welte <laforge@gnumonks.org>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org> for the Debian project (but may be used by others).
diff --git a/man/man8/routel.8 b/man/man8/routel.8
new file mode 100644 (file)
index 0000000..cdf8f55
--- /dev/null
@@ -0,0 +1,32 @@
+.TH "ROUTEL" "8" "3 Jan, 2008" "iproute2" "Linux"
+.SH "NAME"
+.LP 
+routel \- list routes with pretty output format
+.br
+routef \- flush routes
+.SH "SYNTAX"
+.LP 
+routel [\fItablenr\fP [\fIraw ip args...\fP]]
+.br 
+routef
+.SH "DESCRIPTION"
+.LP 
+These programs are a set of helper scripts you can use instead of raw iproute2 commands.
+.br
+The routel script will list routes in a format that some might consider easier to interpret then the ip route list equivalent.
+.br
+The routef script does not take any arguments and will simply flush the routing table down the drain. Beware! This means deleting all routes which will make your network unusable!
+
+.SH "FILES"
+.LP 
+\fI/usr/bin/routef\fP 
+.br 
+\fI/usr/bin/routel\fP 
+.SH "AUTHORS"
+.LP 
+The routel script was written by Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18 and donated to the public domain.
+.br
+This manual page was written by Andreas Henriksson  <andreas@fatal.se>, for the Debian GNU/Linux system.
+.SH "SEE ALSO"
+.LP 
+ip(8)
diff --git a/man/man8/rtacct.8 b/man/man8/rtacct.8
new file mode 100644 (file)
index 0000000..fb9afe8
--- /dev/null
@@ -0,0 +1,48 @@
+.TH RTACCT 8 "27 June, 2007"
+
+.SH NAME
+nstat, rtacct - network statistics tools.
+
+.SH SYNOPSIS
+Usage: nstat [ -h?vVzrnasd:t: ] [ PATTERN [ PATTERN ] ]
+.br
+Usage: rtacct [ -h?vVzrnasd:t: ] [ ListOfRealms ]
+
+.SH DESCRIPTION
+.B nstat
+and
+.B rtacct
+are simple tools to monitor kernel snmp counters and network interface statistics.
+
+.SH OPTIONS
+.TP
+-h -?
+Print help
+.TP
+-v -V
+Print version
+.TP
+-z
+Dump zero counters too. By default they are not shown.
+.TP
+-r
+Reset history.
+.TP
+-n
+Do not display anything, only update history.
+.TP
+-a
+Dump absolute values of counters. The default is to calculate increments since the previous use.
+.TP
+-s
+Do not update history, so that the next time you will see counters including values accumulated to the moment of this measurement too.
+.TP
+-d <INTERVAL>
+Run in daemon mode collecting statistics. <INTERVAL> is interval between measurements in seconds.
+.TP
+-t <INTERVAL>
+Time interval to average rates. Default value is 60 seconds.
+
+.SH SEE ALSO
+lnstat(8)
+
diff --git a/man/man8/rtmon.8 b/man/man8/rtmon.8
new file mode 100644 (file)
index 0000000..c9359d8
--- /dev/null
@@ -0,0 +1,68 @@
+.TH RTMON 8
+.SH NAME
+rtmon \- listens to and monitors RTnetlink
+.SH SYNOPSIS
+.B rtmon
+.RI "[ options ] file FILE [ all | LISTofOBJECTS ]"
+.SH DESCRIPTION
+This manual page documents briefly the
+.B rtmon
+command.
+.PP
+.B rtmon
+listens on 
+.I netlink 
+socket and monitors routing table changes.
+
+.I rtmon 
+can be started before the first network configuration command is issued.
+For example if you insert:
+
+.B rtmon file /var/log/rtmon.log
+
+in a startup script, you will be able to view the full history later.
+Certainly, it is possible to start rtmon at any time. It prepends the history with the state snapshot dumped at the moment of starting.
+
+.SH OPTIONS
+.I rtmon supports the following options:
+.TP
+.B \-Version
+Print version and exit.
+.TP
+.B help
+Show summary of options.
+.TP
+.B file FILE [ all | LISTofOBJECTS ]
+Log output to FILE. LISTofOBJECTS is the list of object types that we
+want to monitor.  It may contain 'link', 'address', 'route'
+and 'all'. 'link' specifies the network device, 'address' the protocol
+(IP or IPv6) address on a device, 'route' the routing table entry
+and 'all' does what the name says.
+.TP
+.B \-family [ inet | inet6 | link | help ]
+Specify protocol family. 'inet' is IPv4, 'inet6' is IPv6, 'link'
+means that no networking protocol is involved and 'help' prints usage information.
+.TP
+.B \-4
+Use IPv4. Shortcut for -family inet.
+.TP
+.B \-6
+Use IPv6. Shortcut for -family inet6.
+.TP
+.B \-0
+Use a special family identifier meaning that no networking protocol is involved. Shortcut for -family link.
+.SH USAGE EXAMPLES
+.TP
+.B # rtmon file /var/log/rtmon.log
+Log to file /var/log/rtmon.log, then run:
+.TP
+.B # ip monitor file /var/log/rtmon.log
+to display logged output from file.
+.SH SEE ALSO
+.BR ip (8)
+.SH AUTHOR
+.B rtmon 
+was written by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org>,
+for the Debian project (but may be used by others).
diff --git a/man/man8/ss.8 b/man/man8/ss.8
new file mode 100644 (file)
index 0000000..015feb3
--- /dev/null
@@ -0,0 +1,123 @@
+.TH SS 8
+.SH NAME
+ss \- another utility to investigate sockets
+.SH SYNOPSIS
+.B ss
+.RI [ options ] " [ FILTER ]"
+.SH DESCRIPTION
+.B ss
+is used to dump socket statistics. It allows showing information similar
+to
+.IR netstat .
+It can display more TCP and state informations than other tools.
+
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+A summary of options is included below.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-V, \-\-version
+Output version information.
+.TP
+.B \-n, \-\-numeric
+Do now try to resolve service names.
+.TP
+.B \-r, \-\-resolve
+Try to resolve numeric address/ports.
+.TP
+.B \-a, \-\-all
+Display all sockets.
+.TP
+.B \-l, \-\-listening
+Display listening sockets.
+.TP
+.B \-o, \-\-options
+Show timer information.
+.TP
+.B \-e, \-\-extended
+Show detailed socket information
+.TP
+.B \-m, \-\-memory
+Show socket memory usage.
+.TP
+.B \-p, \-\-processes
+Show process using socket.
+.TP
+.B \-i, \-\-info
+Show internal TCP information.
+.TP
+.B \-s, \-\-summary
+Print summary statistics. This option does not parse socket lists obtaining
+summary from various sources. It is useful when amount of sockets is so huge
+that parsing /proc/net/tcp is painful.
+.TP
+.B \-4, \-\-ipv4
+Display only IP version 4 sockets (alias for -f inet).
+.TP
+.B \-6, \-\-ipv6
+Display only IP version 6 sockets (alias for -f inet6).
+.TP
+.B \-0, \-\-packet
+Display PACKET sockets.
+.TP
+.B \-t, \-\-tcp
+Display only TCP sockets.
+.TP
+.B \-u, \-\-udp
+Display only UDP sockets.
+.TP
+.B \-d, \-\-dccp
+Display only DCCP sockets.
+.TP
+.B \-w, \-\-raw
+Display only RAW sockets.
+.TP
+.B \-x, \-\-unix
+Display only Unix domain sockets.
+.TP
+.B \-f FAMILY, \-\-family=FAMILY
+Display sockets of type FAMILY.
+Currently the following families are supported: unix, inet, inet6, link, netlink.
+.TP
+.B \-A QUERY, \-\-query=QUERY
+List of socket tables to dump, separated by commas. The following identifiers
+are understood: all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram,
+unix_stream, packet_raw, packet_dgram.
+.TP
+.B \-D FILE
+Do not display anything, just dump raw information about TCP sockets to FILE after applying filters. If FILE is - stdout is used.
+.TP
+.B \-F FILE, \-\-filter=FILE
+Read filter information from FILE.
+Each line of FILE is interpreted like single command line option. If FILE is - stdin is used.
+.TP
+.B FILTER := [ state TCP-STATE ] [ EXPRESSION ]
+Please take a look at the official documentation (Debian package iproute-doc) for details regarding filters.
+.SH USAGE EXAMPLES
+.TP
+.B ss -t -a
+Display all TCP sockets.
+.TP
+.B ss -u -a
+Display all UDP sockets.
+.TP
+.B ss -o state established '( dport = :ssh or sport = :ssh )'
+Display all established ssh connections.
+.TP
+.B ss -x src /tmp/.X11-unix/*
+Find all local processes connected to X server.
+.TP
+.B ss -o state fin-wait-1 '( sport = :http or sport = :https )' dst 193.233.7/24
+List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers.
+.SH SEE ALSO
+.BR ip (8),
+.BR /usr/share/doc/iproute-doc/ss.html " (package iproute­doc)"
+.SH AUTHOR
+.I ss 
+was written by Alexey Kuznetosv, <kuznet@ms2.inr.ac.ru>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org>
+for the Debian project (but may be used by others).
similarity index 100%
rename from man/man8/tc-pbfifo.8
rename to man/man8/tc-bfifo.8
index e47da62..09badb9 100644 (file)
@@ -210,7 +210,7 @@ Consult the map for a class for the
 priority. If found, choose it, and terminate.
 .TP
 (iii)
-Choose the class at which break out to the fallback algorithm occured. Terminate.
+Choose the class at which break out to the fallback algorithm occurred. Terminate.
 .P
 The packet is enqueued to the class which was chosen when either algorithm 
 terminated. It is therefore possible for a packet to be enqueued *not* at a
index f61b818..d196ecd 100644 (file)
@@ -137,7 +137,7 @@ packet. Should be at least as high as the highest cburst of all children.
 .SH NOTES
 Due to Unix timing constraints, the maximum ceil rate is not infinite and may in fact be quite low. On Intel, 
 there are 100 timer events per second, the maximum rate is that rate at which 'burst' bytes are sent each timer tick.
-From this, the mininum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte 
+From this, the minimum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte 
 burst as 100*12kb*8 equals 10mbit.
 
 .SH SEE ALSO
deleted file mode 100644 (file)
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..70a54af15e9e1499cbb4827766c468cf40447b63
--- /dev/null
@@ -0,0 +1 @@
+tc-bfifo.8
\ No newline at end of file
index e942e62..780bcd5 100644 (file)
@@ -30,7 +30,7 @@ traffic.
 On creation with 'tc qdisc add', a fixed number of bands is created. Each
 band is a class, although is not possible to add classes with 'tc qdisc
 add', the number of bands to be created must instead be specified on the
-commandline attaching PRIO to its root.
+command line attaching PRIO to its root.
 
 When dequeueing, band 0 is tried first and only if it did not deliver a
 packet does PRIO try band 1, and so onwards. Maximum reliability packets
@@ -88,7 +88,7 @@ this:
 The four TOS bits (the 'TOS field') are defined as:
 
 .nf
-Binary Decimcal  Meaning
+Binary Decimal  Meaning
 -----------------------------------------
 1000   8         Minimize delay (md)
 0100   4         Maximize throughput (mt)
@@ -125,13 +125,13 @@ TOS     Bits  Means                    Linux Priority    Band
 
 The second column contains the value of the relevant
 four TOS bits, followed by their translated meaning. For example, 15 stands
-for a packet wanting Minimal Montetary Cost, Maximum Reliability, Maximum
+for a packet wanting Minimal Monetary Cost, Maximum Reliability, Maximum
 Throughput AND Minimum Delay. 
 
 The fourth column lists the way the Linux kernel interprets the TOS bits, by
 showing to which Priority they are mapped.
 
-The last column shows the result of the default priomap. On the commandline,
+The last column shows the result of the default priomap. On the command line,
 the default priomap looks like this:
 
     1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
index b9b8039..8c0880f 100644 (file)
@@ -34,16 +34,28 @@ priority filtertype
 .B flowid
 flow-id
 
-.B tc [-s | -d ] qdisc show [ dev 
+.B tc
+.RI "[ " FORMAT " ]"
+.B qdisc show [ dev 
 DEV 
 .B  ]
 .P
-.B tc [-s | -d ] class show dev 
+.B tc 
+.RI "[ " FORMAT " ]"
+.B class show dev 
 DEV 
 .P
 .B tc filter show dev 
 DEV 
 
+.ti -8
+.IR FORMAT " := {"
+\fB\-s\fR[\fItatistics\fR] |
+\fB\-d\fR[\fIetails\fR] |
+\fB\-r\fR[\fIaw\fR] |
+\fB\-p\fR[\fIretty\fR] |
+\fB\i\fR[\fIec\fR] }
+
 .SH DESCRIPTION
 .B Tc
 is used to configure Traffic Control in the Linux kernel. Traffic Control consists 
@@ -202,8 +214,7 @@ qdiscs will use all three:
 tc filters
 If tc filters are attached to a class, they are consulted first 
 for relevant instructions. Filters can match on all fields of a packet header, 
-as well as on the firewall mark applied by ipchains or iptables. See 
-.BR tc-filters (8).
+as well as on the firewall mark applied by ipchains or iptables. 
 .TP
 Type of Service
 Some qdiscs have built in rules for classifying packets based on the TOS field.
@@ -242,8 +253,7 @@ qdiscs applies.
 .TP 
 FILTERS
 Filters have a three part ID, which is only needed when using a hashed
-filter hierarchy, for which see
-.BR tc-filters (8).
+filter hierarchy.
 .SH UNITS
 All parameters accept a floating point number, possibly followed by a unit.
 .P
@@ -328,6 +338,29 @@ link
 Only available for qdiscs and performs a replace where the node 
 must exist already.
 
+.SH FORMAT
+The show command has additional formatting options:
+
+.TP
+.BR "\-s" , " \-stats", " \-statistics"
+output more statistics about packet usage.
+
+.TP
+.BR "\-d", " \-details"
+output more detailed information about rates and cell sizes.
+
+.TP
+.BR "\-r", " \-raw"
+output raw hex values for handles.
+
+.TP
+.BR "\-p", " \-pretty"
+decode filter offset and mask values to equivalent filter commands based on TCP/IP.
+
+.TP
+.BR "\-iec"
+print rates in IEC units (ie. 1K = 1024).
+
 
 .SH HISTORY
 .B tc
@@ -341,7 +374,8 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
 .BR tc-pfifo (8),
 .BR tc-bfifo (8),
 .BR tc-pfifo_fast (8),
-.BR tc-filters (8)
+.br
+.RB "User documentation at " http://lartc.org/ ", but please direct bugreports and patches to: " <netdev@vger.kernel.org>
 
 .SH AUTHOR
 Manpage maintained by bert hubert (ahu@ds9a.nl)
diff --git a/misc/.gitignore b/misc/.gitignore
new file mode 100644 (file)
index 0000000..f73f7f2
--- /dev/null
@@ -0,0 +1,7 @@
+arpd
+ifstat
+ss
+ssfilter.c
+nstat
+lnstat
+rtacct
index bda37e5..8c25381 100644 (file)
@@ -27,7 +27,7 @@ ssfilter.c: ssfilter.y
 lnstat: $(LNSTATOBJ)
 
 install: all
-       install -m 0755 -s $(TARGETS) $(DESTDIR)$(SBINDIR)
+       install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
        ln -sf lnstat $(DESTDIR)$(SBINDIR)/rtstat
        ln -sf lnstat $(DESTDIR)$(SBINDIR)/ctstat
 
index 4fd226e..71cd082 100644 (file)
@@ -42,7 +42,7 @@ int resolve_hosts;
 DB     *dbase;
 char   *dbname = "/var/lib/arpd/arpd.db";
 
-int    ifnum;  
+int    ifnum;
 int    *ifvec;
 char   **ifnames;
 
@@ -53,7 +53,7 @@ struct dbkey
 };
 
 #define IS_NEG(x)      (((__u8*)(x))[0] == 0xFF)
-#define NEG_TIME(x)    (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5]) 
+#define NEG_TIME(x)    (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
 #define NEG_AGE(x)     ((__u32)time(NULL) - NEG_TIME((__u8*)x))
 #define NEG_VALID(x)   (NEG_AGE(x) < negative_timeout)
 #define NEG_CNT(x)     (((__u8*)(x))[1])
@@ -485,7 +485,7 @@ void get_arp_pkt(void)
        DBT dbkey, dbdat;
        int n;
 
-       n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, 
+       n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
                     (struct sockaddr*)&sll, &sll_len);
        if (n < 0) {
                if (errno != EINTR && errno != EAGAIN)
@@ -510,7 +510,7 @@ void get_arp_pkt(void)
        key.iface = sll.sll_ifindex;
        memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4);
 
-       /* DAD message, ignore. */ 
+       /* DAD message, ignore. */
        if (key.addr == 0)
                return;
 
@@ -538,7 +538,7 @@ void catch_signal(int sig, void (*handler)(int))
        sa.sa_handler = handler;
 #ifdef SA_INTERRUPT
        sa.sa_flags = SA_INTERRUPT;
-#endif 
+#endif
        sigaction(sig, &sa, NULL);
 }
 
@@ -728,7 +728,7 @@ int main(int argc, char **argv)
                DBT dbkey, dbdat;
                printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
                while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
-                       struct dbkey *key = dbkey.data; 
+                       struct dbkey *key = dbkey.data;
                        if (handle_if(key->iface)) {
                                if (!IS_NEG(dbdat.data)) {
                                        char b1[18];
index 4b87994..68dfdee 100644 (file)
@@ -77,7 +77,7 @@ static int match(const char *id)
        return 0;
 }
 
-static int get_nlmsg(const struct sockaddr_nl *who, 
+static int get_nlmsg(const struct sockaddr_nl *who,
                     struct nlmsghdr *m, void *arg)
 {
        struct ifinfomsg *ifi = NLMSG_DATA(m);
@@ -442,11 +442,11 @@ void update_db(int interval)
                                int i;
                                for (i = 0; i < MAXS; i++) {
                                        if ((long)(h1->ival[i] - n->ival[i]) < 0) {
-                                               memset(n->ival, 0, sizeof(n->ival)); 
+                                               memset(n->ival, 0, sizeof(n->ival));
                                                break;
                                        }
                                }
-                               for (i = 0; i < MAXS; i++) { 
+                               for (i = 0; i < MAXS; i++) {
                                        double sample;
                                        unsigned long incr = h1->ival[i] - n->ival[i];
                                        n->val[i] += incr;
index 460540e..32ab6a4 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 /* Maximum number of fields that can be displayed */
-#define MAX_FIELDS             64
+#define MAX_FIELDS             128
 
 /* Maximum number of header lines */
 #define HDR_LINES              10
@@ -119,11 +119,19 @@ static int map_field_params(struct lnstat_file *lnstat_files,
                                fps->params[j].lf->file->interval.tv_sec =
                                                                interval;
                                if (!fps->params[j].print.width)
-                                       fps->params[j].print.width = 
+                                       fps->params[j].print.width =
                                                        FIELD_WIDTH_DEFAULT;
-                               j++;
+                               
+                               if (++j >= MAX_FIELDS - 1) {
+                                       fprintf(stderr,
+                                               "WARN: MAX_FIELDS (%d) reached,"
+                                               " truncating number of keys\n",
+                                               MAX_FIELDS);
+                                       goto full;
+                               }
                        }
                }
+       full:
                fps->num = j;
                return 1;
        }
@@ -204,7 +212,7 @@ static int print_hdr(FILE *of, struct table_hdr *th)
        }
        return 0;
 }
-               
+
 
 int main(int argc, char **argv)
 {
@@ -222,10 +230,10 @@ int main(int argc, char **argv)
        static struct field_params fp;
        int num_req_files = 0;
        char *req_files[LNSTAT_MAX_FILES];
-       
+
        /* backwards compatibility mode for old tools */
        basename = strrchr(argv[0], '/');
-       if (basename) 
+       if (basename)
                basename += 1;    /* name after slash */
        else
                basename = argv[0]; /* no slash */
@@ -240,7 +248,7 @@ int main(int argc, char **argv)
                num_req_files = 1;
        }
 
-       while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:", 
+       while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:",
                                opts, NULL)) != -1) {
                int i, len = 0;
                char *tmp, *tok;
@@ -256,7 +264,7 @@ int main(int argc, char **argv)
                                req_files[num_req_files++] = strdup(optarg);
                                break;
                        case '?':
-                       case 'h':       
+                       case 'h':
                                usage(argv[0], 0);
                                break;
                        case 'i':
@@ -269,8 +277,13 @@ int main(int argc, char **argv)
                                for (tok = strtok(tmp, ",");
                                     tok;
                                     tok = strtok(NULL, ",")) {
-                                       if (fp.num >= MAX_FIELDS)
+                                       if (fp.num >= MAX_FIELDS) {
+                                               fprintf(stderr, 
+                                                       "WARN: too many keys"
+                                                       " requested: (%d max)\n",
+                                                       MAX_FIELDS);
                                                break;
+                                       }
                                        fp.params[fp.num++].name = tok;
                                }
                                break;
@@ -315,12 +328,12 @@ int main(int argc, char **argv)
 
                if (!map_field_params(lnstat_files, &fp, interval))
                        exit(1);
-       
+
                header = build_hdr_string(lnstat_files, &fp, 80);
                if (!header)
                        exit(1);
 
-               if (interval < 1 ) 
+               if (interval < 1 )
                        interval=1;
 
                for (i = 0; i < count; i++) {
@@ -328,6 +341,7 @@ int main(int argc, char **argv)
                                print_hdr(stdout, header);
                        lnstat_update(lnstat_files);
                        print_line(stdout, lnstat_files, &fp);
+                       fflush(stdout);
                        sleep(interval);
                }
        }
index 59c5e96..9492baf 100644 (file)
@@ -49,12 +49,12 @@ static int scan_lines(struct lnstat_file *lf, int i)
 
                num_lines++;
 
-               fgets(buf, sizeof(buf)-1, lf->fp); 
+               fgets(buf, sizeof(buf)-1, lf->fp);
                gettimeofday(&lf->last_read, NULL);
 
                for (j = 0; j < lf->num_fields; j++) {
                        unsigned long f = strtoul(ptr, &ptr, 16);
-                       if (j == 0) 
+                       if (j == 0)
                                lf->fields[j].values[i] = f;
                        else
                                lf->fields[j].values[i] += f;
@@ -63,8 +63,8 @@ static int scan_lines(struct lnstat_file *lf, int i)
        return num_lines;
 }
 
-static int time_after(struct timeval *last, 
-                     struct timeval *tout, 
+static int time_after(struct timeval *last,
+                     struct timeval *tout,
                      struct timeval *now)
 {
        if (now->tv_sec > last->tv_sec + tout->tv_sec)
@@ -98,7 +98,7 @@ int lnstat_update(struct lnstat_file *lnstat_files)
                        }
                        scan_lines(lf, 1);
 
-                       for (i = 0, lfi = &lf->fields[i]; 
+                       for (i = 0, lfi = &lf->fields[i];
                             i < lf->num_fields; i++, lfi = &lf->fields[i]) {
                                if (i == 0)
                                        lfi->result = lfi->values[1];
@@ -211,7 +211,7 @@ struct lnstat_file *lnstat_scan_dir(const char *path, const int num_req_files,
 
        if (!path)
                path = PROC_NET_STAT;
-       
+
        dir = opendir(path);
        if (!dir) {
                struct lnstat_file *lf;
@@ -307,7 +307,7 @@ struct lnstat_field *lnstat_find_field(struct lnstat_file *lnstat_files,
                file = NULL;
                field = name;
        }
-               
+
        for (lf = lnstat_files; lf; lf = lf->next) {
                int i;
 
diff --git a/misc/netbug b/misc/netbug
deleted file mode 100755 (executable)
index 6d13c8e..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#! /bin/bash
-
-echo -n "Send network configuration summary to [ENTER means kuznet@ms2.inr.ac.ru] "
-IFS="" read mail || exit 1
-[ -z "$mail" ] && mail=kuznet@ms2.inr.ac.ru
-
-
-netbug=""
-while [ "$netbug" = "" ]; do
-       netbug=`echo netbug.$$.$RANDOM`
-       if [ -e /tmp/$netbug ]; then
-               netbug=""
-       fi
-done
-
-tmppath=/tmp/$netbug
-
-trap "rm -rf $tmppath $tmppath.tar.gz" 0 SIGINT
-
-mkdir $tmppath
-mkdir $tmppath/net
-
-cat /proc/slabinfo > $tmppath/slabinfo
-cat /proc/net/netstat > $tmppath/net/netstat
-cat /proc/net/unix > $tmppath/net/unix
-cat /proc/net/packet > $tmppath/net/packet
-cat /proc/net/netlink > $tmppath/net/netlink
-cat /proc/net/psched > $tmppath/net/psched
-cat /proc/net/softnet_stat > $tmppath/net/softnet_stat
-cat /proc/net/sockstat > $tmppath/net/sockstat
-cat /proc/net/tcp > $tmppath/net/tcp
-cat /proc/net/udp > $tmppath/net/udp
-cat /proc/net/raw > $tmppath/net/raw
-cat /proc/net/snmp > $tmppath/net/snmp
-
-ss -aioem -D $tmppath/tcpdiag
-
-if [ -e /proc/net/tcp6 ]; then
-       cat /proc/net/sockstat6 > $tmppath/net/sockstat6
-       cat /proc/net/tcp6 > $tmppath/net/tcp6
-       cat /proc/net/udp6 > $tmppath/net/udp6
-       cat /proc/net/raw6 > $tmppath/net/raw6
-       cat /proc/net/snmp6 > $tmppath/net/snmp6
-fi
-
-cd /tmp
-tar c $netbug | gzip -9c > $netbug.tar.gz
-
-uuencode $netbug.tar.gz $netbug.tar.gz | mail -s $netbug "$mail"
-
-echo "Sending to <$mail>; subject is $netbug"
-
-exit 0
index fc4b03b..80e695f 100644 (file)
@@ -43,7 +43,7 @@ int npatterns;
 char info_source[128];
 int source_mismatch;
 
-int generic_proc_open(char *env, char *name)
+static int generic_proc_open(const char *env, char *name)
 {
        char store[128];
        char *p = getenv(env);
@@ -52,7 +52,7 @@ int generic_proc_open(char *env, char *name)
                snprintf(store, sizeof(store)-1, "%s/%s", p, name);
                p = store;
        }
-       return open(store, O_RDONLY);
+       return open(p, O_RDONLY);
 }
 
 int net_netstat_open(void)
@@ -373,7 +373,7 @@ void server_loop(int fd)
        struct pollfd p;
        p.fd = fd;
        p.events = p.revents = POLLIN;
-       
+
        sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
                getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);
 
index 0d8ff7b..eb3ea9e 100644 (file)
@@ -43,7 +43,7 @@ int dump_zeros = 0;
 unsigned long magic_number = 0;
 double W;
 
-int generic_proc_open(char *env, char *name)
+static int generic_proc_open(const char *env, const char *name)
 {
        char store[1024];
        char *p = getenv(env);
@@ -52,7 +52,7 @@ int generic_proc_open(char *env, char *name)
                snprintf(store, sizeof(store)-1, "%s/%s", p, name);
                p = store;
        }
-       return open(store, O_RDONLY);
+       return open(p, O_RDONLY);
 }
 
 int net_rtacct_open(void)
@@ -168,7 +168,7 @@ void dump_abs_db(FILE *fp)
 "%-10s "
 "%-10s "
 "\n"
-                      , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom"); 
+                      , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
                fprintf(fp,
 "%-10s "
 "%-10s "
@@ -176,7 +176,7 @@ void dump_abs_db(FILE *fp)
 "%-10s "
 "%-10s "
 "\n"
-                      , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom"); 
+                      , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
 
        }
 
@@ -207,10 +207,10 @@ void dump_abs_db(FILE *fp)
 
                fprintf(fp, "%-10s", rtnl_rtrealm_n2a(realm, b1, sizeof(b1)));
                for (i = 0; i < 4; i++)
-                       format_count(fp, val[i]); 
+                       format_count(fp, val[i]);
                fprintf(fp, "\n%-10s", "");
                for (i = 0; i < 4; i++)
-                       format_rate(fp, rate[i]); 
+                       format_rate(fp, rate[i]);
                fprintf(fp, "\n");
        }
 }
@@ -230,7 +230,7 @@ void dump_incr_db(FILE *fp)
 "%-10s "
 "%-10s "
 "\n"
-                      , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom"); 
+                      , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
                fprintf(fp,
 "%-10s "
 "%-10s "
@@ -238,7 +238,7 @@ void dump_incr_db(FILE *fp)
 "%-10s "
 "%-10s "
 "\n"
-                      , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom"); 
+                      , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
        }
 
        for (realm=0; realm<256; realm++) {
@@ -282,10 +282,10 @@ void dump_incr_db(FILE *fp)
 
                fprintf(fp, "%-10s", rtnl_rtrealm_n2a(realm, b1, sizeof(b1)));
                for (i = 0; i < 4; i++)
-                       format_count(fp, rval[i]); 
+                       format_count(fp, rval[i]);
                fprintf(fp, "\n%-10s", "");
                for (i = 0; i < 4; i++)
-                       format_rate(fp, rate[i]); 
+                       format_rate(fp, rate[i]);
                fprintf(fp, "\n");
        }
 }
@@ -297,7 +297,7 @@ void sigchild(int signo)
 {
 }
 
-/* Server side only: read kernel data, update tables, calculate rates. */ 
+/* Server side only: read kernel data, update tables, calculate rates. */
 
 void update_db(int interval)
 {
@@ -368,9 +368,9 @@ void server_loop(int fd)
        p.fd = fd;
        p.events = p.revents = POLLIN;
 
-       sprintf(kern_db->signature, 
+       sprintf(kern_db->signature,
                "%u.%lu sampling_interval=%d time_const=%d",
-               (unsigned) getpid(), (unsigned long)random(), 
+               (unsigned) getpid(), (unsigned long)random(),
                scan_interval/1000, time_constant/1000);
 
        pad_kern_table(kern_db, read_kern_table(kern_db->ival));
index f902560..651fe3b 100644 (file)
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -33,9 +33,8 @@
 #include "libnetlink.h"
 #include "SNAPSHOT.h"
 
+#include <netinet/tcp.h>
 #include <linux/inet_diag.h>
-#include <linux/tcp.h>
-#include <net/tcp_states.h>
 
 int resolve_hosts = 0;
 int resolve_services = 1;
@@ -105,101 +104,98 @@ struct filter
 };
 
 struct filter default_filter = {
-       dbs: (1<<TCP_DB),
-       states: SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
-       families: (1<<AF_INET)|(1<<AF_INET6),
+       .dbs    =  (1<<TCP_DB),
+       .states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
+       .families= (1<<AF_INET)|(1<<AF_INET6),
 };
 
 struct filter current_filter;
 
-int generic_proc_open(char *env, char *name)
+static FILE *generic_proc_open(const char *env, const char *name)
 {
+       const char *p = getenv(env);
        char store[128];
-       char *p = getenv(env);
+
        if (!p) {
                p = getenv("PROC_ROOT") ? : "/proc";
                snprintf(store, sizeof(store)-1, "%s/%s", p, name);
                p = store;
        }
-       return open(store, O_RDONLY);
+
+       return fopen(p, "r");
 }
 
-int net_tcp_open(void)
+static FILE *net_tcp_open(void)
 {
        return generic_proc_open("PROC_NET_TCP", "net/tcp");
 }
 
-int net_tcp6_open(void)
+static FILE *net_tcp6_open(void)
 {
        return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
 }
 
-int net_udp_open(void)
+static FILE *net_udp_open(void)
 {
        return generic_proc_open("PROC_NET_UDP", "net/udp");
 }
 
-int net_udp6_open(void)
+static FILE *net_udp6_open(void)
 {
        return generic_proc_open("PROC_NET_UDP6", "net/udp6");
 }
 
-int net_raw_open(void)
+static FILE *net_raw_open(void)
 {
        return generic_proc_open("PROC_NET_RAW", "net/raw");
 }
 
-int net_raw6_open(void)
+static FILE *net_raw6_open(void)
 {
        return generic_proc_open("PROC_NET_RAW6", "net/raw6");
 }
 
-int net_unix_open(void)
+static FILE *net_unix_open(void)
 {
        return generic_proc_open("PROC_NET_UNIX", "net/unix");
 }
 
-int net_packet_open(void)
+static FILE *net_packet_open(void)
 {
        return generic_proc_open("PROC_NET_PACKET", "net/packet");
 }
 
-int net_netlink_open(void)
+static FILE *net_netlink_open(void)
 {
        return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
 }
 
-int slabinfo_open(void)
+static FILE *slabinfo_open(void)
 {
        return generic_proc_open("PROC_SLABINFO", "slabinfo");
 }
 
-int net_sockstat_open(void)
+static FILE *net_sockstat_open(void)
 {
        return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
 }
 
-int net_sockstat6_open(void)
+static FILE *net_sockstat6_open(void)
 {
        return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
 }
 
-int net_snmp_open(void)
+static FILE *net_snmp_open(void)
 {
        return generic_proc_open("PROC_NET_SNMP", "net/snmp");
 }
 
-int net_netstat_open(void)
-{
-       return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
-}
-
-int ephemeral_ports_open(void)
+static FILE *ephemeral_ports_open(void)
 {
        return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
 }
 
-int find_users(int ino, char *buf, int buflen)
+int find_users(unsigned ino, char *buf, int buflen)
 {
        char pattern[64];
        int  pattern_len;
@@ -213,7 +209,7 @@ int find_users(int ino, char *buf, int buflen)
        if (!ino)
                return 0;
 
-       sprintf(pattern, "socket:[%d]", ino);
+       sprintf(pattern, "socket:[%u]", ino);
        pattern_len = strlen(pattern);
 
        strncpy(name, getenv("PROC_ROOT") ? : "/proc/", sizeof(name)/2);
@@ -296,7 +292,7 @@ struct slabstat
 
 struct slabstat slabstat;
 
-static const char *slabstat_ids[] = 
+static const char *slabstat_ids[] =
 {
        "sock",
        "tcp_bind_bucket",
@@ -313,7 +309,8 @@ int get_slabstat(struct slabstat *s)
 
        memset(s, 0, sizeof(*s));
 
-       if ((fp = fdopen(slabinfo_open(), "r")) == NULL)
+       fp = slabinfo_open();
+       if (!fp)
                return -1;
 
        cnt = sizeof(*s)/sizeof(int);
@@ -377,9 +374,9 @@ struct tcpstat
        int             timer;
        int             timeout;
        int             retrs;
-       int             ino;
+       unsigned        ino;
        int             probes;
-       int             uid;
+       unsigned        uid;
        int             refcnt;
        unsigned long long sk;
        int             rto, ato, qack, cwnd, ssthresh;
@@ -419,13 +416,13 @@ const char *print_ms_timer(int timeout)
        if (msecs)
                sprintf(buf+strlen(buf), "%03dms", msecs);
        return buf;
-};
+}
 
 const char *print_hz_timer(int timeout)
 {
-       int hz = get_hz();
+       int hz = get_user_hz();
        return print_ms_timer(((timeout*1000) + hz-1)/hz);
-};
+}
 
 struct scache
 {
@@ -478,9 +475,9 @@ static int ip_local_port_min, ip_local_port_max;
 static int is_ephemeral(int port)
 {
        if (!ip_local_port_min) {
-               FILE *f = fdopen(ephemeral_ports_open(), "r");
+               FILE *f = ephemeral_ports_open();
                if (f) {
-                       fscanf(f, "%d %d", 
+                       fscanf(f, "%d %d",
                               &ip_local_port_min, &ip_local_port_max);
                        fclose(f);
                } else {
@@ -508,7 +505,7 @@ const char *__resolve_service(int port)
                if (!notfirst) {
                        setservent(1);
                        notfirst = 1;
-               } 
+               }
                se = getservbyport(htons(port), dg_proto);
                if (se)
                        return se->s_name;
@@ -537,7 +534,7 @@ const char *resolve_service(int port)
                        const char *res;
                        int hash = (port^(((unsigned long)dg_proto)>>2))&255;
 
-                       for (c = &cache[hash]; c; c = c->next) { 
+                       for (c = &cache[hash]; c; c = c->next) {
                                if (c->port == port &&
                                    c->proto == dg_proto) {
                                        if (c->name)
@@ -647,7 +644,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
                        char *p;
                        memcpy(&p, s->local.data, sizeof(p));
                        return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
-                                            strspn(p+1, "0123456789abcdef") == 5); 
+                                            strspn(p+1, "0123456789abcdef") == 5);
                }
                if (s->local.family == AF_PACKET)
                        return s->lport == 0 && s->local.data == 0;
@@ -655,7 +652,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
                        return s->lport < 0;
 
                 if (!low) {
-                       FILE *fp = fdopen(ephemeral_ports_open(), "r");
+                       FILE *fp = ephemeral_ports_open();
                        if (fp) {
                                fscanf(fp, "%d%d", &low, &high);
                                fclose(fp);
@@ -690,7 +687,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
                        do {
                                if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
                                        return 1;
-                       } while ((a = a->next) != NULL); 
+                       } while ((a = a->next) != NULL);
                        return 0;
                }
                return 1;
@@ -728,7 +725,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
        }
 }
 
-/* Relocate external jumps by reloc. */ 
+/* Relocate external jumps by reloc. */
 static void ssfilter_patch(char *a, int len, int reloc)
 {
        while (len > 0) {
@@ -868,7 +865,7 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
 
 static int remember_he(struct aafilter *a, struct hostent *he)
 {
-       char **ptr = he->h_addr_list; 
+       char **ptr = he->h_addr_list;
        int cnt = 0;
        int len;
 
@@ -1103,35 +1100,35 @@ void *parse_hostcond(char *addr)
        return res;
 }
 
-static int tcp_show_line(char *line, struct filter *f, int family)
+static int tcp_show_line(char *line, const struct filter *f, int family)
 {
        struct tcpstat s;
        char *loc, *rem, *data;
        char opt[256];
        int n;
        char *p;
-       
+
        if ((p = strchr(line, ':')) == NULL)
                return -1;
        loc = p+2;
-       
+
        if ((p = strchr(loc, ':')) == NULL)
                return -1;
        p[5] = 0;
        rem = p+6;
-       
+
        if ((p = strchr(rem, ':')) == NULL)
                return -1;
        p[5] = 0;
        data = p+6;
-       
+
        do {
                int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
 
                if (!(f->states & (1<<state)))
                        return 0;
        } while (0);
-       
+
        s.local.family = s.remote.family = family;
        if (family == AF_INET) {
                sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
@@ -1152,37 +1149,37 @@ static int tcp_show_line(char *line, struct filter *f, int family)
                       &s.rport);
                s.local.bytelen = s.remote.bytelen = 16;
        }
-       
+
        if (f->f && run_ssfilter(f->f, &s) == 0)
                return 0;
-       
+
        opt[0] = 0;
-       n = sscanf(data, "%x %x:%x %x:%x %x %d %d %d %d %llx %d %d %d %d %d %[^\n]\n",
+       n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
                   &s.state, &s.wq, &s.rq,
                   &s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
                   &s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
                   &s.cwnd, &s.ssthresh, opt);
-       
+
        if (n < 17)
                opt[0] = 0;
-       
+
        if (n < 12) {
                s.rto = 0;
                s.cwnd = 2;
                s.ssthresh = -1;
                s.ato = s.qack = 0;
        }
-       
+
        if (netid_width)
                printf("%-*s ", netid_width, "tcp");
        if (state_width)
                printf("%-*s ", state_width, sstate_name[s.state]);
-       
+
        printf("%-6d %-6d ", s.rq, s.wq);
-       
+
        formatted_print(&s.local, s.lport);
        formatted_print(&s.remote, s.rport);
-       
+
        if (show_options) {
                if (s.timer) {
                        if (s.timer > 4)
@@ -1194,10 +1191,11 @@ static int tcp_show_line(char *line, struct filter *f, int family)
                }
        }
        if (show_tcpinfo) {
-               if (s.rto && s.rto != 3*get_hz())
-                       printf(" rto:%g", (double)s.rto/get_hz());
+               int hz = get_user_hz();
+               if (s.rto && s.rto != 3*hz)
+                       printf(" rto:%g", (double)s.rto/hz);
                if (s.ato)
-                       printf(" ato:%g", (double)s.ato/get_hz());
+                       printf(" ato:%g", (double)s.ato/hz);
                if (s.cwnd != 2)
                        printf(" cwnd:%d", s.cwnd);
                if (s.ssthresh != -1)
@@ -1215,7 +1213,7 @@ static int tcp_show_line(char *line, struct filter *f, int family)
        if (show_details) {
                if (s.uid)
                        printf(" uid:%u", (unsigned)s.uid);
-               printf(" ino:%u", (unsigned)s.ino);
+               printf(" ino:%u", s.ino);
                printf(" sk:%llx", s.sk);
                if (opt[0])
                        printf(" opt:\"%s\"", opt);
@@ -1225,73 +1223,35 @@ static int tcp_show_line(char *line, struct filter *f, int family)
        return 0;
 }
 
-static int generic_record_read(int fd, char *buf, int bufsize,
-                       int (*worker)(char*, struct filter *, int),
-                       struct filter *f, int fam)
+static int generic_record_read(FILE *fp,
+                              int (*worker)(char*, const struct filter *, int),
+                              const struct filter *f, int fam)
 {
-       int n;
-       int recsize;
-       int eof = 0;
-       char *p;
+       char line[256];
 
-       /* Load the first chunk and calculate record length from it. */
-       n = read(fd, buf, bufsize);
-       if (n < 0)
+       /* skip header */
+       if (fgets(line, sizeof(line), fp) == NULL)
                goto outerr;
-       /* I _know_ that this is wrong, do not remind. :-)
-        * But this works nowadays. */
-       if (n < bufsize)
-               eof = 1;
-       p = memchr(buf, '\n', n);
-       if (p == NULL || (p-buf) >= n)
-               goto outwrongformat;
-       recsize = (p-buf)+1;
-       p = buf+recsize;
-
-       for (;;) {
-               while ((p+recsize) - buf <= n) {
-                       if (p[recsize-1] != '\n')
-                               goto outwrongformat;
-                       p[recsize-1] = 0;
-                       if (worker(p, f, fam) < 0)
-                               goto done;
-                       p += recsize;
-               }
-               if (!eof) {
-                       int remains = (buf+bufsize) - p;
-                       memcpy(buf, p, remains);
-                       p = buf+remains;
-                       n = read(fd, p, (buf+bufsize) - p);
-                       if (n < 0)
-                               goto outerr;
-                       if (n < (buf+bufsize) - p) {
-                               eof = 1;
-                               if (n == 0) {
-                                       if (remains)
-                                               goto outwrongformat;
-                                       goto done;
-                               }
-                       }
-                       n += remains;
-                       p = buf;
-               } else {
-                       if (p != buf+n)
-                               goto outwrongformat;
-                       goto done;
+
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               int n = strlen(line);
+               if (n == 0 || line[n-1] != '\n') {
+                       errno = -EINVAL;
+                       return -1;
                }
-       }
-done:
-       return 0;
+               line[n-1] = 0;
 
-outwrongformat:
-       errno = EINVAL;
+               if (worker(line, f, fam) < 0)
+                       return 0;
+       }
 outerr:
-       return -1;
+
+       return ferror(fp) ? -1 : 0;
 }
-                       
+
 static char *sprint_bw(char *buf, double bw)
 {
-       if (bw > 1000000.) 
+       if (bw > 1000000.)
                sprintf(buf,"%.1fM", bw / 1000000.);
        else if (bw > 1000.)
                sprintf(buf,"%.1fK", bw / 1000.);
@@ -1344,7 +1304,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r)
                if (tb[INET_DIAG_CONG])
                        printf("%s", (char *) RTA_DATA(tb[INET_DIAG_CONG]));
 
-               if (info->tcpi_options & TCPI_OPT_WSCALE) 
+               if (info->tcpi_options & TCPI_OPT_WSCALE)
                        printf(" wscale:%d,%d", info->tcpi_snd_wscale,
                               info->tcpi_rcv_wscale);
                if (info->tcpi_rto && info->tcpi_rto != 3000000)
@@ -1364,7 +1324,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r)
                        const struct tcpvegas_info *vinfo
                                = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
 
-                       if (vinfo->tcpv_enabled && 
+                       if (vinfo->tcpv_enabled &&
                            vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
                                rtt =  vinfo->tcpv_rtt;
                }
@@ -1384,7 +1344,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r)
        }
 }
 
-int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
+static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
 {
        struct inet_diag_msg *r = NLMSG_DATA(nlh);
        struct tcpstat s;
@@ -1432,7 +1392,7 @@ int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
        if (show_details) {
                if (r->idiag_uid)
                        printf(" uid:%u", (unsigned)r->idiag_uid);
-               printf(" ino:%u", (unsigned)r->idiag_inode);
+               printf(" ino:%u", r->idiag_inode);
                printf(" sk:%08x", r->id.idiag_cookie[0]);
                if (r->id.idiag_cookie[1] != 0)
                        printf("%08x", r->id.idiag_cookie[1]);
@@ -1447,7 +1407,7 @@ int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
        return 0;
 }
 
-int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
+static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
 {
        int fd;
        struct sockaddr_nl nladdr;
@@ -1477,7 +1437,7 @@ int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
        req.r.idiag_family = AF_INET;
        req.r.idiag_states = f->states;
        if (show_mem)
-               req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1)); 
+               req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
 
        if (show_tcpinfo) {
                req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
@@ -1485,9 +1445,9 @@ int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
                req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
        }
 
-       iov[0] = (struct iovec){ 
-               .iov_base = &req, 
-               .iov_len = sizeof(req) 
+       iov[0] = (struct iovec){
+               .iov_base = &req,
+               .iov_len = sizeof(req)
        };
        if (f->f) {
                bclen = ssfilter_bytecompile(f->f, &bc);
@@ -1499,18 +1459,18 @@ int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
        }
 
        msg = (struct msghdr) {
-               .msg_name = (void*)&nladdr, 
+               .msg_name = (void*)&nladdr,
                .msg_namelen = sizeof(nladdr),
-               .msg_iov = iov, 
+               .msg_iov = iov,
                .msg_iovlen = f->f ? 3 : 1,
        };
 
        if (sendmsg(fd, &msg, 0) < 0)
                return -1;
 
-       iov[0] = (struct iovec){ 
-               .iov_base = buf, 
-               .iov_len = sizeof(buf) 
+       iov[0] = (struct iovec){
+               .iov_base = buf,
+               .iov_len = sizeof(buf)
        };
 
        while (1) {
@@ -1543,6 +1503,7 @@ int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
                h = (struct nlmsghdr*)buf;
                while (NLMSG_OK(h, status)) {
                        int err;
+                       struct inet_diag_msg *r = NLMSG_DATA(h);
 
                        if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
                            h->nlmsg_seq != 123456)
@@ -1561,6 +1522,10 @@ int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
                                return 0;
                        }
                        if (!dump_fp) {
+                               if (!(f->families & (1<<r->idiag_family))) {
+                                       h = NLMSG_NEXT(h, status);
+                                       continue;
+                               }
                                err = tcp_show_sock(h, NULL);
                                if (err < 0)
                                        return err;
@@ -1581,7 +1546,7 @@ skip_it:
        return 0;
 }
 
-int tcp_show_netlink_file(struct filter *f)
+static int tcp_show_netlink_file(struct filter *f)
 {
        FILE    *fp;
        char    buf[8192];
@@ -1637,9 +1602,9 @@ int tcp_show_netlink_file(struct filter *f)
        }
 }
 
-int tcp_show(struct filter *f, int socktype)
+static int tcp_show(struct filter *f, int socktype)
 {
-       int fd = -1;
+       FILE *fp = NULL;
        char *buf = NULL;
        int bufsize = 64*1024;
 
@@ -1654,6 +1619,7 @@ int tcp_show(struct filter *f, int socktype)
 
        /* Sigh... We have to parse /proc/net/tcp... */
 
+
        /* Estimate amount of sockets and try to allocate
         * huge buffer to read all the table at one read.
         * Limit it by 16MB though. The assumption is: as soon as
@@ -1681,18 +1647,21 @@ int tcp_show(struct filter *f, int socktype)
        }
 
        if (f->families & (1<<AF_INET)) {
-               if ((fd = net_tcp_open()) < 0)
+               if ((fp = net_tcp_open()) == NULL)
                        goto outerr;
-               if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET))
+
+               setbuffer(fp, buf, bufsize);
+               if (generic_record_read(fp, tcp_show_line, f, AF_INET))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
 
        if ((f->families & (1<<AF_INET6)) &&
-           (fd = net_tcp6_open()) >= 0) {
-               if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET6))
+           (fp = net_tcp6_open()) != NULL) {
+               setbuffer(fp, buf, bufsize);
+               if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
 
        free(buf);
@@ -1703,15 +1672,15 @@ outerr:
                int saved_errno = errno;
                if (buf)
                        free(buf);
-               if (fd >= 0)
-                       close(fd);
+               if (fp)
+                       fclose(fp);
                errno = saved_errno;
                return -1;
        } while (0);
 }
 
 
-int dgram_show_line(char *line, struct filter *f, int family)
+int dgram_show_line(char *line, const struct filter *f, int family)
 {
        struct tcpstat s;
        char *loc, *rem, *data;
@@ -1765,7 +1734,7 @@ int dgram_show_line(char *line, struct filter *f, int family)
                return 0;
 
        opt[0] = 0;
-       n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %d %d %llx %[^\n]\n",
+       n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
               &s.state, &s.wq, &s.rq,
               &s.uid, &s.ino,
               &s.refcnt, &s.sk, opt);
@@ -1792,7 +1761,7 @@ int dgram_show_line(char *line, struct filter *f, int family)
        if (show_details) {
                if (s.uid)
                        printf(" uid=%u", (unsigned)s.uid);
-               printf(" ino=%u", (unsigned)s.ino);
+               printf(" ino=%u", s.ino);
                printf(" sk=%llx", s.sk);
                if (opt[0])
                        printf(" opt:\"%s\"", opt);
@@ -1805,33 +1774,31 @@ int dgram_show_line(char *line, struct filter *f, int family)
 
 int udp_show(struct filter *f)
 {
-       int fd = -1;
-       char buf[8192];
-       int  bufsize = sizeof(buf);
+       FILE *fp = NULL;
 
        dg_proto = UDP_PROTO;
 
        if (f->families&(1<<AF_INET)) {
-               if ((fd = net_udp_open()) < 0)
+               if ((fp = net_udp_open()) == NULL)
                        goto outerr;
-               if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+               if (generic_record_read(fp, dgram_show_line, f, AF_INET))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
 
        if ((f->families&(1<<AF_INET6)) &&
-           (fd = net_udp6_open()) >= 0) {
-               if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+           (fp = net_udp6_open()) != NULL) {
+               if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
        return 0;
 
 outerr:
        do {
                int saved_errno = errno;
-               if (fd >= 0)
-                       close(fd);
+               if (fp)
+                       fclose(fp);
                errno = saved_errno;
                return -1;
        } while (0);
@@ -1839,33 +1806,31 @@ outerr:
 
 int raw_show(struct filter *f)
 {
-       int fd = -1;
-       char buf[8192];
-       int  bufsize = sizeof(buf);
+       FILE *fp = NULL;
 
        dg_proto = RAW_PROTO;
 
        if (f->families&(1<<AF_INET)) {
-               if ((fd = net_raw_open()) < 0)
+               if ((fp = net_raw_open()) == NULL)
                        goto outerr;
-               if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+               if (generic_record_read(fp, dgram_show_line, f, AF_INET))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
 
        if ((f->families&(1<<AF_INET6)) &&
-           (fd = net_raw6_open()) >= 0) {
-               if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+           (fp = net_raw6_open()) != NULL) {
+               if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
                        goto outerr;
-               close(fd);
+               fclose(fp);
        }
        return 0;
 
 outerr:
        do {
                int saved_errno = errno;
-               if (fd >= 0)
-                       close(fd);
+               if (fp)
+                       fclose(fp);
                errno = saved_errno;
                return -1;
        } while (0);
@@ -1938,13 +1903,13 @@ void unix_list_print(struct unixstat *list, struct filter *f)
                        if (strcmp(peer, "*") == 0)
                                memset(tst.remote.data, 0, sizeof(peer));
                        else
-                               memcpy(tst.remote.data, &peer, sizeof(peer));  
+                               memcpy(tst.remote.data, &peer, sizeof(peer));
                        if (run_ssfilter(f->f, &tst) == 0)
                                continue;
                }
 
                if (netid_width)
-                       printf("%-*s ", netid_width, 
+                       printf("%-*s ", netid_width,
                               s->type == SOCK_STREAM ? "u_str" : "u_dgr");
                if (state_width)
                        printf("%-*s ", state_width, sstate_name[s->state]);
@@ -1970,11 +1935,11 @@ int unix_show(struct filter *f)
        int  cnt;
        struct unixstat *list = NULL;
 
-       if ((fp = fdopen(net_unix_open(), "r")) == NULL)
+       if ((fp = net_unix_open()) == NULL)
                return -1;
        fgets(buf, sizeof(buf)-1, fp);
 
-       if (memcmp(buf, "Peer", 4) == 0) 
+       if (memcmp(buf, "Peer", 4) == 0)
                newformat = 1;
        cnt = 0;
 
@@ -2058,7 +2023,7 @@ int packet_show(struct filter *f)
        if (!(f->states & (1<<SS_CLOSE)))
                return 0;
 
-       if ((fp = fdopen(net_packet_open(), "r")) == NULL)
+       if ((fp = net_packet_open()) == NULL)
                return -1;
        fgets(buf, sizeof(buf)-1, fp);
 
@@ -2085,7 +2050,7 @@ int packet_show(struct filter *f)
                }
 
                if (netid_width)
-                       printf("%-*s ", netid_width, 
+                       printf("%-*s ", netid_width,
                               type == SOCK_RAW ? "p_raw" : "p_dgr");
                if (state_width)
                        printf("%-*s ", state_width, "UNCONN");
@@ -2094,7 +2059,7 @@ int packet_show(struct filter *f)
                        printf("%*s:", addr_width, "*");
                } else {
                        char tb[16];
-                       printf("%*s:", addr_width, 
+                       printf("%*s:", addr_width,
                               ll_proto_n2a(htons(prot), tb, sizeof(tb)));
                }
                if (iface == 0) {
@@ -2131,7 +2096,7 @@ int netlink_show(struct filter *f)
        if (!(f->states & (1<<SS_CLOSE)))
                return 0;
 
-       if ((fp = fdopen(net_netlink_open(), "r")) == NULL)
+       if ((fp = net_netlink_open()) == NULL)
                return -1;
        fgets(buf, sizeof(buf)-1, fp);
 
@@ -2153,7 +2118,7 @@ int netlink_show(struct filter *f)
                }
 
                if (netid_width)
-                       printf("%-*s ", netid_width, "nl"); 
+                       printf("%-*s ", netid_width, "nl");
                if (state_width)
                        printf("%-*s ", state_width, "UNCONN");
                printf("%-6d %-6d ", rq, wq);
@@ -2179,7 +2144,7 @@ int netlink_show(struct filter *f)
                                        getenv("PROC_ROOT") ? : "/proc", pid);
                                if ((fp = fopen(procname, "r")) != NULL) {
                                        if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
-                                               sprintf(procname+strlen(procname), "/%d", pid);  
+                                               sprintf(procname+strlen(procname), "/%d", pid);
                                                printf("%-*s ", serv_width, procname);
                                                done = 1;
                                        }
@@ -2217,7 +2182,7 @@ int get_snmp_int(char *proto, char *key, int *result)
 
        *result = 0;
 
-       if ((fp = fdopen(net_snmp_open(), "r")) == NULL)
+       if ((fp = net_snmp_open()) == NULL)
                return -1;
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
@@ -2310,13 +2275,13 @@ int get_sockstat(struct sockstat *s)
 
        memset(s, 0, sizeof(*s));
 
-       if ((fp = fdopen(net_sockstat_open(), "r")) == NULL)
+       if ((fp = net_sockstat_open()) == NULL)
                return -1;
        while(fgets(buf, sizeof(buf), fp) != NULL)
                get_sockstat_line(buf, s);
        fclose(fp);
 
-       if ((fp = fdopen(net_sockstat6_open(), "r")) == NULL)
+       if ((fp = net_sockstat6_open()) == NULL)
                return 0;
        while(fgets(buf, sizeof(buf), fp) != NULL)
                get_sockstat_line(buf, s);
@@ -2353,7 +2318,7 @@ int print_summary(void)
        printf("RAW       %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
        printf("UDP       %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
        printf("TCP       %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
-       printf("INET      %-9d %-9d %-9d\n", 
+       printf("INET      %-9d %-9d %-9d\n",
               s.raw4+s.udp4+s.tcp4_hashed+
               s.raw6+s.udp6+s.tcp6_hashed,
               s.raw4+s.udp4+s.tcp4_hashed,
@@ -2459,7 +2424,7 @@ static const struct option long_opts[] = {
        { "version", 0, 0, 'V' },
        { "help", 0, 0, 'h' },
        { 0 }
-       
+
 };
 
 int main(int argc, char *argv[])
@@ -2565,7 +2530,7 @@ int main(int argc, char *argv[])
                        p = p1 = optarg;
                        do {
                                if ((p1 = strchr(p, ',')) != NULL)
-                                       *p1 = 0; 
+                                       *p1 = 0;
                                if (strcmp(p, "all") == 0) {
                                        current_filter.dbs = ALL_DB;
                                } else if (strcmp(p, "inet") == 0) {
@@ -2662,9 +2627,7 @@ int main(int argc, char *argv[])
                int mask2;
                if (preferred_family == AF_INET ||
                    preferred_family == AF_INET6) {
-                       mask2= (1<<TCP_DB);
-                       if (!do_default)
-                               mask2 = (1<<UDP_DB)|(1<<RAW_DB);
+                       mask2= current_filter.dbs;
                } else if (preferred_family == AF_PACKET) {
                        mask2 = PACKET_DBM;
                } else if (preferred_family == AF_UNIX) {
@@ -2788,7 +2751,7 @@ int main(int argc, char *argv[])
        if (addrp_width < 15+serv_width+1)
                addrp_width = 15+serv_width+1;
 
-       addr_width = addrp_width - serv_width - 1; 
+       addr_width = addrp_width - serv_width - 1;
 
        if (netid_width)
                printf("%-*s ", netid_width, "Netid");
@@ -2800,7 +2763,6 @@ int main(int argc, char *argv[])
               addr_width, "Local Address", serv_width, "Port",
               addr_width, "Peer Address", serv_width, "Port");
 
-//printf("%08x %08x %08x\n", current_filter.dbs, current_filter.states, current_filter.families);
        fflush(stdout);
 
        if (current_filter.dbs & (1<<NETLINK_DB))
index 8be5368..2e9d962 100644 (file)
@@ -55,7 +55,7 @@ expr: DCOND HOSTCOND
                $$ = alloc_node(SSF_DCOND, $2);
         }
         | SCOND HOSTCOND
-        { 
+        {
                $$ = alloc_node(SSF_SCOND, $2);
         }
         | DPORT GEQ HOSTCOND
diff --git a/netem/.gitignore b/netem/.gitignore
new file mode 100644 (file)
index 0000000..e36f396
--- /dev/null
@@ -0,0 +1,5 @@
+*.dist
+maketable
+normal
+pareto
+paretonormal
index 59c7e08..b6ccfc6 100644 (file)
@@ -2,6 +2,7 @@ DISTGEN = maketable normal pareto paretonormal
 DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist
 
 HOSTCC ?= $(CC)
+CCOPTS  = $(CBUILD_CFLAGS)
 LDLIBS += -lm 
 
 all: $(DISTGEN) $(DISTDATA)
@@ -15,10 +16,13 @@ $(DISTGEN):
 experimental.dist: maketable experimental.dat
        ./maketable experimental.dat > experimental.dist
 
+stats: stats.c
+       $(HOSTCC) $(CCOPTS) -I../include -o $@ $@.c -lm
+
 install: all
-       mkdir -p $(DESTDIR)/usr/lib/tc
+       mkdir -p $(DESTDIR)/lib/tc
        for i in $(DISTDATA); \
-       do install -m 755 $$i $(DESTDIR)/usr/lib/tc; \
+       do install -m 755 $$i $(DESTDIR)/lib/tc; \
        done
 
 clean:
index ce09176..a5452b6 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Experimental data  distribution table generator
- * Taken from the uncopyrighted NISTnet code.
+ * Taken from the uncopyrighted NISTnet code (public domain).
  *
- * Rread in a series of "random" data values, either
+ * Read in a series of "random" data values, either
  * experimentally or generated from some probability distribution.
  * From this, create the inverse distribution table used to approximate
  * the distribution.
@@ -192,7 +192,7 @@ printtable(const short *table, int limit)
        }
 }
 
-int 
+int
 main(int argc, char **argv)
 {
        FILE *fp;
diff --git a/netem/stats.c b/netem/stats.c
new file mode 100644 (file)
index 0000000..ed70f16
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Experimental data  distribution table generator
+ * Taken from the uncopyrighted NISTnet code (public domain).
+ *
+ * Rread in a series of "random" data values, either
+ * experimentally or generated from some probability distribution.
+ * From this, report statistics.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void
+stats(FILE *fp)
+{
+       struct stat info;
+       double *x;
+       int limit;
+       int n=0, i;
+       double mu=0.0, sigma=0.0, sumsquare=0.0, sum=0.0, top=0.0, rho=0.0;
+       double sigma2=0.0;
+
+       fstat(fileno(fp), &info);
+       if (info.st_size > 0) {
+               limit = 2*info.st_size/sizeof(double);  /* @@ approximate */
+       } else {
+               limit = 10000;
+       }
+       x = (double *)malloc(limit*sizeof(double));
+
+       for (i=0; i<limit; ++i){
+               fscanf(fp, "%lf", &x[i]);
+               if (feof(fp))
+                       break;
+               sumsquare += x[i]*x[i];
+               sum += x[i];
+               ++n;
+       }
+       mu = sum/(double)n;
+       sigma = sqrt((sumsquare - (double)n*mu*mu)/(double)(n-1));
+
+       for (i=1; i < n; ++i){
+               top += ((double)x[i]-mu)*((double)x[i-1]-mu);
+               sigma2 += ((double)x[i-1] - mu)*((double)x[i-1] - mu);
+
+       }
+       rho = top/sigma2;
+
+       printf("mu =    %12.6f\n", mu);
+       printf("sigma = %12.6f\n", sigma);
+       printf("rho =   %12.6f\n", rho);
+       /*printf("sigma2 = %10.4f\n", sqrt(sigma2/(double)(n-1)));*/
+       /*printf("correlation rho = %10.6f\n", top/((double)(n-1)*sigma*sigma));*/
+}
+
+
+int
+main(int argc, char **argv)
+{
+       FILE *fp;
+
+       if (argc > 1) {
+               fp = fopen(argv[1], "r");
+               if (!fp) {
+                       perror(argv[1]);
+                       exit(1);
+               }
+       } else {
+               fp = stdin;
+       }
+       stats(fp);
+       return 0;
+}
diff --git a/svn-commit.2.tmp b/svn-commit.2.tmp
new file mode 100644 (file)
index 0000000..f4071b4
--- /dev/null
@@ -0,0 +1,5 @@
+Trellis branch including EGRE
+
+--This line, and those below, will be ignored--
+
+A    .
diff --git a/svn-commit.3.tmp b/svn-commit.3.tmp
new file mode 100644 (file)
index 0000000..d372c4d
--- /dev/null
@@ -0,0 +1,5 @@
+Checking in new iproute2
+
+--This line, and those below, will be ignored--
+
+A    .
diff --git a/svn-commit.tmp b/svn-commit.tmp
new file mode 100644 (file)
index 0000000..f4071b4
--- /dev/null
@@ -0,0 +1,5 @@
+Trellis branch including EGRE
+
+--This line, and those below, will be ignored--
+
+A    .
diff --git a/tc-cbq-details.8 b/tc-cbq-details.8
deleted file mode 100644 (file)
index e47da62..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-.TH CBQ 8 "8 December 2001" "iproute2" "Linux"
-.SH NAME
-CBQ \- Class Based Queueing
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B  ( parent
-classid 
-.B | root) [ handle 
-major: 
-.B ] cbq avpkt
-bytes
-.B bandwidth
-rate
-.B [ cell 
-bytes
-.B ] [ ewma
-log
-.B ] [ mpu
-bytes
-.B ] 
-
-.B tc class ... dev
-dev
-.B parent 
-major:[minor]
-.B [ classid 
-major:minor
-.B ] cbq allot
-bytes
-.B [ bandwidth 
-rate 
-.B ] [ rate 
-rate
-.B ] prio
-priority
-.B [ weight
-weight
-.B ] [ minburst 
-packets
-.B ] [ maxburst 
-packets 
-.B ] [ ewma 
-log
-.B ] [ cell
-bytes
-.B ] avpkt
-bytes
-.B [ mpu
-bytes 
-.B ] [ bounded isolated ] [ split
-handle
-.B & defmap
-defmap
-.B ] [ estimator 
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-Class Based Queueing is a classful qdisc that implements a rich
-linksharing hierarchy of classes.  It contains shaping elements as
-well as prioritizing capabilities.  Shaping is performed using link
-idle time calculations based on the timing of dequeue events and 
-underlying link bandwidth.
-
-.SH SHAPING ALGORITHM
-Shaping is done using link idle time calculations, and actions taken if
-these calculations deviate from set limits.
-
-When shaping a 10mbit/s connection to 1mbit/s, the link will
-be idle 90% of the time. If it isn't, it needs to be throttled so that it
-IS idle 90% of the time.
-
-From the kernel's perspective, this is hard to measure, so CBQ instead 
-derives the idle time from the number of microseconds (in fact, jiffies) 
-that elapse between  requests from the device driver for more data. Combined 
-with the  knowledge of packet sizes, this is used to approximate how full or 
-empty the link is.
-
-This is rather circumspect and doesn't always arrive at proper
-results. For example, what is the actual link speed of an interface
-that is not really able to transmit the full 100mbit/s of data,
-perhaps because of a badly implemented driver? A PCMCIA network card
-will also never achieve 100mbit/s because of the way the bus is
-designed - again, how do we calculate the idle time?
-
-The physical link bandwidth may be ill defined in case of not-quite-real 
-network devices like PPP over Ethernet or PPTP over TCP/IP. The effective 
-bandwidth in that case is probably determined by the efficiency of pipes 
-to userspace - which not defined.
-
-During operations, the effective idletime is measured using an
-exponential weighted moving average (EWMA), which considers recent
-packets to be exponentially more important than past ones. The Unix
-loadaverage is calculated in the same way.
-
-The calculated idle time is subtracted from the EWMA measured one,
-the resulting number is called 'avgidle'. A perfectly loaded link has
-an avgidle of zero: packets arrive exactly at the calculated
-interval.
-
-An overloaded link has a negative avgidle and if it gets too negative,
-CBQ throttles and is then 'overlimit'.
-
-Conversely, an idle link might amass a huge avgidle, which would then
-allow infinite bandwidths after a few hours of silence. To prevent
-this, avgidle is capped at 
-.B maxidle.
-
-If overlimit, in theory, the CBQ could throttle itself for exactly the
-amount of time that was calculated to pass between packets, and then
-pass one packet, and throttle again. Due to timer resolution constraints,
-this may not be feasible, see the 
-.B minburst
-parameter below.
-
-.SH CLASSIFICATION
-Within the one CBQ instance many classes may exist. Each of these classes
-contains another qdisc, by default 
-.BR tc-pfifo (8).
-
-When enqueueing a packet, CBQ starts at the root and uses various methods to 
-determine which class should receive the data. If a verdict is reached, this
-process is repeated for the recipient class which might have further
-means of classifying traffic to its children, if any.
-
-CBQ has the following methods available to classify a packet to any child 
-classes.
-.TP
-(i)
-.B skb->priority class encoding.
-Can be set from userspace by an application with the 
-.B SO_PRIORITY
-setsockopt.
-The 
-.B skb->priority class encoding
-only applies if the skb->priority holds a major:minor handle of an existing 
-class within  this qdisc.
-.TP
-(ii)
-tc filters attached to the class.
-.TP
-(iii)
-The defmap of a class, as set with the 
-.B split & defmap
-parameters. The defmap may contain instructions for each possible Linux packet
-priority.
-
-.P
-Each class also has a 
-.B level.
-Leaf nodes, attached to the bottom of the class hierarchy, have a level of 0.
-.SH CLASSIFICATION ALGORITHM
-
-Classification is a loop, which terminates when a leaf class is found. At any 
-point the loop may jump to the fallback algorithm.
-
-The loop consists of the following steps:
-.TP 
-(i)
-If the packet is generated locally and has a valid classid encoded within its
-.B skb->priority,
-choose it and terminate.
-
-.TP
-(ii)
-Consult the tc filters, if any, attached to this child. If these return
-a class which is not a leaf class, restart loop from the class returned.
-If it is a leaf, choose it and terminate.
-.TP
-(iii)
-If the tc filters did not return a class, but did return a classid, 
-try to find a class with that id within this qdisc. 
-Check if the found class is of a lower
-.B level
-than the current class. If so, and the returned class is not a leaf node,
-restart the loop at the found class. If it is a leaf node, terminate.
-If we found an upward reference to a higher level, enter the fallback 
-algorithm.
-.TP
-(iv)
-If the tc filters did not return a class, nor a valid reference to one,
-consider the minor number of the reference to be the priority. Retrieve
-a class from the defmap of this class for the priority. If this did not
-contain a class, consult the defmap of this class for the 
-.B BEST_EFFORT
-class. If this is an upward reference, or no 
-.B BEST_EFFORT 
-class was defined,
-enter the fallback algorithm. If a valid class was found, and it is not a
-leaf node, restart the loop at this class. If it is a leaf, choose it and 
-terminate. If
-neither the priority distilled from the classid, nor the 
-.B BEST_EFFORT 
-priority yielded a class, enter the fallback algorithm.
-.P
-The fallback algorithm resides outside of the loop and is as follows.
-.TP
-(i)
-Consult the defmap of the class at which the jump to fallback occured. If 
-the defmap contains a class for the 
-.B
-priority
-of the class (which is related to the TOS field), choose this class and 
-terminate. 
-.TP
-(ii)
-Consult the map for a class for the
-.B BEST_EFFORT
-priority. If found, choose it, and terminate.
-.TP
-(iii)
-Choose the class at which break out to the fallback algorithm occured. Terminate.
-.P
-The packet is enqueued to the class which was chosen when either algorithm 
-terminated. It is therefore possible for a packet to be enqueued *not* at a
-leaf node, but in the middle of the hierarchy.
-
-.SH LINK SHARING ALGORITHM
-When dequeuing for sending to the network device, CBQ decides which of its 
-classes will be allowed to send. It does so with a Weighted Round Robin process
-in which each class with packets gets a chance to send in turn. The WRR process
-starts by asking the highest priority classes (lowest numerically - 
-highest semantically) for packets, and will continue to do so until they
-have no more data to offer, in which case the process repeats for lower 
-priorities.
-
-.B CERTAINTY ENDS HERE, ANK PLEASE HELP
-
-Each class is not allowed to send at length though - they can only dequeue a
-configurable amount of data during each round. 
-
-If a class is about to go overlimit, and it is not
-.B bounded
-it will try to borrow avgidle from siblings that are not
-.B isolated. 
-This process is repeated from the bottom upwards. If a class is unable
-to borrow enough avgidle to send a packet, it is throttled and not asked
-for a packet for enough time for the avgidle to increase above zero.
-
-.B I REALLY NEED HELP FIGURING THIS OUT. REST OF DOCUMENT IS PRETTY CERTAIN
-.B AGAIN.
-
-.SH QDISC
-The root qdisc of a CBQ class tree has the following parameters:
-
-.TP 
-parent major:minor | root
-This mandatory parameter determines the place of the CBQ instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the CBQ can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional.
-.TP
-avpkt bytes
-For calculations, the average packet size must be known. It is silently capped
-at a minimum of 2/3 of the interface MTU. Mandatory.
-.TP
-bandwidth rate
-To determine the idle time, CBQ must know the bandwidth of your underlying 
-physical interface, or parent qdisc. This is a vital parameter, more about it
-later. Mandatory.
-.TP
-cell
-The cell size determines he granularity of packet transmission time calculations. Has a sensible default.
-.TP 
-mpu
-A zero sized packet may still take time to transmit. This value is the lower
-cap for packet transmission time calculations - packets smaller than this value
-are still deemed to have this size. Defaults to zero.
-.TP
-ewma log
-When CBQ needs to measure the average idle time, it does so using an 
-Exponentially Weighted Moving Average which smoothes out measurements into
-a moving average. The EWMA LOG determines how much smoothing occurs. Defaults 
-to 5. Lower values imply greater sensitivity. Must be between 0 and 31.
-.P
-A CBQ qdisc does not shape out of its own accord. It only needs to know certain
-parameters about the underlying link. Actual shaping is done in classes.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP 
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc 
-and not to another class, minor can be omitted. Mandatory.
-.TP 
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this 
-class is going to have children.
-.TP 
-weight weight
-When dequeuing to the interface, classes are tried for traffic in a 
-round-robin fashion. Classes with a higher configured qdisc will generally
-have more traffic to offer during each round, so it makes sense to allow
-it to dequeue more traffic. All weights under a class are normalized, so
-only the ratios matter. Defaults to the configured rate, unless the priority 
-of this class is maximal, in which case it is set to 1.
-.TP 
-allot bytes
-Allot specifies how many bytes a qdisc can dequeue
-during each round of the process. This parameter is weighted using the 
-renormalized class weight described above.
-
-.TP 
-priority priority
-In the round-robin process, classes with the lowest priority field are tried 
-for packets first. Mandatory.
-
-.TP 
-rate rate
-Maximum rate this class and all its children combined can send at. Mandatory.
-
-.TP
-bandwidth rate
-This is different from the bandwidth specified when creating a CBQ disc. Only
-used to determine maxidle and offtime, which are only calculated when
-specifying maxburst or minburst. Mandatory if specifying maxburst or minburst.
-
-.TP 
-maxburst
-This number of packets is used to calculate maxidle so that when
-avgidle is at maxidle, this number of average packets can be burst
-before avgidle drops to 0. Set it higher to be more tolerant of
-bursts. You can't set maxidle directly, only via this parameter.
-
-.TP
-minburst 
-As mentioned before, CBQ needs to throttle in case of
-overlimit. The ideal solution is to do so for exactly the calculated
-idle time, and pass 1 packet. However, Unix kernels generally have a
-hard time scheduling events shorter than 10ms, so it is better to
-throttle for a longer period, and then pass minburst packets in one
-go, and then sleep minburst times longer.
-
-The time to wait is called the offtime. Higher values of minburst lead
-to more accurate shaping in the long term, but to bigger bursts at
-millisecond timescales.
-
-.TP
-minidle
-If avgidle is below 0, we are overlimits and need to wait until
-avgidle will be big enough to send one packet. To prevent a sudden
-burst from shutting down the link for a prolonged period of time,
-avgidle is reset to minidle if it gets too low.
-
-Minidle is specified in negative microseconds, so 10 means that
-avgidle is capped at -10us.
-
-.TP
-bounded 
-Signifies that this class will not borrow bandwidth from its siblings.
-.TP 
-isolated
-Means that this class will not borrow bandwidth to its siblings
-
-.TP 
-split major:minor & defmap bitmap[/bitmap]
-If consulting filters attached to a class did not give a verdict, 
-CBQ can also classify based on the packet's priority. There are 16
-priorities available, numbered from 0 to 15. 
-
-The defmap specifies which priorities this class wants to receive, 
-specified as a bitmap. The Least Significant Bit corresponds to priority 
-zero. The 
-.B split
-parameter tells CBQ at which class the decision must be made, which should
-be a (grand)parent of the class you are adding.
-
-As an example, 'tc class add ... classid 10:1 cbq .. split 10:0 defmap c0'
-configures class 10:0 to send packets with priorities 6 and 7 to 10:1.
-
-The complimentary configuration would then 
-be: 'tc class add ... classid 10:2 cbq ... split 10:0 defmap 3f'
-Which would send all packets 0, 1, 2, 3, 4 and 5 to 10:1.
-.TP
-estimator interval timeconstant
-CBQ can measure how much bandwidth each class is using, which tc filters
-can use to classify packets with. In order to determine the bandwidth
-it uses a very simple estimator that measures once every
-.B interval
-microseconds how much traffic has passed. This again is a EWMA, for which
-the time constant can be specified, also in microseconds. The 
-.B time constant
-corresponds to the sluggishness of the measurement or, conversely, to the 
-sensitivity of the average to short bursts. Higher values mean less
-sensitivity. 
-
-
-
-.SH SOURCES
-.TP
-o
-Sally Floyd and Van Jacobson, "Link-sharing and Resource
-Management Models for Packet Networks",
-IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
-
-.TP 
-o
-Sally Floyd, "Notes on CBQ and Guarantee Service", 1995
-
-.TP
-o
-Sally Floyd, "Notes on Class-Based Queueing: Setting
-Parameters", 1996
-
-.TP 
-o
-Sally Floyd and Michael Speer, "Experimental Results
-for Class-Based Queueing", 1998, not published.
-
-
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-cbq.8 b/tc-cbq.8
deleted file mode 100644 (file)
index 79fb93b..0000000
--- a/tc-cbq.8
+++ /dev/null
@@ -1,353 +0,0 @@
-.TH CBQ 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-CBQ \- Class Based Queueing
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B  ( parent
-classid 
-.B | root) [ handle 
-major: 
-.B ] cbq [ allot 
-bytes
-.B ] avpkt
-bytes
-.B bandwidth
-rate
-.B [ cell 
-bytes
-.B ] [ ewma
-log
-.B ] [ mpu
-bytes
-.B ] 
-
-.B tc class ... dev
-dev
-.B parent 
-major:[minor]
-.B [ classid 
-major:minor
-.B ] cbq allot
-bytes
-.B [ bandwidth 
-rate 
-.B ] [ rate 
-rate
-.B ] prio
-priority
-.B [ weight
-weight
-.B ] [ minburst 
-packets
-.B ] [ maxburst 
-packets 
-.B ] [ ewma 
-log
-.B ] [ cell
-bytes
-.B ] avpkt
-bytes
-.B [ mpu
-bytes 
-.B ] [ bounded isolated ] [ split
-handle
-.B & defmap
-defmap
-.B ] [ estimator 
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-Class Based Queueing is a classful qdisc that implements a rich
-linksharing hierarchy of classes.  It contains shaping elements as
-well as prioritizing capabilities.  Shaping is performed using link
-idle time calculations based on the timing of dequeue events and 
-underlying link bandwidth.
-
-.SH SHAPING ALGORITHM
-When shaping a 10mbit/s connection to 1mbit/s, the link will
-be idle 90% of the time. If it isn't, it needs to be throttled so that it
-IS idle 90% of the time.
-
-During operations, the effective idletime is measured using an
-exponential weighted moving average (EWMA), which considers recent
-packets to be exponentially more important than past ones. The Unix
-loadaverage is calculated in the same way.
-
-The calculated idle time is subtracted from the EWMA measured one,
-the resulting number is called 'avgidle'. A perfectly loaded link has
-an avgidle of zero: packets arrive exactly at the calculated
-interval.
-
-An overloaded link has a negative avgidle and if it gets too negative,
-CBQ throttles and is then 'overlimit'.
-
-Conversely, an idle link might amass a huge avgidle, which would then
-allow infinite bandwidths after a few hours of silence. To prevent
-this, avgidle is capped at 
-.B maxidle.
-
-If overlimit, in theory, the CBQ could throttle itself for exactly the
-amount of time that was calculated to pass between packets, and then
-pass one packet, and throttle again. Due to timer resolution constraints,
-this may not be feasible, see the 
-.B minburst
-parameter below.
-
-.SH CLASSIFICATION
-Within the one CBQ instance many classes may exist. Each of these classes
-contains another qdisc, by default 
-.BR tc-pfifo (8).
-
-When enqueueing a packet, CBQ starts at the root and uses various methods to 
-determine which class should receive the data. 
-
-In the absence of uncommon configuration options, the process is rather easy. 
-At each node we look for an instruction, and then go to the class the 
-instruction refers us to. If the class found is a barren leaf-node (without 
-children), we enqueue the packet there. If it is not yet a leaf node, we do 
-the whole thing over again starting from that node. 
-
-The following actions are performed, in order at each node we visit, until one 
-sends us to another node, or terminates the process.
-.TP
-(i)
-Consult filters attached to the class. If sent to a leafnode, we are done. 
-Otherwise, restart.
-.TP
-(ii)
-Consult the defmap for the priority assigned to this packet, which depends 
-on the TOS bits. Check if the referral is leafless, otherwise restart.
-.TP
-(iii)
-Ask the defmap for instructions for the 'best effort' priority. Check the 
-answer for leafness, otherwise restart.
-.TP
-(iv)
-If none of the above returned with an instruction, enqueue at this node.
-.P
-This algorithm makes sure that a packet always ends up somewhere, even while
-you are busy building your configuration. 
-
-For more details, see
-.BR tc-cbq-details(8).
-
-.SH LINK SHARING ALGORITHM
-When dequeuing for sending to the network device, CBQ decides which of its 
-classes will be allowed to send. It does so with a Weighted Round Robin process
-in which each class with packets gets a chance to send in turn. The WRR process
-starts by asking the highest priority classes (lowest numerically - 
-highest semantically) for packets, and will continue to do so until they
-have no more data to offer, in which case the process repeats for lower 
-priorities.
-
-Classes by default borrow bandwidth from their siblings. A class can be 
-prevented from doing so by declaring it 'bounded'. A class can also indicate 
-its unwillingness to lend out bandwidth by being 'isolated'.
-
-.SH QDISC
-The root of a CBQ qdisc class tree has the following parameters:
-
-.TP 
-parent major:minor | root
-This mandatory parameter determines the place of the CBQ instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the CBQ can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional, but very useful if classes
-will be generated within this qdisc.
-.TP 
-allot bytes
-This allotment is the 'chunkiness' of link sharing and is used for determining packet
-transmission time tables. The qdisc allot differs slightly from the class allot discussed
-below. Optional. Defaults to a reasonable value, related to avpkt.
-.TP
-avpkt bytes
-The average size of a packet is needed for calculating maxidle, and is also used
-for making sure 'allot' has a safe value. Mandatory.
-.TP
-bandwidth rate
-To determine the idle time, CBQ must know the bandwidth of your underlying 
-physical interface, or parent qdisc. This is a vital parameter, more about it
-later. Mandatory.
-.TP
-cell
-The cell size determines he granularity of packet transmission time calculations. Has a sensible default.
-.TP 
-mpu
-A zero sized packet may still take time to transmit. This value is the lower
-cap for packet transmission time calculations - packets smaller than this value
-are still deemed to have this size. Defaults to zero.
-.TP
-ewma log
-When CBQ needs to measure the average idle time, it does so using an 
-Exponentially Weighted Moving Average which smoothes out measurements into
-a moving average. The EWMA LOG determines how much smoothing occurs. Lower 
-values imply greater sensitivity. Must be between 0 and 31. Defaults 
-to 5.
-.P
-A CBQ qdisc does not shape out of its own accord. It only needs to know certain
-parameters about the underlying link. Actual shaping is done in classes.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP 
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc 
-and not to another class, minor can be omitted. Mandatory.
-.TP 
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this 
-class is going to have children.
-.TP 
-weight weight
-When dequeuing to the interface, classes are tried for traffic in a 
-round-robin fashion. Classes with a higher configured qdisc will generally
-have more traffic to offer during each round, so it makes sense to allow
-it to dequeue more traffic. All weights under a class are normalized, so
-only the ratios matter. Defaults to the configured rate, unless the priority 
-of this class is maximal, in which case it is set to 1.
-.TP 
-allot bytes
-Allot specifies how many bytes a qdisc can dequeue
-during each round of the process. This parameter is weighted using the 
-renormalized class weight described above. Silently capped at a minimum of
-3/2 avpkt. Mandatory.
-
-.TP 
-prio priority
-In the round-robin process, classes with the lowest priority field are tried 
-for packets first. Mandatory.
-
-.TP 
-avpkt
-See the QDISC section.
-
-.TP 
-rate rate
-Maximum rate this class and all its children combined can send at. Mandatory.
-
-.TP
-bandwidth rate
-This is different from the bandwidth specified when creating a CBQ disc! Only
-used to determine maxidle and offtime, which are only calculated when
-specifying maxburst or minburst. Mandatory if specifying maxburst or minburst.
-
-.TP 
-maxburst
-This number of packets is used to calculate maxidle so that when
-avgidle is at maxidle, this number of average packets can be burst
-before avgidle drops to 0. Set it higher to be more tolerant of
-bursts. You can't set maxidle directly, only via this parameter.
-
-.TP
-minburst 
-As mentioned before, CBQ needs to throttle in case of
-overlimit. The ideal solution is to do so for exactly the calculated
-idle time, and pass 1 packet. However, Unix kernels generally have a
-hard time scheduling events shorter than 10ms, so it is better to
-throttle for a longer period, and then pass minburst packets in one
-go, and then sleep minburst times longer.
-
-The time to wait is called the offtime. Higher values of minburst lead
-to more accurate shaping in the long term, but to bigger bursts at
-millisecond timescales. Optional.
-
-.TP
-minidle
-If avgidle is below 0, we are overlimits and need to wait until
-avgidle will be big enough to send one packet. To prevent a sudden
-burst from shutting down the link for a prolonged period of time,
-avgidle is reset to minidle if it gets too low.
-
-Minidle is specified in negative microseconds, so 10 means that
-avgidle is capped at -10us. Optional.
-
-.TP
-bounded 
-Signifies that this class will not borrow bandwidth from its siblings.
-.TP 
-isolated
-Means that this class will not borrow bandwidth to its siblings
-
-.TP 
-split major:minor & defmap bitmap[/bitmap]
-If consulting filters attached to a class did not give a verdict, 
-CBQ can also classify based on the packet's priority. There are 16
-priorities available, numbered from 0 to 15. 
-
-The defmap specifies which priorities this class wants to receive, 
-specified as a bitmap. The Least Significant Bit corresponds to priority 
-zero. The 
-.B split
-parameter tells CBQ at which class the decision must be made, which should
-be a (grand)parent of the class you are adding.
-
-As an example, 'tc class add ... classid 10:1 cbq .. split 10:0 defmap c0'
-configures class 10:0 to send packets with priorities 6 and 7 to 10:1.
-
-The complimentary configuration would then 
-be: 'tc class add ... classid 10:2 cbq ... split 10:0 defmap 3f'
-Which would send all packets 0, 1, 2, 3, 4 and 5 to 10:1.
-.TP
-estimator interval timeconstant
-CBQ can measure how much bandwidth each class is using, which tc filters
-can use to classify packets with. In order to determine the bandwidth
-it uses a very simple estimator that measures once every
-.B interval
-microseconds how much traffic has passed. This again is a EWMA, for which
-the time constant can be specified, also in microseconds. The 
-.B time constant
-corresponds to the sluggishness of the measurement or, conversely, to the 
-sensitivity of the average to short bursts. Higher values mean less
-sensitivity. 
-
-.SH BUGS
-The actual bandwidth of the underlying link may not be known, for example 
-in the case of PPoE or PPTP connections which in fact may send over a 
-pipe, instead of over a physical device. CBQ is quite resilient to major
-errors in the configured bandwidth, probably a the cost of coarser shaping.
-
-Default kernels rely on coarse timing information for making decisions. These 
-may make shaping precise in the long term, but inaccurate on second long scales.
-
-See 
-.BR tc-cbq-details(8)
-for hints on how to improve this.
-
-.SH SOURCES
-.TP
-o
-Sally Floyd and Van Jacobson, "Link-sharing and Resource
-Management Models for Packet Networks",
-IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
-
-.TP 
-o
-Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
-
-.TP
-o
-Sally Floyd, "Notes on Class-Based Queueing: Setting
-Parameters", 1996
-
-.TP 
-o
-Sally Floyd and Michael Speer, "Experimental Results
-for Class-Based Queueing", 1998, not published.
-
-
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-htb.8 b/tc-htb.8
deleted file mode 100644 (file)
index f61b818..0000000
--- a/tc-htb.8
+++ /dev/null
@@ -1,150 +0,0 @@
-.TH HTB 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-HTB \- Hierarchy Token Bucket
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B  ( parent
-classid 
-.B | root) [ handle 
-major: 
-.B ] htb [ default 
-minor-id
-.B ] 
-
-.B tc class ... dev
-dev
-.B parent 
-major:[minor]
-.B [ classid 
-major:minor
-.B ] htb rate
-rate
-.B [ ceil
-rate 
-.B ] burst 
-bytes
-.B [ cburst
-bytes
-.B ] [ prio
-priority
-.B ] 
-
-.SH DESCRIPTION
-HTB is meant as a more understandable and intuitive replacement for
-the CBQ qdisc in Linux. Both CBQ and HTB help you to control the use
-of the outbound bandwidth on a given link. Both allow you to use one
-physical link to simulate several slower links and to send different
-kinds of traffic on different simulated links. In both cases, you have
-to specify how to divide the physical link into simulated links and
-how to decide which simulated link to use for a given packet to be sent. 
-
-Unlike CBQ, HTB shapes traffic based on the Token Bucket Filter algorithm 
-which does not depend on interface characteristics and so does not need to
-know the underlying bandwidth of the outgoing interface.
-
-.SH SHAPING ALGORITHM
-Shaping works as documented in
-.B tc-tbf (8).
-
-.SH CLASSIFICATION
-Within the one HRB instance many classes may exist. Each of these classes
-contains another qdisc, by default 
-.BR tc-pfifo (8).
-
-When enqueueing a packet, HTB starts at the root and uses various methods to 
-determine which class should receive the data. 
-
-In the absence of uncommon configuration options, the process is rather easy. 
-At each node we look for an instruction, and then go to the class the 
-instruction refers us to. If the class found is a barren leaf-node (without 
-children), we enqueue the packet there. If it is not yet a leaf node, we do 
-the whole thing over again starting from that node. 
-
-The following actions are performed, in order at each node we visit, until one 
-sends us to another node, or terminates the process.
-.TP
-(i)
-Consult filters attached to the class. If sent to a leafnode, we are done. 
-Otherwise, restart.
-.TP
-(ii)
-If none of the above returned with an instruction, enqueue at this node.
-.P
-This algorithm makes sure that a packet always ends up somewhere, even while
-you are busy building your configuration. 
-
-.SH LINK SHARING ALGORITHM
-FIXME
-
-.SH QDISC
-The root of a HTB qdisc class tree has the following parameters:
-
-.TP 
-parent major:minor | root
-This mandatory parameter determines the place of the HTB instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the HTB can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional, but very useful if classes
-will be generated within this qdisc.
-.TP 
-default minor-id
-Unclassified traffic gets sent to the class with this minor-id.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP 
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc 
-and not to another class, minor can be omitted. Mandatory.
-.TP 
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this 
-class is going to have children.
-.TP 
-prio priority
-In the round-robin process, classes with the lowest priority field are tried 
-for packets first. Mandatory.
-
-.TP 
-rate rate
-Maximum rate this class and all its children are guaranteed. Mandatory.
-
-.TP
-ceil rate
-Maximum rate at which a class can send, if its parent has bandwidth to spare. 
-Defaults to the configured rate, which implies no borrowing
-
-.TP 
-burst bytes
-Amount of bytes that can be burst at 
-.B ceil
-speed, in excess of the configured
-.B rate. 
-Should be at least as high as the highest burst of all children.
-
-.TP 
-cburst bytes
-Amount of bytes that can be burst at 'infinite' speed, in other words, as fast
-as the interface can transmit them. For perfect evening out, should be equal to at most one average
-packet. Should be at least as high as the highest cburst of all children.
-
-.SH NOTES
-Due to Unix timing constraints, the maximum ceil rate is not infinite and may in fact be quite low. On Intel, 
-there are 100 timer events per second, the maximum rate is that rate at which 'burst' bytes are sent each timer tick.
-From this, the mininum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte 
-burst as 100*12kb*8 equals 10mbit.
-
-.SH SEE ALSO
-.BR tc (8)
-.P
-HTB website: http://luxik.cdi.cz/~devik/qos/htb/
-.SH AUTHOR
-Martin Devera <devik@cdi.cz>. This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-pbfifo.8 b/tc-pbfifo.8
deleted file mode 100644 (file)
index 8dda4bb..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-.TH PBFIFO 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-pfifo \- Packet limited First In, First Out queue
-.P
-bfifo \- Byte limited First In, First Out queue
-
-.SH SYNOPSIS
-.B tc qdisc ... add pfifo
-.B [ limit 
-packets
-.B ]
-.P
-.B tc qdisc ... add bfifo
-.B [ limit 
-bytes
-.B ]
-
-.SH DESCRIPTION
-The pfifo and bfifo qdiscs are unadorned First In, First Out queues. They are the
-simplest queues possible and therefore have no overhead. 
-.B pfifo
-constrains the queue size as measured in packets. 
-.B bfifo
-does so as measured in bytes.
-
-Like all non-default qdiscs, they maintain statistics. This might be a reason to prefer 
-pfifo or bfifo over the default.
-
-.SH ALGORITHM
-A list of packets is maintained, when a packet is enqueued it gets inserted at the tail of
-a list. When a packet needs to be sent out to the network, it is taken from the head of the list. 
-
-If the list is too long, no further packets are allowed on. This is called 'tail drop'.
-
-.SH PARAMETERS
-.TP 
-limit
-Maximum queue size. Specified in bytes for bfifo, in packets for pfifo. For pfifo, defaults 
-to the interface txqueuelen, as specified with 
-.BR ifconfig (8)
-or
-.BR ip (8).
-
-For bfifo, it defaults to the txqueuelen multiplied by the interface MTU.
-
-.SH OUTPUT
-The output of 
-.B tc -s qdisc ls
-contains the limit, either in packets or in bytes, and the number of bytes 
-and packets actually sent. An unsent and dropped packet only appears between braces 
-and is not counted as 'Sent'.
-
-In this example, the queue length is 100 packets, 45894 bytes were sent over 681 packets. 
-No packets were dropped, and as the pfifo queue does not slow down packets, there were also no
-overlimits:
-.P
-.nf
-# tc -s qdisc ls dev eth0 
-qdisc pfifo 8001: dev eth0 limit 100p
- Sent 45894 bytes 681 pkts (dropped 0, overlimits 0) 
-.fi
-
-If a backlog occurs, this is displayed as well.
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>
-
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-pfifo_fast.8 b/tc-pfifo_fast.8
deleted file mode 100644 (file)
index 43ab166..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-.TH PFIFO_FAST 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-pfifo_fast \- three-band first in, first out queue
-
-.SH DESCRIPTION
-pfifo_fast is the default qdisc of each interface.
-
-Whenever an interface is created, the pfifo_fast qdisc is automatically used
-as a queue. If another qdisc is attached, it preempts the default
-pfifo_fast, which automatically returns to function when an existing qdisc
-is detached.
-
-In this sense this qdisc is magic, and unlike other qdiscs.
-
-.SH ALGORITHM
-The algorithm is very similar to that of the classful 
-.BR tc-prio (8)
-qdisc. 
-.B pfifo_fast
-is like three
-.BR tc-pfifo (8)
-queues side by side, where packets can be enqueued in any of the three bands
-based on their Type of Service bits or assigned priority. 
-
-Not all three bands are dequeued simultaneously - as long as lower bands
-have traffic, higher bands are never dequeued. This can be used to
-prioritize interactive traffic or penalize 'lowest cost' traffic.
-
-Each band can be txqueuelen packets long, as configured with
-.BR ifconfig (8)
-or 
-.BR ip (8).
-Additional packets coming in are not enqueued but are instead dropped.
-
-See
-.BR tc-prio (8)
-for complete details on how TOS bits are translated into bands.
-.SH PARAMETERS
-.TP 
-txqueuelen
-The length of the three bands depends on the interface txqueuelen, as
-specified with
-.BR ifconfig (8)
-or
-.BR ip (8).
-
-.SH BUGS
-Does not maintain statistics and does not show up in tc qdisc ls. This is because
-it is the automatic default in the absence of a configured qdisc. 
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>
-
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-prio.8 b/tc-prio.8
deleted file mode 100644 (file)
index e942e62..0000000
--- a/tc-prio.8
+++ /dev/null
@@ -1,187 +0,0 @@
-.TH PRIO 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-PRIO \- Priority qdisc
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B  ( parent
-classid 
-.B | root) [ handle 
-major: 
-.B ] prio [ bands 
-bands
-.B ] [ priomap
-band,band,band... 
-.B ] [ estimator 
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-The PRIO qdisc is a simple classful queueing discipline that contains
-an arbitrary number of classes of differing priority. The classes are
-dequeued in numerical descending order of priority. PRIO is a scheduler 
-and never delays packets - it is a work-conserving qdisc, though the qdiscs
-contained in the classes may not be.
-
-Very useful for lowering latency when there is no need for slowing down
-traffic.
-
-.SH ALGORITHM
-On creation with 'tc qdisc add', a fixed number of bands is created. Each
-band is a class, although is not possible to add classes with 'tc qdisc
-add', the number of bands to be created must instead be specified on the
-commandline attaching PRIO to its root.
-
-When dequeueing, band 0 is tried first and only if it did not deliver a
-packet does PRIO try band 1, and so onwards. Maximum reliability packets
-should therefore go to band 0, minimum delay to band 1 and the rest to band
-2.
-
-As the PRIO qdisc itself will have minor number 0, band 0 is actually
-major:1, band 1 is major:2, etc. For major, substitute the major number
-assigned to the qdisc on 'tc qdisc add' with the
-.B handle
-parameter.
-
-.SH CLASSIFICATION
-Three methods are available to PRIO to determine in which band a packet will
-be enqueued.
-.TP
-From userspace
-A process with sufficient privileges can encode the destination class
-directly with SO_PRIORITY, see
-.BR tc(7).
-.TP 
-with a tc filter
-A tc filter attached to the root qdisc can point traffic directly to a class
-.TP 
-with the priomap
-Based on the packet priority, which in turn is derived from the Type of
-Service assigned to the packet.
-.P
-Only the priomap is specific to this qdisc. 
-.SH QDISC PARAMETERS
-.TP
-bands
-Number of bands. If changed from the default of 3,
-.B priomap
-must be updated as well.
-.TP 
-priomap
-The priomap maps the priority of
-a packet to a class. The priority can either be set directly from userspace,
-or be derived from the Type of Service of the packet.
-
-Determines how packet priorities, as assigned by the kernel, map to
-bands. Mapping occurs based on the TOS octet of the packet, which looks like
-this:
-
-.nf
-0   1   2   3   4   5   6   7
-+---+---+---+---+---+---+---+---+
-|           |               |   |
-|PRECEDENCE |      TOS      |MBZ|
-|           |               |   |
-+---+---+---+---+---+---+---+---+
-.fi
-
-The four TOS bits (the 'TOS field') are defined as:
-
-.nf
-Binary Decimcal  Meaning
------------------------------------------
-1000   8         Minimize delay (md)
-0100   4         Maximize throughput (mt)
-0010   2         Maximize reliability (mr)
-0001   1         Minimize monetary cost (mmc)
-0000   0         Normal Service
-.fi
-
-As there is 1 bit to the right of these four bits, the actual value of the
-TOS field is double the value of the TOS bits. Tcpdump -v -v shows you the
-value of the entire TOS field, not just the four bits. It is the value you
-see in the first column of this table:
-
-.nf
-TOS     Bits  Means                    Linux Priority    Band
-------------------------------------------------------------
-0x0     0     Normal Service           0 Best Effort     1
-0x2     1     Minimize Monetary Cost   1 Filler          2
-0x4     2     Maximize Reliability     0 Best Effort     1
-0x6     3     mmc+mr                   0 Best Effort     1
-0x8     4     Maximize Throughput      2 Bulk            2
-0xa     5     mmc+mt                   2 Bulk            2
-0xc     6     mr+mt                    2 Bulk            2
-0xe     7     mmc+mr+mt                2 Bulk            2
-0x10    8     Minimize Delay           6 Interactive     0
-0x12    9     mmc+md                   6 Interactive     0
-0x14    10    mr+md                    6 Interactive     0
-0x16    11    mmc+mr+md                6 Interactive     0
-0x18    12    mt+md                    4 Int. Bulk       1
-0x1a    13    mmc+mt+md                4 Int. Bulk       1
-0x1c    14    mr+mt+md                 4 Int. Bulk       1
-0x1e    15    mmc+mr+mt+md             4 Int. Bulk       1
-.fi
-
-The second column contains the value of the relevant
-four TOS bits, followed by their translated meaning. For example, 15 stands
-for a packet wanting Minimal Montetary Cost, Maximum Reliability, Maximum
-Throughput AND Minimum Delay. 
-
-The fourth column lists the way the Linux kernel interprets the TOS bits, by
-showing to which Priority they are mapped.
-
-The last column shows the result of the default priomap. On the commandline,
-the default priomap looks like this:
-
-    1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
-
-This means that priority 4, for example, gets mapped to band number 1.
-The priomap also allows you to list higher priorities (> 7) which do not
-correspond to TOS mappings, but which are set by other means.
-
-This table from RFC 1349 (read it for more details) explains how
-applications might very well set their TOS bits:
-
-.nf
-TELNET                   1000           (minimize delay)
-FTP
-        Control          1000           (minimize delay)
-        Data             0100           (maximize throughput)
-
-TFTP                     1000           (minimize delay)
-
-SMTP 
-        Command phase    1000           (minimize delay)
-        DATA phase       0100           (maximize throughput)
-
-Domain Name Service
-        UDP Query        1000           (minimize delay)
-        TCP Query        0000
-        Zone Transfer    0100           (maximize throughput)
-
-NNTP                     0001           (minimize monetary cost)
-
-ICMP
-        Errors           0000
-        Requests         0000 (mostly)
-        Responses        <same as request> (mostly)
-.fi
-
-
-.SH CLASSES
-PRIO classes cannot be configured further - they are automatically created
-when the PRIO qdisc is attached. Each class however can contain yet a
-further qdisc.
-
-.SH BUGS
-Large amounts of traffic in the lower bands can cause starvation of higher
-bands. Can be prevented by attaching a shaper (for example, 
-.BR tc-tbf(8)
-to these bands to make sure they cannot dominate the link.
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>,  J Hadi Salim
-<hadi@cyberus.ca>. This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-red.8 b/tc-red.8
deleted file mode 100644 (file)
index d02b411..0000000
--- a/tc-red.8
+++ /dev/null
@@ -1,131 +0,0 @@
-.TH RED 8 "13 December 2001" "iproute2" "Linux"
-.SH NAME
-red \- Random Early Detection 
-.SH SYNOPSIS
-.B tc qdisc ... red
-.B limit 
-bytes
-.B min 
-bytes 
-.B max 
-bytes 
-.B avpkt
-bytes
-.B burst 
-packets
-.B [ ecn ] [ bandwidth
-rate
-.B ] probability
-chance
-
-.SH DESCRIPTION
-Random Early Detection is a classless qdisc which manages its queue size
-smartly. Regular queues simply drop packets from the tail when they are
-full, which may not be the optimal behaviour. RED also performs tail drop,
-but does so in a more gradual way.
-
-Once the queue hits a certain average length, packets enqueued have a
-configurable chance of being marked (which may mean dropped). This chance
-increases linearly up to a point called the
-.B max
-average queue length, although the queue might get bigger.
-
-This has a host of benefits over simple taildrop, while not being processor
-intensive. It prevents synchronous retransmits after a burst in traffic,
-which cause further retransmits, etc.
-
-The goal is the have a small queue size, which is good for interactivity
-while not disturbing TCP/IP traffic with too many sudden drops after a burst
-of traffic.
-
-Depending on if ECN is configured, marking either means dropping or
-purely marking a packet as overlimit.
-.SH ALGORITHM
-The average queue size is used for determining the marking
-probability. This is calculated using an Exponential Weighted Moving
-Average, which can be more or less sensitive to bursts.
-
-When the average queue size is below 
-.B min
-bytes, no packet will ever be marked. When it exceeds 
-.B min, 
-the probability of doing so climbs linearly up
-to 
-.B probability, 
-until the average queue size hits
-.B max
-bytes. Because 
-.B probability 
-is normally not set to 100%, the queue size might
-conceivably rise above 
-.B max
-bytes, so the 
-.B limit
-parameter is provided to set a hard maximum for the size of the queue.
-
-.SH PARAMETERS
-.TP 
-min
-Average queue size at which marking becomes a possibility.
-.TP 
-max
-At this average queue size, the marking probability is maximal. Should be at
-least twice
-.B min
-to prevent synchronous retransmits, higher for low 
-.B min.
-.TP 
-probability
-Maximum probability for marking, specified as a floating point
-number from 0.0 to 1.0. Suggested values are 0.01 or 0.02 (1 or 2%,
-respectively).
-.TP 
-limit
-Hard limit on the real (not average) queue size in bytes. Further packets
-are dropped. Should be set higher than max+burst. It is advised to set this
-a few times higher than 
-.B max.
-.TP
-burst
-Used for determining how fast the average queue size is influenced by the
-real queue size. Larger values make the calculation more sluggish, allowing
-longer bursts of traffic before marking starts. Real life experiments
-support the following guideline: (min+min+max)/(3*avpkt).
-.TP 
-avpkt
-Specified in bytes. Used with burst to determine the time constant for
-average queue size calculations. 1000 is a good value.
-.TP
-bandwidth
-This rate is used for calculating the average queue size after some
-idle time. Should be set to the bandwidth of your interface. Does not mean
-that RED will shape for you! Optional.
-.TP
-ecn
-As mentioned before, RED can either 'mark' or 'drop'. Explicit Congestion
-Notification allows RED to notify remote hosts that their rate exceeds the
-amount of bandwidth available. Non-ECN capable hosts can only be notified by
-dropping a packet.  If this parameter is specified, packets which indicate
-that their hosts honor ECN will only be marked and not dropped, unless the
-queue size hits
-.B limit
-bytes. Needs a tc binary with RED support compiled in. Recommended.
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH SOURCES
-.TP 
-o
-Floyd, S., and Jacobson, V., Random Early Detection gateways for
-Congestion Avoidance. http://www.aciri.org/floyd/papers/red/red.html
-.TP 
-o
-Some changes to the algorithm by Alexey N. Kuznetsov.
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>,  Alexey Makarenko
-<makar@phoenix.kharkov.ua>, J Hadi Salim <hadi@nortelnetworks.com>.  
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-sfq.8 b/tc-sfq.8
deleted file mode 100644 (file)
index 337c795..0000000
--- a/tc-sfq.8
+++ /dev/null
@@ -1,107 +0,0 @@
-.TH TC 8 "8 December 2001" "iproute2" "Linux"
-.SH NAME
-sfq \- Stochastic Fairness Queueing
-.SH SYNOPSIS
-.B tc qdisc ... perturb
-seconds
-.B quantum
-bytes
-
-.SH DESCRIPTION
-
-Stochastic Fairness Queueing is a classless queueing discipline available for
-traffic control with the 
-.BR tc (8)
-command.
-
-SFQ does not shape traffic but only schedules the transmission of packets, based on 'flows'. 
-The goal is to ensure fairness so that each flow is able to send data in turn, thus preventing
-any single flow from drowning out the rest.
-
-This may in fact have some effect in mitigating a Denial of Service attempt.
-
-SFQ is work-conserving and therefore always delivers a packet if it has one available.
-.SH ALGORITHM
-On enqueueing, each packet is assigned to a hash bucket, based on
-.TP
-(i)
-Source address
-.TP
-(ii)
-Destination address
-.TP
-(iii)
-Source port
-.P
-If these are available. SFQ knows about ipv4 and ipv6 and also UDP, TCP and ESP. 
-Packets with other protocols are hashed based on the 32bits representation of their 
-destination and the socket they belong to. A flow corresponds mostly to a TCP/IP 
-connection.
-
-Each of these buckets should represent a unique flow. Because multiple flows may
-get hashed to the same bucket, the hashing algorithm is perturbed at configurable 
-intervals so that the unfairness lasts only for a short while. Perturbation may 
-however cause some inadvertent packet reordering to occur.
-
-When dequeuing, each hashbucket with data is queried in a round robin fashion.
-
-The compile time maximum length of the SFQ is 128 packets, which can be spread over
-at most 128 buckets of 1024 available. In case of overflow, tail-drop is performed
-on the fullest bucket, thus maintaining fairness.
-
-.SH PARAMETERS
-.TP 
-perturb
-Interval in seconds for queue algorithm perturbation. Defaults to 0, which means that 
-no perturbation occurs. Do not set too low for each perturbation may cause some packet
-reordering. Advised value: 10
-.TP 
-quantum
-Amount of bytes a flow is allowed to dequeue during a round of the round robin process.
-Defaults to the MTU of the interface which is also the advised value and the minimum value.
-
-.SH EXAMPLE & USAGE
-
-To attach to device ppp0:
-.P
-# tc qdisc add dev ppp0 root sfq perturb 10
-.P
-Please note that SFQ, like all non-shaping (work-conserving) qdiscs, is only useful 
-if it owns the queue.
-This is the case when the link speed equals the actually available bandwidth. This holds 
-for regular phone modems, ISDN connections and direct non-switched ethernet links. 
-.P
-Most often, cable modems and DSL devices do not fall into this category. The same holds 
-for when connected to a switch  and trying to send data to a congested segment also 
-connected to the switch.
-.P
-In this case, the effective queue does not reside within Linux and is therefore not 
-available for scheduling.
-.P
-Embed SFQ in a classful qdisc to make sure it owns the queue.
-
-.SH SOURCE
-.TP 
-o
-Paul E. McKenney "Stochastic Fairness Queuing",
-IEEE INFOCOMM'90 Proceedings, San Francisco, 1990.
-
-.TP
-o
-Paul E. McKenney "Stochastic Fairness Queuing",
-"Interworking: Research and Experience", v.2, 1991, p.113-131.
-
-.TP 
-o
-See also:
-M. Shreedhar and George Varghese "Efficient Fair
-Queuing using Deficit Round Robin", Proc. SIGCOMM 95.
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc-tbf.8 b/tc-tbf.8
deleted file mode 100644 (file)
index 3abb238..0000000
--- a/tc-tbf.8
+++ /dev/null
@@ -1,138 +0,0 @@
-.TH TC 8 "13 December 2001" "iproute2" "Linux"
-.SH NAME
-tbf \- Token Bucket Filter
-.SH SYNOPSIS
-.B tc qdisc ... tbf rate
-rate
-.B burst
-bytes/cell
-.B ( latency 
-ms 
-.B | limit
-bytes
-.B ) [ mpu 
-bytes
-.B [ peakrate
-rate
-.B mtu
-bytes/cell
-.B ] ]
-.P
-burst is also known as buffer and maxburst. mtu is also known as minburst.
-.SH DESCRIPTION
-
-The Token Bucket Filter is a classless queueing discipline available for
-traffic control with the 
-.BR tc (8)
-command.
-
-TBF is a pure shaper and never schedules traffic. It is non-work-conserving and may throttle
-itself, although packets are available, to ensure that the configured rate is not exceeded. 
-On all platforms except for Alpha,
-it is able to shape up to 1mbit/s of normal traffic with ideal minimal burstiness, 
-sending out  data exactly at the configured rates. 
-
-Much higher rates are possible but at the cost of losing the minimal burstiness. In that
-case, data is on average dequeued at the configured rate but may be sent much faster at millisecond 
-timescales. Because of further queues living in network adaptors, this is often not a problem.
-
-Kernels with a higher 'HZ' can achieve higher rates with perfect burstiness. On Alpha, HZ is ten
-times higher, leading to a 10mbit/s limit to perfection. These calculations hold for packets of on 
-average 1000 bytes.
-
-.SH ALGORITHM
-As the name implies, traffic is filtered based on the expenditure of 
-.B tokens.
-Tokens roughly correspond to bytes, with the additional constraint that each packet consumes
-some tokens, no matter how small it is. This reflects the fact that even a zero-sized packet occupies
-the link for some time.
-
-On creation, the TBF is stocked with tokens which correspond to the amount of traffic that can be burst 
-in one go. Tokens arrive at a steady rate, until the bucket is full.
-
-If no tokens are available, packets are queued, up to a configured limit. The TBF now 
-calculates the token deficit, and throttles until the first packet in the queue can be sent.
-
-If it is not acceptable to burst out packets at maximum speed, a peakrate can be configured 
-to limit the speed at which the bucket empties. This peakrate is implemented as a second TBF
-with a very small bucket, so that it doesn't burst.
-
-To achieve perfection, the second bucket may contain only a single packet, which leads to 
-the earlier mentioned 1mbit/s limit. 
-
-This limit is caused by the fact that the kernel can only throttle for at minimum 1 'jiffy', which depends
-on HZ as 1/HZ. For perfect shaping, only a single packet can get sent per jiffy - for HZ=100, this means 100 
-packets of on average 1000 bytes each, which roughly corresponds to 1mbit/s.
-
-.SH PARAMETERS
-See 
-.BR tc (8)
-for how to specify the units of these values.
-.TP
-limit or latency
-Limit is the number of bytes that can be queued waiting for tokens to become
-available. You can also specify this the other way around by setting the
-latency parameter, which specifies the maximum amount of time a packet can
-sit in the TBF. The latter calculation takes into account the size of the
-bucket, the rate and possibly the peakrate (if set). These two parameters
-are mutually exclusive. 
-.TP
-burst
-Also known as buffer or maxburst.
-Size of the bucket, in bytes. This is the maximum amount of bytes that tokens can be available for instantaneously. 
-In general, larger shaping rates require a larger buffer. For 10mbit/s on Intel, you need at least 10kbyte buffer 
-if you want to reach your configured rate!
-
-If your buffer is too small, packets may be dropped because more tokens arrive per timer tick than fit in your bucket.
-The minimum buffer size can be calculated by dividing the rate by HZ.
-
-Token usage calculations are performed using a table which by default has a resolution of 8 packets. 
-This resolution can be changed by specifying the 
-.B cell
-size with the burst. For example, to specify a 6000 byte buffer with a 16
-byte cell size, set a burst of 6000/16. You will probably never have to set
-this. Must be an integral power of 2.
-.TP
-mpu
-A zero-sized packet does not use zero bandwidth. For ethernet, no packet uses less than 64 bytes. The Minimum Packet Unit 
-determines the minimal token usage (specified in bytes) for a packet. Defaults to zero.
-.TP
-rate
-The speed knob. See remarks above about limits! See 
-.BR tc (8)
-for units.
-.PP
-Furthermore, if a peakrate is desired, the following parameters are available:
-
-.TP
-peakrate
-Maximum depletion rate of the bucket. Limited to 1mbit/s on Intel, 10mbit/s on Alpha. The peakrate does 
-not need to be set, it is only necessary if perfect millisecond timescale shaping is required.
-
-.TP
-mtu/minburst
-Specifies the size of the peakrate bucket. For perfect accuracy, should be set to the MTU of the interface.
-If a peakrate is needed, but some burstiness is acceptable, this size can be raised. A 3000 byte minburst
-allows around 3mbit/s of peakrate, given 1000 byte packets.
-
-Like the regular burstsize you can also specify a 
-.B cell
-size.
-.SH EXAMPLE & USAGE
-
-To attach a TBF with a sustained maximum rate of 0.5mbit/s, a peakrate of 1.0mbit/s,
-a 5kilobyte buffer, with a pre-bucket queue size limit calculated so the TBF causes
-at most 70ms of latency, with perfect peakrate behaviour, issue:
-.P
-# tc qdisc add dev eth0 root tbf rate 0.5mbit \\
-  burst 5kb latency 70ms peakrate 1mbit       \\
-  minburst 1540
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
diff --git a/tc.8 b/tc.8
deleted file mode 100644 (file)
index b9b8039..0000000
--- a/tc.8
+++ /dev/null
@@ -1,348 +0,0 @@
-.TH TC 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-tc \- show / manipulate traffic control settings
-.SH SYNOPSIS
-.B tc qdisc [ add | change | replace | link ] dev 
-DEV 
-.B 
-[ parent 
-qdisc-id 
-.B | root ] 
-.B [ handle 
-qdisc-id ] qdisc
-[ qdisc specific parameters ]
-.P
-
-.B tc class [ add | change | replace ] dev
-DEV
-.B parent 
-qdisc-id 
-.B [ classid 
-class-id ] qdisc
-[ qdisc specific parameters ]
-.P
-
-.B tc filter [ add | change | replace ] dev
-DEV
-.B  [ parent
-qdisc-id
-.B | root ] protocol
-protocol
-.B prio
-priority filtertype
-[ filtertype specific parameters ]
-.B flowid
-flow-id
-
-.B tc [-s | -d ] qdisc show [ dev 
-DEV 
-.B  ]
-.P
-.B tc [-s | -d ] class show dev 
-DEV 
-.P
-.B tc filter show dev 
-DEV 
-
-.SH DESCRIPTION
-.B Tc
-is used to configure Traffic Control in the Linux kernel. Traffic Control consists 
-of the following:
-
-.TP 
-SHAPING
-When traffic is shaped, its rate of transmission is under control. Shaping may 
-be more than lowering the available bandwidth - it is also used to smooth out 
-bursts in traffic for better network behaviour. Shaping occurs on egress.
-
-.TP 
-SCHEDULING
-By scheduling the transmission of packets it is possible to improve interactivity
-for traffic that needs it while still guaranteeing bandwidth to bulk transfers. Reordering
-is also called prioritizing, and happens only on egress.
-
-.TP
-POLICING
-Where shaping deals with transmission of traffic, policing pertains to traffic
-arriving. Policing thus occurs on ingress.
-
-.TP
-DROPPING
-Traffic exceeding a set bandwidth may also be dropped forthwith, both on 
-ingress and on egress.
-
-.P
-Processing of traffic is controlled by three kinds of objects: qdiscs, 
-classes and filters. 
-
-.SH QDISCS
-.B qdisc 
-is short for 'queueing discipline' and it is elementary to 
-understanding traffic control. Whenever the kernel needs to send a 
-packet to an interface, it is 
-.B enqueued
-to the qdisc configured for that interface. Immediately afterwards, the kernel
-tries to get as many packets as possible from the qdisc, for giving them
-to the network adaptor driver.
-
-A simple QDISC is the 'pfifo' one, which does no processing at all and is a pure 
-First In, First Out queue. It does however store traffic when the network interface
-can't handle it momentarily.
-
-.SH CLASSES
-Some qdiscs can contain classes, which contain further qdiscs - traffic may 
-then be enqueued in any of the inner qdiscs, which are within the
-.B classes.
-When the kernel tries to dequeue a packet from such a 
-.B classful qdisc
-it can come from any of the classes. A qdisc may for example prioritize 
-certain kinds of traffic by trying to dequeue from certain classes
-before others.
-
-.SH FILTERS
-A
-.B filter
-is used by a classful qdisc to determine in which class a packet will
-be enqueued. Whenever traffic arrives at a class with subclasses, it needs
-to be classified. Various methods may be employed to do so, one of these
-are the filters. All filters attached to the class are called, until one of 
-them returns with a verdict. If no verdict was made, other criteria may be 
-available. This differs per qdisc.
-
-It is important to notice that filters reside 
-.B within
-qdiscs - they are not masters of what happens.
-
-.SH CLASSLESS QDISCS
-The classless qdiscs are:
-.TP 
-[p|b]fifo
-Simplest usable qdisc, pure First In, First Out behaviour. Limited in 
-packets or in bytes.
-.TP
-pfifo_fast
-Standard qdisc for 'Advanced Router' enabled kernels. Consists of a three-band
-queue which honors Type of Service flags, as well as the priority that may be 
-assigned to a packet.
-.TP
-red
-Random Early Detection simulates physical congestion by randomly dropping
-packets when nearing configured bandwidth allocation. Well suited to very
-large bandwidth applications.
-.TP 
-sfq
-Stochastic Fairness Queueing reorders queued traffic so each 'session'
-gets to send a packet in turn.
-.TP
-tbf
-The Token Bucket Filter is suited for slowing traffic down to a precisely
-configured rate. Scales well to large bandwidths. 
-.SH CONFIGURING CLASSLESS QDISCS
-In the absence of classful qdiscs, classless qdiscs can only be attached at 
-the root of a device. Full syntax:
-.P
-.B tc qdisc add dev 
-DEV 
-.B root 
-QDISC QDISC-PARAMETERS
-
-To remove, issue
-.P
-.B tc qdisc del dev
-DEV
-.B root
-
-The  
-.B pfifo_fast
-qdisc is the automatic default in the absence of a configured qdisc.
-
-.SH CLASSFUL QDISCS
-The classful qdiscs are:
-.TP
-CBQ
-Class Based Queueing implements a rich linksharing hierarchy of classes. 
-It contains shaping elements as well as prioritizing capabilities. Shaping is
-performed using link idle time calculations based on average packet size and
-underlying link bandwidth. The latter may be ill-defined for some interfaces.
-.TP
-HTB
-The Hierarchy Token Bucket implements a rich linksharing hierarchy of 
-classes with an emphasis on conforming to existing practices. HTB facilitates
-guaranteeing bandwidth to classes, while also allowing specification of upper
-limits to inter-class sharing. It contains shaping elements, based on TBF and
-can prioritize classes.        
-.TP 
-PRIO
-The PRIO qdisc is a non-shaping container for a configurable number of 
-classes which are dequeued in order. This allows for easy prioritization 
-of traffic, where lower classes are only able to send if higher ones have 
-no packets available. To facilitate configuration, Type Of Service bits are 
-honored by default.
-.SH THEORY OF OPERATION
-Classes form a tree, where each class has a single parent. 
-A class may have multiple children. Some qdiscs allow for runtime addition
-of classes (CBQ, HTB) while others (PRIO) are created with a static number of 
-children.
-
-Qdiscs which allow dynamic addition of classes can have zero or more 
-subclasses to which traffic may be enqueued. 
-
-Furthermore, each class contains a
-.B leaf qdisc
-which by default has 
-.B pfifo 
-behaviour though another qdisc can be attached in place. This qdisc may again 
-contain classes, but each class can have only one leaf qdisc. 
-
-When a packet enters a classful qdisc it can be 
-.B classified
-to one of the classes within. Three criteria are available, although not all 
-qdiscs will use all three:
-.TP 
-tc filters
-If tc filters are attached to a class, they are consulted first 
-for relevant instructions. Filters can match on all fields of a packet header, 
-as well as on the firewall mark applied by ipchains or iptables. See 
-.BR tc-filters (8).
-.TP
-Type of Service
-Some qdiscs have built in rules for classifying packets based on the TOS field.
-.TP
-skb->priority
-Userspace programs can encode a class-id in the 'skb->priority' field using 
-the SO_PRIORITY option.
-.P
-Each node within the tree can have its own filters but higher level filters
-may also point directly to lower classes.
-
-If classification did not succeed, packets are enqueued to the leaf qdisc 
-attached to that class. Check qdisc specific manpages for details, however.
-
-.SH NAMING
-All qdiscs, classes and filters have IDs, which can either be specified
-or be automatically assigned. 
-
-IDs consist of a major number and a minor number, separated by a colon.
-
-.TP 
-QDISCS
-A qdisc, which potentially can have children, 
-gets assigned a major number, called a 'handle', leaving the minor 
-number namespace available for classes. The handle is expressed as '10:'. 
-It is customary to explicitly assign a handle to qdiscs expected to have 
-children.
-
-.TP 
-CLASSES
-Classes residing under a qdisc share their qdisc major number, but each have
-a separate minor number called a 'classid' that has no relation to their 
-parent classes, only to their parent qdisc. The same naming custom as for 
-qdiscs applies.
-
-.TP 
-FILTERS
-Filters have a three part ID, which is only needed when using a hashed
-filter hierarchy, for which see
-.BR tc-filters (8).
-.SH UNITS
-All parameters accept a floating point number, possibly followed by a unit.
-.P
-Bandwidths or rates can be specified in:
-.TP 
-kbps
-Kilobytes per second
-.TP
-mbps
-Megabytes per second
-.TP
-kbit
-Kilobits per second
-.TP
-mbit
-Megabits per second
-.TP
-bps or a bare number
-Bytes per second
-.P
-Amounts of data can be specified in:
-.TP
-kb or k
-Kilobytes
-.TP
-mb or m
-Megabytes
-.TP
-mbit
-Megabits
-.TP
-kbit
-Kilobits
-.TP
-b or a bare number
-Bytes.
-.P
-Lengths of time can be specified in:
-.TP
-s, sec or secs
-Whole seconds
-.TP
-ms, msec or msecs
-Milliseconds
-.TP
-us, usec, usecs or a bare number
-Microseconds.
-
-.SH TC COMMANDS
-The following commands are available for qdiscs, classes and filter:
-.TP
-add
-Add a qdisc, class or filter to a node. For all entities, a 
-.B parent
-must be passed, either by passing its ID or by attaching directly to the root of a device. 
-When creating a qdisc or a filter, it can be named with the
-.B handle
-parameter. A class is named with the
-.B classid
-parameter.
-
-.TP
-remove
-A qdisc can be removed by specifying its handle, which may also be 'root'. All subclasses and their leaf qdiscs 
-are automatically deleted, as well as any filters attached to them.
-
-.TP
-change
-Some entities can be modified 'in place'. Shares the syntax of 'add', with the exception
-that the handle cannot be changed and neither can the parent. In other words, 
-.B
-change 
-cannot move a node.
-
-.TP
-replace
-Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet
-it is created.
-
-.TP
-link
-Only available for qdiscs and performs a replace where the node 
-must exist already.
-
-
-.SH HISTORY
-.B tc
-was written by Alexey N. Kuznetsov and added in Linux 2.2.
-.SH SEE ALSO
-.BR tc-cbq (8),
-.BR tc-htb (8),
-.BR tc-sfq (8),
-.BR tc-red (8),
-.BR tc-tbf (8),
-.BR tc-pfifo (8),
-.BR tc-bfifo (8),
-.BR tc-pfifo_fast (8),
-.BR tc-filters (8)
-
-.SH AUTHOR
-Manpage maintained by bert hubert (ahu@ds9a.nl)
-
diff --git a/tc/.gitignore b/tc/.gitignore
new file mode 100644 (file)
index 0000000..e8e86c9
--- /dev/null
@@ -0,0 +1,5 @@
+*.yacc.c
+*.lex.c
+*.output
+*.yacc.h
+tc
index 9d618ff..bd9b833 100644 (file)
@@ -1,6 +1,6 @@
 TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
-       m_police.o m_estimator.o m_action.o m_ematch.o \
-       emp_ematch.yacc.o emp_ematch.lex.o
+       tc_monitor.o m_police.o m_estimator.o m_action.o \
+       m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
 
 include ../Config
 
@@ -11,11 +11,15 @@ TCMODULES += q_red.o
 TCMODULES += q_prio.o
 TCMODULES += q_tbf.o
 TCMODULES += q_cbq.o
+TCMODULES += q_rr.o
+TCMODULES += q_multiq.o
+TCMODULES += q_netem.o
 TCMODULES += f_rsvp.o
 TCMODULES += f_u32.o
 TCMODULES += f_route.o
 TCMODULES += f_fw.o
 TCMODULES += f_basic.o
+TCMODULES += f_flow.o
 TCMODULES += q_dsmark.o
 TCMODULES += q_gred.o
 TCMODULES += f_tcindex.o
@@ -25,7 +29,9 @@ TCMODULES += q_htb.o
 TCMODULES += m_gact.o
 TCMODULES += m_mirred.o
 TCMODULES += m_ipt.o
+TCMODULES += m_nat.o
 TCMODULES += m_pedit.o
+TCMODULES += m_skbedit.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
 TCMODULES += p_tcp.o
@@ -41,11 +47,11 @@ TCLIB := tc_core.o
 TCLIB += tc_red.o
 TCLIB += tc_cbq.o
 TCLIB += tc_estimator.o
+TCLIB += tc_stab.o
 
 CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PROB
 
 TCSO :=
-TCSO += q_netem.so
 ifeq ($(TC_CONFIG_ATM),y)
   TCSO += q_atm.so
 endif
@@ -69,10 +75,10 @@ libtc.a: $(TCLIB)
        $(AR) rcs $@ $(TCLIB)
 
 install: all
-       mkdir -p $(DESTDIR)/usr/lib/tc
-       install -m 0755 -s tc $(DESTDIR)$(SBINDIR)
+       mkdir -p $(DESTDIR)$(LIBDIR)/tc
+       install -m 0755 tc $(DESTDIR)$(SBINDIR)
        for i in $(TCSO); \
-       do install -m 755 -s $$i $(DESTDIR)/usr/lib/tc; \
+       do install -m 755 $$i $(DESTDIR)$(LIBDIR)/tc; \
        done
 
 clean:
index c636c53..ce72a42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * em_cmp.c            Simle coparison Ematch
+ * em_cmp.c            Simple comparison Ematch
  *
  *             This program is free software; you can distribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -32,7 +32,7 @@ static void cmp_print_usage(FILE *fd)
            "Usage: cmp(ALIGN at OFFSET [ ATTRS ] { eq | lt | gt } VALUE)\n" \
            "where: ALIGN  := { u8 | u16 | u32 }\n" \
            "       ATTRS  := [ layer LAYER ] [ mask MASK ] [ trans ]\n" \
-           "       LAYER  := { link | header | next-header | 0..%d }\n" \
+           "       LAYER  := { link | network | transport | 0..%d }\n" \
            "\n" \
            "Example: cmp(u16 at 3 layer 2 mask 0xff00 gt 20)\n",
            TCF_LAYER_MAX);
@@ -63,7 +63,7 @@ static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
                align = TCF_EM_ALIGN_U32;
        else
                return PARSE_ERR(args, "cmp: invalid alignment");
-       
+
        for (a = bstr_next(args); a; a = bstr_next(a)) {
                if (!bstrcmp(a, "at")) {
                        if (a->next == NULL)
@@ -111,7 +111,7 @@ static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
                                opnd = TCF_EM_OPND_GT;
                        else if (!bstrcmp(a, "lt"))
                                opnd = TCF_EM_OPND_LT;
-                       
+
                        if (a->next == NULL)
                                return PARSE_ERR(a, "cmp: missing argument");
                        a = bstr_next(a);
index bd1e151..ee6034f 100644 (file)
@@ -34,9 +34,8 @@ static void meta_print_usage(FILE *fd)
            "       META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
            "\n" \
            "Example: meta(nfmark gt 24)\n" \
-           "         meta(indev shift 1 eq \"ppp\"\n" \
+           "         meta(indev shift 1 eq \"ppp\")\n" \
            "         meta(tcindex mask 0xf0 eq 0xf0)\n" \
-           "         meta(dev eq indev)\n" \
            "\n" \
            "For a list of meta identifiers, use meta(list).\n");
 }
@@ -89,6 +88,7 @@ struct meta_entry {
                                "Routing ClassID (cls_route)"),
        __A(RTIIF,              "rt_iif",       "i",
                                "Incoming interface index"),
+       __A(VLAN_TAG,           "vlan",         "i",    "Vlan tag"),
 
        __A(SECTION,            "Sockets", "", ""),
        __A(SK_FAMILY,          "sk_family",    "i",    "Address family"),
@@ -131,7 +131,7 @@ static struct meta_entry * lookup_meta_entry(struct bstr *kind)
                if (!bstrcmp(kind, meta_table[i].kind) &&
                    meta_table[i].id != 0)
                        return &meta_table[i];
-       
+
        return NULL;
 }
 
@@ -142,7 +142,7 @@ static struct meta_entry * lookup_meta_entry_byid(int id)
        for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
                if (meta_table[i].id == id)
                        return &meta_table[i];
-       
+
        return NULL;
 }
 
@@ -171,12 +171,12 @@ static inline int is_compatible(struct tcf_meta_val *what,
 {
        char *p;
        struct meta_entry *entry;
-       
+
        entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
 
        if (entry == NULL)
                return 0;
-       
+
        for (p = entry->mask; p; p++)
                if (map_type(*p) == TCF_META_TYPE(needed->kind))
                        return 1;
@@ -244,7 +244,7 @@ static inline int overwrite_type(struct tcf_meta_val *src,
 {
        return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
 }
-       
+
 
 static inline struct bstr *
 parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
@@ -262,7 +262,7 @@ parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
        }
 
        num = bstrtoul(arg);
-       if (num != LONG_MAX) {
+       if (num != ULONG_MAX) {
                obj->kind = TCF_META_TYPE_INT << 12;
                obj->kind |= TCF_META_ID_VALUE;
                *dst = (unsigned long) num;
@@ -280,7 +280,7 @@ parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
 
        if (left) {
                struct tcf_meta_val *right = obj;
-               
+
                if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
                        goto compatible;
 
@@ -301,7 +301,7 @@ parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
                                right->kind = overwrite_type(right, left);
                        else
                                goto not_compatible;
-               } else 
+               } else
                        goto not_compatible;
        }
 
@@ -318,9 +318,9 @@ compatible:
                                return PARSE_FAILURE;
                        }
                        a = bstr_next(a);
-                       
+
                        shift = bstrtoul(a);
-                       if (shift == LONG_MAX) {
+                       if (shift == ULONG_MAX) {
                                PARSE_ERR(a, "meta: invalid shift, must " \
                                    "be numeric");
                                return PARSE_FAILURE;
@@ -336,9 +336,9 @@ compatible:
                                return PARSE_FAILURE;
                        }
                        a = bstr_next(a);
-                       
+
                        mask = bstrtoul(a);
-                       if (mask == LONG_MAX) {
+                       if (mask == ULONG_MAX) {
                                PARSE_ERR(a, "meta: invalid mask, must be " \
                                    "numeric");
                                return PARSE_FAILURE;
@@ -400,17 +400,14 @@ static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
                return -1;
        else if (a != NULL)
                return PARSE_ERR(a, "meta: unexpected trailer");
-       
+
 
        addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
 
        addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
 
-       if (lvalue)
-               dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
-
-       if (rvalue)
-               dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
+       dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
+       dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
 
        return 0;
 }
index e0ed5ba..242c361 100644 (file)
@@ -32,7 +32,7 @@ static void nbyte_print_usage(FILE *fd)
            "Usage: nbyte(NEEDLE at OFFSET [layer LAYER])\n" \
            "where: NEEDLE := { string | \"c-escape-sequence\" }\n" \
            "       OFFSET := int\n" \
-           "       LAYER  := { link | header | next-header | 0..%d }\n" \
+           "       LAYER  := { link | network | transport | 0..%d }\n" \
            "\n" \
            "Example: nbyte(\"ababa\" at 12 layer 1)\n",
            TCF_LAYER_MAX);
@@ -92,7 +92,7 @@ static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
 
        if (offset_present == 0)
                return PARSE_ERR(a, "nbyte: offset required");
-       
+
        nb.len = needle->len;
        nb.layer = (__u8) layer;
        nb.off = (__u16) offset;
@@ -131,7 +131,7 @@ static int nbyte_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
        for (i = 0; i < nb->len; i++)
                fprintf(fd, "%c", isprint(needle[i]) ? needle[i] : '.');
        fprintf(fd, "\" at %d layer %d", nb->off, nb->layer);
-       
+
        return 0;
 }
 
index b8857f1..402bea0 100644 (file)
@@ -96,7 +96,7 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
                offset = bstrtoul(a);
        } else
                offset = bstrtoul(a);
-               
+
        if (offset == ULONG_MAX)
                return PARSE_ERR(a, "u32: invalid offset");
 
index 09d535d..0184753 100644 (file)
@@ -77,7 +77,7 @@
                                                                return ERROR;
                                                }
                                                strbuf_index = 0;
-                                               
+
                                                BEGIN(str);
                                        }
 
@@ -90,7 +90,7 @@
 
 <str>\\[0-7]{1,3}                      { /* octal escape sequence */
                                                int res;
-                                               
+
                                                sscanf(yytext + 1, "%o", &res);
                                                if (res > 0xFF) {
                                                        fprintf(stderr, "error: octal escape sequence" \
 
 <str>\\x[0-9a-fA-F]{1,2}               {
                                                int res;
-                                               
+
                                                sscanf(yytext + 2, "%x", &res);
-                                               
+
                                                if (res > 0xFF) {
                                                        fprintf(stderr, "error: hexadecimal escape " \
                                                        "sequence out of range\n");
index 264f358..ad41633 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * f_basic.c           Basic Classifier
  *
- *             This program is free software; you can u32istribute it and/or
+ *             This program is free software; you can distribute 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.
@@ -32,6 +32,7 @@ static void explain(void)
        fprintf(stderr, "\n");
        fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
        fprintf(stderr, "       FILTERID := X:Y:Z\n");
+       fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 static int basic_parse_opt(struct filter_util *qu, char *handle,
@@ -52,7 +53,7 @@ static int basic_parse_opt(struct filter_util *qu, char *handle,
                        return -1;
                }
        }
-               
+
        t->tcm_handle = h;
 
        tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
diff --git a/tc/f_flow.c b/tc/f_flow.c
new file mode 100644 (file)
index 0000000..84b45c9
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * f_flow.c            Flow filter
+ *
+ *             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.
+ *
+ * Authors:    Patrick McHardy <kaber@trash.net>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "m_ematch.h"
+
+static void explain(void)
+{
+       fprintf(stderr,
+"Usage: ... flow ...\n"
+"\n"
+" [mapping mode]: map key KEY [ OPS ] ...\n"
+" [hashing mode]: hash keys KEY-LIST ... [ perturb SECS ]\n"
+"\n"
+"                 [ divisor NUM ] [ baseclass ID ] [ match EMATCH_TREE ]\n"
+"                 [ police POLICE_SPEC ] [ action ACTION_SPEC ]\n"
+"\n"
+"KEY-LIST := [ KEY-LIST , ] KEY\n"
+"KEY      := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n"
+"              mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n"
+"              nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n"
+"              vlan-tag ]\n"
+"OPS      := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n"
+"ID       := X:Y\n"
+       );
+}
+
+static const char *flow_keys[FLOW_KEY_MAX+1] = {
+       [FLOW_KEY_SRC]                  = "src",
+       [FLOW_KEY_DST]                  = "dst",
+       [FLOW_KEY_PROTO]                = "proto",
+       [FLOW_KEY_PROTO_SRC]            = "proto-src",
+       [FLOW_KEY_PROTO_DST]            = "proto-dst",
+       [FLOW_KEY_IIF]                  = "iif",
+       [FLOW_KEY_PRIORITY]             = "priority",
+       [FLOW_KEY_MARK]                 = "mark",
+       [FLOW_KEY_NFCT]                 = "nfct",
+       [FLOW_KEY_NFCT_SRC]             = "nfct-src",
+       [FLOW_KEY_NFCT_DST]             = "nfct-dst",
+       [FLOW_KEY_NFCT_PROTO_SRC]       = "nfct-proto-src",
+       [FLOW_KEY_NFCT_PROTO_DST]       = "nfct-proto-dst",
+       [FLOW_KEY_RTCLASSID]            = "rt-classid",
+       [FLOW_KEY_SKUID]                = "sk-uid",
+       [FLOW_KEY_SKGID]                = "sk-gid",
+       [FLOW_KEY_VLAN_TAG]             = "vlan-tag",
+};
+
+static int flow_parse_keys(__u32 *keys, __u32 *nkeys, char *argv)
+{
+       char *s, *sep;
+       unsigned int i;
+
+       *keys = 0;
+       *nkeys = 0;
+       s = argv;
+       while (s != NULL) {
+               sep = strchr(s, ',');
+               if (sep)
+                       *sep = '\0';
+
+               for (i = 0; i <= FLOW_KEY_MAX; i++) {
+                       if (matches(s, flow_keys[i]) == 0) {
+                               *keys |= 1 << i;
+                               (*nkeys)++;
+                               break;
+                       }
+               }
+               if (i > FLOW_KEY_MAX) {
+                       fprintf(stderr, "Unknown flow key \"%s\"\n", s);
+                       return -1;
+               }
+               s = sep ? sep + 1 : NULL;
+       }
+       return 0;
+}
+
+static void transfer_bitop(__u32 *mask, __u32 *xor, __u32 m, __u32 x)
+{
+       *xor = x ^ (*xor & m);
+       *mask &= m;
+}
+
+static int get_addend(__u32 *addend, char *argv, __u32 keys)
+{
+       inet_prefix addr;
+       int sign = 0;
+       __u32 tmp;
+
+       if (*argv == '-') {
+               sign = 1;
+               argv++;
+       }
+
+       if (get_u32(&tmp, argv, 0) == 0)
+               goto out;
+
+       if (keys & (FLOW_KEY_SRC | FLOW_KEY_DST |
+                   FLOW_KEY_NFCT_SRC | FLOW_KEY_NFCT_DST) &&
+           get_addr(&addr, argv, AF_UNSPEC) == 0) {
+               switch (addr.family) {
+               case AF_INET:
+                       tmp = ntohl(addr.data[0]);
+                       goto out;
+               case AF_INET6:
+                       tmp = ntohl(addr.data[3]);
+                       goto out;
+               }
+       }
+
+       return -1;
+out:
+       if (sign)
+               tmp = -tmp;
+       *addend = tmp;
+       return 0;
+}
+
+static int flow_parse_opt(struct filter_util *fu, char *handle,
+                         int argc, char **argv, struct nlmsghdr *n)
+{
+       struct tc_police tp;
+       struct tcmsg *t = NLMSG_DATA(n);
+       struct rtattr *tail;
+       __u32 mask = ~0U, xor = 0;
+       __u32 keys = 0, nkeys = 0;
+       __u32 mode = FLOW_MODE_MAP;
+       __u32 tmp;
+
+       memset(&tp, 0, sizeof(tp));
+
+       if (handle) {
+               if (get_u32(&t->tcm_handle, handle, 0)) {
+                       fprintf(stderr, "Illegal \"handle\"\n");
+                       return -1;
+               }
+       }
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+
+       while (argc > 0) {
+               if (matches(*argv, "map") == 0) {
+                       mode = FLOW_MODE_MAP;
+               } else if (matches(*argv, "hash") == 0) {
+                       mode = FLOW_MODE_HASH;
+               } else if (matches(*argv, "keys") == 0) {
+                       NEXT_ARG();
+                       if (flow_parse_keys(&keys, &nkeys, *argv))
+                               return -1;
+                       addattr32(n, 4096, TCA_FLOW_KEYS, keys);
+               } else if (matches(*argv, "and") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"mask\"\n");
+                               return -1;
+                       }
+                       transfer_bitop(&mask, &xor, tmp, 0);
+               } else if (matches(*argv, "or") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"or\"\n");
+                               return -1;
+                       }
+                       transfer_bitop(&mask, &xor, ~tmp, tmp);
+               } else if (matches(*argv, "xor") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"xor\"\n");
+                               return -1;
+                       }
+                       transfer_bitop(&mask, &xor, ~0, tmp);
+               } else if (matches(*argv, "rshift") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"rshift\"\n");
+                               return -1;
+                       }
+                       addattr32(n, 4096, TCA_FLOW_RSHIFT, tmp);
+               } else if (matches(*argv, "addend") == 0) {
+                       NEXT_ARG();
+                       if (get_addend(&tmp, *argv, keys)) {
+                               fprintf(stderr, "Illegal \"addend\"\n");
+                               return -1;
+                       }
+                       addattr32(n, 4096, TCA_FLOW_ADDEND, tmp);
+               } else if (matches(*argv, "divisor") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"divisor\"\n");
+                               return -1;
+                       }
+                       addattr32(n, 4096, TCA_FLOW_DIVISOR, tmp);
+               } else if (matches(*argv, "baseclass") == 0) {
+                       NEXT_ARG();
+                       if (get_tc_classid(&tmp, *argv) || TC_H_MIN(tmp) == 0) {
+                               fprintf(stderr, "Illegal \"baseclass\"\n");
+                               return -1;
+                       }
+                       addattr32(n, 4096, TCA_FLOW_BASECLASS, tmp);
+               } else if (matches(*argv, "perturb") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&tmp, *argv, 0)) {
+                               fprintf(stderr, "Illegal \"perturb\"\n");
+                               return -1;
+                       }
+                       addattr32(n, 4096, TCA_FLOW_PERTURB, tmp);
+               } else if (matches(*argv, "police") == 0) {
+                       NEXT_ARG();
+                       if (parse_police(&argc, &argv, TCA_FLOW_POLICE, n)) {
+                               fprintf(stderr, "Illegal \"police\"\n");
+                               return -1;
+                       }
+                       continue;
+               } else if (matches(*argv, "action") == 0) {
+                       NEXT_ARG();
+                       if (parse_action(&argc, &argv, TCA_FLOW_ACT, n)) {
+                               fprintf(stderr, "Illegal \"action\"\n");
+                               return -1;
+                       }
+                       continue;
+               } else if (matches(*argv, "match") == 0) {
+                       NEXT_ARG();
+                       if (parse_ematch(&argc, &argv, TCA_FLOW_EMATCHES, n)) {
+                               fprintf(stderr, "Illegal \"ematch\"\n");
+                               return -1;
+                       }
+                       continue;
+               } else if (matches(*argv, "help") == 0) {
+                       explain();
+                       return -1;
+               } else {
+                       fprintf(stderr, "What is \"%s\"?\n", *argv);
+                       explain();
+                       return -1;
+               }
+               argv++, argc--;
+       }
+
+       if (nkeys > 1 && mode != FLOW_MODE_HASH) {
+               fprintf(stderr, "Invalid mode \"map\" for multiple keys\n");
+               return -1;
+       }
+       addattr32(n, 4096, TCA_FLOW_MODE, mode);
+
+       if (mask != ~0 || xor != 0) {
+               addattr32(n, 4096, TCA_FLOW_MASK, mask);
+               addattr32(n, 4096, TCA_FLOW_XOR, xor);
+       }
+
+       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       return 0;
+}
+
+static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt,
+                         __u32 handle)
+{
+       struct rtattr *tb[TCA_FLOW_MAX+1];
+       SPRINT_BUF(b1);
+       unsigned int i;
+       __u32 mask = ~0, val = 0;
+
+       if (opt == NULL)
+               return -EINVAL;
+
+       parse_rtattr_nested(tb, TCA_FLOW_MAX, opt);
+
+       fprintf(f, "handle 0x%x ", handle);
+
+       if (tb[TCA_FLOW_MODE]) {
+               __u32 mode = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MODE]);
+
+               switch (mode) {
+               case FLOW_MODE_MAP:
+                       fprintf(f, "map ");
+                       break;
+               case FLOW_MODE_HASH:
+                       fprintf(f, "hash ");
+                       break;
+               }
+       }
+
+       if (tb[TCA_FLOW_KEYS]) {
+               __u32 keymask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_KEYS]);
+               char *sep = "";
+
+               fprintf(f, "keys ");
+               for (i = 0; i <= FLOW_KEY_MAX; i++) {
+                       if (keymask & (1 << i)) {
+                               fprintf(f, "%s%s", sep, flow_keys[i]);
+                               sep = ",";
+                       }
+               }
+               fprintf(f, " ");
+       }
+
+       if (tb[TCA_FLOW_MASK])
+               mask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MASK]);
+       if (tb[TCA_FLOW_XOR])
+               val = *(__u32 *)RTA_DATA(tb[TCA_FLOW_XOR]);
+
+       if (mask != ~0 || val != 0) {
+               __u32 or = (mask & val) ^ val;
+               __u32 xor = mask & val;
+
+               if (mask != ~0)
+                       fprintf(f, "and 0x%.8x ", mask);
+               if (xor != 0)
+                       fprintf(f, "xor 0x%.8x ", xor);
+               if (or != 0)
+                       fprintf(f, "or 0x%.8x ", or);
+       }
+
+       if (tb[TCA_FLOW_RSHIFT])
+               fprintf(f, "rshift %u ",
+                       *(__u32 *)RTA_DATA(tb[TCA_FLOW_RSHIFT]));
+       if (tb[TCA_FLOW_ADDEND])
+               fprintf(f, "addend 0x%x ",
+                       *(__u32 *)RTA_DATA(tb[TCA_FLOW_ADDEND]));
+
+       if (tb[TCA_FLOW_DIVISOR])
+               fprintf(f, "divisor %u ",
+                       *(__u32 *)RTA_DATA(tb[TCA_FLOW_DIVISOR]));
+       if (tb[TCA_FLOW_BASECLASS])
+               fprintf(f, "baseclass %s ",
+                       sprint_tc_classid(*(__u32 *)RTA_DATA(tb[TCA_FLOW_BASECLASS]), b1));
+
+       if (tb[TCA_FLOW_PERTURB])
+               fprintf(f, "perturb %usec ",
+                       *(__u32 *)RTA_DATA(tb[TCA_FLOW_PERTURB]));
+
+       if (tb[TCA_FLOW_EMATCHES])
+               print_ematch(f, tb[TCA_FLOW_EMATCHES]);
+       if (tb[TCA_FLOW_POLICE])
+               tc_print_police(f, tb[TCA_FLOW_POLICE]);
+       if (tb[TCA_FLOW_ACT]) {
+               fprintf(f, "\n");
+               tc_print_action(f, tb[TCA_FLOW_ACT]);
+       }
+       return 0;
+}
+
+struct filter_util flow_filter_util = {
+       .id             = "flow",
+       .parse_fopt     = flow_parse_opt,
+       .print_fopt     = flow_print_opt,
+};
index 5a56098..b511735 100644 (file)
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -28,6 +28,7 @@ static void explain(void)
        fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ]\n");
        fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
        fprintf(stderr, "       CLASSID := X:Y\n");
+       fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
@@ -40,19 +41,30 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a
 
        memset(&tp, 0, sizeof(tp));
 
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+
        if (handle) {
+               char *slash;
+               __u32 mask = 0;
+               if ((slash = strchr(handle, '/')) != NULL)
+                       *slash = '\0';
                if (get_u32(&t->tcm_handle, handle, 0)) {
                        fprintf(stderr, "Illegal \"handle\"\n");
                        return -1;
                }
+               if (slash) {
+                       if (get_u32(&mask, slash+1, 0)) {
+                               fprintf(stderr, "Illegal \"handle\" mask\n");
+                               return -1;
+                       }
+                       addattr32(n, MAX_MSG, TCA_FW_MASK, mask);
+               }
        }
 
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
-
        while (argc > 0) {
                if (matches(*argv, "classid") == 0 ||
                    matches(*argv, "flowid") == 0) {
@@ -111,8 +123,16 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u
 
        parse_rtattr_nested(tb, TCA_FW_MAX, opt);
 
-       if (handle)
-               fprintf(f, "handle 0x%x ", handle);
+       if (handle || tb[TCA_FW_MASK]) {
+               __u32 mark = 0, mask = 0;
+               if(handle)
+                       mark = handle;
+               if(tb[TCA_FW_MASK] &&
+                   (mask = *(__u32*)RTA_DATA(tb[TCA_FW_MASK])) != 0xFFFFFFFF)
+                       fprintf(f, "handle 0x%x/0x%x ", mark, mask);
+               else
+                       fprintf(f, "handle 0x%x ", handle);
+       }
 
        if (tb[TCA_FW_CLASSID]) {
                SPRINT_BUF(b1);
@@ -125,7 +145,7 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u
                struct rtattr *idev = tb[TCA_FW_INDEV];
                fprintf(f, "input dev %s ",(char *)RTA_DATA(idev));
        }
-       
+
        if (tb[TCA_FW_ACT]) {
                fprintf(f, "\n");
                tc_print_action(f, tb[TCA_FW_ACT]);
index a41b9d5..67dd49c 100644 (file)
@@ -31,6 +31,7 @@ static void explain(void)
        fprintf(stderr, "                [ flowid CLASSID ] [ police POLICE_SPEC ]\n");
        fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
        fprintf(stderr, "       CLASSID := X:Y\n");
+       fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
index 13fcf97..7e1e6d9 100644 (file)
@@ -34,6 +34,7 @@ static void explain(void)
        fprintf(stderr, "                u{8|16|32} NUMBER mask MASK at OFFSET}\n");
        fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
        fprintf(stderr, "       FILTERID := X:Y\n");
+       fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
index 9d527fc..0bb57ce 100644 (file)
 #include <arpa/inet.h>
 #include <string.h>
 #include <linux/if.h>
+#include <linux/if_ether.h>
 
 #include "utils.h"
 #include "tc_util.h"
 
+extern int show_pretty;
+
 static void explain(void)
 {
-       fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
-       fprintf(stderr, "               [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n");
+       fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]"
+               " [ classid CLASSID ]\n");
+       fprintf(stderr, "               [ police POLICE_SPEC ]"
+               " [ offset OFFSET_SPEC ]\n");
        fprintf(stderr, "               [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
        fprintf(stderr, "               [ sample SAMPLE ]\n");
        fprintf(stderr, "or         u32 divisor DIVISOR\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
-       fprintf(stderr, "       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
+       fprintf(stderr, "       SAMPLE := { ip | ip6 | udp | tcp | icmp |"
+               " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
        fprintf(stderr, "       FILTERID := X:Y:Z\n");
+       fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
 }
 
 #define usage() return(-1)
@@ -109,7 +116,8 @@ char * sprint_u32_handle(__u32 handle, char *buf)
        return buf;
 }
 
-static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+                   int off, int offmask)
 {
        int i;
        int hwm = sel->nkeys;
@@ -140,14 +148,16 @@ static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int
        return 0;
 }
 
-static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+                     int off, int offmask)
 {
        key = htonl(key);
        mask = htonl(mask);
        return pack_key(sel, key, mask, off, offmask);
 }
 
-static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+                     int off, int offmask)
 {
        if (key > 0xFFFF || mask > 0xFFFF)
                return -1;
@@ -215,7 +225,8 @@ int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
 }
 
 
-static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+                    int off, int offmask)
 {
        int res = -1;
        int argc = *argc_p;
@@ -246,7 +257,8 @@ static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int of
        return res;
 }
 
-static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+                    int off, int offmask)
 {
        int res = -1;
        int argc = *argc_p;
@@ -276,7 +288,8 @@ static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int of
        return res;
 }
 
-static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+                   int off, int offmask)
 {
        int res = -1;
        int argc = *argc_p;
@@ -310,7 +323,8 @@ static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off
        return res;
 }
 
-static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
+static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+                        int off)
 {
        int res = -1;
        int argc = *argc_p;
@@ -344,7 +358,8 @@ static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, in
        return res;
 }
 
-static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
+static int parse_ip6_addr(int *argc_p, char ***argv_p,
+                         struct tc_u32_sel *sel, int off)
 {
        int res = -1;
        int argc = *argc_p;
@@ -370,12 +385,16 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, i
        plen = addr.bitlen;
        for (i=0; i<plen; i+=32) {
 //             if (((i+31)&~0x1F)<=plen) {
-               if (((i+31))<=plen) {
-                       if ((res = pack_key(sel, addr.data[i/32], 0xFFFFFFFF, off+4*(i/32), offmask)) < 0)
+               if (i + 31 <= plen) {
+                       res = pack_key(sel, addr.data[i/32],
+                                      0xFFFFFFFF, off+4*(i/32), offmask);
+                       if (res < 0)
                                return -1;
-               } else if (i<plen) {
-                       __u32 mask = htonl(0xFFFFFFFF<<(32-(plen-i)));
-                       if ((res = pack_key(sel, addr.data[i/32], mask, off+4*(i/32), offmask)) < 0)
+               } else if (i < plen) {
+                       __u32 mask = htonl(0xFFFFFFFF << (32 - (plen -i )));
+                       res = pack_key(sel, addr.data[i/32],
+                                      mask, off+4*(i/32), offmask);
+                       if (res < 0)
                                return -1;
                }
        }
@@ -473,7 +492,7 @@ done:
        *argv_p = argv;
        return res;
 }
-
+                               
 static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 {
        int res = -1;
@@ -564,6 +583,7 @@ done:
        return res;
 }
 
+
 static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 {
        int res = -1;
@@ -626,7 +646,8 @@ static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
        return res;
 }
 
-static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, struct nlmsghdr *n)
+static int parse_selector(int *argc_p, char ***argv_p,
+                         struct tc_u32_sel *sel, struct nlmsghdr *n)
 {
        int argc = *argc_p;
        char **argv = *argv_p;
@@ -771,7 +792,101 @@ static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
        return 0;
 }
 
-static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
+static void print_ipv4(FILE *f, const struct tc_u32_key *key)
+{
+       char abuf[256];
+
+       switch (key->off) {
+       case 0:
+               switch (ntohl(key->mask)) {
+               case 0x0f000000:
+                       fprintf(f, "\n  match IP ihl %u", ntohl(key->val) >> 24);
+                       return;
+               case 0x00ff0000:
+                       fprintf(f, "\n  match IP dsfield %#x", ntohl(key->val) >> 16);
+                       return;
+               }
+               break;
+       case 8:
+               if (ntohl(key->mask) == 0x00ff0000) {
+                       fprintf(f, "\n  match IP protocol %d", ntohl(key->val) >> 16);
+                       return;
+               }
+               break;
+       case 12:
+       case 16: {
+                       int bits = mask2bits(key->mask);
+                       if (bits >= 0) {
+                               fprintf(f, "\n  %s %s/%d", 
+                                       key->off == 12 ? "match IP src" : "match IP dst",
+                                       inet_ntop(AF_INET, &key->val,
+                                                 abuf, sizeof(abuf)),
+                                       bits);
+                               return;
+                       }
+               }
+               break;
+
+       case 20:
+               switch (ntohl(key->mask)) {
+               case 0x0000ffff:
+                       fprintf(f, "\n  match sport %u",
+                               ntohl(key->val) & 0xffff);
+                       return;
+               case 0xffff0000:
+                       fprintf(f, "\n  match dport %u",
+                               ntohl(key->val) >> 16);
+                       return;
+               case 0xffffffff:
+                       fprintf(f, "\n  match sport %u, match dport %u",
+                               ntohl(key->val) & 0xffff,
+                               ntohl(key->val) >> 16);
+
+                       return;
+               }
+               /* XXX: Default print_raw */
+       }
+}
+
+static void print_raw(FILE *f, const struct tc_u32_key *key)
+{
+       fprintf(f, "\n  match %08x/%08x at %s%d", 
+               (unsigned int)ntohl(key->val),
+               (unsigned int)ntohl(key->mask),
+               key->offmask ? "nexthdr+" : "",
+               key->off);
+}
+
+static const struct {
+       __u16 proto;
+       __u16 pad;
+       void (*pprinter)(FILE *f, const struct tc_u32_key *key);
+} u32_pprinters[] = {
+       {0,        0, print_raw},
+       {ETH_P_IP, 0, print_ipv4},
+};
+
+static void show_keys(FILE *f, const struct tc_u32_key *key)
+{
+       int i = 0;
+
+       if (!show_pretty)
+               goto show_k;
+
+       for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) {
+               if (u32_pprinters[i].proto == ntohs(f_proto)) {
+show_k:
+                       u32_pprinters[i].pprinter(f, key);
+                       return;
+               }
+       }
+
+       i = 0;
+       goto show_k;
+}
+
+static int u32_parse_opt(struct filter_util *qu, char *handle,
+                        int argc, char **argv, struct nlmsghdr *n)
 {
        struct {
                struct tc_u32_sel sel;
@@ -779,7 +894,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
        } sel;
        struct tcmsg *t = NLMSG_DATA(n);
        struct rtattr *tail;
-       int sel_ok = 0;
+       int sel_ok = 0, terminal_ok = 0;
        int sample_ok = 0;
        __u32 htid = 0;
        __u32 order = 0;
@@ -833,7 +948,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
                } else if (matches(*argv, "divisor") == 0) {
                        unsigned divisor;
                        NEXT_ARG();
-                       if (get_unsigned(&divisor, *argv, 0) || 
+                       if (get_unsigned(&divisor, *argv, 0) ||
                            divisor == 0 ||
                            divisor > 0x100 || ((divisor - 1) & divisor)) {
                                fprintf(stderr, "Illegal \"divisor\"\n");
@@ -888,7 +1003,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
                                return -1;
                        }
                        if (sel2.sel.nkeys != 1) {
-                               fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
+                               fprintf(stderr, "\"sample\" must contain"
+                                       " exactly ONE key.\n");
                                return -1;
                        }
                        if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
@@ -924,6 +1040,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
                                fprintf(stderr, "Illegal \"action\"\n");
                                return -1;
                        }
+                       terminal_ok++;
                        continue;
 
                } else if (matches(*argv, "police") == 0) {
@@ -932,6 +1049,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
                                fprintf(stderr, "Illegal \"police\"\n");
                                return -1;
                        }
+                       terminal_ok++;
                        continue;
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
@@ -944,6 +1062,10 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
                argc--; argv++;
        }
 
+       /* We dont necessarily need class/flowids */
+       if (terminal_ok)
+               sel.sel.flags |= TC_U32_TERMINAL;
+       
        if (order) {
                if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
                        fprintf(stderr, "\"order\" contradicts \"handle\"\n");
@@ -955,12 +1077,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
        if (htid)
                addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
        if (sel_ok)
-               addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
+               addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, 
+                         sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
        tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
        return 0;
 }
 
-static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
+static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
+                        __u32 handle)
 {
        struct rtattr *tb[TCA_U32_MAX+1];
        struct tc_u32_sel *sel = NULL;
@@ -990,7 +1114,8 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __
                fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
        } else if (tb[TCA_U32_HASH]) {
                __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
-               fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid));
+               fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
+                       TC_U32_HASH(htid));
        } else {
                fprintf(f, "??? ");
        }
@@ -1004,7 +1129,8 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __
        }
        if (tb[TCA_U32_LINK]) {
                SPRINT_BUF(b1);
-               fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
+               fprintf(f, "link %s ",
+                       sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
        }
 
        if (tb[TCA_U32_PCNT]) {
@@ -1031,17 +1157,12 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __
        }
 
        if (sel) {
-               int i;
-               struct tc_u32_key *key = sel->keys;
                if (sel->nkeys) {
-                       for (i=0; i<sel->nkeys; i++, key++) {
-                               fprintf(f, "\n  match %08x/%08x at %s%d",
-                                       (unsigned int)ntohl(key->val),
-                                       (unsigned int)ntohl(key->mask),
-                                       key->offmask ? "nexthdr+" : "",
-                                       key->off);
+                       int i;
+                       for (i=0; i<sel->nkeys; i++) {
+                               show_keys(f, sel->keys + i);
                                if (show_stats && NULL != pf)
-                                       fprintf(f, " (success %lld ) ",
+                                       fprintf(f, " (success %llu ) ",
                                                (unsigned long long) pf->kcnts[i]);
                        }
                }
@@ -1049,7 +1170,9 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __
                if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
                        fprintf(f, "\n    offset ");
                        if (sel->flags&TC_U32_VAROFFSET)
-                               fprintf(f, "%04x>>%d at %d ", ntohs(sel->offmask), sel->offshift,  sel->offoff);
+                               fprintf(f, "%04x>>%d at %d ",
+                                       ntohs(sel->offmask),
+                                       sel->offshift,  sel->offoff);
                        if (sel->off)
                                fprintf(f, "plus %d ", sel->off);
                }
index 2d2b0ed..9f24022 100644 (file)
@@ -6,8 +6,8 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  * TODO:
  * - parse to be passed a filedescriptor for logging purposes
  *
@@ -37,13 +37,35 @@ int tab_flush = 0;
 
 void act_usage(void)
 {
-       fprintf (stderr, "action usage improper\n");
+       /*XXX: In the near future add a action->print_help to improve
+        * usability
+        * This would mean new tc will not be backward compatible
+        * with any action .so from the old days. But if someone really
+        * does that, they would know how to fix this ..
+        *
+       */
+       fprintf (stderr, "usage: tc actions <ACTSPECOP>*\n");
+       fprintf(stderr,
+               "Where: \tACTSPECOP := ACR | GD | FL\n"
+                       "\tACR := add | change | replace <ACTSPEC>* \n"
+                       "\tGD := get | delete | <ACTISPEC>*\n"
+                       "\tFL := ls | list | flush | <ACTNAMESPEC>\n"
+                       "\tACTNAMESPEC :=  action <ACTNAME>\n"
+                       "\tACTISPEC := <ACTNAMESPEC> <INDEXSPEC>\n"
+                       "\tACTSPEC := action <ACTDETAIL> [INDEXSPEC]\n"
+                       "\tINDEXSPEC := index <32 bit indexvalue>\n"
+                       "\tACTDETAIL := <ACTNAME> <ACTPARAMS>\n"
+                       "\t\tExample ACTNAME is gact, mirred etc\n"
+                       "\t\tEach action has its own parameters (ACTPARAMS)\n"
+                       "\n");
+
+       exit(-1);
 }
 
 static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt)
 {
        if (opt && RTA_PAYLOAD(opt))
-               fprintf(f, "[Unknown action, optlen=%u] ", 
+               fprintf(f, "[Unknown action, optlen=%u] ",
                        (unsigned) RTA_PAYLOAD(opt));
        return 0;
 }
@@ -117,7 +139,7 @@ noexist:
 }
 
 int
-new_cmd(char **argv) 
+new_cmd(char **argv)
 {
        if ((matches(*argv, "change") == 0) ||
                (matches(*argv, "replace") == 0)||
@@ -181,7 +203,7 @@ done0:
                                        goto done;
                        }
 
-                       if (NULL == a) { 
+                       if (NULL == a) {
                                goto bad_val;
                        }
 
@@ -213,7 +235,7 @@ done:
        *argv_p = argv;
        return 0;
 bad_val:
-       /* no need to undo things, returning from here should 
+       /* no need to undo things, returning from here should
         * cause enough pain */
        fprintf(stderr, "parse_action: bad value (%d:%s)!\n",argc,*argv);
        return -1;
@@ -293,7 +315,7 @@ tc_print_action(FILE * f, const struct rtattr *arg)
        return 0;
 }
 
-static int do_print_action(const struct sockaddr_nl *who,
+int print_action(const struct sockaddr_nl *who,
                           struct nlmsghdr *n,
                           void *arg)
 {
@@ -313,13 +335,13 @@ static int do_print_action(const struct sockaddr_nl *who,
 
        if (NULL == tb[TCA_ACT_TAB]) {
                if (n->nlmsg_type != RTM_GETACTION)
-                       fprintf(stderr, "do_print_action: NULL kind\n");
+                       fprintf(stderr, "print_action: NULL kind\n");
                return -1;
-       }     
+       }
 
        if (n->nlmsg_type == RTM_DELACTION) {
                if (n->nlmsg_flags & NLM_F_ROOT) {
-                       fprintf(fp, "Flushed table "); 
+                       fprintf(fp, "Flushed table ");
                        tab_flush = 1;
                } else {
                        fprintf(fp, "deleted action ");
@@ -381,7 +403,7 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
 
                strncpy(k, *argv, sizeof (k) - 1);
                a = get_action_kind(k);
-               if (NULL == a) { 
+               if (NULL == a) {
                        fprintf(stderr, "Error: non existent action: %s\n",k);
                        ret = -1;
                        goto bad_val;
@@ -434,7 +456,7 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
                return 1;
        }
 
-       if (ans && do_print_action(NULL, &req.n, (void*)stdout) < 0) {
+       if (ans && print_action(NULL, &req.n, (void*)stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return 1;
        }
@@ -514,7 +536,7 @@ int tc_act_list_or_flush(int argc, char **argv, int event)
        }
 #endif
        a = get_action_kind(k);
-       if (NULL == a) { 
+       if (NULL == a) {
                fprintf(stderr,"bad action %s\n",k);
                goto bad_val;
        }
@@ -531,15 +553,15 @@ int tc_act_list_or_flush(int argc, char **argv, int event)
 
        msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
 
-       if (event == RTM_GETACTION) { 
+       if (event == RTM_GETACTION) {
                if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) {
                        perror("Cannot send dump request");
                        return 1;
                }
-               ret = rtnl_dump_filter(&rth, do_print_action, stdout, NULL, NULL);
+               ret = rtnl_dump_filter(&rth, print_action, stdout, NULL, NULL);
        }
 
-       if (event == RTM_DELACTION) { 
+       if (event == RTM_DELACTION) {
                req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);
                req.n.nlmsg_type = RTM_DELACTION;
                req.n.nlmsg_flags |= NLM_F_ROOT;
@@ -598,7 +620,7 @@ int do_action(int argc, char **argv)
                }
 
                if (ret < 0) {
-                       fprintf(stderr, "Command \"%s\" is unknown, try \"tc action help\".\n", *argv);
+                       fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv);
                        return -1;
                }
        }
index 44c621b..7f79a06 100644 (file)
@@ -45,7 +45,7 @@ static inline void map_warning(int num, char *kind)
            "Error: Unable to find ematch \"%s\" in %s\n" \
            "Please assign a unique ID to the ematch kind the suggested " \
            "entry is:\n" \
-           "\t%d\t%s\n", 
+           "\t%d\t%s\n",
            kind, EMATCH_MAP, num, kind);
 }
 
@@ -66,7 +66,7 @@ static int lookup_map(__u16 num, char *dst, int len, const char *file)
                        p++;
                if (*p == '#' || *p == '\n' || *p == 0)
                        continue;
-       
+
                if (sscanf(p, "%d %s", &id, namebuf) != 2) {
                        fprintf(stderr, "ematch map %s corrupted at %s\n",
                            file, p);
@@ -104,7 +104,7 @@ static int lookup_map_id(char *kind, int *dst, const char *file)
                        p++;
                if (*p == '#' || *p == '\n' || *p == 0)
                        continue;
-       
+
                if (sscanf(p, "%d %s", &id, namebuf) != 2) {
                        fprintf(stderr, "ematch map %s corrupted at %s\n",
                            file, p);
@@ -168,8 +168,6 @@ static struct ematch_util *get_ematch_kind_num(__u16 kind)
                return NULL;
 
        return get_ematch_kind(name);
-
-       return NULL;
 }
 
 static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
@@ -185,7 +183,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
 
                if (t->inverted)
                        hdr.flags |= TCF_EM_INVERT;
-               
+
                addattr_l(n, MAX_MSG, index++, NULL, 0);
 
                if (t->child) {
@@ -278,7 +276,7 @@ int em_parse_error(int err, struct bstr *args, struct bstr *carg,
                begin_argv++;
                begin_argc--;
        }
-       
+
        fprintf(stderr, "...\n");
 
        if (args) {
@@ -437,7 +435,7 @@ static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
 
                i++;
        }
-       
+
        return 0;
 }
 
@@ -491,3 +489,80 @@ int print_ematch(FILE *fd, const struct rtattr *rta)
 
        return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
 }
+
+struct bstr * bstr_alloc(const char *text)
+{
+       struct bstr *b = calloc(1, sizeof(*b));
+
+       if (b == NULL)
+               return NULL;
+
+       b->data = strdup(text);
+       if (b->data == NULL) {
+               free(b);
+               return NULL;
+       }
+
+       b->len = strlen(text);
+
+       return b;
+}
+
+unsigned long bstrtoul(const struct bstr *b)
+{
+       char *inv = NULL;
+       unsigned long l;
+       char buf[b->len+1];
+
+       memcpy(buf, b->data, b->len);
+       buf[b->len] = '\0';
+
+       l = strtoul(buf, &inv, 0);
+       if (l == ULONG_MAX || inv == buf)
+               return ULONG_MAX;
+
+       return l;
+}
+
+void bstr_print(FILE *fd, const struct bstr *b, int ascii)
+{
+       int i;
+       char *s = b->data;
+
+       if (ascii)
+               for (i = 0; i < b->len; i++)
+                   fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
+       else {
+               for (i = 0; i < b->len; i++)
+                   fprintf(fd, "%02x", s[i]);
+               fprintf(fd, "\"");
+               for (i = 0; i < b->len; i++)
+                   fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
+               fprintf(fd, "\"");
+       }
+}
+
+void print_ematch_tree(const struct ematch *tree)
+{
+       const struct ematch *t;
+
+       for (t = tree; t; t = t->next) {
+               if (t->inverted)
+                       printf("NOT ");
+
+               if (t->child) {
+                       printf("(");
+                       print_ematch_tree(t->child);
+                       printf(")");
+               } else {
+                       struct bstr *b;
+                       for (b = t->args; b; b = b->next)
+                               printf("%s%s", b->data, b->next ? " " : "");
+               }
+
+               if (t->relation == TCF_EM_REL_AND)
+                       printf(" AND ");
+               else if (t->relation == TCF_EM_REL_OR)
+                       printf(" OR ");
+       }
+}
index ed98446..5036e9b 100644 (file)
@@ -18,23 +18,7 @@ struct bstr
        struct bstr     *next;
 };
 
-static inline struct bstr * bstr_alloc(const char *text)
-{
-       struct bstr *b = calloc(1, sizeof(*b));
-
-       if (b == NULL)
-               return NULL;
-
-       b->data = strdup(text);
-       if (b->data == NULL) {
-               free(b);
-               return NULL;
-       }
-
-       b->len = strlen(text);
-
-       return b;
-}
+extern struct bstr * bstr_alloc(const char *text);
 
 static inline struct bstr * bstr_new(char *data, unsigned int len)
 {
@@ -60,45 +44,15 @@ static inline int bstrcmp(struct bstr *b, const char *text)
        return d;
 }
 
-static inline unsigned long bstrtoul(struct bstr *b)
-{
-       char *inv = NULL;
-       unsigned long l;
-       char buf[b->len+1];
-
-       memcpy(buf, b->data, b->len);
-       buf[b->len] = '\0';
-       
-       l = strtol(buf, &inv, 0);
-       if (l == ULONG_MAX || inv == buf)
-               return LONG_MAX;
-
-       return l;
-}
-
-static inline void bstr_print(FILE *fd, struct bstr *b, int ascii)
-{
-       int i;
-       char *s = b->data;
-
-       if (ascii)
-               for (i = 0; i < b->len; i++)
-                   fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
-       else {
-               for (i = 0; i < b->len; i++)
-                   fprintf(fd, "%02x", s[i]);
-               fprintf(fd, "\"");
-               for (i = 0; i < b->len; i++)
-                   fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
-               fprintf(fd, "\"");
-       }
-}
-
 static inline struct bstr *bstr_next(struct bstr *b)
 {
        return b->next;
 }
 
+extern unsigned long bstrtoul(const struct bstr *b);
+extern void bstr_print(FILE *fd, const struct bstr *b, int ascii);
+
+
 struct ematch
 {
        struct bstr     *args;
@@ -123,30 +77,8 @@ static inline struct ematch * new_ematch(struct bstr *args, int inverted)
        return e;
 }
 
-static inline void print_ematch_tree(struct ematch *tree)
-{
-       struct ematch *t;
-
-       for (t = tree; t; t = t->next) {
-               if (t->inverted)
-                       printf("NOT ");
-
-               if (t->child) {
-                       printf("(");
-                       print_ematch_tree(t->child);
-                       printf(")");
-               } else {
-                       struct bstr *b;
-                       for (b = t->args; b; b = b->next)
-                               printf("%s%s", b->data, b->next ? " " : "");
-               }
-
-               if (t->relation == TCF_EM_REL_AND)
-                       printf(" AND ");
-               else if (t->relation == TCF_EM_REL_OR)
-                       printf(" OR ");
-       }
-}
+extern void print_ematch_tree(const struct ematch *tree);
+
 
 struct ematch_util
 {
index 78eda7a..a9e5dbc 100644 (file)
@@ -39,18 +39,18 @@ int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est)
        int argc = *p_argc;
        char **argv = *p_argv;
        unsigned A, time_const;
-       
+
        NEXT_ARG();
        if (est->ewma_log)
                duparg("estimator", *argv);
        if (matches(*argv, "help") == 0)
                est_help();
-       if (get_usecs(&A, *argv))
+       if (get_time(&A, *argv))
                invarg("estimator", "invalid estimator interval");
        NEXT_ARG();
        if (matches(*argv, "help") == 0)
                est_help();
-       if (get_usecs(&time_const, *argv))
+       if (get_time(&time_const, *argv))
                invarg("estimator", "invalid estimator time constant");
        if (tc_setup_estimator(A, time_const, est) < 0) {
                fprintf(stderr, "Error: estimator parameters are out of range.\n");
index 4bb5041..9f07851 100644 (file)
@@ -1,13 +1,13 @@
 /*
- * m_gact.c            generic actions module 
+ * m_gact.c            generic actions module
  *
  *             This program is free software; you can distribute 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.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #include <stdio.h>
@@ -27,7 +27,7 @@
 /* define to turn on probablity stuff */
 
 #ifdef CONFIG_GACT_PROB
-static const char *prob_n2a(int p) 
+static const char *prob_n2a(int p)
 {
        if (p == PGACT_NONE)
                return "none";
@@ -45,22 +45,28 @@ explain(void)
 #ifdef CONFIG_GACT_PROB
        fprintf(stderr, "Usage: ... gact <ACTION> [RAND] [INDEX]\n");
        fprintf(stderr,
-               "Where: ACTION := reclassify | drop | continue | pass "
-                       "RAND := random <RANDTYPE> <ACTION> <VAL>"
-                       "RANDTYPE := netrand | determ"
-                       "VAL : = value not exceeding 10000"
-                       "INDEX := index value used"
+               "Where: \tACTION := reclassify | drop | continue | pass \n"
+                       "\tRAND := random <RANDTYPE> <ACTION> <VAL>\n"
+                       "\tRANDTYPE := netrand | determ\n"
+                       "\tVAL : = value not exceeding 10000\n"
+                       "\tINDEX := index value used\n"
                        "\n");
 #else
        fprintf(stderr, "Usage: ... gact <ACTION> [INDEX]\n");
        fprintf(stderr,
-               "Where: ACTION := reclassify | drop | continue | pass "
-               "INDEX := index value used"
-                       "\n");
+               "Where: \tACTION := reclassify | drop | continue | pass \n"
+               "\tINDEX := index value used\n"
+               "\n");
 #endif
 }
 
-#define usage() return(-1)
+
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
 
 int
 get_act(char ***argv_p)
@@ -157,6 +163,8 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struc
                        }
                        argc--;
                        argv++;
+               } else if (matches(*argv, "help") == 0) {
+                               usage();
                }
        }
 #endif
@@ -171,6 +179,8 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struc
                        argc--;
                        argv++;
                        ok++;
+               } else if (matches(*argv, "help") == 0) {
+                               usage();
                }
        }
 
index ca39555..f5b7b3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * m_ipt.c     iptables based targets 
+ * m_ipt.c     iptables based targets
  *             utilities mostly ripped from iptables <duh, its the linux way>
  *
  *             This program is free software; you can distribute it and/or
@@ -7,17 +7,16 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
- * TODO: bad bad hardcoding IPT_LIB_DIR and PROC_SYS_MODPROBE
- *
-*/
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ */
 
 #include <syslog.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <linux/if.h>
 #include <iptables.h>
+#include <linux/netfilter.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include "utils.h"
 #include "tc_util.h"
 #include <fcntl.h>
 #include <sys/wait.h>
 
-const char *pname = "tc-ipt";
-const char *tname = "mangle";
-const char *pversion = "0.1";
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef IPT_LIB_DIR
-#define IPT_LIB_DIR "/usr/local/lib/iptables"
-#endif
-
-#ifndef PROC_SYS_MODPROBE
-#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
-#endif
+static const char *pname = "tc-ipt";
+static const char *tname = "mangle";
+static const char *pversion = "0.1";
 
 static const char *ipthooks[] = {
        "NF_IP_PRE_ROUTING",
@@ -73,6 +57,7 @@ static struct option *opts = original_opts;
 static unsigned int global_option_offset = 0;
 #define OPTION_OFFSET 256
 
+char *lib_dir;
 
 void
 register_target(struct iptables_target *me)
@@ -84,6 +69,13 @@ register_target(struct iptables_target *me)
 
 }
 
+void
+xtables_register_target(struct iptables_target *me)
+{
+       me->next = t_list;
+       t_list = me;
+}
+
 void
 exit_tryhelp(int status)
 {
@@ -126,7 +118,7 @@ addr_to_dotted(const struct in_addr *addrp)
        return buf;
 }
 
-int string_to_number_ll(const char *s, unsigned long long min, 
+int string_to_number_ll(const char *s, unsigned long long min,
                        unsigned long long max,
                 unsigned long long *ret)
 {
@@ -227,14 +219,13 @@ find_t(char *name)
 }
 
 static struct iptables_target *
-get_target_name(char *name)
+get_target_name(const char *name)
 {
        void *handle;
        char *error;
        char *new_name, *lname;
        struct iptables_target *m;
-
-       char path[sizeof (IPT_LIB_DIR) + sizeof ("/libipt_.so") + strlen(name)];
+       char path[strlen(lib_dir) + sizeof ("/libipt_.so") + strlen(name)];
 
        new_name = malloc(strlen(name) + 1);
        lname = malloc(strlen(name) + 1);
@@ -265,14 +256,28 @@ get_target_name(char *name)
                }
        }
 
-       sprintf(path, IPT_LIB_DIR "/libipt_%s.so", new_name);
+       /* try libxt_xx first */
+       sprintf(path, "%s/libxt_%s.so", lib_dir, new_name);
        handle = dlopen(path, RTLD_LAZY);
        if (!handle) {
-               sprintf(path, IPT_LIB_DIR "/libipt_%s.so", lname);
+               /* try libipt_xx next */
+               sprintf(path, "%s/libipt_%s.so", lib_dir, new_name);
                handle = dlopen(path, RTLD_LAZY);
+
+               if (!handle) {
+                       sprintf(path, "%s/libxt_%s.so", lib_dir , lname);
+                       handle = dlopen(path, RTLD_LAZY);
+               }
+
+               if (!handle) {
+                       sprintf(path, "%s/libipt_%s.so", lib_dir , lname);
+                       handle = dlopen(path, RTLD_LAZY);
+               }
+               /* ok, lets give up .. */
                if (!handle) {
                        fputs(dlerror(), stderr);
                        printf("\n");
+                       free(new_name);
                        return NULL;
                }
        }
@@ -288,12 +293,14 @@ get_target_name(char *name)
                                        fputs(error, stderr);
                                        fprintf(stderr, "\n");
                                        dlclose(handle);
+                                       free(new_name);
                                        return NULL;
                                }
                        }
                }
        }
 
+       free(new_name);
        return m;
 }
 
@@ -341,7 +348,7 @@ static void set_revision(char *name, u_int8_t revision)
        name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
 }
 
-/* 
+/*
  * we may need to check for version mismatch
 */
 int
@@ -372,7 +379,7 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t)
        return -1;
 }
 
-static int parse_ipt(struct action_util *a,int *argc_p, 
+static int parse_ipt(struct action_util *a,int *argc_p,
                     char ***argv_p, int tca_id, struct nlmsghdr *n)
 {
        struct iptables_target *m = NULL;
@@ -389,6 +396,10 @@ static int parse_ipt(struct action_util *a,int *argc_p,
        __u32 hook = 0, index = 0;
        res = 0;
 
+       lib_dir = getenv("IPTABLES_LIB_DIR");
+       if (!lib_dir)
+               lib_dir = IPT_LIB_DIR;
+
        {
                int i;
                for (i = 0; i < rargc; i++) {
@@ -503,9 +514,16 @@ static int parse_ipt(struct action_util *a,int *argc_p,
        argv += optind;
        *argc_p = rargc - iargc;
        *argv_p = argv;
-       
-       optind = 1;
+
+       optind = 0;
        free_opts(opts);
+       /* Clear flags if target will be used again */
+        m->tflags=0;
+        m->used=0;
+       /* Free allocated memory */
+        if (m->t)
+            free(m->t);
+
 
        return 0;
 
@@ -520,6 +538,10 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg)
        if (arg == NULL)
                return -1;
 
+       lib_dir = getenv("IPTABLES_LIB_DIR");
+       if (!lib_dir)
+               lib_dir = IPT_LIB_DIR;
+
        parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
 
        if (tb[TCA_IPT_TABLE] == NULL) {
@@ -578,7 +600,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg)
                                struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
                                print_tm(f,tm);
                        }
-               } 
+               }
                fprintf(f, " \n");
 
        }
index cbfea84..226df4d 100644 (file)
@@ -1,13 +1,13 @@
 /*
- * m_egress.c          ingress/egress packet mirror/redir actions module 
+ * m_egress.c          ingress/egress packet mirror/redir actions module
  *
  *             This program is free software; you can distribute 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.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  * TODO: Add Ingress support
  *
  */
@@ -33,13 +33,19 @@ explain(void)
 {
        fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> \n");
        fprintf(stderr, "where: \n");
-       fprintf(stderr, "DIRECTION := <ingress | egress>\n");
-       fprintf(stderr, "aCTION := <mirror | redirect>\n");
-       fprintf(stderr, "     : INDEX  is the specific policy instance id\n");
-       fprintf(stderr, "     : DEVICENAME is the devicename \n");
+       fprintf(stderr, "\tDIRECTION := <ingress | egress>\n");
+       fprintf(stderr, "\tACTION := <mirror | redirect>\n");
+       fprintf(stderr, "\tINDEX  is the specific policy instance id\n");
+       fprintf(stderr, "\tDEVICENAME is the devicename \n");
+
 }
 
-#define usage() return(-1)
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
 
 char *mirred_n2a(int action)
 {
@@ -133,7 +139,6 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, str
        }
 
        if (!ok && !iok) {
-               explain();
                return -1;
        }
 
@@ -235,13 +240,14 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, str
 
        } else if (matches(*argv, "ingress") == 0) {
                fprintf(stderr,"mirred ingress not supported at the moment\n");
-
+       } else if (matches(*argv, "help") == 0) {
+               usage();
        } else {
-               fprintf(stderr,"mirred not supported %s\n", *argv);
+               fprintf(stderr,"mirred option not supported %s\n", *argv);
        }
 
        return -1;
-       
+
 }
 
 int
diff --git a/tc/m_nat.c b/tc/m_nat.c
new file mode 100644 (file)
index 0000000..6e7fd05
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * m_nat.c             NAT module
+ *
+ *             This program is free software; you can distribute 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.
+ *
+ * Authors:    Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_nat.h>
+
+static void
+explain(void)
+{
+       fprintf(stderr, "Usage: ... nat NAT\n"
+                       "NAT := DIRECTION OLD NEW\n"
+                       "DIRECTION := { ingress | egress }\n"
+                       "OLD := PREFIX\n"
+                       "NEW := ADDRESS\n");
+}
+
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
+
+static int
+parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel)
+{
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       inet_prefix addr;
+
+       if (argc <= 0)
+               return -1;
+
+       if (matches(*argv, "egress") == 0)
+               sel->flags |= TCA_NAT_FLAG_EGRESS;
+       else if (matches(*argv, "ingress") != 0)
+               goto bad_val;
+
+       NEXT_ARG();
+
+       if (get_prefix_1(&addr, *argv, AF_INET))
+               goto bad_val;
+
+       sel->old_addr = addr.data[0];
+       sel->mask = htonl(~0u << (32 - addr.bitlen));
+
+       NEXT_ARG();
+
+       if (get_prefix_1(&addr, *argv, AF_INET))
+               goto bad_val;
+
+       sel->new_addr = addr.data[0];
+
+       argc--;
+       argv++;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+
+bad_val:
+       return -1;
+}
+
+static int
+parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
+{
+       struct tc_nat sel;
+
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       int ok = 0;
+       struct rtattr *tail;
+
+       memset(&sel, 0, sizeof(sel));
+
+       while (argc > 0) {
+               if (matches(*argv, "nat") == 0) {
+                       NEXT_ARG();
+                       if (parse_nat_args(&argc, &argv, &sel)) {
+                               fprintf(stderr, "Illegal nat construct (%s) \n",
+                                       *argv);
+                               explain();
+                               return -1;
+                       }
+                       ok++;
+                       continue;
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
+               } else {
+                       break;
+               }
+
+       }
+
+       if (!ok) {
+               explain();
+               return -1;
+       }
+
+       if (argc) {
+               if (matches(*argv, "reclassify") == 0) {
+                       sel.action = TC_ACT_RECLASSIFY;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "pipe") == 0) {
+                       sel.action = TC_ACT_PIPE;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "drop") == 0 ||
+                       matches(*argv, "shot") == 0) {
+                       sel.action = TC_ACT_SHOT;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "continue") == 0) {
+                       sel.action = TC_ACT_UNSPEC;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "pass") == 0) {
+                       sel.action = TC_ACT_OK;
+                       argc--;
+                       argv++;
+               }
+       }
+
+       if (argc) {
+               if (matches(*argv, "index") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&sel.index, *argv, 10)) {
+                               fprintf(stderr, "Pedit: Illegal \"index\"\n");
+                               return -1;
+                       }
+                       argc--;
+                       argv++;
+               }
+       }
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
+       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+static int
+print_nat(struct action_util *au,FILE * f, struct rtattr *arg)
+{
+       struct tc_nat *sel;
+       struct rtattr *tb[TCA_NAT_MAX + 1];
+       char buf1[256];
+       char buf2[256];
+       SPRINT_BUF(buf3);
+       int len;
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
+
+       if (tb[TCA_NAT_PARMS] == NULL) {
+               fprintf(f, "[NULL nat parameters]");
+               return -1;
+       }
+       sel = RTA_DATA(tb[TCA_NAT_PARMS]);
+
+       len = ffs(sel->mask);
+       len = len ? 33 - len : 0;
+
+       fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
+                                         "egress" : "ingress",
+               format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
+               len,
+               format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
+               action_n2a(sel->action, buf3, sizeof (buf3)));
+
+       if (show_stats) {
+               if (tb[TCA_NAT_TM]) {
+                       struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
+                       print_tm(f,tm);
+               }
+       }
+
+       return 0;
+}
+
+struct action_util nat_action_util = {
+       .id = "nat",
+       .parse_aopt = parse_nat,
+       .print_aopt = print_nat,
+};
index acfa581..7499846 100644 (file)
@@ -1,18 +1,18 @@
 /*
- * m_pedit.c           generic packet editor actions module 
+ * m_pedit.c           generic packet editor actions module
  *
  *             This program is free software; you can distribute 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.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
- * TODO: 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
+ * TODO:
  *     1) Big endian broken in some spots
  *     2) A lot of this stuff was added on the fly; get a big double-double
  *     and clean it up at some point.
- *     
+ *
  */
 
 #include <stdio.h>
@@ -33,28 +33,33 @@ static struct m_pedit_util *pedit_list;
 int pedit_debug = 1;
 
 static void
-p_explain(void)
+explain(void)
 {
-       fprintf(stderr, "Usage: ... pedit <MUNGE>\n");
+       fprintf(stderr, "Usage: ... pedit munge <MUNGE>\n");
        fprintf(stderr,
-               "Where: MUNGE := <RAW>|<LAYERED>\n" 
-               "<RAW>:= <OFFSETC>[ATC]<CMD>\n "
-               "OFFSETC:= offset <offval> <u8|u16|u32>\n "
-               "ATC:= at <atval> offmask <maskval> shift <shiftval>\n "
-               "NOTE: offval is byte offset, must be multiple of 4\n "
-               "NOTE: maskval is a 32 bit hex number\n "
-               "NOTE: shiftval is a is a shift value\n "
-               "CMD:= clear | invert | set <setval>| retain\n "
-               "<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
-               " | udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
-               "For Example usage look at the examples directory");
+               "Where: MUNGE := <RAW>|<LAYERED>\n"
+               "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n "
+               "\t\tOFFSETC:= offset <offval> <u8|u16|u32>\n "
+               "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n "
+               "\t\tNOTE: offval is byte offset, must be multiple of 4\n "
+               "\t\tNOTE: maskval is a 32 bit hex number\n "
+               "\t\tNOTE: shiftval is a is a shift value\n "
+               "\t\tCMD:= clear | invert | set <setval>| retain\n "
+               "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
+               " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
+               "For Example usage look at the examples directory\n");
 
 }
 
-#define usage() return(-1)
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
 
-static int 
-pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) 
+static int
+pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
 {
        int argc = *argc_p;
        char **argv = *argv_p;
@@ -68,7 +73,7 @@ pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct
 
 }
 
-struct m_pedit_util 
+struct m_pedit_util
 *get_pedit_kind(char *str)
 {
        static void *pBODY;
@@ -222,7 +227,7 @@ pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
        retain <<= stride;
        tkey->mask = retain|m[ind];
        tkey->off &= ~3;
-       
+
        if (pedit_debug)
                printf("pack_key8: Final word off %d  val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask);
        return pack_key(sel,tkey);
@@ -288,7 +293,7 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t
        } else if (matches(*argv, "preserve") == 0) {
                retain = mask = o;
        } else {
-               if (matches(*argv, "clear") != 0) 
+               if (matches(*argv, "clear") != 0)
                        return -1;
        }
 
@@ -385,7 +390,7 @@ done:
                tkey->at = atv;
 
                NEXT_ARG();
-               
+
                if (get_u32(&offmask, *argv, 16))
                        return -1;
                tkey->offmask = offmask;
@@ -423,11 +428,6 @@ parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel)
                NEXT_ARG();
                res = parse_offset(&argc, &argv,sel,&tkey);
                goto done;
-#if jamal
-       } else if (strcmp(*argv, "help") == 0) {
-               p_explain();
-               return -1;
-#endif
        } else {
                char k[16];
                struct m_pedit_util *p = NULL;
@@ -479,16 +479,18 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru
                        NEXT_ARG();
                        ok++;
                        continue;
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
                } else if (matches(*argv, "munge") == 0) {
                        if (!ok) {
                                fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
-                               p_explain();
+                               explain();
                                return -1;
                        }
                        NEXT_ARG();
                        if (parse_munge(&argc, &argv,&sel.sel)) {
                                fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
-                               p_explain();
+                               explain();
                                return -1;
                        }
                        ok++;
@@ -499,7 +501,7 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru
        }
 
        if (!ok) {
-               p_explain();
+               explain();
                return -1;
        }
 
@@ -593,7 +595,7 @@ print_pedit(struct action_util *au,FILE * f, struct rtattr *arg)
        return 0;
 }
 
-int 
+int
 pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
 {
        return 0;
index 0a6d24e..1698c95 100644 (file)
@@ -1,13 +1,13 @@
 /*
- * m_pedit.h           generic packet editor actions module 
+ * m_pedit.h           generic packet editor actions module
  *
  *             This program is free software; you can distribute 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.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #ifndef _ACT_PEDIT_H_
index 71adb59..ace43b5 100644 (file)
@@ -7,8 +7,8 @@
  *             2 of the License, or (at your option) any later version.
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- * FIXES:       19990619 - J Hadi Salim (hadi@cyberus.ca) 
- *             simple addattr packaging fix.            
+ * FIXES:       19990619 - J Hadi Salim (hadi@cyberus.ca)
+ *             simple addattr packaging fix.
  *             2002: J Hadi Salim - Add tc action extensions syntax
  *
  */
@@ -32,15 +32,17 @@ struct action_util police_action_util = {
        .print_aopt = print_police,
 };
 
-static void explain(void)
+static void usage(void)
 {
        fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n");
-       fprintf(stderr, "                [ peakrate BPS ] [ avrate BPS ]\n");
-       fprintf(stderr, "                [ ACTIONTERM ]\n");
-       fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n"); 
-       fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n"); 
+       fprintf(stderr, "                [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n");
+       fprintf(stderr, "                [ linklayer TYPE ] [ ACTIONTERM ]\n");
+
+       fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n");
+       fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n");
        fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n");
        fprintf(stderr, "Where:  pipe is only valid for new syntax \n");
+       exit(-1);
 }
 
 static void explain1(char *arg)
@@ -48,9 +50,6 @@ static void explain1(char *arg)
        fprintf(stderr, "Illegal \"%s\"\n", arg);
 }
 
-#define usage() return(-1)
-
-
 char *police_action_n2a(int action, char *buf, int len)
 {
        switch (action) {
@@ -135,7 +134,9 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_
        __u32 avrate = 0;
        int presult = 0;
        unsigned buffer=0, mtu=0, mpu=0;
-       int Rcell_log=-1, Pcell_log = -1; 
+       unsigned short overhead=0;
+       unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
+       int Rcell_log=-1, Pcell_log = -1;
        struct rtattr *tail;
 
        memset(&p, 0, sizeof(p));
@@ -229,15 +230,25 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_
                        p.action = TC_POLICE_OK;
                } else if (matches(*argv, "pipe") == 0) {
                        p.action = TC_POLICE_PIPE;
-               } else if (strcmp(*argv, "conform-exceed") == 0) {
+               } else if (strcmp(*argv, "action") == 0 ||
+                          strcmp(*argv, "conform-exceed") == 0) {
                        NEXT_ARG();
                        if (get_police_result(&p.action, &presult, *argv)) {
                                fprintf(stderr, "Illegal \"action\"\n");
                                return -1;
                        }
+               } else if (matches(*argv, "overhead") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&overhead, *argv, 10)) {
+                               explain1("overhead"); return -1;
+                       }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (get_linklayer(&linklayer, *argv)) {
+                               explain1("linklayer"); return -1;
+                       }
                } else if (strcmp(*argv, "help") == 0) {
-                       explain();
-                       return -1;
+                       usage();
                } else {
                        break;
                }
@@ -264,22 +275,22 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_
        }
 
        if (p.rate.rate) {
-               if ((Rcell_log = tc_calc_rtable(p.rate.rate, rtab, Rcell_log, mtu, mpu)) < 0) {
+               p.rate.mpu = mpu;
+               p.rate.overhead = overhead;
+               if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
                        fprintf(stderr, "TBF: failed to calculate rate table.\n");
                        return -1;
                }
                p.burst = tc_calc_xmittime(p.rate.rate, buffer);
-               p.rate.cell_log = Rcell_log;
-               p.rate.mpu = mpu;
        }
        p.mtu = mtu;
        if (p.peakrate.rate) {
-               if ((Pcell_log = tc_calc_rtable(p.peakrate.rate, ptab, Pcell_log, mtu, mpu)) < 0) {
+               p.peakrate.mpu = mpu;
+               p.peakrate.overhead = overhead;
+               if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
                        fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
                        return -1;
                }
-               p.peakrate.cell_log = Pcell_log;
-               p.peakrate.mpu = mpu;
        }
 
        tail = NLMSG_TAIL(n);
@@ -307,7 +318,7 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
        return act_parse_police(NULL,argc_p,argv_p,tca_id,n);
 }
 
-int 
+int
 print_police(struct action_util *a, FILE *f, struct rtattr *arg)
 {
        SPRINT_BUF(b1);
@@ -334,7 +345,7 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg)
 
        fprintf(f, " police 0x%x ", p->index);
        fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1));
-       buffer = ((double)p->rate.rate*tc_core_tick2usec(p->burst))/1000000;
+       buffer = tc_calc_xmitsize(p->rate.rate, p->burst);
        fprintf(f, "burst %s ", sprint_size(buffer, b1));
        fprintf(f, "mtu %s ", sprint_size(p->mtu, b1));
        if (show_raw)
@@ -348,12 +359,13 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg)
                fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1)));
        } else
                fprintf(f, " ");
+       fprintf(f, "overhead %ub ", p->rate.overhead);
        fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt);
 
        return 0;
 }
 
-int 
+int
 tc_print_police(FILE *f, struct rtattr *arg) {
        return print_police(&police_action_util,f,arg);
 }
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
new file mode 100644 (file)
index 0000000..55e3f89
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * m_skbedit.c         SKB Editing module
+ *
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:    Alexander Duyck <alexander.h.duyck@intel.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_skbedit.h>
+
+static void
+explain(void)
+{
+       fprintf(stderr, "Usage: ... skbedit "
+                       "queue_mapping QUEUE_MAPPING | priority PRIORITY \n"
+                       "QUEUE_MAPPING = device transmit queue to use\n"
+                       "PRIORITY = classID to assign to priority field\n");
+}
+
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
+
+static int
+parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
+             struct nlmsghdr *n)
+{
+       struct tc_skbedit sel;
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       int ok = 0;
+       struct rtattr *tail;
+       unsigned int tmp;
+       __u16 queue_mapping;
+       __u32 flags = 0, priority;
+
+       if (matches(*argv, "skbedit") != 0)
+               return -1;
+
+       NEXT_ARG();
+
+       while (argc > 0) {
+               if (matches(*argv, "queue_mapping") == 0) {
+                       flags |= SKBEDIT_F_QUEUE_MAPPING;
+                       NEXT_ARG();
+                       if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) {
+                               fprintf(stderr, "Illegal queue_mapping\n");
+                               return -1;
+                       }
+                       queue_mapping = tmp;
+                       ok++;
+               } else if (matches(*argv, "priority") == 0) {
+                       flags |= SKBEDIT_F_PRIORITY;
+                       NEXT_ARG();
+                       if (get_tc_classid(&priority, *argv)) {
+                               fprintf(stderr, "Illegal priority\n");
+                               return -1;
+                       }
+                       ok++;
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
+               } else {
+                       break;
+               }
+               argc--;
+               argv++;
+       }
+
+       if (argc) {
+               if (matches(*argv, "reclassify") == 0) {
+                       sel.action = TC_ACT_RECLASSIFY;
+                       NEXT_ARG();
+               } else if (matches(*argv, "pipe") == 0) {
+                       sel.action = TC_ACT_PIPE;
+                       NEXT_ARG();
+               } else if (matches(*argv, "drop") == 0 ||
+                       matches(*argv, "shot") == 0) {
+                       sel.action = TC_ACT_SHOT;
+                       NEXT_ARG();
+               } else if (matches(*argv, "continue") == 0) {
+                       sel.action = TC_ACT_UNSPEC;
+                       NEXT_ARG();
+               } else if (matches(*argv, "pass") == 0) {
+                       sel.action = TC_ACT_OK;
+                       NEXT_ARG();
+               }
+       }
+
+       if (argc) {
+               if (matches(*argv, "index") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&sel.index, *argv, 10)) {
+                               fprintf(stderr, "Pedit: Illegal \"index\"\n");
+                               return -1;
+                       }
+                       argc--;
+                       argv++;
+                       ok++;
+               }
+       }
+
+       if (!ok) {
+               explain();
+               return -1;
+       }
+
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
+       if (flags & SKBEDIT_F_QUEUE_MAPPING)
+               addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
+                         &queue_mapping, sizeof(queue_mapping));
+       if (flags & SKBEDIT_F_PRIORITY)
+               addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY,
+                         &priority, sizeof(priority));
+       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
+{
+       struct tc_skbedit *sel;
+       struct rtattr *tb[TCA_SKBEDIT_MAX + 1];
+       SPRINT_BUF(b1);
+       __u32 *priority;
+       __u16 *queue_mapping;
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, TCA_SKBEDIT_MAX, arg);
+
+       if (tb[TCA_SKBEDIT_PARMS] == NULL) {
+               fprintf(f, "[NULL skbedit parameters]");
+               return -1;
+       }
+
+       sel = RTA_DATA(tb[TCA_SKBEDIT_PARMS]);
+
+       fprintf(f, " skbedit");
+
+       if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
+               queue_mapping = RTA_DATA(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
+               fprintf(f, " queue_mapping %u", *queue_mapping);
+       }
+       if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
+               priority = RTA_DATA(tb[TCA_SKBEDIT_PRIORITY]);
+               fprintf(f, " priority %s", sprint_tc_classid(*priority, b1));
+       }
+
+       if (show_stats) {
+               if (tb[TCA_SKBEDIT_TM]) {
+                       struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]);
+                       print_tm(f, tm);
+               }
+       }
+
+       return 0;
+}
+
+struct action_util skbedit_action_util = {
+       .id = "skbedit",
+       .parse_aopt = parse_skbedit,
+       .print_aopt = print_skbedit,
+};
index f9ddbe3..a4b80c2 100644 (file)
@@ -6,8 +6,8 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #include <stdio.h>
index 1b2a440..08fdbaa 100644 (file)
--- a/tc/p_ip.c
+++ b/tc/p_ip.c
@@ -1,13 +1,13 @@
 /*
- * m_pedit.c           packet editor: IPV4/6 header 
+ * m_pedit.c           packet editor: IPV4/6 header
  *
  *             This program is free software; you can distribute 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.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #include <stdio.h>
index aab37a6..7f4b6f4 100644 (file)
@@ -6,8 +6,8 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #include <stdio.h>
index 95ed993..1776289 100644 (file)
@@ -6,8 +6,8 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  */
 
 #include <stdio.h>
index a456eda..c99dc3b 100644 (file)
@@ -32,6 +32,7 @@ static void explain_class(void)
        fprintf(stderr, "               [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n");
        fprintf(stderr, "               [ estimator INTERVAL TIME_CONSTANT ]\n");
        fprintf(stderr, "               [ split CLASSID ] [ defmap MASK/CHANGE ]\n");
+       fprintf(stderr, "               [ overhead BYTES ] [ linklayer TYPE ]\n");
 }
 
 static void explain(void)
@@ -53,7 +54,9 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        struct tc_cbq_lssopt lss;
        __u32 rtab[256];
        unsigned mpu=0, avpkt=0, allot=0;
-       int cell_log=-1; 
+       unsigned short overhead=0;
+       unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
+       int cell_log=-1;
        int ewma_log=-1;
        struct rtattr *tail;
 
@@ -61,14 +64,14 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        memset(&r, 0, sizeof(r));
 
        while (argc > 0) {
-               if (strcmp(*argv, "bandwidth") == 0 ||
-                   strcmp(*argv, "rate") == 0) {
+               if (matches(*argv, "bandwidth") == 0 ||
+                   matches(*argv, "rate") == 0) {
                        NEXT_ARG();
                        if (get_rate(&r.rate, *argv)) {
                                explain1("bandwidth");
                                return -1;
                        }
-               } else if (strcmp(*argv, "ewma") == 0) {
+               } else if (matches(*argv, "ewma") == 0) {
                        NEXT_ARG();
                        if (get_integer(&ewma_log, *argv, 0)) {
                                explain1("ewma");
@@ -78,7 +81,7 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
                                fprintf(stderr, "ewma_log must be < 32\n");
                                return -1;
                        }
-               } else if (strcmp(*argv, "cell") == 0) {
+               } else if (matches(*argv, "cell") == 0) {
                        unsigned cell;
                        int i;
                        NEXT_ARG();
@@ -94,26 +97,36 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
                                return -1;
                        }
                        cell_log = i;
-               } else if (strcmp(*argv, "avpkt") == 0) {
+               } else if (matches(*argv, "avpkt") == 0) {
                        NEXT_ARG();
                        if (get_size(&avpkt, *argv)) {
                                explain1("avpkt");
                                return -1;
                        }
-               } else if (strcmp(*argv, "mpu") == 0) {
+               } else if (matches(*argv, "mpu") == 0) {
                        NEXT_ARG();
                        if (get_size(&mpu, *argv)) {
                                explain1("mpu");
                                return -1;
                        }
-               } else if (strcmp(*argv, "allot") == 0) {
+               } else if (matches(*argv, "allot") == 0) {
                        NEXT_ARG();
                        /* Accept and ignore "allot" for backward compatibility */
                        if (get_size(&allot, *argv)) {
                                explain1("allot");
                                return -1;
                        }
-               } else if (strcmp(*argv, "help") == 0) {
+               } else if (matches(*argv, "overhead") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&overhead, *argv, 10)) {
+                               explain1("overhead"); return -1;
+                       }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (get_linklayer(&linklayer, *argv)) {
+                               explain1("linklayer"); return -1;
+                       }
+               } else if (matches(*argv, "help") == 0) {
                        explain();
                        return -1;
                } else {
@@ -137,17 +150,17 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        if (allot < (avpkt*3)/2)
                allot = (avpkt*3)/2;
 
-       if ((cell_log = tc_calc_rtable(r.rate, rtab, cell_log, allot, mpu)) < 0) {
+       r.mpu = mpu;
+       r.overhead = overhead;
+       if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
                fprintf(stderr, "CBQ: failed to calculate rate table.\n");
                return -1;
        }
-       r.cell_log = cell_log;
-       r.mpu = mpu;
 
        if (ewma_log < 0)
                ewma_log = TC_CBQ_DEF_EWMA;
        lss.ewma_log = ewma_log;
-       lss.maxidle = tc_cbq_calc_maxidle(r.rate, r.rate, avpkt, lss.ewma_log, 0);
+       lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
        lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
        lss.avpkt = avpkt;
 
@@ -176,10 +189,12 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        struct tc_cbq_ovl ovl;
        __u32 rtab[256];
        unsigned mpu=0;
-       int cell_log=-1; 
+       int cell_log=-1;
        int ewma_log=-1;
        unsigned bndw = 0;
        unsigned minburst=0, maxburst=0;
+       unsigned short overhead=0;
+       unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
        struct rtattr *tail;
 
        memset(&r, 0, sizeof(r));
@@ -189,52 +204,52 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        memset(&ovl, 0, sizeof(ovl));
 
        while (argc > 0) {
-               if (strcmp(*argv, "rate") == 0) {
+               if (matches(*argv, "rate") == 0) {
                        NEXT_ARG();
                        if (get_rate(&r.rate, *argv)) {
                                explain1("rate");
                                return -1;
                        }
-               } else if (strcmp(*argv, "bandwidth") == 0) {
+               } else if (matches(*argv, "bandwidth") == 0) {
                        NEXT_ARG();
                        if (get_rate(&bndw, *argv)) {
                                explain1("bandwidth");
                                return -1;
                        }
-               } else if (strcmp(*argv, "minidle") == 0) {
+               } else if (matches(*argv, "minidle") == 0) {
                        NEXT_ARG();
                        if (get_u32(&lss.minidle, *argv, 0)) {
                                explain1("minidle");
                                return -1;
                        }
                        lss.change |= TCF_CBQ_LSS_MINIDLE;
-               } else if (strcmp(*argv, "minburst") == 0) {
+               } else if (matches(*argv, "minburst") == 0) {
                        NEXT_ARG();
                        if (get_u32(&minburst, *argv, 0)) {
                                explain1("minburst");
                                return -1;
                        }
                        lss.change |= TCF_CBQ_LSS_OFFTIME;
-               } else if (strcmp(*argv, "maxburst") == 0) {
+               } else if (matches(*argv, "maxburst") == 0) {
                        NEXT_ARG();
                        if (get_u32(&maxburst, *argv, 0)) {
                                explain1("maxburst");
                                return -1;
                        }
                        lss.change |= TCF_CBQ_LSS_MAXIDLE;
-               } else if (strcmp(*argv, "bounded") == 0) {
+               } else if (matches(*argv, "bounded") == 0) {
                        lss.flags |= TCF_CBQ_LSS_BOUNDED;
                        lss.change |= TCF_CBQ_LSS_FLAGS;
-               } else if (strcmp(*argv, "borrow") == 0) {
+               } else if (matches(*argv, "borrow") == 0) {
                        lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
                        lss.change |= TCF_CBQ_LSS_FLAGS;
-               } else if (strcmp(*argv, "isolated") == 0) {
+               } else if (matches(*argv, "isolated") == 0) {
                        lss.flags |= TCF_CBQ_LSS_ISOLATED;
                        lss.change |= TCF_CBQ_LSS_FLAGS;
-               } else if (strcmp(*argv, "sharing") == 0) {
+               } else if (matches(*argv, "sharing") == 0) {
                        lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
                        lss.change |= TCF_CBQ_LSS_FLAGS;
-               } else if (strcmp(*argv, "ewma") == 0) {
+               } else if (matches(*argv, "ewma") == 0) {
                        NEXT_ARG();
                        if (get_integer(&ewma_log, *argv, 0)) {
                                explain1("ewma");
@@ -245,7 +260,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                                return -1;
                        }
                        lss.change |= TCF_CBQ_LSS_EWMA;
-               } else if (strcmp(*argv, "cell") == 0) {
+               } else if (matches(*argv, "cell") == 0) {
                        unsigned cell;
                        int i;
                        NEXT_ARG();
@@ -261,7 +276,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                                return -1;
                        }
                        cell_log = i;
-               } else if (strcmp(*argv, "prio") == 0) {
+               } else if (matches(*argv, "prio") == 0) {
                        unsigned prio;
                        NEXT_ARG();
                        if (get_u32(&prio, *argv, 0)) {
@@ -274,40 +289,40 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                        }
                        wrr.priority = prio;
                        wrr_ok++;
-               } else if (strcmp(*argv, "allot") == 0) {
+               } else if (matches(*argv, "allot") == 0) {
                        NEXT_ARG();
                        if (get_size(&wrr.allot, *argv)) {
                                explain1("allot");
                                return -1;
                        }
-               } else if (strcmp(*argv, "avpkt") == 0) {
+               } else if (matches(*argv, "avpkt") == 0) {
                        NEXT_ARG();
                        if (get_size(&lss.avpkt, *argv)) {
                                explain1("avpkt");
                                return -1;
                        }
                        lss.change |= TCF_CBQ_LSS_AVPKT;
-               } else if (strcmp(*argv, "mpu") == 0) {
+               } else if (matches(*argv, "mpu") == 0) {
                        NEXT_ARG();
                        if (get_size(&mpu, *argv)) {
                                explain1("mpu");
                                return -1;
                        }
-               } else if (strcmp(*argv, "weight") == 0) {
+               } else if (matches(*argv, "weight") == 0) {
                        NEXT_ARG();
                        if (get_size(&wrr.weight, *argv)) {
                                explain1("weight");
                                return -1;
                        }
                        wrr_ok++;
-               } else if (strcmp(*argv, "split") == 0) {
+               } else if (matches(*argv, "split") == 0) {
                        NEXT_ARG();
                        if (get_tc_classid(&fopt.split, *argv)) {
                                fprintf(stderr, "Invalid split node ID.\n");
                                usage();
                        }
                        fopt_ok++;
-               } else if (strcmp(*argv, "defmap") == 0) {
+               } else if (matches(*argv, "defmap") == 0) {
                        int err;
                        NEXT_ARG();
                        err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
@@ -318,7 +333,17 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                        if (err == 1)
                                fopt.defchange = ~0;
                        fopt_ok++;
-               } else if (strcmp(*argv, "help") == 0) {
+               } else if (matches(*argv, "overhead") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&overhead, *argv, 10)) {
+                               explain1("overhead"); return -1;
+                       }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (get_linklayer(&linklayer, *argv)) {
+                               explain1("linklayer"); return -1;
+                       }
+               } else if (matches(*argv, "help") == 0) {
                        explain_class();
                        return -1;
                } else {
@@ -336,12 +361,12 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                unsigned pktsize = wrr.allot;
                if (wrr.allot < (lss.avpkt*3)/2)
                        wrr.allot = (lss.avpkt*3)/2;
-               if ((cell_log = tc_calc_rtable(r.rate, rtab, cell_log, pktsize, mpu)) < 0) {
+               r.mpu = mpu;
+               r.overhead = overhead;
+               if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
                        fprintf(stderr, "CBQ: failed to calculate rate table.\n");
                        return -1;
                }
-               r.cell_log = cell_log;
-               r.mpu = mpu;
        }
        if (ewma_log < 0)
                ewma_log = TC_CBQ_DEF_EWMA;
@@ -418,6 +443,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        struct tc_cbq_wrropt *wrr = NULL;
        struct tc_cbq_fopt *fopt = NULL;
        struct tc_cbq_ovl *ovl = NULL;
+       SPRINT_BUF(b1);
 
        if (opt == NULL)
                return 0;
@@ -451,7 +477,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (tb[TCA_CBQ_OVL_STRATEGY]) {
                if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
                        fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
-                               (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), 
+                               (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
                                (unsigned) sizeof(*ovl));
                else
                        ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
@@ -465,6 +491,8 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                        fprintf(f, "cell %ub ", 1<<r->cell_log);
                        if (r->mpu)
                                fprintf(f, "mpu %ub ", r->mpu);
+                       if (r->overhead)
+                               fprintf(f, "overhead %ub ", r->overhead);
                }
        }
        if (lss && lss->flags) {
@@ -500,17 +528,17 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (lss && show_details) {
                fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
                if (lss->maxidle) {
-                       fprintf(f, "maxidle %luus ", tc_core_tick2usec(lss->maxidle>>lss->ewma_log));
+                       fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
                        if (show_raw)
                                fprintf(f, "[%08x] ", lss->maxidle);
                }
                if (lss->minidle!=0x7fffffff) {
-                       fprintf(f, "minidle %luus ", tc_core_tick2usec(lss->minidle>>lss->ewma_log));
+                       fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
                        if (show_raw)
                                fprintf(f, "[%08x] ", lss->minidle);
                }
                if (lss->offtime) {
-                       fprintf(f, "offtime %luus ", tc_core_tick2usec(lss->offtime));
+                       fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
                        if (show_raw)
                                fprintf(f, "[%08x] ", lss->offtime);
                }
index 0526c75..4aaa29b 100644 (file)
@@ -6,9 +6,9 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:    J Hadi Salim(hadi@nortelnetworks.com)   
- *             code ruthlessly ripped from 
- *            Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 
+ * Authors:    J Hadi Salim(hadi@nortelnetworks.com)
+ *             code ruthlessly ripped from
+ *            Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
  */
 
@@ -140,7 +140,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
                                return -1;
                        }
                return init_gred(qu,argc-1, argv+1,n);
-                       
+
                } else if (strcmp(*argv, "min") == 0) {
                        NEXT_ARG();
                        if (get_size(&opt.qth_min, *argv)) {
@@ -276,7 +276,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                fprintf(f,"\n GRED received message smaller than expected\n");
                return -1;
                }
-         
+
 /* Bad hack! should really return a proper message as shown above*/
 
        for (i=0;i<MAX_DPs;i++, qopt++) {
index f09c606..b190c71 100644 (file)
@@ -226,7 +226,7 @@ hfsc_print_sc(FILE *f, char *name, struct tc_service_curve *sc)
 
        fprintf(f, "%s ", name);
        fprintf(f, "m1 %s ", sprint_rate(sc->m1, b1));
-       fprintf(f, "d %s ", sprint_usecs(sc->d, b1));
+       fprintf(f, "d %s ", sprint_time(tc_core_ktime2time(sc->d), b1));
        fprintf(f, "m2 %s ", sprint_rate(sc->m2, b1));
 }
 
@@ -260,7 +260,7 @@ hfsc_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                        usc = RTA_DATA(tb[TCA_HFSC_USC]);
        }
 
-       
+
        if (rsc != NULL && fsc != NULL &&
            memcmp(rsc, fsc, sizeof(*rsc)) == 0)
                hfsc_print_sc(f, "sc", rsc);
@@ -275,7 +275,7 @@ hfsc_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 
        return 0;
 }
+
 struct qdisc_util hfsc_qdisc_util = {
        .id             = "hfsc",
        .parse_qopt     = hfsc_parse_opt,
@@ -303,7 +303,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "d") == 0) {
                NEXT_ARG();
-               if (get_usecs(&d, *argv) < 0) {
+               if (get_time(&d, *argv) < 0) {
                        explain1("d");
                        return -1;
                }
@@ -320,7 +320,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
                return -1;
 
        sc->m1 = m1;
-       sc->d  = d;
+       sc->d  = tc_core_time2ktime(d);
        sc->m2 = m2;
 
        *argvp = argv;
@@ -346,7 +346,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "dmax") == 0) {
                NEXT_ARG();
-               if (get_usecs(&dmax, *argv) < 0) {
+               if (get_time(&dmax, *argv) < 0) {
                        explain1("dmax");
                        return -1;
                }
@@ -367,13 +367,13 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
                return -1;
        }
 
-       if (dmax != 0 && ceil(umax * 1000000.0 / dmax) > rate) {
+       if (dmax != 0 && ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax) > rate) {
                /*
                 * concave curve, slope of first segment is umax/dmax,
                 * intersection is at dmax
                 */
-               sc->m1 = ceil(umax * 1000000.0 / dmax); /* in bps */
-               sc->d  = dmax;
+               sc->m1 = ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax); /* in bps */
+               sc->d  = tc_core_time2ktime(dmax);
                sc->m2 = rate;
        } else {
                /*
@@ -381,7 +381,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
                 * is at dmax - umax / rate
                 */
                sc->m1 = 0;
-               sc->d  = ceil(dmax - umax * 1000000.0 / rate); /* in usec */
+               sc->d  = tc_core_time2ktime(ceil(dmax - umax * TIME_UNITS_PER_SEC / rate));
                sc->m2 = rate;
        }
 
index 828d4b1..c69e350 100644 (file)
@@ -41,7 +41,7 @@ static void explain(void)
                " burst    max bytes burst which can be accumulated during idle period {computed}\n"
                " mpu      minimum packet size used in rate computations\n"
                " overhead per-packet size overhead used in rate computations\n"
-
+               " linklay  adapting to a linklayer e.g. atm\n"
                " ceil     definite upper class rate (no borrows) {rate}\n"
                " cburst   burst but for ceil {computed}\n"
                " mtu      max packet size we create rate map for {1600}\n"
@@ -107,8 +107,10 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        __u32 rtab[256],ctab[256];
        unsigned buffer=0,cbuffer=0;
        int cell_log=-1,ccell_log = -1;
-       unsigned mtu, mpu;
-       unsigned char mpu8 = 0, overhead = 0;
+       unsigned mtu;
+       unsigned short mpu = 0;
+       unsigned short overhead = 0;
+       unsigned int linklayer  = LINKLAYER_ETHERNET; /* Assume ethernet */
        struct rtattr *tail;
 
        memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
@@ -127,14 +129,19 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                        }
                } else if (matches(*argv, "mpu") == 0) {
                        NEXT_ARG();
-                       if (get_u8(&mpu8, *argv, 10)) {
+                       if (get_u16(&mpu, *argv, 10)) {
                                explain1("mpu"); return -1;
                        }
                } else if (matches(*argv, "overhead") == 0) {
                        NEXT_ARG();
-                       if (get_u8(&overhead, *argv, 10)) {
+                       if (get_u16(&overhead, *argv, 10)) {
                                explain1("overhead"); return -1;
                        }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (get_linklayer(&linklayer, *argv)) {
+                               explain1("linklayer"); return -1;
+                       }
                } else if (matches(*argv, "quantum") == 0) {
                        NEXT_ARG();
                        if (get_u32(&opt.quantum, *argv, 10)) {
@@ -206,23 +213,23 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        if (!buffer) buffer = opt.rate.rate / get_hz() + mtu;
        if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu;
 
-/* encode overhead and mpu, 8 bits each, into lower 16 bits */
-       mpu = (unsigned)mpu8 | (unsigned)overhead << 8;
-       opt.ceil.mpu = mpu; opt.rate.mpu = mpu;
+       opt.ceil.overhead = overhead;
+       opt.rate.overhead = overhead;
 
-       if ((cell_log = tc_calc_rtable(opt.rate.rate, rtab, cell_log, mtu, mpu)) < 0) {
+       opt.ceil.mpu = mpu;
+       opt.rate.mpu = mpu;
+
+       if (tc_calc_rtable(&opt.rate, rtab, cell_log, mtu, linklayer) < 0) {
                fprintf(stderr, "htb: failed to calculate rate table.\n");
                return -1;
        }
        opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
-       opt.rate.cell_log = cell_log;
-       
-       if ((ccell_log = tc_calc_rtable(opt.ceil.rate, ctab, cell_log, mtu, mpu)) < 0) {
+
+       if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
                fprintf(stderr, "htb: failed to calculate ceil rate table.\n");
                return -1;
        }
        opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer);
-       opt.ceil.cell_log = ccell_log;
 
        tail = NLMSG_TAIL(n);
        addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
@@ -259,9 +266,9 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                                fprintf(f, "quantum %d ", (int)hopt->quantum);
                }
            fprintf(f, "rate %s ", sprint_rate(hopt->rate.rate, b1));
-           buffer = ((double)hopt->rate.rate*tc_core_tick2usec(hopt->buffer))/1000000;
+           buffer = tc_calc_xmitsize(hopt->rate.rate, hopt->buffer);
            fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1));
-           cbuffer = ((double)hopt->ceil.rate*tc_core_tick2usec(hopt->cbuffer))/1000000;
+           cbuffer = tc_calc_xmitsize(hopt->ceil.rate, hopt->cbuffer);
            if (show_details) {
                fprintf(f, "burst %s/%u mpu %s overhead %s ",
                        sprint_size(buffer, b1),
@@ -279,14 +286,14 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                fprintf(f, "cburst %s ", sprint_size(cbuffer, b1));
            }
            if (show_raw)
-               fprintf(f, "buffer [%08x] cbuffer [%08x] ", 
+               fprintf(f, "buffer [%08x] cbuffer [%08x] ",
                        hopt->buffer,hopt->cbuffer);
        }
        if (tb[TCA_HTB_INIT]) {
            gopt = RTA_DATA(tb[TCA_HTB_INIT]);
            if (RTA_PAYLOAD(tb[TCA_HTB_INIT])  < sizeof(*gopt)) return -1;
 
-           fprintf(f, "r2q %d default %x direct_packets_stat %u", 
+           fprintf(f, "r2q %d default %x direct_packets_stat %u",
                    gopt->rate2quantum,gopt->defcls,gopt->direct_pkts);
                if (show_details)
                        fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff);
@@ -304,7 +311,7 @@ static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstat
                return -1;
 
        st = RTA_DATA(xstats);
-       fprintf(f, " lended: %u borrowed: %u giants: %u\n", 
+       fprintf(f, " lended: %u borrowed: %u giants: %u\n",
                st->lends,st->borrows,st->giants);
        fprintf(f, " tokens: %d ctokens: %d\n", st->tokens,st->ctokens);
        return 0;
diff --git a/tc/q_multiq.c b/tc/q_multiq.c
new file mode 100644 (file)
index 0000000..306e170
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * q_multiq.c          Multiqueue aware qdisc
+ *
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ *
+ * Original Authors:   PJ Waskiewicz, <peter.p.waskiewicz.jr@intel.com> (RR)
+ *                     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (from PRIO)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+       fprintf(stderr, "Usage: ... multiq [help]\n");
+}
+
+#define usage() return(-1)
+
+static int multiq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+                           struct nlmsghdr *n)
+{
+       struct tc_multiq_qopt opt;
+
+       if (argc > 0) {
+               if (strcmp(*argv, "help") == 0) {
+                       explain();
+                       return -1;
+               } else {
+                       fprintf(stderr, "What is \"%s\"?\n", *argv);
+                       explain();
+                       return -1;
+               }
+               argc--; argv++;
+       }
+
+       addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+       return 0;
+}
+
+int multiq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+       struct tc_multiq_qopt *qopt;
+
+       if (opt == NULL)
+               return 0;
+       if (RTA_PAYLOAD(opt) < sizeof(*qopt))
+               return 0;
+
+       qopt = RTA_DATA(opt);
+
+       fprintf(f, "bands %u/%u ", qopt->bands, qopt->max_bands);
+
+       return 0;
+}
+
+struct qdisc_util multiq_qdisc_util = {
+       .id             = "multiq",
+       .parse_qopt     = multiq_parse_opt,
+       .print_qopt     = multiq_print_opt,
+};
index 757edca..d06932e 100644 (file)
@@ -27,7 +27,7 @@
 
 static void explain(void)
 {
-       fprintf(stderr, 
+       fprintf(stderr,
 "Usage: ... netem [ limit PACKETS ] \n" \
 "                 [ delay TIME [ JITTER [CORRELATION]]]\n" \
 "                 [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
@@ -44,14 +44,18 @@ static void explain1(const char *arg)
 
 #define usage() return(-1)
 
+/* Upper bound on size of distribution 
+ *  really (TCA_BUF_MAX - other headers) / sizeof (__s16)
+ */
+#define MAX_DIST       (16*1024)
+
 /*
  * Simplistic file parser for distrbution data.
  * Format is:
  *     # comment line(s)
- *     data0 data1
+ *     data0 data1 ...
  */
-#define MAXDIST        65536
-static int get_distribution(const char *type, __s16 *data)
+static int get_distribution(const char *type, __s16 *data, int maxdata)
 {
        FILE *f;
        int n;
@@ -60,13 +64,13 @@ static int get_distribution(const char *type, __s16 *data)
        char *line = NULL;
        char name[128];
 
-       snprintf(name, sizeof(name), "/usr/lib/tc/%s.dist", type);
+       snprintf(name, sizeof(name), "%s/%s.dist", get_tc_lib(), type);
        if ((f = fopen(name, "r")) == NULL) {
-               fprintf(stderr, "No distribution data for %s (%s: %s)\n", 
+               fprintf(stderr, "No distribution data for %s (%s: %s)\n",
                        type, name, strerror(errno));
                return -1;
        }
-       
+
        n = 0;
        while (getline(&line, &len, f) != -1) {
                char *p, *endp;
@@ -75,10 +79,10 @@ static int get_distribution(const char *type, __s16 *data)
 
                for (p = line; ; p = endp) {
                        x = strtol(p, &endp, 0);
-                       if (endp == p) 
+                       if (endp == p)
                                break;
 
-                       if (n >= MAXDIST) {
+                       if (n >= maxdata) {
                                fprintf(stderr, "%s: too much data\n",
                                        name);
                                n = -1;
@@ -93,7 +97,7 @@ static int get_distribution(const char *type, __s16 *data)
        return n;
 }
 
-static int isnumber(const char *arg) 
+static int isnumber(const char *arg)
 {
        char *p;
        (void) strtod(arg, &p);
@@ -102,26 +106,25 @@ static int isnumber(const char *arg)
 
 #define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1]))
 
-/* Adjust for the fact that psched_ticks aren't always usecs 
+/* Adjust for the fact that psched_ticks aren't always usecs
    (based on kernel PSCHED_CLOCK configuration */
 static int get_ticks(__u32 *ticks, const char *str)
 {
        unsigned t;
 
-       if(get_usecs(&t, str))
+       if(get_time(&t, str))
                return -1;
-       
-       *ticks = tc_core_usec2tick(t);
-       return 0;
-}
 
-static char *sprint_ticks(__u32 ticks, char *buf)
-{
-       return sprint_usecs(tc_core_tick2usec(ticks), buf);
-}
+       if (tc_core_time2big(t)) {
+               fprintf(stderr, "Illegal %u time (too large)\n", t);
+               return -1;
+       }
 
+       *ticks = tc_core_time2tick(t);
+       return 0;
+}
 
-static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, 
+static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                           struct nlmsghdr *n)
 {
        size_t dist_size = 0;
@@ -131,12 +134,14 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        struct tc_netem_reorder reorder;
        struct tc_netem_corrupt corrupt;
        __s16 *dist_data = NULL;
+       int present[__TCA_NETEM_MAX];
 
        memset(&opt, 0, sizeof(opt));
        opt.limit = 1000;
        memset(&cor, 0, sizeof(cor));
        memset(&reorder, 0, sizeof(reorder));
        memset(&corrupt, 0, sizeof(corrupt));
+       memset(present, 0, sizeof(present));
 
        while (argc > 0) {
                if (matches(*argv, "limit") == 0) {
@@ -162,8 +167,8 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 
                                if (NEXT_IS_NUMBER()) {
                                        NEXT_ARG();
-                                       if (get_percent(&cor.delay_corr, 
-                                                       *argv)) {
+                                       ++present[TCA_NETEM_CORR];
+                                       if (get_percent(&cor.delay_corr,                                                        *argv)) {
                                                explain1("latency");
                                                return -1;
                                        }
@@ -178,6 +183,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        }
                        if (NEXT_IS_NUMBER()) {
                                NEXT_ARG();
+                               ++present[TCA_NETEM_CORR];
                                if (get_percent(&cor.loss_corr, *argv)) {
                                        explain1("loss");
                                        return -1;
@@ -185,12 +191,14 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        }
                } else if (matches(*argv, "reorder") == 0) {
                        NEXT_ARG();
+                       present[TCA_NETEM_REORDER] = 1;
                        if (get_percent(&reorder.probability, *argv)) {
                                explain1("reorder");
                                return -1;
                        }
                        if (NEXT_IS_NUMBER()) {
                                NEXT_ARG();
+                               ++present[TCA_NETEM_CORR];
                                if (get_percent(&reorder.correlation, *argv)) {
                                        explain1("reorder");
                                        return -1;
@@ -198,12 +206,14 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        }
                } else if (matches(*argv, "corrupt") == 0) {
                        NEXT_ARG();
+                       present[TCA_NETEM_CORRUPT] = 1;
                        if (get_percent(&corrupt.probability, *argv)) {
                                explain1("corrupt");
                                return -1;
                        }
                        if (NEXT_IS_NUMBER()) {
                                NEXT_ARG();
+                               ++present[TCA_NETEM_CORR];
                                if (get_percent(&corrupt.correlation, *argv)) {
                                        explain1("corrupt");
                                        return -1;
@@ -230,10 +240,12 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        }
                } else if (matches(*argv, "distribution") == 0) {
                        NEXT_ARG();
-                       dist_data = alloca(MAXDIST);
-                       dist_size = get_distribution(*argv, dist_data);
-                       if (dist_size < 0)
+                       dist_data = calloc(sizeof(dist_data[0]), MAX_DIST);
+                       dist_size = get_distribution(*argv, dist_data, MAX_DIST);
+                       if (dist_size <= 0) {
+                               free(dist_data);
                                return -1;
+                       }
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -265,26 +277,27 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                return -1;
        }
 
-       if (addattr_l(n, TCA_BUF_MAX, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
+       if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
                return -1;
 
-       if (cor.delay_corr || cor.loss_corr || cor.dup_corr) {
-               if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
+       if (present[TCA_NETEM_CORR] &&
+           addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
                        return -1;
-       }
 
-       if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
+       if (present[TCA_NETEM_REORDER] && 
+           addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
                return -1;
 
-       if (corrupt.probability) {
-               if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
-                       return -1;
-       }
+       if (present[TCA_NETEM_CORRUPT] &&
+           addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
+               return -1;
 
        if (dist_data) {
-               if (addattr_l(n, 32768, TCA_NETEM_DELAY_DIST,
-                             dist_data, dist_size*sizeof(dist_data[0])) < 0)
+               if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]),
+                             TCA_NETEM_DELAY_DIST,
+                             dist_data, dist_size * sizeof(dist_data[0])) < 0)
                        return -1;
+               free(dist_data);
        }
        tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
        return 0;
@@ -312,7 +325,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                struct rtattr *tb[TCA_NETEM_MAX+1];
                parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt),
                             len);
-               
+
                if (tb[TCA_NETEM_CORR]) {
                        if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor))
                                return -1;
@@ -354,20 +367,20 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                if (cor && cor->dup_corr)
                        fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
        }
-                       
+
        if (reorder && reorder->probability) {
-               fprintf(f, " reorder %s", 
+               fprintf(f, " reorder %s",
                        sprint_percent(reorder->probability, b1));
                if (reorder->correlation)
-                       fprintf(f, " %s", 
+                       fprintf(f, " %s",
                                sprint_percent(reorder->correlation, b1));
        }
 
        if (corrupt && corrupt->probability) {
-               fprintf(f, " corrupt %s", 
+               fprintf(f, " corrupt %s",
                        sprint_percent(corrupt->probability, b1));
                if (corrupt->correlation)
-                       fprintf(f, " %s", 
+                       fprintf(f, " %s",
                                sprint_percent(corrupt->correlation, b1));
        }
 
index d696e1b..6883edb 100644 (file)
@@ -29,7 +29,7 @@
 
 static void explain(void)
 {
-       fprintf(stderr, "Usage: ... prio bands NUMBER priomap P1 P2...\n");
+       fprintf(stderr, "Usage: ... prio bands NUMBER priomap P1 P2...[multiqueue]\n");
 }
 
 #define usage() return(-1)
@@ -40,6 +40,8 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
        int pmap_mode = 0;
        int idx = 0;
        struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }};
+       struct rtattr *nest;
+       unsigned char mq = 0;
 
        while (argc > 0) {
                if (strcmp(*argv, "bands") == 0) {
@@ -57,6 +59,8 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
                                return -1;
                        }
                        pmap_mode = 1;
+               } else if (strcmp(*argv, "multiqueue") == 0) {
+                       mq = 1;
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -90,7 +94,10 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
                        opt.priomap[idx] = opt.priomap[TC_PRIO_BESTEFFORT];
        }
 */
-       addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+       nest = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+       if (mq)
+               addattr_l(n, 1024, TCA_PRIO_MQ, NULL, 0);
+       addattr_nest_compat_end(n, nest);
        return 0;
 }
 
@@ -98,16 +105,23 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
        int i;
        struct tc_prio_qopt *qopt;
+       struct rtattr *tb[TCA_PRIO_MAX+1];
 
        if (opt == NULL)
                return 0;
 
-       if (RTA_PAYLOAD(opt)  < sizeof(*qopt))
-               return -1;
-       qopt = RTA_DATA(opt);
+       if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
+                                       sizeof(*qopt)))
+                return -1;
+
        fprintf(f, "bands %u priomap ", qopt->bands);
        for (i=0; i<=TC_PRIO_MAX; i++)
                fprintf(f, " %d", qopt->priomap[i]);
+
+       if (tb[TCA_PRIO_MQ])
+               fprintf(f, " multiqueue: %s ",
+                   *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "on" : "off");
+
        return 0;
 }
 
index 1743f6c..6f93b26 100644 (file)
@@ -205,7 +205,7 @@ static int red_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstat
        fprintf(f, "  marked %u early %u pdrop %u other %u",
                st->marked, st->early, st->pdrop, st->other);
        return 0;
-       
+
 #endif
        return 0;
 }
diff --git a/tc/q_rr.c b/tc/q_rr.c
new file mode 100644 (file)
index 0000000..9335c47
--- /dev/null
+++ b/tc/q_rr.c
@@ -0,0 +1,127 @@
+/*
+ * q_rr.c              RR.
+ *
+ *             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.
+ *
+ * Authors:    PJ Waskiewicz, <peter.p.waskiewicz.jr@intel.com>
+ * Original Authors:   Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (from PRIO)
+ *
+ * Changes:
+ *
+ * Ole Husgaard <sparre@login.dknet.dk>: 990513: prio2band map was always reset.
+ * J Hadi Salim <hadi@cyberus.ca>: 990609: priomap fix.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+       fprintf(stderr, "Usage: ... rr bands NUMBER priomap P1 P2... [multiqueue]\n");
+}
+
+#define usage() return(-1)
+
+static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
+{
+       int ok = 0;
+       int pmap_mode = 0;
+       int idx = 0;
+       struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }};
+       struct rtattr *nest;
+       unsigned char mq = 0;
+
+       while (argc > 0) {
+               if (strcmp(*argv, "bands") == 0) {
+                       if (pmap_mode)
+                               explain();
+                       NEXT_ARG();
+                       if (get_integer(&opt.bands, *argv, 10)) {
+                               fprintf(stderr, "Illegal \"bands\"\n");
+                               return -1;
+                       }
+                       ok++;
+               } else if (strcmp(*argv, "priomap") == 0) {
+                       if (pmap_mode) {
+                               fprintf(stderr, "Error: duplicate priomap\n");
+                               return -1;
+                       }
+                       pmap_mode = 1;
+               } else if (strcmp(*argv, "help") == 0) {
+                       explain();
+                       return -1;
+               } else if (strcmp(*argv, "multiqueue") == 0) {
+                       mq = 1;
+               } else {
+                       unsigned band;
+                       if (!pmap_mode) {
+                               fprintf(stderr, "What is \"%s\"?\n", *argv);
+                               explain();
+                               return -1;
+                       }
+                       if (get_unsigned(&band, *argv, 10)) {
+                               fprintf(stderr, "Illegal \"priomap\" element\n");
+                               return -1;
+                       }
+                       if (band > opt.bands) {
+                               fprintf(stderr, "\"priomap\" element is out of bands\n");
+                               return -1;
+                       }
+                       if (idx > TC_PRIO_MAX) {
+                               fprintf(stderr, "\"priomap\" index > TC_RR_MAX=%u\n", TC_PRIO_MAX);
+                               return -1;
+                       }
+                       opt.priomap[idx++] = band;
+               }
+               argc--; argv++;
+       }
+
+       nest = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+       if (mq)
+               addattr_l(n, 1024, TCA_PRIO_MQ, NULL, 0);
+       addattr_nest_compat_end(n, nest);
+       return 0;
+}
+
+int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+       int i;
+       struct tc_prio_qopt *qopt;
+       struct rtattr *tb[TCA_PRIO_MAX + 1];
+
+       if (opt == NULL)
+               return 0;
+
+       if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
+                                               sizeof(*qopt)))
+               return -1;
+
+       fprintf(f, "bands %u priomap ", qopt->bands);
+       for (i=0; i <= TC_PRIO_MAX; i++)
+               fprintf(f, " %d", qopt->priomap[i]);
+
+       if (tb[TCA_PRIO_MQ])
+               fprintf(f, " multiqueue: %s ",
+                   *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "on" : "off");
+
+       return 0;
+}
+
+struct qdisc_util rr_qdisc_util = {
+       .id             = "rr",
+       .parse_qopt     = rr_parse_opt,
+       .print_qopt     = rr_print_opt,
+};
index 05385cf..ce4dade 100644 (file)
@@ -100,8 +100,25 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        return 0;
 }
 
+static int sfq_print_xstats(struct qdisc_util *qu, FILE *f,
+                           struct rtattr *xstats)
+{
+       struct tc_sfq_xstats *st;
+
+       if (xstats == NULL)
+               return 0;
+       if (RTA_PAYLOAD(xstats) < sizeof(*st))
+               return -1;
+       st = RTA_DATA(xstats);
+
+       fprintf(f, " allot %d ", st->allot);
+       fprintf(f, "\n");
+       return 0;
+}
+
 struct qdisc_util sfq_qdisc_util = {
        .id             = "sfq",
        .parse_qopt     = sfq_parse_opt,
        .print_qopt     = sfq_print_opt,
+       .print_xstats   = sfq_print_xstats,
 };
index 6ed5e0b..dbf9586 100644 (file)
@@ -26,7 +26,8 @@
 static void explain(void)
 {
        fprintf(stderr, "Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ]\n");
-       fprintf(stderr, "               [ peakrate KBPS ] [ latency TIME ]\n");
+       fprintf(stderr, "               [ peakrate KBPS ] [ latency TIME ] ");
+       fprintf(stderr, "[ overhead BYTES ] [ linklayer TYPE ]\n");
 }
 
 static void explain1(char *arg)
@@ -44,7 +45,9 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        __u32 rtab[256];
        __u32 ptab[256];
        unsigned buffer=0, mtu=0, mpu=0, latency=0;
-       int Rcell_log=-1, Pcell_log = -1; 
+       int Rcell_log=-1, Pcell_log = -1;
+       unsigned short overhead=0;
+       unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
        struct rtattr *tail;
 
        memset(&opt, 0, sizeof(opt));
@@ -67,7 +70,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
                                fprintf(stderr, "Double \"limit/latency\" spec\n");
                                return -1;
                        }
-                       if (get_usecs(&latency, *argv)) {
+                       if (get_time(&latency, *argv)) {
                                explain1("latency");
                                return -1;
                        }
@@ -130,6 +133,20 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
                                return -1;
                        }
                        ok++;
+               } else if (matches(*argv, "overhead") == 0) {
+                       NEXT_ARG();
+                       if (overhead) {
+                               fprintf(stderr, "Double \"overhead\" spec\n");
+                               return -1;
+                       }
+                       if (get_u16(&overhead, *argv, 10)) {
+                               explain1("overhead"); return -1;
+                       }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (get_linklayer(&linklayer, *argv)) {
+                               explain1("linklayer"); return -1;
+                       }
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -161,30 +178,31 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        }
 
        if (opt.limit == 0) {
-               double lim = opt.rate.rate*(double)latency/1000000 + buffer;
+               double lim = opt.rate.rate*(double)latency/TIME_UNITS_PER_SEC + buffer;
                if (opt.peakrate.rate) {
-                       double lim2 = opt.peakrate.rate*(double)latency/1000000 + mtu;
+                       double lim2 = opt.peakrate.rate*(double)latency/TIME_UNITS_PER_SEC + mtu;
                        if (lim2 < lim)
                                lim = lim2;
                }
                opt.limit = lim;
        }
 
-       if ((Rcell_log = tc_calc_rtable(opt.rate.rate, rtab, Rcell_log, mtu, mpu)) < 0) {
+       opt.rate.mpu      = mpu;
+       opt.rate.overhead = overhead;
+       if (tc_calc_rtable(&opt.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
                fprintf(stderr, "TBF: failed to calculate rate table.\n");
                return -1;
        }
        opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
-       opt.rate.cell_log = Rcell_log;
-       opt.rate.mpu = mpu;
+
        if (opt.peakrate.rate) {
-               if ((Pcell_log = tc_calc_rtable(opt.peakrate.rate, ptab, Pcell_log, mtu, mpu)) < 0) {
+               opt.peakrate.mpu      = mpu;
+               opt.peakrate.overhead = overhead;
+               if (tc_calc_rtable(&opt.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
                        fprintf(stderr, "TBF: failed to calculate peak rate table.\n");
                        return -1;
                }
                opt.mtu = tc_calc_xmittime(opt.peakrate.rate, mtu);
-               opt.peakrate.cell_log = Pcell_log;
-               opt.peakrate.mpu = mpu;
        }
 
        tail = NLMSG_TAIL(n);
@@ -218,7 +236,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (RTA_PAYLOAD(tb[TCA_TBF_PARMS])  < sizeof(*qopt))
                return -1;
        fprintf(f, "rate %s ", sprint_rate(qopt->rate.rate, b1));
-       buffer = ((double)qopt->rate.rate*tc_core_tick2usec(qopt->buffer))/1000000;
+       buffer = tc_calc_xmitsize(qopt->rate.rate, qopt->buffer);
        if (show_details) {
                fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1),
                        1<<qopt->rate.cell_log, sprint_size(qopt->rate.mpu, b2));
@@ -230,7 +248,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (qopt->peakrate.rate) {
                fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate.rate, b1));
                if (qopt->mtu || qopt->peakrate.mpu) {
-                       mtu = ((double)qopt->peakrate.rate*tc_core_tick2usec(qopt->mtu))/1000000;
+                       mtu = tc_calc_xmitsize(qopt->peakrate.rate, qopt->mtu);
                        if (show_details) {
                                fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1),
                                        1<<qopt->peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2));
@@ -245,13 +263,17 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (show_raw)
                fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
 
-       latency = 1000000*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2usec(qopt->buffer);
+       latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2time(qopt->buffer);
        if (qopt->peakrate.rate) {
-               double lat2 = 1000000*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2usec(qopt->mtu);
+               double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2time(qopt->mtu);
                if (lat2 > latency)
                        latency = lat2;
        }
-       fprintf(f, "lat %s ", sprint_usecs(tc_core_tick2usec(latency), b1));
+       fprintf(f, "lat %s ", sprint_time(latency, b1));
+
+       if (qopt->rate.overhead) {
+               fprintf(f, "overhead %d", qopt->rate.overhead);
+       }
 
        return 0;
 }
diff --git a/tc/tc.c b/tc/tc.c
index fa36ee0..aabeac8 100644 (file)
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -33,6 +33,8 @@
 int show_stats = 0;
 int show_details = 0;
 int show_raw = 0;
+int show_pretty = 0;
+
 int resolve_hosts = 0;
 int use_iec = 0;
 int force = 0;
@@ -42,11 +44,11 @@ static void *BODY = NULL;   /* cached handle dlopen(NULL) */
 static struct qdisc_util * qdisc_list;
 static struct filter_util * filter_list;
 
-static int print_noqopt(struct qdisc_util *qu, FILE *f, 
+static int print_noqopt(struct qdisc_util *qu, FILE *f,
                        struct rtattr *opt)
 {
        if (opt && RTA_PAYLOAD(opt))
-               fprintf(f, "[Unknown qdisc, optlen=%u] ", 
+               fprintf(f, "[Unknown qdisc, optlen=%u] ",
                        (unsigned) RTA_PAYLOAD(opt));
        return 0;
 }
@@ -63,7 +65,7 @@ static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlm
 static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle)
 {
        if (opt && RTA_PAYLOAD(opt))
-               fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", 
+               fprintf(f, "fh %08x [Unknown filter, optlen=%u] ",
                        fhandle, (unsigned) RTA_PAYLOAD(opt));
        else if (fhandle)
                fprintf(f, "fh %08x ", fhandle);
@@ -99,7 +101,7 @@ struct qdisc_util *get_qdisc_kind(const char *str)
                if (strcmp(q->id, str) == 0)
                        return q;
 
-       snprintf(buf, sizeof(buf), "/usr/lib/tc/q_%s.so", str);
+       snprintf(buf, sizeof(buf), "%s/q_%s.so", get_tc_lib(), str);
        dlh = dlopen(buf, RTLD_LAZY);
        if (!dlh) {
                /* look in current binary, only open once */
@@ -145,7 +147,7 @@ struct filter_util *get_filter_kind(const char *str)
                if (strcmp(q->id, str) == 0)
                        return q;
 
-       snprintf(buf, sizeof(buf), "/usr/lib/tc/f_%s.so", str);
+       snprintf(buf, sizeof(buf), "%s/f_%s.so", get_tc_lib(), str);
        dlh = dlopen(buf, RTLD_LAZY);
        if (dlh == NULL) {
                dlh = BODY;
@@ -181,8 +183,8 @@ static void usage(void)
 {
        fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
                        "       tc [-force] -batch file\n"
-                       "where  OBJECT := { qdisc | class | filter | action }\n"
-                       "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [file] }\n");
+                       "where  OBJECT := { qdisc | class | filter | action | monitor }\n"
+                       "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [file] }\n");
 }
 
 static int do_cmd(int argc, char **argv)
@@ -199,12 +201,15 @@ static int do_cmd(int argc, char **argv)
        if (matches(*argv, "actions") == 0)
                return do_action(argc-1, argv+1);
 
+       if (matches(*argv, "monitor") == 0)
+               return do_tcmonitor(argc-1, argv+1);
+
        if (matches(*argv, "help") == 0) {
                usage();
                return 0;
        }
-       
-       fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", 
+
+       fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n",
                *argv);
        return -1;
 }
@@ -217,7 +222,7 @@ static int batch(const char *name)
 
        if (name && strcmp(name, "-") != 0) {
                if (freopen(name, "r", stdin) == NULL) {
-                       fprintf(stderr, "Cannot open file \"%s\" for reading: %s=n",
+                       fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
                                name, strerror(errno));
                        return -1;
                }
@@ -270,6 +275,8 @@ int main(int argc, char **argv)
                        ++show_details;
                } else if (matches(argv[1], "-raw") == 0) {
                        ++show_raw;
+               } else if (matches(argv[1], "-pretty") == 0) {
+                       ++show_pretty;
                } else if (matches(argv[1], "-Version") == 0) {
                        printf("tc utility, iproute2-ss%s\n", SNAPSHOT);
                        return 0;
index 0abcc9d..0bb262e 100644 (file)
@@ -38,7 +38,7 @@ unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt,
                if (vxmt > maxidle)
                        maxidle = vxmt;
        }
-       return tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000);
+       return tc_core_time2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC);
 }
 
 unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt,
@@ -53,5 +53,5 @@ unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt,
                offtime *= pow(g, -(double)minburst) - 1;
        else
                offtime *= 1 + (pow(g, -(double)(minburst-1)) - 1)/(1-g);
-       return tc_core_usec2tick(offtime*1000000);
+       return tc_core_time2tick(offtime*TIME_UNITS_PER_SEC);
 }
index 894caa1..774497a 100644 (file)
@@ -29,7 +29,7 @@ static void usage(void);
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: tc class [ add | del | change | get ] dev STRING\n");
+       fprintf(stderr, "Usage: tc class [ add | del | change | replace | show ] dev STRING\n");
        fprintf(stderr, "       [ classid CLASSID ] [ root | parent CLASSID ]\n");
        fprintf(stderr, "       [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n");
        fprintf(stderr, "\n");
@@ -147,7 +147,7 @@ int tc_class_modify(int cmd, unsigned flags, int argc, char **argv)
 int filter_ifindex;
 __u32 filter_qdisc;
 
-static int print_class(const struct sockaddr_nl *who, 
+int print_class(const struct sockaddr_nl *who,
                       struct nlmsghdr *n, void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -213,7 +213,7 @@ static int print_class(const struct sockaddr_nl *who,
        fprintf(fp, "\n");
        if (show_stats) {
                struct rtattr *xstats = NULL;
-               
+
                if (tb[TCA_STATS] || tb[TCA_STATS2]) {
                        print_tcstats_attr(fp, tb, " ", &xstats);
                        fprintf(fp, "\n");
@@ -315,8 +315,10 @@ int do_class(int argc, char **argv)
        if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
            || matches(*argv, "lst") == 0)
                return tc_class_list(argc-1, argv+1);
-       if (matches(*argv, "help") == 0)
+       if (matches(*argv, "help") == 0) {
                usage();
+               return 0;
+       }
        fprintf(stderr, "Command \"%s\" is unknown, try \"tc class help\".\n", *argv);
        return -1;
 }
index 7e13582..4f88856 100644 (file)
@@ -6,6 +6,16 @@ extern int do_qdisc(int argc, char **argv);
 extern int do_class(int argc, char **argv);
 extern int do_filter(int argc, char **argv);
 extern int do_action(int argc, char **argv);
+extern int do_tcmonitor(int argc, char **argv);
+extern int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta);
 
 struct tc_estimator;
 extern int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est);
+
+struct tc_sizespec;
+extern int parse_size_table(int *p_argc, char ***p_argv, struct tc_sizespec *s);
+extern int check_size_table_opts(struct tc_sizespec *s);
index 07cf2fa..9a0ff39 100644 (file)
 #include <string.h>
 
 #include "tc_core.h"
+#include <linux/atm.h>
 
-static __u32 t2us=1;
-static __u32 us2t=1;
 static double tick_in_usec = 1;
+static double clock_factor = 1;
 
-long tc_core_usec2tick(long usec)
+int tc_core_time2big(unsigned time)
 {
-       return usec*tick_in_usec;
+       __u64 t = time;
+
+       t *= tick_in_usec;
+       return (t >> 32) != 0;
+}
+
+
+unsigned tc_core_time2tick(unsigned time)
+{
+       return time*tick_in_usec;
 }
 
-long tc_core_tick2usec(long tick)
+unsigned tc_core_tick2time(unsigned tick)
 {
        return tick/tick_in_usec;
 }
 
+unsigned tc_core_time2ktime(unsigned time)
+{
+       return time * clock_factor;
+}
+
+unsigned tc_core_ktime2time(unsigned ktime)
+{
+       return ktime / clock_factor;
+}
+
 unsigned tc_calc_xmittime(unsigned rate, unsigned size)
 {
-       return tc_core_usec2tick(1000000*((double)size/rate));
+       return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/rate));
+}
+
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
+{
+       return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC;
+}
+
+/*
+ * 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@diku.dk>
+ */
+unsigned tc_align_to_atm(unsigned 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;
+}
+
+unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linklayer)
+{
+       if (sz < mpu)
+               sz = mpu;
+
+       switch (linklayer) {
+       case LINKLAYER_ATM:
+               return tc_align_to_atm(sz);
+       case LINKLAYER_ETHERNET:
+       default:
+               // No size adjustments on Ethernet
+               return sz;
+       }
 }
 
 /*
    rtab[pkt_len>>cell_log] = pkt_xmit_time
  */
 
-int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu,
-                  unsigned mpu)
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+                  int cell_log, unsigned mtu,
+                  enum link_layer linklayer)
 {
        int i;
-       unsigned overhead = (mpu >> 8) & 0xFF;
-       mpu = mpu & 0xFF;
+       unsigned sz;
+       unsigned bps = r->rate;
+       unsigned mpu = r->mpu;
 
        if (mtu == 0)
                mtu = 2047;
 
        if (cell_log < 0) {
                cell_log = 0;
-               while ((mtu>>cell_log) > 255)
+               while ((mtu >> cell_log) > 255)
                        cell_log++;
        }
+
        for (i=0; i<256; i++) {
-               unsigned sz = (i<<cell_log);
-               if (overhead)
-                       sz += overhead;
-               if (sz < mpu)
-                       sz = mpu;
-               rtab[i] = tc_core_usec2tick(1000000*((double)sz/bps));
+               sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer);
+               rtab[i] = tc_calc_xmittime(bps, sz);
        }
+
+       r->cell_align=-1; // Due to the sz calc
+       r->cell_log=cell_log;
        return cell_log;
 }
 
+/*
+   stab[pkt_len>>cell_log] = pkt_xmit_size>>size_log
+ */
+
+int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab)
+{
+       int i;
+       enum link_layer linklayer = s->linklayer;
+       unsigned int sz;
+
+       if (linklayer <= LINKLAYER_ETHERNET && s->mpu == 0) {
+               /* don't need data table in this case (only overhead set) */
+               s->mtu = 0;
+               s->tsize = 0;
+               s->cell_log = 0;
+               s->cell_align = 0;
+               *stab = NULL;
+               return 0;
+       }
+
+       if (s->mtu == 0)
+               s->mtu = 2047;
+       if (s->tsize == 0)
+               s->tsize = 512;
+
+       s->cell_log = 0;
+       while ((s->mtu >> s->cell_log) > s->tsize - 1)
+               s->cell_log++;
+
+       *stab = malloc(s->tsize * sizeof(__u16));
+       if (!*stab)
+               return -1;
+
+again:
+       for (i = s->tsize - 1; i >= 0; i--) {
+               sz = tc_adjust_size((i + 1) << s->cell_log, s->mpu, linklayer);
+               if ((sz >> s->size_log) > UINT16_MAX) {
+                       s->size_log++;
+                       goto again;
+               }
+               (*stab)[i] = sz >> s->size_log;
+       }
+
+       s->cell_align = -1; // Due to the sz calc
+       return 0;
+}
+
 int tc_core_init()
 {
-       FILE *fp = fopen("/proc/net/psched", "r");
+       FILE *fp;
+       __u32 clock_res;
+       __u32 t2us;
+       __u32 us2t;
 
+       fp = fopen("/proc/net/psched", "r");
        if (fp == NULL)
                return -1;
 
-       if (fscanf(fp, "%08x%08x", &t2us, &us2t) != 2) {
+       if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) {
                fclose(fp);
                return -1;
        }
        fclose(fp);
-       tick_in_usec = (double)t2us/us2t;
+
+       /* compatibility hack: for old iproute binaries (ignoring
+        * the kernel clock resolution) the kernel advertises a
+        * tick multiplier of 1000 in case of nano-second resolution,
+        * which really is 1. */
+       if (clock_res == 1000000000)
+               t2us = us2t;
+
+       clock_factor  = (double)clock_res / TIME_UNITS_PER_SEC;
+       tick_in_usec = (double)t2us / us2t * clock_factor;
        return 0;
 }
index 1537f95..5a693ba 100644 (file)
@@ -4,10 +4,25 @@
 #include <asm/types.h>
 #include <linux/pkt_sched.h>
 
-long tc_core_usec2tick(long usec);
-long tc_core_tick2usec(long tick);
+#define TIME_UNITS_PER_SEC     1000000
+
+enum link_layer {
+       LINKLAYER_UNSPEC,
+       LINKLAYER_ETHERNET,
+       LINKLAYER_ATM,
+};
+
+
+int  tc_core_time2big(unsigned time);
+unsigned tc_core_time2tick(unsigned time);
+unsigned tc_core_tick2time(unsigned tick);
+unsigned tc_core_time2ktime(unsigned time);
+unsigned tc_core_ktime2time(unsigned ktime);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
-int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu, unsigned mpu);
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+                  int cell_log, unsigned mtu, enum link_layer link_layer);
+int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab);
 
 int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est);
 
index 434db0f..e559add 100644 (file)
@@ -26,7 +26,7 @@
 int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est)
 {
        for (est->interval=0; est->interval<=5; est->interval++) {
-               if (A <= (1<<est->interval)*(1000000/4))
+               if (A <= (1<<est->interval)*(TIME_UNITS_PER_SEC/4))
                        break;
        }
        if (est->interval > 5)
index f6de840..919c57c 100644 (file)
@@ -15,8 +15,6 @@
 #include <unistd.h>
 #include <syslog.h>
 #include <fcntl.h>
-#include <net/if.h>
-#include <net/if_arp.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -32,8 +30,8 @@ static void usage(void);
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: tc filter [ add | del | change | get ] dev STRING\n");
-       fprintf(stderr, "       [ pref PRIO ] [ protocol PROTO ]\n");
+       fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n");
+       fprintf(stderr, "       [ pref PRIO ] protocol PROTO\n");
        fprintf(stderr, "       [ estimator INTERVAL TIME_CONSTANT ]\n");
        fprintf(stderr, "       [ root | classid CLASSID ] [ handle FILTERID ]\n");
        fprintf(stderr, "       [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n");
@@ -57,6 +55,7 @@ int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv)
        struct filter_util *q = NULL;
        __u32 prio = 0;
        __u32 protocol = 0;
+       int protocol_set = 0;
        char *fhandle = NULL;
        char  d[16];
        char  k[16];
@@ -73,6 +72,9 @@ int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv)
        req.n.nlmsg_type = cmd;
        req.t.tcm_family = AF_UNSPEC;
 
+       if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
+               protocol = ETH_P_ALL;
+
        while (argc > 0) {
                if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
@@ -104,20 +106,22 @@ int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv)
                        if (prio)
                                duparg("priority", *argv);
                        if (get_u32(&prio, *argv, 0))
-                               invarg(*argv, "invalid prpriority value");
+                               invarg(*argv, "invalid priority value");
                } else if (matches(*argv, "protocol") == 0) {
                        __u16 id;
                        NEXT_ARG();
-                       if (protocol)
+                       if (protocol_set)
                                duparg("protocol", *argv);
                        if (ll_proto_a2n(&id, *argv))
                                invarg(*argv, "invalid protocol");
                        protocol = id;
+                       protocol_set = 1;
                } else if (matches(*argv, "estimator") == 0) {
                        if (parse_estimator(&argc, &argv, &est) < 0)
                                return -1;
                } else if (matches(*argv, "help") == 0) {
                        usage();
+                       return 0;
                } else {
                        strncpy(k, *argv, sizeof(k)-1);
 
@@ -175,9 +179,10 @@ static __u32 filter_parent;
 static int filter_ifindex;
 static __u32 filter_prio;
 static __u32 filter_protocol;
+__u16 f_proto = 0;
 
-static int print_filter(const struct sockaddr_nl *who,
-                       struct nlmsghdr *n, 
+int print_filter(const struct sockaddr_nl *who,
+                       struct nlmsghdr *n,
                        void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -221,13 +226,13 @@ static int print_filter(const struct sockaddr_nl *who,
                }
        }
        if (t->tcm_info) {
-               __u32 protocol = TC_H_MIN(t->tcm_info);
+               f_proto = TC_H_MIN(t->tcm_info);
                __u32 prio = TC_H_MAJ(t->tcm_info)>>16;
-               if (!filter_protocol || filter_protocol != protocol) {
-                       if (protocol) {
+               if (!filter_protocol || filter_protocol != f_proto) {
+                       if (f_proto) {
                                SPRINT_BUF(b1);
                                fprintf(fp, "protocol %s ",
-                                       ll_proto_n2a(protocol, b1, sizeof(b1)));
+                                       ll_proto_n2a(f_proto, b1, sizeof(b1)));
                        }
                }
                if (!filter_prio || filter_prio != prio) {
@@ -363,8 +368,10 @@ int do_filter(int argc, char **argv)
        if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
            || matches(*argv, "lst") == 0)
                return tc_filter_list(argc-1, argv+1);
-       if (matches(*argv, "help") == 0)
+       if (matches(*argv, "help") == 0) {
                usage();
+               return 0;
+        }
        fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv);
        return -1;
 }
diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c
new file mode 100644 (file)
index 0000000..bf58744
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * tc_monitor.c                "tc monitor".
+ *
+ *             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.
+ *
+ * Authors:    Jamal Hadi Salim
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <time.h>
+#include "rt_names.h"
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_common.h"
+
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: tc monitor\n");
+       exit(-1);
+}
+
+
+int accept_tcmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE*)arg;
+
+       if (n->nlmsg_type == RTM_NEWTFILTER || n->nlmsg_type == RTM_DELTFILTER) {
+               print_filter(who, n, arg);
+               return 0;
+       }
+       if (n->nlmsg_type == RTM_NEWTCLASS || n->nlmsg_type == RTM_DELTCLASS) {
+               print_class(who, n, arg);
+               return 0;
+       }
+       if (n->nlmsg_type == RTM_NEWQDISC || n->nlmsg_type == RTM_DELQDISC) {
+               print_qdisc(who, n, arg);
+               return 0;
+       }
+       if (n->nlmsg_type == RTM_GETACTION || n->nlmsg_type == RTM_NEWACTION ||
+           n->nlmsg_type == RTM_DELACTION) {
+               print_action(who, n, arg);
+               return 0;
+       }
+       if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
+           n->nlmsg_type != NLMSG_DONE) {
+               fprintf(fp, "Unknown message: length %08d type %08x flags %08x\n",
+                       n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+       }
+       return 0;
+}
+
+int do_tcmonitor(int argc, char **argv)
+{
+       struct rtnl_handle rth;
+       char *file = NULL;
+       unsigned groups = nl_mgrp(RTNLGRP_TC);
+
+       while (argc > 0) {
+               if (matches(*argv, "file") == 0) {
+                       NEXT_ARG();
+                       file = *argv;
+               } else {
+                       if (matches(*argv, "help") == 0) {
+                               usage();
+                       } else {
+                               fprintf(stderr, "Argument \"%s\" is unknown, try \"tc monitor help\".\n", *argv);
+                               exit(-1);
+                       }
+               }
+               argc--; argv++;
+       }
+
+       if (file) {
+               FILE *fp;
+               fp = fopen(file, "r");
+               if (fp == NULL) {
+                       perror("Cannot fopen");
+                       exit(-1);
+               }
+               return rtnl_from_file(fp, accept_tcmsg, (void*)stdout);
+       }
+
+       if (rtnl_open(&rth, groups) < 0)
+               exit(1);
+
+       ll_init_map(&rth);
+
+       if (rtnl_listen(&rth, accept_tcmsg, (void*)stdout) < 0) {
+               rtnl_close(&rth);
+               exit(2);
+       }
+
+       rtnl_close(&rth);
+       exit(0);
+}
index e9174ab..c7f2988 100644 (file)
@@ -20,6 +20,7 @@
 #include <arpa/inet.h>
 #include <string.h>
 #include <math.h>
+#include <malloc.h>
 
 #include "utils.h"
 #include "tc_util.h"
@@ -29,15 +30,17 @@ static int usage(void);
 
 static int usage(void)
 {
-       fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | get ] dev STRING\n");
+       fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | show ] dev STRING\n");
        fprintf(stderr, "       [ handle QHANDLE ] [ root | ingress | parent CLASSID ]\n");
        fprintf(stderr, "       [ estimator INTERVAL TIME_CONSTANT ]\n");
+       fprintf(stderr, "       [ stab [ help | STAB_OPTIONS] ]\n");
        fprintf(stderr, "       [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "       tc qdisc show [ dev STRING ] [ingress]\n");
        fprintf(stderr, "Where:\n");
        fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n");
        fprintf(stderr, "OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help\n");
+       fprintf(stderr, "STAB_OPTIONS := ... try tc qdisc add stab help\n");
        return -1;
 }
 
@@ -45,6 +48,10 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
 {
        struct qdisc_util *q = NULL;
        struct tc_estimator est;
+       struct {
+               struct tc_sizespec      szopts;
+               __u16                   *data;
+       } stab;
        char  d[16];
        char  k[16];
        struct {
@@ -54,6 +61,7 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
        } req;
 
        memset(&req, 0, sizeof(req));
+       memset(&stab, 0, sizeof(stab));
        memset(&est, 0, sizeof(est));
        memset(&d, 0, sizeof(d));
        memset(&k, 0, sizeof(k));
@@ -108,6 +116,10 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
                } else if (matches(*argv, "estimator") == 0) {
                        if (parse_estimator(&argc, &argv, &est))
                                return -1;
+               } else if (matches(*argv, "stab") == 0) {
+                       if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
+                               return -1;
+                       continue;
                } else if (matches(*argv, "help") == 0) {
                        usage();
                } else {
@@ -142,6 +154,26 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
                }
        }
 
+       if (check_size_table_opts(&stab.szopts)) {
+               struct rtattr *tail;
+
+               if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
+                       fprintf(stderr, "failed to calculate size table.\n");
+                       return -1;
+               }
+
+               tail = NLMSG_TAIL(&req.n);
+               addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
+               addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
+                         sizeof(stab.szopts));
+               if (stab.data)
+                       addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
+                                 stab.szopts.tsize * sizeof(__u16));
+               tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
+               if (stab.data)
+                       free(stab.data);
+       }
+
        if (d[0])  {
                int idx;
 
@@ -154,7 +186,7 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
                req.t.tcm_ifindex = idx;
        }
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
                return 2;
 
        return 0;
@@ -162,8 +194,8 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
 
 static int filter_ifindex;
 
-static int print_qdisc(const struct sockaddr_nl *who, 
-                      struct nlmsghdr *n, 
+int print_qdisc(const struct sockaddr_nl *who,
+                      struct nlmsghdr *n,
                       void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -209,13 +241,13 @@ static int print_qdisc(const struct sockaddr_nl *who,
        if (t->tcm_info != 1) {
                fprintf(fp, "refcnt %d ", t->tcm_info);
        }
-       /* pfifo_fast is generic enough to warrant the hardcoding --JHS */      
-               
+       /* pfifo_fast is generic enough to warrant the hardcoding --JHS */
+
        if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])))
                q = get_qdisc_kind("prio");
        else
                q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));
-       
+
        if (tb[TCA_OPTIONS]) {
                if (q)
                        q->print_qopt(q, fp, tb[TCA_OPTIONS]);
@@ -223,6 +255,10 @@ static int print_qdisc(const struct sockaddr_nl *who,
                        fprintf(fp, "[cannot parse qdisc parameters]");
        }
        fprintf(fp, "\n");
+       if (show_details && tb[TCA_STAB]) {
+               print_size_table(fp, " ", tb[TCA_STAB]);
+               fprintf(fp, "\n");
+       }
        if (show_stats) {
                struct rtattr *xstats = NULL;
 
@@ -249,7 +285,7 @@ int tc_qdisc_list(int argc, char **argv)
        memset(&t, 0, sizeof(t));
        t.tcm_family = AF_UNSPEC;
        memset(&d, 0, sizeof(d));
-       
+
        while (argc > 0) {
                if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
@@ -316,8 +352,10 @@ int do_qdisc(int argc, char **argv)
        if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
            || matches(*argv, "lst") == 0)
                return tc_qdisc_list(argc-1, argv+1);
-       if (matches(*argv, "help") == 0)
+       if (matches(*argv, "help") == 0) {
                usage();
+               return 0;
+        }
        fprintf(stderr, "Command \"%s\" is unknown, try \"tc qdisc help\".\n", *argv);
        return -1;
 }
index 385e7af..8f9bde0 100644 (file)
@@ -71,7 +71,7 @@ int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt)
 
 int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf)
 {
-       double xmit_time = tc_core_usec2tick(1000000*(double)avpkt/bps);
+       double xmit_time = tc_calc_xmittime(bps, avpkt);
        double lW = -log(1.0 - 1.0/(1<<Wlog))/xmit_time;
        double maxtime = 31/lW;
        int clog;
diff --git a/tc/tc_stab.c b/tc/tc_stab.c
new file mode 100644 (file)
index 0000000..47b4e5e
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * tc_stab.c           "tc qdisc ... stab *".
+ *
+ *             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.
+ *
+ * Authors:    Jussi Kivilinna, <jussi.kivilinna@mbnet.fi>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_core.h"
+#include "tc_common.h"
+
+static void stab_help(void)
+{
+       fprintf(stderr,
+               "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ] \n"
+               "                [ overhead BYTES ] [ linklayer TYPE ] ...\n"
+               "   mtu       : max packet size we create rate map for {2047}\n"
+               "   tsize     : how many slots should size table have {512}\n"
+               "   mpu       : minimum packet size used in rate computations\n"
+               "   overhead  : per-packet size overhead used in rate computations\n"
+               "   linklayer : adapting to a linklayer e.g. atm\n"
+               "Example: ... stab overhead 20 linklayer atm\n");
+
+       return;
+}
+
+int check_size_table_opts(struct tc_sizespec *s)
+{
+       return s->linklayer >= LINKLAYER_ETHERNET || s->mpu != 0 ||
+                                                       s->overhead != 0;
+}
+
+int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp)
+{
+       char **argv = *argvp;
+       int argc = *argcp;
+       struct tc_sizespec s;
+
+       memset(&s, 0, sizeof(s));
+
+       NEXT_ARG();
+       if (matches(*argv, "help") == 0) {
+               stab_help();
+               return -1;
+       }
+       while (argc > 0) {
+               if (matches(*argv, "mtu") == 0) {
+                       NEXT_ARG();
+                       if (s.mtu)
+                               duparg("mtu", *argv);
+                       if (get_u32(&s.mtu, *argv, 10)) {
+                               invarg("mtu", "invalid mtu");
+                               return -1;
+                       }
+               } else if (matches(*argv, "mpu") == 0) {
+                       NEXT_ARG();
+                       if (s.mpu)
+                               duparg("mpu", *argv);
+                       if (get_u32(&s.mpu, *argv, 10)) {
+                               invarg("mpu", "invalid mpu");
+                               return -1;
+                       }
+               } else if (matches(*argv, "overhead") == 0) {
+                       NEXT_ARG();
+                       if (s.overhead)
+                               duparg("overhead", *argv);
+                       if (get_integer(&s.overhead, *argv, 10)) {
+                               invarg("overhead", "invalid overhead");
+                               return -1;
+                       }
+               } else if (matches(*argv, "tsize") == 0) {
+                       NEXT_ARG();
+                       if (s.tsize)
+                               duparg("tsize", *argv);
+                       if (get_u32(&s.tsize, *argv, 10)) {
+                               invarg("tsize", "invalid table size");
+                               return -1;
+                       }
+               } else if (matches(*argv, "linklayer") == 0) {
+                       NEXT_ARG();
+                       if (s.linklayer != LINKLAYER_UNSPEC)
+                               duparg("linklayer", *argv);
+                       if (get_linklayer(&s.linklayer, *argv)) {
+                               invarg("linklayer", "invalid linklayer");
+                               return -1;
+                       }
+               } else
+                       break;
+               argc--; argv++;
+       }
+
+       if (!check_size_table_opts(&s))
+               return -1;
+
+       *sp = s;
+       *argvp = argv;
+       *argcp = argc;
+       return 0;
+}
+
+void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta)
+{
+       struct rtattr *tb[TCA_STAB_MAX + 1];
+       SPRINT_BUF(b1);
+
+       parse_rtattr_nested(tb, TCA_STAB_MAX, rta);
+
+       if (tb[TCA_STAB_BASE]) {
+               struct tc_sizespec s = {0};
+               memcpy(&s, RTA_DATA(tb[TCA_STAB_BASE]),
+                               MIN(RTA_PAYLOAD(tb[TCA_STAB_BASE]), sizeof(s)));
+
+               fprintf(fp, "%s", prefix);
+               if (s.linklayer)
+                       fprintf(fp, "linklayer %s ",
+                                       sprint_linklayer(s.linklayer, b1));
+               if (s.overhead)
+                       fprintf(fp, "overhead %d ", s.overhead);
+               if (s.mpu)
+                       fprintf(fp, "mpu %u ", s.mpu);
+               if (s.mtu)
+                       fprintf(fp, "mtu %u ", s.mtu);
+               if (s.tsize)
+                       fprintf(fp, "tsize %u ", s.tsize);
+       }
+
+#if 0
+       if (tb[TCA_STAB_DATA]) {
+               unsigned i, j, dlen;
+               __u16 *data = RTA_DATA(tb[TCA_STAB_DATA]);
+               dlen = RTA_PAYLOAD(tb[TCA_STAB_DATA]) / sizeof(__u16);
+
+               fprintf(fp, "\n%sstab data:", prefix);
+               for (i = 0; i < dlen/12; i++) {
+                       fprintf(fp, "\n%s %3u:", prefix, i * 12);
+                       for (j = 0; i * 12 + j < dlen; j++)
+                               fprintf(fp, " %05x", data[i * 12 + j]);
+               }
+       }
+#endif
+}
+
index 9cde144..fe2c7eb 100644 (file)
 #include "utils.h"
 #include "tc_util.h"
 
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+const char *get_tc_lib(void)
+{
+       const char *lib_dir;
+
+       lib_dir = getenv("TC_LIB_DIR");
+       if (!lib_dir)
+               lib_dir = LIBDIR "/tc/";
+
+       return lib_dir;
+}
+
 int get_qdisc_handle(__u32 *h, const char *str)
 {
        __u32 maj;
@@ -209,7 +224,7 @@ char * sprint_rate(__u32 rate, char *buf)
        return buf;
 }
 
-int get_usecs(unsigned *usecs, const char *str)
+int get_time(unsigned *time, const char *str)
 {
        double t;
        char *p;
@@ -221,40 +236,45 @@ int get_usecs(unsigned *usecs, const char *str)
        if (*p) {
                if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
                    strcasecmp(p, "secs")==0)
-                       t *= 1000000;
+                       t *= TIME_UNITS_PER_SEC;
                else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
                         strcasecmp(p, "msecs") == 0)
-                       t *= 1000;
+                       t *= TIME_UNITS_PER_SEC/1000;
                else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
                         strcasecmp(p, "usecs") == 0)
-                       t *= 1;
+                       t *= TIME_UNITS_PER_SEC/1000000;
                else
                        return -1;
        }
 
-       *usecs = t;
+       *time = t;
        return 0;
 }
 
 
-void print_usecs(char *buf, int len, __u32 usec)
+void print_time(char *buf, int len, __u32 time)
 {
-       double tmp = usec;
+       double tmp = time;
 
-       if (tmp >= 1000000)
-               snprintf(buf, len, "%.1fs", tmp/1000000);
-       else if (tmp >= 1000)
-               snprintf(buf, len, "%.1fms", tmp/1000);
+       if (tmp >= TIME_UNITS_PER_SEC)
+               snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
+       else if (tmp >= TIME_UNITS_PER_SEC/1000)
+               snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
        else
-               snprintf(buf, len, "%uus", usec);
+               snprintf(buf, len, "%uus", time);
 }
 
-char * sprint_usecs(__u32 usecs, char *buf)
+char * sprint_time(__u32 time, char *buf)
 {
-       print_usecs(buf, SPRINT_BSIZE-1, usecs);
+       print_time(buf, SPRINT_BSIZE-1, time);
        return buf;
 }
 
+char * sprint_ticks(__u32 ticks, char *buf)
+{
+       return sprint_time(tc_core_tick2time(ticks), buf);
+}
+
 int get_size(unsigned *size, const char *str)
 {
        double sz;
@@ -419,6 +439,47 @@ int action_a2n(char *arg, int *result)
        return 0;
 }
 
+int get_linklayer(unsigned *val, const char *arg)
+{
+       int res;
+
+       if (matches(arg, "ethernet") == 0)
+               res = LINKLAYER_ETHERNET;
+       else if (matches(arg, "atm") == 0)
+               res = LINKLAYER_ATM;
+       else if (matches(arg, "adsl") == 0)
+               res = LINKLAYER_ATM;
+       else
+               return -1; /* Indicate error */
+
+       *val = res;
+       return 0;
+}
+
+void print_linklayer(char *buf, int len, unsigned linklayer)
+{
+       switch (linklayer) {
+       case LINKLAYER_UNSPEC:
+               snprintf(buf, len, "%s", "unspec");
+               return;
+       case LINKLAYER_ETHERNET:
+               snprintf(buf, len, "%s", "ethernet");
+               return;
+       case LINKLAYER_ATM:
+               snprintf(buf, len, "%s", "atm");
+               return;
+       default:
+               snprintf(buf, len, "%s", "unknown");
+               return;
+       }
+}
+
+char *sprint_linklayer(unsigned linklayer, char *buf)
+{
+       print_linklayer(buf, SPRINT_BSIZE-1, linklayer);
+       return buf;
+}
+
 void print_tm(FILE * f, const struct tcf_t *tm)
 {
        int hz = get_user_hz();
@@ -450,7 +511,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
                fprintf(fp, " (dropped %u, overlimits %u requeues %u) ",
                        q.drops, q.overlimits, q.requeues);
        }
-                       
+
        if (tbs[TCA_STATS_RATE_EST]) {
                struct gnet_stats_rate_est re = {0};
                memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re)));
@@ -490,7 +551,7 @@ void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtat
                memcpy(&st, RTA_DATA(tb[TCA_STATS]), MIN(RTA_PAYLOAD(tb[TCA_STATS]), sizeof(st)));
 
                fprintf(fp, "%sSent %llu bytes %u pkts (dropped %u, overlimits %u) ",
-                       prefix, (unsigned long long)st.bytes, st.packets, st.drops, 
+                       prefix, (unsigned long long)st.bytes, st.packets, st.drops,
                        st.overlimits);
 
                if (st.bps || st.pps || st.qlen || st.backlog) {
index 1aa1bda..d84b09a 100644 (file)
@@ -7,6 +7,18 @@
 #include <linux/gen_stats.h>
 #include "tc_core.h"
 
+/* This is the deprecated multiqueue interface */
+#ifndef TCA_PRIO_MAX
+enum
+{
+       TCA_PRIO_UNSPEC,
+       TCA_PRIO_MQ,
+       __TCA_PRIO_MAX
+};
+
+#define TCA_PRIO_MAX    (__TCA_PRIO_MAX - 1)
+#endif
+
 struct qdisc_util
 {
        struct  qdisc_util *next;
@@ -19,11 +31,12 @@ struct qdisc_util
        int     (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
 };
 
+extern __u16 f_proto;
 struct filter_util
 {
        struct filter_util *next;
        char    id[16];
-       int     (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc, 
+       int     (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc,
                              char **argv, struct nlmsghdr *n);
        int     (*print_fopt)(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle);
 };
@@ -32,12 +45,14 @@ struct action_util
 {
        struct  action_util *next;
        char    id[16];
-       int     (*parse_aopt)(struct action_util *a, int *argc, char ***argv, 
+       int     (*parse_aopt)(struct action_util *a, int *argc, char ***argv,
                              int code, struct nlmsghdr *n);
        int     (*print_aopt)(struct action_util *au, FILE *f, struct rtattr *opt);
        int     (*print_xstats)(struct action_util *au, FILE *f, struct rtattr *xstats);
 };
 
+extern const char *get_tc_lib(void);
+
 extern struct qdisc_util *get_qdisc_kind(const char *str);
 extern struct filter_util *get_filter_kind(const char *str);
 
@@ -46,18 +61,23 @@ extern int get_rate(unsigned *rate, const char *str);
 extern int get_percent(unsigned *percent, const char *str);
 extern int get_size(unsigned *size, const char *str);
 extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
-extern int get_usecs(unsigned *usecs, const char *str);
+extern int get_time(unsigned *time, const char *str);
+extern int get_linklayer(unsigned *val, const char *arg);
+
 extern void print_rate(char *buf, int len, __u32 rate);
 extern void print_size(char *buf, int len, __u32 size);
 extern void print_percent(char *buf, int len, __u32 percent);
 extern void print_qdisc_handle(char *buf, int len, __u32 h);
-extern void print_usecs(char *buf, int len, __u32 usecs);
+extern void print_time(char *buf, int len, __u32 time);
+extern void print_linklayer(char *buf, int len, unsigned linklayer);
 extern char * sprint_rate(__u32 rate, char *buf);
 extern char * sprint_size(__u32 size, char *buf);
 extern char * sprint_qdisc_handle(__u32 h, char *buf);
 extern char * sprint_tc_classid(__u32 h, char *buf);
-extern char * sprint_usecs(__u32 usecs, char *buf);
+extern char * sprint_time(__u32 time, char *buf);
+extern char * sprint_ticks(__u32 ticks, char *buf);
 extern char * sprint_percent(__u32 percent, char *buf);
+extern char * sprint_linklayer(unsigned linklayer, char *buf);
 
 extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats);
 extern void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats);
@@ -72,9 +92,9 @@ extern int parse_police(int *, char ***, int, struct nlmsghdr *);
 extern char *action_n2a(int action, char *buf, int len);
 extern int  action_a2n(char *arg, int *result);
 extern int  act_parse_police(struct action_util *a,int *, char ***, int, struct nlmsghdr *);
-extern int  print_police(struct action_util *a, FILE *f, 
+extern int  print_police(struct action_util *a, FILE *f,
                         struct rtattr *tb);
-extern int  police_print_xstats(struct action_util *a,FILE *f, 
+extern int  police_print_xstats(struct action_util *a,FILE *f,
                                struct rtattr *tb);
 extern int  tc_print_action(FILE *f, const struct rtattr *tb);
 extern int  tc_print_ipt(FILE *f, const struct rtattr *tb);
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)