From: Sapan Bhatia Date: Thu, 26 Feb 2009 13:54:16 +0000 (+0000) Subject: Checkign in new iproute2 X-Git-Url: http://git.onelab.eu/?p=iproute2.git;a=commitdiff_plain;h=7132284647c15ca30d942926bc506d6019d3b61c Checkign in new iproute2 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8199aae --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Config +*.o +*.a +*.so +*~ diff --git a/COPYING b/COPYING index 2b7b643..3912109 100644 --- 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. - Copyright (C) 19yy + Copyright (C) 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 index 0000000..4360f0f --- /dev/null +++ b/Config @@ -0,0 +1 @@ +# Generated config based on /d/Projects/iproute2-2.6.28/include diff --git a/Makefile b/Makefile index ac58cd9..6096a99 100644 --- 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 --- 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. diff --git a/doc/actions/actions-general b/doc/actions/actions-general index bb2295d..70f7cd6 100644 --- a/doc/actions/actions-general +++ b/doc/actions/actions-general @@ -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 diff --git a/doc/actions/dummy-README b/doc/actions/ifb-README similarity index 58% rename from doc/actions/dummy-README rename to doc/actions/ifb-README index 3ef9f21..3d01179 100644 --- a/doc/actions/dummy-README +++ b/doc/actions/ifb-README @@ -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 dummy0 +# redirect all IP packets arriving in eth0 to ifb0 # 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]. diff --git a/doc/actions/mirred-usage b/doc/actions/mirred-usage index aa942e5..2622c43 100644 --- a/doc/actions/mirred-usage +++ b/doc/actions/mirred-usage @@ -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 := 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 diff --git a/doc/do-psnup b/doc/do-psnup old mode 100755 new mode 100644 diff --git a/doc/ip-cref.tex b/doc/ip-cref.tex index 5eaa4a8..bb4eb78 100644 --- a/doc/ip-cref.tex +++ b/doc/ip-cref.tex @@ -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//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| diff --git a/etc/iproute2/rt_dsfield b/etc/iproute2/rt_dsfield index 110061a..496ef66 100644 --- a/etc/iproute2/rt_dsfield +++ b/etc/iproute2/rt_dsfield @@ -1,3 +1,4 @@ +0x00 default 0x10 lowdelay 0x08 throughput 0x04 reliability @@ -11,3 +12,16 @@ 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 diff --git a/examples/cbqinit.eth1 b/examples/cbqinit.eth1 old mode 100755 new mode 100644 diff --git a/examples/dhcp-client-script b/examples/dhcp-client-script old mode 100755 new mode 100644 diff --git a/genl/.gitignore b/genl/.gitignore new file mode 100644 index 0000000..383ef04 --- /dev/null +++ b/genl/.gitignore @@ -0,0 +1 @@ +genl diff --git a/genl/Makefile b/genl/Makefile new file mode 100644 index 0000000..6435875 --- /dev/null +++ b/genl/Makefile @@ -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 index 0000000..30ea4d7 --- /dev/null +++ b/genl/ctrl.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \n" \ + "CMD := get | list | monitor\n" \ + "PARMS := name | 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 index 0000000..3ae75ae --- /dev/null +++ b/genl/genl.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 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 index 0000000..85b5183 --- /dev/null +++ b/genl/genl_utils.h @@ -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 diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index 9438c0f..f97113f 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static char SNAPSHOT[] = "060323"; +static const char SNAPSHOT[] = "090115"; diff --git a/include/ip6tables.h b/include/ip6tables.h index 8360617..1050593 100644 --- a/include/ip6tables.h +++ b/include/ip6tables.h @@ -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); diff --git a/include/iptables.h b/include/iptables.h index 25f36ae..dd844c1 100644 --- a/include/iptables.h +++ b/include/iptables.h @@ -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); diff --git a/include/iptables_common.h b/include/iptables_common.h index ed5b9c0..9099667 100644 --- a/include/iptables_common.h +++ b/include/iptables_common.h @@ -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*/ diff --git a/include/libiptc/ipt_kernel_headers.h b/include/libiptc/ipt_kernel_headers.h index 18861fe..7e87828 100644 --- a/include/libiptc/ipt_kernel_headers.h +++ b/include/libiptc/ipt_kernel_headers.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #else /* libc5 */ #include diff --git a/include/libnetlink.h b/include/libnetlink.h index 63cc3c8..0e02468 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include 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 index 0000000..6de1627 --- /dev/null +++ b/include/linux/atm.h @@ -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 directly. + * Instead, #include + */ + +#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 +#include +#include +#include + + +/* 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 index 0000000..8fe54d9 --- /dev/null +++ b/include/linux/atmapi.h @@ -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 index 0000000..37f67aa --- /dev/null +++ b/include/linux/atmioc.h @@ -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 + /* 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 index 0000000..799b104 --- /dev/null +++ b/include/linux/atmsap.h @@ -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 + +/* + * 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 index 0000000..87b606b --- /dev/null +++ b/include/linux/fib_rules.h @@ -0,0 +1,71 @@ +#ifndef __LINUX_FIB_RULES_H +#define __LINUX_FIB_RULES_H + +#include +#include + +/* 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 index 0000000..7da02c9 --- /dev/null +++ b/include/linux/genetlink.h @@ -0,0 +1,82 @@ +#ifndef __LINUX_GENERIC_NETLINK_H +#define __LINUX_GENERIC_NETLINK_H + +#include + +#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 index 0000000..5839723 --- /dev/null +++ b/include/linux/hdlc/ioctl.h @@ -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 index 0000000..2c3ccc7 --- /dev/null +++ b/include/linux/if.h @@ -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, + * + * 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 /* for "__kernel_caddr_t" et al */ +#include /* for "struct sockaddr" et al */ + /* for "__user" et al */ + +#define IFNAMSIZ 16 +#define IFALIASZ 256 +#include + +/* 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 index 0000000..befcb3c --- /dev/null +++ b/include/linux/if_addr.h @@ -0,0 +1,60 @@ +#ifndef __LINUX_IF_ADDR_H +#define __LINUX_IF_ADDR_H + +#include + +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 index 0000000..9fe79c9 --- /dev/null +++ b/include/linux/if_addrlabel.h @@ -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 + */ + +#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 diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 9b3382d..977c4de 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -9,7 +9,7 @@ * * Author: Fred N. van Kempen, * Donald Becker, - * Alan Cox, + * Alan Cox, * Steve Whitehouse, * * 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 */ @@ -75,8 +75,10 @@ #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) */ @@ -99,6 +102,9 @@ #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 - -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 index 0000000..c1fd1a8 --- /dev/null +++ b/include/linux/if_link.h @@ -0,0 +1,190 @@ +#ifndef _LINUX_IF_LINK_H +#define _LINUX_IF_LINK_H + +#include + +/* 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 */ diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 53435b9..aeab2cb 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -2,11 +2,16 @@ #define _IF_TUNNEL_H_ #include +#include #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 index 0000000..2dc4a57 --- /dev/null +++ b/include/linux/if_vlan.h @@ -0,0 +1,62 @@ +/* + * VLAN An implementation of 802.1Q VLAN tagging. + * + * Authors: Ben Greear + * + * 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_) */ diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 85d456d..1ae9303 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -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 index 0000000..1e7cc4a --- /dev/null +++ b/include/linux/ip6_tunnel.h @@ -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 index e234e20..0000000 --- a/include/linux/ip_mp_alg.h +++ /dev/null @@ -1,22 +0,0 @@ -/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values. - * - * Copyright (C) 2004, 2005 Einar Lueck - * Copyright (C) 2005 David S. Miller - */ - -#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 index 0000000..bd3bbf6 --- /dev/null +++ b/include/linux/neighbour.h @@ -0,0 +1,159 @@ +#ifndef __LINUX_NEIGHBOUR_H +#define __LINUX_NEIGHBOUR_H + +#include + +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 index 0000000..2eb00b6 --- /dev/null +++ b/include/linux/netfilter.h @@ -0,0 +1,59 @@ +#ifndef __LINUX_NETFILTER_H +#define __LINUX_NETFILTER_H + +#include + + +/* 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 index 0000000..89eae5c --- /dev/null +++ b/include/linux/netfilter/x_tables.h @@ -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 index 0000000..78bc65f --- /dev/null +++ b/include/linux/netfilter/xt_tcpudp.h @@ -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 index 0000000..4d7ba3e --- /dev/null +++ b/include/linux/netfilter_ipv4.h @@ -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 + +/* 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*/ diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 17d8eff..a9f21c9 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -15,10 +15,18 @@ #ifndef _IPTABLES_H #define _IPTABLES_H +#include + #include -#define IPT_FUNCTION_MAXNAMELEN 30 -#define IPT_TABLE_MAXNAMELEN 32 +#include + +#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 +#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. diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 24a38ae..5593f05 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -5,7 +5,7 @@ #include #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 */ @@ -21,14 +21,19 @@ #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))) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index bd2c5a2..7cf7824 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -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 { diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index d10f353..5d921fa 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -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. * diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 7504618..f43140a 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -2,6 +2,9 @@ #define __LINUX_RTNETLINK_H #include +#include +#include +#include /**** * 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) diff --git a/include/linux/socket.h b/include/linux/socket.h index dc979c0..0a2418d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -1 +1,304 @@ -#include +#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 /* arch-dependent defines */ +#include /* the SIOCxxx I/O controls */ +#include /* iovec support */ +#include /* 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 index 964f473..0000000 --- a/include/linux/tc_act/tc_defact.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __LINUX_TC_DEF_H -#define __LINUX_TC_DEF_H - -#include - -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 index 0000000..e7cf31e --- /dev/null +++ b/include/linux/tc_act/tc_nat.h @@ -0,0 +1,29 @@ +#ifndef __LINUX_TC_NAT_H +#define __LINUX_TC_NAT_H + +#include +#include + +#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 index 0000000..a14e461 --- /dev/null +++ b/include/linux/tc_act/tc_skbedit.h @@ -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 + */ + +#ifndef __LINUX_TC_SKBEDIT_H +#define __LINUX_TC_SKBEDIT_H + +#include + +#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 diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h index e21937c..c50d2ba 100644 --- a/include/linux/tc_ematch/tc_em_meta.h +++ b/include/linux/tc_ematch/tc_em_meta.h @@ -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 index b4d74eb..0000000 --- a/include/linux/tcp.h +++ /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, - * - * 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 -#include - -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 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< +#include + +#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 index 0000000..3354c1e --- /dev/null +++ b/include/linux/veth.h @@ -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 diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index f2bbf4b..da2f1fe 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -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) diff --git a/include/ll_map.h b/include/ll_map.h index d085813..c4d5c6d 100644 --- a/include/ll_map.h +++ b/include/ll_map.h @@ -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 index b0b6459..0000000 --- a/include/net/tcp_states.h +++ /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 index 0000000..282b29c --- /dev/null +++ b/include/netinet/tcp.h @@ -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 + +/* + * 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 + +# 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 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 */ diff --git a/include/rt_names.h b/include/rt_names.h index 2d9ef10..07a10e0 100644 --- a/include/rt_names.h +++ b/include/rt_names.h @@ -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); diff --git a/include/utils.h b/include/utils.h index 0f1d1f6..f7ef939 100644 --- a/include/utils.h +++ b/include/utils.h @@ -3,6 +3,7 @@ #include #include +#include #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 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 diff --git a/ip/.gitignore b/ip/.gitignore new file mode 100644 index 0000000..b95b232 --- /dev/null +++ b/ip/.gitignore @@ -0,0 +1,2 @@ +ip +rtmon diff --git a/ip/Makefile b/ip/Makefile index 3383c72..98ba876 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -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 diff --git a/ip/ifcfg b/ip/ifcfg old mode 100755 new mode 100644 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 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 --- a/ip/ip.c +++ b/ip/ip.c @@ -30,13 +30,14 @@ 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 index 0000000..8421983 --- /dev/null +++ b/ip/ip6tunnel.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/ip/ip_common.h b/ip/ip_common.h index 1fe4a69..273065f 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -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 diff --git a/ip/ipaddress.c b/ip/ipaddress.c index cb164c0..a732d80 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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 index 0000000..cf438d6 --- /dev/null +++ b/ip/ipaddrlabel.c @@ -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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/ip/iplink.c b/ip/iplink.c index ffc9f06..fd23db1 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -31,23 +32,47 @@ #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 index 0000000..9724482 --- /dev/null +++ b/ip/iplink_vlan.c @@ -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 + */ + +#include +#include +#include +#include + +#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, +}; diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c index e6bd625..44ffdfc 100644 --- a/ip/ipmaddr.c +++ b/ip/ipmaddr.c @@ -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); diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 50b6327..df0fd91 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -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) { diff --git a/ip/ipmroute.c b/ip/ipmroute.c index 951a54f..8f4b061 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -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))); diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 249ee68..30c7c72 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -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; } diff --git a/ip/ipntable.c b/ip/ipntable.c index 5655d93..141ad42 100644 --- a/ip/ipntable.c +++ b/ip/ipntable.c @@ -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 diff --git a/ip/ipprefix.c b/ip/ipprefix.c index 61d12f9..cb1f582 100644 --- a/ip/ipprefix.c +++ b/ip/ipprefix.c @@ -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); diff --git a/ip/iproute.c b/ip/iproute.c index a43c09e..6a2ea05 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "rt_names.h" #include "utils.h" @@ -39,6 +38,20 @@ #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<= 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<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); diff --git a/ip/iprule.c b/ip/iprule.c index ccf699f..e1a943a 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -24,9 +24,11 @@ #include #include #include +#include #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; diff --git a/ip/iptunnel.c b/ip/iptunnel.c index 35b0895..0d9a17f 100644 --- a/ip/iptunnel.c +++ b/ip/iptunnel.c @@ -20,31 +20,26 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include #include #include - -#ifndef __constant_htons -#define __constant_htons(x) htons(x) -#endif - #include #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); diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 8baaabd..24b2114 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -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 #include #include -#include #include #include #include @@ -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 index 0000000..9109312 --- /dev/null +++ b/ip/link_gre.c @@ -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 + * + */ + +#include +#include +#include +#include +#include +#include + +#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 index 0000000..9f5e871 --- /dev/null +++ b/ip/link_veth.c @@ -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 + * + */ + +#include +#include +#include + +#include "utils.h" +#include "ip_common.h" + +static void usage(void) +{ + printf("Usage: ip link type veth " + "[peer ]\nTo get 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, +}; diff --git a/ip/routef b/ip/routef old mode 100755 new mode 100644 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 diff --git a/ip/routel b/ip/routel old mode 100755 new mode 100644 diff --git a/ip/rtmon.c b/ip/rtmon.c index 5ce7731..7869b32 100644 --- a/ip/rtmon.c +++ b/ip/rtmon.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -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 new mode 100644 diff --git a/ip/tunnel.c b/ip/tunnel.c new file mode 100644 index 0000000..104340d --- /dev/null +++ b/ip/tunnel.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..1b58834 --- /dev/null +++ b/ip/tunnel.h @@ -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 + +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 diff --git a/ip/xfrm.h b/ip/xfrm.h index 4833b36..930bb3f 100644 --- 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); diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c index 153621f..dc12fca 100644 --- a/ip/xfrm_monitor.c +++ b/ip/xfrm_monitor.c @@ -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; diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c index 433b513..11116e5 100644 --- a/ip/xfrm_policy.c +++ b/ip/xfrm_policy.c @@ -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); diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index 3eefaff..b1e3f22 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -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 index 022a794..0000000 --- a/iproute.spec +++ /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 -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 2.6.11-1 -- update to iproute-2.6.11 - -* Fri Mar 04 2005 Radek Vokal 2.6.10-2 -- gcc4 rebuilt - -* Wed Feb 16 2005 Radek Vokal 2.6.10-1 -- update to iproute-2.6.10 - -* Thu Dec 23 2004 Radek Vokal 2.6.9-6 -- added arpd into sbin - -* Mon Nov 29 2004 Radek Vokal 2.6.9-5 -- debug info removed from makefile and from spec (#140891) - -* Tue Nov 16 2004 Radek Vokal 2.6.9-4 -- source file updated from snapshot version -- endian patch adding - -* Sat Sep 18 2004 Joshua Blanton 2.6.9-3 -- added installation of netem module for tc - -* Mon Sep 06 2004 Radek Vokal 2.6.9-2 -- fixed possible buffer owerflow, path by Steve Grubb - -* Wed Sep 01 2004 Radek Vokal 2.6.9-1 -- updated to iproute-2.6.9, spec file change, patches cleared - -* Tue Jun 15 2004 Elliot Lee -- rebuilt - -* Wed May 26 2004 Phil Knirsch 2.4.7-16 -- Took tons of manpages from debian, much more complete (#123952). - -* Thu May 06 2004 Phil Knirsch 2.4.7-15 -- rebuilt - -* Thu May 06 2004 Phil Knirsch 2.4.7-13.2 -- Built security errata version for FC1. - -* Wed Apr 21 2004 Phil Knirsch 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 -- rebuilt - -* Wed Nov 05 2003 Phil Knirsch 2.4.7-12 -- Security errata for netlink (CAN-2003-0856). - -* Thu Oct 23 2003 Phil Knirsch -- 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 -- rebuilt - -* Wed Jun 04 2003 Elliot Lee -- rebuilt - -* Wed Jan 22 2003 Tim Powers -- rebuilt - -* Thu Jan 16 2003 Phil Knirsch 2.4.7-7 -- Added htb3-tc patch from http://luxik.cdi.cz/~devik/qos/htb/ (#75486). - -* Fri Oct 11 2002 Bill Nottingham 2.4.7-6 -- remove flags patch at author's request - -* Fri Jun 21 2002 Tim Powers -- automated rebuild - -* Wed Jun 19 2002 Phil Knirsch 2.4.7-4 -- Don't forcibly strip binaries - -* Mon May 27 2002 Phil Knirsch 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 2.4.7-2 -- Added patch to fix crosscompiling by Adrian Linkins. - -* Fri Mar 15 2002 Phil Knirsch 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 -- allow setting of allmulti & promisc flags (#48669) - -* Mon Jul 02 2001 Than Ngo -- fix build problem in beehive if kernel-sources is not installed - -* Fri May 25 2001 Helge Deller -- 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 -- use the system headers - the included ones are broken -- ETH_P_ECHO went away - -* Sat Jan 6 2001 Jeff Johnson -- test for specific KERNEL_INCLUDE directories. - -* Thu Oct 12 2000 Than Ngo -- rebuild for 7.1 - -* Thu Oct 12 2000 Than Ngo -- add default configuration files for iproute (Bug #10549, #18887) - -* Tue Jul 25 2000 Jakub Jelinek -- fix include-glibc/ to cope with glibc 2.2 new resolver headers - -* Thu Jul 13 2000 Prospector -- automatic rebuild - -* Sun Jun 18 2000 Than Ngo -- rebuilt in the new build environment -- use RPM macros -- handle RPM_OPT_FLAGS - -* Sat Jun 03 2000 Than Ngo -- fix iproute to build with new glibc - -* Fri May 26 2000 Ngo Than -- update to 2.2.4-now-ss000305 -- add configuration files - -* Mon Sep 13 1999 Bill Nottingham -- strip binaries - -* Mon Aug 16 1999 Cristian Gafton -- first build diff --git a/lib/ipx_ntop.c b/lib/ipx_ntop.c index b2d6790..7b6d728 100644 --- a/lib/ipx_ntop.c +++ b/lib/ipx_ntop.c @@ -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; diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 67951fe..5ae64f7 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -27,7 +27,10 @@ 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; +} diff --git a/lib/ll_addr.c b/lib/ll_addr.c index 581487d..f558050 100644 --- a/lib/ll_addr.c +++ b/lib/ll_addr.c @@ -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 #include #include -#include #include #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; diff --git a/lib/ll_proto.c b/lib/ll_proto.c index 98c67fe..1057ee3 100644 --- a/lib/ll_proto.c +++ b/lib/ll_proto.c @@ -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" }, diff --git a/lib/ll_types.c b/lib/ll_types.c index 5b0f106..d47dee7 100644 --- a/lib/ll_types.c +++ b/lib/ll_types.c @@ -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 diff --git a/lib/rt_names.c b/lib/rt_names.c index 05046c2..8d019a0 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -23,6 +23,51 @@ #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; diff --git a/lib/utils.c b/lib/utils.c index 4bdda71..0bb0832 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -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; diff --git a/man/man3/libnetlink.3 b/man/man3/libnetlink.3 index 145f38d..15a478a 100644 --- a/man/man3/libnetlink.3 +++ b/man/man3/libnetlink.3 @@ -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 index 0000000..d172600 --- /dev/null +++ b/man/man8/arpd.8 @@ -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 +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 +location of database file. Default location is /var/lib/arpd/arpd.db +.TP +-a +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