--- /dev/null
+Config
+*.o
+*.a
+*.so
+*~
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.
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
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
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
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
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
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
+ Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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.
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.
--- /dev/null
+# Generated config based on /d/Projects/iproute2-2.6.28/include
-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
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:
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; \
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.
{ 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
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
+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
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
--------
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
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].
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:
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:
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
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,
(\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
prefix bits already exists. The first address is primary.
It is the leader of the group of all secondary addresses. When the leader
is deleted, all secondaries are purged too.
+There is a tweak in \verb|/proc/sys/net/ipv4/conf/<dev>/promote_secondaries|
+which activate secondaries promotion when a primary is deleted.
+To permanently enable this feature on all devices add
+\verb|net.ipv4.conf.all.promote_secondaries=1| to \verb|/etc/sysctl.conf|.
+This tweak is available in linux 2.6.15 and later.
\item \verb|dynamic|
+0x00 default
0x10 lowdelay
0x08 throughput
0x04 reliability
0xa0 critical
0xc0 internet
0xe0 network
+# Newer RFC2597 values
+0x28 AF11
+0x30 AF12
+0x38 AF13
+0x48 AF21
+0x50 AF22
+0x58 AF23
+0x68 AF31
+0x70 AF32
+0x78 AF33
+0x88 AF41
+0x90 AF42
+0x98 AF43
--- /dev/null
+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
--- /dev/null
+/*
+ * ctrl.c generic netlink controller
+ *
+ * This program is free software; you can distribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ * Johannes Berg (johannes@sipsolutions.net)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "genl_utils.h"
+
+#define GENL_MAX_FAM_OPS 256
+#define GENL_MAX_FAM_GRPS 256
+
+static int usage(void)
+{
+ fprintf(stderr,"Usage: ctrl <CMD>\n" \
+ "CMD := get <PARMS> | list | monitor\n" \
+ "PARMS := name <name> | id <id>\n" \
+ "Examples:\n" \
+ "\tctrl ls\n" \
+ "\tctrl monitor\n" \
+ "\tctrl get name foobar\n" \
+ "\tctrl get id 0xF\n");
+ return -1;
+}
+
+int genl_ctrl_resolve_family(const char *family)
+{
+ struct rtnl_handle rth;
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ int ret = 0;
+ struct {
+ struct nlmsghdr n;
+ char buf[4096];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = GENL_ID_CTRL;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+ fprintf(stderr, "Cannot open generic netlink socket\n");
+ exit(1);
+ }
+
+ addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
+ fprintf(stderr, "Error talking to the kernel\n");
+ goto errout;
+ }
+
+ {
+ struct rtattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
+ int len = nlh->nlmsg_len;
+ struct rtattr *attrs;
+
+ if (nlh->nlmsg_type != GENL_ID_CTRL) {
+ fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+ "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
+ goto errout;
+ }
+
+ if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
+ fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+ goto errout;
+ }
+
+ len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+ if (len < 0) {
+ fprintf(stderr, "wrong controller message len %d\n", len);
+ return -1;
+ }
+
+ attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+ parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+ if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+ fprintf(stderr, "Missing family id TLV\n");
+ goto errout;
+ }
+
+ ret = *(__u16 *) RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+ }
+
+errout:
+ rtnl_close(&rth);
+ return ret;
+}
+
+void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
+{
+ fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
+ if (!fl) {
+ fprintf(fp, "\n");
+ return;
+ }
+ fprintf(fp, "\t\t ");
+
+ if (fl & GENL_ADMIN_PERM)
+ fprintf(fp, " requires admin permission;");
+ if (fl & GENL_CMD_CAP_DO)
+ fprintf(fp, " can doit;");
+ if (fl & GENL_CMD_CAP_DUMP)
+ fprintf(fp, " can dumpit;");
+ if (fl & GENL_CMD_CAP_HASPOL)
+ fprintf(fp, " has policy");
+
+ fprintf(fp, "\n");
+}
+
+static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+ struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
+
+ if (arg == NULL)
+ return -1;
+
+ parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
+ if (tb[CTRL_ATTR_OP_ID]) {
+ __u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
+ fprintf(fp, " ID-0x%x ",*id);
+ }
+ /* we are only gonna do this for newer version of the controller */
+ if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
+ __u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
+ print_ctrl_cmd_flags(fp, *fl);
+ }
+ return 0;
+
+}
+
+static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+ struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
+
+ if (arg == NULL)
+ return -1;
+
+ parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
+ if (tb[2]) {
+ __u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
+ fprintf(fp, " ID-0x%x ",*id);
+ }
+ if (tb[1]) {
+ char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+ fprintf(fp, " name: %s ", name);
+ }
+ return 0;
+
+}
+
+/*
+ * The controller sends one nlmsg per family
+*/
+static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ struct rtattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *ghdr = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *attrs;
+ FILE *fp = (FILE *) arg;
+ __u32 ctrl_v = 0x1;
+
+ if (n->nlmsg_type != GENL_ID_CTRL) {
+ fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+ "nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
+ return 0;
+ }
+
+ if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
+ ghdr->cmd != CTRL_CMD_DELFAMILY &&
+ ghdr->cmd != CTRL_CMD_NEWFAMILY &&
+ ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
+ ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
+ fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+ return 0;
+ }
+
+ len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+ if (len < 0) {
+ fprintf(stderr, "wrong controller message len %d\n", len);
+ return -1;
+ }
+
+ attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+ parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+ if (tb[CTRL_ATTR_FAMILY_NAME]) {
+ char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
+ fprintf(fp, "\nName: %s\n",name);
+ }
+ if (tb[CTRL_ATTR_FAMILY_ID]) {
+ __u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+ fprintf(fp, "\tID: 0x%x ",*id);
+ }
+ if (tb[CTRL_ATTR_VERSION]) {
+ __u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
+ fprintf(fp, " Version: 0x%x ",*v);
+ ctrl_v = *v;
+ }
+ if (tb[CTRL_ATTR_HDRSIZE]) {
+ __u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
+ fprintf(fp, " header size: %d ",*h);
+ }
+ if (tb[CTRL_ATTR_MAXATTR]) {
+ __u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
+ fprintf(fp, " max attribs: %d ",*ma);
+ }
+ /* end of family definitions .. */
+ fprintf(fp,"\n");
+ if (tb[CTRL_ATTR_OPS]) {
+ struct rtattr *tb2[GENL_MAX_FAM_OPS];
+ int i=0;
+ parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
+ fprintf(fp, "\tcommands supported: \n");
+ for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
+ if (tb2[i]) {
+ fprintf(fp, "\t\t#%d: ", i);
+ if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
+ fprintf(fp, "Error printing command\n");
+ }
+ /* for next command */
+ fprintf(fp,"\n");
+ }
+ }
+
+ /* end of family::cmds definitions .. */
+ fprintf(fp,"\n");
+ }
+
+ if (tb[CTRL_ATTR_MCAST_GROUPS]) {
+ struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
+ int i;
+
+ parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
+ tb[CTRL_ATTR_MCAST_GROUPS]);
+ fprintf(fp, "\tmulticast groups:\n");
+
+ for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
+ if (tb2[i]) {
+ fprintf(fp, "\t\t#%d: ", i);
+ if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
+ fprintf(fp, "Error printing group\n");
+ /* for next group */
+ fprintf(fp,"\n");
+ }
+ }
+
+ /* end of family::groups definitions .. */
+ fprintf(fp,"\n");
+ }
+
+ fflush(fp);
+ return 0;
+}
+
+static int ctrl_list(int cmd, int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ int ret = -1;
+ char d[GENL_NAMSIZ];
+ struct {
+ struct nlmsghdr n;
+ char buf[4096];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = GENL_ID_CTRL;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+ fprintf(stderr, "Cannot open generic netlink socket\n");
+ exit(1);
+ }
+
+ if (cmd == CTRL_CMD_GETFAMILY) {
+ if (argc != 2) {
+ fprintf(stderr, "Wrong number of params\n");
+ return -1;
+ }
+
+ if (matches(*argv, "name") == 0) {
+ NEXT_ARG();
+ strncpy(d, *argv, sizeof (d) - 1);
+ addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
+ d, strlen(d) + 1);
+ } else if (matches(*argv, "id") == 0) {
+ __u16 id;
+ NEXT_ARG();
+ if (get_u16(&id, *argv, 0)) {
+ fprintf(stderr, "Illegal \"id\"\n");
+ goto ctrl_done;
+ }
+
+ addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
+
+ } else {
+ fprintf(stderr, "Wrong params\n");
+ goto ctrl_done;
+ }
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
+ fprintf(stderr, "Error talking to the kernel\n");
+ goto ctrl_done;
+ }
+
+ if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ goto ctrl_done;
+ }
+
+ }
+
+ if (cmd == CTRL_CMD_UNSPEC) {
+ nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ nlh->nlmsg_seq = rth.dump = ++rth.seq;
+
+ if (rtnl_send(&rth, (const char *) nlh, nlh->nlmsg_len) < 0) {
+ perror("Failed to send dump request\n");
+ goto ctrl_done;
+ }
+
+ rtnl_dump_filter(&rth, print_ctrl, stdout, NULL, NULL);
+
+ }
+
+ ret = 0;
+ctrl_done:
+ rtnl_close(&rth);
+ return ret;
+}
+
+static int ctrl_listen(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+
+ if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
+ fprintf(stderr, "Canot open generic netlink socket\n");
+ return -1;
+ }
+
+ if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int parse_ctrl(struct genl_util *a, int argc, char **argv)
+{
+ argv++;
+ if (--argc <= 0) {
+ fprintf(stderr, "wrong controller params\n");
+ return -1;
+ }
+
+ if (matches(*argv, "monitor") == 0)
+ return ctrl_listen(argc-1, argv+1);
+ if (matches(*argv, "get") == 0)
+ return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
+ if (matches(*argv, "list") == 0 ||
+ matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0)
+ return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ return usage();
+
+ fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl -help\".\n",
+ *argv);
+
+ return -1;
+}
+
+struct genl_util ctrl_genl_util = {
+ .name = "ctrl",
+ .parse_genlopt = parse_ctrl,
+ .print_genlopt = print_ctrl,
+};
--- /dev/null
+/*
+ * genl.c "genl" utility frontend.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Jamal Hadi Salim
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h> /* until we put our own header */
+#include "SNAPSHOT.h"
+#include "utils.h"
+#include "genl_utils.h"
+
+int show_stats = 0;
+int show_details = 0;
+int show_raw = 0;
+int resolve_hosts = 0;
+
+static void *BODY;
+static struct genl_util * genl_list;
+
+
+static int print_nofopt(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ fprintf((FILE *) arg, "unknown genl type ..\n");
+ return 0;
+}
+
+static int parse_nofopt(struct genl_util *f, int argc, char **argv)
+{
+ if (argc) {
+ fprintf(stderr, "Unknown genl \"%s\", hence option \"%s\" "
+ "is unparsable\n", f->name, *argv);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct genl_util *get_genl_kind(char *str)
+{
+ void *dlh;
+ char buf[256];
+ struct genl_util *f;
+
+ for (f = genl_list; f; f = f->next)
+ if (strcmp(f->name, str) == 0)
+ return f;
+
+ snprintf(buf, sizeof(buf), "%s.so", str);
+ dlh = dlopen(buf, RTLD_LAZY);
+ if (dlh == NULL) {
+ dlh = BODY;
+ if (dlh == NULL) {
+ dlh = BODY = dlopen(NULL, RTLD_LAZY);
+ if (dlh == NULL)
+ goto noexist;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "%s_genl_util", str);
+
+ f = dlsym(dlh, buf);
+ if (f == NULL)
+ goto noexist;
+reg:
+ f->next = genl_list;
+ genl_list = f;
+ return f;
+
+noexist:
+ f = malloc(sizeof(*f));
+ if (f) {
+ memset(f, 0, sizeof(*f));
+ strncpy(f->name, str, 15);
+ f->parse_genlopt = parse_nofopt;
+ f->print_genlopt = print_nofopt;
+ goto reg;
+ }
+ return f;
+}
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: genl [ OPTIONS ] OBJECT | help }\n"
+ "where OBJECT := { ctrl etc }\n"
+ " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }\n");
+ exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+ char *basename;
+
+ basename = strrchr(argv[0], '/');
+ if (basename == NULL)
+ basename = argv[0];
+ else
+ basename++;
+
+ while (argc > 1) {
+ if (argv[1][0] != '-')
+ break;
+ if (matches(argv[1], "-stats") == 0 ||
+ matches(argv[1], "-statistics") == 0) {
+ ++show_stats;
+ } else if (matches(argv[1], "-details") == 0) {
+ ++show_details;
+ } else if (matches(argv[1], "-raw") == 0) {
+ ++show_raw;
+ } else if (matches(argv[1], "-Version") == 0) {
+ printf("genl utility, iproute2-ss%s\n", SNAPSHOT);
+ exit(0);
+ } else if (matches(argv[1], "-help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Option \"%s\" is unknown, try "
+ "\"genl -help\".\n", argv[1]);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+
+ if (argc > 1) {
+ int ret;
+ struct genl_util *a = NULL;
+ a = get_genl_kind(argv[1]);
+ if (NULL == a) {
+ fprintf(stderr,"bad genl %s\n",argv[1]);
+ }
+
+ ret = a->parse_genlopt(a, argc-1, argv+1);
+ return ret;
+
+ if (matches(argv[1], "help") == 0)
+ usage();
+ fprintf(stderr, "Object \"%s\" is unknown, try \"genl "
+ "-help\".\n", argv[1]);
+ exit(-1);
+ }
+
+ usage();
+}
--- /dev/null
+#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
-static char SNAPSHOT[] = "060323";
+static const char SNAPSHOT[] = "090115";
struct ip6tables_target
{
struct ip6tables_target *next;
-
+
ip6t_chainlabel name;
const char *version;
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);
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);
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);
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*/
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
-#include <net/if.h>
#include <sys/types.h>
#else /* libc5 */
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
struct rtnl_handle
{
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,
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);
#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__ */
--- /dev/null
+/* atm.h - general ATM declarations */
+
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
+
+
+/*
+ * WARNING: User-space programs should not #include <linux/atm.h> directly.
+ * Instead, #include <atm.h>
+ */
+
+#ifndef _LINUX_ATM_H
+#define _LINUX_ATM_H
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+
+#include <linux/atmapi.h>
+#include <linux/atmsap.h>
+#include <linux/atmioc.h>
+#include <linux/types.h>
+
+
+/* general ATM constants */
+#define ATM_CELL_SIZE 53 /* ATM cell size incl. header */
+#define ATM_CELL_PAYLOAD 48 /* ATM payload size */
+#define ATM_AAL0_SDU 52 /* AAL0 SDU size */
+#define ATM_MAX_AAL34_PDU 65535 /* maximum AAL3/4 PDU payload */
+#define ATM_AAL5_TRAILER 8 /* AAL5 trailer size */
+#define ATM_MAX_AAL5_PDU 65535 /* maximum AAL5 PDU payload */
+#define ATM_MAX_CDV 9999 /* maximum (default) CDV */
+#define ATM_NOT_RSV_VCI 32 /* first non-reserved VCI value */
+
+#define ATM_MAX_VPI 255 /* maximum VPI at the UNI */
+#define ATM_MAX_VPI_NNI 4096 /* maximum VPI at the NNI */
+#define ATM_MAX_VCI 65535 /* maximum VCI */
+
+
+/* "protcol" values for the socket system call */
+#define ATM_NO_AAL 0 /* AAL not specified */
+#define ATM_AAL0 13 /* "raw" ATM cells */
+#define ATM_AAL1 1 /* AAL1 (CBR) */
+#define ATM_AAL2 2 /* AAL2 (VBR) */
+#define ATM_AAL34 3 /* AAL3/4 (data) */
+#define ATM_AAL5 5 /* AAL5 (data) */
+
+/*
+ * socket option name coding functions
+ *
+ * Note that __SO_ENCODE and __SO_LEVEL are somewhat a hack since the
+ * << 22 only reserves 9 bits for the level. On some architectures
+ * SOL_SOCKET is 0xFFFF, so that's a bit of a problem
+ */
+
+#define __SO_ENCODE(l,n,t) ((((l) & 0x1FF) << 22) | ((n) << 16) | \
+ sizeof(t))
+#define __SO_LEVEL_MATCH(c,m) (((c) >> 22) == ((m) & 0x1FF))
+#define __SO_NUMBER(c) (((c) >> 16) & 0x3f)
+#define __SO_SIZE(c) ((c) & 0x3fff)
+
+/*
+ * ATM layer
+ */
+
+#define SO_SETCLP __SO_ENCODE(SOL_ATM,0,int)
+ /* set CLP bit value - TODO */
+#define SO_CIRANGE __SO_ENCODE(SOL_ATM,1,struct atm_cirange)
+ /* connection identifier range; socket must be
+ bound or connected */
+#define SO_ATMQOS __SO_ENCODE(SOL_ATM,2,struct atm_qos)
+ /* Quality of Service setting */
+#define SO_ATMSAP __SO_ENCODE(SOL_ATM,3,struct atm_sap)
+ /* Service Access Point */
+#define SO_ATMPVC __SO_ENCODE(SOL_ATM,4,struct sockaddr_atmpvc)
+ /* "PVC" address (also for SVCs); get only */
+#define SO_MULTIPOINT __SO_ENCODE(SOL_ATM, 5, int)
+ /* make this vc a p2mp */
+
+
+/*
+ * Note @@@: since the socket layers don't really distinguish the control and
+ * the data plane but generally seems to be data plane-centric, any layer is
+ * about equally wrong for the SAP. If you have a better idea about this,
+ * please speak up ...
+ */
+
+
+/* ATM cell header (for AAL0) */
+
+/* BEGIN_CH */
+#define ATM_HDR_GFC_MASK 0xf0000000
+#define ATM_HDR_GFC_SHIFT 28
+#define ATM_HDR_VPI_MASK 0x0ff00000
+#define ATM_HDR_VPI_SHIFT 20
+#define ATM_HDR_VCI_MASK 0x000ffff0
+#define ATM_HDR_VCI_SHIFT 4
+#define ATM_HDR_PTI_MASK 0x0000000e
+#define ATM_HDR_PTI_SHIFT 1
+#define ATM_HDR_CLP 0x00000001
+/* END_CH */
+
+
+/* PTI codings */
+
+/* BEGIN_PTI */
+#define ATM_PTI_US0 0 /* user data cell, congestion not exp, SDU-type 0 */
+#define ATM_PTI_US1 1 /* user data cell, congestion not exp, SDU-type 1 */
+#define ATM_PTI_UCES0 2 /* user data cell, cong. experienced, SDU-type 0 */
+#define ATM_PTI_UCES1 3 /* user data cell, cong. experienced, SDU-type 1 */
+#define ATM_PTI_SEGF5 4 /* segment OAM F5 flow related cell */
+#define ATM_PTI_E2EF5 5 /* end-to-end OAM F5 flow related cell */
+#define ATM_PTI_RSV_RM 6 /* reserved for traffic control/resource mgmt */
+#define ATM_PTI_RSV 7 /* reserved */
+/* END_PTI */
+
+
+/*
+ * The following items should stay in linux/atm.h, which should be linked to
+ * netatm/atm.h
+ */
+
+/* Traffic description */
+
+#define ATM_NONE 0 /* no traffic */
+#define ATM_UBR 1
+#define ATM_CBR 2
+#define ATM_VBR 3
+#define ATM_ABR 4
+#define ATM_ANYCLASS 5 /* compatible with everything */
+
+#define ATM_MAX_PCR -1 /* maximum available PCR */
+
+struct atm_trafprm {
+ unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */
+ int max_pcr; /* maximum PCR in cells per second */
+ int pcr; /* desired PCR in cells per second */
+ int min_pcr; /* minimum PCR in cells per second */
+ int max_cdv; /* maximum CDV in microseconds */
+ int max_sdu; /* maximum SDU in bytes */
+ /* extra params for ABR */
+ unsigned int icr; /* Initial Cell Rate (24-bit) */
+ unsigned int tbe; /* Transient Buffer Exposure (24-bit) */
+ unsigned int frtt : 24; /* Fixed Round Trip Time (24-bit) */
+ unsigned int rif : 4; /* Rate Increment Factor (4-bit) */
+ unsigned int rdf : 4; /* Rate Decrease Factor (4-bit) */
+ unsigned int nrm_pres :1; /* nrm present bit */
+ unsigned int trm_pres :1; /* rm present bit */
+ unsigned int adtf_pres :1; /* adtf present bit */
+ unsigned int cdf_pres :1; /* cdf present bit*/
+ unsigned int nrm :3; /* Max # of Cells for each forward RM cell (3-bit) */
+ unsigned int trm :3; /* Time between forward RM cells (3-bit) */
+ unsigned int adtf :10; /* ACR Decrease Time Factor (10-bit) */
+ unsigned int cdf :3; /* Cutoff Decrease Factor (3-bit) */
+ unsigned int spare :9; /* spare bits */
+};
+
+struct atm_qos {
+ struct atm_trafprm txtp; /* parameters in TX direction */
+ struct atm_trafprm rxtp __ATM_API_ALIGN;
+ /* parameters in RX direction */
+ unsigned char aal __ATM_API_ALIGN;
+};
+
+/* PVC addressing */
+
+#define ATM_ITF_ANY -1 /* "magic" PVC address values */
+#define ATM_VPI_ANY -1
+#define ATM_VCI_ANY -1
+#define ATM_VPI_UNSPEC -2
+#define ATM_VCI_UNSPEC -2
+
+
+struct sockaddr_atmpvc {
+ unsigned short sap_family; /* address family, AF_ATMPVC */
+ struct { /* PVC address */
+ short itf; /* ATM interface */
+ short vpi; /* VPI (only 8 bits at UNI) */
+ int vci; /* VCI (only 16 bits at UNI) */
+ } sap_addr __ATM_API_ALIGN; /* PVC address */
+};
+
+/* SVC addressing */
+
+#define ATM_ESA_LEN 20 /* ATM End System Address length */
+#define ATM_E164_LEN 12 /* maximum E.164 number length */
+
+#define ATM_AFI_DCC 0x39 /* DCC ATM Format */
+#define ATM_AFI_ICD 0x47 /* ICD ATM Format */
+#define ATM_AFI_E164 0x45 /* E.164 ATM Format */
+#define ATM_AFI_LOCAL 0x49 /* Local ATM Format */
+
+#define ATM_AFI_DCC_GROUP 0xBD /* DCC ATM Group Format */
+#define ATM_AFI_ICD_GROUP 0xC5 /* ICD ATM Group Format */
+#define ATM_AFI_E164_GROUP 0xC3 /* E.164 ATM Group Format */
+#define ATM_AFI_LOCAL_GROUP 0xC7 /* Local ATM Group Format */
+
+#define ATM_LIJ_NONE 0 /* no leaf-initiated join */
+#define ATM_LIJ 1 /* request joining */
+#define ATM_LIJ_RPJ 2 /* set to root-prompted join */
+#define ATM_LIJ_NJ 3 /* set to network join */
+
+
+struct sockaddr_atmsvc {
+ unsigned short sas_family; /* address family, AF_ATMSVC */
+ struct { /* SVC address */
+ unsigned char prv[ATM_ESA_LEN];/* private ATM address */
+ char pub[ATM_E164_LEN+1]; /* public address (E.164) */
+ /* unused addresses must be bzero'ed */
+ char lij_type; /* role in LIJ call; one of ATM_LIJ* */
+ __u32 lij_id; /* LIJ call identifier */
+ } sas_addr __ATM_API_ALIGN; /* SVC address */
+};
+
+
+static __inline__ int atmsvc_addr_in_use(struct sockaddr_atmsvc addr)
+{
+ return *addr.sas_addr.prv || *addr.sas_addr.pub;
+}
+
+
+static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr)
+{
+ return addr.sap_addr.itf || addr.sap_addr.vpi || addr.sap_addr.vci;
+}
+
+
+/*
+ * Some stuff for linux/sockios.h
+ */
+
+struct atmif_sioc {
+ int number;
+ int length;
+ void *arg;
+};
+
+typedef unsigned short atm_backend_t;
+#endif
--- /dev/null
+/* 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
--- /dev/null
+/* atmioc.h - ranges for ATM-related ioctl numbers */
+
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+/*
+ * See http://icawww1.epfl.ch/linux-atm/magic.html for the complete list of
+ * "magic" ioctl numbers.
+ */
+
+
+#ifndef _LINUX_ATMIOC_H
+#define _LINUX_ATMIOC_H
+
+#include <asm/ioctl.h>
+ /* everybody including atmioc.h will also need _IO{,R,W,WR} */
+
+#define ATMIOC_PHYCOM 0x00 /* PHY device common ioctls, globally unique */
+#define ATMIOC_PHYCOM_END 0x0f
+#define ATMIOC_PHYTYP 0x10 /* PHY dev type ioctls, unique per PHY type */
+#define ATMIOC_PHYTYP_END 0x2f
+#define ATMIOC_PHYPRV 0x30 /* PHY dev private ioctls, unique per driver */
+#define ATMIOC_PHYPRV_END 0x4f
+#define ATMIOC_SARCOM 0x50 /* SAR device common ioctls, globally unique */
+#define ATMIOC_SARCOM_END 0x50
+#define ATMIOC_SARPRV 0x60 /* SAR dev private ioctls, unique per driver */
+#define ATMIOC_SARPRV_END 0x7f
+#define ATMIOC_ITF 0x80 /* Interface ioctls, globally unique */
+#define ATMIOC_ITF_END 0x8f
+#define ATMIOC_BACKEND 0x90 /* ATM generic backend ioctls, u. per backend */
+#define ATMIOC_BACKEND_END 0xaf
+/* 0xb0-0xbf: Reserved for future use */
+#define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */
+#define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */
+#define ATMIOC_MPOA 0xd8 /* MPOA, globally unique */
+#define ATMIOC_CLIP 0xe0 /* Classical IP over ATM control, globally u. */
+#define ATMIOC_CLIP_END 0xef
+#define ATMIOC_SPECIAL 0xf0 /* Special-purpose controls, globally unique */
+#define ATMIOC_SPECIAL_END 0xff
+
+#endif
--- /dev/null
+/* atmsap.h - ATM Service Access Point addressing definitions */
+
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+#ifndef _LINUX_ATMSAP_H
+#define _LINUX_ATMSAP_H
+
+#include <linux/atmapi.h>
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+
+/*
+ * Layer 2 protocol identifiers
+ */
+
+/* BEGIN_L2 */
+#define ATM_L2_NONE 0 /* L2 not specified */
+#define ATM_L2_ISO1745 0x01 /* Basic mode ISO 1745 */
+#define ATM_L2_Q291 0x02 /* ITU-T Q.291 (Rec. I.441) */
+#define ATM_L2_X25_LL 0x06 /* ITU-T X.25, link layer */
+#define ATM_L2_X25_ML 0x07 /* ITU-T X.25, multilink */
+#define ATM_L2_LAPB 0x08 /* Extended LAPB, half-duplex (Rec. T.71) */
+#define ATM_L2_HDLC_ARM 0x09 /* HDLC ARM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_NRM 0x0a /* HDLC NRM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_ABM 0x0b /* HDLC ABM (ISO/IEC 4335) */
+#define ATM_L2_ISO8802 0x0c /* LAN LLC (ISO/IEC 8802/2) */
+#define ATM_L2_X75 0x0d /* ITU-T X.75, SLP */
+#define ATM_L2_Q922 0x0e /* ITU-T Q.922 */
+#define ATM_L2_USER 0x10 /* user-specified */
+#define ATM_L2_ISO7776 0x11 /* ISO 7776 DTE-DTE */
+/* END_L2 */
+
+
+/*
+ * Layer 3 protocol identifiers
+ */
+
+/* BEGIN_L3 */
+#define ATM_L3_NONE 0 /* L3 not specified */
+#define ATM_L3_X25 0x06 /* ITU-T X.25, packet layer */
+#define ATM_L3_ISO8208 0x07 /* ISO/IEC 8208 */
+#define ATM_L3_X223 0x08 /* ITU-T X.223 | ISO/IEC 8878 */
+#define ATM_L3_ISO8473 0x09 /* ITU-T X.233 | ISO/IEC 8473 */
+#define ATM_L3_T70 0x0a /* ITU-T T.70 minimum network layer */
+#define ATM_L3_TR9577 0x0b /* ISO/IEC TR 9577 */
+#define ATM_L3_H310 0x0c /* ITU-T Recommendation H.310 */
+#define ATM_L3_H321 0x0d /* ITU-T Recommendation H.321 */
+#define ATM_L3_USER 0x10 /* user-specified */
+/* END_L3 */
+
+
+/*
+ * High layer identifiers
+ */
+
+/* BEGIN_HL */
+#define ATM_HL_NONE 0 /* HL not specified */
+#define ATM_HL_ISO 0x01 /* ISO */
+#define ATM_HL_USER 0x02 /* user-specific */
+#define ATM_HL_HLP 0x03 /* high layer profile - UNI 3.0 only */
+#define ATM_HL_VENDOR 0x04 /* vendor-specific application identifier */
+/* END_HL */
+
+
+/*
+ * ITU-T coded mode of operation
+ */
+
+/* BEGIN_IMD */
+#define ATM_IMD_NONE 0 /* mode not specified */
+#define ATM_IMD_NORMAL 1 /* normal mode of operation */
+#define ATM_IMD_EXTENDED 2 /* extended mode of operation */
+/* END_IMD */
+
+/*
+ * H.310 code points
+ */
+
+#define ATM_TT_NONE 0 /* terminal type not specified */
+#define ATM_TT_RX 1 /* receive only */
+#define ATM_TT_TX 2 /* send only */
+#define ATM_TT_RXTX 3 /* receive and send */
+
+#define ATM_MC_NONE 0 /* no multiplexing */
+#define ATM_MC_TS 1 /* transport stream (TS) */
+#define ATM_MC_TS_FEC 2 /* transport stream with forward error corr. */
+#define ATM_MC_PS 3 /* program stream (PS) */
+#define ATM_MC_PS_FEC 4 /* program stream with forward error corr. */
+#define ATM_MC_H221 5 /* ITU-T Rec. H.221 */
+
+/*
+ * SAP structures
+ */
+
+#define ATM_MAX_HLI 8 /* maximum high-layer information length */
+
+
+struct atm_blli {
+ unsigned char l2_proto; /* layer 2 protocol */
+ union {
+ struct {
+ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */
+ /* absent */
+ unsigned char window; /* window size (k), 1-127 (0 to omit) */
+ } itu; /* ITU-T encoding */
+ unsigned char user; /* user-specified l2 information */
+ } l2;
+ unsigned char l3_proto; /* layer 3 protocol */
+ union {
+ struct {
+ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */
+ /* absent */
+ unsigned char def_size; /* default packet size (log2), 4-12 (0 to */
+ /* omit) */
+ unsigned char window;/* packet window size, 1-127 (0 to omit) */
+ } itu; /* ITU-T encoding */
+ unsigned char user; /* user specified l3 information */
+ struct { /* if l3_proto = ATM_L3_H310 */
+ unsigned char term_type; /* terminal type */
+ unsigned char fw_mpx_cap; /* forward multiplexing capability */
+ /* only if term_type != ATM_TT_NONE */
+ unsigned char bw_mpx_cap; /* backward multiplexing capability */
+ /* only if term_type != ATM_TT_NONE */
+ } h310;
+ struct { /* if l3_proto = ATM_L3_TR9577 */
+ unsigned char ipi; /* initial protocol id */
+ unsigned char snap[5];/* IEEE 802.1 SNAP identifier */
+ /* (only if ipi == NLPID_IEEE802_1_SNAP) */
+ } tr9577;
+ } l3;
+} __ATM_API_ALIGN;
+
+
+struct atm_bhli {
+ unsigned char hl_type; /* high layer information type */
+ unsigned char hl_length; /* length (only if hl_type == ATM_HL_USER || */
+ /* hl_type == ATM_HL_ISO) */
+ unsigned char hl_info[ATM_MAX_HLI];/* high layer information */
+};
+
+
+#define ATM_MAX_BLLI 3 /* maximum number of BLLI elements */
+
+
+struct atm_sap {
+ struct atm_bhli bhli; /* local SAP, high-layer information */
+ struct atm_blli blli[ATM_MAX_BLLI] __ATM_API_ALIGN;
+ /* local SAP, low-layer info */
+};
+
+
+static __inline__ int blli_in_use(struct atm_blli blli)
+{
+ return blli.l2_proto || blli.l3_proto;
+}
+
+#endif
--- /dev/null
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
+/* rule is permanent, and cannot be deleted */
+#define FIB_RULE_PERMANENT 0x00000001
+#define FIB_RULE_INVERT 0x00000002
+#define FIB_RULE_UNRESOLVED 0x00000004
+#define FIB_RULE_DEV_DETACHED 0x00000008
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR 0x00010000
+
+struct fib_rule_hdr
+{
+ __u8 family;
+ __u8 dst_len;
+ __u8 src_len;
+ __u8 tos;
+
+ __u8 table;
+ __u8 res1; /* reserved */
+ __u8 res2; /* reserved */
+ __u8 action;
+
+ __u32 flags;
+};
+
+enum
+{
+ FRA_UNSPEC,
+ FRA_DST, /* destination address */
+ FRA_SRC, /* source address */
+ FRA_IFNAME, /* interface name */
+ FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */
+ FRA_UNUSED2,
+ FRA_PRIORITY, /* priority/preference */
+ FRA_UNUSED3,
+ FRA_UNUSED4,
+ FRA_UNUSED5,
+ FRA_FWMARK, /* mark */
+ FRA_FLOW, /* flow/class id */
+ FRA_UNUSED6,
+ FRA_UNUSED7,
+ FRA_UNUSED8,
+ FRA_TABLE, /* Extended table id */
+ FRA_FWMASK, /* mask for netfilter mark */
+ __FRA_MAX
+};
+
+#define FRA_MAX (__FRA_MAX - 1)
+
+enum
+{
+ FR_ACT_UNSPEC,
+ FR_ACT_TO_TBL, /* Pass to fixed table */
+ FR_ACT_GOTO, /* Jump to another rule */
+ FR_ACT_NOP, /* No operation */
+ FR_ACT_RES3,
+ FR_ACT_RES4,
+ FR_ACT_BLACKHOLE, /* Drop without notification */
+ FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
+ FR_ACT_PROHIBIT, /* Drop with EACCES */
+ __FR_ACT_MAX,
+};
+
+#define FR_ACT_MAX (__FR_ACT_MAX - 1)
+
+#endif
--- /dev/null
+#ifndef __LINUX_GENERIC_NETLINK_H
+#define __LINUX_GENERIC_NETLINK_H
+
+#include <linux/netlink.h>
+
+#define GENL_NAMSIZ 16 /* length of family name */
+
+#define GENL_MIN_ID NLMSG_MIN_TYPE
+#define GENL_MAX_ID 1023
+
+struct genlmsghdr {
+ __u8 cmd;
+ __u8 version;
+ __u16 reserved;
+};
+
+#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
+#define GENL_ADMIN_PERM 0x01
+#define GENL_CMD_CAP_DO 0x02
+#define GENL_CMD_CAP_DUMP 0x04
+#define GENL_CMD_CAP_HASPOL 0x08
+
+/*
+ * List of reserved static generic netlink identifiers:
+ */
+#define GENL_ID_GENERATE 0
+#define GENL_ID_CTRL NLMSG_MIN_TYPE
+
+/**************************************************************************
+ * Controller
+ **************************************************************************/
+
+enum {
+ CTRL_CMD_UNSPEC,
+ CTRL_CMD_NEWFAMILY,
+ CTRL_CMD_DELFAMILY,
+ CTRL_CMD_GETFAMILY,
+ CTRL_CMD_NEWOPS,
+ CTRL_CMD_DELOPS,
+ CTRL_CMD_GETOPS,
+ CTRL_CMD_NEWMCAST_GRP,
+ CTRL_CMD_DELMCAST_GRP,
+ CTRL_CMD_GETMCAST_GRP, /* unused */
+ __CTRL_CMD_MAX,
+};
+
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+ CTRL_ATTR_UNSPEC,
+ CTRL_ATTR_FAMILY_ID,
+ CTRL_ATTR_FAMILY_NAME,
+ CTRL_ATTR_VERSION,
+ CTRL_ATTR_HDRSIZE,
+ CTRL_ATTR_MAXATTR,
+ CTRL_ATTR_OPS,
+ CTRL_ATTR_MCAST_GROUPS,
+ __CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+enum {
+ CTRL_ATTR_OP_UNSPEC,
+ CTRL_ATTR_OP_ID,
+ CTRL_ATTR_OP_FLAGS,
+ __CTRL_ATTR_OP_MAX,
+};
+
+#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
+
+enum {
+ CTRL_ATTR_MCAST_GRP_UNSPEC,
+ CTRL_ATTR_MCAST_GRP_NAME,
+ CTRL_ATTR_MCAST_GRP_ID,
+ __CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
+#endif /* __LINUX_GENERIC_NETLINK_H */
--- /dev/null
+#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__ */
--- /dev/null
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the INET interface module.
+ *
+ * Version: @(#)if.h 1.0.2 04/18/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ * Ross Biro
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#include <linux/types.h> /* for "__kernel_caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+ /* for "__user" et al */
+
+#define IFNAMSIZ 16
+#define IFALIASZ 256
+#include <linux/hdlc/ioctl.h>
+
+/* Standard interface flags (netdevice->flags). */
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_LOOPBACK 0x8 /* is a loopback net */
+#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */
+#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */
+#define IFF_RUNNING 0x40 /* interface RFC2863 OPER_UP */
+#define IFF_NOARP 0x80 /* no ARP protocol */
+#define IFF_PROMISC 0x100 /* receive all packets */
+#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/
+
+#define IFF_MASTER 0x400 /* master of a load balancer */
+#define IFF_SLAVE 0x800 /* slave of a load balancer */
+
+#define IFF_MULTICAST 0x1000 /* Supports multicast */
+
+#define IFF_PORTSEL 0x2000 /* can set media type */
+#define IFF_AUTOMEDIA 0x4000 /* auto media select active */
+#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/
+
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+
+#define IFF_ECHO 0x40000 /* echo sent packets */
+
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
+/* Private (from user) interface flags (netdevice->priv_flags). */
+#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
+#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
+#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
+#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
+#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
+#define IFF_BONDING 0x20 /* bonding master or slave */
+#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
+#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */
+
+#define IF_GET_IFACE 0x0001 /* for querying only */
+#define IF_GET_PROTO 0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35 0x1000 /* V.35 serial interface */
+#define IF_IFACE_V24 0x1001 /* V.24 serial interface */
+#define IF_IFACE_X21 0x1002 /* X.21 serial interface */
+#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */
+#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */
+#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */
+#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */
+#define IF_PROTO_PPP 0x2001 /* PPP protocol */
+#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */
+#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */
+#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */
+#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */
+#define IF_PROTO_X25 0x2006 /* X.25 */
+#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */
+#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */
+#define IF_PROTO_FR_ETH_PVC 0x200B
+#define IF_PROTO_RAW 0x200C /* RAW Socket */
+
+/* RFC 2863 operational status */
+enum {
+ IF_OPER_UNKNOWN,
+ IF_OPER_NOTPRESENT,
+ IF_OPER_DOWN,
+ IF_OPER_LOWERLAYERDOWN,
+ IF_OPER_TESTING,
+ IF_OPER_DORMANT,
+ IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+ IF_LINK_MODE_DEFAULT,
+ IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
+};
+
+/*
+ * Device mapping structure. I'd just gone off and designed a
+ * beautiful scheme using only loadable modules with arguments
+ * for driver options and along come the PCMCIA people 8)
+ *
+ * Ah well. The get() side of this is good for WDSETUP, and it'll
+ * be handy for debugging things. The set side is fine for now and
+ * being very small might be worth keeping for clean configuration.
+ */
+
+struct ifmap
+{
+ unsigned long mem_start;
+ unsigned long mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+ /* 3 bytes spare */
+};
+
+struct if_settings
+{
+ unsigned int type; /* Type of physical device or protocol */
+ unsigned int size; /* Size of the data allocated by the caller */
+ union {
+ /* {atm/eth/dsl}_settings anyone ? */
+ raw_hdlc_proto *raw_hdlc;
+ cisco_proto *cisco;
+ fr_proto *fr;
+ fr_proto_pvc *fr_pvc;
+ fr_proto_pvc_info *fr_pvc_info;
+
+ /* interface settings */
+ sync_serial_settings *sync;
+ te1_settings *te1;
+ } ifs_ifsu;
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's. All interface ioctl's must have parameter
+ * definitions which begin with ifr_name. The
+ * remainder may be interface specific.
+ */
+
+struct ifreq
+{
+#define IFHWADDRLEN 6
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
+ void * ifru_data;
+ struct if_settings ifru_settings;
+ } ifr_ifru;
+};
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+#define ifr_map ifr_ifru.ifru_map /* device map */
+#define ifr_slave ifr_ifru.ifru_slave /* slave device */
+#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
+#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
+#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
+#define ifr_newname ifr_ifru.ifru_newname /* New name */
+#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+
+struct ifconf
+{
+ int ifc_len; /* size of buffer */
+ union
+ {
+ char *ifcu_buf;
+ struct ifreq *ifcu_req;
+ } ifc_ifcu;
+};
+#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
+#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
+
+#endif /* _LINUX_IF_H */
--- /dev/null
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/netlink.h>
+
+struct ifaddrmsg
+{
+ __u8 ifa_family;
+ __u8 ifa_prefixlen; /* The prefix length */
+ __u8 ifa_flags; /* Flags */
+ __u8 ifa_scope; /* Address scope */
+ __u32 ifa_index; /* Link index */
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ */
+enum
+{
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO,
+ IFA_MULTICAST,
+ __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_NODAD 0x02
+#define IFA_F_OPTIMISTIC 0x04
+#define IFA_F_HOMEADDRESS 0x10
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+
+struct ifa_cacheinfo
+{
+ __u32 ifa_prefered;
+ __u32 ifa_valid;
+ __u32 cstamp; /* created timestamp, hundredths of seconds */
+ __u32 tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+/* backwards compatibility for userspace */
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
--- /dev/null
+/*
+ * if_addrlabel.h - netlink interface for address labels
+ *
+ * Copyright (C)2007 USAGI/WIDE Project, All Rights Reserved.
+ *
+ * Authors:
+ * YOSHIFUJI Hideaki @ USAGI/WIDE <yoshfuji@linux-ipv6.org>
+ */
+
+#ifndef __LINUX_IF_ADDRLABEL_H
+#define __LINUX_IF_ADDRLABEL_H
+
+struct ifaddrlblmsg
+{
+ __u8 ifal_family; /* Address family */
+ __u8 __ifal_reserved; /* Reserved */
+ __u8 ifal_prefixlen; /* Prefix length */
+ __u8 ifal_flags; /* Flags */
+ __u32 ifal_index; /* Link index */
+ __u32 ifal_seq; /* sequence number */
+};
+
+enum
+{
+ IFAL_ADDRESS = 1,
+ IFAL_LABEL = 2,
+ __IFAL_MAX
+};
+
+#define IFAL_MAX (__IFAL_MAX - 1)
+
+#endif
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
*
* This program is free software; you can redistribute it and/or
#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
#define ETH_P_CUST 0x6006 /* DEC Customer use */
#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
-#define ETH_P_ETH 0x6558 /* Ethernet in Ethernet, for EGRE */
+#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */
#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
#define ETH_P_ATALK 0x809B /* Appletalk DDP */
#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
* over Ethernet
*/
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
#define ETH_P_TIPC 0x88CA /* TIPC */
+#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
/*
* Non DIX types. Won't clash for 1500 types.
#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_CAN 0x000C /* Controller Area Network */
#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
#define ETH_P_ECONET 0x0018 /* Acorn Econet */
#define ETH_P_HDLC 0x0019 /* HDLC frames */
#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
+#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */
+#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */
+#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
/*
* This is an Ethernet frame header.
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
-static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
-{
- return (struct ethhdr *)skb_mac_header(skb);
-}
-
-#ifdef CONFIG_SYSCTL
-extern struct ctl_table ether_table[];
-#endif
-#endif
#endif /* _LINUX_IF_ETHER_H */
--- /dev/null
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/netlink.h>
+
+/* The struct should be in sync with struct net_device_stats */
+struct rtnl_link_stats
+{
+ __u32 rx_packets; /* total packets received */
+ __u32 tx_packets; /* total packets transmitted */
+ __u32 rx_bytes; /* total bytes received */
+ __u32 tx_bytes; /* total bytes transmitted */
+ __u32 rx_errors; /* bad packets received */
+ __u32 tx_errors; /* packet transmit problems */
+ __u32 rx_dropped; /* no space in linux buffers */
+ __u32 tx_dropped; /* no space available in linux */
+ __u32 multicast; /* multicast packets received */
+ __u32 collisions;
+
+ /* detailed rx_errors: */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors; /* receiver ring buff overflow */
+ __u32 rx_crc_errors; /* recved pkt with crc error */
+ __u32 rx_frame_errors; /* recv'd frame alignment error */
+ __u32 rx_fifo_errors; /* recv'r fifo overrun */
+ __u32 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap
+{
+ __u64 mem_start;
+ __u64 mem_end;
+ __u64 base_addr;
+ __u16 irq;
+ __u8 dma;
+ __u8 port;
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+ IFLA_PROTINFO, /* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+ IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+ IFLA_OPERSTATE,
+ IFLA_LINKMODE,
+ IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+ IFLA_NET_NS_PID,
+ IFLA_IFALIAS,
+ __IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+/* backwards compatibility for userspace */
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neither of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum
+{
+ IFLA_INET6_UNSPEC,
+ IFLA_INET6_FLAGS, /* link flags */
+ IFLA_INET6_CONF, /* sysctl parameters */
+ IFLA_INET6_STATS, /* statistics */
+ IFLA_INET6_MCAST, /* MC things. What of them? */
+ IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
+ __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+struct ifla_cacheinfo
+{
+ __u32 max_reasm_len;
+ __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
+ __u32 reachable_time;
+ __u32 retrans_time;
+};
+
+enum
+{
+ IFLA_INFO_UNSPEC,
+ IFLA_INFO_KIND,
+ IFLA_INFO_DATA,
+ IFLA_INFO_XSTATS,
+ __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum
+{
+ IFLA_VLAN_UNSPEC,
+ IFLA_VLAN_ID,
+ IFLA_VLAN_FLAGS,
+ IFLA_VLAN_EGRESS_QOS,
+ IFLA_VLAN_INGRESS_QOS,
+ __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+enum
+{
+ IFLA_VLAN_QOS_UNSPEC,
+ IFLA_VLAN_QOS_MAPPING,
+ __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+ __u32 from;
+ __u32 to;
+};
+
+#endif /* _LINUX_IF_LINK_H */
#define _IF_TUNNEL_H_
#include <linux/types.h>
+#include <linux/ip.h>
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
+#define SIOCGETPRL (SIOCDEVPRIVATE + 4)
+#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
+#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
+#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
#define GRE_CSUM __constant_htons(0x8000)
#define GRE_ROUTING __constant_htons(0x4000)
__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_ */
--- /dev/null
+/*
+ * VLAN An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors: Ben Greear <greearb@candelatech.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+
+/* VLAN IOCTLs are found in sockios.h */
+
+/* Passed in vlan_ioctl_args structure to determine behaviour. */
+enum vlan_ioctl_cmds {
+ ADD_VLAN_CMD,
+ DEL_VLAN_CMD,
+ SET_VLAN_INGRESS_PRIORITY_CMD,
+ SET_VLAN_EGRESS_PRIORITY_CMD,
+ GET_VLAN_INGRESS_PRIORITY_CMD,
+ GET_VLAN_EGRESS_PRIORITY_CMD,
+ SET_VLAN_NAME_TYPE_CMD,
+ SET_VLAN_FLAG_CMD,
+ GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+ GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
+};
+
+enum vlan_flags {
+ VLAN_FLAG_REORDER_HDR = 0x1,
+ VLAN_FLAG_GVRP = 0x2,
+};
+
+enum vlan_name_types {
+ VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */
+ VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */
+ VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+ int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+ char device1[24];
+
+ union {
+ char device2[24];
+ int VID;
+ unsigned int skb_priority;
+ unsigned int name_type;
+ unsigned int bind_type;
+ unsigned int flag; /* Matches vlan_dev_info flags */
+ } u;
+
+ short vlan_qos;
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
/* 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)
__u8 family;
__u8 prefix_len;
int port;
- __u32 addr[0];
+ __be32 addr[0];
};
/* Base info structure. It contains socket identity (addrs/ports/cookie)
--- /dev/null
+#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
+++ /dev/null
-/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
- */
-
-#ifndef _LINUX_IP_MP_ALG_H
-#define _LINUX_IP_MP_ALG_H
-
-enum ip_mp_alg {
- IP_MP_ALG_NONE,
- IP_MP_ALG_RR,
- IP_MP_ALG_DRR,
- IP_MP_ALG_RANDOM,
- IP_MP_ALG_WRANDOM,
- __IP_MP_ALG_MAX
-};
-
-#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
-
-#endif /* _LINUX_IP_MP_ALG_H */
-
--- /dev/null
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_H
+
+#include <linux/netlink.h>
+
+struct ndmsg
+{
+ __u8 ndm_family;
+ __u8 ndm_pad1;
+ __u16 ndm_pad2;
+ __s32 ndm_ifindex;
+ __u16 ndm_state;
+ __u8 ndm_flags;
+ __u8 ndm_type;
+};
+
+enum
+{
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO,
+ NDA_PROBES,
+ __NDA_MAX
+};
+
+#define NDA_MAX (__NDA_MAX - 1)
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+ and make no address resolution or NUD.
+ NUD_PERMANENT is also cannot be deleted by garbage collectors.
+ */
+
+struct nda_cacheinfo
+{
+ __u32 ndm_confirmed;
+ __u32 ndm_used;
+ __u32 ndm_updated;
+ __u32 ndm_refcnt;
+};
+
+/*****************************************************************
+ * Neighbour tables specific messages.
+ *
+ * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
+ * NLM_F_DUMP flag set. Every neighbour table configuration is
+ * spread over multiple messages to avoid running into message
+ * size limits on systems with many interfaces. The first message
+ * in the sequence transports all not device specific data such as
+ * statistics, configuration, and the default parameter set.
+ * This message is followed by 0..n messages carrying device
+ * specific parameter sets.
+ * Although the ordering should be sufficient, NDTA_NAME can be
+ * used to identify sequences. The initial message can be identified
+ * by checking for NDTA_CONFIG. The device specific messages do
+ * not contain this TLV but have NDTPA_IFINDEX set to the
+ * corresponding interface index.
+ *
+ * To change neighbour table attributes, send RTM_SETNEIGHTBL
+ * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
+ * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
+ * otherwise. Device specific parameter sets can be changed by
+ * setting NDTPA_IFINDEX to the interface index of the corresponding
+ * device.
+ ****/
+
+struct ndt_stats
+{
+ __u64 ndts_allocs;
+ __u64 ndts_destroys;
+ __u64 ndts_hash_grows;
+ __u64 ndts_res_failed;
+ __u64 ndts_lookups;
+ __u64 ndts_hits;
+ __u64 ndts_rcv_probes_mcast;
+ __u64 ndts_rcv_probes_ucast;
+ __u64 ndts_periodic_gc_runs;
+ __u64 ndts_forced_gc_runs;
+};
+
+enum {
+ NDTPA_UNSPEC,
+ NDTPA_IFINDEX, /* u32, unchangeable */
+ NDTPA_REFCNT, /* u32, read-only */
+ NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */
+ NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */
+ NDTPA_RETRANS_TIME, /* u64, msecs */
+ NDTPA_GC_STALETIME, /* u64, msecs */
+ NDTPA_DELAY_PROBE_TIME, /* u64, msecs */
+ NDTPA_QUEUE_LEN, /* u32 */
+ NDTPA_APP_PROBES, /* u32 */
+ NDTPA_UCAST_PROBES, /* u32 */
+ NDTPA_MCAST_PROBES, /* u32 */
+ NDTPA_ANYCAST_DELAY, /* u64, msecs */
+ NDTPA_PROXY_DELAY, /* u64, msecs */
+ NDTPA_PROXY_QLEN, /* u32 */
+ NDTPA_LOCKTIME, /* u64, msecs */
+ __NDTPA_MAX
+};
+#define NDTPA_MAX (__NDTPA_MAX - 1)
+
+struct ndtmsg
+{
+ __u8 ndtm_family;
+ __u8 ndtm_pad1;
+ __u16 ndtm_pad2;
+};
+
+struct ndt_config
+{
+ __u16 ndtc_key_len;
+ __u16 ndtc_entry_size;
+ __u32 ndtc_entries;
+ __u32 ndtc_last_flush; /* delta to now in msecs */
+ __u32 ndtc_last_rand; /* delta to now in msecs */
+ __u32 ndtc_hash_rnd;
+ __u32 ndtc_hash_mask;
+ __u32 ndtc_hash_chain_gc;
+ __u32 ndtc_proxy_qlen;
+};
+
+enum {
+ NDTA_UNSPEC,
+ NDTA_NAME, /* char *, unchangeable */
+ NDTA_THRESH1, /* u32 */
+ NDTA_THRESH2, /* u32 */
+ NDTA_THRESH3, /* u32 */
+ NDTA_CONFIG, /* struct ndt_config, read-only */
+ NDTA_PARMS, /* nested TLV NDTPA_* */
+ NDTA_STATS, /* struct ndt_stats, read-only */
+ NDTA_GC_INTERVAL, /* u64, msecs */
+ __NDTA_MAX
+};
+#define NDTA_MAX (__NDTA_MAX - 1)
+
+#endif
--- /dev/null
+#ifndef __LINUX_NETFILTER_H
+#define __LINUX_NETFILTER_H
+
+#include <linux/types.h>
+
+
+/* Responses from hook functions. */
+#define NF_DROP 0
+#define NF_ACCEPT 1
+#define NF_STOLEN 2
+#define NF_QUEUE 3
+#define NF_REPEAT 4
+#define NF_STOP 5
+#define NF_MAX_VERDICT NF_STOP
+
+/* we overload the higher bits for encoding auxiliary data such as the queue
+ * number. Not nice, but better than additional function arguments. */
+#define NF_VERDICT_MASK 0x0000ffff
+#define NF_VERDICT_BITS 16
+
+#define NF_VERDICT_QMASK 0xffff0000
+#define NF_VERDICT_QBITS 16
+
+#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+/* only for userspace compatibility */
+/* Generic cache responses from hook functions.
+ <= 0x2000 is used for protocol-flags. */
+#define NFC_UNKNOWN 0x4000
+#define NFC_ALTERED 0x8000
+
+enum nf_inet_hooks {
+ NF_INET_PRE_ROUTING,
+ NF_INET_LOCAL_IN,
+ NF_INET_FORWARD,
+ NF_INET_LOCAL_OUT,
+ NF_INET_POST_ROUTING,
+ NF_INET_NUMHOOKS
+};
+
+enum {
+ NFPROTO_UNSPEC = 0,
+ NFPROTO_IPV4 = 2,
+ NFPROTO_ARP = 3,
+ NFPROTO_BRIDGE = 7,
+ NFPROTO_IPV6 = 10,
+ NFPROTO_DECNET = 12,
+ NFPROTO_NUMPROTO,
+};
+
+union nf_inet_addr {
+ __u32 all[4];
+ __be32 ip;
+ __be32 ip6[4];
+ struct in_addr in;
+ struct in6_addr in6;
+};
+
+#endif /*__LINUX_NETFILTER_H*/
--- /dev/null
+#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 */
--- /dev/null
+#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
--- /dev/null
+#ifndef __LINUX_IP_NETFILTER_H
+#define __LINUX_IP_NETFILTER_H
+
+/* IPv4-specific defines for netfilter.
+ * (C)1998 Rusty Russell -- This code is GPL.
+ */
+
+#include <linux/netfilter.h>
+
+/* only for userspace compatibility */
+/* IP Cache bits. */
+/* Src IP address. */
+#define NFC_IP_SRC 0x0001
+/* Dest IP address. */
+#define NFC_IP_DST 0x0002
+/* Input device. */
+#define NFC_IP_IF_IN 0x0004
+/* Output device. */
+#define NFC_IP_IF_OUT 0x0008
+/* TOS. */
+#define NFC_IP_TOS 0x0010
+/* Protocol. */
+#define NFC_IP_PROTO 0x0020
+/* IP options. */
+#define NFC_IP_OPTIONS 0x0040
+/* Frag & flags. */
+#define NFC_IP_FRAG 0x0080
+
+/* Per-protocol information: only matters if proto match. */
+/* TCP flags. */
+#define NFC_IP_TCPFLAGS 0x0100
+/* Source port. */
+#define NFC_IP_SRC_PT 0x0200
+/* Dest port. */
+#define NFC_IP_DST_PT 0x0400
+/* Something else about the proto */
+#define NFC_IP_PROTO_UNKNOWN 0x2000
+
+/* IP Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_IP_PRE_ROUTING 0
+/* If the packet is destined for this box. */
+#define NF_IP_LOCAL_IN 1
+/* If the packet is destined for another interface. */
+#define NF_IP_FORWARD 2
+/* Packets coming from a local process. */
+#define NF_IP_LOCAL_OUT 3
+/* Packets about to hit the wire. */
+#define NF_IP_POST_ROUTING 4
+#define NF_IP_NUMHOOKS 5
+
+enum nf_ip_hook_priorities {
+ NF_IP_PRI_FIRST = INT_MIN,
+ NF_IP_PRI_CONNTRACK_DEFRAG = -400,
+ NF_IP_PRI_RAW = -300,
+ NF_IP_PRI_SELINUX_FIRST = -225,
+ NF_IP_PRI_CONNTRACK = -200,
+ NF_IP_PRI_MANGLE = -150,
+ NF_IP_PRI_NAT_DST = -100,
+ NF_IP_PRI_FILTER = 0,
+ NF_IP_PRI_SECURITY = 50,
+ NF_IP_PRI_NAT_SRC = 100,
+ NF_IP_PRI_SELINUX_LAST = 225,
+ NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
+ NF_IP_PRI_LAST = INT_MAX,
+};
+
+/* Arguments for setsockopt SOL_IP: */
+/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */
+/* 2.2 firewalling (+ masq) went from 64 through 76 */
+/* 2.4 firewalling went 64 through 67. */
+#define SO_ORIGINAL_DST 80
+
+
+#endif /*__LINUX_IP_NETFILTER_H*/
#ifndef _IPTABLES_H
#define _IPTABLES_H
+#include <linux/types.h>
+
#include <linux/netfilter_ipv4.h>
-#define IPT_FUNCTION_MAXNAMELEN 30
-#define IPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
/* Yes, Virginia, you have to zero the padding. */
struct ipt_ip {
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. */
#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
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];
/*
* 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)
#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
-/* CONTINUE verdict for targets */
-#define IPT_CONTINUE 0xFFFFFFFF
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
-/* For standard target */
-#define IPT_RETURN (-NF_MAX_VERDICT - 1)
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
-/* TCP matching stuff */
-struct ipt_tcp
-{
- u_int16_t spts[2]; /* Source port range. */
- u_int16_t dpts[2]; /* Destination port range. */
- u_int8_t option; /* TCP Option iff non-zero*/
- u_int8_t flg_mask; /* TCP flags mask byte */
- u_int8_t flg_cmp; /* TCP flags compare byte */
- u_int8_t invflags; /* Inverse flags */
-};
+#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
-/* Values for "inv" field in struct ipt_tcp. */
-#define IPT_TCP_INV_SRCPT 0x01 /* Invert the sense of source ports. */
-#define IPT_TCP_INV_DSTPT 0x02 /* Invert the sense of dest ports. */
-#define IPT_TCP_INV_FLAGS 0x04 /* Invert the sense of TCP flags. */
-#define IPT_TCP_INV_OPTION 0x08 /* Invert the sense of option test. */
-#define IPT_TCP_INV_MASK 0x0F /* All possible flags. */
-
-/* UDP matching stuff */
-struct ipt_udp
-{
- u_int16_t spts[2]; /* Source port range. */
- u_int16_t dpts[2]; /* Destination port range. */
- u_int8_t invflags; /* Inverse flags */
-};
-
-/* Values for "invflags" field in struct ipt_udp. */
-#define IPT_UDP_INV_SRCPT 0x01 /* Invert the sense of source ports. */
-#define IPT_UDP_INV_DSTPT 0x02 /* Invert the sense of dest ports. */
-#define IPT_UDP_INV_MASK 0x03 /* All possible flags. */
+#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
/* ICMP matching stuff */
struct ipt_icmp
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;
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
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 *
}
/* 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.
#include <linux/types.h>
#define NETLINK_ROUTE 0 /* Routing/device hook */
-#define NETLINK_W1 1 /* 1-wire subsystem */
+#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_INET_DIAG 4 /* INET socket monitoring */
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+#define NETLINK_ECRYPTFS 19
#define MAX_LINKS 32
+struct net;
+
struct sockaddr_nl
{
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
- __u32 nl_pid; /* process pid */
+ __u32 nl_pid; /* port ID */
__u32 nl_groups; /* multicast groups mask */
};
__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 */
__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)))
struct tc_u32_key
{
- __u32 mask;
- __u32 val;
+ __be32 mask;
+ __be32 val;
int off;
int offmask;
};
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];
};
TCA_FW_POLICE,
TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */
TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
+ TCA_FW_MASK,
__TCA_FW_MAX
};
#define TCA_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
* 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
{
{
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
__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
unsigned flows; /* Maximal number of flows */
};
+struct tc_sfq_xstats
+{
+ __s32 allot;
+};
+
/*
* NOTE: limit, divisor and flows are hardwired to code at the moment.
*
#define __LINUX_RTNETLINK_H
#include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
/****
* Routing/neighbour discovery messages.
RTM_NEWPREFIX = 52,
#define RTM_NEWPREFIX RTM_NEWPREFIX
- RTM_GETPREFIX = 54,
-#define RTM_GETPREFIX RTM_GETPREFIX
RTM_GETMULTICAST = 58,
#define RTM_GETMULTICAST RTM_GETMULTICAST
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)
};
{
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 */
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
};
#define RTAX_INITCWND RTAX_INITCWND
RTAX_FEATURES,
#define RTAX_FEATURES RTAX_FEATURES
+ RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
__RTAX_MAX
};
} 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.
****/
__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.
TCA_RATE,
TCA_FCNT,
TCA_STATS2,
+ TCA_STAB,
__TCA_MAX
};
#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
#define RTMGRP_IPV4_IFADDR 0x10
#define RTMGRP_IPV4_MROUTE 0x20
#define RTMGRP_IPV4_ROUTE 0x40
+#define RTMGRP_IPV4_RULE 0x80
#define RTMGRP_IPV6_IFADDR 0x100
#define RTMGRP_IPV6_MROUTE 0x200
#define 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,
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)
-#include <sys/socket.h>
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
+#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *))
+ /* Implementation specific desired alignment */
+
+struct __kernel_sockaddr_storage {
+ unsigned short ss_family; /* address family */
+ /* Following field(s) are implementation specific */
+ char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+ /* space to achieve desired size, */
+ /* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#include <asm/socket.h> /* arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <linux/uio.h> /* iovec support */
+#include <linux/types.h> /* pid_t */
+ /* */
+
+#ifdef CONFIG_PROC_FS
+struct seq_file;
+extern void socket_seq_show(struct seq_file *seq);
+#endif
+
+typedef unsigned short sa_family_t;
+
+/*
+ * 1003.1g requires sa_family_t and that sa_data is char.
+ */
+
+struct sockaddr {
+ sa_family_t sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+#define sockaddr_storage __kernel_sockaddr_storage
+
+/*
+ * As we do 4.4BSD message passing we use a 4.4BSD message passing
+ * system, not 4.3. Thus msg_accrights(len) are now missing. They
+ * belong in an obscure libc emulation or the bin.
+ */
+
+struct msghdr {
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ __kernel_size_t msg_iovlen; /* Number of blocks */
+ void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
+ __kernel_size_t msg_controllen; /* Length of cmsg list */
+ unsigned msg_flags;
+};
+
+/*
+ * POSIX 1003.1g - ancillary data object information
+ * Ancillary data consits of a sequence of pairs of
+ * (cmsghdr, cmsg_data[])
+ */
+
+struct cmsghdr {
+ __kernel_size_t cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+};
+
+/*
+ * Ancilliary data object information MACROS
+ * Table 5-14 of POSIX 1003.1g
+ */
+
+#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+
+#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
+
+#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
+ (struct cmsghdr *)(ctl) : \
+ (struct cmsghdr *)NULL)
+#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+ (cmsg)->cmsg_len <= (unsigned long) \
+ ((mhdr)->msg_controllen - \
+ ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
+
+/*
+ * This mess will go away with glibc
+ */
+
+#if defined(__GNUC__)
+#define __KINLINE static __inline__
+#elif defined(__cplusplus)
+#define __KINLINE static inline
+#else
+#define __KINLINE static
+#endif
+
+
+/*
+ * Get the next cmsg header
+ *
+ * PLEASE, do not touch this function. If you think, that it is
+ * incorrect, grep kernel sources and think about consequences
+ * before trying to improve it.
+ *
+ * Now it always returns valid, not truncated ancillary object
+ * HEADER. But caller still MUST check, that cmsg->cmsg_len is
+ * inside range, given by msg->msg_controllen before using
+ * ancillary object DATA. --ANK (980731)
+ */
+
+__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr *__cmsg)
+{
+ struct cmsghdr * __ptr;
+
+ __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return (struct cmsghdr *)0;
+
+ return __ptr;
+}
+
+__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+ return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+/* "Socket"-level control message types: */
+
+#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
+#define SCM_SECURITY 0x03 /* rw: security label */
+
+struct ucred {
+ __u32 pid;
+ __u32 uid;
+ __u32 gid;
+};
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* AppleTalk DDP */
+#define AF_NETROM 6 /* Amateur Radio NET/ROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_ATMPVC 8 /* ATM PVCs */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
+#define AF_DECnet 12 /* Reserved for DECnet project */
+#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
+#define AF_SECURITY 14 /* Security callback pseudo AF */
+#define AF_KEY 15 /* PF_KEY key management API */
+#define AF_NETLINK 16
+#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
+#define AF_PACKET 17 /* Packet family */
+#define AF_ASH 18 /* Ash */
+#define AF_ECONET 19 /* Acorn Econet */
+#define AF_ATMSVC 20 /* ATM SVCs */
+#define AF_SNA 22 /* Linux SNA Project (nutters!) */
+#define AF_IRDA 23 /* IRDA sockets */
+#define AF_PPPOX 24 /* PPPoX sockets */
+#define AF_WANPIPE 25 /* Wanpipe API Sockets */
+#define AF_LLC 26 /* Linux LLC */
+#define AF_CAN 29 /* Controller Area Network */
+#define AF_TIPC 30 /* TIPC sockets */
+#define AF_BLUETOOTH 31 /* Bluetooth sockets */
+#define AF_IUCV 32 /* IUCV sockets */
+#define AF_RXRPC 33 /* RxRPC sockets */
+#define AF_ISDN 34 /* mISDN sockets */
+#define AF_PHONET 35 /* Phonet sockets */
+#define AF_MAX 36 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_LOCAL AF_LOCAL
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_ATMPVC AF_ATMPVC
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+#define PF_ROSE AF_ROSE
+#define PF_DECnet AF_DECnet
+#define PF_NETBEUI AF_NETBEUI
+#define PF_SECURITY AF_SECURITY
+#define PF_KEY AF_KEY
+#define PF_NETLINK AF_NETLINK
+#define PF_ROUTE AF_ROUTE
+#define PF_PACKET AF_PACKET
+#define PF_ASH AF_ASH
+#define PF_ECONET AF_ECONET
+#define PF_ATMSVC AF_ATMSVC
+#define PF_SNA AF_SNA
+#define PF_IRDA AF_IRDA
+#define PF_PPPOX AF_PPPOX
+#define PF_WANPIPE AF_WANPIPE
+#define PF_LLC AF_LLC
+#define PF_CAN AF_CAN
+#define PF_TIPC AF_TIPC
+#define PF_BLUETOOTH AF_BLUETOOTH
+#define PF_IUCV AF_IUCV
+#define PF_RXRPC AF_RXRPC
+#define PF_ISDN AF_ISDN
+#define PF_PHONET AF_PHONET
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specifiable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv.
+ Added those for 1003.1g not all are supported yet
+ */
+
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */
+#define MSG_CTRUNC 8
+#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40 /* Nonblocking io */
+#define MSG_EOR 0x80 /* End of record */
+#define MSG_WAITALL 0x100 /* Wait for a full request */
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800 /* Confirm path validity */
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */
+#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
+#define MSG_MORE 0x8000 /* Sender will send more */
+
+#define MSG_EOF MSG_FIN
+
+#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exit for file
+ descriptor received through
+ SCM_RIGHTS */
+#if defined(CONFIG_COMPAT)
+#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
+#else
+#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
+#endif
+
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_IP 0
+/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
+#define SOL_TCP 6
+#define SOL_UDP 17
+#define SOL_IPV6 41
+#define SOL_ICMPV6 58
+#define SOL_SCTP 132
+#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */
+#define SOL_RAW 255
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_ROSE 260
+#define SOL_DECNET 261
+#define SOL_X25 262
+#define SOL_PACKET 263
+#define SOL_ATM 264 /* ATM layer (cell level) */
+#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */
+#define SOL_IRDA 266
+#define SOL_NETBEUI 267
+#define SOL_LLC 268
+#define SOL_DCCP 269
+#define SOL_NETLINK 270
+#define SOL_TIPC 271
+#define SOL_RXRPC 272
+#define SOL_PPPOL2TP 273
+#define SOL_BLUETOOTH 274
+#define SOL_PNPIPE 275
+
+/* IPX options */
+#define IPX_TYPE 1
+
+#endif /* not kernel and not glibc */
+#endif /* _LINUX_SOCKET_H */
+++ /dev/null
-#ifndef __LINUX_TC_DEF_H
-#define __LINUX_TC_DEF_H
-
-#include <linux/pkt_cls.h>
-
-struct tc_defact
-{
- tc_gen;
-};
-
-enum
-{
- TCA_DEF_UNSPEC,
- TCA_DEF_TM,
- TCA_DEF_PARMS,
- TCA_DEF_DATA,
- __TCA_DEF_MAX
-};
-#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
-
-#endif
--- /dev/null
+#ifndef __LINUX_TC_NAT_H
+#define __LINUX_TC_NAT_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#define TCA_ACT_NAT 9
+
+enum
+{
+ TCA_NAT_UNSPEC,
+ TCA_NAT_PARMS,
+ TCA_NAT_TM,
+ __TCA_NAT_MAX
+};
+#define TCA_NAT_MAX (__TCA_NAT_MAX - 1)
+
+#define TCA_NAT_FLAG_EGRESS 1
+
+struct tc_nat
+{
+ tc_gen;
+ __be32 old_addr;
+ __be32 new_addr;
+ __be32 mask;
+ __u32 flags;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#ifndef __LINUX_TC_SKBEDIT_H
+#define __LINUX_TC_SKBEDIT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_SKBEDIT 11
+
+#define SKBEDIT_F_PRIORITY 0x1
+#define SKBEDIT_F_QUEUE_MAPPING 0x2
+
+struct tc_skbedit {
+ tc_gen;
+};
+
+enum {
+ TCA_SKBEDIT_UNSPEC,
+ TCA_SKBEDIT_TM,
+ TCA_SKBEDIT_PARMS,
+ TCA_SKBEDIT_PRIORITY,
+ TCA_SKBEDIT_QUEUE_MAPPING,
+ __TCA_SKBEDIT_MAX
+};
+#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
+
+#endif
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)
+++ /dev/null
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the TCP protocol.
- *
- * Version: @(#)tcp.h 1.0.2 04/28/93
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_TCP_H
-#define _LINUX_TCP_H
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-struct tcphdr {
- __u16 source;
- __u16 dest;
- __u32 seq;
- __u32 ack_seq;
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u16 res1:4,
- doff:4,
- fin:1,
- syn:1,
- rst:1,
- psh:1,
- ack:1,
- urg:1,
- ece:1,
- cwr:1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u16 doff:4,
- res1:4,
- cwr:1,
- ece:1,
- urg:1,
- ack:1,
- psh:1,
- rst:1,
- syn:1,
- fin:1;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
- __u16 window;
- __u16 check;
- __u16 urg_ptr;
-};
-
-/*
- * The union cast uses a gcc extension to avoid aliasing problems
- * (union is compatible to any of its members)
- * This means this part of the code is -fstrict-aliasing safe now.
- */
-union tcp_word_hdr {
- struct tcphdr hdr;
- __u32 words[5];
-};
-
-#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])
-
-enum {
- TCP_FLAG_CWR = __constant_htonl(0x00800000),
- TCP_FLAG_ECE = __constant_htonl(0x00400000),
- TCP_FLAG_URG = __constant_htonl(0x00200000),
- TCP_FLAG_ACK = __constant_htonl(0x00100000),
- TCP_FLAG_PSH = __constant_htonl(0x00080000),
- TCP_FLAG_RST = __constant_htonl(0x00040000),
- TCP_FLAG_SYN = __constant_htonl(0x00020000),
- TCP_FLAG_FIN = __constant_htonl(0x00010000),
- TCP_RESERVED_BITS = __constant_htonl(0x0F000000),
- TCP_DATA_OFFSET = __constant_htonl(0xF0000000)
-};
-
-/* TCP socket options */
-#define TCP_NODELAY 1 /* Turn off Nagle's algorithm. */
-#define TCP_MAXSEG 2 /* Limit MSS */
-#define TCP_CORK 3 /* Never send partially complete segments */
-#define TCP_KEEPIDLE 4 /* Start keeplives after this period */
-#define TCP_KEEPINTVL 5 /* Interval between keepalives */
-#define TCP_KEEPCNT 6 /* Number of keepalives before death */
-#define TCP_SYNCNT 7 /* Number of SYN retransmits */
-#define TCP_LINGER2 8 /* Life time of orphaned FIN-WAIT-2 state */
-#define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */
-#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */
-#define TCP_INFO 11 /* Information about this connection. */
-#define TCP_QUICKACK 12 /* Block/reenable quick acks */
-#define TCP_CONGESTION 13 /* Congestion control algorithm */
-
-#define TCPI_OPT_TIMESTAMPS 1
-#define TCPI_OPT_SACK 2
-#define TCPI_OPT_WSCALE 4
-#define TCPI_OPT_ECN 8
-
-enum tcp_ca_state
-{
- TCP_CA_Open = 0,
-#define TCPF_CA_Open (1<<TCP_CA_Open)
- TCP_CA_Disorder = 1,
-#define TCPF_CA_Disorder (1<<TCP_CA_Disorder)
- TCP_CA_CWR = 2,
-#define TCPF_CA_CWR (1<<TCP_CA_CWR)
- TCP_CA_Recovery = 3,
-#define TCPF_CA_Recovery (1<<TCP_CA_Recovery)
- TCP_CA_Loss = 4
-#define TCPF_CA_Loss (1<<TCP_CA_Loss)
-};
-
-struct tcp_info
-{
- __u8 tcpi_state;
- __u8 tcpi_ca_state;
- __u8 tcpi_retransmits;
- __u8 tcpi_probes;
- __u8 tcpi_backoff;
- __u8 tcpi_options;
- __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
-
- __u32 tcpi_rto;
- __u32 tcpi_ato;
- __u32 tcpi_snd_mss;
- __u32 tcpi_rcv_mss;
-
- __u32 tcpi_unacked;
- __u32 tcpi_sacked;
- __u32 tcpi_lost;
- __u32 tcpi_retrans;
- __u32 tcpi_fackets;
-
- /* Times. */
- __u32 tcpi_last_data_sent;
- __u32 tcpi_last_ack_sent; /* Not remembered, sorry. */
- __u32 tcpi_last_data_recv;
- __u32 tcpi_last_ack_recv;
-
- /* Metrics. */
- __u32 tcpi_pmtu;
- __u32 tcpi_rcv_ssthresh;
- __u32 tcpi_rtt;
- __u32 tcpi_rttvar;
- __u32 tcpi_snd_ssthresh;
- __u32 tcpi_snd_cwnd;
- __u32 tcpi_advmss;
- __u32 tcpi_reordering;
-
- __u32 tcpi_rcv_rtt;
- __u32 tcpi_rcv_space;
-
- __u32 tcpi_total_retrans;
-};
-
-
-#endif /* _LINUX_TCP_H */
--- /dev/null
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+
+typedef __u32 __kernel_dev_t;
+
+typedef __kernel_fd_set fd_set;
+typedef __kernel_dev_t dev_t;
+typedef __kernel_ino_t ino_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_nlink_t nlink_t;
+typedef __kernel_off_t off_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_daddr_t daddr_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+typedef __kernel_timer_t timer_t;
+typedef __kernel_clockid_t clockid_t;
+typedef __kernel_mqd_t mqd_t;
+
+typedef __kernel_uid_t uid_t;
+typedef __kernel_gid_t gid_t;
+
+#if defined(__GNUC__)
+typedef __kernel_loff_t loff_t;
+#endif
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t caddr_t;
+#endif
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef __u8 u_int8_t;
+typedef __s8 int8_t;
+typedef __u16 u_int16_t;
+typedef __s16 int16_t;
+typedef __u32 u_int32_t;
+typedef __s32 int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+typedef __u8 uint8_t;
+typedef __u16 uint16_t;
+typedef __u32 uint32_t;
+
+#if defined(__GNUC__)
+typedef __u64 uint64_t;
+typedef __u64 u_int64_t;
+typedef __s64 int64_t;
+#endif
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 __u64 __attribute__((aligned(8)))
+#define aligned_be64 __be64 __attribute__((aligned(8)))
+#define aligned_le64 __le64 __attribute__((aligned(8)))
+
+/**
+ * The type used for indexing onto a disc or disc partition.
+ *
+ * Linux always considers sectors to be 512 bytes long independently
+ * of the devices real block size.
+ */
+#ifdef CONFIG_LBD
+typedef u64 sector_t;
+#else
+typedef unsigned long sector_t;
+#endif
+
+/*
+ * The type of the inode's block count.
+ */
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#else
+typedef unsigned long blkcnt_t;
+#endif
+
+/*
+ * The type of an index into the pagecache. Use a #define so asm/types.h
+ * can override it.
+ */
+#ifndef pgoff_t
+#define pgoff_t unsigned long
+#endif
+
+#endif /* __KERNEL_STRICT_NAMES */
+
+/*
+ * Below are truly Linux-specific types that should never collide with
+ * any application/library that wants linux/types.h.
+ */
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+#if defined(__GNUC__)
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+#endif
+typedef __u16 __bitwise __sum16;
+typedef __u32 __bitwise __wsum;
+
+
+#endif /* _LINUX_TYPES_H */
--- /dev/null
+#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
*/
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
struct xfrm_id
{
xfrm_address_t daddr;
- __u32 spi;
+ __be32 spi;
__u8 proto;
};
{
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;
};
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 {
__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
};
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,
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)
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,
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;
__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;
#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;
};
__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,
#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)
#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);
+++ /dev/null
-/*
- * 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 */
--- /dev/null
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tcp.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H 1
+
+#include <features.h>
+
+/*
+ * User-settable options (used with setsockopt).
+ */
+#define TCP_NODELAY 1 /* Don't delay send to coalesce packets */
+#define TCP_MAXSEG 2 /* Set maximum segment size */
+#define TCP_CORK 3 /* Control sending of partial frames */
+#define TCP_KEEPIDLE 4 /* Start keeplives after this period */
+#define TCP_KEEPINTVL 5 /* Interval between keepalives */
+#define TCP_KEEPCNT 6 /* Number of keepalives before death */
+#define TCP_SYNCNT 7 /* Number of SYN retransmits */
+#define TCP_LINGER2 8 /* Life time of orphaned FIN-WAIT-2 state */
+#define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */
+#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */
+#define TCP_INFO 11 /* Information about this connection. */
+#define TCP_QUICKACK 12 /* Bock/reenable quick ACKs. */
+#define TCP_CONGESTION 13 /* Congestion control algorithm. */
+
+#ifdef __USE_MISC
+# include <sys/types.h>
+
+# ifdef __FAVOR_BSD
+typedef u_int32_t tcp_seq;
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+struct tcphdr
+ {
+ u_int16_t th_sport; /* source port */
+ u_int16_t th_dport; /* destination port */
+ tcp_seq th_seq; /* sequence number */
+ tcp_seq th_ack; /* acknowledgement number */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int8_t th_x2:4; /* (unused) */
+ u_int8_t th_off:4; /* data offset */
+# endif
+# if __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t th_off:4; /* data offset */
+ u_int8_t th_x2:4; /* (unused) */
+# endif
+ u_int8_t th_flags;
+# define TH_FIN 0x01
+# define TH_SYN 0x02
+# define TH_RST 0x04
+# define TH_PUSH 0x08
+# define TH_ACK 0x10
+# define TH_URG 0x20
+ u_int16_t th_win; /* window */
+ u_int16_t th_sum; /* checksum */
+ u_int16_t th_urp; /* urgent pointer */
+};
+
+# else /* !__FAVOR_BSD */
+struct tcphdr
+ {
+ u_int16_t source;
+ u_int16_t dest;
+ u_int32_t seq;
+ u_int32_t ack_seq;
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int16_t res1:4;
+ u_int16_t doff:4;
+ u_int16_t fin:1;
+ u_int16_t syn:1;
+ u_int16_t rst:1;
+ u_int16_t psh:1;
+ u_int16_t ack:1;
+ u_int16_t urg:1;
+ u_int16_t res2:2;
+# elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int16_t doff:4;
+ u_int16_t res1:4;
+ u_int16_t res2:2;
+ u_int16_t urg:1;
+ u_int16_t ack:1;
+ u_int16_t psh:1;
+ u_int16_t rst:1;
+ u_int16_t syn:1;
+ u_int16_t fin:1;
+# else
+# error "Adjust your <bits/endian.h> defines"
+# endif
+ u_int16_t window;
+ u_int16_t check;
+ u_int16_t urg_ptr;
+};
+# endif /* __FAVOR_BSD */
+
+enum
+{
+ TCP_ESTABLISHED = 1,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_TIME_WAIT,
+ TCP_CLOSE,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_LISTEN,
+ TCP_CLOSING /* now a valid state */
+};
+
+# define TCPOPT_EOL 0
+# define TCPOPT_NOP 1
+# define TCPOPT_MAXSEG 2
+# define TCPOLEN_MAXSEG 4
+# define TCPOPT_WINDOW 3
+# define TCPOLEN_WINDOW 3
+# define TCPOPT_SACK_PERMITTED 4 /* Experimental */
+# define TCPOLEN_SACK_PERMITTED 2
+# define TCPOPT_SACK 5 /* Experimental */
+# define TCPOPT_TIMESTAMP 8
+# define TCPOLEN_TIMESTAMP 10
+# define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */
+
+# define TCPOPT_TSTAMP_HDR \
+ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ */
+# define TCP_MSS 512
+
+# define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
+
+# define TCP_MAX_WINSHIFT 14 /* maximum window shift */
+
+# define SOL_TCP 6 /* TCP level */
+
+
+# define TCPI_OPT_TIMESTAMPS 1
+# define TCPI_OPT_SACK 2
+# define TCPI_OPT_WSCALE 4
+# define TCPI_OPT_ECN 8
+
+/* Values for tcpi_state. */
+enum tcp_ca_state
+{
+ TCP_CA_Open = 0,
+ TCP_CA_Disorder = 1,
+ TCP_CA_CWR = 2,
+ TCP_CA_Recovery = 3,
+ TCP_CA_Loss = 4
+};
+
+struct tcp_info
+{
+ u_int8_t tcpi_state;
+ u_int8_t tcpi_ca_state;
+ u_int8_t tcpi_retransmits;
+ u_int8_t tcpi_probes;
+ u_int8_t tcpi_backoff;
+ u_int8_t tcpi_options;
+ u_int8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+
+ u_int32_t tcpi_rto;
+ u_int32_t tcpi_ato;
+ u_int32_t tcpi_snd_mss;
+ u_int32_t tcpi_rcv_mss;
+
+ u_int32_t tcpi_unacked;
+ u_int32_t tcpi_sacked;
+ u_int32_t tcpi_lost;
+ u_int32_t tcpi_retrans;
+ u_int32_t tcpi_fackets;
+
+ /* Times. */
+ u_int32_t tcpi_last_data_sent;
+ u_int32_t tcpi_last_ack_sent; /* Not remembered, sorry. */
+ u_int32_t tcpi_last_data_recv;
+ u_int32_t tcpi_last_ack_recv;
+
+ /* Metrics. */
+ u_int32_t tcpi_pmtu;
+ u_int32_t tcpi_rcv_ssthresh;
+ u_int32_t tcpi_rtt;
+ u_int32_t tcpi_rttvar;
+ u_int32_t tcpi_snd_ssthresh;
+ u_int32_t tcpi_snd_cwnd;
+ u_int32_t tcpi_advmss;
+ u_int32_t tcpi_reordering;
+ u_int32_t tcpi_rcv_rtt;
+ u_int32_t tcpi_rcv_space;
+ u_int32_t tcpi_total_retrans;
+
+};
+
+#endif /* Misc. */
+
+#endif /* netinet/tcp.h */
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);
#include <asm/types.h>
#include <resolv.h>
+#include <stdlib.h>
#include "libnetlink.h"
#include "ll_map.h"
__u8 bytelen;
__s16 bitlen;
__u32 flags;
- __u32 data[4];
+ __u32 data[8];
} inet_prefix;
#define PREFIXLEN_SPECIFIED 1
#define AF_DECnet 12
#endif
-struct dn_naddr
+struct dn_naddr
{
unsigned short a_len;
unsigned char a_addr[DN_MAXADDL];
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
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));
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__ */
+++ /dev/null
-.TH IP 8 "17 January 2002" "iproute2" "Linux"
-.SH NAME
-ip \- show / manipulate routing, devices, policy routing and tunnels
-.SH SYNOPSIS
-
-.ad l
-.in +8
-.ti -8
-.B ip
-.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
-.BR help " }"
-.sp
-
-.ti -8
-.IR OBJECT " := { "
-.BR link " | " addr " | " route " | " rule " | " neigh " | " tunnel " | "\
-maddr " | " mroute " | " monitor " }"
-.sp
-
-.ti -8
-.IR OPTIONS " := { "
-\fB\-V\fR[\fIersion\fR] |
-\fB\-s\fR[\fItatistics\fR] |
-\fB\-r\fR[\fIesolve\fR] |
-\fB\-f\fR[\fIamily\fR] {
-.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
-\fB\-o\fR[\fIneline\fR] }
-
-.ti -8
-.BI "ip link set " DEVICE
-.RB "{ " up " | " down " | " arp " { " on " | " off " } |"
-.br
-.BR promisc " { " on " | " off " } |"
-.br
-.BR allmulti " { " on " | " off " } |"
-.br
-.BR dynamic " { " on " | " off " } |"
-.br
-.BR multicast " { " on " | " off " } |"
-.br
-.B txqueuelen
-.IR PACKETS " |"
-.br
-.B name
-.IR NEWNAME " |"
-.br
-.B address
-.IR LLADDR " |"
-.B broadcast
-.IR LLADDR " |"
-.br
-.B mtu
-.IR MTU " }"
-
-.ti -8
-.B ip link show
-.RI "[ " DEVICE " ]"
-
-.ti -8
-.BR "ip addr" " { " add " | " del " } "
-.IB IFADDR " dev " STRING
-
-.ti -8
-.BR "ip addr" " { " show " | " flush " } [ " dev
-.IR STRING " ] [ "
-.B scope
-.IR SCOPE-ID " ] [ "
-.B to
-.IR PREFIX " ] [ " FLAG-LIST " ] [ "
-.B label
-.IR PATTERN " ]"
-
-.ti -8
-.IR IFADDR " := " PREFIX " | " ADDR
-.B peer
-.IR PREFIX " [ "
-.B broadcast
-.IR ADDR " ] [ "
-.B anycast
-.IR ADDR " ] [ "
-.B label
-.IR STRING " ] [ "
-.B scope
-.IR SCOPE-ID " ]"
-
-.ti -8
-.IR SCOPE-ID " := "
-.RB "[ " host " | " link " | " global " | "
-.IR NUMBER " ]"
-
-.ti -8
-.IR FLAG-LIST " := [ " FLAG-LIST " ] " FLAG
-
-.ti -8
-.IR FLAG " := "
-.RB "[ " permanent " | " dynamic " | " secondary " | " primary " | "\
-tentative " | " deprecated " ]"
-
-.ti -8
-.BR "ip route" " { "
-.BR list " | " flush " } "
-.I SELECTOR
-
-.ti -8
-.B ip route get
-.IR ADDRESS " [ "
-.BI from " ADDRESS " iif " STRING"
-.RB " ] [ " oif
-.IR STRING " ] [ "
-.B tos
-.IR TOS " ]"
-
-.ti -8
-.BR "ip route" " { " add " | " del " | " change " | " append " | "\
-replace " | " monitor " } "
-.I ROUTE
-
-.ti -8
-.IR SELECTOR " := "
-.RB "[ " root
-.IR PREFIX " ] [ "
-.B match
-.IR PREFIX " ] [ "
-.B exact
-.IR PREFIX " ] [ "
-.B table
-.IR TABLE_ID " ] [ "
-.B proto
-.IR RTPROTO " ] [ "
-.B type
-.IR TYPE " ] [ "
-.B scope
-.IR SCOPE " ]"
-
-.ti -8
-.IR ROUTE " := " NODE_SPEC " [ " INFO_SPEC " ]"
-
-.ti -8
-.IR NODE_SPEC " := [ " TYPE " ] " PREFIX " ["
-.B tos
-.IR TOS " ] [ "
-.B table
-.IR TABLE_ID " ] [ "
-.B proto
-.IR RTPROTO " ] [ "
-.B scope
-.IR SCOPE " ] [ "
-.B metric
-.IR METRIC " ]"
-
-.ti -8
-.IR INFO_SPEC " := " "NH OPTIONS FLAGS" " ["
-.B nexthop
-.IR NH " ] ..."
-
-.ti -8
-.IR NH " := [ "
-.B via
-.IR ADDRESS " ] [ "
-.B dev
-.IR STRING " ] [ "
-.B weight
-.IR NUMBER " ] " NHFLAGS
-
-.ti -8
-.IR OPTIONS " := " FLAGS " [ "
-.B mtu
-.IR NUMBER " ] [ "
-.B advmss
-.IR NUMBER " ] [ "
-.B rtt
-.IR NUMBER " ] [ "
-.B rttvar
-.IR NUMBER " ] [ "
-.B window
-.IR NUMBER " ] [ "
-.B cwnd
-.IR NUMBER " ] [ "
-.B ssthresh
-.IR REALM " ] [ "
-.B realms
-.IR REALM " ]"
-
-.ti -8
-.IR TYPE " := [ "
-.BR unicast " | " local " | " broadcast " | " multicast " | "\
-throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
-
-.ti -8
-.IR TABLE_ID " := [ "
-.BR local "| " main " | " default " | " all " |"
-.IR NUMBER " ]"
-
-.ti -8
-.IR SCOPE " := [ "
-.BR host " | " link " | " global " |"
-.IR NUMBER " ]"
-
-.ti -8
-.IR FLAGS " := [ "
-.BR equalize " ]"
-
-.ti -8
-.IR NHFLAGS " := [ "
-.BR onlink " | " pervasive " ]"
-
-.ti -8
-.IR RTPROTO " := [ "
-.BR kernel " | " boot " | " static " |"
-.IR NUMBER " ]"
-
-.ti -8
-.B ip rule
-.RB " [ " list " | " add " | " del " ]"
-.I SELECTOR ACTION
-
-.ti -8
-.IR SELECTOR " := [ "
-.B from
-.IR PREFIX " ] [ "
-.B to
-.IR PREFIX " ] [ "
-.B tos
-.IR TOS " ] [ "
-.B fwmark
-.IR FWMARK " ] [ "
-.B dev
-.IR STRING " ] [ "
-.B pref
-.IR NUMBER " ]"
-
-.ti -8
-.IR ACTION " := [ "
-.B table
-.IR TABLE_ID " ] [ "
-.B nat
-.IR ADDRESS " ] [ "
-.BR prohibit " | " reject " | " unreachable " ] [ " realms
-.RI "[" SRCREALM "/]" DSTREALM " ]"
-
-.ti -8
-.IR TABLE_ID " := [ "
-.BR local " | " main " | " default " |"
-.IR NUMBER " ]"
-
-.ti -8
-.BR "ip neigh" " { " add " | " del " | " change " | " replace " } { "
-.IR ADDR " [ "
-.B lladdr
-.IR LLADDR " ] [ "
-.BR nud " { " permanent " | " noarp " | " stale " | " reachable " } ] | " proxy
-.IR ADDR " } [ "
-.B dev
-.IR DEV " ]"
-
-.ti -8
-.BR "ip neigh" " { " show " | " flush " } [ " to
-.IR PREFIX " ] [ "
-.B dev
-.IR DEV " ] [ "
-.B nud
-.IR STATE " ]"
-
-.ti -8
-.BR "ip tunnel" " { " add " | " change " | " del " | " show " }"
-.RI "[ " NAME " ]"
-.br
-.RB "[ " mode " { " ipip " | " gre " | " sit " } ]"
-.br
-.RB "[ " remote
-.IR ADDR " ] [ "
-.B local
-.IR ADDR " ]"
-.br
-.RB "[ [" i "|" o "]" seq " ] [ [" i "|" o "]" key
-.IR KEY " ] [ "
-.RB "[" i "|" o "]" csum " ] ]"
-.br
-.RB "[ " ttl
-.IR TTL " ] [ "
-.B tos
-.IR TOS " ] [ "
-.RB "[" no "]" pmtudisc " ]"
-.br
-.RB "[ " dev
-.IR PHYS_DEV " ]"
-
-.ti -8
-.IR ADDR " := { " IP_ADDRESS " |"
-.BR any " }"
-
-.ti -8
-.IR TOS " := { " NUMBER " |"
-.BR inherit " }"
-
-.ti -8
-.IR TTL " := { " 1 ".." 255 " | "
-.BR inherit " }"
-
-.ti -8
-.IR KEY " := { " DOTTED_QUAD " | " NUMBER " }"
-
-.ti -8
-.BR "ip maddr" " [ " add " | " del " ]"
-.IB MULTIADDR " dev " STRING
-
-.ti -8
-.BR "ip maddr show" " [ " dev
-.IR STRING " ]"
-
-.ti -8
-.BR "ip mroute show" " ["
-.IR PREFIX " ] [ "
-.B from
-.IR PREFIX " ] [ "
-.B iif
-.IR DEVICE " ]"
-
-.ti -8
-.BR "ip monitor" " [ " all " |"
-.IR LISTofOBJECTS " ]"
-.in -8
-.ad b
-
-.SH OPTIONS
-
-.TP
-.BR "\-V" , " -Version"
-print the version of the
-.B ip
-utility and exit.
-
-.TP
-.BR "\-s" , " \-stats", " \-statistics"
-output more information. If the option
-appears twice or more, the amount of information increases.
-As a rule, the information is statistics or some time values.
-
-.TP
-.BR "\-f" , " \-family"
-followed by protocol family identifier:
-.BR "inet" , " inet6"
-or
-.B link
-,enforce the protocol family to use. If the option is not present,
-the protocol family is guessed from other arguments. If the rest
-of the command line does not give enough information to guess the
-family,
-.B ip
-falls back to the default one, usually
-.B inet
-or
-.BR "any" .
-.B link
-is a special family identifier meaning that no networking protocol
-is involved.
-
-.TP
-.B \-4
-shortcut for
-.BR "-family inet" .
-
-.TP
-.B \-6
-shortcut for
-.BR "\-family inet6" .
-
-.TP
-.B \-0
-shortcut for
-.BR "\-family link" .
-
-.TP
-.BR "\-o" , " \-oneline"
-output each record on a single line, replacing line feeds
-with the
-.B '\'
-character. This is convenient when you want to count records
-with
-.BR wc (1)
- or to
-.BR grep (1)
-the output.
-
-.TP
-.BR "\-r" , " \-resolve"
-use the system's name resolver to print DNS names instead of
-host addresses.
-
-.SH IP - COMMAND SYNTAX
-
-.SS
-.I OBJECT
-
-.TP
-.B link
-- network device.
-
-.TP
-.B address
-- protocol (IP or IPv6) address on a device.
-.TP
-.B neighbour
-- ARP or NDISC cache entry.
-
-.TP
-.B route
-- routing table entry.
-
-.TP
-.B rule
-- rule in routing policy database.
-
-.TP
-.B maddress
-- multicast address.
-
-.TP
-.B mroute
-- multicast routing cache entry.
-
-.TP
-.B tunnel
-- tunnel over IP.
-
-.PP
-The names of all objects may be written in full or
-abbreviated form, f.e.
-.B address
-is abbreviated as
-.B addr
-or just
-.B a.
-
-.SS
-.I COMMAND
-
-Specifies the action to perform on the object.
-The set of possible actions depends on the object type.
-As a rule, it is possible to
-.BR "add" , " delete"
-and
-.B show
-(or
-.B list
-) objects, but some objects do not allow all of these operations
-or have some additional commands. The
-.B help
-command is available for all objects. It prints
-out a list of available commands and argument syntax conventions.
-.sp
-If no command is given, some default command is assumed.
-Usually it is
-.B list
-or, if the objects of this class cannot be listed,
-.BR "help" .
-
-.SH ip link - network device configuration
-
-.B link
-is a network device and the corresponding commands
-display and change the state of devices.
-
-.SS ip link set - change device attributes
-
-.TP
-.BI dev " NAME " (default)
-.I NAME
-specifies network device to operate on.
-
-.TP
-.BR up " and " down
-change the state of the device to
-.B UP
-or
-.BR "DOWN" .
-
-.TP
-.BR "arp on " or " arp off"
-change the
-.B NOARP
-flag on the device.
-
-.TP
-.BR "multicast on " or " multicast off"
-change the
-.B MULTICAST
-flag on the device.
-
-.TP
-.BR "dynamic on " or " dynamic off"
-change the
-.B DYNAMIC
-flag on the device.
-
-.TP
-.BI name " NAME"
-change the name of the device. This operation is not
-recommended if the device is running or has some addresses
-already configured.
-
-.TP
-.BI txqueuelen " NUMBER"
-.TP
-.BI txqlen " NUMBER"
-change the transmit queue length of the device.
-
-.TP
-.BI mtu " NUMBER"
-change the
-.I MTU
-of the device.
-
-.TP
-.BI address " LLADDRESS"
-change the station address of the interface.
-
-.TP
-.BI broadcast " LLADDRESS"
-.TP
-.BI brd " LLADDRESS"
-.TP
-.BI peer " LLADDRESS"
-change the link layer broadcast address or the peer address when
-the interface is
-.IR "POINTOPOINT" .
-
-.PP
-.B Warning:
-If multiple parameter changes are requested,
-.B ip
-aborts immediately after any of the changes have failed.
-This is the only case when
-.B ip
-can move the system to an unpredictable state. The solution
-is to avoid changing several parameters with one
-.B ip link set
-call.
-
-.SS ip link show - display device attributes
-
-.TP
-.BI dev " NAME " (default)
-.I NAME
-specifies the network device to show.
-If this argument is omitted all devices are listed.
-
-.TP
-.B up
-only display running interfaces.
-
-.SH ip address - protocol address management.
-
-The
-.B address
-is a protocol (IP or IPv6) address attached
-to a network device. Each device must have at least one address
-to use the corresponding protocol. It is possible to have several
-different addresses attached to one device. These addresses are not
-discriminated, so that the term
-.B alias
-is not quite appropriate for them and we do not use it in this document.
-.sp
-The
-.B ip addr
-command displays addresses and their properties, adds new addresses
-and deletes old ones.
-
-.SS ip address add - add new protocol address.
-
-.TP
-.BI dev " NAME"
-the name of the device to add the address to.
-
-.TP
-.BI local " ADDRESS " (default)
-the address of the interface. The format of the address depends
-on the protocol. It is a dotted quad for IP and a sequence of
-hexadecimal halfwords separated by colons for IPv6. The
-.I ADDRESS
-may be followed by a slash and a decimal number which encodes
-the network prefix length.
-
-.TP
-.BI peer " ADDRESS"
-the address of the remote endpoint for pointopoint interfaces.
-Again, the
-.I ADDRESS
-may be followed by a slash and a decimal number, encoding the network
-prefix length. If a peer address is specified, the local address
-cannot have a prefix length. The network prefix is associated
-with the peer rather than with the local address.
-
-.TP
-.BI broadcast " ADDRESS"
-the broadcast address on the interface.
-.sp
-It is possible to use the special symbols
-.B '+'
-and
-.B '-'
-instead of the broadcast address. In this case, the broadcast address
-is derived by setting/resetting the host bits of the interface prefix.
-
-.TP
-.BI label " NAME"
-Each address may be tagged with a label string.
-In order to preserve compatibility with Linux-2.0 net aliases,
-this string must coincide with the name of the device or must be prefixed
-with the device name followed by colon.
-
-.TP
-.BI scope " SCOPE_VALUE"
-the scope of the area where this address is valid.
-The available scopes are listed in file
-.BR "/etc/iproute2/rt_scopes" .
-Predefined scope values are:
-
-.in +8
-.B global
-- the address is globally valid.
-.sp
-.B site
-- (IPv6 only) the address is site local, i.e. it is
-valid inside this site.
-.sp
-.B link
-- the address is link local, i.e. it is valid only on this device.
-.sp
-.B host
-- the address is valid only inside this host.
-.in -8
-
-.SS ip address delete - delete protocol address
-.B Arguments:
-coincide with the arguments of
-.B ip addr add.
-The device name is a required argument. The rest are optional.
-If no arguments are given, the first address is deleted.
-
-.SS ip address show - look at protocol addresses
-
-.TP
-.BI dev " NAME " (default)
-name of device.
-
-.TP
-.BI scope " SCOPE_VAL"
-only list addresses with this scope.
-
-.TP
-.BI to " PREFIX"
-only list addresses matching this prefix.
-
-.TP
-.BI label " PATTERN"
-only list addresses with labels matching the
-.IR "PATTERN" .
-.I PATTERN
-is a usual shell style pattern.
-
-.TP
-.BR dynamic " and " permanent
-(IPv6 only) only list addresses installed due to stateless
-address configuration or only list permanent (not dynamic)
-addresses.
-
-.TP
-.B tentative
-(IPv6 only) only list addresses which did not pass duplicate
-address detection.
-
-.TP
-.B deprecated
-(IPv6 only) only list deprecated addresses.
-
-.TP
-.BR primary " and " secondary
-only list primary (or secondary) addresses.
-
-.SS ip address flush - flush protocol addresses
-This command flushes the protocol addresses selected by some criteria.
-
-.PP
-This command has the same arguments as
-.B show.
-The difference is that it does not run when no arguments are given.
-
-.PP
-.B Warning:
-This command (and other
-.B flush
-commands described below) is pretty dangerous. If you make a mistake,
-it will not forgive it, but will cruelly purge all the addresses.
-
-.PP
-With the
-.B -statistics
-option, the command becomes verbose. It prints out the number of deleted
-addresses and the number of rounds made to flush the address list. If
-this option is given twice,
-.B ip addr flush
-also dumps all the deleted addresses in the format described in the
-previous subsection.
-
-.SH ip neighbour - neighbour/arp tables management.
-
-.B neighbour
-objects establish bindings between protocol addresses and
-link layer addresses for hosts sharing the same link.
-Neighbour entries are organized into tables. The IPv4 neighbour table
-is known by another name - the ARP table.
-
-.P
-The corresponding commands display neighbour bindings
-and their properties, add new neighbour entries and delete old ones.
-
-.SS ip neighbour add - add a new neighbour entry
-.SS ip neighbour change - change an existing entry
-.SS ip neighbour replace - add a new entry or change an existing one
-
-These commands create new neighbour records or update existing ones.
-
-.TP
-.BI to " ADDRESS " (default)
-the protocol address of the neighbour. It is either an IPv4 or IPv6 address.
-
-.TP
-.BI dev " NAME"
-the interface to which this neighbour is attached.
-
-.TP
-.BI lladdr " LLADDRESS"
-the link layer address of the neighbour.
-.I LLADDRESS
-can also be
-.BR "null" .
-
-.TP
-.BI nud " NUD_STATE"
-the state of the neighbour entry.
-.B nud
-is an abbreviation for 'Neigh bour Unreachability Detection'.
-The state can take one of the following values:
-
-.in +8
-.B permanent
-- the neighbour entry is valid forever and can be only
-be removed administratively.
-.sp
-
-.B noarp
-- the neighbour entry is valid. No attempts to validate
-this entry will be made but it can be removed when its lifetime expires.
-.sp
-
-.B reachable
-- the neighbour entry is valid until the reachability
-timeout expires.
-.sp
-
-.B stale
-- the neighbour entry is valid but suspicious.
-This option to
-.B ip neigh
-does not change the neighbour state if it was valid and the address
-is not changed by this command.
-.in -8
-
-.SS ip neighbour delete - delete a neighbour entry
-This command invalidates a neighbour entry.
-
-.PP
-The arguments are the same as with
-.BR "ip neigh add" ,
-except that
-.B lladdr
-and
-.B nud
-are ignored.
-
-.PP
-.B Warning:
-Attempts to delete or manually change a
-.B noarp
-entry created by the kernel may result in unpredictable behaviour.
-Particularly, the kernel may try to resolve this address even
-on a
-.B NOARP
-interface or if the address is multicast or broadcast.
-
-.SS ip neighbour show - list neighbour entries
-
-This commands displays neighbour tables.
-
-.TP
-.BI to " ADDRESS " (default)
-the prefix selecting the neighbours to list.
-
-.TP
-.BI dev " NAME"
-only list the neighbours attached to this device.
-
-.TP
-.B unused
-only list neighbours which are not currently in use.
-
-.TP
-.BI nud " NUD_STATE"
-only list neighbour entries in this state.
-.I NUD_STATE
-takes values listed below or the special value
-.B all
-which means all states. This option may occur more than once.
-If this option is absent,
-.B ip
-lists all entries except for
-.B none
-and
-.BR "noarp" .
-
-.SS ip neighbour flush - flush neighbour entries
-This command flushes neighbour tables, selecting
-entries to flush by some criteria.
-
-.PP
-This command has the same arguments as
-.B show.
-The differences are that it does not run when no arguments are given,
-and that the default neighbour states to be flushed do not include
-.B permanent
-and
-.BR "noarp" .
-
-.PP
-With the
-.B -statistics
-option, the command becomes verbose. It prints out the number of
-deleted neighbours and the number of rounds made to flush the
-neighbour table. If the option is given
-twice,
-.B ip neigh flush
-also dumps all the deleted neighbours.
-
-.SH ip route - routing table management
-Manipulate route entries in the kernel routing tables keep
-information about paths to other networked nodes.
-.sp
-.B Route types:
-
-.in +8
-.B unicast
-- the route entry describes real paths to the destinations covered
-by the route prefix.
-
-.sp
-.B unreachable
-- these destinations are unreachable. Packets are discarded and the
-ICMP message
-.I host unreachable
-is generated.
-The local senders get an
-.I EHOSTUNREACH
-error.
-
-.sp
-.B blackhole
-- these destinations are unreachable. Packets are discarded silently.
-The local senders get an
-.I EINVAL
-error.
-
-.sp
-.B prohibit
-- these destinations are unreachable. Packets are discarded and the
-ICMP message
-.I communication administratively prohibited
-is generated. The local senders get an
-.I EACCES
-error.
-
-.sp
-.B local
-- the destinations are assigned to this host. The packets are looped
-back and delivered locally.
-
-.sp
-.B broadcast
-- the destinations are broadcast addresses. The packets are sent as
-link broadcasts.
-
-.sp
-.B throw
-- a special control route used together with policy rules. If such a
-route is selected, lookup in this table is terminated pretending that
-no route was found. Without policy routing it is equivalent to the
-absence of the route in the routing table. The packets are dropped
-and the ICMP message
-.I net unreachable
-is generated. The local senders get an
-.I ENETUNREACH
-error.
-
-.sp
-.B nat
-- a special NAT route. Destinations covered by the prefix
-are considered to be dummy (or external) addresses which require translation
-to real (or internal) ones before forwarding. The addresses to translate to
-are selected with the attribute
-.BR "via" .
-
-.sp
-.B anycast
-.RI "- " "not implemented"
-the destinations are
-.I anycast
-addresses assigned to this host. They are mainly equivalent
-to
-.B local
-with one difference: such addresses are invalid when used
-as the source address of any packet.
-
-.sp
-.B multicast
-- a special type used for multicast routing. It is not present in
-normal routing tables.
-.in -8
-
-.P
-.B Route tables:
-Linux-2.x can pack routes into several routing
-tables identified by a number in the range from 1 to 255 or by
-name from the file
-.B /etc/iproute2/rt_tables
-. By default all normal routes are inserted into the
-.B main
-table (ID 254) and the kernel only uses this table when calculating routes.
-
-.sp
-Actually, one other table always exists, which is invisible but
-even more important. It is the
-.B local
-table (ID 255). This table
-consists of routes for local and broadcast addresses. The kernel maintains
-this table automatically and the administrator usually need not modify it
-or even look at it.
-
-The multiple routing tables enter the game when
-.I policy routing
-is used.
-
-.SS ip route add - add new route
-.SS ip route change - change route
-.SS ip route replace - change or add new one
-
-.TP
-.BI to " TYPE PREFIX " (default)
-the destination prefix of the route. If
-.I TYPE
-is omitted,
-.B ip
-assumes type
-.BR "unicast" .
-Other values of
-.I TYPE
-are listed above.
-.I PREFIX
-is an IP or IPv6 address optionally followed by a slash and the
-prefix length. If the length of the prefix is missing,
-.B ip
-assumes a full-length host route. There is also a special
-.I PREFIX
-.B default
-- which is equivalent to IP
-.B 0/0
-or to IPv6
-.BR "::/0" .
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-the Type Of Service (TOS) key. This key has no associated mask and
-the longest match is understood as: First, compare the TOS
-of the route and of the packet. If they are not equal, then the packet
-may still match a route with a zero TOS.
-.I TOS
-is either an 8 bit hexadecimal number or an identifier
-from
-.BR "/etc/iproute2/rt_dsfield" .
-
-.TP
-.BI metric " NUMBER"
-.TP
-.BI preference " NUMBER"
-the preference value of the route.
-.I NUMBER
-is an arbitrary 32bit number.
-
-.TP
-.BI table " TABLEID"
-the table to add this route to.
-.I TABLEID
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_tables" .
-If this parameter is omitted,
-.B ip
-assumes the
-.B main
-table, with the exception of
-.BR local " , " broadcast " and " nat
-routes, which are put into the
-.B local
-table by default.
-
-.TP
-.BI dev " NAME"
-the output device name.
-
-.TP
-.BI via " ADDRESS"
-the address of the nexthop router. Actually, the sense of this field
-depends on the route type. For normal
-.B unicast
-routes it is either the true next hop router or, if it is a direct
-route installed in BSD compatibility mode, it can be a local address
-of the interface. For NAT routes it is the first address of the block
-of translated IP destinations.
-
-.TP
-.BI src " ADDRESS"
-the source address to prefer when sending to the destinations
-covered by the route prefix.
-
-.TP
-.BI realm " REALMID"
-the realm to which this route is assigned.
-.I REALMID
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_realms" .
-
-.TP
-.BI mtu " MTU"
-.TP
-.BI "mtu lock" " MTU"
-the MTU along the path to the destination. If the modifier
-.B lock
-is not used, the MTU may be updated by the kernel due to
-Path MTU Discovery. If the modifier
-.B lock
-is used, no path MTU discovery will be tried, all packets
-will be sent without the DF bit in IPv4 case or fragmented
-to MTU for IPv6.
-
-.TP
-.BI window " NUMBER"
-the maximal window for TCP to advertise to these destinations,
-measured in bytes. It limits maximal data bursts that our TCP
-peers are allowed to send to us.
-
-.TP
-.BI rtt " NUMBER"
-the initial RTT ('Round Trip Time') estimate.
-
-.TP
-.BI rttvar " NUMBER " "(2.3.15+ only)"
-the initial RTT variance estimate.
-
-.TP
-.BI ssthresh " NUMBER " "(2.3.15+ only)"
-an estimate for the initial slow start threshold.
-
-.TP
-.BI cwnd " NUMBER " "(2.3.15+ only)"
-the clamp for congestion window. It is ignored if the
-.B lock
-flag is not used.
-
-.TP
-.BI advmss " NUMBER " "(2.3.15+ only)"
-the MSS ('Maximal Segment Size') to advertise to these
-destinations when establishing TCP connections. If it is not given,
-Linux uses a default value calculated from the first hop device MTU.
-(If the path to these destination is asymmetric, this guess may be wrong.)
-
-.TP
-.BI reordering " NUMBER " "(2.3.15+ only)"
-Maximal reordering on the path to this destination.
-If it is not given, Linux uses the value selected with
-.B sysctl
-variable
-.BR "net/ipv4/tcp_reordering" .
-
-.TP
-.BI nexthop " NEXTHOP"
-the nexthop of a multipath route.
-.I NEXTHOP
-is a complex value with its own syntax similar to the top level
-argument lists:
-
-.in +8
-.BI via " ADDRESS"
-- is the nexthop router.
-.sp
-
-.BI dev " NAME"
-- is the output device.
-.sp
-
-.BI weight " NUMBER"
-- is a weight for this element of a multipath
-route reflecting its relative bandwidth or quality.
-.in -8
-
-.TP
-.BI scope " SCOPE_VAL"
-the scope of the destinations covered by the route prefix.
-.I SCOPE_VAL
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_scopes" .
-If this parameter is omitted,
-.B ip
-assumes scope
-.B global
-for all gatewayed
-.B unicast
-routes, scope
-.B link
-for direct
-.BR unicast " and " broadcast
-routes and scope
-.BR host " for " local
-routes.
-
-.TP
-.BI protocol " RTPROTO"
-the routing protocol identifier of this route.
-.I RTPROTO
-may be a number or a string from the file
-.BR "/etc/iproute2/rt_protos" .
-If the routing protocol ID is not given,
-.B ip assumes protocol
-.B boot
-(i.e. it assumes the route was added by someone who doesn't
-understand what they are doing). Several protocol values have
-a fixed interpretation.
-Namely:
-
-.in +8
-.B redirect
-- the route was installed due to an ICMP redirect.
-.sp
-
-.B kernel
-- the route was installed by the kernel during autoconfiguration.
-.sp
-
-.B boot
-- the route was installed during the bootup sequence.
-If a routing daemon starts, it will purge all of them.
-.sp
-
-.B static
-- the route was installed by the administrator
-to override dynamic routing. Routing daemon will respect them
-and, probably, even advertise them to its peers.
-.sp
-
-.B ra
-- the route was installed by Router Discovery protocol.
-.in -8
-
-.sp
-The rest of the values are not reserved and the administrator is free
-to assign (or not to assign) protocol tags.
-
-.TP
-.B onlink
-pretend that the nexthop is directly attached to this link,
-even if it does not match any interface prefix.
-
-.TP
-.B equalize
-allow packet by packet randomization on multipath routes.
-Without this modifier, the route will be frozen to one selected
-nexthop, so that load splitting will only occur on per-flow base.
-.B equalize
-only works if the kernel is patched.
-
-.SS ip route delete - delete route
-
-.B ip route del
-has the same arguments as
-.BR "ip route add" ,
-but their semantics are a bit different.
-
-Key values
-.RB "(" to ", " tos ", " preference " and " table ")"
-select the route to delete. If optional attributes are present,
-.B ip
-verifies that they coincide with the attributes of the route to delete.
-If no route with the given key and attributes was found,
-.B ip route del
-fails.
-
-.SS ip route show - list routes
-the command displays the contents of the routing tables or the route(s)
-selected by some criteria.
-
-.TP
-.BI to " SELECTOR " (default)
-only select routes from the given range of destinations.
-.I SELECTOR
-consists of an optional modifier
-.RB "(" root ", " match " or " exact ")"
-and a prefix.
-.BI root " PREFIX"
-selects routes with prefixes not shorter than
-.IR PREFIX "."
-F.e.
-.BI root " 0/0"
-selects the entire routing table.
-.BI match " PREFIX"
-selects routes with prefixes not longer than
-.IR PREFIX "."
-F.e.
-.BI match " 10.0/16"
-selects
-.IR 10.0/16 ","
-.IR 10/8 " and " 0/0 ,
-but it does not select
-.IR 10.1/16 " and " 10.0.0/24 .
-And
-.BI exact " PREFIX"
-(or just
-.IR PREFIX ")"
-selects routes with this exact prefix. If neither of these options
-are present,
-.B ip
-assumes
-.BI root " 0/0"
-i.e. it lists the entire table.
-
-.TP
-.BI tos " TOS"
-.BI dsfield " TOS"
-only select routes with the given TOS.
-
-.TP
-.BI table " TABLEID"
-show the routes from this table(s). The default setting is to show
-.BR table main "."
-.I TABLEID
-may either be the ID of a real table or one of the special values:
-.sp
-.in +8
-.B all
-- list all of the tables.
-.sp
-.B cache
-- dump the routing cache.
-.in -8
-
-.TP
-.B cloned
-.TP
-.B cached
-list cloned routes i.e. routes which were dynamically forked from
-other routes because some route attribute (f.e. MTU) was updated.
-Actually, it is equivalent to
-.BR "table cache" "."
-
-.TP
-.BI from " SELECTOR"
-the same syntax as for
-.BR to ","
-but it binds the source address range rather than destinations.
-Note that the
-.B from
-option only works with cloned routes.
-
-.TP
-.BI protocol " RTPROTO"
-only list routes of this protocol.
-
-.TP
-.BI scope " SCOPE_VAL"
-only list routes with this scope.
-
-.TP
-.BI type " TYPE"
-only list routes of this type.
-
-.TP
-.BI dev " NAME"
-only list routes going via this device.
-
-.TP
-.BI via " PREFIX"
-only list routes going via the nexthop routers selected by
-.IR PREFIX "."
-
-.TP
-.BI src " PREFIX"
-only list routes with preferred source addresses selected
-by
-.IR PREFIX "."
-
-.TP
-.BI realm " REALMID"
-.TP
-.BI realms " FROMREALM/TOREALM"
-only list routes with these realms.
-
-.SS ip route flush - flush routing tables
-this command flushes routes selected by some criteria.
-
-.sp
-The arguments have the same syntax and semantics as the arguments of
-.BR "ip route show" ,
-but routing tables are not listed but purged. The only difference is
-the default action:
-.B show
-dumps all the IP main routing table but
-.B flush
-prints the helper page.
-
-.sp
-With the
-.B -statistics
-option, the command becomes verbose. It prints out the number of
-deleted routes and the number of rounds made to flush the routing
-table. If the option is given
-twice,
-.B ip route flush
-also dumps all the deleted routes in the format described in the
-previous subsection.
-
-.SS ip route get - get a single route
-this command gets a single route to a destination and prints its
-contents exactly as the kernel sees it.
-
-.TP
-.BI to " ADDRESS " (default)
-the destination address.
-
-.TP
-.BI from " ADDRESS"
-the source address.
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-the Type Of Service.
-
-.TP
-.BI iif " NAME"
-the device from which this packet is expected to arrive.
-
-.TP
-.BI oif " NAME"
-force the output device on which this packet will be routed.
-
-.TP
-.B connected
-if no source address
-.RB "(option " from ")"
-was given, relookup the route with the source set to the preferred
-address received from the first lookup.
-If policy routing is used, it may be a different route.
-
-.P
-Note that this operation is not equivalent to
-.BR "ip route show" .
-.B show
-shows existing routes.
-.B get
-resolves them and creates new clones if necessary. Essentially,
-.B get
-is equivalent to sending a packet along this path.
-If the
-.B iif
-argument is not given, the kernel creates a route
-to output packets towards the requested destination.
-This is equivalent to pinging the destination
-with a subsequent
-.BR "ip route ls cache" ,
-however, no packets are actually sent. With the
-.B iif
-argument, the kernel pretends that a packet arrived from this interface
-and searches for a path to forward the packet.
-
-.SH ip rule - routing policy database management
-
-.BR "Rule" s
-in the routing policy database control the route selection algorithm.
-
-.P
-Classic routing algorithms used in the Internet make routing decisions
-based only on the destination address of packets (and in theory,
-but not in practice, on the TOS field).
-
-.P
-In some circumstances we want to route packets differently depending not only
-on destination addresses, but also on other packet fields: source address,
-IP protocol, transport protocol ports or even packet payload.
-This task is called 'policy routing'.
-
-.P
-To solve this task, the conventional destination based routing table, ordered
-according to the longest match rule, is replaced with a 'routing policy
-database' (or RPDB), which selects routes by executing some set of rules.
-
-.P
-Each policy routing rule consists of a
-.B selector
-and an
-.B action predicate.
-The RPDB is scanned in the order of increasing priority. The selector
-of each rule is applied to {source address, destination address, incoming
-interface, tos, fwmark} and, if the selector matches the packet,
-the action is performed. The action predicate may return with success.
-In this case, it will either give a route or failure indication
-and the RPDB lookup is terminated. Otherwise, the RPDB program
-continues on the next rule.
-
-.P
-Semantically, natural action is to select the nexthop and the output device.
-
-.P
-At startup time the kernel configures the default RPDB consisting of three
-rules:
-
-.TP
-1.
-Priority: 0, Selector: match anything, Action: lookup routing
-table
-.B local
-(ID 255).
-The
-.B local
-table is a special routing table containing
-high priority control routes for local and broadcast addresses.
-.sp
-Rule 0 is special. It cannot be deleted or overridden.
-
-.TP
-2.
-Priority: 32766, Selector: match anything, Action: lookup routing
-table
-.B main
-(ID 254).
-The
-.B main
-table is the normal routing table containing all non-policy
-routes. This rule may be deleted and/or overridden with other
-ones by the administrator.
-
-.TP
-3.
-Priority: 32767, Selector: match anything, Action: lookup routing
-table
-.B default
-(ID 253).
-The
-.B default
-table is empty. It is reserved for some post-processing if no previous
-default rules selected the packet.
-This rule may also be deleted.
-
-.P
-Each RPDB entry has additional
-attributes. F.e. each rule has a pointer to some routing
-table. NAT and masquerading rules have an attribute to select new IP
-address to translate/masquerade. Besides that, rules have some
-optional attributes, which routes have, namely
-.BR "realms" .
-These values do not override those contained in the routing tables. They
-are only used if the route did not select any attributes.
-
-.sp
-The RPDB may contain rules of the following types:
-
-.in +8
-.B unicast
-- the rule prescribes to return the route found
-in the routing table referenced by the rule.
-
-.B blackhole
-- the rule prescribes to silently drop the packet.
-
-.B unreachable
-- the rule prescribes to generate a 'Network is unreachable' error.
-
-.B prohibit
-- the rule prescribes to generate 'Communication is administratively
-prohibited' error.
-
-.B nat
-- the rule prescribes to translate the source address
-of the IP packet into some other value.
-.in -8
-
-.SS ip rule add - insert a new rule
-.SS ip rule delete - delete a rule
-
-.TP
-.BI type " TYPE " (default)
-the type of this rule. The list of valid types was given in the previous
-subsection.
-
-.TP
-.BI from " PREFIX"
-select the source prefix to match.
-
-.TP
-.BI to " PREFIX"
-select the destination prefix to match.
-
-.TP
-.BI iif " NAME"
-select the incoming device to match. If the interface is loopback,
-the rule only matches packets originating from this host. This means
-that you may create separate routing tables for forwarded and local
-packets and, hence, completely segregate them.
-
-.TP
-.BI tos " TOS"
-.TP
-.BI dsfield " TOS"
-select the TOS value to match.
-
-.TP
-.BI fwmark " MARK"
-select the
-.B fwmark
-value to match.
-
-.TP
-.BI priority " PREFERENCE"
-the priority of this rule. Each rule should have an explicitly
-set
-.I unique
-priority value.
-
-.TP
-.BI table " TABLEID"
-the routing table identifier to lookup if the rule selector matches.
-
-.TP
-.BI realms " FROM/TO"
-Realms to select if the rule matched and the routing table lookup
-succeeded. Realm
-.I TO
-is only used if the route did not select any realm.
-
-.TP
-.BI nat " ADDRESS"
-The base of the IP address block to translate (for source addresses).
-The
-.I ADDRESS
-may be either the start of the block of NAT addresses (selected by NAT
-routes) or a local host address (or even zero).
-In the last case the router does not translate the packets, but
-masquerades them to this address.
-
-.B Warning:
-Changes to the RPDB made with these commands do not become active
-immediately. It is assumed that after a script finishes a batch of
-updates, it flushes the routing cache with
-.BR "ip route flush cache" .
-
-.SS ip rule show - list rules
-This command has no arguments.
-
-.SH ip maddress - multicast addresses management
-
-.B maddress
-objects are multicast addresses.
-
-.SS ip maddress show - list multicast addresses
-
-.TP
-.BI dev " NAME " (default)
-the device name.
-
-.SS ip maddress add - add a multicast address
-.SS ip maddress delete - delete a multicast address
-these commands attach/detach a static link layer multicast address
-to listen on the interface.
-Note that it is impossible to join protocol multicast groups
-statically. This command only manages link layer addresses.
-
-.TP
-.BI address " LLADDRESS " (default)
-the link layer multicast address.
-
-.TP
-.BI dev " NAME"
-the device to join/leave this multicast address.
-
-.SH ip mroute - multicast routing cache management
-.B mroute
-objects are multicast routing cache entries created by a user level
-mrouting daemon (f.e.
-.B pimd
-or
-.B mrouted
-).
-
-Due to the limitations of the current interface to the multicast routing
-engine, it is impossible to change
-.B mroute
-objects administratively, so we may only display them. This limitation
-will be removed in the future.
-
-.SS ip mroute show - list mroute cache entries
-
-.TP
-.BI to " PREFIX " (default)
-the prefix selecting the destination multicast addresses to list.
-
-.TP
-.BI iif " NAME"
-the interface on which multicast packets are received.
-
-.TP
-.BI from " PREFIX"
-the prefix selecting the IP source addresses of the multicast route.
-
-.SH ip tunnel - tunnel configuration
-.B tunnel
-objects are tunnels, encapsulating packets in IPv4 packets and then
-sending them over the IP infrastructure.
-
-.SS ip tunnel add - add a new tunnel
-.SS ip tunnel change - change an existing tunnel
-.SS ip tunnel delete - destroy a tunnel
-
-.TP
-.BI name " NAME " (default)
-select the tunnel device name.
-
-.TP
-.BI mode " MODE"
-set the tunnel mode. Three modes are currently available:
-.BR ipip ", " sit " and " gre "."
-
-.TP
-.BI remote " ADDRESS"
-set the remote endpoint of the tunnel.
-
-.TP
-.BI local " ADDRESS"
-set the fixed local address for tunneled packets.
-It must be an address on another interface of this host.
-
-.TP
-.BI ttl " N"
-set a fixed TTL
-.I N
-on tunneled packets.
-.I N
-is a number in the range 1--255. 0 is a special value
-meaning that packets inherit the TTL value.
-The default value is:
-.BR "inherit" .
-
-.TP
-.BI tos " T"
-.TP
-.BI dsfield " T"
-set a fixed TOS
-.I T
-on tunneled packets.
-The default value is:
-.BR "inherit" .
-
-.TP
-.BI dev " NAME"
-bind the tunnel to the device
-.I NAME
-so that tunneled packets will only be routed via this device and will
-not be able to escape to another device when the route to endpoint
-changes.
-
-.TP
-.B nopmtudisc
-disable Path MTU Discovery on this tunnel.
-It is enabled by default. Note that a fixed ttl is incompatible
-with this option: tunnelling with a fixed ttl always makes pmtu
-discovery.
-
-.TP
-.BI key " K"
-.TP
-.BI ikey " K"
-.TP
-.BI okey " K"
-.RB ( " only GRE tunnels " )
-use keyed GRE with key
-.IR K ". " K
-is either a number or an IP address-like dotted quad.
-The
-.B key
-parameter sets the key to use in both directions.
-The
-.BR ikey " and " okey
-parameters set different keys for input and output.
-
-.TP
-.BR csum ", " icsum ", " ocsum
-.RB ( " only GRE tunnels " )
-generate/require checksums for tunneled packets.
-The
-.B ocsum
-flag calculates checksums for outgoing packets.
-The
-.B icsum
-flag requires that all input packets have the correct
-checksum. The
-.B csum
-flag is equivalent to the combination
-.BR "icsum ocsum" .
-
-.TP
-.BR seq ", " iseq ", " oseq
-.RB ( " only GRE tunnels " )
-serialize packets.
-The
-.B oseq
-flag enables sequencing of outgoing packets.
-The
-.B iseq
-flag requires that all input packets are serialized.
-The
-.B seq
-flag is equivalent to the combination
-.BR "iseq oseq" .
-.B It isn't work. Don't use it.
-
-.SS ip tunnel show - list tunnels
-This command has no arguments.
-
-.SH ip monitor and rtmon - state monitoring
-
-The
-.B ip
-utility can monitor the state of devices, addresses
-and routes continuously. This option has a slightly different format.
-Namely, the
-.B monitor
-command is the first in the command line and then the object list follows:
-
-.BR "ip monitor" " [ " all " |"
-.IR LISTofOBJECTS " ]"
-
-.I OBJECT-LIST
-is the list of object types that we want to monitor.
-It may contain
-.BR link ", " address " and " route "."
-If no
-.B file
-argument is given,
-.B ip
-opens RTNETLINK, listens on it and dumps state changes in the format
-described in previous sections.
-
-.P
-If a file name is given, it does not listen on RTNETLINK,
-but opens the file containing RTNETLINK messages saved in binary format
-and dumps them. Such a history file can be generated with the
-.B rtmon
-utility. This utility has a command line syntax similar to
-.BR "ip monitor" .
-Ideally,
-.B rtmon
-should be started before the first network configuration command
-is issued. F.e. if you insert:
-.sp
-.in +8
-rtmon file /var/log/rtmon.log
-.in -8
-.sp
-in a startup script, you will be able to view the full history
-later.
-
-.P
-Certainly, it is possible to start
-.B rtmon
-at any time.
-It prepends the history with the state snapshot dumped at the moment
-of starting.
-
-.SH HISTORY
-
-.B ip
-was written by Alexey N. Kuznetsov and added in Linux 2.2.
-.SH SEE ALSO
-.BR tc (8)
-.br
-.RB "IP Command reference " ip-cref.ps
-.br
-.RB "IP tunnels " ip-cref.ps
-
-.SH AUTHOR
-
-Manpage maintained by Michail Litvak <mci@owl.openwall.com>
-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
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
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=$?
( sleep 2 ;
arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
-ip route add unreachable 224.0.0.0/24 >& /dev/null
+ip route add unreachable 224.0.0.0/24 >& /dev/null
ip route add unreachable 255.255.255.255 >& /dev/null
if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
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));
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);
int (*func)(int argc, char **argv);
} cmds[] = {
{ "address", do_ipaddr },
+ { "addrlabel", do_ipaddrlabel },
{ "maddress", do_multiaddr },
{ "route", do_iproute },
{ "rule", do_iprule },
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;
}
basename = argv[0];
else
basename++;
-
+
while (argc > 1) {
char *opt = argv[1];
if (strcmp(opt,"--") == 0) {
} 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) {
_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);
--- /dev/null
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on:
+ * $Id: s.ipv6tunnel.c 1.7 02/12/11 11:21:51+02:00 antti@traci.mipl.mediapoli.com $
+ *
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <linux/ip.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+
+#define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
+
+#define DEFAULT_TNL_HOP_LIMIT (64)
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
+ fprintf(stderr, " [ mode { ip6ip6 | ipip6 | any } ]\n");
+ fprintf(stderr, " [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, " [ encaplimit ELIM ]\n");
+ fprintf(stderr ," [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ fprintf(stderr, " [ dscp inherit ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
+ fprintf(stderr, " ELIM := { none | 0..255 }(default=%d)\n",
+ IPV6_DEFAULT_TNL_ENCAP_LIMIT);
+ fprintf(stderr, " TTL := 0..255 (default=%d)\n",
+ DEFAULT_TNL_HOP_LIMIT);
+ fprintf(stderr, " TOS := { 0x0..0xff | inherit }\n");
+ fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ exit(-1);
+}
+
+static void print_tunnel(struct ip6_tnl_parm *p)
+{
+ char remote[64];
+ char local[64];
+
+ inet_ntop(AF_INET6, &p->raddr, remote, sizeof(remote));
+ inet_ntop(AF_INET6, &p->laddr, local, sizeof(local));
+
+ printf("%s: %s/ipv6 remote %s local %s",
+ p->name, tnl_strproto(p->proto), remote, local);
+ if (p->link) {
+ char *n = tnl_ioctl_get_ifname(p->link);
+ if (n)
+ printf(" dev %s", n);
+ }
+
+ if (p->flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
+ printf(" encaplimit none");
+ else
+ printf(" encaplimit %u", p->encap_limit);
+
+ printf(" hoplimit %u", p->hop_limit);
+
+ if (p->flags & IP6_TNL_F_USE_ORIG_TCLASS)
+ printf(" tclass inherit");
+ else {
+ __u32 val = ntohl(p->flowinfo & IP6_FLOWINFO_TCLASS);
+ printf(" tclass 0x%02x", (__u8)(val >> 20));
+ }
+
+ if (p->flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ printf(" flowlabel inherit");
+ else
+ printf(" flowlabel 0x%05x", ntohl(p->flowinfo & IP6_FLOWINFO_FLOWLABEL));
+
+ printf(" (flowinfo 0x%08x)", ntohl(p->flowinfo));
+
+ if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
+ printf(" dscp inherit");
+}
+
+static int parse_args(int argc, char **argv, struct ip6_tnl_parm *p)
+{
+ char medium[IFNAMSIZ];
+
+ memset(medium, 0, sizeof(medium));
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "ipv6/ipv6") == 0 ||
+ strcmp(*argv, "ip6ip6") == 0)
+ p->proto = IPPROTO_IPV6;
+ else if (strcmp(*argv, "ip/ipv6") == 0 ||
+ strcmp(*argv, "ipv4/ipv6") == 0 ||
+ strcmp(*argv, "ipip6") == 0 ||
+ strcmp(*argv, "ip4ip6") == 0)
+ p->proto = IPPROTO_IPIP;
+ else if (strcmp(*argv, "any/ipv6") == 0 ||
+ strcmp(*argv, "any") == 0)
+ p->proto = 0;
+ else {
+ fprintf(stderr,"Cannot guess tunnel mode.\n");
+ exit(-1);
+ }
+ } else if (strcmp(*argv, "remote") == 0) {
+ inet_prefix raddr;
+ NEXT_ARG();
+ get_prefix(&raddr, *argv, preferred_family);
+ if (raddr.family == AF_UNSPEC)
+ invarg("\"remote\" address family is AF_UNSPEC", *argv);
+ memcpy(&p->raddr, &raddr.data, sizeof(p->raddr));
+ } else if (strcmp(*argv, "local") == 0) {
+ inet_prefix laddr;
+ NEXT_ARG();
+ get_prefix(&laddr, *argv, preferred_family);
+ if (laddr.family == AF_UNSPEC)
+ invarg("\"local\" address family is AF_UNSPEC", *argv);
+ memcpy(&p->laddr, &laddr.data, sizeof(p->laddr));
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ - 1);
+ } else if (strcmp(*argv, "encaplimit") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "none") == 0) {
+ p->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
+ } else {
+ __u8 uval;
+ if (get_u8(&uval, *argv, 0) < -1)
+ invarg("invalid ELIM", *argv);
+ p->encap_limit = uval;
+ }
+ } else if (strcmp(*argv, "hoplimit") == 0 ||
+ strcmp(*argv, "ttl") == 0 ||
+ strcmp(*argv, "hlim") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid TTL", *argv);
+ p->hop_limit = uval;
+ } else if (strcmp(*argv, "tclass") == 0 ||
+ strcmp(*argv, "tc") == 0 ||
+ strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ p->flags |= IP6_TNL_F_USE_ORIG_TCLASS;
+ else {
+ if (get_u8(&uval, *argv, 16))
+ invarg("invalid TClass", *argv);
+ p->flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
+ p->flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
+ }
+ } else if (strcmp(*argv, "flowlabel") == 0 ||
+ strcmp(*argv, "fl") == 0) {
+ __u32 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ p->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ else {
+ if (get_u32(&uval, *argv, 16))
+ invarg("invalid Flowlabel", *argv);
+ if (uval > 0xFFFFF)
+ invarg("invalid Flowlabel", *argv);
+ p->flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
+ p->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ }
+ } else if (strcmp(*argv, "dscp") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0)
+ invarg("not inherit", *argv);
+ p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else {
+ if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (p->name[0])
+ duparg2("name", *argv);
+ strncpy(p->name, *argv, IFNAMSIZ - 1);
+ }
+ argc--; argv++;
+ }
+ if (medium[0]) {
+ p->link = tnl_ioctl_get_ifindex(medium);
+ if (p->link == 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
+{
+ memset(p, 0, sizeof(*p));
+ p->proto = IPPROTO_IPV6;
+ if (apply_default) {
+ p->hop_limit = DEFAULT_TNL_HOP_LIMIT;
+ p->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+ }
+}
+
+/*
+ * @p1: user specified parameter
+ * @p2: database entry
+ */
+static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
+ const struct ip6_tnl_parm *p2)
+{
+ return ((!p1->link || p1->link == p2->link) &&
+ (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+ (memcmp(&p1->laddr, &in6addr_any, sizeof(p1->laddr)) == 0 ||
+ memcmp(&p1->laddr, &p2->laddr, sizeof(p1->laddr)) == 0) &&
+ (memcmp(&p1->raddr, &in6addr_any, sizeof(p1->raddr)) == 0 ||
+ memcmp(&p1->raddr, &p2->raddr, sizeof(p1->raddr)) == 0) &&
+ (!p1->proto || !p2->proto || p1->proto == p2->proto) &&
+ (!p1->encap_limit || p1->encap_limit == p2->encap_limit) &&
+ (!p1->hop_limit || p1->hop_limit == p2->hop_limit) &&
+ (!(p1->flowinfo & IP6_FLOWINFO_TCLASS) ||
+ !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_TCLASS)) &&
+ (!(p1->flowinfo & IP6_FLOWINFO_FLOWLABEL) ||
+ !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_FLOWLABEL)) &&
+ (!p1->flags || (p1->flags & p2->flags)));
+}
+
+static int do_tunnels_list(struct ip6_tnl_parm *p)
+{
+ char buf[512];
+ int err = -1;
+ FILE *fp = fopen("/proc/net/dev", "r");
+ if (fp == NULL) {
+ perror("fopen");
+ goto end;
+ }
+
+ /* skip two lines at the begenning of the file */
+ fgets(buf, sizeof(buf), fp);
+ fgets(buf, sizeof(buf), fp);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ char name[IFNAMSIZ];
+ int type;
+ unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+ rx_fifo, rx_frame,
+ tx_bytes, tx_packets, tx_errs, tx_drops,
+ tx_fifo, tx_colls, tx_carrier, rx_multi;
+ struct ip6_tnl_parm p1;
+ char *ptr;
+
+ buf[sizeof(buf) - 1] = '\0';
+ if ((ptr = strchr(buf, ':')) == NULL ||
+ (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
+ fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
+ goto end;
+ }
+ if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+ &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+ &rx_fifo, &rx_frame, &rx_multi,
+ &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+ &tx_fifo, &tx_colls, &tx_carrier) != 14)
+ continue;
+ if (p->name[0] && strcmp(p->name, name))
+ continue;
+ type = tnl_ioctl_get_iftype(name);
+ if (type == -1) {
+ fprintf(stderr, "Failed to get type of [%s]\n", name);
+ continue;
+ }
+ if (type != ARPHRD_TUNNEL6)
+ continue;
+ memset(&p1, 0, sizeof(p1));
+ ip6_tnl_parm_init(&p1, 0);
+ strcpy(p1.name, name);
+ p1.link = tnl_ioctl_get_ifindex(p1.name);
+ if (p1.link == 0)
+ continue;
+ if (tnl_get_ioctl(p1.name, &p1))
+ continue;
+ if (!ip6_tnl_parm_match(p, &p1))
+ continue;
+ print_tunnel(&p1);
+ if (show_stats) {
+ printf("%s", _SL_);
+ printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
+ rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+ printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
+ tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+ }
+ printf("\n");
+ }
+ err = 0;
+
+ end:
+ if (fp)
+ fclose(fp);
+ return err;
+}
+
+static int do_show(int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ip6_tnl_parm_init(&p, 0);
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ if (!p.name[0] || show_stats)
+ do_tunnels_list(&p);
+ else {
+ if (tnl_get_ioctl(p.name, &p))
+ return -1;
+ print_tunnel(&p);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int do_add(int cmd, int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ip6_tnl_parm_init(&p, 1);
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ return tnl_add_ioctl(cmd,
+ cmd == SIOCCHGTUNNEL && p.name[0] ?
+ p.name : "ip6tnl0", p.name, &p);
+}
+
+static int do_del(int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ip6_tnl_parm_init(&p, 1);
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
+}
+
+int do_ip6tunnel(int argc, char **argv)
+{
+ switch (preferred_family) {
+ case AF_UNSPEC:
+ preferred_family = AF_INET6;
+ break;
+ case AF_INET6:
+ break;
+ default:
+ fprintf(stderr, "Unsupported family:%d\n", preferred_family);
+ exit(-1);
+ }
+
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
+ if (matches(*argv, "change") == 0)
+ return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc - 1, argv + 1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc - 1, argv + 1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return do_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip -f inet6 tunnel help\".\n", *argv);
+ exit(-1);
+}
-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,
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
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <sys/errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "ll_map.h"
#include "ip_common.h"
+#define MAX_ROUNDS 10
+
static struct
{
int ifindex;
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");
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);
}
_PF(PORTSEL);
_PF(NOTRAILERS);
_PF(UP);
+ _PF(LOWER_UP);
+ _PF(DORMANT);
#undef _PF
if (flags)
fprintf(fp, "%x", flags);
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;
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;
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_);
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]);
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);
}
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
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");
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;
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;
}
-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;
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;
} 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;
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);
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;
}
fflush(stdout);
}
}
+ fprintf(stderr, "*** Flush remains incomplete after %d rounds. ***\n", MAX_ROUNDS); fflush(stderr);
+ return 1;
}
if (filter.family != AF_PACKET) {
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)
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)
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;
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;
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;
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();
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);
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);
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);
}
--- /dev/null
+/*
+ * ipaddrlabel.c "ip addrlabel"
+ *
+ * Copyright (C)2007 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Based on iprule.c.
+ *
+ * Authors: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/types.h>
+#include <linux/if_addrlabel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define IFAL_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
+#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
+
+extern struct rtnl_handle rth;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
+ exit(-1);
+}
+
+int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ int host_len = -1;
+ struct rtattr *tb[IFAL_MAX+1];
+ char abuf[256];
+
+ if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
+ return 0;
+
+ len -= NLMSG_LENGTH(sizeof(*ifal));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
+
+ if (ifal->ifal_family == AF_INET)
+ host_len = 32;
+ else if (ifal->ifal_family == AF_INET6)
+ host_len = 128;
+
+ if (n->nlmsg_type == RTM_DELADDRLABEL)
+ fprintf(fp, "Deleted ");
+
+ if (tb[IFAL_ADDRESS]) {
+ fprintf(fp, "prefix %s/%u ",
+ format_host(ifal->ifal_family,
+ RTA_PAYLOAD(tb[IFAL_ADDRESS]),
+ RTA_DATA(tb[IFAL_ADDRESS]),
+ abuf, sizeof(abuf)),
+ ifal->ifal_prefixlen);
+ }
+
+ if (ifal->ifal_index)
+ fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
+
+ if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
+ int32_t label;
+ memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
+ fprintf(fp, "label %d ", label);
+ }
+
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+static int ipaddrlabel_list(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET6;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, print_addrlabel, stdout, NULL, NULL) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int ipaddrlabel_modify(int cmd, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrlblmsg ifal;
+ char buf[1024];
+ } req;
+
+ inet_prefix prefix;
+ uint32_t label = 0xffffffffUL;
+ char *p = NULL;
+ char *l = NULL;
+
+ memset(&req, 0, sizeof(req));
+ memset(&prefix, 0, sizeof(prefix));
+
+ req.n.nlmsg_type = cmd;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.ifal.ifal_family = preferred_family;
+ req.ifal.ifal_prefixlen = 0;
+ req.ifal.ifal_index = 0;
+
+ if (cmd == RTM_NEWADDRLABEL) {
+ req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+ }
+
+ while (argc > 0) {
+ if (strcmp(*argv, "prefix") == 0) {
+ NEXT_ARG();
+ p = *argv;
+ get_prefix(&prefix, *argv, preferred_family);
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
+ invarg("dev is invalid\n", *argv);
+ } else if (strcmp(*argv, "label") == 0) {
+ NEXT_ARG();
+ l = *argv;
+ if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
+ invarg("label is invalid\n", *argv);
+ }
+ argc--;
+ argv++;
+ }
+ if (p == NULL) {
+ fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
+ return -1;
+ }
+ if (l == NULL) {
+ fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
+ return -1;
+ }
+ addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
+ addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
+ req.ifal.ifal_prefixlen = prefix.bitlen;
+
+ if (req.ifal.ifal_family == AF_UNSPEC)
+ req.ifal.ifal_family = AF_INET6;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ return 2;
+
+ return 0;
+}
+
+
+static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct rtnl_handle rth2;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[IFAL_MAX+1];
+
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
+
+ if (tb[IFAL_ADDRESS]) {
+ n->nlmsg_type = RTM_DELADDRLABEL;
+ n->nlmsg_flags = NLM_F_REQUEST;
+
+ if (rtnl_open(&rth2, 0) < 0)
+ return -1;
+
+ if (rtnl_talk(&rth2, n, 0, 0, NULL, NULL, NULL) < 0)
+ return -2;
+
+ rtnl_close(&rth2);
+ }
+
+ return 0;
+}
+
+static int ipaddrlabel_flush(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET6;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, flush_addrlabel, NULL, NULL, NULL) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int do_ipaddrlabel(int argc, char **argv)
+{
+ if (argc < 1) {
+ return ipaddrlabel_list(0, NULL);
+ } else if (matches(argv[0], "list") == 0 ||
+ matches(argv[0], "show") == 0) {
+ return ipaddrlabel_list(argc-1, argv+1);
+ } else if (matches(argv[0], "add") == 0) {
+ return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
+ } else if (matches(argv[0], "delete") == 0) {
+ return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
+ } else if (matches(argv[0], "flush") == 0) {
+ return ipaddrlabel_flush(argc-1, argv+1);
+ } else if (matches(argv[0], "help") == 0)
+ usage();
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
+ exit(-1);
+}
+
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
+#include <dlfcn.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/if.h>
#include "utils.h"
#include "ip_common.h"
+#define IPLINK_IOCTL_COMPAT 1
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
static void usage(void) __attribute__((noreturn));
+static int iplink_have_newlink(void);
void iplink_usage(void)
{
- fprintf(stderr, "Usage: ip link set DEVICE { up | down |\n");
- fprintf(stderr, " arp { on | off } |\n");
- fprintf(stderr, " dynamic { on | off } |\n");
- fprintf(stderr, " multicast { on | off } |\n");
- fprintf(stderr, " allmulticast { on | off } |\n");
- fprintf(stderr, " promisc { on | off } |\n");
- fprintf(stderr, " trailers { on | off } |\n");
- fprintf(stderr, " txqueuelen PACKETS |\n");
- fprintf(stderr, " name NEWNAME |\n");
- fprintf(stderr, " address LLADDR | broadcast LLADDR |\n");
- fprintf(stderr, " mtu MTU }\n");
+ if (iplink_have_newlink()) {
+ fprintf(stderr, "Usage: ip link add link DEV [ name ] NAME\n");
+ fprintf(stderr, " [ txqueuelen PACKETS ]\n");
+ fprintf(stderr, " [ address LLADDR ]\n");
+ fprintf(stderr, " [ broadcast LLADDR ]\n");
+ fprintf(stderr, " [ mtu MTU ]\n");
+ fprintf(stderr, " type TYPE [ ARGS ]\n");
+ fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " ip link set DEVICE [ { up | down } ]\n");
+ } else
+ fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
+
+ fprintf(stderr, " [ arp { on | off } ]\n");
+ fprintf(stderr, " [ dynamic { on | off } ]\n");
+ fprintf(stderr, " [ multicast { on | off } ]\n");
+ fprintf(stderr, " [ allmulticast { on | off } ]\n");
+ fprintf(stderr, " [ promisc { on | off } ]\n");
+ fprintf(stderr, " [ trailers { on | off } ]\n");
+ fprintf(stderr, " [ txqueuelen PACKETS ]\n");
+ fprintf(stderr, " [ name NEWNAME ]\n");
+ fprintf(stderr, " [ address LLADDR ]\n");
+ fprintf(stderr, " [ broadcast LLADDR ]\n");
+ fprintf(stderr, " [ mtu MTU ]\n");
+ fprintf(stderr, " [ netns PID ]\n");
fprintf(stderr, " ip link show [ DEVICE ]\n");
+
+ if (iplink_have_newlink()) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "TYPE := { vlan | veth | dummy | ifb | macvlan }\n");
+ }
exit(-1);
}
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;
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);
}
close(s);
- return 0;
+ return 0;
}
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);
}
close(s);
- return 0;
+ return 0;
}
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;
}
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;
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)
return -1;
}
close(s);
- return 0;
+ return 0;
}
}
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)
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)
--- /dev/null
+/*
+ * iplink_vlan.c VLAN device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Patrick McHardy <kaber@trash.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/if_vlan.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+ fprintf(stderr,
+ "Usage: ... vlan id VLANID [ FLAG-LIST ]\n"
+ " [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
+ "\n"
+ "VLANID := 0-4095\n"
+ "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
+ "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+ "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
+ "QOS-MAPPING := FROM:TO\n"
+ );
+}
+
+static int on_off(char *msg)
+{
+ fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
+ return -1;
+}
+
+static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
+ int attrtype)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ struct ifla_vlan_qos_mapping m;
+ struct rtattr *tail;
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 1024, attrtype, NULL, 0);
+
+ while (argc > 0) {
+ char *colon = strchr(*argv, ':');
+
+ if (!colon)
+ break;
+ *colon = '\0';
+
+ if (get_u32(&m.from, *argv, 0))
+ return 1;
+ if (get_u32(&m.to, colon + 1, 0))
+ return 1;
+ argc--, argv++;
+
+ addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
+ }
+
+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+
+ *argcp = argc;
+ *argvp = argv;
+ return 0;
+}
+
+static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct ifla_vlan_flags flags = { 0 };
+ __u16 id;
+
+ while (argc > 0) {
+ if (matches(*argv, "id") == 0) {
+ NEXT_ARG();
+ if (get_u16(&id, *argv, 0))
+ invarg("id is invalid", *argv);
+ addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
+ } else if (matches(*argv, "reorder_hdr") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_REORDER_HDR;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_REORDER_HDR;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_REORDER_HDR;
+ else
+ return on_off("reorder_hdr");
+ } else if (matches(*argv, "gvrp") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_GVRP;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_GVRP;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_GVRP;
+ else
+ return on_off("gvrp");
+ } else if (matches(*argv, "ingress-qos-map") == 0) {
+ NEXT_ARG();
+ if (vlan_parse_qos_map(&argc, &argv, n,
+ IFLA_VLAN_INGRESS_QOS))
+ invarg("invalid ingress-qos-map", *argv);
+ continue;
+ } else if (matches(*argv, "egress-qos-map") == 0) {
+ NEXT_ARG();
+ if (vlan_parse_qos_map(&argc, &argv, n,
+ IFLA_VLAN_EGRESS_QOS))
+ invarg("invalid egress-qos-map", *argv);
+ continue;
+ } else if (matches(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "vlan: what is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ if (flags.mask)
+ addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+
+ return 0;
+}
+
+static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+{
+ struct ifla_vlan_qos_mapping *m;
+ struct rtattr *i;
+ int rem;
+
+ fprintf(f, "\n %s { ", name);
+
+ rem = RTA_PAYLOAD(attr);
+ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ m = RTA_DATA(i);
+ fprintf(f, "%u:%u ", m->from, m->to);
+ }
+ fprintf(f, "} ");
+}
+
+static void vlan_print_flags(FILE *fp, __u32 flags)
+{
+ fprintf(fp, "<");
+#define _PF(f) if (flags & VLAN_FLAG_##f) { \
+ flags &= ~ VLAN_FLAG_##f; \
+ fprintf(fp, #f "%s", flags ? "," : ""); \
+ }
+ _PF(REORDER_HDR);
+ _PF(GVRP);
+#undef _PF
+ if (flags)
+ fprintf(fp, "%x", flags);
+ fprintf(fp, "> ");
+}
+
+static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ struct ifla_vlan_flags *flags;
+ if (!tb)
+ return;
+
+ if (!tb[IFLA_VLAN_ID] ||
+ RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
+ return;
+
+ fprintf(f, "id %u ", *(__u16 *)RTA_DATA(tb[IFLA_VLAN_ID]));
+
+ if (tb[IFLA_VLAN_FLAGS]) {
+ if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
+ return;
+ flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
+ vlan_print_flags(f, flags->flags);
+ }
+ if (tb[IFLA_VLAN_INGRESS_QOS])
+ vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+ if (tb[IFLA_VLAN_EGRESS_QOS])
+ vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+}
+
+struct link_util vlan_link_util = {
+ .id = "vlan",
+ .maxattr = IFLA_VLAN_MAX,
+ .parse_opt = vlan_parse_opt,
+ .print_opt = vlan_print_opt,
+};
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;
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));
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));
fprintf(fp, "family %d ", list->addr.family);
break;
}
- fprintf(fp, "%s",
+ fprintf(fp, "%s",
format_host(list->addr.family,
-1,
list->addr.data,
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);
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;
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];
}
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) {
if (sscanf(buf, "%d%s", &vifi, dev) < 2)
continue;
-
+
if (vifi<0 || vifi>31)
continue;
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)));
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
-#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
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;
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));
}
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]),
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,
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;
}
/*
* 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
/*
* 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
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);
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <linux/in_route.h>
-#include <linux/ip_mp_alg.h>
#include "rt_names.h"
#include "utils.h"
#endif
+static const char *mx_names[RTAX_MAX+1] = {
+ [RTAX_MTU] = "mtu",
+ [RTAX_WINDOW] = "window",
+ [RTAX_RTT] = "rtt",
+ [RTAX_RTTVAR] = "rttvar",
+ [RTAX_SSTHRESH] = "ssthresh",
+ [RTAX_CWND] = "cwnd",
+ [RTAX_ADVMSS] = "advmss",
+ [RTAX_REORDERING]="reordering",
+ [RTAX_HOPLIMIT] = "hoplimit",
+ [RTAX_INITCWND] = "initcwnd",
+ [RTAX_FEATURES] = "features",
+ [RTAX_RTO_MIN] = "rto_min",
+};
static void usage(void) __attribute__((noreturn));
static void usage(void)
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");
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);
}
static struct
{
int tb;
+ int cloned;
int flushed;
char *flushb;
int flushp;
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;
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",
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)
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])
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 &&
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]),
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)
/* 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]),
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)
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)
if (mxrta[RTAX_LOCK])
mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]);
- for (i=2; i<=RTAX_MAX; i++) {
- static char *mx_names[] =
- {
- "mtu",
- "window",
- "rtt",
- "rttvar",
- "ssthresh",
- "cwnd",
- "advmss",
- "reordering",
- };
- static int hz;
+ for (i=2; i<= RTAX_MAX; i++) {
if (mxrta[i] == NULL)
continue;
if (!hz)
hz = get_hz();
- if (i-2 < sizeof(mx_names)/sizeof(char*))
- fprintf(fp, " %s", mx_names[i-2]);
+
+ if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i])
+ fprintf(fp, " %s", mx_names[i]);
else
fprintf(fp, " metric %d", i);
if (mxlock & (1<<i))
fprintf(fp, " lock");
- if (i != RTAX_RTT && i != RTAX_RTTVAR)
+ if (i != RTAX_RTT && i != RTAX_RTTVAR &&
+ i != RTAX_RTO_MIN)
fprintf(fp, " %u", *(unsigned*)RTA_DATA(mxrta[i]));
else {
- unsigned val = *(unsigned*)RTA_DATA(mxrta[i]);
+ unsigned long long val = *(unsigned*)RTA_DATA(mxrta[i]);
val *= 1000;
if (i == RTAX_RTT)
val /= 8;
- else
+ else if (i == RTAX_RTTVAR)
val /= 4;
if (val >= hz)
- fprintf(fp, " %ums", val/hz);
+ fprintf(fp, " %llums", val/hz);
else
fprintf(fp, " %.2fms", (float)val/hz);
}
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));
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;
}
int table_ok = 0;
int proto_ok = 0;
int type_ok = 0;
+ int raw = 0;
memset(&req, 0, sizeof(req));
mxlock |= (1<<RTAX_RTT);
NEXT_ARG();
}
- if (get_unsigned(&rtt, *argv, 0))
+ if (get_jiffies(&rtt, *argv, 0, &raw))
invarg("\"rtt\" value is invalid\n", *argv);
- rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, rtt);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
+ (raw) ? rtt : rtt * 8);
+ } else if (strcmp(*argv, "rto_min") == 0) {
+ unsigned rto_min;
+ NEXT_ARG();
+ mxlock |= (1<<RTAX_RTO_MIN);
+ if (get_jiffies(&rto_min, *argv, 0, &raw))
+ invarg("\"rto_min\" value is invalid\n",
+ *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
+ rto_min);
} else if (matches(*argv, "window") == 0) {
unsigned win;
NEXT_ARG();
if (get_unsigned(&win, *argv, 0))
invarg("\"cwnd\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
+ } else if (matches(*argv, "initcwnd") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_INITCWND);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"initcwnd\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
} else if (matches(*argv, "rttvar") == 0) {
unsigned win;
NEXT_ARG();
mxlock |= (1<<RTAX_RTTVAR);
NEXT_ARG();
}
- if (get_unsigned(&win, *argv, 0))
+ if (get_jiffies(&win, *argv, 0, &raw))
invarg("\"rttvar\" value is invalid\n", *argv);
- rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR, win);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
+ (raw) ? win : win * 4);
} else if (matches(*argv, "ssthresh") == 0) {
unsigned win;
NEXT_ARG();
NEXT_ARG();
if (rtnl_rttable_a2n(&tid, *argv))
invarg("\"table\" value is invalid\n", *argv);
- req.r.rtm_table = tid;
+ if (tid < 256)
+ req.r.rtm_table = tid;
+ else {
+ req.r.rtm_table = RT_TABLE_UNSPEC;
+ addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
+ }
table_ok = 1;
} else if (strcmp(*argv, "dev") == 0 ||
strcmp(*argv, "oif") == 0) {
NEXT_ARG();
d = *argv;
- } else if (strcmp(*argv, "mpath") == 0 ||
- strcmp(*argv, "mp") == 0) {
- int i;
- __u32 mp_alg = IP_MP_ALG_NONE;
-
- NEXT_ARG();
- for (i = 1; i < ARRAY_SIZE(mp_alg_names); i++)
- if (strcmp(*argv, mp_alg_names[i]) == 0)
- mp_alg = i;
- if (mp_alg == IP_MP_ALG_NONE)
- invarg("\"mpath\" value is invalid\n", *argv);
- addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg));
} else {
int type;
inet_prefix dst;
}
len = strlen (buffer);
-
+
if ((write (flush_fd, (void *)buffer, len)) < len) {
fprintf (stderr, "Cannot flush routing cache\n");
return -1;
NEXT_ARG();
if (rtnl_rttable_a2n(&tid, *argv)) {
if (strcmp(*argv, "all") == 0) {
- tid = 0;
+ filter.tb = 0;
} else if (strcmp(*argv, "cache") == 0) {
- tid = -1;
+ filter.cloned = 1;
} else if (strcmp(*argv, "help") == 0) {
usage();
} else {
invarg("table id value is invalid\n", *argv);
}
- }
- filter.tb = tid;
+ } else
+ filter.tb = tid;
} else if (matches(*argv, "cached") == 0 ||
matches(*argv, "cloned") == 0) {
- filter.tb = -1;
+ filter.cloned = 1;
} else if (strcmp(*argv, "tos") == 0 ||
matches(*argv, "dsfield") == 0) {
__u32 tos;
char flushb[4096-512];
time_t start = time(0);
- if (filter.tb == -1) {
+ if (filter.cloned) {
if (do_ipv6 != AF_INET6) {
iproute_flush_cache();
if (show_stats)
exit(1);
}
if (filter.flushed == 0) {
- if (round == 0) {
- if (filter.tb != -1 || do_ipv6 == AF_INET6)
- fprintf(stderr, "Nothing to flush.\n");
- } else if (show_stats)
- printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+ if (show_stats) {
+ if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
+ printf("Nothing to flush.\n");
+ else
+ printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+ }
fflush(stdout);
return 0;
}
}
}
- if (filter.tb != -1) {
+ if (!filter.cloned) {
if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
perror("Cannot send dump request");
exit(1);
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) {
{
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);
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
+#include <linux/fib_rules.h>
#include "rt_names.h"
#include "utils.h"
+#include "ip_common.h"
extern struct rtnl_handle rth;
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;
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))
);
}
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) {
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) {
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");
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;
}
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) {
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();
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();
}
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++;
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;
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <syslog.h>
-#include <fcntl.h>
+#include <sys/types.h>
#include <sys/socket.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
-
-#ifndef __constant_htons
-#define __constant_htons(x) htons(x)
-#endif
-
#include <linux/if_tunnel.h>
#include "rt_names.h"
#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr, "Usage: ip tunnel { add | change | del | show } [ NAME ]\n");
- fprintf(stderr, " [ mode { ipip | gre | gre/ip | gre/eth | sit } ] [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ mode { ipip | gre | sit | isatap } ] [ remote ADDR ] [ local ADDR ]\n");
fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
fprintf(stderr, "\n");
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));
}
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) {
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);
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");
} 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) {
p->iph.ttl = uval;
}
} else if (strcmp(*argv, "tos") == 0 ||
+ strcmp(*argv, "tclass") == 0 ||
matches(*argv, "dsfield") == 0) {
__u32 uval;
NEXT_ARG();
} 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);
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;
}
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) {
}
if (medium[0]) {
- p->link = do_ioctl_get_ifindex(medium);
+ p->link = tnl_ioctl_get_ifindex(medium);
if (p->link == 0)
return -1;
}
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;
}
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;
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];
/* 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);
}
printf(" ttl %d ", p->iph.ttl);
else
printf(" ttl inherit ");
-
+
if (p->iph.tos) {
SPRINT_BUF(b1);
printf(" tos");
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;
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)) ||
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);
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);
/*
* 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
#include <sys/socket.h>
#include <time.h>
#include <netdb.h>
-#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/xfrm.h>
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);
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;
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 }
};
const char *strxf_xfrmproto(__u8 proto)
{
+ static char str[16];
int i;
for (i = 0; ; i++) {
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)
const char *strxf_algotype(int type)
{
+ static char str[32];
int i;
for (i = 0; ; i++) {
return t->t_name;
}
- return NULL;
+ sprintf(str, "%d", type);
+ return str;
}
const char *strxf_mask8(__u8 mask)
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)
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),
fprintf(fp, "%s", _SL_);
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, "\t");
fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
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;
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);
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;
{
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 ");
fprintf(fp, "%s", _SL_);
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, " ");
fprintf(fp, "limit: ");
fprintf(fp, "soft ");
fprintf(fp, "%s", _SL_);
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, " ");
fprintf(fp, "expire add: ");
fprintf(fp, "soft ");
fprintf(fp, "%s", _SL_);
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, " ");
fprintf(fp, "expire use: ");
fprintf(fp, "soft ");
}
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));
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),
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);
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));
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_);
}
if (ntmpls <= 0) {
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, "(ERROR \"tmpl\" truncated)");
fprintf(fp, "%s", _SL_);
return;
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:
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),
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),
char abuf[256];
if (prefix)
- fprintf(fp, prefix);
+ fputs(prefix, fp);
fprintf(fp, "encap ");
if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
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)
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);
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);
STRBUF_CAT(buf, prefix);
STRBUF_CAT(buf, "\t");
- fprintf(fp, buf);
+ fputs(buf, fp);
fprintf(fp, "dir ");
switch (xpinfo->dir) {
case XFRM_POLICY_IN:
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)
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);
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));
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);
}
--- /dev/null
+/*
+ * link_gre.c gre driver module
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/if_tunnel.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(stderr, " TOS := { NUMBER | inherit }\n");
+ fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ exit(-1);
+}
+
+static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ __u16 iflags = 0;
+ __u16 oflags = 0;
+ unsigned ikey = 0;
+ unsigned okey = 0;
+ unsigned saddr = 0;
+ unsigned daddr = 0;
+ unsigned link = 0;
+ __u8 pmtudisc = 1;
+ __u8 ttl = 0;
+ __u8 tos = 0;
+ int len;
+
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_family = preferred_family;
+ req.i.ifi_index = ifi->ifi_index;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
+get_failed:
+ fprintf(stderr,
+ "Failed to get existing tunnel info.\n");
+ return -1;
+ }
+
+ len = req.n.nlmsg_len;
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ goto get_failed;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+
+ if (!tb[IFLA_LINKINFO])
+ goto get_failed;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!linkinfo[IFLA_INFO_DATA])
+ goto get_failed;
+
+ parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
+ linkinfo[IFLA_INFO_DATA]);
+
+ if (greinfo[IFLA_GRE_IKEY])
+ ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
+
+ if (greinfo[IFLA_GRE_OKEY])
+ okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
+
+ if (greinfo[IFLA_GRE_IFLAGS])
+ iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
+
+ if (greinfo[IFLA_GRE_OFLAGS])
+ oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
+
+ if (greinfo[IFLA_GRE_LOCAL])
+ saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
+
+ if (greinfo[IFLA_GRE_REMOTE])
+ daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
+
+ if (greinfo[IFLA_GRE_PMTUDISC])
+ pmtudisc = *(__u8 *)RTA_DATA(
+ greinfo[IFLA_GRE_PMTUDISC]);
+
+ if (greinfo[IFLA_GRE_TTL])
+ ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
+
+ if (greinfo[IFLA_GRE_TOS])
+ tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
+
+ if (greinfo[IFLA_GRE_LINK])
+ link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
+ }
+
+ while (argc > 0) {
+ if (!matches(*argv, "key")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0) < 0) {
+ fprintf(stderr,
+ "Invalid value for \"key\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+
+ ikey = okey = uval;
+ } else if (!matches(*argv, "ikey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"ikey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ ikey = uval;
+ } else if (!matches(*argv, "okey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"okey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ okey = uval;
+ } else if (!matches(*argv, "seq")) {
+ iflags |= GRE_SEQ;
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "iseq")) {
+ iflags |= GRE_SEQ;
+ } else if (!matches(*argv, "oseq")) {
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "csum")) {
+ iflags |= GRE_CSUM;
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "icsum")) {
+ iflags |= GRE_CSUM;
+ } else if (!matches(*argv, "ocsum")) {
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "nopmtudisc")) {
+ pmtudisc = 0;
+ } else if (!matches(*argv, "pmtudisc")) {
+ pmtudisc = 1;
+ } else if (!matches(*argv, "remote")) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ daddr = get_addr32(*argv);
+ } else if (!matches(*argv, "local")) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ saddr = get_addr32(*argv);
+ } else if (!matches(*argv, "dev")) {
+ NEXT_ARG();
+ link = tnl_ioctl_get_ifindex(*argv);
+ if (link == 0)
+ exit(-1);
+ } else if (!matches(*argv, "ttl") ||
+ !matches(*argv, "hoplimit")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (get_unsigned(&uval, *argv, 0))
+ invarg("invalid TTL\n", *argv);
+ if (uval > 255)
+ invarg("TTL must be <= 255\n", *argv);
+ ttl = uval;
+ }
+ } else if (!matches(*argv, "tos") ||
+ !matches(*argv, "tclass") ||
+ !matches(*argv, "dsfield")) {
+ __u32 uval;
+
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (rtnl_dsfield_a2n(&uval, *argv))
+ invarg("bad TOS value", *argv);
+ tos = uval;
+ } else
+ tos = 1;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ if (!ikey && IN_MULTICAST(ntohl(daddr))) {
+ ikey = daddr;
+ iflags |= GRE_KEY;
+ }
+ if (!okey && IN_MULTICAST(ntohl(daddr))) {
+ okey = daddr;
+ oflags |= GRE_KEY;
+ }
+ if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
+ fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+ return -1;
+ }
+
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
+ addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
+ addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
+
+ return 0;
+}
+
+static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ char s1[1024];
+ char s2[64];
+ const char *local = "any";
+ const char *remote = "any";
+ unsigned iflags = 0;
+ unsigned oflags = 0;
+
+ if (!tb)
+ return;
+
+ if (tb[IFLA_GRE_REMOTE]) {
+ unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
+
+ if (addr)
+ remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "remote %s ", remote);
+
+ if (tb[IFLA_GRE_LOCAL]) {
+ unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
+
+ if (addr)
+ local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "local %s ", local);
+
+ if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
+ unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
+ char *n = tnl_ioctl_get_ifname(link);
+
+ if (n)
+ fprintf(f, "dev %s ", n);
+ else
+ fprintf(f, "dev %u ", link);
+ }
+
+ if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
+ fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
+ else
+ fprintf(f, "ttl inherit ");
+
+ if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
+ int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
+
+ fputs("tos ", f);
+ if (tos == 1)
+ fputs("inherit ", f);
+ else
+ fprintf(f, "0x%x ", tos);
+ }
+
+ if (tb[IFLA_GRE_PMTUDISC] &&
+ !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
+ fputs("nopmtudisc ", f);
+
+ if (tb[IFLA_GRE_IFLAGS])
+ iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
+
+ if (tb[IFLA_GRE_OFLAGS])
+ oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
+
+ if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
+ *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
+ fprintf(f, "ikey %s ", s2);
+ }
+
+ if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
+ *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
+ fprintf(f, "ikey %s ", s2);
+ }
+
+ if (iflags & GRE_SEQ)
+ fputs("iseq ", f);
+ if (oflags & GRE_SEQ)
+ fputs("oseq ", f);
+ if (iflags & GRE_CSUM)
+ fputs("icsum ", f);
+ if (oflags & GRE_CSUM)
+ fputs("ocsum ", f);
+}
+
+struct link_util gre_link_util = {
+ .id = "gre",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
+
+struct link_util gretap_link_util = {
+ .id = "gretap",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
--- /dev/null
+/*
+ * link_veth.c veth driver module
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Pavel Emelianov <xemul@openvz.org>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/veth.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+ printf("Usage: ip link <options> type veth "
+ "[peer <options>]\nTo get <options> type "
+ "'ip link add help'\n");
+}
+
+static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *hdr)
+{
+ char *name, *type, *link, *dev;
+ int err, len;
+ struct rtattr * data;
+
+ if (strcmp(argv[0], "peer") != 0) {
+ usage();
+ return -1;
+ }
+
+ data = NLMSG_TAIL(hdr);
+ addattr_l(hdr, 1024, VETH_INFO_PEER, NULL, 0);
+
+ hdr->nlmsg_len += sizeof(struct ifinfomsg);
+
+ err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
+ &name, &type, &link, &dev);
+ if (err < 0)
+ return err;
+
+ if (name) {
+ len = strlen(name) + 1;
+ if (len > IFNAMSIZ)
+ invarg("\"name\" too long\n", *argv);
+ addattr_l(hdr, 1024, IFLA_IFNAME, name, len);
+ }
+
+ data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+ return argc - 1 - err;
+}
+
+struct link_util veth_link_util = {
+ .id = "veth",
+ .parse_opt = veth_parse_opt,
+};
#! /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
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
-#include <net/if.h>
#include <netinet/in.h>
#include <string.h>
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;
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");
--- /dev/null
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * split from ip_tunnel.c
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+
+const char *tnl_strproto(__u8 proto)
+{
+ static char buf[16];
+
+ switch (proto) {
+ case IPPROTO_IPIP:
+ strcpy(buf, "ip");
+ break;
+ case IPPROTO_GRE:
+ strcpy(buf, "gre");
+ break;
+ case IPPROTO_IPV6:
+ strcpy(buf, "ipv6");
+ break;
+ case 0:
+ strcpy(buf, "any");
+ break;
+ default:
+ strcpy(buf, "unknown");
+ break;
+ }
+
+ return buf;
+}
+
+int tnl_ioctl_get_ifindex(const char *dev)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err) {
+ perror("ioctl");
+ return 0;
+ }
+ close(fd);
+ return ifr.ifr_ifindex;
+}
+
+int tnl_ioctl_get_iftype(const char *dev)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFHWADDR, &ifr);
+ if (err) {
+ perror("ioctl");
+ return -1;
+ }
+ close(fd);
+ return ifr.ifr_addr.sa_family;
+}
+
+
+char * tnl_ioctl_get_ifname(int idx)
+{
+ static struct ifreq ifr;
+ int fd;
+ int err;
+
+ ifr.ifr_ifindex = idx;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFNAME, &ifr);
+ if (err) {
+ perror("ioctl");
+ return NULL;
+ }
+ close(fd);
+ return ifr.ifr_name;
+}
+
+int tnl_get_ioctl(const char *basedev, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = (void*)p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGETTUNNEL, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
+
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ if (cmd == SIOCCHGTUNNEL && name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ else
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, cmd, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
+
+int tnl_del_ioctl(const char *basedev, const char *name, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ if (name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ else
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCDELTUNNEL, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
--- /dev/null
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+#ifndef __TUNNEL_H__
+#define __TUNNEL_H__ 1
+
+#include <linux/types.h>
+
+const char *tnl_strproto(__u8 proto);
+int tnl_ioctl_get_ifindex(const char *dev);
+int tnl_ioctl_get_iftype(const char *dev);
+char * tnl_ioctl_get_ifname(int idx);
+int tnl_get_ioctl(const char *basedev, void *p);
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p);
+int tnl_del_ioctl(const char *basedev, const char *name, void *p);
+
+#endif
/*
* 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
#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))
#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) { \
__u32 index_mask;
__u8 action_mask;
__u32 priority_mask;
+ __u8 policy_flags_mask;
+
+ __u8 ptype;
+ __u8 ptype_mask;
+
};
#define XFRM_FILTER_MASK_FULL (~0)
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);
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);
/*
* 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
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);
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)
{
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",
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) {
} 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 {
}
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;
/*
* 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
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");
//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");
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");
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)
{
} 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));
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)
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);
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);
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;
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))
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;
}
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;
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) {
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)
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]) {
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;
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);
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);
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;
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) {
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)
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);
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)
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);
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);
/*
* 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
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));
}
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);
if (get_u8(&val, vbuf, 16))
invarg("\"ALGOKEY\" is invalid", key);
- alg->alg_key[j] = val;
+ buf[j] = val;
}
} else {
len = slen;
if (len > max)
invarg("\"ALGOKEY\" makes buffer overflow\n", key);
- strncpy(alg->alg_key, key, len);
+ strncpy(buf, key, len);
}
}
*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;
}
}
- filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
-
*argcp = argc;
*argvp = 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;
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);
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);
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);
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);
}
}
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) {
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);
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);
struct {
struct nlmsghdr n;
struct xfrm_usersa_id xsid;
+ char buf[RTA_BUF_SIZE];
} req;
struct xfrm_id id;
char *idp = NULL;
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);
/* 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++;
}
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 ++;
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);
}
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;
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) {
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)
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);
+++ /dev/null
-#
-# $Id$
-#
-%define url $URL$
-
-%define name iproute
-%define version 2.6.16
-%define taglevel 1
-
-%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
-
-Vendor: PlanetLab
-Packager: PlanetLab Central <support@planet-lab.org>
-Distribution: PlanetLab %{plrelease}
-URL: %(echo %{url} | cut -d ' ' -f 2)
-
-Summary: Advanced IP routing and network device configuration tools.
-Name: %{name}
-Version: %{version}
-Release: %{release}
-Group: Applications/System
-#Source: http://developer.osdl.org/dev/iproute2/download/iproute2-%{version}-050314.tar.gz
-#URL: http://developer.osdl.org/dev/iproute2/
-Source: %{name}-%{version}.tar.gz
-%define SOURCE1 ip.8
-%define SOURCE2 tc.8
-%define SOURCE3 tc-cbq.8
-%define SOURCE4 tc-cbq-details.8
-%define SOURCE5 tc-htb.8
-%define SOURCE6 tc-pbfifo.8
-%define SOURCE7 tc-pfifo_fast.8
-%define SOURCE8 tc-prio.8
-%define SOURCE9 tc-red.8
-%define SOURCE10 tc-sfq.8
-%define SOURCE11 tc-tbf.8
-License: GNU GPL
-BuildRoot: %{_tmppath}/%{name}-%{version}-root
-BuildPrereq: tetex-latex tetex-dvips psutils linuxdoc-tools db4-devel bison flex
-
-%description
-The iproute package contains networking utilities (ip and rtmon, for
-example) which are designed to use the advanced networking
-capabilities of the Linux 2.4.x and 2.6.x kernel.
-
-%prep
-%setup -q
-
-%build
-make
-make -C doc
-
-%install
-#rm -rf $RPM_BUILD_ROOT
-[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
-
-mkdir -p $RPM_BUILD_ROOT/sbin \
- $RPM_BUILD_ROOT%{_sbindir} \
- $RPM_BUILD_ROOT%{_mandir}/man8 \
- $RPM_BUILD_ROOT/etc/iproute2 \
- $RPM_BUILD_ROOT%{_libdir}/tc
-
-install -m 755 ip/ip ip/ifcfg ip/rtmon tc/tc $RPM_BUILD_ROOT/sbin
-install -m 755 misc/ss misc/nstat misc/rtacct misc/lnstat misc/arpd $RPM_BUILD_ROOT%{_sbindir}
-install -m 755 tc/q_netem.so $RPM_BUILD_ROOT%{_libdir}/tc
-install -m 644 netem/normal.dist netem/pareto.dist netem/paretonormal.dist $RPM_BUILD_ROOT%{_libdir}/tc
-install -m 644 %{SOURCE1} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE2} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE3} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE4} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE5} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE6} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE7} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE8} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE9} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE10} $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 %{SOURCE11} $RPM_BUILD_ROOT/%{_mandir}/man8
-
-cp -f etc/iproute2/* $RPM_BUILD_ROOT/etc/iproute2
-rm -rf $RPM_BUILD_ROOT/%{_libdir}/debug/*
-
-%clean
-#rm -rf $RPM_BUILD_ROOT
-[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-%dir /etc/iproute2
-%doc README.decnet README.iproute2+tc RELNOTES
-%doc doc/*.ps examples
-/sbin/*
-%{_mandir}/man8/*
-%attr(644,root,root) %config(noreplace) /etc/iproute2/*
-%{_sbindir}/*
-%{_libdir}/tc/*
-
-%changelog
-* Tue Mar 15 2005 Radek Vokal <rvokal@redhat.com> 2.6.11-1
-- update to iproute-2.6.11
-
-* Fri Mar 04 2005 Radek Vokal <rvokal@redhat.com> 2.6.10-2
-- gcc4 rebuilt
-
-* Wed Feb 16 2005 Radek Vokal <rvokal@redhat.com> 2.6.10-1
-- update to iproute-2.6.10
-
-* Thu Dec 23 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-6
-- added arpd into sbin
-
-* Mon Nov 29 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-5
-- debug info removed from makefile and from spec (#140891)
-
-* Tue Nov 16 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-4
-- source file updated from snapshot version
-- endian patch adding <endian.h>
-
-* Sat Sep 18 2004 Joshua Blanton <jblanton@cs.ohiou.edu> 2.6.9-3
-- added installation of netem module for tc
-
-* Mon Sep 06 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-2
-- fixed possible buffer owerflow, path by Steve Grubb <linux_4ever@yahoo.com>
-
-* Wed Sep 01 2004 Radek Vokal <rvokal@redhat.com> 2.6.9-1
-- updated to iproute-2.6.9, spec file change, patches cleared
-
-* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed May 26 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-16
-- Took tons of manpages from debian, much more complete (#123952).
-
-* Thu May 06 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-15
-- rebuilt
-
-* Thu May 06 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-13.2
-- Built security errata version for FC1.
-
-* Wed Apr 21 2004 Phil Knirsch <pknirsch@redhat.com> 2.4.7-14
-- Fixed -f option for ss (#118355).
-- Small description fix (#110997).
-- Added initialization of some vars (#74961).
-- Added patch to initialize "default" rule as well (#60693).
-
-* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed Nov 05 2003 Phil Knirsch <pknirsch@redhat.com> 2.4.7-12
-- Security errata for netlink (CAN-2003-0856).
-
-* Thu Oct 23 2003 Phil Knirsch <pknirsch@redhat.com>
-- Updated to latest version. Used by other distros, so seems stable. ;-)
-- Quite a few patches needed updating in that turn.
-- Added ss (#107363) and several other new nifty tools.
-
-* Tue Jun 17 2003 Phil Knirsch <pknirsch@redhat.com>
-- rebuilt
-
-* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
-- rebuilt
-
-* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
-- rebuilt
-
-* Thu Jan 16 2003 Phil Knirsch <pknirsch@redhat.com> 2.4.7-7
-- Added htb3-tc patch from http://luxik.cdi.cz/~devik/qos/htb/ (#75486).
-
-* Fri Oct 11 2002 Bill Nottingham <notting@redhat.com> 2.4.7-6
-- remove flags patch at author's request
-
-* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
-- automated rebuild
-
-* Wed Jun 19 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-4
-- Don't forcibly strip binaries
-
-* Mon May 27 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-3
-- Fixed missing diffserv and atm support in config (#57278).
-- Fixed inconsistent numeric base problem for command line (#65473).
-
-* Tue May 14 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-2
-- Added patch to fix crosscompiling by Adrian Linkins.
-
-* Fri Mar 15 2002 Phil Knirsch <pknirsch@redhat.com> 2.4.7-1
-- Update to latest stable release 2.4.7-now-ss010824.
-- Added simple man page for ip.
-
-* Wed Aug 8 2001 Bill Nottingham <notting@redhat.com>
-- allow setting of allmulti & promisc flags (#48669)
-
-* Mon Jul 02 2001 Than Ngo <than@redhat.com>
-- fix build problem in beehive if kernel-sources is not installed
-
-* Fri May 25 2001 Helge Deller <hdeller@redhat.de>
-- updated to iproute2-2.2.4-now-ss001007.tar.gz
-- bzip2 source tar file
-- "License" replaces "Copyright"
-- added "BuildPrereq: tetex-latex tetex-dvips psutils"
-- rebuilt for 7.2
-
-* Tue May 1 2001 Bill Nottingham <notting@redhat.com>
-- use the system headers - the included ones are broken
-- ETH_P_ECHO went away
-
-* Sat Jan 6 2001 Jeff Johnson <jbj@redhat.com>
-- test for specific KERNEL_INCLUDE directories.
-
-* Thu Oct 12 2000 Than Ngo <than@redhat.com>
-- rebuild for 7.1
-
-* Thu Oct 12 2000 Than Ngo <than@redhat.com>
-- add default configuration files for iproute (Bug #10549, #18887)
-
-* Tue Jul 25 2000 Jakub Jelinek <jakub@redhat.com>
-- fix include-glibc/ to cope with glibc 2.2 new resolver headers
-
-* Thu Jul 13 2000 Prospector <bugzilla@redhat.com>
-- automatic rebuild
-
-* Sun Jun 18 2000 Than Ngo <than@redhat.de>
-- rebuilt in the new build environment
-- use RPM macros
-- handle RPM_OPT_FLAGS
-
-* Sat Jun 03 2000 Than Ngo <than@redhat.de>
-- fix iproute to build with new glibc
-
-* Fri May 26 2000 Ngo Than <than@redhat.de>
-- update to 2.2.4-now-ss000305
-- add configuration files
-
-* Mon Sep 13 1999 Bill Nottingham <notting@redhat.com>
-- strip binaries
-
-* Mon Aug 16 1999 Cristian Gafton <gafton@redhat.com>
-- first build
*(str + pos) = '.';
pos++;
-
+
for(i = 0; i < 6; i++) {
if (do_digit(str + pos, addr->ipx_node[i], 1, &pos, len))
return str;
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,
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) {
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);
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)
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) {
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");
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");
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);
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;
+}
(type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
return inet_ntop(AF_INET, addr, buf, blen);
}
+ if (alen == 16 && type == ARPHRD_TUNNEL6) {
+ return inet_ntop(AF_INET6, addr, buf, blen);
+ }
l = 0;
for (i=0; i<alen; i++) {
if (i==0) {
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <net/if.h>
#include <string.h>
#include "libnetlink.h"
#include "ll_map.h"
+extern unsigned int if_nametoindex (const char *);
+
struct idxmap
{
struct idxmap * next;
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;
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" },
#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
#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];
fclose(fp);
}
-
static char * rtnl_rtprot_tab[256] = {
[RTPROT_UNSPEC] = "none",
[RTPROT_REDIRECT] ="redirect",
}
+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;
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;
}
{
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;
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;
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;
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;
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 ||
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;
}
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;
}
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;
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;
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 &&
{
#ifdef RESOLVE_HOSTNAMES
if (resolve_hosts) {
- char *n;
+ const char *n;
+
if (len <= 0) {
switch (af) {
case AF_INET:
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;
*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;
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
--- /dev/null
+.TH ARPD 8 "28 June, 2007"
+
+.SH NAME
+arpd \- userspace arp daemon.
+
+.SH SYNOPSIS
+Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]
+
+.SH DESCRIPTION
+The
+.B arpd
+daemon collects gratuitous ARP information, saving it on local disk and feeding it to kernel on demand to avoid redundant broadcasting due to limited size of kernel ARP cache.
+
+.SH OPTIONS
+.TP
+-h -?
+Print help
+.TP
+-l
+Dump arpd database to stdout and exit. Output consists of three columns: interface index, IP address and MAC address. Negative entries for dead hosts are also shown, in this case MAC address is replaced by word FAILED followed by colon and time when the fact that host is dead was proven the last time.
+.TP
+-f <FILE>
+Read and load arpd database from FILE in text format similar dumped by option -l. Exit after load, probably listing resulting database, if option -l is also given. If FILE is -, stdin is read to get ARP table.
+.TP
+-b <DATABASE>
+location of database file. Default location is /var/lib/arpd/arpd.db
+.TP
+-a <NUMBER>
+arpd not only passively listens ARP on wire, but also send brodcast queries itself. NUMBER is number of such queries to make before destination is considered as dead. When arpd is started as kernel helper (i.e. with app_solicit enabled in sysctl or even with option -k) without this option and still did not learn enough information, you can observe 1 second gaps in service. Not fatal, but not good.
+.TP
+-k
+Suppress sending broadcast queries by kernel. It takes sense together with option -a.
+.TP
+-n <TIME>
+Timeout of negative cache. When resolution fails arpd suppresses further attempts to resolve for this period. It makes sense only together with option -k This timeout should not be too much longer than boot time of a typical host not supporting gratuitous ARP. Default value is 60 seconds.
+.TP
+-r <RATE>
+Maximal steady rate of broadcasts sent by arpd in packets per second. Default value is 1.
+.TP
+-B <NUMBER>
+Number of broadcasts sent by <tt/arpd/ back to back. Default value is 3. Together with option <tt/-R/ this option allows to police broadcasting not to exceed B+R*T over any interval of time T.
+.P
+<INTERFACE> is the name of networking interface to watch. If no interfaces given, arpd monitors all the interfaces. In this case arpd does not adjust sysctl parameters, it is supposed user does this himself after arpd is started.
+.P
+Signals
+.br
+arpd exits gracefully syncing database and restoring adjusted sysctl parameters, when receives SIGINT or SIGTERM. SIGHUP syncs database to disk. SIGUSR1 sends some statistics to syslog. Effect of another signals is undefined, they may corrupt database and leave sysctl praameters in an unpredictable state.
+.P
+Note
+.br
+In order for arpd to be able to serve as ARP resolver, kernel must be compiled with the option CONFIG_ARPD and, in the case when interface list in not given on command line, variable app_solicit on interfaces of interest should be in /proc/sys/net/ipv4/neigh/*. If this is not made arpd still collects gratuitous ARP information in its database.
+.SH EXAMPLES
+.TP
+arpd -b /var/tmp/arpd.db
+Start arpd to collect gratuitous ARP, but not messing with kernel functionality.
+.TP
+killall arpd ; arpd -l -b /var/tmp/arpd.db
+Look at result after some time.
+.TP
+arpd -b /var/tmp/arpd.db -a 1 eth0 eth1
+Enable kernel helper, leaving leading role to kernel.
+.TP
+arpd -b /var/tmp/arpd.db -a 3 -k eth0 eth1
+Completely replace kernel resolution on interfaces eth0 and eth1. In this case kernel still does unicast probing to validate entries, but all the broadcast activity is suppressed and made under authority of arpd.
+.PP
+This is mode which arpd is supposed to work normally. It is not default just to prevent occasional enabling of too aggressive mode occasionally.
.ti -8
.IR OBJECT " := { "
-.BR link " | " addr " | " route " | " rule " | " neigh " | " tunnel " | "\
-maddr " | " mroute " | " monitor " }"
+.BR link " | " addr " | " addrlabel " | " route " | " rule " | " neigh " | "\
+ tunnel " | " maddr " | " mroute " | " monitor " }"
.sp
.ti -8
-.IR OPTIONS " := { "
+.IR OPTIONS " := { "
\fB\-V\fR[\fIersion\fR] |
\fB\-s\fR[\fItatistics\fR] |
\fB\-r\fR[\fIesolve\fR] |
.br
.BR promisc " { " on " | " off " } |"
.br
-.BR allmulti " { " on " | " off " } |"
+.BR allmulticast " { " on " | " off " } |"
.br
.BR dynamic " { " on " | " off " } |"
.br
.br
.B address
.IR LLADDR " |"
-.B broadcast
+.B broadcast
.IR LLADDR " |"
.br
.B mtu
-.IR MTU " }"
+.IR MTU " |"
+.br
+.B netns
+.IR PID " }"
.ti -8
.B ip link show
.RI "[ " DEVICE " ]"
.ti -8
-.BR "ip addr" " { " add " | " del " } "
+.BR "ip addr" " { " add " | " del " } "
.IB IFADDR " dev " STRING
.ti -8
.IR STRING " ] [ "
.B scope
.IR SCOPE-ID " ] [ "
-.B to
+.B to
.IR PREFIX " ] [ " FLAG-LIST " ] [ "
.B label
.IR PATTERN " ]"
.RB "[ " permanent " | " dynamic " | " secondary " | " primary " | "\
tentative " | " deprecated " ]"
+.ti -8
+.BR "ip addrlabel" " { " add " | " del " } " prefix
+.BR PREFIX " [ "
+.B dev
+.IR DEV " ] [ "
+.B label
+.IR NUMBER " ]"
+
+.ti -8
+.BR "ip addrlabel" " { " list " | " flush " }"
+
.ti -8
.BR "ip route" " { "
.BR list " | " flush " } "
.I SELECTOR
.ti -8
-.B ip route get
+.B ip route get
.IR ADDRESS " [ "
.BI from " ADDRESS " iif " STRING"
-.RB " ] [ " oif
+.RB " ] [ " oif
.IR STRING " ] [ "
.B tos
.IR TOS " ]"
.B advmss
.IR NUMBER " ] [ "
.B rtt
-.IR NUMBER " ] [ "
+.IR TIME " ] [ "
.B rttvar
-.IR NUMBER " ] [ "
+.IR TIME " ] [ "
.B window
.IR NUMBER " ] [ "
.B cwnd
.B ssthresh
.IR REALM " ] [ "
.B realms
-.IR REALM " ]"
+.IR REALM " ] [ "
+.B rto_min
+.IR TIME " ]"
.ti -8
.IR TYPE " := [ "
.B tos
.IR TOS " ] [ "
.B fwmark
-.IR FWMARK " ] [ "
+.IR FWMARK[/MASK] " ] [ "
.B dev
.IR STRING " ] [ "
.B pref
.BR "ip tunnel" " { " add " | " change " | " del " | " show " }"
.RI "[ " NAME " ]"
.br
-.RB "[ " mode " { " ipip " | " gre " | " sit " } ]"
-.br
-.RB "[ " remote
+.RB "[ " mode
+.IR MODE " ] [ "
+.B remote
.IR ADDR " ] [ "
.B local
.IR ADDR " ]"
.IR KEY " ] [ "
.RB "[" i "|" o "]" csum " ] ]"
.br
+.RB "[ " encaplimit
+.IR ELIM " ]"
.RB "[ " ttl
-.IR TTL " ] [ "
-.B tos
+.IR TTL " ]"
+.br
+.RB "[ " tos
.IR TOS " ] [ "
-.RB "[" no "]" pmtudisc " ]"
+.B flowlabel
+.IR FLOWLABEL " ]"
.br
+.RB "[ [" no "]" pmtudisc " ]"
.RB "[ " dev
.IR PHYS_DEV " ]"
+.RB "[ " "dscp inherit" " ]"
+
+.ti -8
+.IR MODE " := "
+.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | " any " }"
.ti -8
.IR ADDR " := { " IP_ADDRESS " |"
.IR TOS " := { " NUMBER " |"
.BR inherit " }"
+.ti -8
+.IR ELIM " := {
+.BR none " | "
+.IR 0 ".." 255 " }"
+
+.ti -8
.ti -8
.IR TTL " := { " 1 ".." 255 " | "
.BR inherit " }"
.ti -8
.IR KEY " := { " DOTTED_QUAD " | " NUMBER " }"
+.ti -8
+.IR TIME " := " NUMBER "[s|ms|us|ns|j]"
+
.ti -8
.BR "ip maddr" " [ " add " | " del " ]"
.IB MULTIADDR " dev " STRING
.ti -8
.BR "ip monitor" " [ " all " |"
.IR LISTofOBJECTS " ]"
+
+.ti -8
+.BR "ip xfrm"
+.IR XFRM_OBJECT " { " COMMAND " }"
+
+.ti -8
+.IR XFRM_OBJECT " := { " state " | " policy " | " monitor " } "
+
+.ti -8
+.BR "ip xfrm state " { " add " | " update " } "
+.IR ID " [ "
+.IR XFRM_OPT " ] "
+.RB " [ " mode
+.IR MODE " ] "
+.br
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " seq
+.IR SEQ " ] "
+.RB " [ " replay-window
+.IR SIZE " ] "
+.br
+.RB " [ " flag
+.IR FLAG-LIST " ] "
+.RB " [ " encap
+.IR ENCAP " ] "
+.RB " [ " sel
+.IR SELECTOR " ] "
+.br
+.RB " [ "
+.IR LIMIT-LIST " ] "
+
+.ti -8
+.BR "ip xfrm state allocspi "
+.IR ID
+.RB " [ " mode
+.IR MODE " ] "
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " seq
+.IR SEQ " ] "
+.RB " [ " min
+.IR SPI
+.B max
+.IR SPI " ] "
+
+.ti -8
+.BR "ip xfrm state" " { " delete " | " get " } "
+.IR ID
+
+.ti -8
+.BR "ip xfrm state" " { " deleteall " | " list " } [ "
+.IR ID " ] "
+.RB " [ " mode
+.IR MODE " ] "
+.br
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " flag
+.IR FLAG_LIST " ] "
+
+.ti -8
+.BR "ip xfrm state flush" " [ " proto
+.IR XFRM_PROTO " ] "
+
+.ti -8
+.BR "ip xfrm state count"
+
+.ti -8
+.IR ID " := "
+.RB " [ " src
+.IR ADDR " ] "
+.RB " [ " dst
+.IR ADDR " ] "
+.RB " [ " proto
+.IR XFRM_PROTO " ] "
+.RB " [ " spi
+.IR SPI " ] "
+
+.ti -8
+.IR XFRM_PROTO " := "
+.RB " [ " esp " | " ah " | " comp " | " route2 " | " hao " ] "
+
+.ti -8
+.IR MODE " := "
+.RB " [ " transport " | " tunnel " | " ro " | " beet " ] "
+.B (default=transport)
+
+.ti -8
+.IR FLAG-LIST " := "
+.RI " [ " FLAG-LIST " ] " FLAG
+
+.ti -8
+.IR FLAG " := "
+.RB " [ " noecn " | " decap-dscp " | " wildrecv " ] "
+
+.ti -8
+.IR ENCAP " := " ENCAP-TYPE " " SPORT " " DPORT " " OADDR
+
+.ti -8
+.IR ENCAP-TYPE " := "
+.B espinudp
+.RB " | "
+.B espinudp-nonike
+
+.ti -8
+.IR ALGO-LIST " := [ "
+.IR ALGO-LIST " ] | [ "
+.IR ALGO " ] "
+
+.ti -8
+.IR ALGO " := "
+.IR ALGO_TYPE
+.IR ALGO_NAME
+.IR ALGO_KEY
+
+.ti -8
+.IR ALGO_TYPE " := "
+.RB " [ " enc " | " auth " | " comp " ] "
+
+.ti -8
+.IR SELECTOR " := "
+.B src
+.IR ADDR "[/" PLEN "]"
+.B dst
+.IR ADDR "[/" PLEN "]"
+.RI " [ " UPSPEC " ] "
+.RB " [ " dev
+.IR DEV " ] "
+
+.ti -8
+.IR UPSPEC " := "
+.B proto
+.IR PROTO " [[ "
+.B sport
+.IR PORT " ] "
+.RB " [ " dport
+.IR PORT " ] | "
+.br
+.RB " [ " type
+.IR NUMBER " ] "
+.RB " [ " code
+.IR NUMBER " ]] "
+
+.ti -8
+.IR LIMIT-LIST " := [ " LIMIT-LIST " ] |"
+.RB " [ "limit
+.IR LIMIT " ] "
+
+.ti -8
+.IR LIMIT " := "
+.RB " [ [" time-soft "|" time-hard "|" time-use-soft "|" time-use-hard "]"
+.IR SECONDS " ] | "
+.RB "[ ["byte-soft "|" byte-hard "]"
+.IR SIZE " ] | "
+.br
+.RB " [ ["packet-soft "|" packet-hard "]"
+.IR COUNT " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " add " | " update " } " " dir "
+.IR DIR
+.IR SELECTOR " [ "
+.BR index
+.IR INDEX " ] "
+.br
+.RB " [ " ptype
+.IR PTYPE " ] "
+.RB " [ " action
+.IR ACTION " ] "
+.RB " [ " priority
+.IR PRIORITY " ] "
+.br
+.RI " [ " LIMIT-LIST " ] [ "
+.IR TMPL-LIST " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " delete " | " get " } " " dir "
+.IR DIR " [ " SELECTOR " | "
+.BR index
+.IR INDEX
+.RB " ] "
+.br
+.RB " [ " ptype
+.IR PTYPE " ] "
+
+.ti -8
+.BR "ip xfrm policy" " { " deleteall " | " list " } "
+.RB " [ " dir
+.IR DIR " ] [ "
+.IR SELECTOR " ] "
+.br
+.RB " [ " index
+.IR INDEX " ] "
+.RB " [ " action
+.IR ACTION " ] "
+.RB " [ " priority
+.IR PRIORITY " ] "
+
+.ti -8
+.B "ip xfrm policy flush"
+.RB " [ " ptype
+.IR PTYPE " ] "
+
+.ti -8
+.B "ip xfrm count"
+
+.ti -8
+.IR PTYPE " := "
+.RB " [ " main " | " sub " ] "
+.B (default=main)
+
+.ti -8
+.IR DIR " := "
+.RB " [ " in " | " out " | " fwd " ] "
+
+.ti -8
+.IR SELECTOR " := "
+.B src
+.IR ADDR "[/" PLEN "]"
+.B dst
+.IR ADDR "[/" PLEN] " [ " UPSPEC
+.RB " ] [ " dev
+.IR DEV " ] "
+
+.ti -8
+.IR UPSPEC " := "
+.B proto
+.IR PROTO " [ "
+.RB " [ " sport
+.IR PORT " ] "
+.RB " [ " dport
+.IR PORT " ] | "
+.br
+.RB " [ " type
+.IR NUMBER " ] "
+.RB " [ " code
+.IR NUMBER " ] ] "
+
+.ti -8
+.IR ACTION " := "
+.RB " [ " allow " | " block " ]"
+.B (default=allow)
+
+.ti -8
+.IR LIMIT-LIST " := "
+.RB " [ "
+.IR LIMIT-LIST " ] | "
+.RB " [ " limit
+.IR LIMIT " ] "
+
+.ti -8
+.IR LIMIT " := "
+.RB " [ [" time-soft "|" time-hard "|" time-use-soft "|" time-use-hard "]"
+.IR SECONDS " ] | "
+.RB " [ [" byte-soft "|" byte-hard "]"
+.IR SIZE " ] | "
+.br [ "
+.RB "[" packet-soft "|" packet-hard "]"
+.IR NUMBER " ] "
+
+.ti -8
+.IR TMPL-LIST " := "
+.B " [ "
+.IR TMPL-LIST " ] | "
+.RB " [ " tmpl
+.IR TMPL " ] "
+
+.ti -8
+.IR TMPL " := "
+.IR ID " [ "
+.B mode
+.IR MODE " ] "
+.RB " [ " reqid
+.IR REQID " ] "
+.RB " [ " level
+.IR LEVEL " ] "
+
+.ti -8
+.IR ID " := "
+.RB " [ " src
+.IR ADDR " ] "
+.RB " [ " dst
+.IR ADDR " ] "
+.RB " [ " proto
+.IR XFRM_PROTO " ] "
+.RB " [ " spi
+.IR SPI " ] "
+
+.ti -8
+.IR XFRM_PROTO " := "
+.RB " [ " esp " | " ah " | " comp " | " route2 " | " hao " ] "
+
+.ti -8
+.IR MODE " := "
+.RB " [ " transport " | " tunnel " | " beet " ] "
+.B (default=transport)
+
+.ti -8
+.IR LEVEL " := "
+.RB " [ " required " | " use " ] "
+.B (default=required)
+
+.ti -8
+.BR "ip xfrm monitor" " [ " all " | "
+.IR LISTofOBJECTS " ] "
+
.in -8
.ad b
or
.B link
,enforce the protocol family to use. If the option is not present,
-the protocol family is guessed from other arguments. If the rest
+the protocol family is guessed from other arguments. If the rest
of the command line does not give enough information to guess the
family,
.B ip
.BR "\-o" , " \-oneline"
output each record on a single line, replacing line feeds
with the
-.B '\'
-character. This is convenient when you want to count records
+.B '\e\'
+character. This is convenient when you want to count records
with
.BR wc (1)
or to
.TP
.B address
- protocol (IP or IPv6) address on a device.
+
+.TP
+.B addrlabel
+- label configuration for protocol address selection.
+
.TP
.B neighbour
- ARP or NDISC cache entry.
.B tunnel
- tunnel over IP.
+.TP
+.B xfrm
+- framework for IPsec protocol.
+
.PP
The names of all objects may be written in full or
abbreviated form, f.e.
.TP
.BI txqueuelen " NUMBER"
-.TP
+.TP
.BI txqlen " NUMBER"
change the transmit queue length of the device.
.TP
.BI mtu " NUMBER"
-change the
+change the
.I MTU
of the device.
the interface is
.IR "POINTOPOINT" .
+.TP
+.BI netns " PID"
+move the device to the network namespace associated with the process
+.IR "PID" .
+
.PP
.B Warning:
If multiple parameter changes are requested,
also dumps all the deleted addresses in the format described in the
previous subsection.
+.SH ip addrlabel - protocol address label management.
+
+IPv6 address label is used for address selection
+described in RFC 3484. Precedence is managed by userspace,
+and only label is stored in kernel.
+
+.SS ip addrlabel add - add an address label
+the command adds an address label entry to the kernel.
+.TP
+.BI prefix " PREFIX"
+.TP
+.BI dev " DEV"
+the outgoing interface.
+.TP
+.BI label " NUMBER"
+the label for the prefix.
+0xffffffff is reserved.
+.SS ip addrlabel del - delete an address label
+the command deletes an address label entry in the kernel.
+.B Arguments:
+coincide with the arguments of
+.B ip addrlabel add
+but label is not required.
+.SS ip addrlabel list - list address labels
+the command show contents of address labels.
+.SS ip addrlabel flush - flush address labels
+the commoand flushes the contents of address labels and it does not restore default settings.
.SH ip neighbour - neighbour/arp tables management.
.B neighbour
tables identified by a number in the range from 1 to 255 or by
name from the file
.B /etc/iproute2/rt_tables
-. By default all normal routes are inserted into the
+By default all normal routes are inserted into the
.B main
table (ID 254) and the kernel only uses this table when calculating routes.
peers are allowed to send to us.
.TP
-.BI rtt " NUMBER"
-the initial RTT ('Round Trip Time') estimate.
+.BI rtt " TIME"
+the initial RTT ('Round Trip Time') estimate. If no suffix is
+specified the units are raw values passed directly to the
+routing code to maintain compatability with previous releases.
+Otherwise if a suffix of s, sec or secs is used to specify
+seconds; ms, msec or msecs to specify milliseconds; us, usec
+or usecs to specify microseconds; ns, nsec or nsecs to specify
+nanoseconds; j, hz or jiffies to specify jiffies, the value is
+converted to what the routing code expects.
+
.TP
-.BI rttvar " NUMBER " "(2.3.15+ only)"
-the initial RTT variance estimate.
+.BI rttvar " TIME " "(2.3.15+ only)"
+the initial RTT variance estimate. Values are specified as with
+.BI rtt
+above.
+
+.TP
+.BI rto_min " TIME " "(2.6.23+ only)"
+the minimum TCP Retransmission TimeOut to use when communicating with this
+destination. Values are specified as with
+.BI rtt
+above.
.TP
.BI ssthresh " NUMBER " "(2.3.15+ only)"
.TP
.B connected
-if no source address
+if no source address
.RB "(option " from ")"
was given, relookup the route with the source set to the preferred
address received from the first lookup.
set
.I unique
priority value.
+The options preference and order are synonyms with priority.
.TP
.BI table " TABLEID"
the routing table identifier to lookup if the rule selector matches.
+It is also possible to use lookup instead of table.
.TP
.BI realms " FROM/TO"
Realms to select if the rule matched and the routing table lookup
-succeeded. Realm
+succeeded. Realm
.I TO
is only used if the route did not select any realm.
.TP
.BI nat " ADDRESS"
The base of the IP address block to translate (for source addresses).
-The
+The
.I ADDRESS
may be either the start of the block of NAT addresses (selected by NAT
routes) or a local host address (or even zero).
In the last case the router does not translate the packets, but
masquerades them to this address.
+Using map-to instead of nat means the same thing.
.B Warning:
Changes to the RPDB made with these commands do not become active
.SS ip rule show - list rules
This command has no arguments.
+The options list or lst are synonyms with show.
.SH ip maddress - multicast addresses management
.SH ip tunnel - tunnel configuration
.B tunnel
-objects are tunnels, encapsulating packets in IPv4 packets and then
+objects are tunnels, encapsulating packets in IP packets and then
sending them over the IP infrastructure.
+The encapulating (or outer) address family is specified by the
+.B -f
+option. The default is IPv4.
.SS ip tunnel add - add a new tunnel
.SS ip tunnel change - change an existing tunnel
.TP
.BI mode " MODE"
-set the tunnel mode. Three modes are currently available:
-.BR ipip ", " sit " and " gre "."
+set the tunnel mode. Available modes depend on the encapsulating address family.
+.br
+Modes for IPv4 encapsulation available:
+.BR ipip ", " sit ", " isatap " and " gre "."
+.br
+Modes for IPv6 encapsulation available:
+.BR ip6ip6 ", " ipip6 " and " any "."
.TP
.BI remote " ADDRESS"
.TP
.BI ttl " N"
-set a fixed TTL
+set a fixed TTL
.I N
on tunneled packets.
.I N
is a number in the range 1--255. 0 is a special value
-meaning that packets inherit the TTL value.
-The default value is:
+meaning that packets inherit the TTL value.
+The default value for IPv4 tunnels is:
.BR "inherit" .
+The default value for IPv6 tunnels is:
+.BR "64" .
+
.TP
.BI tos " T"
.TP
.BI dsfield " T"
-set a fixed TOS
+.TP
+.BI tclass " T"
+set a fixed TOS (or traffic class in IPv6)
.I T
on tunneled packets.
The default value is:
.BR "inherit" .
.TP
-.BI dev " NAME"
+.BI dev " NAME"
bind the tunnel to the device
.I NAME
so that tunneled packets will only be routed via this device and will
The
.BR ikey " and " okey
parameters set different keys for input and output.
-
+
.TP
.BR csum ", " icsum ", " ocsum
.RB ( " only GRE tunnels " )
generate/require checksums for tunneled packets.
-The
+The
.B ocsum
flag calculates checksums for outgoing packets.
The
flag requires that all input packets are serialized.
The
.B seq
-flag is equivalent to the combination
+flag is equivalent to the combination
.BR "iseq oseq" .
.B It isn't work. Don't use it.
+.TP
+.BR "dscp inherit"
+.RB ( " only IPv6 tunnels " )
+Inherit DS field between inner and outer header.
+
+.TP
+.BI encaplim " ELIM"
+.RB ( " only IPv6 tunnels " )
+set a fixed encapsulation limit. Default is 4.
+
+.TP
+.BI flowlabel " FLOWLABEL"
+.RB ( " only IPv6 tunnels " )
+set a fixed flowlabel.
+
.SS ip tunnel show - list tunnels
This command has no arguments.
It prepends the history with the state snapshot dumped at the moment
of starting.
+.SH ip xfrm - setting xfrm
+xfrm is an IP framework, which can transform format of the datagrams,
+.br
+i.e. encrypt the packets with some algorithm. xfrm policy and xfrm state
+are associated through templates
+.IR TMPL_LIST "."
+This framework is used as a part of IPsec protocol.
+
+.SS ip xfrm state add - add new state into xfrm
+
+.SS ip xfrm state update - update existing xfrm state
+
+.SS ip xfrm state allocspi - allocate SPI value
+
+.TP
+.I MODE
+is set as default to
+.BR transport ","
+but it could be set to
+.BR tunnel "," ro " or " beet "."
+
+.TP
+.I FLAG-LIST
+contains one or more flags.
+
+.TP
+.I FLAG
+could be set to
+.BR noecn ", " decap-dscp " or " wildrecv "."
+
+.TP
+.I ENCAP
+encapsulation is set to encapsulation type
+.IR ENCAP-TYPE ", source port " SPORT ", destination port " DPORT " and " OADDR "."
+
+.TP
+.I ENCAP-TYPE
+could be set to
+.BR espinudp " or " espinudp-nonike "."
+
+.TP
+.I ALGO-LIST
+contains one or more algorithms
+.I ALGO
+which depend on the type of algorithm set by
+.IR ALGO_TYPE "."
+It can be used these algoritms
+.BR enc ", " auth " or " comp "."
+
+.SS ip xfrm policy add - add a new policy
+
+.SS ip xfrm policy update - update an existing policy
+
+.SS ip xfrm policy delete - delete existing policy
+
+.SS ip xfrm policy get - get existing policy
+
+.SS ip xfrm policy deleteall - delete all existing xfrm policy
+
+.SS ip xfrm policy list - print out the list of xfrm policy
+
+.SS ip xfrm policy flush - flush policies
+It can be flush
+.BR all
+policies or only those specified with
+.BR ptype "."
+
+.TP
+.BI dir " DIR "
+directory could be one of these:
+.BR "inp", " out " or " fwd".
+
+.TP
+.IR SELECTOR
+selects for which addresses will be set up the policy. The selector
+is defined by source and destination address.
+
+.TP
+.IR UPSPEC
+is defined by source port
+.BR sport ", "
+destination port
+.BR dport ", " type
+as number and
+.B code
+also number.
+
+.TP
+.BI dev " DEV "
+specify network device.
+
+.TP
+.BI index " INDEX "
+the number of indexed policy.
+
+.TP
+.BI ptype " PTYPE "
+type is set as default on
+.BR "main" ,
+could be switch on
+.BR "sub" .
+
+.TP
+.BI action " ACTION "
+is set as default on
+.BR "allow".
+It could be switch on
+.BR "block".
+
+.TP
+.BI priority " PRIORITY "
+priority is a number. Default priority is set on zero.
+
+.TP
+.IR LIMIT-LIST
+limits are set in seconds, bytes or numbers of packets.
+
+.TP
+.IR TMPL-LIST
+template list is based on
+.IR ID ","
+.BR mode ", " reqid " and " level ". "
+
+.TP
+.IR ID
+is specified by source address, destination address,
+.I proto
+and value of
+.IR spi "."
+
+.TP
+.IR XFRM_PROTO
+values:
+.BR esp ", " ah ", " comp ", " route2 " or " hao "."
+
+.TP
+.IR MODE
+is set as default on
+.BR transport ","
+but it could be set on
+.BR tunnel " or " beet "."
+
+.TP
+.IR LEVEL
+is set as default on
+.BR required
+and the other choice is
+.BR use "."
+
+.TP
+.IR UPSPEC
+is specified by
+.BR sport ", "
+.BR dport ", " type
+and
+.B code
+(NUMBER).
+
+.SS ip xfrm monitor - is used for listing all objects or defined group of them.
+The
+.B xfrm monitor
+can monitor the policies for all objects or defined group of them.
+
.SH HISTORY
.B ip
was written by Alexey N. Kuznetsov and added in Linux 2.2.
.RB "IP Command reference " ip-cref.ps
.br
.RB "IP tunnels " ip-cref.ps
+.br
+.RB "User documentation at " http://lartc.org/ ", but please direct bugreports and patches to: " <netdev@vger.kernel.org>
.SH AUTHOR
Original Manpage by Michail Litvak <mci@owl.openwall.com>
--- /dev/null
+.TH LNSTAT 8
+.SH NAME
+lnstat \- unified linux network statistics
+.SH SYNOPSIS
+.B lnstat
+.RI [ options ]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B lnstat
+command.
+.PP
+\fBlnstat\fP is a generalized and more feature-complete replacement for the old rtstat program.
+In addition to routing cache statistics, it supports any kind of statistics the linux kernel
+exports via a file in /proc/net/stat/.
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+lnstat supports the following options.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-V, \-\-version
+Show version of program.
+.TP
+.B \-c, \-\-count <count>
+Print <count> number of intervals.
+.TP
+.B \-d, \-\-dump
+Dump list of available files/keys.
+.TP
+.B \-f, \-\-file <file>
+Statistics file to use.
+.TP
+.B \-i, \-\-interval <intv>
+Set interval to 'intv' seconds.
+.TP
+.B \-k, \-\-keys k,k,k,...
+Display only keys specified.
+.TP
+.B \-s, \-\-subject [0-2]
+Specify display of subject/header. '0' means no header at all, '1' prints a header only at start of the program and '2' prints a header every 20 lines.
+.TP
+.B \-w, \-\-width n,n,n,...
+Width for each field.
+.SH USAGE EXAMPLES
+.TP
+.B # lnstat -d
+Get a list of supported statistics files.
+.TP
+.B # lnstat -k arp_cache:entries,rt_cache:in_hit,arp_cache:destroys
+Select the specified files and keys.
+.TP
+.B # lnstat -i 10
+Use an interval of 10 seconds.
+.TP
+.B # lnstat -f ip_conntrack
+Use only the specified file for statistics.
+.TP
+.B # lnstat -s 0
+Do not print a header at all.
+.TP
+.B # lnstat -s 20
+Print a header at start and every 20 lines.
+.TP
+.B # lnstat -c -1 -i 1 -f rt_cache -k entries,in_hit,in_slow_tot
+Display statistics for keys entries, in_hit and in_slow_tot of field rt_cache every second.
+.SH SEE ALSO
+.BR ip (8),
+and /usr/share/doc/iproute-doc/README.lnstat (package iproute-doc on Debian)
+.br
+.SH AUTHOR
+lnstat was written by Harald Welte <laforge@gnumonks.org>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org> for the Debian project (but may be used by others).
--- /dev/null
+.TH "ROUTEL" "8" "3 Jan, 2008" "iproute2" "Linux"
+.SH "NAME"
+.LP
+routel \- list routes with pretty output format
+.br
+routef \- flush routes
+.SH "SYNTAX"
+.LP
+routel [\fItablenr\fP [\fIraw ip args...\fP]]
+.br
+routef
+.SH "DESCRIPTION"
+.LP
+These programs are a set of helper scripts you can use instead of raw iproute2 commands.
+.br
+The routel script will list routes in a format that some might consider easier to interpret then the ip route list equivalent.
+.br
+The routef script does not take any arguments and will simply flush the routing table down the drain. Beware! This means deleting all routes which will make your network unusable!
+
+.SH "FILES"
+.LP
+\fI/usr/bin/routef\fP
+.br
+\fI/usr/bin/routel\fP
+.SH "AUTHORS"
+.LP
+The routel script was written by Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18 and donated to the public domain.
+.br
+This manual page was written by Andreas Henriksson <andreas@fatal.se>, for the Debian GNU/Linux system.
+.SH "SEE ALSO"
+.LP
+ip(8)
--- /dev/null
+.TH RTACCT 8 "27 June, 2007"
+
+.SH NAME
+nstat, rtacct - network statistics tools.
+
+.SH SYNOPSIS
+Usage: nstat [ -h?vVzrnasd:t: ] [ PATTERN [ PATTERN ] ]
+.br
+Usage: rtacct [ -h?vVzrnasd:t: ] [ ListOfRealms ]
+
+.SH DESCRIPTION
+.B nstat
+and
+.B rtacct
+are simple tools to monitor kernel snmp counters and network interface statistics.
+
+.SH OPTIONS
+.TP
+-h -?
+Print help
+.TP
+-v -V
+Print version
+.TP
+-z
+Dump zero counters too. By default they are not shown.
+.TP
+-r
+Reset history.
+.TP
+-n
+Do not display anything, only update history.
+.TP
+-a
+Dump absolute values of counters. The default is to calculate increments since the previous use.
+.TP
+-s
+Do not update history, so that the next time you will see counters including values accumulated to the moment of this measurement too.
+.TP
+-d <INTERVAL>
+Run in daemon mode collecting statistics. <INTERVAL> is interval between measurements in seconds.
+.TP
+-t <INTERVAL>
+Time interval to average rates. Default value is 60 seconds.
+
+.SH SEE ALSO
+lnstat(8)
+
--- /dev/null
+.TH RTMON 8
+.SH NAME
+rtmon \- listens to and monitors RTnetlink
+.SH SYNOPSIS
+.B rtmon
+.RI "[ options ] file FILE [ all | LISTofOBJECTS ]"
+.SH DESCRIPTION
+This manual page documents briefly the
+.B rtmon
+command.
+.PP
+.B rtmon
+listens on
+.I netlink
+socket and monitors routing table changes.
+
+.I rtmon
+can be started before the first network configuration command is issued.
+For example if you insert:
+
+.B rtmon file /var/log/rtmon.log
+
+in a startup script, you will be able to view the full history later.
+Certainly, it is possible to start rtmon at any time. It prepends the history with the state snapshot dumped at the moment of starting.
+
+.SH OPTIONS
+.I rtmon supports the following options:
+.TP
+.B \-Version
+Print version and exit.
+.TP
+.B help
+Show summary of options.
+.TP
+.B file FILE [ all | LISTofOBJECTS ]
+Log output to FILE. LISTofOBJECTS is the list of object types that we
+want to monitor. It may contain 'link', 'address', 'route'
+and 'all'. 'link' specifies the network device, 'address' the protocol
+(IP or IPv6) address on a device, 'route' the routing table entry
+and 'all' does what the name says.
+.TP
+.B \-family [ inet | inet6 | link | help ]
+Specify protocol family. 'inet' is IPv4, 'inet6' is IPv6, 'link'
+means that no networking protocol is involved and 'help' prints usage information.
+.TP
+.B \-4
+Use IPv4. Shortcut for -family inet.
+.TP
+.B \-6
+Use IPv6. Shortcut for -family inet6.
+.TP
+.B \-0
+Use a special family identifier meaning that no networking protocol is involved. Shortcut for -family link.
+.SH USAGE EXAMPLES
+.TP
+.B # rtmon file /var/log/rtmon.log
+Log to file /var/log/rtmon.log, then run:
+.TP
+.B # ip monitor file /var/log/rtmon.log
+to display logged output from file.
+.SH SEE ALSO
+.BR ip (8)
+.SH AUTHOR
+.B rtmon
+was written by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org>,
+for the Debian project (but may be used by others).
--- /dev/null
+.TH SS 8
+.SH NAME
+ss \- another utility to investigate sockets
+.SH SYNOPSIS
+.B ss
+.RI [ options ] " [ FILTER ]"
+.SH DESCRIPTION
+.B ss
+is used to dump socket statistics. It allows showing information similar
+to
+.IR netstat .
+It can display more TCP and state informations than other tools.
+
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+A summary of options is included below.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-V, \-\-version
+Output version information.
+.TP
+.B \-n, \-\-numeric
+Do now try to resolve service names.
+.TP
+.B \-r, \-\-resolve
+Try to resolve numeric address/ports.
+.TP
+.B \-a, \-\-all
+Display all sockets.
+.TP
+.B \-l, \-\-listening
+Display listening sockets.
+.TP
+.B \-o, \-\-options
+Show timer information.
+.TP
+.B \-e, \-\-extended
+Show detailed socket information
+.TP
+.B \-m, \-\-memory
+Show socket memory usage.
+.TP
+.B \-p, \-\-processes
+Show process using socket.
+.TP
+.B \-i, \-\-info
+Show internal TCP information.
+.TP
+.B \-s, \-\-summary
+Print summary statistics. This option does not parse socket lists obtaining
+summary from various sources. It is useful when amount of sockets is so huge
+that parsing /proc/net/tcp is painful.
+.TP
+.B \-4, \-\-ipv4
+Display only IP version 4 sockets (alias for -f inet).
+.TP
+.B \-6, \-\-ipv6
+Display only IP version 6 sockets (alias for -f inet6).
+.TP
+.B \-0, \-\-packet
+Display PACKET sockets.
+.TP
+.B \-t, \-\-tcp
+Display only TCP sockets.
+.TP
+.B \-u, \-\-udp
+Display only UDP sockets.
+.TP
+.B \-d, \-\-dccp
+Display only DCCP sockets.
+.TP
+.B \-w, \-\-raw
+Display only RAW sockets.
+.TP
+.B \-x, \-\-unix
+Display only Unix domain sockets.
+.TP
+.B \-f FAMILY, \-\-family=FAMILY
+Display sockets of type FAMILY.
+Currently the following families are supported: unix, inet, inet6, link, netlink.
+.TP
+.B \-A QUERY, \-\-query=QUERY
+List of socket tables to dump, separated by commas. The following identifiers
+are understood: all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram,
+unix_stream, packet_raw, packet_dgram.
+.TP
+.B \-D FILE
+Do not display anything, just dump raw information about TCP sockets to FILE after applying filters. If FILE is - stdout is used.
+.TP
+.B \-F FILE, \-\-filter=FILE
+Read filter information from FILE.
+Each line of FILE is interpreted like single command line option. If FILE is - stdin is used.
+.TP
+.B FILTER := [ state TCP-STATE ] [ EXPRESSION ]
+Please take a look at the official documentation (Debian package iproute-doc) for details regarding filters.
+.SH USAGE EXAMPLES
+.TP
+.B ss -t -a
+Display all TCP sockets.
+.TP
+.B ss -u -a
+Display all UDP sockets.
+.TP
+.B ss -o state established '( dport = :ssh or sport = :ssh )'
+Display all established ssh connections.
+.TP
+.B ss -x src /tmp/.X11-unix/*
+Find all local processes connected to X server.
+.TP
+.B ss -o state fin-wait-1 '( sport = :http or sport = :https )' dst 193.233.7/24
+List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers.
+.SH SEE ALSO
+.BR ip (8),
+.BR /usr/share/doc/iproute-doc/ss.html " (package iprouteÂdoc)"
+.SH AUTHOR
+.I ss
+was written by Alexey Kuznetosv, <kuznet@ms2.inr.ac.ru>.
+.PP
+This manual page was written by Michael Prokop <mika@grml.org>
+for the Debian project (but may be used by others).
priority. If found, choose it, and terminate.
.TP
(iii)
-Choose the class at which break out to the fallback algorithm occured. Terminate.
+Choose the class at which break out to the fallback algorithm occurred. Terminate.
.P
The packet is enqueued to the class which was chosen when either algorithm
terminated. It is therefore possible for a packet to be enqueued *not* at a
.SH NOTES
Due to Unix timing constraints, the maximum ceil rate is not infinite and may in fact be quite low. On Intel,
there are 100 timer events per second, the maximum rate is that rate at which 'burst' bytes are sent each timer tick.
-From this, the mininum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte
+From this, the minimum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte
burst as 100*12kb*8 equals 10mbit.
.SH SEE ALSO
--- /dev/null
+tc-bfifo.8
\ No newline at end of file
On creation with 'tc qdisc add', a fixed number of bands is created. Each
band is a class, although is not possible to add classes with 'tc qdisc
add', the number of bands to be created must instead be specified on the
-commandline attaching PRIO to its root.
+command line attaching PRIO to its root.
When dequeueing, band 0 is tried first and only if it did not deliver a
packet does PRIO try band 1, and so onwards. Maximum reliability packets
The four TOS bits (the 'TOS field') are defined as:
.nf
-Binary Decimcal Meaning
+Binary Decimal Meaning
-----------------------------------------
1000 8 Minimize delay (md)
0100 4 Maximize throughput (mt)
The second column contains the value of the relevant
four TOS bits, followed by their translated meaning. For example, 15 stands
-for a packet wanting Minimal Montetary Cost, Maximum Reliability, Maximum
+for a packet wanting Minimal Monetary Cost, Maximum Reliability, Maximum
Throughput AND Minimum Delay.
The fourth column lists the way the Linux kernel interprets the TOS bits, by
showing to which Priority they are mapped.
-The last column shows the result of the default priomap. On the commandline,
+The last column shows the result of the default priomap. On the command line,
the default priomap looks like this:
1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
.B flowid
flow-id
-.B tc [-s | -d ] qdisc show [ dev
+.B tc
+.RI "[ " FORMAT " ]"
+.B qdisc show [ dev
DEV
.B ]
.P
-.B tc [-s | -d ] class show dev
+.B tc
+.RI "[ " FORMAT " ]"
+.B class show dev
DEV
.P
.B tc filter show dev
DEV
+.ti -8
+.IR FORMAT " := {"
+\fB\-s\fR[\fItatistics\fR] |
+\fB\-d\fR[\fIetails\fR] |
+\fB\-r\fR[\fIaw\fR] |
+\fB\-p\fR[\fIretty\fR] |
+\fB\i\fR[\fIec\fR] }
+
.SH DESCRIPTION
.B Tc
is used to configure Traffic Control in the Linux kernel. Traffic Control consists
tc filters
If tc filters are attached to a class, they are consulted first
for relevant instructions. Filters can match on all fields of a packet header,
-as well as on the firewall mark applied by ipchains or iptables. See
-.BR tc-filters (8).
+as well as on the firewall mark applied by ipchains or iptables.
.TP
Type of Service
Some qdiscs have built in rules for classifying packets based on the TOS field.
.TP
FILTERS
Filters have a three part ID, which is only needed when using a hashed
-filter hierarchy, for which see
-.BR tc-filters (8).
+filter hierarchy.
.SH UNITS
All parameters accept a floating point number, possibly followed by a unit.
.P
Only available for qdiscs and performs a replace where the node
must exist already.
+.SH FORMAT
+The show command has additional formatting options:
+
+.TP
+.BR "\-s" , " \-stats", " \-statistics"
+output more statistics about packet usage.
+
+.TP
+.BR "\-d", " \-details"
+output more detailed information about rates and cell sizes.
+
+.TP
+.BR "\-r", " \-raw"
+output raw hex values for handles.
+
+.TP
+.BR "\-p", " \-pretty"
+decode filter offset and mask values to equivalent filter commands based on TCP/IP.
+
+.TP
+.BR "\-iec"
+print rates in IEC units (ie. 1K = 1024).
+
.SH HISTORY
.B tc
.BR tc-pfifo (8),
.BR tc-bfifo (8),
.BR tc-pfifo_fast (8),
-.BR tc-filters (8)
+.br
+.RB "User documentation at " http://lartc.org/ ", but please direct bugreports and patches to: " <netdev@vger.kernel.org>
.SH AUTHOR
Manpage maintained by bert hubert (ahu@ds9a.nl)
--- /dev/null
+arpd
+ifstat
+ss
+ssfilter.c
+nstat
+lnstat
+rtacct
lnstat: $(LNSTATOBJ)
install: all
- install -m 0755 -s $(TARGETS) $(DESTDIR)$(SBINDIR)
+ install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
ln -sf lnstat $(DESTDIR)$(SBINDIR)/rtstat
ln -sf lnstat $(DESTDIR)$(SBINDIR)/ctstat
DB *dbase;
char *dbname = "/var/lib/arpd/arpd.db";
-int ifnum;
+int ifnum;
int *ifvec;
char **ifnames;
};
#define IS_NEG(x) (((__u8*)(x))[0] == 0xFF)
-#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
+#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x))
#define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
#define NEG_CNT(x) (((__u8*)(x))[1])
DBT dbkey, dbdat;
int n;
- n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
+ n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
(struct sockaddr*)&sll, &sll_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
key.iface = sll.sll_ifindex;
memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4);
- /* DAD message, ignore. */
+ /* DAD message, ignore. */
if (key.addr == 0)
return;
sa.sa_handler = handler;
#ifdef SA_INTERRUPT
sa.sa_flags = SA_INTERRUPT;
-#endif
+#endif
sigaction(sig, &sa, NULL);
}
DBT dbkey, dbdat;
printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
- struct dbkey *key = dbkey.data;
+ struct dbkey *key = dbkey.data;
if (handle_if(key->iface)) {
if (!IS_NEG(dbdat.data)) {
char b1[18];
return 0;
}
-static int get_nlmsg(const struct sockaddr_nl *who,
+static int get_nlmsg(const struct sockaddr_nl *who,
struct nlmsghdr *m, void *arg)
{
struct ifinfomsg *ifi = NLMSG_DATA(m);
int i;
for (i = 0; i < MAXS; i++) {
if ((long)(h1->ival[i] - n->ival[i]) < 0) {
- memset(n->ival, 0, sizeof(n->ival));
+ memset(n->ival, 0, sizeof(n->ival));
break;
}
}
- for (i = 0; i < MAXS; i++) {
+ for (i = 0; i < MAXS; i++) {
double sample;
unsigned long incr = h1->ival[i] - n->ival[i];
n->val[i] += incr;
*/
/* Maximum number of fields that can be displayed */
-#define MAX_FIELDS 64
+#define MAX_FIELDS 128
/* Maximum number of header lines */
#define HDR_LINES 10
fps->params[j].lf->file->interval.tv_sec =
interval;
if (!fps->params[j].print.width)
- fps->params[j].print.width =
+ fps->params[j].print.width =
FIELD_WIDTH_DEFAULT;
- j++;
+
+ if (++j >= MAX_FIELDS - 1) {
+ fprintf(stderr,
+ "WARN: MAX_FIELDS (%d) reached,"
+ " truncating number of keys\n",
+ MAX_FIELDS);
+ goto full;
+ }
}
}
+ full:
fps->num = j;
return 1;
}
}
return 0;
}
-
+
int main(int argc, char **argv)
{
static struct field_params fp;
int num_req_files = 0;
char *req_files[LNSTAT_MAX_FILES];
-
+
/* backwards compatibility mode for old tools */
basename = strrchr(argv[0], '/');
- if (basename)
+ if (basename)
basename += 1; /* name after slash */
else
basename = argv[0]; /* no slash */
num_req_files = 1;
}
- while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:",
+ while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:",
opts, NULL)) != -1) {
int i, len = 0;
char *tmp, *tok;
req_files[num_req_files++] = strdup(optarg);
break;
case '?':
- case 'h':
+ case 'h':
usage(argv[0], 0);
break;
case 'i':
for (tok = strtok(tmp, ",");
tok;
tok = strtok(NULL, ",")) {
- if (fp.num >= MAX_FIELDS)
+ if (fp.num >= MAX_FIELDS) {
+ fprintf(stderr,
+ "WARN: too many keys"
+ " requested: (%d max)\n",
+ MAX_FIELDS);
break;
+ }
fp.params[fp.num++].name = tok;
}
break;
if (!map_field_params(lnstat_files, &fp, interval))
exit(1);
-
+
header = build_hdr_string(lnstat_files, &fp, 80);
if (!header)
exit(1);
- if (interval < 1 )
+ if (interval < 1 )
interval=1;
for (i = 0; i < count; i++) {
print_hdr(stdout, header);
lnstat_update(lnstat_files);
print_line(stdout, lnstat_files, &fp);
+ fflush(stdout);
sleep(interval);
}
}
num_lines++;
- fgets(buf, sizeof(buf)-1, lf->fp);
+ fgets(buf, sizeof(buf)-1, lf->fp);
gettimeofday(&lf->last_read, NULL);
for (j = 0; j < lf->num_fields; j++) {
unsigned long f = strtoul(ptr, &ptr, 16);
- if (j == 0)
+ if (j == 0)
lf->fields[j].values[i] = f;
else
lf->fields[j].values[i] += f;
return num_lines;
}
-static int time_after(struct timeval *last,
- struct timeval *tout,
+static int time_after(struct timeval *last,
+ struct timeval *tout,
struct timeval *now)
{
if (now->tv_sec > last->tv_sec + tout->tv_sec)
}
scan_lines(lf, 1);
- for (i = 0, lfi = &lf->fields[i];
+ for (i = 0, lfi = &lf->fields[i];
i < lf->num_fields; i++, lfi = &lf->fields[i]) {
if (i == 0)
lfi->result = lfi->values[1];
if (!path)
path = PROC_NET_STAT;
-
+
dir = opendir(path);
if (!dir) {
struct lnstat_file *lf;
file = NULL;
field = name;
}
-
+
for (lf = lnstat_files; lf; lf = lf->next) {
int i;
+++ /dev/null
-#! /bin/bash
-
-echo -n "Send network configuration summary to [ENTER means kuznet@ms2.inr.ac.ru] "
-IFS="" read mail || exit 1
-[ -z "$mail" ] && mail=kuznet@ms2.inr.ac.ru
-
-
-netbug=""
-while [ "$netbug" = "" ]; do
- netbug=`echo netbug.$$.$RANDOM`
- if [ -e /tmp/$netbug ]; then
- netbug=""
- fi
-done
-
-tmppath=/tmp/$netbug
-
-trap "rm -rf $tmppath $tmppath.tar.gz" 0 SIGINT
-
-mkdir $tmppath
-mkdir $tmppath/net
-
-cat /proc/slabinfo > $tmppath/slabinfo
-cat /proc/net/netstat > $tmppath/net/netstat
-cat /proc/net/unix > $tmppath/net/unix
-cat /proc/net/packet > $tmppath/net/packet
-cat /proc/net/netlink > $tmppath/net/netlink
-cat /proc/net/psched > $tmppath/net/psched
-cat /proc/net/softnet_stat > $tmppath/net/softnet_stat
-cat /proc/net/sockstat > $tmppath/net/sockstat
-cat /proc/net/tcp > $tmppath/net/tcp
-cat /proc/net/udp > $tmppath/net/udp
-cat /proc/net/raw > $tmppath/net/raw
-cat /proc/net/snmp > $tmppath/net/snmp
-
-ss -aioem -D $tmppath/tcpdiag
-
-if [ -e /proc/net/tcp6 ]; then
- cat /proc/net/sockstat6 > $tmppath/net/sockstat6
- cat /proc/net/tcp6 > $tmppath/net/tcp6
- cat /proc/net/udp6 > $tmppath/net/udp6
- cat /proc/net/raw6 > $tmppath/net/raw6
- cat /proc/net/snmp6 > $tmppath/net/snmp6
-fi
-
-cd /tmp
-tar c $netbug | gzip -9c > $netbug.tar.gz
-
-uuencode $netbug.tar.gz $netbug.tar.gz | mail -s $netbug "$mail"
-
-echo "Sending to <$mail>; subject is $netbug"
-
-exit 0
char info_source[128];
int source_mismatch;
-int generic_proc_open(char *env, char *name)
+static int generic_proc_open(const char *env, char *name)
{
char store[128];
char *p = getenv(env);
snprintf(store, sizeof(store)-1, "%s/%s", p, name);
p = store;
}
- return open(store, O_RDONLY);
+ return open(p, O_RDONLY);
}
int net_netstat_open(void)
struct pollfd p;
p.fd = fd;
p.events = p.revents = POLLIN;
-
+
sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);
unsigned long magic_number = 0;
double W;
-int generic_proc_open(char *env, char *name)
+static int generic_proc_open(const char *env, const char *name)
{
char store[1024];
char *p = getenv(env);
snprintf(store, sizeof(store)-1, "%s/%s", p, name);
p = store;
}
- return open(store, O_RDONLY);
+ return open(p, O_RDONLY);
}
int net_rtacct_open(void)
"%-10s "
"%-10s "
"\n"
- , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
+ , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
fprintf(fp,
"%-10s "
"%-10s "
"%-10s "
"%-10s "
"\n"
- , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
+ , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
}
fprintf(fp, "%-10s", rtnl_rtrealm_n2a(realm, b1, sizeof(b1)));
for (i = 0; i < 4; i++)
- format_count(fp, val[i]);
+ format_count(fp, val[i]);
fprintf(fp, "\n%-10s", "");
for (i = 0; i < 4; i++)
- format_rate(fp, rate[i]);
+ format_rate(fp, rate[i]);
fprintf(fp, "\n");
}
}
"%-10s "
"%-10s "
"\n"
- , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
+ , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom");
fprintf(fp,
"%-10s "
"%-10s "
"%-10s "
"%-10s "
"\n"
- , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
+ , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom");
}
for (realm=0; realm<256; realm++) {
fprintf(fp, "%-10s", rtnl_rtrealm_n2a(realm, b1, sizeof(b1)));
for (i = 0; i < 4; i++)
- format_count(fp, rval[i]);
+ format_count(fp, rval[i]);
fprintf(fp, "\n%-10s", "");
for (i = 0; i < 4; i++)
- format_rate(fp, rate[i]);
+ format_rate(fp, rate[i]);
fprintf(fp, "\n");
}
}
{
}
-/* Server side only: read kernel data, update tables, calculate rates. */
+/* Server side only: read kernel data, update tables, calculate rates. */
void update_db(int interval)
{
p.fd = fd;
p.events = p.revents = POLLIN;
- sprintf(kern_db->signature,
+ sprintf(kern_db->signature,
"%u.%lu sampling_interval=%d time_const=%d",
- (unsigned) getpid(), (unsigned long)random(),
+ (unsigned) getpid(), (unsigned long)random(),
scan_interval/1000, time_constant/1000);
pad_kern_table(kern_db, read_kern_table(kern_db->ival));
#include "libnetlink.h"
#include "SNAPSHOT.h"
+#include <netinet/tcp.h>
#include <linux/inet_diag.h>
-#include <linux/tcp.h>
-#include <net/tcp_states.h>
int resolve_hosts = 0;
int resolve_services = 1;
};
struct filter default_filter = {
- dbs: (1<<TCP_DB),
- states: SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
- families: (1<<AF_INET)|(1<<AF_INET6),
+ .dbs = (1<<TCP_DB),
+ .states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
+ .families= (1<<AF_INET)|(1<<AF_INET6),
};
struct filter current_filter;
-int generic_proc_open(char *env, char *name)
+static FILE *generic_proc_open(const char *env, const char *name)
{
+ const char *p = getenv(env);
char store[128];
- char *p = getenv(env);
+
if (!p) {
p = getenv("PROC_ROOT") ? : "/proc";
snprintf(store, sizeof(store)-1, "%s/%s", p, name);
p = store;
}
- return open(store, O_RDONLY);
+
+ return fopen(p, "r");
}
-int net_tcp_open(void)
+static FILE *net_tcp_open(void)
{
return generic_proc_open("PROC_NET_TCP", "net/tcp");
}
-int net_tcp6_open(void)
+static FILE *net_tcp6_open(void)
{
return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
}
-int net_udp_open(void)
+static FILE *net_udp_open(void)
{
return generic_proc_open("PROC_NET_UDP", "net/udp");
}
-int net_udp6_open(void)
+static FILE *net_udp6_open(void)
{
return generic_proc_open("PROC_NET_UDP6", "net/udp6");
}
-int net_raw_open(void)
+static FILE *net_raw_open(void)
{
return generic_proc_open("PROC_NET_RAW", "net/raw");
}
-int net_raw6_open(void)
+static FILE *net_raw6_open(void)
{
return generic_proc_open("PROC_NET_RAW6", "net/raw6");
}
-int net_unix_open(void)
+static FILE *net_unix_open(void)
{
return generic_proc_open("PROC_NET_UNIX", "net/unix");
}
-int net_packet_open(void)
+static FILE *net_packet_open(void)
{
return generic_proc_open("PROC_NET_PACKET", "net/packet");
}
-int net_netlink_open(void)
+static FILE *net_netlink_open(void)
{
return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
}
-int slabinfo_open(void)
+static FILE *slabinfo_open(void)
{
return generic_proc_open("PROC_SLABINFO", "slabinfo");
}
-int net_sockstat_open(void)
+static FILE *net_sockstat_open(void)
{
return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
}
-int net_sockstat6_open(void)
+static FILE *net_sockstat6_open(void)
{
return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
}
-int net_snmp_open(void)
+static FILE *net_snmp_open(void)
{
return generic_proc_open("PROC_NET_SNMP", "net/snmp");
}
-int net_netstat_open(void)
-{
- return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
-}
-
-int ephemeral_ports_open(void)
+static FILE *ephemeral_ports_open(void)
{
return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
}
-int find_users(int ino, char *buf, int buflen)
+int find_users(unsigned ino, char *buf, int buflen)
{
char pattern[64];
int pattern_len;
if (!ino)
return 0;
- sprintf(pattern, "socket:[%d]", ino);
+ sprintf(pattern, "socket:[%u]", ino);
pattern_len = strlen(pattern);
strncpy(name, getenv("PROC_ROOT") ? : "/proc/", sizeof(name)/2);
struct slabstat slabstat;
-static const char *slabstat_ids[] =
+static const char *slabstat_ids[] =
{
"sock",
"tcp_bind_bucket",
memset(s, 0, sizeof(*s));
- if ((fp = fdopen(slabinfo_open(), "r")) == NULL)
+ fp = slabinfo_open();
+ if (!fp)
return -1;
cnt = sizeof(*s)/sizeof(int);
int timer;
int timeout;
int retrs;
- int ino;
+ unsigned ino;
int probes;
- int uid;
+ unsigned uid;
int refcnt;
unsigned long long sk;
int rto, ato, qack, cwnd, ssthresh;
if (msecs)
sprintf(buf+strlen(buf), "%03dms", msecs);
return buf;
-};
+}
const char *print_hz_timer(int timeout)
{
- int hz = get_hz();
+ int hz = get_user_hz();
return print_ms_timer(((timeout*1000) + hz-1)/hz);
-};
+}
struct scache
{
static int is_ephemeral(int port)
{
if (!ip_local_port_min) {
- FILE *f = fdopen(ephemeral_ports_open(), "r");
+ FILE *f = ephemeral_ports_open();
if (f) {
- fscanf(f, "%d %d",
+ fscanf(f, "%d %d",
&ip_local_port_min, &ip_local_port_max);
fclose(f);
} else {
if (!notfirst) {
setservent(1);
notfirst = 1;
- }
+ }
se = getservbyport(htons(port), dg_proto);
if (se)
return se->s_name;
const char *res;
int hash = (port^(((unsigned long)dg_proto)>>2))&255;
- for (c = &cache[hash]; c; c = c->next) {
+ for (c = &cache[hash]; c; c = c->next) {
if (c->port == port &&
c->proto == dg_proto) {
if (c->name)
char *p;
memcpy(&p, s->local.data, sizeof(p));
return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
- strspn(p+1, "0123456789abcdef") == 5);
+ strspn(p+1, "0123456789abcdef") == 5);
}
if (s->local.family == AF_PACKET)
return s->lport == 0 && s->local.data == 0;
return s->lport < 0;
if (!low) {
- FILE *fp = fdopen(ephemeral_ports_open(), "r");
+ FILE *fp = ephemeral_ports_open();
if (fp) {
fscanf(fp, "%d%d", &low, &high);
fclose(fp);
do {
if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
return 1;
- } while ((a = a->next) != NULL);
+ } while ((a = a->next) != NULL);
return 0;
}
return 1;
}
}
-/* Relocate external jumps by reloc. */
+/* Relocate external jumps by reloc. */
static void ssfilter_patch(char *a, int len, int reloc)
{
while (len > 0) {
static int remember_he(struct aafilter *a, struct hostent *he)
{
- char **ptr = he->h_addr_list;
+ char **ptr = he->h_addr_list;
int cnt = 0;
int len;
return res;
}
-static int tcp_show_line(char *line, struct filter *f, int family)
+static int tcp_show_line(char *line, const struct filter *f, int family)
{
struct tcpstat s;
char *loc, *rem, *data;
char opt[256];
int n;
char *p;
-
+
if ((p = strchr(line, ':')) == NULL)
return -1;
loc = p+2;
-
+
if ((p = strchr(loc, ':')) == NULL)
return -1;
p[5] = 0;
rem = p+6;
-
+
if ((p = strchr(rem, ':')) == NULL)
return -1;
p[5] = 0;
data = p+6;
-
+
do {
int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
if (!(f->states & (1<<state)))
return 0;
} while (0);
-
+
s.local.family = s.remote.family = family;
if (family == AF_INET) {
sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
&s.rport);
s.local.bytelen = s.remote.bytelen = 16;
}
-
+
if (f->f && run_ssfilter(f->f, &s) == 0)
return 0;
-
+
opt[0] = 0;
- n = sscanf(data, "%x %x:%x %x:%x %x %d %d %d %d %llx %d %d %d %d %d %[^\n]\n",
+ n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
&s.state, &s.wq, &s.rq,
&s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
&s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
&s.cwnd, &s.ssthresh, opt);
-
+
if (n < 17)
opt[0] = 0;
-
+
if (n < 12) {
s.rto = 0;
s.cwnd = 2;
s.ssthresh = -1;
s.ato = s.qack = 0;
}
-
+
if (netid_width)
printf("%-*s ", netid_width, "tcp");
if (state_width)
printf("%-*s ", state_width, sstate_name[s.state]);
-
+
printf("%-6d %-6d ", s.rq, s.wq);
-
+
formatted_print(&s.local, s.lport);
formatted_print(&s.remote, s.rport);
-
+
if (show_options) {
if (s.timer) {
if (s.timer > 4)
}
}
if (show_tcpinfo) {
- if (s.rto && s.rto != 3*get_hz())
- printf(" rto:%g", (double)s.rto/get_hz());
+ int hz = get_user_hz();
+ if (s.rto && s.rto != 3*hz)
+ printf(" rto:%g", (double)s.rto/hz);
if (s.ato)
- printf(" ato:%g", (double)s.ato/get_hz());
+ printf(" ato:%g", (double)s.ato/hz);
if (s.cwnd != 2)
printf(" cwnd:%d", s.cwnd);
if (s.ssthresh != -1)
if (show_details) {
if (s.uid)
printf(" uid:%u", (unsigned)s.uid);
- printf(" ino:%u", (unsigned)s.ino);
+ printf(" ino:%u", s.ino);
printf(" sk:%llx", s.sk);
if (opt[0])
printf(" opt:\"%s\"", opt);
return 0;
}
-static int generic_record_read(int fd, char *buf, int bufsize,
- int (*worker)(char*, struct filter *, int),
- struct filter *f, int fam)
+static int generic_record_read(FILE *fp,
+ int (*worker)(char*, const struct filter *, int),
+ const struct filter *f, int fam)
{
- int n;
- int recsize;
- int eof = 0;
- char *p;
+ char line[256];
- /* Load the first chunk and calculate record length from it. */
- n = read(fd, buf, bufsize);
- if (n < 0)
+ /* skip header */
+ if (fgets(line, sizeof(line), fp) == NULL)
goto outerr;
- /* I _know_ that this is wrong, do not remind. :-)
- * But this works nowadays. */
- if (n < bufsize)
- eof = 1;
- p = memchr(buf, '\n', n);
- if (p == NULL || (p-buf) >= n)
- goto outwrongformat;
- recsize = (p-buf)+1;
- p = buf+recsize;
-
- for (;;) {
- while ((p+recsize) - buf <= n) {
- if (p[recsize-1] != '\n')
- goto outwrongformat;
- p[recsize-1] = 0;
- if (worker(p, f, fam) < 0)
- goto done;
- p += recsize;
- }
- if (!eof) {
- int remains = (buf+bufsize) - p;
- memcpy(buf, p, remains);
- p = buf+remains;
- n = read(fd, p, (buf+bufsize) - p);
- if (n < 0)
- goto outerr;
- if (n < (buf+bufsize) - p) {
- eof = 1;
- if (n == 0) {
- if (remains)
- goto outwrongformat;
- goto done;
- }
- }
- n += remains;
- p = buf;
- } else {
- if (p != buf+n)
- goto outwrongformat;
- goto done;
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int n = strlen(line);
+ if (n == 0 || line[n-1] != '\n') {
+ errno = -EINVAL;
+ return -1;
}
- }
-done:
- return 0;
+ line[n-1] = 0;
-outwrongformat:
- errno = EINVAL;
+ if (worker(line, f, fam) < 0)
+ return 0;
+ }
outerr:
- return -1;
+
+ return ferror(fp) ? -1 : 0;
}
-
+
static char *sprint_bw(char *buf, double bw)
{
- if (bw > 1000000.)
+ if (bw > 1000000.)
sprintf(buf,"%.1fM", bw / 1000000.);
else if (bw > 1000.)
sprintf(buf,"%.1fK", bw / 1000.);
if (tb[INET_DIAG_CONG])
printf("%s", (char *) RTA_DATA(tb[INET_DIAG_CONG]));
- if (info->tcpi_options & TCPI_OPT_WSCALE)
+ if (info->tcpi_options & TCPI_OPT_WSCALE)
printf(" wscale:%d,%d", info->tcpi_snd_wscale,
info->tcpi_rcv_wscale);
if (info->tcpi_rto && info->tcpi_rto != 3000000)
const struct tcpvegas_info *vinfo
= RTA_DATA(tb[INET_DIAG_VEGASINFO]);
- if (vinfo->tcpv_enabled &&
+ if (vinfo->tcpv_enabled &&
vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
rtt = vinfo->tcpv_rtt;
}
}
}
-int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
+static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
{
struct inet_diag_msg *r = NLMSG_DATA(nlh);
struct tcpstat s;
if (show_details) {
if (r->idiag_uid)
printf(" uid:%u", (unsigned)r->idiag_uid);
- printf(" ino:%u", (unsigned)r->idiag_inode);
+ printf(" ino:%u", r->idiag_inode);
printf(" sk:%08x", r->id.idiag_cookie[0]);
if (r->id.idiag_cookie[1] != 0)
printf("%08x", r->id.idiag_cookie[1]);
return 0;
}
-int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
+static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
{
int fd;
struct sockaddr_nl nladdr;
req.r.idiag_family = AF_INET;
req.r.idiag_states = f->states;
if (show_mem)
- req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
+ req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
if (show_tcpinfo) {
req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
}
- iov[0] = (struct iovec){
- .iov_base = &req,
- .iov_len = sizeof(req)
+ iov[0] = (struct iovec){
+ .iov_base = &req,
+ .iov_len = sizeof(req)
};
if (f->f) {
bclen = ssfilter_bytecompile(f->f, &bc);
}
msg = (struct msghdr) {
- .msg_name = (void*)&nladdr,
+ .msg_name = (void*)&nladdr,
.msg_namelen = sizeof(nladdr),
- .msg_iov = iov,
+ .msg_iov = iov,
.msg_iovlen = f->f ? 3 : 1,
};
if (sendmsg(fd, &msg, 0) < 0)
return -1;
- iov[0] = (struct iovec){
- .iov_base = buf,
- .iov_len = sizeof(buf)
+ iov[0] = (struct iovec){
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
};
while (1) {
h = (struct nlmsghdr*)buf;
while (NLMSG_OK(h, status)) {
int err;
+ struct inet_diag_msg *r = NLMSG_DATA(h);
if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
h->nlmsg_seq != 123456)
return 0;
}
if (!dump_fp) {
+ if (!(f->families & (1<<r->idiag_family))) {
+ h = NLMSG_NEXT(h, status);
+ continue;
+ }
err = tcp_show_sock(h, NULL);
if (err < 0)
return err;
return 0;
}
-int tcp_show_netlink_file(struct filter *f)
+static int tcp_show_netlink_file(struct filter *f)
{
FILE *fp;
char buf[8192];
}
}
-int tcp_show(struct filter *f, int socktype)
+static int tcp_show(struct filter *f, int socktype)
{
- int fd = -1;
+ FILE *fp = NULL;
char *buf = NULL;
int bufsize = 64*1024;
/* Sigh... We have to parse /proc/net/tcp... */
+
/* Estimate amount of sockets and try to allocate
* huge buffer to read all the table at one read.
* Limit it by 16MB though. The assumption is: as soon as
}
if (f->families & (1<<AF_INET)) {
- if ((fd = net_tcp_open()) < 0)
+ if ((fp = net_tcp_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET))
+
+ setbuffer(fp, buf, bufsize);
+ if (generic_record_read(fp, tcp_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families & (1<<AF_INET6)) &&
- (fd = net_tcp6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET6))
+ (fp = net_tcp6_open()) != NULL) {
+ setbuffer(fp, buf, bufsize);
+ if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
free(buf);
int saved_errno = errno;
if (buf)
free(buf);
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
}
-int dgram_show_line(char *line, struct filter *f, int family)
+int dgram_show_line(char *line, const struct filter *f, int family)
{
struct tcpstat s;
char *loc, *rem, *data;
return 0;
opt[0] = 0;
- n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %d %d %llx %[^\n]\n",
+ n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
&s.state, &s.wq, &s.rq,
&s.uid, &s.ino,
&s.refcnt, &s.sk, opt);
if (show_details) {
if (s.uid)
printf(" uid=%u", (unsigned)s.uid);
- printf(" ino=%u", (unsigned)s.ino);
+ printf(" ino=%u", s.ino);
printf(" sk=%llx", s.sk);
if (opt[0])
printf(" opt:\"%s\"", opt);
int udp_show(struct filter *f)
{
- int fd = -1;
- char buf[8192];
- int bufsize = sizeof(buf);
+ FILE *fp = NULL;
dg_proto = UDP_PROTO;
if (f->families&(1<<AF_INET)) {
- if ((fd = net_udp_open()) < 0)
+ if ((fp = net_udp_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families&(1<<AF_INET6)) &&
- (fd = net_udp6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+ (fp = net_udp6_open()) != NULL) {
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
return 0;
outerr:
do {
int saved_errno = errno;
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
int raw_show(struct filter *f)
{
- int fd = -1;
- char buf[8192];
- int bufsize = sizeof(buf);
+ FILE *fp = NULL;
dg_proto = RAW_PROTO;
if (f->families&(1<<AF_INET)) {
- if ((fd = net_raw_open()) < 0)
+ if ((fp = net_raw_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families&(1<<AF_INET6)) &&
- (fd = net_raw6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+ (fp = net_raw6_open()) != NULL) {
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
return 0;
outerr:
do {
int saved_errno = errno;
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
if (strcmp(peer, "*") == 0)
memset(tst.remote.data, 0, sizeof(peer));
else
- memcpy(tst.remote.data, &peer, sizeof(peer));
+ memcpy(tst.remote.data, &peer, sizeof(peer));
if (run_ssfilter(f->f, &tst) == 0)
continue;
}
if (netid_width)
- printf("%-*s ", netid_width,
+ printf("%-*s ", netid_width,
s->type == SOCK_STREAM ? "u_str" : "u_dgr");
if (state_width)
printf("%-*s ", state_width, sstate_name[s->state]);
int cnt;
struct unixstat *list = NULL;
- if ((fp = fdopen(net_unix_open(), "r")) == NULL)
+ if ((fp = net_unix_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
- if (memcmp(buf, "Peer", 4) == 0)
+ if (memcmp(buf, "Peer", 4) == 0)
newformat = 1;
cnt = 0;
if (!(f->states & (1<<SS_CLOSE)))
return 0;
- if ((fp = fdopen(net_packet_open(), "r")) == NULL)
+ if ((fp = net_packet_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
}
if (netid_width)
- printf("%-*s ", netid_width,
+ printf("%-*s ", netid_width,
type == SOCK_RAW ? "p_raw" : "p_dgr");
if (state_width)
printf("%-*s ", state_width, "UNCONN");
printf("%*s:", addr_width, "*");
} else {
char tb[16];
- printf("%*s:", addr_width,
+ printf("%*s:", addr_width,
ll_proto_n2a(htons(prot), tb, sizeof(tb)));
}
if (iface == 0) {
if (!(f->states & (1<<SS_CLOSE)))
return 0;
- if ((fp = fdopen(net_netlink_open(), "r")) == NULL)
+ if ((fp = net_netlink_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
}
if (netid_width)
- printf("%-*s ", netid_width, "nl");
+ printf("%-*s ", netid_width, "nl");
if (state_width)
printf("%-*s ", state_width, "UNCONN");
printf("%-6d %-6d ", rq, wq);
getenv("PROC_ROOT") ? : "/proc", pid);
if ((fp = fopen(procname, "r")) != NULL) {
if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
- sprintf(procname+strlen(procname), "/%d", pid);
+ sprintf(procname+strlen(procname), "/%d", pid);
printf("%-*s ", serv_width, procname);
done = 1;
}
*result = 0;
- if ((fp = fdopen(net_snmp_open(), "r")) == NULL)
+ if ((fp = net_snmp_open()) == NULL)
return -1;
while (fgets(buf, sizeof(buf), fp) != NULL) {
memset(s, 0, sizeof(*s));
- if ((fp = fdopen(net_sockstat_open(), "r")) == NULL)
+ if ((fp = net_sockstat_open()) == NULL)
return -1;
while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s);
fclose(fp);
- if ((fp = fdopen(net_sockstat6_open(), "r")) == NULL)
+ if ((fp = net_sockstat6_open()) == NULL)
return 0;
while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s);
printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
- printf("INET %-9d %-9d %-9d\n",
+ printf("INET %-9d %-9d %-9d\n",
s.raw4+s.udp4+s.tcp4_hashed+
s.raw6+s.udp6+s.tcp6_hashed,
s.raw4+s.udp4+s.tcp4_hashed,
{ "version", 0, 0, 'V' },
{ "help", 0, 0, 'h' },
{ 0 }
-
+
};
int main(int argc, char *argv[])
p = p1 = optarg;
do {
if ((p1 = strchr(p, ',')) != NULL)
- *p1 = 0;
+ *p1 = 0;
if (strcmp(p, "all") == 0) {
current_filter.dbs = ALL_DB;
} else if (strcmp(p, "inet") == 0) {
int mask2;
if (preferred_family == AF_INET ||
preferred_family == AF_INET6) {
- mask2= (1<<TCP_DB);
- if (!do_default)
- mask2 = (1<<UDP_DB)|(1<<RAW_DB);
+ mask2= current_filter.dbs;
} else if (preferred_family == AF_PACKET) {
mask2 = PACKET_DBM;
} else if (preferred_family == AF_UNIX) {
if (addrp_width < 15+serv_width+1)
addrp_width = 15+serv_width+1;
- addr_width = addrp_width - serv_width - 1;
+ addr_width = addrp_width - serv_width - 1;
if (netid_width)
printf("%-*s ", netid_width, "Netid");
addr_width, "Local Address", serv_width, "Port",
addr_width, "Peer Address", serv_width, "Port");
-//printf("%08x %08x %08x\n", current_filter.dbs, current_filter.states, current_filter.families);
fflush(stdout);
if (current_filter.dbs & (1<<NETLINK_DB))
$$ = alloc_node(SSF_DCOND, $2);
}
| SCOND HOSTCOND
- {
+ {
$$ = alloc_node(SSF_SCOND, $2);
}
| DPORT GEQ HOSTCOND
--- /dev/null
+*.dist
+maketable
+normal
+pareto
+paretonormal
DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist
HOSTCC ?= $(CC)
+CCOPTS = $(CBUILD_CFLAGS)
LDLIBS += -lm
all: $(DISTGEN) $(DISTDATA)
experimental.dist: maketable experimental.dat
./maketable experimental.dat > experimental.dist
+stats: stats.c
+ $(HOSTCC) $(CCOPTS) -I../include -o $@ $@.c -lm
+
install: all
- mkdir -p $(DESTDIR)/usr/lib/tc
+ mkdir -p $(DESTDIR)/lib/tc
for i in $(DISTDATA); \
- do install -m 755 $$i $(DESTDIR)/usr/lib/tc; \
+ do install -m 755 $$i $(DESTDIR)/lib/tc; \
done
clean:
/*
* Experimental data distribution table generator
- * Taken from the uncopyrighted NISTnet code.
+ * Taken from the uncopyrighted NISTnet code (public domain).
*
- * Rread in a series of "random" data values, either
+ * Read in a series of "random" data values, either
* experimentally or generated from some probability distribution.
* From this, create the inverse distribution table used to approximate
* the distribution.
}
}
-int
+int
main(int argc, char **argv)
{
FILE *fp;
--- /dev/null
+/*
+ * Experimental data distribution table generator
+ * Taken from the uncopyrighted NISTnet code (public domain).
+ *
+ * Rread in a series of "random" data values, either
+ * experimentally or generated from some probability distribution.
+ * From this, report statistics.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void
+stats(FILE *fp)
+{
+ struct stat info;
+ double *x;
+ int limit;
+ int n=0, i;
+ double mu=0.0, sigma=0.0, sumsquare=0.0, sum=0.0, top=0.0, rho=0.0;
+ double sigma2=0.0;
+
+ fstat(fileno(fp), &info);
+ if (info.st_size > 0) {
+ limit = 2*info.st_size/sizeof(double); /* @@ approximate */
+ } else {
+ limit = 10000;
+ }
+ x = (double *)malloc(limit*sizeof(double));
+
+ for (i=0; i<limit; ++i){
+ fscanf(fp, "%lf", &x[i]);
+ if (feof(fp))
+ break;
+ sumsquare += x[i]*x[i];
+ sum += x[i];
+ ++n;
+ }
+ mu = sum/(double)n;
+ sigma = sqrt((sumsquare - (double)n*mu*mu)/(double)(n-1));
+
+ for (i=1; i < n; ++i){
+ top += ((double)x[i]-mu)*((double)x[i-1]-mu);
+ sigma2 += ((double)x[i-1] - mu)*((double)x[i-1] - mu);
+
+ }
+ rho = top/sigma2;
+
+ printf("mu = %12.6f\n", mu);
+ printf("sigma = %12.6f\n", sigma);
+ printf("rho = %12.6f\n", rho);
+ /*printf("sigma2 = %10.4f\n", sqrt(sigma2/(double)(n-1)));*/
+ /*printf("correlation rho = %10.6f\n", top/((double)(n-1)*sigma*sigma));*/
+}
+
+
+int
+main(int argc, char **argv)
+{
+ FILE *fp;
+
+ if (argc > 1) {
+ fp = fopen(argv[1], "r");
+ if (!fp) {
+ perror(argv[1]);
+ exit(1);
+ }
+ } else {
+ fp = stdin;
+ }
+ stats(fp);
+ return 0;
+}
--- /dev/null
+Trellis branch including EGRE
+
+--This line, and those below, will be ignored--
+
+A .
--- /dev/null
+Checking in new iproute2
+
+--This line, and those below, will be ignored--
+
+A .
--- /dev/null
+Trellis branch including EGRE
+
+--This line, and those below, will be ignored--
+
+A .
+++ /dev/null
-.TH CBQ 8 "8 December 2001" "iproute2" "Linux"
-.SH NAME
-CBQ \- Class Based Queueing
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B ( parent
-classid
-.B | root) [ handle
-major:
-.B ] cbq avpkt
-bytes
-.B bandwidth
-rate
-.B [ cell
-bytes
-.B ] [ ewma
-log
-.B ] [ mpu
-bytes
-.B ]
-
-.B tc class ... dev
-dev
-.B parent
-major:[minor]
-.B [ classid
-major:minor
-.B ] cbq allot
-bytes
-.B [ bandwidth
-rate
-.B ] [ rate
-rate
-.B ] prio
-priority
-.B [ weight
-weight
-.B ] [ minburst
-packets
-.B ] [ maxburst
-packets
-.B ] [ ewma
-log
-.B ] [ cell
-bytes
-.B ] avpkt
-bytes
-.B [ mpu
-bytes
-.B ] [ bounded isolated ] [ split
-handle
-.B & defmap
-defmap
-.B ] [ estimator
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-Class Based Queueing is a classful qdisc that implements a rich
-linksharing hierarchy of classes. It contains shaping elements as
-well as prioritizing capabilities. Shaping is performed using link
-idle time calculations based on the timing of dequeue events and
-underlying link bandwidth.
-
-.SH SHAPING ALGORITHM
-Shaping is done using link idle time calculations, and actions taken if
-these calculations deviate from set limits.
-
-When shaping a 10mbit/s connection to 1mbit/s, the link will
-be idle 90% of the time. If it isn't, it needs to be throttled so that it
-IS idle 90% of the time.
-
-From the kernel's perspective, this is hard to measure, so CBQ instead
-derives the idle time from the number of microseconds (in fact, jiffies)
-that elapse between requests from the device driver for more data. Combined
-with the knowledge of packet sizes, this is used to approximate how full or
-empty the link is.
-
-This is rather circumspect and doesn't always arrive at proper
-results. For example, what is the actual link speed of an interface
-that is not really able to transmit the full 100mbit/s of data,
-perhaps because of a badly implemented driver? A PCMCIA network card
-will also never achieve 100mbit/s because of the way the bus is
-designed - again, how do we calculate the idle time?
-
-The physical link bandwidth may be ill defined in case of not-quite-real
-network devices like PPP over Ethernet or PPTP over TCP/IP. The effective
-bandwidth in that case is probably determined by the efficiency of pipes
-to userspace - which not defined.
-
-During operations, the effective idletime is measured using an
-exponential weighted moving average (EWMA), which considers recent
-packets to be exponentially more important than past ones. The Unix
-loadaverage is calculated in the same way.
-
-The calculated idle time is subtracted from the EWMA measured one,
-the resulting number is called 'avgidle'. A perfectly loaded link has
-an avgidle of zero: packets arrive exactly at the calculated
-interval.
-
-An overloaded link has a negative avgidle and if it gets too negative,
-CBQ throttles and is then 'overlimit'.
-
-Conversely, an idle link might amass a huge avgidle, which would then
-allow infinite bandwidths after a few hours of silence. To prevent
-this, avgidle is capped at
-.B maxidle.
-
-If overlimit, in theory, the CBQ could throttle itself for exactly the
-amount of time that was calculated to pass between packets, and then
-pass one packet, and throttle again. Due to timer resolution constraints,
-this may not be feasible, see the
-.B minburst
-parameter below.
-
-.SH CLASSIFICATION
-Within the one CBQ instance many classes may exist. Each of these classes
-contains another qdisc, by default
-.BR tc-pfifo (8).
-
-When enqueueing a packet, CBQ starts at the root and uses various methods to
-determine which class should receive the data. If a verdict is reached, this
-process is repeated for the recipient class which might have further
-means of classifying traffic to its children, if any.
-
-CBQ has the following methods available to classify a packet to any child
-classes.
-.TP
-(i)
-.B skb->priority class encoding.
-Can be set from userspace by an application with the
-.B SO_PRIORITY
-setsockopt.
-The
-.B skb->priority class encoding
-only applies if the skb->priority holds a major:minor handle of an existing
-class within this qdisc.
-.TP
-(ii)
-tc filters attached to the class.
-.TP
-(iii)
-The defmap of a class, as set with the
-.B split & defmap
-parameters. The defmap may contain instructions for each possible Linux packet
-priority.
-
-.P
-Each class also has a
-.B level.
-Leaf nodes, attached to the bottom of the class hierarchy, have a level of 0.
-.SH CLASSIFICATION ALGORITHM
-
-Classification is a loop, which terminates when a leaf class is found. At any
-point the loop may jump to the fallback algorithm.
-
-The loop consists of the following steps:
-.TP
-(i)
-If the packet is generated locally and has a valid classid encoded within its
-.B skb->priority,
-choose it and terminate.
-
-.TP
-(ii)
-Consult the tc filters, if any, attached to this child. If these return
-a class which is not a leaf class, restart loop from the class returned.
-If it is a leaf, choose it and terminate.
-.TP
-(iii)
-If the tc filters did not return a class, but did return a classid,
-try to find a class with that id within this qdisc.
-Check if the found class is of a lower
-.B level
-than the current class. If so, and the returned class is not a leaf node,
-restart the loop at the found class. If it is a leaf node, terminate.
-If we found an upward reference to a higher level, enter the fallback
-algorithm.
-.TP
-(iv)
-If the tc filters did not return a class, nor a valid reference to one,
-consider the minor number of the reference to be the priority. Retrieve
-a class from the defmap of this class for the priority. If this did not
-contain a class, consult the defmap of this class for the
-.B BEST_EFFORT
-class. If this is an upward reference, or no
-.B BEST_EFFORT
-class was defined,
-enter the fallback algorithm. If a valid class was found, and it is not a
-leaf node, restart the loop at this class. If it is a leaf, choose it and
-terminate. If
-neither the priority distilled from the classid, nor the
-.B BEST_EFFORT
-priority yielded a class, enter the fallback algorithm.
-.P
-The fallback algorithm resides outside of the loop and is as follows.
-.TP
-(i)
-Consult the defmap of the class at which the jump to fallback occured. If
-the defmap contains a class for the
-.B
-priority
-of the class (which is related to the TOS field), choose this class and
-terminate.
-.TP
-(ii)
-Consult the map for a class for the
-.B BEST_EFFORT
-priority. If found, choose it, and terminate.
-.TP
-(iii)
-Choose the class at which break out to the fallback algorithm occured. Terminate.
-.P
-The packet is enqueued to the class which was chosen when either algorithm
-terminated. It is therefore possible for a packet to be enqueued *not* at a
-leaf node, but in the middle of the hierarchy.
-
-.SH LINK SHARING ALGORITHM
-When dequeuing for sending to the network device, CBQ decides which of its
-classes will be allowed to send. It does so with a Weighted Round Robin process
-in which each class with packets gets a chance to send in turn. The WRR process
-starts by asking the highest priority classes (lowest numerically -
-highest semantically) for packets, and will continue to do so until they
-have no more data to offer, in which case the process repeats for lower
-priorities.
-
-.B CERTAINTY ENDS HERE, ANK PLEASE HELP
-
-Each class is not allowed to send at length though - they can only dequeue a
-configurable amount of data during each round.
-
-If a class is about to go overlimit, and it is not
-.B bounded
-it will try to borrow avgidle from siblings that are not
-.B isolated.
-This process is repeated from the bottom upwards. If a class is unable
-to borrow enough avgidle to send a packet, it is throttled and not asked
-for a packet for enough time for the avgidle to increase above zero.
-
-.B I REALLY NEED HELP FIGURING THIS OUT. REST OF DOCUMENT IS PRETTY CERTAIN
-.B AGAIN.
-
-.SH QDISC
-The root qdisc of a CBQ class tree has the following parameters:
-
-.TP
-parent major:minor | root
-This mandatory parameter determines the place of the CBQ instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the CBQ can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional.
-.TP
-avpkt bytes
-For calculations, the average packet size must be known. It is silently capped
-at a minimum of 2/3 of the interface MTU. Mandatory.
-.TP
-bandwidth rate
-To determine the idle time, CBQ must know the bandwidth of your underlying
-physical interface, or parent qdisc. This is a vital parameter, more about it
-later. Mandatory.
-.TP
-cell
-The cell size determines he granularity of packet transmission time calculations. Has a sensible default.
-.TP
-mpu
-A zero sized packet may still take time to transmit. This value is the lower
-cap for packet transmission time calculations - packets smaller than this value
-are still deemed to have this size. Defaults to zero.
-.TP
-ewma log
-When CBQ needs to measure the average idle time, it does so using an
-Exponentially Weighted Moving Average which smoothes out measurements into
-a moving average. The EWMA LOG determines how much smoothing occurs. Defaults
-to 5. Lower values imply greater sensitivity. Must be between 0 and 31.
-.P
-A CBQ qdisc does not shape out of its own accord. It only needs to know certain
-parameters about the underlying link. Actual shaping is done in classes.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc
-and not to another class, minor can be omitted. Mandatory.
-.TP
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this
-class is going to have children.
-.TP
-weight weight
-When dequeuing to the interface, classes are tried for traffic in a
-round-robin fashion. Classes with a higher configured qdisc will generally
-have more traffic to offer during each round, so it makes sense to allow
-it to dequeue more traffic. All weights under a class are normalized, so
-only the ratios matter. Defaults to the configured rate, unless the priority
-of this class is maximal, in which case it is set to 1.
-.TP
-allot bytes
-Allot specifies how many bytes a qdisc can dequeue
-during each round of the process. This parameter is weighted using the
-renormalized class weight described above.
-
-.TP
-priority priority
-In the round-robin process, classes with the lowest priority field are tried
-for packets first. Mandatory.
-
-.TP
-rate rate
-Maximum rate this class and all its children combined can send at. Mandatory.
-
-.TP
-bandwidth rate
-This is different from the bandwidth specified when creating a CBQ disc. Only
-used to determine maxidle and offtime, which are only calculated when
-specifying maxburst or minburst. Mandatory if specifying maxburst or minburst.
-
-.TP
-maxburst
-This number of packets is used to calculate maxidle so that when
-avgidle is at maxidle, this number of average packets can be burst
-before avgidle drops to 0. Set it higher to be more tolerant of
-bursts. You can't set maxidle directly, only via this parameter.
-
-.TP
-minburst
-As mentioned before, CBQ needs to throttle in case of
-overlimit. The ideal solution is to do so for exactly the calculated
-idle time, and pass 1 packet. However, Unix kernels generally have a
-hard time scheduling events shorter than 10ms, so it is better to
-throttle for a longer period, and then pass minburst packets in one
-go, and then sleep minburst times longer.
-
-The time to wait is called the offtime. Higher values of minburst lead
-to more accurate shaping in the long term, but to bigger bursts at
-millisecond timescales.
-
-.TP
-minidle
-If avgidle is below 0, we are overlimits and need to wait until
-avgidle will be big enough to send one packet. To prevent a sudden
-burst from shutting down the link for a prolonged period of time,
-avgidle is reset to minidle if it gets too low.
-
-Minidle is specified in negative microseconds, so 10 means that
-avgidle is capped at -10us.
-
-.TP
-bounded
-Signifies that this class will not borrow bandwidth from its siblings.
-.TP
-isolated
-Means that this class will not borrow bandwidth to its siblings
-
-.TP
-split major:minor & defmap bitmap[/bitmap]
-If consulting filters attached to a class did not give a verdict,
-CBQ can also classify based on the packet's priority. There are 16
-priorities available, numbered from 0 to 15.
-
-The defmap specifies which priorities this class wants to receive,
-specified as a bitmap. The Least Significant Bit corresponds to priority
-zero. The
-.B split
-parameter tells CBQ at which class the decision must be made, which should
-be a (grand)parent of the class you are adding.
-
-As an example, 'tc class add ... classid 10:1 cbq .. split 10:0 defmap c0'
-configures class 10:0 to send packets with priorities 6 and 7 to 10:1.
-
-The complimentary configuration would then
-be: 'tc class add ... classid 10:2 cbq ... split 10:0 defmap 3f'
-Which would send all packets 0, 1, 2, 3, 4 and 5 to 10:1.
-.TP
-estimator interval timeconstant
-CBQ can measure how much bandwidth each class is using, which tc filters
-can use to classify packets with. In order to determine the bandwidth
-it uses a very simple estimator that measures once every
-.B interval
-microseconds how much traffic has passed. This again is a EWMA, for which
-the time constant can be specified, also in microseconds. The
-.B time constant
-corresponds to the sluggishness of the measurement or, conversely, to the
-sensitivity of the average to short bursts. Higher values mean less
-sensitivity.
-
-
-
-.SH SOURCES
-.TP
-o
-Sally Floyd and Van Jacobson, "Link-sharing and Resource
-Management Models for Packet Networks",
-IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
-
-.TP
-o
-Sally Floyd, "Notes on CBQ and Guarantee Service", 1995
-
-.TP
-o
-Sally Floyd, "Notes on Class-Based Queueing: Setting
-Parameters", 1996
-
-.TP
-o
-Sally Floyd and Michael Speer, "Experimental Results
-for Class-Based Queueing", 1998, not published.
-
-
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH CBQ 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-CBQ \- Class Based Queueing
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B ( parent
-classid
-.B | root) [ handle
-major:
-.B ] cbq [ allot
-bytes
-.B ] avpkt
-bytes
-.B bandwidth
-rate
-.B [ cell
-bytes
-.B ] [ ewma
-log
-.B ] [ mpu
-bytes
-.B ]
-
-.B tc class ... dev
-dev
-.B parent
-major:[minor]
-.B [ classid
-major:minor
-.B ] cbq allot
-bytes
-.B [ bandwidth
-rate
-.B ] [ rate
-rate
-.B ] prio
-priority
-.B [ weight
-weight
-.B ] [ minburst
-packets
-.B ] [ maxburst
-packets
-.B ] [ ewma
-log
-.B ] [ cell
-bytes
-.B ] avpkt
-bytes
-.B [ mpu
-bytes
-.B ] [ bounded isolated ] [ split
-handle
-.B & defmap
-defmap
-.B ] [ estimator
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-Class Based Queueing is a classful qdisc that implements a rich
-linksharing hierarchy of classes. It contains shaping elements as
-well as prioritizing capabilities. Shaping is performed using link
-idle time calculations based on the timing of dequeue events and
-underlying link bandwidth.
-
-.SH SHAPING ALGORITHM
-When shaping a 10mbit/s connection to 1mbit/s, the link will
-be idle 90% of the time. If it isn't, it needs to be throttled so that it
-IS idle 90% of the time.
-
-During operations, the effective idletime is measured using an
-exponential weighted moving average (EWMA), which considers recent
-packets to be exponentially more important than past ones. The Unix
-loadaverage is calculated in the same way.
-
-The calculated idle time is subtracted from the EWMA measured one,
-the resulting number is called 'avgidle'. A perfectly loaded link has
-an avgidle of zero: packets arrive exactly at the calculated
-interval.
-
-An overloaded link has a negative avgidle and if it gets too negative,
-CBQ throttles and is then 'overlimit'.
-
-Conversely, an idle link might amass a huge avgidle, which would then
-allow infinite bandwidths after a few hours of silence. To prevent
-this, avgidle is capped at
-.B maxidle.
-
-If overlimit, in theory, the CBQ could throttle itself for exactly the
-amount of time that was calculated to pass between packets, and then
-pass one packet, and throttle again. Due to timer resolution constraints,
-this may not be feasible, see the
-.B minburst
-parameter below.
-
-.SH CLASSIFICATION
-Within the one CBQ instance many classes may exist. Each of these classes
-contains another qdisc, by default
-.BR tc-pfifo (8).
-
-When enqueueing a packet, CBQ starts at the root and uses various methods to
-determine which class should receive the data.
-
-In the absence of uncommon configuration options, the process is rather easy.
-At each node we look for an instruction, and then go to the class the
-instruction refers us to. If the class found is a barren leaf-node (without
-children), we enqueue the packet there. If it is not yet a leaf node, we do
-the whole thing over again starting from that node.
-
-The following actions are performed, in order at each node we visit, until one
-sends us to another node, or terminates the process.
-.TP
-(i)
-Consult filters attached to the class. If sent to a leafnode, we are done.
-Otherwise, restart.
-.TP
-(ii)
-Consult the defmap for the priority assigned to this packet, which depends
-on the TOS bits. Check if the referral is leafless, otherwise restart.
-.TP
-(iii)
-Ask the defmap for instructions for the 'best effort' priority. Check the
-answer for leafness, otherwise restart.
-.TP
-(iv)
-If none of the above returned with an instruction, enqueue at this node.
-.P
-This algorithm makes sure that a packet always ends up somewhere, even while
-you are busy building your configuration.
-
-For more details, see
-.BR tc-cbq-details(8).
-
-.SH LINK SHARING ALGORITHM
-When dequeuing for sending to the network device, CBQ decides which of its
-classes will be allowed to send. It does so with a Weighted Round Robin process
-in which each class with packets gets a chance to send in turn. The WRR process
-starts by asking the highest priority classes (lowest numerically -
-highest semantically) for packets, and will continue to do so until they
-have no more data to offer, in which case the process repeats for lower
-priorities.
-
-Classes by default borrow bandwidth from their siblings. A class can be
-prevented from doing so by declaring it 'bounded'. A class can also indicate
-its unwillingness to lend out bandwidth by being 'isolated'.
-
-.SH QDISC
-The root of a CBQ qdisc class tree has the following parameters:
-
-.TP
-parent major:minor | root
-This mandatory parameter determines the place of the CBQ instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the CBQ can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional, but very useful if classes
-will be generated within this qdisc.
-.TP
-allot bytes
-This allotment is the 'chunkiness' of link sharing and is used for determining packet
-transmission time tables. The qdisc allot differs slightly from the class allot discussed
-below. Optional. Defaults to a reasonable value, related to avpkt.
-.TP
-avpkt bytes
-The average size of a packet is needed for calculating maxidle, and is also used
-for making sure 'allot' has a safe value. Mandatory.
-.TP
-bandwidth rate
-To determine the idle time, CBQ must know the bandwidth of your underlying
-physical interface, or parent qdisc. This is a vital parameter, more about it
-later. Mandatory.
-.TP
-cell
-The cell size determines he granularity of packet transmission time calculations. Has a sensible default.
-.TP
-mpu
-A zero sized packet may still take time to transmit. This value is the lower
-cap for packet transmission time calculations - packets smaller than this value
-are still deemed to have this size. Defaults to zero.
-.TP
-ewma log
-When CBQ needs to measure the average idle time, it does so using an
-Exponentially Weighted Moving Average which smoothes out measurements into
-a moving average. The EWMA LOG determines how much smoothing occurs. Lower
-values imply greater sensitivity. Must be between 0 and 31. Defaults
-to 5.
-.P
-A CBQ qdisc does not shape out of its own accord. It only needs to know certain
-parameters about the underlying link. Actual shaping is done in classes.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc
-and not to another class, minor can be omitted. Mandatory.
-.TP
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this
-class is going to have children.
-.TP
-weight weight
-When dequeuing to the interface, classes are tried for traffic in a
-round-robin fashion. Classes with a higher configured qdisc will generally
-have more traffic to offer during each round, so it makes sense to allow
-it to dequeue more traffic. All weights under a class are normalized, so
-only the ratios matter. Defaults to the configured rate, unless the priority
-of this class is maximal, in which case it is set to 1.
-.TP
-allot bytes
-Allot specifies how many bytes a qdisc can dequeue
-during each round of the process. This parameter is weighted using the
-renormalized class weight described above. Silently capped at a minimum of
-3/2 avpkt. Mandatory.
-
-.TP
-prio priority
-In the round-robin process, classes with the lowest priority field are tried
-for packets first. Mandatory.
-
-.TP
-avpkt
-See the QDISC section.
-
-.TP
-rate rate
-Maximum rate this class and all its children combined can send at. Mandatory.
-
-.TP
-bandwidth rate
-This is different from the bandwidth specified when creating a CBQ disc! Only
-used to determine maxidle and offtime, which are only calculated when
-specifying maxburst or minburst. Mandatory if specifying maxburst or minburst.
-
-.TP
-maxburst
-This number of packets is used to calculate maxidle so that when
-avgidle is at maxidle, this number of average packets can be burst
-before avgidle drops to 0. Set it higher to be more tolerant of
-bursts. You can't set maxidle directly, only via this parameter.
-
-.TP
-minburst
-As mentioned before, CBQ needs to throttle in case of
-overlimit. The ideal solution is to do so for exactly the calculated
-idle time, and pass 1 packet. However, Unix kernels generally have a
-hard time scheduling events shorter than 10ms, so it is better to
-throttle for a longer period, and then pass minburst packets in one
-go, and then sleep minburst times longer.
-
-The time to wait is called the offtime. Higher values of minburst lead
-to more accurate shaping in the long term, but to bigger bursts at
-millisecond timescales. Optional.
-
-.TP
-minidle
-If avgidle is below 0, we are overlimits and need to wait until
-avgidle will be big enough to send one packet. To prevent a sudden
-burst from shutting down the link for a prolonged period of time,
-avgidle is reset to minidle if it gets too low.
-
-Minidle is specified in negative microseconds, so 10 means that
-avgidle is capped at -10us. Optional.
-
-.TP
-bounded
-Signifies that this class will not borrow bandwidth from its siblings.
-.TP
-isolated
-Means that this class will not borrow bandwidth to its siblings
-
-.TP
-split major:minor & defmap bitmap[/bitmap]
-If consulting filters attached to a class did not give a verdict,
-CBQ can also classify based on the packet's priority. There are 16
-priorities available, numbered from 0 to 15.
-
-The defmap specifies which priorities this class wants to receive,
-specified as a bitmap. The Least Significant Bit corresponds to priority
-zero. The
-.B split
-parameter tells CBQ at which class the decision must be made, which should
-be a (grand)parent of the class you are adding.
-
-As an example, 'tc class add ... classid 10:1 cbq .. split 10:0 defmap c0'
-configures class 10:0 to send packets with priorities 6 and 7 to 10:1.
-
-The complimentary configuration would then
-be: 'tc class add ... classid 10:2 cbq ... split 10:0 defmap 3f'
-Which would send all packets 0, 1, 2, 3, 4 and 5 to 10:1.
-.TP
-estimator interval timeconstant
-CBQ can measure how much bandwidth each class is using, which tc filters
-can use to classify packets with. In order to determine the bandwidth
-it uses a very simple estimator that measures once every
-.B interval
-microseconds how much traffic has passed. This again is a EWMA, for which
-the time constant can be specified, also in microseconds. The
-.B time constant
-corresponds to the sluggishness of the measurement or, conversely, to the
-sensitivity of the average to short bursts. Higher values mean less
-sensitivity.
-
-.SH BUGS
-The actual bandwidth of the underlying link may not be known, for example
-in the case of PPoE or PPTP connections which in fact may send over a
-pipe, instead of over a physical device. CBQ is quite resilient to major
-errors in the configured bandwidth, probably a the cost of coarser shaping.
-
-Default kernels rely on coarse timing information for making decisions. These
-may make shaping precise in the long term, but inaccurate on second long scales.
-
-See
-.BR tc-cbq-details(8)
-for hints on how to improve this.
-
-.SH SOURCES
-.TP
-o
-Sally Floyd and Van Jacobson, "Link-sharing and Resource
-Management Models for Packet Networks",
-IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
-
-.TP
-o
-Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
-
-.TP
-o
-Sally Floyd, "Notes on Class-Based Queueing: Setting
-Parameters", 1996
-
-.TP
-o
-Sally Floyd and Michael Speer, "Experimental Results
-for Class-Based Queueing", 1998, not published.
-
-
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH HTB 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-HTB \- Hierarchy Token Bucket
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B ( parent
-classid
-.B | root) [ handle
-major:
-.B ] htb [ default
-minor-id
-.B ]
-
-.B tc class ... dev
-dev
-.B parent
-major:[minor]
-.B [ classid
-major:minor
-.B ] htb rate
-rate
-.B [ ceil
-rate
-.B ] burst
-bytes
-.B [ cburst
-bytes
-.B ] [ prio
-priority
-.B ]
-
-.SH DESCRIPTION
-HTB is meant as a more understandable and intuitive replacement for
-the CBQ qdisc in Linux. Both CBQ and HTB help you to control the use
-of the outbound bandwidth on a given link. Both allow you to use one
-physical link to simulate several slower links and to send different
-kinds of traffic on different simulated links. In both cases, you have
-to specify how to divide the physical link into simulated links and
-how to decide which simulated link to use for a given packet to be sent.
-
-Unlike CBQ, HTB shapes traffic based on the Token Bucket Filter algorithm
-which does not depend on interface characteristics and so does not need to
-know the underlying bandwidth of the outgoing interface.
-
-.SH SHAPING ALGORITHM
-Shaping works as documented in
-.B tc-tbf (8).
-
-.SH CLASSIFICATION
-Within the one HRB instance many classes may exist. Each of these classes
-contains another qdisc, by default
-.BR tc-pfifo (8).
-
-When enqueueing a packet, HTB starts at the root and uses various methods to
-determine which class should receive the data.
-
-In the absence of uncommon configuration options, the process is rather easy.
-At each node we look for an instruction, and then go to the class the
-instruction refers us to. If the class found is a barren leaf-node (without
-children), we enqueue the packet there. If it is not yet a leaf node, we do
-the whole thing over again starting from that node.
-
-The following actions are performed, in order at each node we visit, until one
-sends us to another node, or terminates the process.
-.TP
-(i)
-Consult filters attached to the class. If sent to a leafnode, we are done.
-Otherwise, restart.
-.TP
-(ii)
-If none of the above returned with an instruction, enqueue at this node.
-.P
-This algorithm makes sure that a packet always ends up somewhere, even while
-you are busy building your configuration.
-
-.SH LINK SHARING ALGORITHM
-FIXME
-
-.SH QDISC
-The root of a HTB qdisc class tree has the following parameters:
-
-.TP
-parent major:minor | root
-This mandatory parameter determines the place of the HTB instance, either at the
-.B root
-of an interface or within an existing class.
-.TP
-handle major:
-Like all other qdiscs, the HTB can be assigned a handle. Should consist only
-of a major number, followed by a colon. Optional, but very useful if classes
-will be generated within this qdisc.
-.TP
-default minor-id
-Unclassified traffic gets sent to the class with this minor-id.
-
-.SH CLASSES
-Classes have a host of parameters to configure their operation.
-
-.TP
-parent major:minor
-Place of this class within the hierarchy. If attached directly to a qdisc
-and not to another class, minor can be omitted. Mandatory.
-.TP
-classid major:minor
-Like qdiscs, classes can be named. The major number must be equal to the
-major number of the qdisc to which it belongs. Optional, but needed if this
-class is going to have children.
-.TP
-prio priority
-In the round-robin process, classes with the lowest priority field are tried
-for packets first. Mandatory.
-
-.TP
-rate rate
-Maximum rate this class and all its children are guaranteed. Mandatory.
-
-.TP
-ceil rate
-Maximum rate at which a class can send, if its parent has bandwidth to spare.
-Defaults to the configured rate, which implies no borrowing
-
-.TP
-burst bytes
-Amount of bytes that can be burst at
-.B ceil
-speed, in excess of the configured
-.B rate.
-Should be at least as high as the highest burst of all children.
-
-.TP
-cburst bytes
-Amount of bytes that can be burst at 'infinite' speed, in other words, as fast
-as the interface can transmit them. For perfect evening out, should be equal to at most one average
-packet. Should be at least as high as the highest cburst of all children.
-
-.SH NOTES
-Due to Unix timing constraints, the maximum ceil rate is not infinite and may in fact be quite low. On Intel,
-there are 100 timer events per second, the maximum rate is that rate at which 'burst' bytes are sent each timer tick.
-From this, the mininum burst size for a specified rate can be calculated. For i386, a 10mbit rate requires a 12 kilobyte
-burst as 100*12kb*8 equals 10mbit.
-
-.SH SEE ALSO
-.BR tc (8)
-.P
-HTB website: http://luxik.cdi.cz/~devik/qos/htb/
-.SH AUTHOR
-Martin Devera <devik@cdi.cz>. This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH PBFIFO 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-pfifo \- Packet limited First In, First Out queue
-.P
-bfifo \- Byte limited First In, First Out queue
-
-.SH SYNOPSIS
-.B tc qdisc ... add pfifo
-.B [ limit
-packets
-.B ]
-.P
-.B tc qdisc ... add bfifo
-.B [ limit
-bytes
-.B ]
-
-.SH DESCRIPTION
-The pfifo and bfifo qdiscs are unadorned First In, First Out queues. They are the
-simplest queues possible and therefore have no overhead.
-.B pfifo
-constrains the queue size as measured in packets.
-.B bfifo
-does so as measured in bytes.
-
-Like all non-default qdiscs, they maintain statistics. This might be a reason to prefer
-pfifo or bfifo over the default.
-
-.SH ALGORITHM
-A list of packets is maintained, when a packet is enqueued it gets inserted at the tail of
-a list. When a packet needs to be sent out to the network, it is taken from the head of the list.
-
-If the list is too long, no further packets are allowed on. This is called 'tail drop'.
-
-.SH PARAMETERS
-.TP
-limit
-Maximum queue size. Specified in bytes for bfifo, in packets for pfifo. For pfifo, defaults
-to the interface txqueuelen, as specified with
-.BR ifconfig (8)
-or
-.BR ip (8).
-
-For bfifo, it defaults to the txqueuelen multiplied by the interface MTU.
-
-.SH OUTPUT
-The output of
-.B tc -s qdisc ls
-contains the limit, either in packets or in bytes, and the number of bytes
-and packets actually sent. An unsent and dropped packet only appears between braces
-and is not counted as 'Sent'.
-
-In this example, the queue length is 100 packets, 45894 bytes were sent over 681 packets.
-No packets were dropped, and as the pfifo queue does not slow down packets, there were also no
-overlimits:
-.P
-.nf
-# tc -s qdisc ls dev eth0
-qdisc pfifo 8001: dev eth0 limit 100p
- Sent 45894 bytes 681 pkts (dropped 0, overlimits 0)
-.fi
-
-If a backlog occurs, this is displayed as well.
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>
-
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH PFIFO_FAST 8 "10 January 2002" "iproute2" "Linux"
-.SH NAME
-pfifo_fast \- three-band first in, first out queue
-
-.SH DESCRIPTION
-pfifo_fast is the default qdisc of each interface.
-
-Whenever an interface is created, the pfifo_fast qdisc is automatically used
-as a queue. If another qdisc is attached, it preempts the default
-pfifo_fast, which automatically returns to function when an existing qdisc
-is detached.
-
-In this sense this qdisc is magic, and unlike other qdiscs.
-
-.SH ALGORITHM
-The algorithm is very similar to that of the classful
-.BR tc-prio (8)
-qdisc.
-.B pfifo_fast
-is like three
-.BR tc-pfifo (8)
-queues side by side, where packets can be enqueued in any of the three bands
-based on their Type of Service bits or assigned priority.
-
-Not all three bands are dequeued simultaneously - as long as lower bands
-have traffic, higher bands are never dequeued. This can be used to
-prioritize interactive traffic or penalize 'lowest cost' traffic.
-
-Each band can be txqueuelen packets long, as configured with
-.BR ifconfig (8)
-or
-.BR ip (8).
-Additional packets coming in are not enqueued but are instead dropped.
-
-See
-.BR tc-prio (8)
-for complete details on how TOS bits are translated into bands.
-.SH PARAMETERS
-.TP
-txqueuelen
-The length of the three bands depends on the interface txqueuelen, as
-specified with
-.BR ifconfig (8)
-or
-.BR ip (8).
-
-.SH BUGS
-Does not maintain statistics and does not show up in tc qdisc ls. This is because
-it is the automatic default in the absence of a configured qdisc.
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>
-
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH PRIO 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-PRIO \- Priority qdisc
-.SH SYNOPSIS
-.B tc qdisc ... dev
-dev
-.B ( parent
-classid
-.B | root) [ handle
-major:
-.B ] prio [ bands
-bands
-.B ] [ priomap
-band,band,band...
-.B ] [ estimator
-interval timeconstant
-.B ]
-
-.SH DESCRIPTION
-The PRIO qdisc is a simple classful queueing discipline that contains
-an arbitrary number of classes of differing priority. The classes are
-dequeued in numerical descending order of priority. PRIO is a scheduler
-and never delays packets - it is a work-conserving qdisc, though the qdiscs
-contained in the classes may not be.
-
-Very useful for lowering latency when there is no need for slowing down
-traffic.
-
-.SH ALGORITHM
-On creation with 'tc qdisc add', a fixed number of bands is created. Each
-band is a class, although is not possible to add classes with 'tc qdisc
-add', the number of bands to be created must instead be specified on the
-commandline attaching PRIO to its root.
-
-When dequeueing, band 0 is tried first and only if it did not deliver a
-packet does PRIO try band 1, and so onwards. Maximum reliability packets
-should therefore go to band 0, minimum delay to band 1 and the rest to band
-2.
-
-As the PRIO qdisc itself will have minor number 0, band 0 is actually
-major:1, band 1 is major:2, etc. For major, substitute the major number
-assigned to the qdisc on 'tc qdisc add' with the
-.B handle
-parameter.
-
-.SH CLASSIFICATION
-Three methods are available to PRIO to determine in which band a packet will
-be enqueued.
-.TP
-From userspace
-A process with sufficient privileges can encode the destination class
-directly with SO_PRIORITY, see
-.BR tc(7).
-.TP
-with a tc filter
-A tc filter attached to the root qdisc can point traffic directly to a class
-.TP
-with the priomap
-Based on the packet priority, which in turn is derived from the Type of
-Service assigned to the packet.
-.P
-Only the priomap is specific to this qdisc.
-.SH QDISC PARAMETERS
-.TP
-bands
-Number of bands. If changed from the default of 3,
-.B priomap
-must be updated as well.
-.TP
-priomap
-The priomap maps the priority of
-a packet to a class. The priority can either be set directly from userspace,
-or be derived from the Type of Service of the packet.
-
-Determines how packet priorities, as assigned by the kernel, map to
-bands. Mapping occurs based on the TOS octet of the packet, which looks like
-this:
-
-.nf
-0 1 2 3 4 5 6 7
-+---+---+---+---+---+---+---+---+
-| | | |
-|PRECEDENCE | TOS |MBZ|
-| | | |
-+---+---+---+---+---+---+---+---+
-.fi
-
-The four TOS bits (the 'TOS field') are defined as:
-
-.nf
-Binary Decimcal Meaning
------------------------------------------
-1000 8 Minimize delay (md)
-0100 4 Maximize throughput (mt)
-0010 2 Maximize reliability (mr)
-0001 1 Minimize monetary cost (mmc)
-0000 0 Normal Service
-.fi
-
-As there is 1 bit to the right of these four bits, the actual value of the
-TOS field is double the value of the TOS bits. Tcpdump -v -v shows you the
-value of the entire TOS field, not just the four bits. It is the value you
-see in the first column of this table:
-
-.nf
-TOS Bits Means Linux Priority Band
-------------------------------------------------------------
-0x0 0 Normal Service 0 Best Effort 1
-0x2 1 Minimize Monetary Cost 1 Filler 2
-0x4 2 Maximize Reliability 0 Best Effort 1
-0x6 3 mmc+mr 0 Best Effort 1
-0x8 4 Maximize Throughput 2 Bulk 2
-0xa 5 mmc+mt 2 Bulk 2
-0xc 6 mr+mt 2 Bulk 2
-0xe 7 mmc+mr+mt 2 Bulk 2
-0x10 8 Minimize Delay 6 Interactive 0
-0x12 9 mmc+md 6 Interactive 0
-0x14 10 mr+md 6 Interactive 0
-0x16 11 mmc+mr+md 6 Interactive 0
-0x18 12 mt+md 4 Int. Bulk 1
-0x1a 13 mmc+mt+md 4 Int. Bulk 1
-0x1c 14 mr+mt+md 4 Int. Bulk 1
-0x1e 15 mmc+mr+mt+md 4 Int. Bulk 1
-.fi
-
-The second column contains the value of the relevant
-four TOS bits, followed by their translated meaning. For example, 15 stands
-for a packet wanting Minimal Montetary Cost, Maximum Reliability, Maximum
-Throughput AND Minimum Delay.
-
-The fourth column lists the way the Linux kernel interprets the TOS bits, by
-showing to which Priority they are mapped.
-
-The last column shows the result of the default priomap. On the commandline,
-the default priomap looks like this:
-
- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
-
-This means that priority 4, for example, gets mapped to band number 1.
-The priomap also allows you to list higher priorities (> 7) which do not
-correspond to TOS mappings, but which are set by other means.
-
-This table from RFC 1349 (read it for more details) explains how
-applications might very well set their TOS bits:
-
-.nf
-TELNET 1000 (minimize delay)
-FTP
- Control 1000 (minimize delay)
- Data 0100 (maximize throughput)
-
-TFTP 1000 (minimize delay)
-
-SMTP
- Command phase 1000 (minimize delay)
- DATA phase 0100 (maximize throughput)
-
-Domain Name Service
- UDP Query 1000 (minimize delay)
- TCP Query 0000
- Zone Transfer 0100 (maximize throughput)
-
-NNTP 0001 (minimize monetary cost)
-
-ICMP
- Errors 0000
- Requests 0000 (mostly)
- Responses <same as request> (mostly)
-.fi
-
-
-.SH CLASSES
-PRIO classes cannot be configured further - they are automatically created
-when the PRIO qdisc is attached. Each class however can contain yet a
-further qdisc.
-
-.SH BUGS
-Large amounts of traffic in the lower bands can cause starvation of higher
-bands. Can be prevented by attaching a shaper (for example,
-.BR tc-tbf(8)
-to these bands to make sure they cannot dominate the link.
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>, J Hadi Salim
-<hadi@cyberus.ca>. This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH RED 8 "13 December 2001" "iproute2" "Linux"
-.SH NAME
-red \- Random Early Detection
-.SH SYNOPSIS
-.B tc qdisc ... red
-.B limit
-bytes
-.B min
-bytes
-.B max
-bytes
-.B avpkt
-bytes
-.B burst
-packets
-.B [ ecn ] [ bandwidth
-rate
-.B ] probability
-chance
-
-.SH DESCRIPTION
-Random Early Detection is a classless qdisc which manages its queue size
-smartly. Regular queues simply drop packets from the tail when they are
-full, which may not be the optimal behaviour. RED also performs tail drop,
-but does so in a more gradual way.
-
-Once the queue hits a certain average length, packets enqueued have a
-configurable chance of being marked (which may mean dropped). This chance
-increases linearly up to a point called the
-.B max
-average queue length, although the queue might get bigger.
-
-This has a host of benefits over simple taildrop, while not being processor
-intensive. It prevents synchronous retransmits after a burst in traffic,
-which cause further retransmits, etc.
-
-The goal is the have a small queue size, which is good for interactivity
-while not disturbing TCP/IP traffic with too many sudden drops after a burst
-of traffic.
-
-Depending on if ECN is configured, marking either means dropping or
-purely marking a packet as overlimit.
-.SH ALGORITHM
-The average queue size is used for determining the marking
-probability. This is calculated using an Exponential Weighted Moving
-Average, which can be more or less sensitive to bursts.
-
-When the average queue size is below
-.B min
-bytes, no packet will ever be marked. When it exceeds
-.B min,
-the probability of doing so climbs linearly up
-to
-.B probability,
-until the average queue size hits
-.B max
-bytes. Because
-.B probability
-is normally not set to 100%, the queue size might
-conceivably rise above
-.B max
-bytes, so the
-.B limit
-parameter is provided to set a hard maximum for the size of the queue.
-
-.SH PARAMETERS
-.TP
-min
-Average queue size at which marking becomes a possibility.
-.TP
-max
-At this average queue size, the marking probability is maximal. Should be at
-least twice
-.B min
-to prevent synchronous retransmits, higher for low
-.B min.
-.TP
-probability
-Maximum probability for marking, specified as a floating point
-number from 0.0 to 1.0. Suggested values are 0.01 or 0.02 (1 or 2%,
-respectively).
-.TP
-limit
-Hard limit on the real (not average) queue size in bytes. Further packets
-are dropped. Should be set higher than max+burst. It is advised to set this
-a few times higher than
-.B max.
-.TP
-burst
-Used for determining how fast the average queue size is influenced by the
-real queue size. Larger values make the calculation more sluggish, allowing
-longer bursts of traffic before marking starts. Real life experiments
-support the following guideline: (min+min+max)/(3*avpkt).
-.TP
-avpkt
-Specified in bytes. Used with burst to determine the time constant for
-average queue size calculations. 1000 is a good value.
-.TP
-bandwidth
-This rate is used for calculating the average queue size after some
-idle time. Should be set to the bandwidth of your interface. Does not mean
-that RED will shape for you! Optional.
-.TP
-ecn
-As mentioned before, RED can either 'mark' or 'drop'. Explicit Congestion
-Notification allows RED to notify remote hosts that their rate exceeds the
-amount of bandwidth available. Non-ECN capable hosts can only be notified by
-dropping a packet. If this parameter is specified, packets which indicate
-that their hosts honor ECN will only be marked and not dropped, unless the
-queue size hits
-.B limit
-bytes. Needs a tc binary with RED support compiled in. Recommended.
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH SOURCES
-.TP
-o
-Floyd, S., and Jacobson, V., Random Early Detection gateways for
-Congestion Avoidance. http://www.aciri.org/floyd/papers/red/red.html
-.TP
-o
-Some changes to the algorithm by Alexey N. Kuznetsov.
-
-.SH AUTHORS
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>, Alexey Makarenko
-<makar@phoenix.kharkov.ua>, J Hadi Salim <hadi@nortelnetworks.com>.
-This manpage maintained by bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH TC 8 "8 December 2001" "iproute2" "Linux"
-.SH NAME
-sfq \- Stochastic Fairness Queueing
-.SH SYNOPSIS
-.B tc qdisc ... perturb
-seconds
-.B quantum
-bytes
-
-.SH DESCRIPTION
-
-Stochastic Fairness Queueing is a classless queueing discipline available for
-traffic control with the
-.BR tc (8)
-command.
-
-SFQ does not shape traffic but only schedules the transmission of packets, based on 'flows'.
-The goal is to ensure fairness so that each flow is able to send data in turn, thus preventing
-any single flow from drowning out the rest.
-
-This may in fact have some effect in mitigating a Denial of Service attempt.
-
-SFQ is work-conserving and therefore always delivers a packet if it has one available.
-.SH ALGORITHM
-On enqueueing, each packet is assigned to a hash bucket, based on
-.TP
-(i)
-Source address
-.TP
-(ii)
-Destination address
-.TP
-(iii)
-Source port
-.P
-If these are available. SFQ knows about ipv4 and ipv6 and also UDP, TCP and ESP.
-Packets with other protocols are hashed based on the 32bits representation of their
-destination and the socket they belong to. A flow corresponds mostly to a TCP/IP
-connection.
-
-Each of these buckets should represent a unique flow. Because multiple flows may
-get hashed to the same bucket, the hashing algorithm is perturbed at configurable
-intervals so that the unfairness lasts only for a short while. Perturbation may
-however cause some inadvertent packet reordering to occur.
-
-When dequeuing, each hashbucket with data is queried in a round robin fashion.
-
-The compile time maximum length of the SFQ is 128 packets, which can be spread over
-at most 128 buckets of 1024 available. In case of overflow, tail-drop is performed
-on the fullest bucket, thus maintaining fairness.
-
-.SH PARAMETERS
-.TP
-perturb
-Interval in seconds for queue algorithm perturbation. Defaults to 0, which means that
-no perturbation occurs. Do not set too low for each perturbation may cause some packet
-reordering. Advised value: 10
-.TP
-quantum
-Amount of bytes a flow is allowed to dequeue during a round of the round robin process.
-Defaults to the MTU of the interface which is also the advised value and the minimum value.
-
-.SH EXAMPLE & USAGE
-
-To attach to device ppp0:
-.P
-# tc qdisc add dev ppp0 root sfq perturb 10
-.P
-Please note that SFQ, like all non-shaping (work-conserving) qdiscs, is only useful
-if it owns the queue.
-This is the case when the link speed equals the actually available bandwidth. This holds
-for regular phone modems, ISDN connections and direct non-switched ethernet links.
-.P
-Most often, cable modems and DSL devices do not fall into this category. The same holds
-for when connected to a switch and trying to send data to a congested segment also
-connected to the switch.
-.P
-In this case, the effective queue does not reside within Linux and is therefore not
-available for scheduling.
-.P
-Embed SFQ in a classful qdisc to make sure it owns the queue.
-
-.SH SOURCE
-.TP
-o
-Paul E. McKenney "Stochastic Fairness Queuing",
-IEEE INFOCOMM'90 Proceedings, San Francisco, 1990.
-
-.TP
-o
-Paul E. McKenney "Stochastic Fairness Queuing",
-"Interworking: Research and Experience", v.2, 1991, p.113-131.
-
-.TP
-o
-See also:
-M. Shreedhar and George Varghese "Efficient Fair
-Queuing using Deficit Round Robin", Proc. SIGCOMM 95.
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH TC 8 "13 December 2001" "iproute2" "Linux"
-.SH NAME
-tbf \- Token Bucket Filter
-.SH SYNOPSIS
-.B tc qdisc ... tbf rate
-rate
-.B burst
-bytes/cell
-.B ( latency
-ms
-.B | limit
-bytes
-.B ) [ mpu
-bytes
-.B [ peakrate
-rate
-.B mtu
-bytes/cell
-.B ] ]
-.P
-burst is also known as buffer and maxburst. mtu is also known as minburst.
-.SH DESCRIPTION
-
-The Token Bucket Filter is a classless queueing discipline available for
-traffic control with the
-.BR tc (8)
-command.
-
-TBF is a pure shaper and never schedules traffic. It is non-work-conserving and may throttle
-itself, although packets are available, to ensure that the configured rate is not exceeded.
-On all platforms except for Alpha,
-it is able to shape up to 1mbit/s of normal traffic with ideal minimal burstiness,
-sending out data exactly at the configured rates.
-
-Much higher rates are possible but at the cost of losing the minimal burstiness. In that
-case, data is on average dequeued at the configured rate but may be sent much faster at millisecond
-timescales. Because of further queues living in network adaptors, this is often not a problem.
-
-Kernels with a higher 'HZ' can achieve higher rates with perfect burstiness. On Alpha, HZ is ten
-times higher, leading to a 10mbit/s limit to perfection. These calculations hold for packets of on
-average 1000 bytes.
-
-.SH ALGORITHM
-As the name implies, traffic is filtered based on the expenditure of
-.B tokens.
-Tokens roughly correspond to bytes, with the additional constraint that each packet consumes
-some tokens, no matter how small it is. This reflects the fact that even a zero-sized packet occupies
-the link for some time.
-
-On creation, the TBF is stocked with tokens which correspond to the amount of traffic that can be burst
-in one go. Tokens arrive at a steady rate, until the bucket is full.
-
-If no tokens are available, packets are queued, up to a configured limit. The TBF now
-calculates the token deficit, and throttles until the first packet in the queue can be sent.
-
-If it is not acceptable to burst out packets at maximum speed, a peakrate can be configured
-to limit the speed at which the bucket empties. This peakrate is implemented as a second TBF
-with a very small bucket, so that it doesn't burst.
-
-To achieve perfection, the second bucket may contain only a single packet, which leads to
-the earlier mentioned 1mbit/s limit.
-
-This limit is caused by the fact that the kernel can only throttle for at minimum 1 'jiffy', which depends
-on HZ as 1/HZ. For perfect shaping, only a single packet can get sent per jiffy - for HZ=100, this means 100
-packets of on average 1000 bytes each, which roughly corresponds to 1mbit/s.
-
-.SH PARAMETERS
-See
-.BR tc (8)
-for how to specify the units of these values.
-.TP
-limit or latency
-Limit is the number of bytes that can be queued waiting for tokens to become
-available. You can also specify this the other way around by setting the
-latency parameter, which specifies the maximum amount of time a packet can
-sit in the TBF. The latter calculation takes into account the size of the
-bucket, the rate and possibly the peakrate (if set). These two parameters
-are mutually exclusive.
-.TP
-burst
-Also known as buffer or maxburst.
-Size of the bucket, in bytes. This is the maximum amount of bytes that tokens can be available for instantaneously.
-In general, larger shaping rates require a larger buffer. For 10mbit/s on Intel, you need at least 10kbyte buffer
-if you want to reach your configured rate!
-
-If your buffer is too small, packets may be dropped because more tokens arrive per timer tick than fit in your bucket.
-The minimum buffer size can be calculated by dividing the rate by HZ.
-
-Token usage calculations are performed using a table which by default has a resolution of 8 packets.
-This resolution can be changed by specifying the
-.B cell
-size with the burst. For example, to specify a 6000 byte buffer with a 16
-byte cell size, set a burst of 6000/16. You will probably never have to set
-this. Must be an integral power of 2.
-.TP
-mpu
-A zero-sized packet does not use zero bandwidth. For ethernet, no packet uses less than 64 bytes. The Minimum Packet Unit
-determines the minimal token usage (specified in bytes) for a packet. Defaults to zero.
-.TP
-rate
-The speed knob. See remarks above about limits! See
-.BR tc (8)
-for units.
-.PP
-Furthermore, if a peakrate is desired, the following parameters are available:
-
-.TP
-peakrate
-Maximum depletion rate of the bucket. Limited to 1mbit/s on Intel, 10mbit/s on Alpha. The peakrate does
-not need to be set, it is only necessary if perfect millisecond timescale shaping is required.
-
-.TP
-mtu/minburst
-Specifies the size of the peakrate bucket. For perfect accuracy, should be set to the MTU of the interface.
-If a peakrate is needed, but some burstiness is acceptable, this size can be raised. A 3000 byte minburst
-allows around 3mbit/s of peakrate, given 1000 byte packets.
-
-Like the regular burstsize you can also specify a
-.B cell
-size.
-.SH EXAMPLE & USAGE
-
-To attach a TBF with a sustained maximum rate of 0.5mbit/s, a peakrate of 1.0mbit/s,
-a 5kilobyte buffer, with a pre-bucket queue size limit calculated so the TBF causes
-at most 70ms of latency, with perfect peakrate behaviour, issue:
-.P
-# tc qdisc add dev eth0 root tbf rate 0.5mbit \\
- burst 5kb latency 70ms peakrate 1mbit \\
- minburst 1540
-
-.SH SEE ALSO
-.BR tc (8)
-
-.SH AUTHOR
-Alexey N. Kuznetsov, <kuznet@ms2.inr.ac.ru>. This manpage maintained by
-bert hubert <ahu@ds9a.nl>
-
-
+++ /dev/null
-.TH TC 8 "16 December 2001" "iproute2" "Linux"
-.SH NAME
-tc \- show / manipulate traffic control settings
-.SH SYNOPSIS
-.B tc qdisc [ add | change | replace | link ] dev
-DEV
-.B
-[ parent
-qdisc-id
-.B | root ]
-.B [ handle
-qdisc-id ] qdisc
-[ qdisc specific parameters ]
-.P
-
-.B tc class [ add | change | replace ] dev
-DEV
-.B parent
-qdisc-id
-.B [ classid
-class-id ] qdisc
-[ qdisc specific parameters ]
-.P
-
-.B tc filter [ add | change | replace ] dev
-DEV
-.B [ parent
-qdisc-id
-.B | root ] protocol
-protocol
-.B prio
-priority filtertype
-[ filtertype specific parameters ]
-.B flowid
-flow-id
-
-.B tc [-s | -d ] qdisc show [ dev
-DEV
-.B ]
-.P
-.B tc [-s | -d ] class show dev
-DEV
-.P
-.B tc filter show dev
-DEV
-
-.SH DESCRIPTION
-.B Tc
-is used to configure Traffic Control in the Linux kernel. Traffic Control consists
-of the following:
-
-.TP
-SHAPING
-When traffic is shaped, its rate of transmission is under control. Shaping may
-be more than lowering the available bandwidth - it is also used to smooth out
-bursts in traffic for better network behaviour. Shaping occurs on egress.
-
-.TP
-SCHEDULING
-By scheduling the transmission of packets it is possible to improve interactivity
-for traffic that needs it while still guaranteeing bandwidth to bulk transfers. Reordering
-is also called prioritizing, and happens only on egress.
-
-.TP
-POLICING
-Where shaping deals with transmission of traffic, policing pertains to traffic
-arriving. Policing thus occurs on ingress.
-
-.TP
-DROPPING
-Traffic exceeding a set bandwidth may also be dropped forthwith, both on
-ingress and on egress.
-
-.P
-Processing of traffic is controlled by three kinds of objects: qdiscs,
-classes and filters.
-
-.SH QDISCS
-.B qdisc
-is short for 'queueing discipline' and it is elementary to
-understanding traffic control. Whenever the kernel needs to send a
-packet to an interface, it is
-.B enqueued
-to the qdisc configured for that interface. Immediately afterwards, the kernel
-tries to get as many packets as possible from the qdisc, for giving them
-to the network adaptor driver.
-
-A simple QDISC is the 'pfifo' one, which does no processing at all and is a pure
-First In, First Out queue. It does however store traffic when the network interface
-can't handle it momentarily.
-
-.SH CLASSES
-Some qdiscs can contain classes, which contain further qdiscs - traffic may
-then be enqueued in any of the inner qdiscs, which are within the
-.B classes.
-When the kernel tries to dequeue a packet from such a
-.B classful qdisc
-it can come from any of the classes. A qdisc may for example prioritize
-certain kinds of traffic by trying to dequeue from certain classes
-before others.
-
-.SH FILTERS
-A
-.B filter
-is used by a classful qdisc to determine in which class a packet will
-be enqueued. Whenever traffic arrives at a class with subclasses, it needs
-to be classified. Various methods may be employed to do so, one of these
-are the filters. All filters attached to the class are called, until one of
-them returns with a verdict. If no verdict was made, other criteria may be
-available. This differs per qdisc.
-
-It is important to notice that filters reside
-.B within
-qdiscs - they are not masters of what happens.
-
-.SH CLASSLESS QDISCS
-The classless qdiscs are:
-.TP
-[p|b]fifo
-Simplest usable qdisc, pure First In, First Out behaviour. Limited in
-packets or in bytes.
-.TP
-pfifo_fast
-Standard qdisc for 'Advanced Router' enabled kernels. Consists of a three-band
-queue which honors Type of Service flags, as well as the priority that may be
-assigned to a packet.
-.TP
-red
-Random Early Detection simulates physical congestion by randomly dropping
-packets when nearing configured bandwidth allocation. Well suited to very
-large bandwidth applications.
-.TP
-sfq
-Stochastic Fairness Queueing reorders queued traffic so each 'session'
-gets to send a packet in turn.
-.TP
-tbf
-The Token Bucket Filter is suited for slowing traffic down to a precisely
-configured rate. Scales well to large bandwidths.
-.SH CONFIGURING CLASSLESS QDISCS
-In the absence of classful qdiscs, classless qdiscs can only be attached at
-the root of a device. Full syntax:
-.P
-.B tc qdisc add dev
-DEV
-.B root
-QDISC QDISC-PARAMETERS
-
-To remove, issue
-.P
-.B tc qdisc del dev
-DEV
-.B root
-
-The
-.B pfifo_fast
-qdisc is the automatic default in the absence of a configured qdisc.
-
-.SH CLASSFUL QDISCS
-The classful qdiscs are:
-.TP
-CBQ
-Class Based Queueing implements a rich linksharing hierarchy of classes.
-It contains shaping elements as well as prioritizing capabilities. Shaping is
-performed using link idle time calculations based on average packet size and
-underlying link bandwidth. The latter may be ill-defined for some interfaces.
-.TP
-HTB
-The Hierarchy Token Bucket implements a rich linksharing hierarchy of
-classes with an emphasis on conforming to existing practices. HTB facilitates
-guaranteeing bandwidth to classes, while also allowing specification of upper
-limits to inter-class sharing. It contains shaping elements, based on TBF and
-can prioritize classes.
-.TP
-PRIO
-The PRIO qdisc is a non-shaping container for a configurable number of
-classes which are dequeued in order. This allows for easy prioritization
-of traffic, where lower classes are only able to send if higher ones have
-no packets available. To facilitate configuration, Type Of Service bits are
-honored by default.
-.SH THEORY OF OPERATION
-Classes form a tree, where each class has a single parent.
-A class may have multiple children. Some qdiscs allow for runtime addition
-of classes (CBQ, HTB) while others (PRIO) are created with a static number of
-children.
-
-Qdiscs which allow dynamic addition of classes can have zero or more
-subclasses to which traffic may be enqueued.
-
-Furthermore, each class contains a
-.B leaf qdisc
-which by default has
-.B pfifo
-behaviour though another qdisc can be attached in place. This qdisc may again
-contain classes, but each class can have only one leaf qdisc.
-
-When a packet enters a classful qdisc it can be
-.B classified
-to one of the classes within. Three criteria are available, although not all
-qdiscs will use all three:
-.TP
-tc filters
-If tc filters are attached to a class, they are consulted first
-for relevant instructions. Filters can match on all fields of a packet header,
-as well as on the firewall mark applied by ipchains or iptables. See
-.BR tc-filters (8).
-.TP
-Type of Service
-Some qdiscs have built in rules for classifying packets based on the TOS field.
-.TP
-skb->priority
-Userspace programs can encode a class-id in the 'skb->priority' field using
-the SO_PRIORITY option.
-.P
-Each node within the tree can have its own filters but higher level filters
-may also point directly to lower classes.
-
-If classification did not succeed, packets are enqueued to the leaf qdisc
-attached to that class. Check qdisc specific manpages for details, however.
-
-.SH NAMING
-All qdiscs, classes and filters have IDs, which can either be specified
-or be automatically assigned.
-
-IDs consist of a major number and a minor number, separated by a colon.
-
-.TP
-QDISCS
-A qdisc, which potentially can have children,
-gets assigned a major number, called a 'handle', leaving the minor
-number namespace available for classes. The handle is expressed as '10:'.
-It is customary to explicitly assign a handle to qdiscs expected to have
-children.
-
-.TP
-CLASSES
-Classes residing under a qdisc share their qdisc major number, but each have
-a separate minor number called a 'classid' that has no relation to their
-parent classes, only to their parent qdisc. The same naming custom as for
-qdiscs applies.
-
-.TP
-FILTERS
-Filters have a three part ID, which is only needed when using a hashed
-filter hierarchy, for which see
-.BR tc-filters (8).
-.SH UNITS
-All parameters accept a floating point number, possibly followed by a unit.
-.P
-Bandwidths or rates can be specified in:
-.TP
-kbps
-Kilobytes per second
-.TP
-mbps
-Megabytes per second
-.TP
-kbit
-Kilobits per second
-.TP
-mbit
-Megabits per second
-.TP
-bps or a bare number
-Bytes per second
-.P
-Amounts of data can be specified in:
-.TP
-kb or k
-Kilobytes
-.TP
-mb or m
-Megabytes
-.TP
-mbit
-Megabits
-.TP
-kbit
-Kilobits
-.TP
-b or a bare number
-Bytes.
-.P
-Lengths of time can be specified in:
-.TP
-s, sec or secs
-Whole seconds
-.TP
-ms, msec or msecs
-Milliseconds
-.TP
-us, usec, usecs or a bare number
-Microseconds.
-
-.SH TC COMMANDS
-The following commands are available for qdiscs, classes and filter:
-.TP
-add
-Add a qdisc, class or filter to a node. For all entities, a
-.B parent
-must be passed, either by passing its ID or by attaching directly to the root of a device.
-When creating a qdisc or a filter, it can be named with the
-.B handle
-parameter. A class is named with the
-.B classid
-parameter.
-
-.TP
-remove
-A qdisc can be removed by specifying its handle, which may also be 'root'. All subclasses and their leaf qdiscs
-are automatically deleted, as well as any filters attached to them.
-
-.TP
-change
-Some entities can be modified 'in place'. Shares the syntax of 'add', with the exception
-that the handle cannot be changed and neither can the parent. In other words,
-.B
-change
-cannot move a node.
-
-.TP
-replace
-Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet
-it is created.
-
-.TP
-link
-Only available for qdiscs and performs a replace where the node
-must exist already.
-
-
-.SH HISTORY
-.B tc
-was written by Alexey N. Kuznetsov and added in Linux 2.2.
-.SH SEE ALSO
-.BR tc-cbq (8),
-.BR tc-htb (8),
-.BR tc-sfq (8),
-.BR tc-red (8),
-.BR tc-tbf (8),
-.BR tc-pfifo (8),
-.BR tc-bfifo (8),
-.BR tc-pfifo_fast (8),
-.BR tc-filters (8)
-
-.SH AUTHOR
-Manpage maintained by bert hubert (ahu@ds9a.nl)
-
--- /dev/null
+*.yacc.c
+*.lex.c
+*.output
+*.yacc.h
+tc
TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
- m_police.o m_estimator.o m_action.o m_ematch.o \
- emp_ematch.yacc.o emp_ematch.lex.o
+ tc_monitor.o m_police.o m_estimator.o m_action.o \
+ m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
include ../Config
TCMODULES += q_prio.o
TCMODULES += q_tbf.o
TCMODULES += q_cbq.o
+TCMODULES += q_rr.o
+TCMODULES += q_multiq.o
+TCMODULES += q_netem.o
TCMODULES += f_rsvp.o
TCMODULES += f_u32.o
TCMODULES += f_route.o
TCMODULES += f_fw.o
TCMODULES += f_basic.o
+TCMODULES += f_flow.o
TCMODULES += q_dsmark.o
TCMODULES += q_gred.o
TCMODULES += f_tcindex.o
TCMODULES += m_gact.o
TCMODULES += m_mirred.o
TCMODULES += m_ipt.o
+TCMODULES += m_nat.o
TCMODULES += m_pedit.o
+TCMODULES += m_skbedit.o
TCMODULES += p_ip.o
TCMODULES += p_icmp.o
TCMODULES += p_tcp.o
TCLIB += tc_red.o
TCLIB += tc_cbq.o
TCLIB += tc_estimator.o
+TCLIB += tc_stab.o
CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PROB
TCSO :=
-TCSO += q_netem.so
ifeq ($(TC_CONFIG_ATM),y)
TCSO += q_atm.so
endif
$(AR) rcs $@ $(TCLIB)
install: all
- mkdir -p $(DESTDIR)/usr/lib/tc
- install -m 0755 -s tc $(DESTDIR)$(SBINDIR)
+ mkdir -p $(DESTDIR)$(LIBDIR)/tc
+ install -m 0755 tc $(DESTDIR)$(SBINDIR)
for i in $(TCSO); \
- do install -m 755 -s $$i $(DESTDIR)/usr/lib/tc; \
+ do install -m 755 $$i $(DESTDIR)$(LIBDIR)/tc; \
done
clean:
/*
- * em_cmp.c Simle coparison Ematch
+ * em_cmp.c Simple comparison Ematch
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
"Usage: cmp(ALIGN at OFFSET [ ATTRS ] { eq | lt | gt } VALUE)\n" \
"where: ALIGN := { u8 | u16 | u32 }\n" \
" ATTRS := [ layer LAYER ] [ mask MASK ] [ trans ]\n" \
- " LAYER := { link | header | next-header | 0..%d }\n" \
+ " LAYER := { link | network | transport | 0..%d }\n" \
"\n" \
"Example: cmp(u16 at 3 layer 2 mask 0xff00 gt 20)\n",
TCF_LAYER_MAX);
align = TCF_EM_ALIGN_U32;
else
return PARSE_ERR(args, "cmp: invalid alignment");
-
+
for (a = bstr_next(args); a; a = bstr_next(a)) {
if (!bstrcmp(a, "at")) {
if (a->next == NULL)
opnd = TCF_EM_OPND_GT;
else if (!bstrcmp(a, "lt"))
opnd = TCF_EM_OPND_LT;
-
+
if (a->next == NULL)
return PARSE_ERR(a, "cmp: missing argument");
a = bstr_next(a);
" META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
"\n" \
"Example: meta(nfmark gt 24)\n" \
- " meta(indev shift 1 eq \"ppp\"\n" \
+ " meta(indev shift 1 eq \"ppp\")\n" \
" meta(tcindex mask 0xf0 eq 0xf0)\n" \
- " meta(dev eq indev)\n" \
"\n" \
"For a list of meta identifiers, use meta(list).\n");
}
"Routing ClassID (cls_route)"),
__A(RTIIF, "rt_iif", "i",
"Incoming interface index"),
+ __A(VLAN_TAG, "vlan", "i", "Vlan tag"),
__A(SECTION, "Sockets", "", ""),
__A(SK_FAMILY, "sk_family", "i", "Address family"),
if (!bstrcmp(kind, meta_table[i].kind) &&
meta_table[i].id != 0)
return &meta_table[i];
-
+
return NULL;
}
for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
if (meta_table[i].id == id)
return &meta_table[i];
-
+
return NULL;
}
{
char *p;
struct meta_entry *entry;
-
+
entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
if (entry == NULL)
return 0;
-
+
for (p = entry->mask; p; p++)
if (map_type(*p) == TCF_META_TYPE(needed->kind))
return 1;
{
return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
}
-
+
static inline struct bstr *
parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
}
num = bstrtoul(arg);
- if (num != LONG_MAX) {
+ if (num != ULONG_MAX) {
obj->kind = TCF_META_TYPE_INT << 12;
obj->kind |= TCF_META_ID_VALUE;
*dst = (unsigned long) num;
if (left) {
struct tcf_meta_val *right = obj;
-
+
if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
goto compatible;
right->kind = overwrite_type(right, left);
else
goto not_compatible;
- } else
+ } else
goto not_compatible;
}
return PARSE_FAILURE;
}
a = bstr_next(a);
-
+
shift = bstrtoul(a);
- if (shift == LONG_MAX) {
+ if (shift == ULONG_MAX) {
PARSE_ERR(a, "meta: invalid shift, must " \
"be numeric");
return PARSE_FAILURE;
return PARSE_FAILURE;
}
a = bstr_next(a);
-
+
mask = bstrtoul(a);
- if (mask == LONG_MAX) {
+ if (mask == ULONG_MAX) {
PARSE_ERR(a, "meta: invalid mask, must be " \
"numeric");
return PARSE_FAILURE;
return -1;
else if (a != NULL)
return PARSE_ERR(a, "meta: unexpected trailer");
-
+
addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
- if (lvalue)
- dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
-
- if (rvalue)
- dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
+ dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
+ dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
return 0;
}
"Usage: nbyte(NEEDLE at OFFSET [layer LAYER])\n" \
"where: NEEDLE := { string | \"c-escape-sequence\" }\n" \
" OFFSET := int\n" \
- " LAYER := { link | header | next-header | 0..%d }\n" \
+ " LAYER := { link | network | transport | 0..%d }\n" \
"\n" \
"Example: nbyte(\"ababa\" at 12 layer 1)\n",
TCF_LAYER_MAX);
if (offset_present == 0)
return PARSE_ERR(a, "nbyte: offset required");
-
+
nb.len = needle->len;
nb.layer = (__u8) layer;
nb.off = (__u16) offset;
for (i = 0; i < nb->len; i++)
fprintf(fd, "%c", isprint(needle[i]) ? needle[i] : '.');
fprintf(fd, "\" at %d layer %d", nb->off, nb->layer);
-
+
return 0;
}
offset = bstrtoul(a);
} else
offset = bstrtoul(a);
-
+
if (offset == ULONG_MAX)
return PARSE_ERR(a, "u32: invalid offset");
return ERROR;
}
strbuf_index = 0;
-
+
BEGIN(str);
}
<str>\\[0-7]{1,3} { /* octal escape sequence */
int res;
-
+
sscanf(yytext + 1, "%o", &res);
if (res > 0xFF) {
fprintf(stderr, "error: octal escape sequence" \
<str>\\x[0-9a-fA-F]{1,2} {
int res;
-
+
sscanf(yytext + 2, "%x", &res);
-
+
if (res > 0xFF) {
fprintf(stderr, "error: hexadecimal escape " \
"sequence out of range\n");
/*
* f_basic.c Basic Classifier
*
- * This program is free software; you can u32istribute it and/or
+ * This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
fprintf(stderr, "\n");
fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
fprintf(stderr, " FILTERID := X:Y:Z\n");
+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
}
static int basic_parse_opt(struct filter_util *qu, char *handle,
return -1;
}
}
-
+
t->tcm_handle = h;
tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
--- /dev/null
+/*
+ * f_flow.c Flow filter
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Patrick McHardy <kaber@trash.net>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "m_ematch.h"
+
+static void explain(void)
+{
+ fprintf(stderr,
+"Usage: ... flow ...\n"
+"\n"
+" [mapping mode]: map key KEY [ OPS ] ...\n"
+" [hashing mode]: hash keys KEY-LIST ... [ perturb SECS ]\n"
+"\n"
+" [ divisor NUM ] [ baseclass ID ] [ match EMATCH_TREE ]\n"
+" [ police POLICE_SPEC ] [ action ACTION_SPEC ]\n"
+"\n"
+"KEY-LIST := [ KEY-LIST , ] KEY\n"
+"KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n"
+" mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n"
+" nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n"
+" vlan-tag ]\n"
+"OPS := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n"
+"ID := X:Y\n"
+ );
+}
+
+static const char *flow_keys[FLOW_KEY_MAX+1] = {
+ [FLOW_KEY_SRC] = "src",
+ [FLOW_KEY_DST] = "dst",
+ [FLOW_KEY_PROTO] = "proto",
+ [FLOW_KEY_PROTO_SRC] = "proto-src",
+ [FLOW_KEY_PROTO_DST] = "proto-dst",
+ [FLOW_KEY_IIF] = "iif",
+ [FLOW_KEY_PRIORITY] = "priority",
+ [FLOW_KEY_MARK] = "mark",
+ [FLOW_KEY_NFCT] = "nfct",
+ [FLOW_KEY_NFCT_SRC] = "nfct-src",
+ [FLOW_KEY_NFCT_DST] = "nfct-dst",
+ [FLOW_KEY_NFCT_PROTO_SRC] = "nfct-proto-src",
+ [FLOW_KEY_NFCT_PROTO_DST] = "nfct-proto-dst",
+ [FLOW_KEY_RTCLASSID] = "rt-classid",
+ [FLOW_KEY_SKUID] = "sk-uid",
+ [FLOW_KEY_SKGID] = "sk-gid",
+ [FLOW_KEY_VLAN_TAG] = "vlan-tag",
+};
+
+static int flow_parse_keys(__u32 *keys, __u32 *nkeys, char *argv)
+{
+ char *s, *sep;
+ unsigned int i;
+
+ *keys = 0;
+ *nkeys = 0;
+ s = argv;
+ while (s != NULL) {
+ sep = strchr(s, ',');
+ if (sep)
+ *sep = '\0';
+
+ for (i = 0; i <= FLOW_KEY_MAX; i++) {
+ if (matches(s, flow_keys[i]) == 0) {
+ *keys |= 1 << i;
+ (*nkeys)++;
+ break;
+ }
+ }
+ if (i > FLOW_KEY_MAX) {
+ fprintf(stderr, "Unknown flow key \"%s\"\n", s);
+ return -1;
+ }
+ s = sep ? sep + 1 : NULL;
+ }
+ return 0;
+}
+
+static void transfer_bitop(__u32 *mask, __u32 *xor, __u32 m, __u32 x)
+{
+ *xor = x ^ (*xor & m);
+ *mask &= m;
+}
+
+static int get_addend(__u32 *addend, char *argv, __u32 keys)
+{
+ inet_prefix addr;
+ int sign = 0;
+ __u32 tmp;
+
+ if (*argv == '-') {
+ sign = 1;
+ argv++;
+ }
+
+ if (get_u32(&tmp, argv, 0) == 0)
+ goto out;
+
+ if (keys & (FLOW_KEY_SRC | FLOW_KEY_DST |
+ FLOW_KEY_NFCT_SRC | FLOW_KEY_NFCT_DST) &&
+ get_addr(&addr, argv, AF_UNSPEC) == 0) {
+ switch (addr.family) {
+ case AF_INET:
+ tmp = ntohl(addr.data[0]);
+ goto out;
+ case AF_INET6:
+ tmp = ntohl(addr.data[3]);
+ goto out;
+ }
+ }
+
+ return -1;
+out:
+ if (sign)
+ tmp = -tmp;
+ *addend = tmp;
+ return 0;
+}
+
+static int flow_parse_opt(struct filter_util *fu, char *handle,
+ int argc, char **argv, struct nlmsghdr *n)
+{
+ struct tc_police tp;
+ struct tcmsg *t = NLMSG_DATA(n);
+ struct rtattr *tail;
+ __u32 mask = ~0U, xor = 0;
+ __u32 keys = 0, nkeys = 0;
+ __u32 mode = FLOW_MODE_MAP;
+ __u32 tmp;
+
+ memset(&tp, 0, sizeof(tp));
+
+ if (handle) {
+ if (get_u32(&t->tcm_handle, handle, 0)) {
+ fprintf(stderr, "Illegal \"handle\"\n");
+ return -1;
+ }
+ }
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+
+ while (argc > 0) {
+ if (matches(*argv, "map") == 0) {
+ mode = FLOW_MODE_MAP;
+ } else if (matches(*argv, "hash") == 0) {
+ mode = FLOW_MODE_HASH;
+ } else if (matches(*argv, "keys") == 0) {
+ NEXT_ARG();
+ if (flow_parse_keys(&keys, &nkeys, *argv))
+ return -1;
+ addattr32(n, 4096, TCA_FLOW_KEYS, keys);
+ } else if (matches(*argv, "and") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"mask\"\n");
+ return -1;
+ }
+ transfer_bitop(&mask, &xor, tmp, 0);
+ } else if (matches(*argv, "or") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"or\"\n");
+ return -1;
+ }
+ transfer_bitop(&mask, &xor, ~tmp, tmp);
+ } else if (matches(*argv, "xor") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"xor\"\n");
+ return -1;
+ }
+ transfer_bitop(&mask, &xor, ~0, tmp);
+ } else if (matches(*argv, "rshift") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"rshift\"\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_RSHIFT, tmp);
+ } else if (matches(*argv, "addend") == 0) {
+ NEXT_ARG();
+ if (get_addend(&tmp, *argv, keys)) {
+ fprintf(stderr, "Illegal \"addend\"\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_ADDEND, tmp);
+ } else if (matches(*argv, "divisor") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"divisor\"\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_DIVISOR, tmp);
+ } else if (matches(*argv, "baseclass") == 0) {
+ NEXT_ARG();
+ if (get_tc_classid(&tmp, *argv) || TC_H_MIN(tmp) == 0) {
+ fprintf(stderr, "Illegal \"baseclass\"\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_BASECLASS, tmp);
+ } else if (matches(*argv, "perturb") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tmp, *argv, 0)) {
+ fprintf(stderr, "Illegal \"perturb\"\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_PERTURB, tmp);
+ } else if (matches(*argv, "police") == 0) {
+ NEXT_ARG();
+ if (parse_police(&argc, &argv, TCA_FLOW_POLICE, n)) {
+ fprintf(stderr, "Illegal \"police\"\n");
+ return -1;
+ }
+ continue;
+ } else if (matches(*argv, "action") == 0) {
+ NEXT_ARG();
+ if (parse_action(&argc, &argv, TCA_FLOW_ACT, n)) {
+ fprintf(stderr, "Illegal \"action\"\n");
+ return -1;
+ }
+ continue;
+ } else if (matches(*argv, "match") == 0) {
+ NEXT_ARG();
+ if (parse_ematch(&argc, &argv, TCA_FLOW_EMATCHES, n)) {
+ fprintf(stderr, "Illegal \"ematch\"\n");
+ return -1;
+ }
+ continue;
+ } else if (matches(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argv++, argc--;
+ }
+
+ if (nkeys > 1 && mode != FLOW_MODE_HASH) {
+ fprintf(stderr, "Invalid mode \"map\" for multiple keys\n");
+ return -1;
+ }
+ addattr32(n, 4096, TCA_FLOW_MODE, mode);
+
+ if (mask != ~0 || xor != 0) {
+ addattr32(n, 4096, TCA_FLOW_MASK, mask);
+ addattr32(n, 4096, TCA_FLOW_XOR, xor);
+ }
+
+ tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ return 0;
+}
+
+static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt,
+ __u32 handle)
+{
+ struct rtattr *tb[TCA_FLOW_MAX+1];
+ SPRINT_BUF(b1);
+ unsigned int i;
+ __u32 mask = ~0, val = 0;
+
+ if (opt == NULL)
+ return -EINVAL;
+
+ parse_rtattr_nested(tb, TCA_FLOW_MAX, opt);
+
+ fprintf(f, "handle 0x%x ", handle);
+
+ if (tb[TCA_FLOW_MODE]) {
+ __u32 mode = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MODE]);
+
+ switch (mode) {
+ case FLOW_MODE_MAP:
+ fprintf(f, "map ");
+ break;
+ case FLOW_MODE_HASH:
+ fprintf(f, "hash ");
+ break;
+ }
+ }
+
+ if (tb[TCA_FLOW_KEYS]) {
+ __u32 keymask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_KEYS]);
+ char *sep = "";
+
+ fprintf(f, "keys ");
+ for (i = 0; i <= FLOW_KEY_MAX; i++) {
+ if (keymask & (1 << i)) {
+ fprintf(f, "%s%s", sep, flow_keys[i]);
+ sep = ",";
+ }
+ }
+ fprintf(f, " ");
+ }
+
+ if (tb[TCA_FLOW_MASK])
+ mask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MASK]);
+ if (tb[TCA_FLOW_XOR])
+ val = *(__u32 *)RTA_DATA(tb[TCA_FLOW_XOR]);
+
+ if (mask != ~0 || val != 0) {
+ __u32 or = (mask & val) ^ val;
+ __u32 xor = mask & val;
+
+ if (mask != ~0)
+ fprintf(f, "and 0x%.8x ", mask);
+ if (xor != 0)
+ fprintf(f, "xor 0x%.8x ", xor);
+ if (or != 0)
+ fprintf(f, "or 0x%.8x ", or);
+ }
+
+ if (tb[TCA_FLOW_RSHIFT])
+ fprintf(f, "rshift %u ",
+ *(__u32 *)RTA_DATA(tb[TCA_FLOW_RSHIFT]));
+ if (tb[TCA_FLOW_ADDEND])
+ fprintf(f, "addend 0x%x ",
+ *(__u32 *)RTA_DATA(tb[TCA_FLOW_ADDEND]));
+
+ if (tb[TCA_FLOW_DIVISOR])
+ fprintf(f, "divisor %u ",
+ *(__u32 *)RTA_DATA(tb[TCA_FLOW_DIVISOR]));
+ if (tb[TCA_FLOW_BASECLASS])
+ fprintf(f, "baseclass %s ",
+ sprint_tc_classid(*(__u32 *)RTA_DATA(tb[TCA_FLOW_BASECLASS]), b1));
+
+ if (tb[TCA_FLOW_PERTURB])
+ fprintf(f, "perturb %usec ",
+ *(__u32 *)RTA_DATA(tb[TCA_FLOW_PERTURB]));
+
+ if (tb[TCA_FLOW_EMATCHES])
+ print_ematch(f, tb[TCA_FLOW_EMATCHES]);
+ if (tb[TCA_FLOW_POLICE])
+ tc_print_police(f, tb[TCA_FLOW_POLICE]);
+ if (tb[TCA_FLOW_ACT]) {
+ fprintf(f, "\n");
+ tc_print_action(f, tb[TCA_FLOW_ACT]);
+ }
+ return 0;
+}
+
+struct filter_util flow_filter_util = {
+ .id = "flow",
+ .parse_fopt = flow_parse_opt,
+ .print_fopt = flow_print_opt,
+};
fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ]\n");
fprintf(stderr, " POLICE_SPEC := ... look at TBF\n");
fprintf(stderr, " CLASSID := X:Y\n");
+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
}
#define usage() return(-1)
memset(&tp, 0, sizeof(tp));
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+
if (handle) {
+ char *slash;
+ __u32 mask = 0;
+ if ((slash = strchr(handle, '/')) != NULL)
+ *slash = '\0';
if (get_u32(&t->tcm_handle, handle, 0)) {
fprintf(stderr, "Illegal \"handle\"\n");
return -1;
}
+ if (slash) {
+ if (get_u32(&mask, slash+1, 0)) {
+ fprintf(stderr, "Illegal \"handle\" mask\n");
+ return -1;
+ }
+ addattr32(n, MAX_MSG, TCA_FW_MASK, mask);
+ }
}
if (argc == 0)
return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
-
while (argc > 0) {
if (matches(*argv, "classid") == 0 ||
matches(*argv, "flowid") == 0) {
parse_rtattr_nested(tb, TCA_FW_MAX, opt);
- if (handle)
- fprintf(f, "handle 0x%x ", handle);
+ if (handle || tb[TCA_FW_MASK]) {
+ __u32 mark = 0, mask = 0;
+ if(handle)
+ mark = handle;
+ if(tb[TCA_FW_MASK] &&
+ (mask = *(__u32*)RTA_DATA(tb[TCA_FW_MASK])) != 0xFFFFFFFF)
+ fprintf(f, "handle 0x%x/0x%x ", mark, mask);
+ else
+ fprintf(f, "handle 0x%x ", handle);
+ }
if (tb[TCA_FW_CLASSID]) {
SPRINT_BUF(b1);
struct rtattr *idev = tb[TCA_FW_INDEV];
fprintf(f, "input dev %s ",(char *)RTA_DATA(idev));
}
-
+
if (tb[TCA_FW_ACT]) {
fprintf(f, "\n");
tc_print_action(f, tb[TCA_FW_ACT]);
fprintf(stderr, " [ flowid CLASSID ] [ police POLICE_SPEC ]\n");
fprintf(stderr, " POLICE_SPEC := ... look at TBF\n");
fprintf(stderr, " CLASSID := X:Y\n");
+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
}
#define usage() return(-1)
fprintf(stderr, " u{8|16|32} NUMBER mask MASK at OFFSET}\n");
fprintf(stderr, " POLICE_SPEC := ... look at TBF\n");
fprintf(stderr, " FILTERID := X:Y\n");
+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
}
#define usage() return(-1)
#include <arpa/inet.h>
#include <string.h>
#include <linux/if.h>
+#include <linux/if_ether.h>
#include "utils.h"
#include "tc_util.h"
+extern int show_pretty;
+
static void explain(void)
{
- fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
- fprintf(stderr, " [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]\n");
+ fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]"
+ " [ classid CLASSID ]\n");
+ fprintf(stderr, " [ police POLICE_SPEC ]"
+ " [ offset OFFSET_SPEC ]\n");
fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
fprintf(stderr, " [ sample SAMPLE ]\n");
fprintf(stderr, "or u32 divisor DIVISOR\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
- fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
+ fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp |"
+ " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
fprintf(stderr, " FILTERID := X:Y:Z\n");
+ fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
}
#define usage() return(-1)
return buf;
}
-static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+ int off, int offmask)
{
int i;
int hwm = sel->nkeys;
return 0;
}
-static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+ int off, int offmask)
{
key = htonl(key);
mask = htonl(mask);
return pack_key(sel, key, mask, off, offmask);
}
-static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
+static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
+ int off, int offmask)
{
if (key > 0xFFFF || mask > 0xFFFF)
return -1;
}
-static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+ int off, int offmask)
{
int res = -1;
int argc = *argc_p;
return res;
}
-static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+ int off, int offmask)
{
int res = -1;
int argc = *argc_p;
return res;
}
-static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off, int offmask)
+static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+ int off, int offmask)
{
int res = -1;
int argc = *argc_p;
return res;
}
-static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
+static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
+ int off)
{
int res = -1;
int argc = *argc_p;
return res;
}
-static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, int off)
+static int parse_ip6_addr(int *argc_p, char ***argv_p,
+ struct tc_u32_sel *sel, int off)
{
int res = -1;
int argc = *argc_p;
plen = addr.bitlen;
for (i=0; i<plen; i+=32) {
// if (((i+31)&~0x1F)<=plen) {
- if (((i+31))<=plen) {
- if ((res = pack_key(sel, addr.data[i/32], 0xFFFFFFFF, off+4*(i/32), offmask)) < 0)
+ if (i + 31 <= plen) {
+ res = pack_key(sel, addr.data[i/32],
+ 0xFFFFFFFF, off+4*(i/32), offmask);
+ if (res < 0)
return -1;
- } else if (i<plen) {
- __u32 mask = htonl(0xFFFFFFFF<<(32-(plen-i)));
- if ((res = pack_key(sel, addr.data[i/32], mask, off+4*(i/32), offmask)) < 0)
+ } else if (i < plen) {
+ __u32 mask = htonl(0xFFFFFFFF << (32 - (plen -i )));
+ res = pack_key(sel, addr.data[i/32],
+ mask, off+4*(i/32), offmask);
+ if (res < 0)
return -1;
}
}
*argv_p = argv;
return res;
}
-
+
static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
{
int res = -1;
return res;
}
+
static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
{
int res = -1;
return res;
}
-static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, struct nlmsghdr *n)
+static int parse_selector(int *argc_p, char ***argv_p,
+ struct tc_u32_sel *sel, struct nlmsghdr *n)
{
int argc = *argc_p;
char **argv = *argv_p;
return 0;
}
-static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
+static void print_ipv4(FILE *f, const struct tc_u32_key *key)
+{
+ char abuf[256];
+
+ switch (key->off) {
+ case 0:
+ switch (ntohl(key->mask)) {
+ case 0x0f000000:
+ fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
+ return;
+ case 0x00ff0000:
+ fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
+ return;
+ }
+ break;
+ case 8:
+ if (ntohl(key->mask) == 0x00ff0000) {
+ fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
+ return;
+ }
+ break;
+ case 12:
+ case 16: {
+ int bits = mask2bits(key->mask);
+ if (bits >= 0) {
+ fprintf(f, "\n %s %s/%d",
+ key->off == 12 ? "match IP src" : "match IP dst",
+ inet_ntop(AF_INET, &key->val,
+ abuf, sizeof(abuf)),
+ bits);
+ return;
+ }
+ }
+ break;
+
+ case 20:
+ switch (ntohl(key->mask)) {
+ case 0x0000ffff:
+ fprintf(f, "\n match sport %u",
+ ntohl(key->val) & 0xffff);
+ return;
+ case 0xffff0000:
+ fprintf(f, "\n match dport %u",
+ ntohl(key->val) >> 16);
+ return;
+ case 0xffffffff:
+ fprintf(f, "\n match sport %u, match dport %u",
+ ntohl(key->val) & 0xffff,
+ ntohl(key->val) >> 16);
+
+ return;
+ }
+ /* XXX: Default print_raw */
+ }
+}
+
+static void print_raw(FILE *f, const struct tc_u32_key *key)
+{
+ fprintf(f, "\n match %08x/%08x at %s%d",
+ (unsigned int)ntohl(key->val),
+ (unsigned int)ntohl(key->mask),
+ key->offmask ? "nexthdr+" : "",
+ key->off);
+}
+
+static const struct {
+ __u16 proto;
+ __u16 pad;
+ void (*pprinter)(FILE *f, const struct tc_u32_key *key);
+} u32_pprinters[] = {
+ {0, 0, print_raw},
+ {ETH_P_IP, 0, print_ipv4},
+};
+
+static void show_keys(FILE *f, const struct tc_u32_key *key)
+{
+ int i = 0;
+
+ if (!show_pretty)
+ goto show_k;
+
+ for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) {
+ if (u32_pprinters[i].proto == ntohs(f_proto)) {
+show_k:
+ u32_pprinters[i].pprinter(f, key);
+ return;
+ }
+ }
+
+ i = 0;
+ goto show_k;
+}
+
+static int u32_parse_opt(struct filter_util *qu, char *handle,
+ int argc, char **argv, struct nlmsghdr *n)
{
struct {
struct tc_u32_sel sel;
} sel;
struct tcmsg *t = NLMSG_DATA(n);
struct rtattr *tail;
- int sel_ok = 0;
+ int sel_ok = 0, terminal_ok = 0;
int sample_ok = 0;
__u32 htid = 0;
__u32 order = 0;
} else if (matches(*argv, "divisor") == 0) {
unsigned divisor;
NEXT_ARG();
- if (get_unsigned(&divisor, *argv, 0) ||
+ if (get_unsigned(&divisor, *argv, 0) ||
divisor == 0 ||
divisor > 0x100 || ((divisor - 1) & divisor)) {
fprintf(stderr, "Illegal \"divisor\"\n");
return -1;
}
if (sel2.sel.nkeys != 1) {
- fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
+ fprintf(stderr, "\"sample\" must contain"
+ " exactly ONE key.\n");
return -1;
}
if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
fprintf(stderr, "Illegal \"action\"\n");
return -1;
}
+ terminal_ok++;
continue;
} else if (matches(*argv, "police") == 0) {
fprintf(stderr, "Illegal \"police\"\n");
return -1;
}
+ terminal_ok++;
continue;
} else if (strcmp(*argv, "help") == 0) {
explain();
argc--; argv++;
}
+ /* We dont necessarily need class/flowids */
+ if (terminal_ok)
+ sel.sel.flags |= TC_U32_TERMINAL;
+
if (order) {
if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
fprintf(stderr, "\"order\" contradicts \"handle\"\n");
if (htid)
addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
if (sel_ok)
- addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
+ addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
+ sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
return 0;
}
-static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
+static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
+ __u32 handle)
{
struct rtattr *tb[TCA_U32_MAX+1];
struct tc_u32_sel *sel = NULL;
fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
} else if (tb[TCA_U32_HASH]) {
__u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
- fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid));
+ fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
+ TC_U32_HASH(htid));
} else {
fprintf(f, "??? ");
}
}
if (tb[TCA_U32_LINK]) {
SPRINT_BUF(b1);
- fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
+ fprintf(f, "link %s ",
+ sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
}
if (tb[TCA_U32_PCNT]) {
}
if (sel) {
- int i;
- struct tc_u32_key *key = sel->keys;
if (sel->nkeys) {
- for (i=0; i<sel->nkeys; i++, key++) {
- fprintf(f, "\n match %08x/%08x at %s%d",
- (unsigned int)ntohl(key->val),
- (unsigned int)ntohl(key->mask),
- key->offmask ? "nexthdr+" : "",
- key->off);
+ int i;
+ for (i=0; i<sel->nkeys; i++) {
+ show_keys(f, sel->keys + i);
if (show_stats && NULL != pf)
- fprintf(f, " (success %lld ) ",
+ fprintf(f, " (success %llu ) ",
(unsigned long long) pf->kcnts[i]);
}
}
if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
fprintf(f, "\n offset ");
if (sel->flags&TC_U32_VAROFFSET)
- fprintf(f, "%04x>>%d at %d ", ntohs(sel->offmask), sel->offshift, sel->offoff);
+ fprintf(f, "%04x>>%d at %d ",
+ ntohs(sel->offmask),
+ sel->offshift, sel->offoff);
if (sel->off)
fprintf(f, "plus %d ", sel->off);
}
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
* TODO:
* - parse to be passed a filedescriptor for logging purposes
*
void act_usage(void)
{
- fprintf (stderr, "action usage improper\n");
+ /*XXX: In the near future add a action->print_help to improve
+ * usability
+ * This would mean new tc will not be backward compatible
+ * with any action .so from the old days. But if someone really
+ * does that, they would know how to fix this ..
+ *
+ */
+ fprintf (stderr, "usage: tc actions <ACTSPECOP>*\n");
+ fprintf(stderr,
+ "Where: \tACTSPECOP := ACR | GD | FL\n"
+ "\tACR := add | change | replace <ACTSPEC>* \n"
+ "\tGD := get | delete | <ACTISPEC>*\n"
+ "\tFL := ls | list | flush | <ACTNAMESPEC>\n"
+ "\tACTNAMESPEC := action <ACTNAME>\n"
+ "\tACTISPEC := <ACTNAMESPEC> <INDEXSPEC>\n"
+ "\tACTSPEC := action <ACTDETAIL> [INDEXSPEC]\n"
+ "\tINDEXSPEC := index <32 bit indexvalue>\n"
+ "\tACTDETAIL := <ACTNAME> <ACTPARAMS>\n"
+ "\t\tExample ACTNAME is gact, mirred etc\n"
+ "\t\tEach action has its own parameters (ACTPARAMS)\n"
+ "\n");
+
+ exit(-1);
}
static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt)
{
if (opt && RTA_PAYLOAD(opt))
- fprintf(f, "[Unknown action, optlen=%u] ",
+ fprintf(f, "[Unknown action, optlen=%u] ",
(unsigned) RTA_PAYLOAD(opt));
return 0;
}
}
int
-new_cmd(char **argv)
+new_cmd(char **argv)
{
if ((matches(*argv, "change") == 0) ||
(matches(*argv, "replace") == 0)||
goto done;
}
- if (NULL == a) {
+ if (NULL == a) {
goto bad_val;
}
*argv_p = argv;
return 0;
bad_val:
- /* no need to undo things, returning from here should
+ /* no need to undo things, returning from here should
* cause enough pain */
fprintf(stderr, "parse_action: bad value (%d:%s)!\n",argc,*argv);
return -1;
return 0;
}
-static int do_print_action(const struct sockaddr_nl *who,
+int print_action(const struct sockaddr_nl *who,
struct nlmsghdr *n,
void *arg)
{
if (NULL == tb[TCA_ACT_TAB]) {
if (n->nlmsg_type != RTM_GETACTION)
- fprintf(stderr, "do_print_action: NULL kind\n");
+ fprintf(stderr, "print_action: NULL kind\n");
return -1;
- }
+ }
if (n->nlmsg_type == RTM_DELACTION) {
if (n->nlmsg_flags & NLM_F_ROOT) {
- fprintf(fp, "Flushed table ");
+ fprintf(fp, "Flushed table ");
tab_flush = 1;
} else {
fprintf(fp, "deleted action ");
strncpy(k, *argv, sizeof (k) - 1);
a = get_action_kind(k);
- if (NULL == a) {
+ if (NULL == a) {
fprintf(stderr, "Error: non existent action: %s\n",k);
ret = -1;
goto bad_val;
return 1;
}
- if (ans && do_print_action(NULL, &req.n, (void*)stdout) < 0) {
+ if (ans && print_action(NULL, &req.n, (void*)stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return 1;
}
}
#endif
a = get_action_kind(k);
- if (NULL == a) {
+ if (NULL == a) {
fprintf(stderr,"bad action %s\n",k);
goto bad_val;
}
msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
- if (event == RTM_GETACTION) {
+ if (event == RTM_GETACTION) {
if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) {
perror("Cannot send dump request");
return 1;
}
- ret = rtnl_dump_filter(&rth, do_print_action, stdout, NULL, NULL);
+ ret = rtnl_dump_filter(&rth, print_action, stdout, NULL, NULL);
}
- if (event == RTM_DELACTION) {
+ if (event == RTM_DELACTION) {
req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);
req.n.nlmsg_type = RTM_DELACTION;
req.n.nlmsg_flags |= NLM_F_ROOT;
}
if (ret < 0) {
- fprintf(stderr, "Command \"%s\" is unknown, try \"tc action help\".\n", *argv);
+ fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv);
return -1;
}
}
"Error: Unable to find ematch \"%s\" in %s\n" \
"Please assign a unique ID to the ematch kind the suggested " \
"entry is:\n" \
- "\t%d\t%s\n",
+ "\t%d\t%s\n",
kind, EMATCH_MAP, num, kind);
}
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
-
+
if (sscanf(p, "%d %s", &id, namebuf) != 2) {
fprintf(stderr, "ematch map %s corrupted at %s\n",
file, p);
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
-
+
if (sscanf(p, "%d %s", &id, namebuf) != 2) {
fprintf(stderr, "ematch map %s corrupted at %s\n",
file, p);
return NULL;
return get_ematch_kind(name);
-
- return NULL;
}
static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
if (t->inverted)
hdr.flags |= TCF_EM_INVERT;
-
+
addattr_l(n, MAX_MSG, index++, NULL, 0);
if (t->child) {
begin_argv++;
begin_argc--;
}
-
+
fprintf(stderr, "...\n");
if (args) {
i++;
}
-
+
return 0;
}
return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
}
+
+struct bstr * bstr_alloc(const char *text)
+{
+ struct bstr *b = calloc(1, sizeof(*b));
+
+ if (b == NULL)
+ return NULL;
+
+ b->data = strdup(text);
+ if (b->data == NULL) {
+ free(b);
+ return NULL;
+ }
+
+ b->len = strlen(text);
+
+ return b;
+}
+
+unsigned long bstrtoul(const struct bstr *b)
+{
+ char *inv = NULL;
+ unsigned long l;
+ char buf[b->len+1];
+
+ memcpy(buf, b->data, b->len);
+ buf[b->len] = '\0';
+
+ l = strtoul(buf, &inv, 0);
+ if (l == ULONG_MAX || inv == buf)
+ return ULONG_MAX;
+
+ return l;
+}
+
+void bstr_print(FILE *fd, const struct bstr *b, int ascii)
+{
+ int i;
+ char *s = b->data;
+
+ if (ascii)
+ for (i = 0; i < b->len; i++)
+ fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
+ else {
+ for (i = 0; i < b->len; i++)
+ fprintf(fd, "%02x", s[i]);
+ fprintf(fd, "\"");
+ for (i = 0; i < b->len; i++)
+ fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
+ fprintf(fd, "\"");
+ }
+}
+
+void print_ematch_tree(const struct ematch *tree)
+{
+ const struct ematch *t;
+
+ for (t = tree; t; t = t->next) {
+ if (t->inverted)
+ printf("NOT ");
+
+ if (t->child) {
+ printf("(");
+ print_ematch_tree(t->child);
+ printf(")");
+ } else {
+ struct bstr *b;
+ for (b = t->args; b; b = b->next)
+ printf("%s%s", b->data, b->next ? " " : "");
+ }
+
+ if (t->relation == TCF_EM_REL_AND)
+ printf(" AND ");
+ else if (t->relation == TCF_EM_REL_OR)
+ printf(" OR ");
+ }
+}
struct bstr *next;
};
-static inline struct bstr * bstr_alloc(const char *text)
-{
- struct bstr *b = calloc(1, sizeof(*b));
-
- if (b == NULL)
- return NULL;
-
- b->data = strdup(text);
- if (b->data == NULL) {
- free(b);
- return NULL;
- }
-
- b->len = strlen(text);
-
- return b;
-}
+extern struct bstr * bstr_alloc(const char *text);
static inline struct bstr * bstr_new(char *data, unsigned int len)
{
return d;
}
-static inline unsigned long bstrtoul(struct bstr *b)
-{
- char *inv = NULL;
- unsigned long l;
- char buf[b->len+1];
-
- memcpy(buf, b->data, b->len);
- buf[b->len] = '\0';
-
- l = strtol(buf, &inv, 0);
- if (l == ULONG_MAX || inv == buf)
- return LONG_MAX;
-
- return l;
-}
-
-static inline void bstr_print(FILE *fd, struct bstr *b, int ascii)
-{
- int i;
- char *s = b->data;
-
- if (ascii)
- for (i = 0; i < b->len; i++)
- fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
- else {
- for (i = 0; i < b->len; i++)
- fprintf(fd, "%02x", s[i]);
- fprintf(fd, "\"");
- for (i = 0; i < b->len; i++)
- fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
- fprintf(fd, "\"");
- }
-}
-
static inline struct bstr *bstr_next(struct bstr *b)
{
return b->next;
}
+extern unsigned long bstrtoul(const struct bstr *b);
+extern void bstr_print(FILE *fd, const struct bstr *b, int ascii);
+
+
struct ematch
{
struct bstr *args;
return e;
}
-static inline void print_ematch_tree(struct ematch *tree)
-{
- struct ematch *t;
-
- for (t = tree; t; t = t->next) {
- if (t->inverted)
- printf("NOT ");
-
- if (t->child) {
- printf("(");
- print_ematch_tree(t->child);
- printf(")");
- } else {
- struct bstr *b;
- for (b = t->args; b; b = b->next)
- printf("%s%s", b->data, b->next ? " " : "");
- }
-
- if (t->relation == TCF_EM_REL_AND)
- printf(" AND ");
- else if (t->relation == TCF_EM_REL_OR)
- printf(" OR ");
- }
-}
+extern void print_ematch_tree(const struct ematch *tree);
+
struct ematch_util
{
int argc = *p_argc;
char **argv = *p_argv;
unsigned A, time_const;
-
+
NEXT_ARG();
if (est->ewma_log)
duparg("estimator", *argv);
if (matches(*argv, "help") == 0)
est_help();
- if (get_usecs(&A, *argv))
+ if (get_time(&A, *argv))
invarg("estimator", "invalid estimator interval");
NEXT_ARG();
if (matches(*argv, "help") == 0)
est_help();
- if (get_usecs(&time_const, *argv))
+ if (get_time(&time_const, *argv))
invarg("estimator", "invalid estimator time constant");
if (tc_setup_estimator(A, time_const, est) < 0) {
fprintf(stderr, "Error: estimator parameters are out of range.\n");
/*
- * m_gact.c generic actions module
+ * m_gact.c generic actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#include <stdio.h>
/* define to turn on probablity stuff */
#ifdef CONFIG_GACT_PROB
-static const char *prob_n2a(int p)
+static const char *prob_n2a(int p)
{
if (p == PGACT_NONE)
return "none";
#ifdef CONFIG_GACT_PROB
fprintf(stderr, "Usage: ... gact <ACTION> [RAND] [INDEX]\n");
fprintf(stderr,
- "Where: ACTION := reclassify | drop | continue | pass "
- "RAND := random <RANDTYPE> <ACTION> <VAL>"
- "RANDTYPE := netrand | determ"
- "VAL : = value not exceeding 10000"
- "INDEX := index value used"
+ "Where: \tACTION := reclassify | drop | continue | pass \n"
+ "\tRAND := random <RANDTYPE> <ACTION> <VAL>\n"
+ "\tRANDTYPE := netrand | determ\n"
+ "\tVAL : = value not exceeding 10000\n"
+ "\tINDEX := index value used\n"
"\n");
#else
fprintf(stderr, "Usage: ... gact <ACTION> [INDEX]\n");
fprintf(stderr,
- "Where: ACTION := reclassify | drop | continue | pass "
- "INDEX := index value used"
- "\n");
+ "Where: \tACTION := reclassify | drop | continue | pass \n"
+ "\tINDEX := index value used\n"
+ "\n");
#endif
}
-#define usage() return(-1)
+
+static void
+usage(void)
+{
+ explain();
+ exit(-1);
+}
int
get_act(char ***argv_p)
}
argc--;
argv++;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
}
}
#endif
argc--;
argv++;
ok++;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
}
}
/*
- * m_ipt.c iptables based targets
+ * m_ipt.c iptables based targets
* utilities mostly ripped from iptables <duh, its the linux way>
*
* This program is free software; you can distribute it and/or
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
- * TODO: bad bad hardcoding IPT_LIB_DIR and PROC_SYS_MODPROBE
- *
-*/
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ */
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <linux/if.h>
#include <iptables.h>
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "utils.h"
#include "tc_util.h"
#include <fcntl.h>
#include <sys/wait.h>
-const char *pname = "tc-ipt";
-const char *tname = "mangle";
-const char *pversion = "0.1";
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef IPT_LIB_DIR
-#define IPT_LIB_DIR "/usr/local/lib/iptables"
-#endif
-
-#ifndef PROC_SYS_MODPROBE
-#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
-#endif
+static const char *pname = "tc-ipt";
+static const char *tname = "mangle";
+static const char *pversion = "0.1";
static const char *ipthooks[] = {
"NF_IP_PRE_ROUTING",
static unsigned int global_option_offset = 0;
#define OPTION_OFFSET 256
+char *lib_dir;
void
register_target(struct iptables_target *me)
}
+void
+xtables_register_target(struct iptables_target *me)
+{
+ me->next = t_list;
+ t_list = me;
+}
+
void
exit_tryhelp(int status)
{
return buf;
}
-int string_to_number_ll(const char *s, unsigned long long min,
+int string_to_number_ll(const char *s, unsigned long long min,
unsigned long long max,
unsigned long long *ret)
{
}
static struct iptables_target *
-get_target_name(char *name)
+get_target_name(const char *name)
{
void *handle;
char *error;
char *new_name, *lname;
struct iptables_target *m;
-
- char path[sizeof (IPT_LIB_DIR) + sizeof ("/libipt_.so") + strlen(name)];
+ char path[strlen(lib_dir) + sizeof ("/libipt_.so") + strlen(name)];
new_name = malloc(strlen(name) + 1);
lname = malloc(strlen(name) + 1);
}
}
- sprintf(path, IPT_LIB_DIR "/libipt_%s.so", new_name);
+ /* try libxt_xx first */
+ sprintf(path, "%s/libxt_%s.so", lib_dir, new_name);
handle = dlopen(path, RTLD_LAZY);
if (!handle) {
- sprintf(path, IPT_LIB_DIR "/libipt_%s.so", lname);
+ /* try libipt_xx next */
+ sprintf(path, "%s/libipt_%s.so", lib_dir, new_name);
handle = dlopen(path, RTLD_LAZY);
+
+ if (!handle) {
+ sprintf(path, "%s/libxt_%s.so", lib_dir , lname);
+ handle = dlopen(path, RTLD_LAZY);
+ }
+
+ if (!handle) {
+ sprintf(path, "%s/libipt_%s.so", lib_dir , lname);
+ handle = dlopen(path, RTLD_LAZY);
+ }
+ /* ok, lets give up .. */
if (!handle) {
fputs(dlerror(), stderr);
printf("\n");
+ free(new_name);
return NULL;
}
}
fputs(error, stderr);
fprintf(stderr, "\n");
dlclose(handle);
+ free(new_name);
return NULL;
}
}
}
}
+ free(new_name);
return m;
}
name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
}
-/*
+/*
* we may need to check for version mismatch
*/
int
return -1;
}
-static int parse_ipt(struct action_util *a,int *argc_p,
+static int parse_ipt(struct action_util *a,int *argc_p,
char ***argv_p, int tca_id, struct nlmsghdr *n)
{
struct iptables_target *m = NULL;
__u32 hook = 0, index = 0;
res = 0;
+ lib_dir = getenv("IPTABLES_LIB_DIR");
+ if (!lib_dir)
+ lib_dir = IPT_LIB_DIR;
+
{
int i;
for (i = 0; i < rargc; i++) {
argv += optind;
*argc_p = rargc - iargc;
*argv_p = argv;
-
- optind = 1;
+
+ optind = 0;
free_opts(opts);
+ /* Clear flags if target will be used again */
+ m->tflags=0;
+ m->used=0;
+ /* Free allocated memory */
+ if (m->t)
+ free(m->t);
+
return 0;
if (arg == NULL)
return -1;
+ lib_dir = getenv("IPTABLES_LIB_DIR");
+ if (!lib_dir)
+ lib_dir = IPT_LIB_DIR;
+
parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
if (tb[TCA_IPT_TABLE] == NULL) {
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
print_tm(f,tm);
}
- }
+ }
fprintf(f, " \n");
}
/*
- * m_egress.c ingress/egress packet mirror/redir actions module
+ * m_egress.c ingress/egress packet mirror/redir actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
* TODO: Add Ingress support
*
*/
{
fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> \n");
fprintf(stderr, "where: \n");
- fprintf(stderr, "DIRECTION := <ingress | egress>\n");
- fprintf(stderr, "aCTION := <mirror | redirect>\n");
- fprintf(stderr, " : INDEX is the specific policy instance id\n");
- fprintf(stderr, " : DEVICENAME is the devicename \n");
+ fprintf(stderr, "\tDIRECTION := <ingress | egress>\n");
+ fprintf(stderr, "\tACTION := <mirror | redirect>\n");
+ fprintf(stderr, "\tINDEX is the specific policy instance id\n");
+ fprintf(stderr, "\tDEVICENAME is the devicename \n");
+
}
-#define usage() return(-1)
+static void
+usage(void)
+{
+ explain();
+ exit(-1);
+}
char *mirred_n2a(int action)
{
}
if (!ok && !iok) {
- explain();
return -1;
}
} else if (matches(*argv, "ingress") == 0) {
fprintf(stderr,"mirred ingress not supported at the moment\n");
-
+ } else if (matches(*argv, "help") == 0) {
+ usage();
} else {
- fprintf(stderr,"mirred not supported %s\n", *argv);
+ fprintf(stderr,"mirred option not supported %s\n", *argv);
}
return -1;
-
+
}
int
--- /dev/null
+/*
+ * m_nat.c NAT module
+ *
+ * This program is free software; you can distribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_nat.h>
+
+static void
+explain(void)
+{
+ fprintf(stderr, "Usage: ... nat NAT\n"
+ "NAT := DIRECTION OLD NEW\n"
+ "DIRECTION := { ingress | egress }\n"
+ "OLD := PREFIX\n"
+ "NEW := ADDRESS\n");
+}
+
+static void
+usage(void)
+{
+ explain();
+ exit(-1);
+}
+
+static int
+parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel)
+{
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ inet_prefix addr;
+
+ if (argc <= 0)
+ return -1;
+
+ if (matches(*argv, "egress") == 0)
+ sel->flags |= TCA_NAT_FLAG_EGRESS;
+ else if (matches(*argv, "ingress") != 0)
+ goto bad_val;
+
+ NEXT_ARG();
+
+ if (get_prefix_1(&addr, *argv, AF_INET))
+ goto bad_val;
+
+ sel->old_addr = addr.data[0];
+ sel->mask = htonl(~0u << (32 - addr.bitlen));
+
+ NEXT_ARG();
+
+ if (get_prefix_1(&addr, *argv, AF_INET))
+ goto bad_val;
+
+ sel->new_addr = addr.data[0];
+
+ argc--;
+ argv++;
+
+ *argc_p = argc;
+ *argv_p = argv;
+ return 0;
+
+bad_val:
+ return -1;
+}
+
+static int
+parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
+{
+ struct tc_nat sel;
+
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ int ok = 0;
+ struct rtattr *tail;
+
+ memset(&sel, 0, sizeof(sel));
+
+ while (argc > 0) {
+ if (matches(*argv, "nat") == 0) {
+ NEXT_ARG();
+ if (parse_nat_args(&argc, &argv, &sel)) {
+ fprintf(stderr, "Illegal nat construct (%s) \n",
+ *argv);
+ explain();
+ return -1;
+ }
+ ok++;
+ continue;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ break;
+ }
+
+ }
+
+ if (!ok) {
+ explain();
+ return -1;
+ }
+
+ if (argc) {
+ if (matches(*argv, "reclassify") == 0) {
+ sel.action = TC_ACT_RECLASSIFY;
+ argc--;
+ argv++;
+ } else if (matches(*argv, "pipe") == 0) {
+ sel.action = TC_ACT_PIPE;
+ argc--;
+ argv++;
+ } else if (matches(*argv, "drop") == 0 ||
+ matches(*argv, "shot") == 0) {
+ sel.action = TC_ACT_SHOT;
+ argc--;
+ argv++;
+ } else if (matches(*argv, "continue") == 0) {
+ sel.action = TC_ACT_UNSPEC;
+ argc--;
+ argv++;
+ } else if (matches(*argv, "pass") == 0) {
+ sel.action = TC_ACT_OK;
+ argc--;
+ argv++;
+ }
+ }
+
+ if (argc) {
+ if (matches(*argv, "index") == 0) {
+ NEXT_ARG();
+ if (get_u32(&sel.index, *argv, 10)) {
+ fprintf(stderr, "Pedit: Illegal \"index\"\n");
+ return -1;
+ }
+ argc--;
+ argv++;
+ }
+ }
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
+ tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+ *argc_p = argc;
+ *argv_p = argv;
+ return 0;
+}
+
+static int
+print_nat(struct action_util *au,FILE * f, struct rtattr *arg)
+{
+ struct tc_nat *sel;
+ struct rtattr *tb[TCA_NAT_MAX + 1];
+ char buf1[256];
+ char buf2[256];
+ SPRINT_BUF(buf3);
+ int len;
+
+ if (arg == NULL)
+ return -1;
+
+ parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
+
+ if (tb[TCA_NAT_PARMS] == NULL) {
+ fprintf(f, "[NULL nat parameters]");
+ return -1;
+ }
+ sel = RTA_DATA(tb[TCA_NAT_PARMS]);
+
+ len = ffs(sel->mask);
+ len = len ? 33 - len : 0;
+
+ fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
+ "egress" : "ingress",
+ format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
+ len,
+ format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
+ action_n2a(sel->action, buf3, sizeof (buf3)));
+
+ if (show_stats) {
+ if (tb[TCA_NAT_TM]) {
+ struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
+ print_tm(f,tm);
+ }
+ }
+
+ return 0;
+}
+
+struct action_util nat_action_util = {
+ .id = "nat",
+ .parse_aopt = parse_nat,
+ .print_aopt = print_nat,
+};
/*
- * m_pedit.c generic packet editor actions module
+ * m_pedit.c generic packet editor actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
- * TODO:
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
+ * TODO:
* 1) Big endian broken in some spots
* 2) A lot of this stuff was added on the fly; get a big double-double
* and clean it up at some point.
- *
+ *
*/
#include <stdio.h>
int pedit_debug = 1;
static void
-p_explain(void)
+explain(void)
{
- fprintf(stderr, "Usage: ... pedit <MUNGE>\n");
+ fprintf(stderr, "Usage: ... pedit munge <MUNGE>\n");
fprintf(stderr,
- "Where: MUNGE := <RAW>|<LAYERED>\n"
- "<RAW>:= <OFFSETC>[ATC]<CMD>\n "
- "OFFSETC:= offset <offval> <u8|u16|u32>\n "
- "ATC:= at <atval> offmask <maskval> shift <shiftval>\n "
- "NOTE: offval is byte offset, must be multiple of 4\n "
- "NOTE: maskval is a 32 bit hex number\n "
- "NOTE: shiftval is a is a shift value\n "
- "CMD:= clear | invert | set <setval>| retain\n "
- "<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
- " | udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
- "For Example usage look at the examples directory");
+ "Where: MUNGE := <RAW>|<LAYERED>\n"
+ "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n "
+ "\t\tOFFSETC:= offset <offval> <u8|u16|u32>\n "
+ "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n "
+ "\t\tNOTE: offval is byte offset, must be multiple of 4\n "
+ "\t\tNOTE: maskval is a 32 bit hex number\n "
+ "\t\tNOTE: shiftval is a is a shift value\n "
+ "\t\tCMD:= clear | invert | set <setval>| retain\n "
+ "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
+ " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
+ "For Example usage look at the examples directory\n");
}
-#define usage() return(-1)
+static void
+usage(void)
+{
+ explain();
+ exit(-1);
+}
-static int
-pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
+static int
+pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
{
int argc = *argc_p;
char **argv = *argv_p;
}
-struct m_pedit_util
+struct m_pedit_util
*get_pedit_kind(char *str)
{
static void *pBODY;
retain <<= stride;
tkey->mask = retain|m[ind];
tkey->off &= ~3;
-
+
if (pedit_debug)
printf("pack_key8: Final word off %d val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask);
return pack_key(sel,tkey);
} else if (matches(*argv, "preserve") == 0) {
retain = mask = o;
} else {
- if (matches(*argv, "clear") != 0)
+ if (matches(*argv, "clear") != 0)
return -1;
}
tkey->at = atv;
NEXT_ARG();
-
+
if (get_u32(&offmask, *argv, 16))
return -1;
tkey->offmask = offmask;
NEXT_ARG();
res = parse_offset(&argc, &argv,sel,&tkey);
goto done;
-#if jamal
- } else if (strcmp(*argv, "help") == 0) {
- p_explain();
- return -1;
-#endif
} else {
char k[16];
struct m_pedit_util *p = NULL;
NEXT_ARG();
ok++;
continue;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
} else if (matches(*argv, "munge") == 0) {
if (!ok) {
fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
- p_explain();
+ explain();
return -1;
}
NEXT_ARG();
if (parse_munge(&argc, &argv,&sel.sel)) {
fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
- p_explain();
+ explain();
return -1;
}
ok++;
}
if (!ok) {
- p_explain();
+ explain();
return -1;
}
return 0;
}
-int
+int
pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
{
return 0;
/*
- * m_pedit.h generic packet editor actions module
+ * m_pedit.h generic packet editor actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#ifndef _ACT_PEDIT_H_
* 2 of the License, or (at your option) any later version.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- * FIXES: 19990619 - J Hadi Salim (hadi@cyberus.ca)
- * simple addattr packaging fix.
+ * FIXES: 19990619 - J Hadi Salim (hadi@cyberus.ca)
+ * simple addattr packaging fix.
* 2002: J Hadi Salim - Add tc action extensions syntax
*
*/
.print_aopt = print_police,
};
-static void explain(void)
+static void usage(void)
{
fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n");
- fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ]\n");
- fprintf(stderr, " [ ACTIONTERM ]\n");
- fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n");
- fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n");
+ fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n");
+ fprintf(stderr, " [ linklayer TYPE ] [ ACTIONTERM ]\n");
+
+ fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n");
+ fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n");
fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n");
fprintf(stderr, "Where: pipe is only valid for new syntax \n");
+ exit(-1);
}
static void explain1(char *arg)
fprintf(stderr, "Illegal \"%s\"\n", arg);
}
-#define usage() return(-1)
-
-
char *police_action_n2a(int action, char *buf, int len)
{
switch (action) {
__u32 avrate = 0;
int presult = 0;
unsigned buffer=0, mtu=0, mpu=0;
- int Rcell_log=-1, Pcell_log = -1;
+ unsigned short overhead=0;
+ unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
+ int Rcell_log=-1, Pcell_log = -1;
struct rtattr *tail;
memset(&p, 0, sizeof(p));
p.action = TC_POLICE_OK;
} else if (matches(*argv, "pipe") == 0) {
p.action = TC_POLICE_PIPE;
- } else if (strcmp(*argv, "conform-exceed") == 0) {
+ } else if (strcmp(*argv, "action") == 0 ||
+ strcmp(*argv, "conform-exceed") == 0) {
NEXT_ARG();
if (get_police_result(&p.action, &presult, *argv)) {
fprintf(stderr, "Illegal \"action\"\n");
return -1;
}
+ } else if (matches(*argv, "overhead") == 0) {
+ NEXT_ARG();
+ if (get_u16(&overhead, *argv, 10)) {
+ explain1("overhead"); return -1;
+ }
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (get_linklayer(&linklayer, *argv)) {
+ explain1("linklayer"); return -1;
+ }
} else if (strcmp(*argv, "help") == 0) {
- explain();
- return -1;
+ usage();
} else {
break;
}
}
if (p.rate.rate) {
- if ((Rcell_log = tc_calc_rtable(p.rate.rate, rtab, Rcell_log, mtu, mpu)) < 0) {
+ p.rate.mpu = mpu;
+ p.rate.overhead = overhead;
+ if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
fprintf(stderr, "TBF: failed to calculate rate table.\n");
return -1;
}
p.burst = tc_calc_xmittime(p.rate.rate, buffer);
- p.rate.cell_log = Rcell_log;
- p.rate.mpu = mpu;
}
p.mtu = mtu;
if (p.peakrate.rate) {
- if ((Pcell_log = tc_calc_rtable(p.peakrate.rate, ptab, Pcell_log, mtu, mpu)) < 0) {
+ p.peakrate.mpu = mpu;
+ p.peakrate.overhead = overhead;
+ if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
return -1;
}
- p.peakrate.cell_log = Pcell_log;
- p.peakrate.mpu = mpu;
}
tail = NLMSG_TAIL(n);
return act_parse_police(NULL,argc_p,argv_p,tca_id,n);
}
-int
+int
print_police(struct action_util *a, FILE *f, struct rtattr *arg)
{
SPRINT_BUF(b1);
fprintf(f, " police 0x%x ", p->index);
fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1));
- buffer = ((double)p->rate.rate*tc_core_tick2usec(p->burst))/1000000;
+ buffer = tc_calc_xmitsize(p->rate.rate, p->burst);
fprintf(f, "burst %s ", sprint_size(buffer, b1));
fprintf(f, "mtu %s ", sprint_size(p->mtu, b1));
if (show_raw)
fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1)));
} else
fprintf(f, " ");
+ fprintf(f, "overhead %ub ", p->rate.overhead);
fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt);
return 0;
}
-int
+int
tc_print_police(FILE *f, struct rtattr *arg) {
return print_police(&police_action_util,f,arg);
}
--- /dev/null
+/*
+ * m_skbedit.c SKB Editing module
+ *
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors: Alexander Duyck <alexander.h.duyck@intel.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_skbedit.h>
+
+static void
+explain(void)
+{
+ fprintf(stderr, "Usage: ... skbedit "
+ "queue_mapping QUEUE_MAPPING | priority PRIORITY \n"
+ "QUEUE_MAPPING = device transmit queue to use\n"
+ "PRIORITY = classID to assign to priority field\n");
+}
+
+static void
+usage(void)
+{
+ explain();
+ exit(-1);
+}
+
+static int
+parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
+ struct nlmsghdr *n)
+{
+ struct tc_skbedit sel;
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ int ok = 0;
+ struct rtattr *tail;
+ unsigned int tmp;
+ __u16 queue_mapping;
+ __u32 flags = 0, priority;
+
+ if (matches(*argv, "skbedit") != 0)
+ return -1;
+
+ NEXT_ARG();
+
+ while (argc > 0) {
+ if (matches(*argv, "queue_mapping") == 0) {
+ flags |= SKBEDIT_F_QUEUE_MAPPING;
+ NEXT_ARG();
+ if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) {
+ fprintf(stderr, "Illegal queue_mapping\n");
+ return -1;
+ }
+ queue_mapping = tmp;
+ ok++;
+ } else if (matches(*argv, "priority") == 0) {
+ flags |= SKBEDIT_F_PRIORITY;
+ NEXT_ARG();
+ if (get_tc_classid(&priority, *argv)) {
+ fprintf(stderr, "Illegal priority\n");
+ return -1;
+ }
+ ok++;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ break;
+ }
+ argc--;
+ argv++;
+ }
+
+ if (argc) {
+ if (matches(*argv, "reclassify") == 0) {
+ sel.action = TC_ACT_RECLASSIFY;
+ NEXT_ARG();
+ } else if (matches(*argv, "pipe") == 0) {
+ sel.action = TC_ACT_PIPE;
+ NEXT_ARG();
+ } else if (matches(*argv, "drop") == 0 ||
+ matches(*argv, "shot") == 0) {
+ sel.action = TC_ACT_SHOT;
+ NEXT_ARG();
+ } else if (matches(*argv, "continue") == 0) {
+ sel.action = TC_ACT_UNSPEC;
+ NEXT_ARG();
+ } else if (matches(*argv, "pass") == 0) {
+ sel.action = TC_ACT_OK;
+ NEXT_ARG();
+ }
+ }
+
+ if (argc) {
+ if (matches(*argv, "index") == 0) {
+ NEXT_ARG();
+ if (get_u32(&sel.index, *argv, 10)) {
+ fprintf(stderr, "Pedit: Illegal \"index\"\n");
+ return -1;
+ }
+ argc--;
+ argv++;
+ ok++;
+ }
+ }
+
+ if (!ok) {
+ explain();
+ return -1;
+ }
+
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
+ if (flags & SKBEDIT_F_QUEUE_MAPPING)
+ addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
+ &queue_mapping, sizeof(queue_mapping));
+ if (flags & SKBEDIT_F_PRIORITY)
+ addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY,
+ &priority, sizeof(priority));
+ tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+ *argc_p = argc;
+ *argv_p = argv;
+ return 0;
+}
+
+static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
+{
+ struct tc_skbedit *sel;
+ struct rtattr *tb[TCA_SKBEDIT_MAX + 1];
+ SPRINT_BUF(b1);
+ __u32 *priority;
+ __u16 *queue_mapping;
+
+ if (arg == NULL)
+ return -1;
+
+ parse_rtattr_nested(tb, TCA_SKBEDIT_MAX, arg);
+
+ if (tb[TCA_SKBEDIT_PARMS] == NULL) {
+ fprintf(f, "[NULL skbedit parameters]");
+ return -1;
+ }
+
+ sel = RTA_DATA(tb[TCA_SKBEDIT_PARMS]);
+
+ fprintf(f, " skbedit");
+
+ if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
+ queue_mapping = RTA_DATA(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
+ fprintf(f, " queue_mapping %u", *queue_mapping);
+ }
+ if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
+ priority = RTA_DATA(tb[TCA_SKBEDIT_PRIORITY]);
+ fprintf(f, " priority %s", sprint_tc_classid(*priority, b1));
+ }
+
+ if (show_stats) {
+ if (tb[TCA_SKBEDIT_TM]) {
+ struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]);
+ print_tm(f, tm);
+ }
+ }
+
+ return 0;
+}
+
+struct action_util skbedit_action_util = {
+ .id = "skbedit",
+ .parse_aopt = parse_skbedit,
+ .print_aopt = print_skbedit,
+};
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#include <stdio.h>
/*
- * m_pedit.c packet editor: IPV4/6 header
+ * m_pedit.c packet editor: IPV4/6 header
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#include <stdio.h>
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#include <stdio.h>
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ *
*/
#include <stdio.h>
fprintf(stderr, " [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n");
fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
fprintf(stderr, " [ split CLASSID ] [ defmap MASK/CHANGE ]\n");
+ fprintf(stderr, " [ overhead BYTES ] [ linklayer TYPE ]\n");
}
static void explain(void)
struct tc_cbq_lssopt lss;
__u32 rtab[256];
unsigned mpu=0, avpkt=0, allot=0;
- int cell_log=-1;
+ unsigned short overhead=0;
+ unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
+ int cell_log=-1;
int ewma_log=-1;
struct rtattr *tail;
memset(&r, 0, sizeof(r));
while (argc > 0) {
- if (strcmp(*argv, "bandwidth") == 0 ||
- strcmp(*argv, "rate") == 0) {
+ if (matches(*argv, "bandwidth") == 0 ||
+ matches(*argv, "rate") == 0) {
NEXT_ARG();
if (get_rate(&r.rate, *argv)) {
explain1("bandwidth");
return -1;
}
- } else if (strcmp(*argv, "ewma") == 0) {
+ } else if (matches(*argv, "ewma") == 0) {
NEXT_ARG();
if (get_integer(&ewma_log, *argv, 0)) {
explain1("ewma");
fprintf(stderr, "ewma_log must be < 32\n");
return -1;
}
- } else if (strcmp(*argv, "cell") == 0) {
+ } else if (matches(*argv, "cell") == 0) {
unsigned cell;
int i;
NEXT_ARG();
return -1;
}
cell_log = i;
- } else if (strcmp(*argv, "avpkt") == 0) {
+ } else if (matches(*argv, "avpkt") == 0) {
NEXT_ARG();
if (get_size(&avpkt, *argv)) {
explain1("avpkt");
return -1;
}
- } else if (strcmp(*argv, "mpu") == 0) {
+ } else if (matches(*argv, "mpu") == 0) {
NEXT_ARG();
if (get_size(&mpu, *argv)) {
explain1("mpu");
return -1;
}
- } else if (strcmp(*argv, "allot") == 0) {
+ } else if (matches(*argv, "allot") == 0) {
NEXT_ARG();
/* Accept and ignore "allot" for backward compatibility */
if (get_size(&allot, *argv)) {
explain1("allot");
return -1;
}
- } else if (strcmp(*argv, "help") == 0) {
+ } else if (matches(*argv, "overhead") == 0) {
+ NEXT_ARG();
+ if (get_u16(&overhead, *argv, 10)) {
+ explain1("overhead"); return -1;
+ }
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (get_linklayer(&linklayer, *argv)) {
+ explain1("linklayer"); return -1;
+ }
+ } else if (matches(*argv, "help") == 0) {
explain();
return -1;
} else {
if (allot < (avpkt*3)/2)
allot = (avpkt*3)/2;
- if ((cell_log = tc_calc_rtable(r.rate, rtab, cell_log, allot, mpu)) < 0) {
+ r.mpu = mpu;
+ r.overhead = overhead;
+ if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
fprintf(stderr, "CBQ: failed to calculate rate table.\n");
return -1;
}
- r.cell_log = cell_log;
- r.mpu = mpu;
if (ewma_log < 0)
ewma_log = TC_CBQ_DEF_EWMA;
lss.ewma_log = ewma_log;
- lss.maxidle = tc_cbq_calc_maxidle(r.rate, r.rate, avpkt, lss.ewma_log, 0);
+ lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
lss.avpkt = avpkt;
struct tc_cbq_ovl ovl;
__u32 rtab[256];
unsigned mpu=0;
- int cell_log=-1;
+ int cell_log=-1;
int ewma_log=-1;
unsigned bndw = 0;
unsigned minburst=0, maxburst=0;
+ unsigned short overhead=0;
+ unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
memset(&r, 0, sizeof(r));
memset(&ovl, 0, sizeof(ovl));
while (argc > 0) {
- if (strcmp(*argv, "rate") == 0) {
+ if (matches(*argv, "rate") == 0) {
NEXT_ARG();
if (get_rate(&r.rate, *argv)) {
explain1("rate");
return -1;
}
- } else if (strcmp(*argv, "bandwidth") == 0) {
+ } else if (matches(*argv, "bandwidth") == 0) {
NEXT_ARG();
if (get_rate(&bndw, *argv)) {
explain1("bandwidth");
return -1;
}
- } else if (strcmp(*argv, "minidle") == 0) {
+ } else if (matches(*argv, "minidle") == 0) {
NEXT_ARG();
if (get_u32(&lss.minidle, *argv, 0)) {
explain1("minidle");
return -1;
}
lss.change |= TCF_CBQ_LSS_MINIDLE;
- } else if (strcmp(*argv, "minburst") == 0) {
+ } else if (matches(*argv, "minburst") == 0) {
NEXT_ARG();
if (get_u32(&minburst, *argv, 0)) {
explain1("minburst");
return -1;
}
lss.change |= TCF_CBQ_LSS_OFFTIME;
- } else if (strcmp(*argv, "maxburst") == 0) {
+ } else if (matches(*argv, "maxburst") == 0) {
NEXT_ARG();
if (get_u32(&maxburst, *argv, 0)) {
explain1("maxburst");
return -1;
}
lss.change |= TCF_CBQ_LSS_MAXIDLE;
- } else if (strcmp(*argv, "bounded") == 0) {
+ } else if (matches(*argv, "bounded") == 0) {
lss.flags |= TCF_CBQ_LSS_BOUNDED;
lss.change |= TCF_CBQ_LSS_FLAGS;
- } else if (strcmp(*argv, "borrow") == 0) {
+ } else if (matches(*argv, "borrow") == 0) {
lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
lss.change |= TCF_CBQ_LSS_FLAGS;
- } else if (strcmp(*argv, "isolated") == 0) {
+ } else if (matches(*argv, "isolated") == 0) {
lss.flags |= TCF_CBQ_LSS_ISOLATED;
lss.change |= TCF_CBQ_LSS_FLAGS;
- } else if (strcmp(*argv, "sharing") == 0) {
+ } else if (matches(*argv, "sharing") == 0) {
lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
lss.change |= TCF_CBQ_LSS_FLAGS;
- } else if (strcmp(*argv, "ewma") == 0) {
+ } else if (matches(*argv, "ewma") == 0) {
NEXT_ARG();
if (get_integer(&ewma_log, *argv, 0)) {
explain1("ewma");
return -1;
}
lss.change |= TCF_CBQ_LSS_EWMA;
- } else if (strcmp(*argv, "cell") == 0) {
+ } else if (matches(*argv, "cell") == 0) {
unsigned cell;
int i;
NEXT_ARG();
return -1;
}
cell_log = i;
- } else if (strcmp(*argv, "prio") == 0) {
+ } else if (matches(*argv, "prio") == 0) {
unsigned prio;
NEXT_ARG();
if (get_u32(&prio, *argv, 0)) {
}
wrr.priority = prio;
wrr_ok++;
- } else if (strcmp(*argv, "allot") == 0) {
+ } else if (matches(*argv, "allot") == 0) {
NEXT_ARG();
if (get_size(&wrr.allot, *argv)) {
explain1("allot");
return -1;
}
- } else if (strcmp(*argv, "avpkt") == 0) {
+ } else if (matches(*argv, "avpkt") == 0) {
NEXT_ARG();
if (get_size(&lss.avpkt, *argv)) {
explain1("avpkt");
return -1;
}
lss.change |= TCF_CBQ_LSS_AVPKT;
- } else if (strcmp(*argv, "mpu") == 0) {
+ } else if (matches(*argv, "mpu") == 0) {
NEXT_ARG();
if (get_size(&mpu, *argv)) {
explain1("mpu");
return -1;
}
- } else if (strcmp(*argv, "weight") == 0) {
+ } else if (matches(*argv, "weight") == 0) {
NEXT_ARG();
if (get_size(&wrr.weight, *argv)) {
explain1("weight");
return -1;
}
wrr_ok++;
- } else if (strcmp(*argv, "split") == 0) {
+ } else if (matches(*argv, "split") == 0) {
NEXT_ARG();
if (get_tc_classid(&fopt.split, *argv)) {
fprintf(stderr, "Invalid split node ID.\n");
usage();
}
fopt_ok++;
- } else if (strcmp(*argv, "defmap") == 0) {
+ } else if (matches(*argv, "defmap") == 0) {
int err;
NEXT_ARG();
err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
if (err == 1)
fopt.defchange = ~0;
fopt_ok++;
- } else if (strcmp(*argv, "help") == 0) {
+ } else if (matches(*argv, "overhead") == 0) {
+ NEXT_ARG();
+ if (get_u16(&overhead, *argv, 10)) {
+ explain1("overhead"); return -1;
+ }
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (get_linklayer(&linklayer, *argv)) {
+ explain1("linklayer"); return -1;
+ }
+ } else if (matches(*argv, "help") == 0) {
explain_class();
return -1;
} else {
unsigned pktsize = wrr.allot;
if (wrr.allot < (lss.avpkt*3)/2)
wrr.allot = (lss.avpkt*3)/2;
- if ((cell_log = tc_calc_rtable(r.rate, rtab, cell_log, pktsize, mpu)) < 0) {
+ r.mpu = mpu;
+ r.overhead = overhead;
+ if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
fprintf(stderr, "CBQ: failed to calculate rate table.\n");
return -1;
}
- r.cell_log = cell_log;
- r.mpu = mpu;
}
if (ewma_log < 0)
ewma_log = TC_CBQ_DEF_EWMA;
struct tc_cbq_wrropt *wrr = NULL;
struct tc_cbq_fopt *fopt = NULL;
struct tc_cbq_ovl *ovl = NULL;
+ SPRINT_BUF(b1);
if (opt == NULL)
return 0;
if (tb[TCA_CBQ_OVL_STRATEGY]) {
if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
- (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
+ (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
(unsigned) sizeof(*ovl));
else
ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
fprintf(f, "cell %ub ", 1<<r->cell_log);
if (r->mpu)
fprintf(f, "mpu %ub ", r->mpu);
+ if (r->overhead)
+ fprintf(f, "overhead %ub ", r->overhead);
}
}
if (lss && lss->flags) {
if (lss && show_details) {
fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
if (lss->maxidle) {
- fprintf(f, "maxidle %luus ", tc_core_tick2usec(lss->maxidle>>lss->ewma_log));
+ fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
if (show_raw)
fprintf(f, "[%08x] ", lss->maxidle);
}
if (lss->minidle!=0x7fffffff) {
- fprintf(f, "minidle %luus ", tc_core_tick2usec(lss->minidle>>lss->ewma_log));
+ fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
if (show_raw)
fprintf(f, "[%08x] ", lss->minidle);
}
if (lss->offtime) {
- fprintf(f, "offtime %luus ", tc_core_tick2usec(lss->offtime));
+ fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
if (show_raw)
fprintf(f, "[%08x] ", lss->offtime);
}
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim(hadi@nortelnetworks.com)
- * code ruthlessly ripped from
- * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * Authors: J Hadi Salim(hadi@nortelnetworks.com)
+ * code ruthlessly ripped from
+ * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
*/
return -1;
}
return init_gred(qu,argc-1, argv+1,n);
-
+
} else if (strcmp(*argv, "min") == 0) {
NEXT_ARG();
if (get_size(&opt.qth_min, *argv)) {
fprintf(f,"\n GRED received message smaller than expected\n");
return -1;
}
-
+
/* Bad hack! should really return a proper message as shown above*/
for (i=0;i<MAX_DPs;i++, qopt++) {
fprintf(f, "%s ", name);
fprintf(f, "m1 %s ", sprint_rate(sc->m1, b1));
- fprintf(f, "d %s ", sprint_usecs(sc->d, b1));
+ fprintf(f, "d %s ", sprint_time(tc_core_ktime2time(sc->d), b1));
fprintf(f, "m2 %s ", sprint_rate(sc->m2, b1));
}
usc = RTA_DATA(tb[TCA_HFSC_USC]);
}
-
+
if (rsc != NULL && fsc != NULL &&
memcmp(rsc, fsc, sizeof(*rsc)) == 0)
hfsc_print_sc(f, "sc", rsc);
return 0;
}
-
+
struct qdisc_util hfsc_qdisc_util = {
.id = "hfsc",
.parse_qopt = hfsc_parse_opt,
if (matches(*argv, "d") == 0) {
NEXT_ARG();
- if (get_usecs(&d, *argv) < 0) {
+ if (get_time(&d, *argv) < 0) {
explain1("d");
return -1;
}
return -1;
sc->m1 = m1;
- sc->d = d;
+ sc->d = tc_core_time2ktime(d);
sc->m2 = m2;
*argvp = argv;
if (matches(*argv, "dmax") == 0) {
NEXT_ARG();
- if (get_usecs(&dmax, *argv) < 0) {
+ if (get_time(&dmax, *argv) < 0) {
explain1("dmax");
return -1;
}
return -1;
}
- if (dmax != 0 && ceil(umax * 1000000.0 / dmax) > rate) {
+ if (dmax != 0 && ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax) > rate) {
/*
* concave curve, slope of first segment is umax/dmax,
* intersection is at dmax
*/
- sc->m1 = ceil(umax * 1000000.0 / dmax); /* in bps */
- sc->d = dmax;
+ sc->m1 = ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax); /* in bps */
+ sc->d = tc_core_time2ktime(dmax);
sc->m2 = rate;
} else {
/*
* is at dmax - umax / rate
*/
sc->m1 = 0;
- sc->d = ceil(dmax - umax * 1000000.0 / rate); /* in usec */
+ sc->d = tc_core_time2ktime(ceil(dmax - umax * TIME_UNITS_PER_SEC / rate));
sc->m2 = rate;
}
" burst max bytes burst which can be accumulated during idle period {computed}\n"
" mpu minimum packet size used in rate computations\n"
" overhead per-packet size overhead used in rate computations\n"
-
+ " linklay adapting to a linklayer e.g. atm\n"
" ceil definite upper class rate (no borrows) {rate}\n"
" cburst burst but for ceil {computed}\n"
" mtu max packet size we create rate map for {1600}\n"
__u32 rtab[256],ctab[256];
unsigned buffer=0,cbuffer=0;
int cell_log=-1,ccell_log = -1;
- unsigned mtu, mpu;
- unsigned char mpu8 = 0, overhead = 0;
+ unsigned mtu;
+ unsigned short mpu = 0;
+ unsigned short overhead = 0;
+ unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
}
} else if (matches(*argv, "mpu") == 0) {
NEXT_ARG();
- if (get_u8(&mpu8, *argv, 10)) {
+ if (get_u16(&mpu, *argv, 10)) {
explain1("mpu"); return -1;
}
} else if (matches(*argv, "overhead") == 0) {
NEXT_ARG();
- if (get_u8(&overhead, *argv, 10)) {
+ if (get_u16(&overhead, *argv, 10)) {
explain1("overhead"); return -1;
}
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (get_linklayer(&linklayer, *argv)) {
+ explain1("linklayer"); return -1;
+ }
} else if (matches(*argv, "quantum") == 0) {
NEXT_ARG();
if (get_u32(&opt.quantum, *argv, 10)) {
if (!buffer) buffer = opt.rate.rate / get_hz() + mtu;
if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu;
-/* encode overhead and mpu, 8 bits each, into lower 16 bits */
- mpu = (unsigned)mpu8 | (unsigned)overhead << 8;
- opt.ceil.mpu = mpu; opt.rate.mpu = mpu;
+ opt.ceil.overhead = overhead;
+ opt.rate.overhead = overhead;
- if ((cell_log = tc_calc_rtable(opt.rate.rate, rtab, cell_log, mtu, mpu)) < 0) {
+ opt.ceil.mpu = mpu;
+ opt.rate.mpu = mpu;
+
+ if (tc_calc_rtable(&opt.rate, rtab, cell_log, mtu, linklayer) < 0) {
fprintf(stderr, "htb: failed to calculate rate table.\n");
return -1;
}
opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
- opt.rate.cell_log = cell_log;
-
- if ((ccell_log = tc_calc_rtable(opt.ceil.rate, ctab, cell_log, mtu, mpu)) < 0) {
+
+ if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
fprintf(stderr, "htb: failed to calculate ceil rate table.\n");
return -1;
}
opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer);
- opt.ceil.cell_log = ccell_log;
tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
fprintf(f, "quantum %d ", (int)hopt->quantum);
}
fprintf(f, "rate %s ", sprint_rate(hopt->rate.rate, b1));
- buffer = ((double)hopt->rate.rate*tc_core_tick2usec(hopt->buffer))/1000000;
+ buffer = tc_calc_xmitsize(hopt->rate.rate, hopt->buffer);
fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1));
- cbuffer = ((double)hopt->ceil.rate*tc_core_tick2usec(hopt->cbuffer))/1000000;
+ cbuffer = tc_calc_xmitsize(hopt->ceil.rate, hopt->cbuffer);
if (show_details) {
fprintf(f, "burst %s/%u mpu %s overhead %s ",
sprint_size(buffer, b1),
fprintf(f, "cburst %s ", sprint_size(cbuffer, b1));
}
if (show_raw)
- fprintf(f, "buffer [%08x] cbuffer [%08x] ",
+ fprintf(f, "buffer [%08x] cbuffer [%08x] ",
hopt->buffer,hopt->cbuffer);
}
if (tb[TCA_HTB_INIT]) {
gopt = RTA_DATA(tb[TCA_HTB_INIT]);
if (RTA_PAYLOAD(tb[TCA_HTB_INIT]) < sizeof(*gopt)) return -1;
- fprintf(f, "r2q %d default %x direct_packets_stat %u",
+ fprintf(f, "r2q %d default %x direct_packets_stat %u",
gopt->rate2quantum,gopt->defcls,gopt->direct_pkts);
if (show_details)
fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff);
return -1;
st = RTA_DATA(xstats);
- fprintf(f, " lended: %u borrowed: %u giants: %u\n",
+ fprintf(f, " lended: %u borrowed: %u giants: %u\n",
st->lends,st->borrows,st->giants);
fprintf(f, " tokens: %d ctokens: %d\n", st->tokens,st->ctokens);
return 0;
--- /dev/null
+/*
+ * q_multiq.c Multiqueue aware qdisc
+ *
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ *
+ * Original Authors: PJ Waskiewicz, <peter.p.waskiewicz.jr@intel.com> (RR)
+ * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (from PRIO)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+ fprintf(stderr, "Usage: ... multiq [help]\n");
+}
+
+#define usage() return(-1)
+
+static int multiq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct tc_multiq_qopt opt;
+
+ if (argc > 0) {
+ if (strcmp(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--; argv++;
+ }
+
+ addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+ return 0;
+}
+
+int multiq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ struct tc_multiq_qopt *qopt;
+
+ if (opt == NULL)
+ return 0;
+ if (RTA_PAYLOAD(opt) < sizeof(*qopt))
+ return 0;
+
+ qopt = RTA_DATA(opt);
+
+ fprintf(f, "bands %u/%u ", qopt->bands, qopt->max_bands);
+
+ return 0;
+}
+
+struct qdisc_util multiq_qdisc_util = {
+ .id = "multiq",
+ .parse_qopt = multiq_parse_opt,
+ .print_qopt = multiq_print_opt,
+};
static void explain(void)
{
- fprintf(stderr,
+ fprintf(stderr,
"Usage: ... netem [ limit PACKETS ] \n" \
" [ delay TIME [ JITTER [CORRELATION]]]\n" \
" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
#define usage() return(-1)
+/* Upper bound on size of distribution
+ * really (TCA_BUF_MAX - other headers) / sizeof (__s16)
+ */
+#define MAX_DIST (16*1024)
+
/*
* Simplistic file parser for distrbution data.
* Format is:
* # comment line(s)
- * data0 data1
+ * data0 data1 ...
*/
-#define MAXDIST 65536
-static int get_distribution(const char *type, __s16 *data)
+static int get_distribution(const char *type, __s16 *data, int maxdata)
{
FILE *f;
int n;
char *line = NULL;
char name[128];
- snprintf(name, sizeof(name), "/usr/lib/tc/%s.dist", type);
+ snprintf(name, sizeof(name), "%s/%s.dist", get_tc_lib(), type);
if ((f = fopen(name, "r")) == NULL) {
- fprintf(stderr, "No distribution data for %s (%s: %s)\n",
+ fprintf(stderr, "No distribution data for %s (%s: %s)\n",
type, name, strerror(errno));
return -1;
}
-
+
n = 0;
while (getline(&line, &len, f) != -1) {
char *p, *endp;
for (p = line; ; p = endp) {
x = strtol(p, &endp, 0);
- if (endp == p)
+ if (endp == p)
break;
- if (n >= MAXDIST) {
+ if (n >= maxdata) {
fprintf(stderr, "%s: too much data\n",
name);
n = -1;
return n;
}
-static int isnumber(const char *arg)
+static int isnumber(const char *arg)
{
char *p;
(void) strtod(arg, &p);
#define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1]))
-/* Adjust for the fact that psched_ticks aren't always usecs
+/* Adjust for the fact that psched_ticks aren't always usecs
(based on kernel PSCHED_CLOCK configuration */
static int get_ticks(__u32 *ticks, const char *str)
{
unsigned t;
- if(get_usecs(&t, str))
+ if(get_time(&t, str))
return -1;
-
- *ticks = tc_core_usec2tick(t);
- return 0;
-}
-static char *sprint_ticks(__u32 ticks, char *buf)
-{
- return sprint_usecs(tc_core_tick2usec(ticks), buf);
-}
+ if (tc_core_time2big(t)) {
+ fprintf(stderr, "Illegal %u time (too large)\n", t);
+ return -1;
+ }
+ *ticks = tc_core_time2tick(t);
+ return 0;
+}
-static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n)
{
size_t dist_size = 0;
struct tc_netem_reorder reorder;
struct tc_netem_corrupt corrupt;
__s16 *dist_data = NULL;
+ int present[__TCA_NETEM_MAX];
memset(&opt, 0, sizeof(opt));
opt.limit = 1000;
memset(&cor, 0, sizeof(cor));
memset(&reorder, 0, sizeof(reorder));
memset(&corrupt, 0, sizeof(corrupt));
+ memset(present, 0, sizeof(present));
while (argc > 0) {
if (matches(*argv, "limit") == 0) {
if (NEXT_IS_NUMBER()) {
NEXT_ARG();
- if (get_percent(&cor.delay_corr,
- *argv)) {
+ ++present[TCA_NETEM_CORR];
+ if (get_percent(&cor.delay_corr, *argv)) {
explain1("latency");
return -1;
}
}
if (NEXT_IS_NUMBER()) {
NEXT_ARG();
+ ++present[TCA_NETEM_CORR];
if (get_percent(&cor.loss_corr, *argv)) {
explain1("loss");
return -1;
}
} else if (matches(*argv, "reorder") == 0) {
NEXT_ARG();
+ present[TCA_NETEM_REORDER] = 1;
if (get_percent(&reorder.probability, *argv)) {
explain1("reorder");
return -1;
}
if (NEXT_IS_NUMBER()) {
NEXT_ARG();
+ ++present[TCA_NETEM_CORR];
if (get_percent(&reorder.correlation, *argv)) {
explain1("reorder");
return -1;
}
} else if (matches(*argv, "corrupt") == 0) {
NEXT_ARG();
+ present[TCA_NETEM_CORRUPT] = 1;
if (get_percent(&corrupt.probability, *argv)) {
explain1("corrupt");
return -1;
}
if (NEXT_IS_NUMBER()) {
NEXT_ARG();
+ ++present[TCA_NETEM_CORR];
if (get_percent(&corrupt.correlation, *argv)) {
explain1("corrupt");
return -1;
}
} else if (matches(*argv, "distribution") == 0) {
NEXT_ARG();
- dist_data = alloca(MAXDIST);
- dist_size = get_distribution(*argv, dist_data);
- if (dist_size < 0)
+ dist_data = calloc(sizeof(dist_data[0]), MAX_DIST);
+ dist_size = get_distribution(*argv, dist_data, MAX_DIST);
+ if (dist_size <= 0) {
+ free(dist_data);
return -1;
+ }
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
return -1;
}
- if (addattr_l(n, TCA_BUF_MAX, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
+ if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
return -1;
- if (cor.delay_corr || cor.loss_corr || cor.dup_corr) {
- if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
+ if (present[TCA_NETEM_CORR] &&
+ addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
return -1;
- }
- if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
+ if (present[TCA_NETEM_REORDER] &&
+ addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
return -1;
- if (corrupt.probability) {
- if (addattr_l(n, TCA_BUF_MAX, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
- return -1;
- }
+ if (present[TCA_NETEM_CORRUPT] &&
+ addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
+ return -1;
if (dist_data) {
- if (addattr_l(n, 32768, TCA_NETEM_DELAY_DIST,
- dist_data, dist_size*sizeof(dist_data[0])) < 0)
+ if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]),
+ TCA_NETEM_DELAY_DIST,
+ dist_data, dist_size * sizeof(dist_data[0])) < 0)
return -1;
+ free(dist_data);
}
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
return 0;
struct rtattr *tb[TCA_NETEM_MAX+1];
parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt),
len);
-
+
if (tb[TCA_NETEM_CORR]) {
if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor))
return -1;
if (cor && cor->dup_corr)
fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
}
-
+
if (reorder && reorder->probability) {
- fprintf(f, " reorder %s",
+ fprintf(f, " reorder %s",
sprint_percent(reorder->probability, b1));
if (reorder->correlation)
- fprintf(f, " %s",
+ fprintf(f, " %s",
sprint_percent(reorder->correlation, b1));
}
if (corrupt && corrupt->probability) {
- fprintf(f, " corrupt %s",
+ fprintf(f, " corrupt %s",
sprint_percent(corrupt->probability, b1));
if (corrupt->correlation)
- fprintf(f, " %s",
+ fprintf(f, " %s",
sprint_percent(corrupt->correlation, b1));
}
static void explain(void)
{
- fprintf(stderr, "Usage: ... prio bands NUMBER priomap P1 P2...\n");
+ fprintf(stderr, "Usage: ... prio bands NUMBER priomap P1 P2...[multiqueue]\n");
}
#define usage() return(-1)
int pmap_mode = 0;
int idx = 0;
struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }};
+ struct rtattr *nest;
+ unsigned char mq = 0;
while (argc > 0) {
if (strcmp(*argv, "bands") == 0) {
return -1;
}
pmap_mode = 1;
+ } else if (strcmp(*argv, "multiqueue") == 0) {
+ mq = 1;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
opt.priomap[idx] = opt.priomap[TC_PRIO_BESTEFFORT];
}
*/
- addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+ nest = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+ if (mq)
+ addattr_l(n, 1024, TCA_PRIO_MQ, NULL, 0);
+ addattr_nest_compat_end(n, nest);
return 0;
}
{
int i;
struct tc_prio_qopt *qopt;
+ struct rtattr *tb[TCA_PRIO_MAX+1];
if (opt == NULL)
return 0;
- if (RTA_PAYLOAD(opt) < sizeof(*qopt))
- return -1;
- qopt = RTA_DATA(opt);
+ if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
+ sizeof(*qopt)))
+ return -1;
+
fprintf(f, "bands %u priomap ", qopt->bands);
for (i=0; i<=TC_PRIO_MAX; i++)
fprintf(f, " %d", qopt->priomap[i]);
+
+ if (tb[TCA_PRIO_MQ])
+ fprintf(f, " multiqueue: %s ",
+ *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "on" : "off");
+
return 0;
}
fprintf(f, " marked %u early %u pdrop %u other %u",
st->marked, st->early, st->pdrop, st->other);
return 0;
-
+
#endif
return 0;
}
--- /dev/null
+/*
+ * q_rr.c RR.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: PJ Waskiewicz, <peter.p.waskiewicz.jr@intel.com>
+ * Original Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (from PRIO)
+ *
+ * Changes:
+ *
+ * Ole Husgaard <sparre@login.dknet.dk>: 990513: prio2band map was always reset.
+ * J Hadi Salim <hadi@cyberus.ca>: 990609: priomap fix.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+ fprintf(stderr, "Usage: ... rr bands NUMBER priomap P1 P2... [multiqueue]\n");
+}
+
+#define usage() return(-1)
+
+static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
+{
+ int ok = 0;
+ int pmap_mode = 0;
+ int idx = 0;
+ struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }};
+ struct rtattr *nest;
+ unsigned char mq = 0;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "bands") == 0) {
+ if (pmap_mode)
+ explain();
+ NEXT_ARG();
+ if (get_integer(&opt.bands, *argv, 10)) {
+ fprintf(stderr, "Illegal \"bands\"\n");
+ return -1;
+ }
+ ok++;
+ } else if (strcmp(*argv, "priomap") == 0) {
+ if (pmap_mode) {
+ fprintf(stderr, "Error: duplicate priomap\n");
+ return -1;
+ }
+ pmap_mode = 1;
+ } else if (strcmp(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else if (strcmp(*argv, "multiqueue") == 0) {
+ mq = 1;
+ } else {
+ unsigned band;
+ if (!pmap_mode) {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ if (get_unsigned(&band, *argv, 10)) {
+ fprintf(stderr, "Illegal \"priomap\" element\n");
+ return -1;
+ }
+ if (band > opt.bands) {
+ fprintf(stderr, "\"priomap\" element is out of bands\n");
+ return -1;
+ }
+ if (idx > TC_PRIO_MAX) {
+ fprintf(stderr, "\"priomap\" index > TC_RR_MAX=%u\n", TC_PRIO_MAX);
+ return -1;
+ }
+ opt.priomap[idx++] = band;
+ }
+ argc--; argv++;
+ }
+
+ nest = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+ if (mq)
+ addattr_l(n, 1024, TCA_PRIO_MQ, NULL, 0);
+ addattr_nest_compat_end(n, nest);
+ return 0;
+}
+
+int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ int i;
+ struct tc_prio_qopt *qopt;
+ struct rtattr *tb[TCA_PRIO_MAX + 1];
+
+ if (opt == NULL)
+ return 0;
+
+ if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
+ sizeof(*qopt)))
+ return -1;
+
+ fprintf(f, "bands %u priomap ", qopt->bands);
+ for (i=0; i <= TC_PRIO_MAX; i++)
+ fprintf(f, " %d", qopt->priomap[i]);
+
+ if (tb[TCA_PRIO_MQ])
+ fprintf(f, " multiqueue: %s ",
+ *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "on" : "off");
+
+ return 0;
+}
+
+struct qdisc_util rr_qdisc_util = {
+ .id = "rr",
+ .parse_qopt = rr_parse_opt,
+ .print_qopt = rr_print_opt,
+};
return 0;
}
+static int sfq_print_xstats(struct qdisc_util *qu, FILE *f,
+ struct rtattr *xstats)
+{
+ struct tc_sfq_xstats *st;
+
+ if (xstats == NULL)
+ return 0;
+ if (RTA_PAYLOAD(xstats) < sizeof(*st))
+ return -1;
+ st = RTA_DATA(xstats);
+
+ fprintf(f, " allot %d ", st->allot);
+ fprintf(f, "\n");
+ return 0;
+}
+
struct qdisc_util sfq_qdisc_util = {
.id = "sfq",
.parse_qopt = sfq_parse_opt,
.print_qopt = sfq_print_opt,
+ .print_xstats = sfq_print_xstats,
};
static void explain(void)
{
fprintf(stderr, "Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ]\n");
- fprintf(stderr, " [ peakrate KBPS ] [ latency TIME ]\n");
+ fprintf(stderr, " [ peakrate KBPS ] [ latency TIME ] ");
+ fprintf(stderr, "[ overhead BYTES ] [ linklayer TYPE ]\n");
}
static void explain1(char *arg)
__u32 rtab[256];
__u32 ptab[256];
unsigned buffer=0, mtu=0, mpu=0, latency=0;
- int Rcell_log=-1, Pcell_log = -1;
+ int Rcell_log=-1, Pcell_log = -1;
+ unsigned short overhead=0;
+ unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
memset(&opt, 0, sizeof(opt));
fprintf(stderr, "Double \"limit/latency\" spec\n");
return -1;
}
- if (get_usecs(&latency, *argv)) {
+ if (get_time(&latency, *argv)) {
explain1("latency");
return -1;
}
return -1;
}
ok++;
+ } else if (matches(*argv, "overhead") == 0) {
+ NEXT_ARG();
+ if (overhead) {
+ fprintf(stderr, "Double \"overhead\" spec\n");
+ return -1;
+ }
+ if (get_u16(&overhead, *argv, 10)) {
+ explain1("overhead"); return -1;
+ }
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (get_linklayer(&linklayer, *argv)) {
+ explain1("linklayer"); return -1;
+ }
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
}
if (opt.limit == 0) {
- double lim = opt.rate.rate*(double)latency/1000000 + buffer;
+ double lim = opt.rate.rate*(double)latency/TIME_UNITS_PER_SEC + buffer;
if (opt.peakrate.rate) {
- double lim2 = opt.peakrate.rate*(double)latency/1000000 + mtu;
+ double lim2 = opt.peakrate.rate*(double)latency/TIME_UNITS_PER_SEC + mtu;
if (lim2 < lim)
lim = lim2;
}
opt.limit = lim;
}
- if ((Rcell_log = tc_calc_rtable(opt.rate.rate, rtab, Rcell_log, mtu, mpu)) < 0) {
+ opt.rate.mpu = mpu;
+ opt.rate.overhead = overhead;
+ if (tc_calc_rtable(&opt.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
fprintf(stderr, "TBF: failed to calculate rate table.\n");
return -1;
}
opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
- opt.rate.cell_log = Rcell_log;
- opt.rate.mpu = mpu;
+
if (opt.peakrate.rate) {
- if ((Pcell_log = tc_calc_rtable(opt.peakrate.rate, ptab, Pcell_log, mtu, mpu)) < 0) {
+ opt.peakrate.mpu = mpu;
+ opt.peakrate.overhead = overhead;
+ if (tc_calc_rtable(&opt.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
fprintf(stderr, "TBF: failed to calculate peak rate table.\n");
return -1;
}
opt.mtu = tc_calc_xmittime(opt.peakrate.rate, mtu);
- opt.peakrate.cell_log = Pcell_log;
- opt.peakrate.mpu = mpu;
}
tail = NLMSG_TAIL(n);
if (RTA_PAYLOAD(tb[TCA_TBF_PARMS]) < sizeof(*qopt))
return -1;
fprintf(f, "rate %s ", sprint_rate(qopt->rate.rate, b1));
- buffer = ((double)qopt->rate.rate*tc_core_tick2usec(qopt->buffer))/1000000;
+ buffer = tc_calc_xmitsize(qopt->rate.rate, qopt->buffer);
if (show_details) {
fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1),
1<<qopt->rate.cell_log, sprint_size(qopt->rate.mpu, b2));
if (qopt->peakrate.rate) {
fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate.rate, b1));
if (qopt->mtu || qopt->peakrate.mpu) {
- mtu = ((double)qopt->peakrate.rate*tc_core_tick2usec(qopt->mtu))/1000000;
+ mtu = tc_calc_xmitsize(qopt->peakrate.rate, qopt->mtu);
if (show_details) {
fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1),
1<<qopt->peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2));
if (show_raw)
fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
- latency = 1000000*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2usec(qopt->buffer);
+ latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2time(qopt->buffer);
if (qopt->peakrate.rate) {
- double lat2 = 1000000*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2usec(qopt->mtu);
+ double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2time(qopt->mtu);
if (lat2 > latency)
latency = lat2;
}
- fprintf(f, "lat %s ", sprint_usecs(tc_core_tick2usec(latency), b1));
+ fprintf(f, "lat %s ", sprint_time(latency, b1));
+
+ if (qopt->rate.overhead) {
+ fprintf(f, "overhead %d", qopt->rate.overhead);
+ }
return 0;
}
int show_stats = 0;
int show_details = 0;
int show_raw = 0;
+int show_pretty = 0;
+
int resolve_hosts = 0;
int use_iec = 0;
int force = 0;
static struct qdisc_util * qdisc_list;
static struct filter_util * filter_list;
-static int print_noqopt(struct qdisc_util *qu, FILE *f,
+static int print_noqopt(struct qdisc_util *qu, FILE *f,
struct rtattr *opt)
{
if (opt && RTA_PAYLOAD(opt))
- fprintf(f, "[Unknown qdisc, optlen=%u] ",
+ fprintf(f, "[Unknown qdisc, optlen=%u] ",
(unsigned) RTA_PAYLOAD(opt));
return 0;
}
static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle)
{
if (opt && RTA_PAYLOAD(opt))
- fprintf(f, "fh %08x [Unknown filter, optlen=%u] ",
+ fprintf(f, "fh %08x [Unknown filter, optlen=%u] ",
fhandle, (unsigned) RTA_PAYLOAD(opt));
else if (fhandle)
fprintf(f, "fh %08x ", fhandle);
if (strcmp(q->id, str) == 0)
return q;
- snprintf(buf, sizeof(buf), "/usr/lib/tc/q_%s.so", str);
+ snprintf(buf, sizeof(buf), "%s/q_%s.so", get_tc_lib(), str);
dlh = dlopen(buf, RTLD_LAZY);
if (!dlh) {
/* look in current binary, only open once */
if (strcmp(q->id, str) == 0)
return q;
- snprintf(buf, sizeof(buf), "/usr/lib/tc/f_%s.so", str);
+ snprintf(buf, sizeof(buf), "%s/f_%s.so", get_tc_lib(), str);
dlh = dlopen(buf, RTLD_LAZY);
if (dlh == NULL) {
dlh = BODY;
{
fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
" tc [-force] -batch file\n"
- "where OBJECT := { qdisc | class | filter | action }\n"
- " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [file] }\n");
+ "where OBJECT := { qdisc | class | filter | action | monitor }\n"
+ " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [file] }\n");
}
static int do_cmd(int argc, char **argv)
if (matches(*argv, "actions") == 0)
return do_action(argc-1, argv+1);
+ if (matches(*argv, "monitor") == 0)
+ return do_tcmonitor(argc-1, argv+1);
+
if (matches(*argv, "help") == 0) {
usage();
return 0;
}
-
- fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n",
+
+ fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n",
*argv);
return -1;
}
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;
}
++show_details;
} else if (matches(argv[1], "-raw") == 0) {
++show_raw;
+ } else if (matches(argv[1], "-pretty") == 0) {
+ ++show_pretty;
} else if (matches(argv[1], "-Version") == 0) {
printf("tc utility, iproute2-ss%s\n", SNAPSHOT);
return 0;
if (vxmt > maxidle)
maxidle = vxmt;
}
- return tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000);
+ return tc_core_time2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC);
}
unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt,
offtime *= pow(g, -(double)minburst) - 1;
else
offtime *= 1 + (pow(g, -(double)(minburst-1)) - 1)/(1-g);
- return tc_core_usec2tick(offtime*1000000);
+ return tc_core_time2tick(offtime*TIME_UNITS_PER_SEC);
}
static void usage(void)
{
- fprintf(stderr, "Usage: tc class [ add | del | change | get ] dev STRING\n");
+ fprintf(stderr, "Usage: tc class [ add | del | change | replace | show ] dev STRING\n");
fprintf(stderr, " [ classid CLASSID ] [ root | parent CLASSID ]\n");
fprintf(stderr, " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n");
fprintf(stderr, "\n");
int filter_ifindex;
__u32 filter_qdisc;
-static int print_class(const struct sockaddr_nl *who,
+int print_class(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE*)arg;
fprintf(fp, "\n");
if (show_stats) {
struct rtattr *xstats = NULL;
-
+
if (tb[TCA_STATS] || tb[TCA_STATS2]) {
print_tcstats_attr(fp, tb, " ", &xstats);
fprintf(fp, "\n");
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return tc_class_list(argc-1, argv+1);
- if (matches(*argv, "help") == 0)
+ if (matches(*argv, "help") == 0) {
usage();
+ return 0;
+ }
fprintf(stderr, "Command \"%s\" is unknown, try \"tc class help\".\n", *argv);
return -1;
}
extern int do_class(int argc, char **argv);
extern int do_filter(int argc, char **argv);
extern int do_action(int argc, char **argv);
+extern int do_tcmonitor(int argc, char **argv);
+extern int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta);
struct tc_estimator;
extern int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est);
+
+struct tc_sizespec;
+extern int parse_size_table(int *p_argc, char ***p_argv, struct tc_sizespec *s);
+extern int check_size_table_opts(struct tc_sizespec *s);
#include <string.h>
#include "tc_core.h"
+#include <linux/atm.h>
-static __u32 t2us=1;
-static __u32 us2t=1;
static double tick_in_usec = 1;
+static double clock_factor = 1;
-long tc_core_usec2tick(long usec)
+int tc_core_time2big(unsigned time)
{
- return usec*tick_in_usec;
+ __u64 t = time;
+
+ t *= tick_in_usec;
+ return (t >> 32) != 0;
+}
+
+
+unsigned tc_core_time2tick(unsigned time)
+{
+ return time*tick_in_usec;
}
-long tc_core_tick2usec(long tick)
+unsigned tc_core_tick2time(unsigned tick)
{
return tick/tick_in_usec;
}
+unsigned tc_core_time2ktime(unsigned time)
+{
+ return time * clock_factor;
+}
+
+unsigned tc_core_ktime2time(unsigned ktime)
+{
+ return ktime / clock_factor;
+}
+
unsigned tc_calc_xmittime(unsigned rate, unsigned size)
{
- return tc_core_usec2tick(1000000*((double)size/rate));
+ return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/rate));
+}
+
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
+{
+ return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC;
+}
+
+/*
+ * The align to ATM cells is used for determining the (ATM) SAR
+ * alignment overhead at the ATM layer. (SAR = Segmentation And
+ * Reassembly). This is for example needed when scheduling packet on
+ * an ADSL connection. Note that the extra ATM-AAL overhead is _not_
+ * included in this calculation. This overhead is added in the kernel
+ * before doing the rate table lookup, as this gives better precision
+ * (as the table will always be aligned for 48 bytes).
+ * --Hawk, d.7/11-2004. <hawk@diku.dk>
+ */
+unsigned tc_align_to_atm(unsigned size)
+{
+ int linksize, cells;
+ cells = size / ATM_CELL_PAYLOAD;
+ if ((size % ATM_CELL_PAYLOAD) > 0)
+ cells++;
+
+ linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
+ return linksize;
+}
+
+unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linklayer)
+{
+ if (sz < mpu)
+ sz = mpu;
+
+ switch (linklayer) {
+ case LINKLAYER_ATM:
+ return tc_align_to_atm(sz);
+ case LINKLAYER_ETHERNET:
+ default:
+ // No size adjustments on Ethernet
+ return sz;
+ }
}
/*
rtab[pkt_len>>cell_log] = pkt_xmit_time
*/
-int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu,
- unsigned mpu)
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+ int cell_log, unsigned mtu,
+ enum link_layer linklayer)
{
int i;
- unsigned overhead = (mpu >> 8) & 0xFF;
- mpu = mpu & 0xFF;
+ unsigned sz;
+ unsigned bps = r->rate;
+ unsigned mpu = r->mpu;
if (mtu == 0)
mtu = 2047;
if (cell_log < 0) {
cell_log = 0;
- while ((mtu>>cell_log) > 255)
+ while ((mtu >> cell_log) > 255)
cell_log++;
}
+
for (i=0; i<256; i++) {
- unsigned sz = (i<<cell_log);
- if (overhead)
- sz += overhead;
- if (sz < mpu)
- sz = mpu;
- rtab[i] = tc_core_usec2tick(1000000*((double)sz/bps));
+ sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer);
+ rtab[i] = tc_calc_xmittime(bps, sz);
}
+
+ r->cell_align=-1; // Due to the sz calc
+ r->cell_log=cell_log;
return cell_log;
}
+/*
+ stab[pkt_len>>cell_log] = pkt_xmit_size>>size_log
+ */
+
+int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab)
+{
+ int i;
+ enum link_layer linklayer = s->linklayer;
+ unsigned int sz;
+
+ if (linklayer <= LINKLAYER_ETHERNET && s->mpu == 0) {
+ /* don't need data table in this case (only overhead set) */
+ s->mtu = 0;
+ s->tsize = 0;
+ s->cell_log = 0;
+ s->cell_align = 0;
+ *stab = NULL;
+ return 0;
+ }
+
+ if (s->mtu == 0)
+ s->mtu = 2047;
+ if (s->tsize == 0)
+ s->tsize = 512;
+
+ s->cell_log = 0;
+ while ((s->mtu >> s->cell_log) > s->tsize - 1)
+ s->cell_log++;
+
+ *stab = malloc(s->tsize * sizeof(__u16));
+ if (!*stab)
+ return -1;
+
+again:
+ for (i = s->tsize - 1; i >= 0; i--) {
+ sz = tc_adjust_size((i + 1) << s->cell_log, s->mpu, linklayer);
+ if ((sz >> s->size_log) > UINT16_MAX) {
+ s->size_log++;
+ goto again;
+ }
+ (*stab)[i] = sz >> s->size_log;
+ }
+
+ s->cell_align = -1; // Due to the sz calc
+ return 0;
+}
+
int tc_core_init()
{
- FILE *fp = fopen("/proc/net/psched", "r");
+ FILE *fp;
+ __u32 clock_res;
+ __u32 t2us;
+ __u32 us2t;
+ fp = fopen("/proc/net/psched", "r");
if (fp == NULL)
return -1;
- if (fscanf(fp, "%08x%08x", &t2us, &us2t) != 2) {
+ if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) {
fclose(fp);
return -1;
}
fclose(fp);
- tick_in_usec = (double)t2us/us2t;
+
+ /* compatibility hack: for old iproute binaries (ignoring
+ * the kernel clock resolution) the kernel advertises a
+ * tick multiplier of 1000 in case of nano-second resolution,
+ * which really is 1. */
+ if (clock_res == 1000000000)
+ t2us = us2t;
+
+ clock_factor = (double)clock_res / TIME_UNITS_PER_SEC;
+ tick_in_usec = (double)t2us / us2t * clock_factor;
return 0;
}
#include <asm/types.h>
#include <linux/pkt_sched.h>
-long tc_core_usec2tick(long usec);
-long tc_core_tick2usec(long tick);
+#define TIME_UNITS_PER_SEC 1000000
+
+enum link_layer {
+ LINKLAYER_UNSPEC,
+ LINKLAYER_ETHERNET,
+ LINKLAYER_ATM,
+};
+
+
+int tc_core_time2big(unsigned time);
+unsigned tc_core_time2tick(unsigned time);
+unsigned tc_core_tick2time(unsigned tick);
+unsigned tc_core_time2ktime(unsigned time);
+unsigned tc_core_ktime2time(unsigned ktime);
unsigned tc_calc_xmittime(unsigned rate, unsigned size);
-int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu, unsigned mpu);
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+ int cell_log, unsigned mtu, enum link_layer link_layer);
+int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab);
int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est);
int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est)
{
for (est->interval=0; est->interval<=5; est->interval++) {
- if (A <= (1<<est->interval)*(1000000/4))
+ if (A <= (1<<est->interval)*(TIME_UNITS_PER_SEC/4))
break;
}
if (est->interval > 5)
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
-#include <net/if.h>
-#include <net/if_arp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static void usage(void)
{
- fprintf(stderr, "Usage: tc filter [ add | del | change | get ] dev STRING\n");
- fprintf(stderr, " [ pref PRIO ] [ protocol PROTO ]\n");
+ fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n");
+ fprintf(stderr, " [ pref PRIO ] protocol PROTO\n");
fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
fprintf(stderr, " [ root | classid CLASSID ] [ handle FILTERID ]\n");
fprintf(stderr, " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n");
struct filter_util *q = NULL;
__u32 prio = 0;
__u32 protocol = 0;
+ int protocol_set = 0;
char *fhandle = NULL;
char d[16];
char k[16];
req.n.nlmsg_type = cmd;
req.t.tcm_family = AF_UNSPEC;
+ if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
+ protocol = ETH_P_ALL;
+
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
if (prio)
duparg("priority", *argv);
if (get_u32(&prio, *argv, 0))
- invarg(*argv, "invalid prpriority value");
+ invarg(*argv, "invalid priority value");
} else if (matches(*argv, "protocol") == 0) {
__u16 id;
NEXT_ARG();
- if (protocol)
+ if (protocol_set)
duparg("protocol", *argv);
if (ll_proto_a2n(&id, *argv))
invarg(*argv, "invalid protocol");
protocol = id;
+ protocol_set = 1;
} else if (matches(*argv, "estimator") == 0) {
if (parse_estimator(&argc, &argv, &est) < 0)
return -1;
} else if (matches(*argv, "help") == 0) {
usage();
+ return 0;
} else {
strncpy(k, *argv, sizeof(k)-1);
static int filter_ifindex;
static __u32 filter_prio;
static __u32 filter_protocol;
+__u16 f_proto = 0;
-static int print_filter(const struct sockaddr_nl *who,
- struct nlmsghdr *n,
+int print_filter(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
void *arg)
{
FILE *fp = (FILE*)arg;
}
}
if (t->tcm_info) {
- __u32 protocol = TC_H_MIN(t->tcm_info);
+ f_proto = TC_H_MIN(t->tcm_info);
__u32 prio = TC_H_MAJ(t->tcm_info)>>16;
- if (!filter_protocol || filter_protocol != protocol) {
- if (protocol) {
+ if (!filter_protocol || filter_protocol != f_proto) {
+ if (f_proto) {
SPRINT_BUF(b1);
fprintf(fp, "protocol %s ",
- ll_proto_n2a(protocol, b1, sizeof(b1)));
+ ll_proto_n2a(f_proto, b1, sizeof(b1)));
}
}
if (!filter_prio || filter_prio != prio) {
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return tc_filter_list(argc-1, argv+1);
- if (matches(*argv, "help") == 0)
+ if (matches(*argv, "help") == 0) {
usage();
+ return 0;
+ }
fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv);
return -1;
}
--- /dev/null
+/*
+ * tc_monitor.c "tc monitor".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Jamal Hadi Salim
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <time.h>
+#include "rt_names.h"
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_common.h"
+
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: tc monitor\n");
+ exit(-1);
+}
+
+
+int accept_tcmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+
+ if (n->nlmsg_type == RTM_NEWTFILTER || n->nlmsg_type == RTM_DELTFILTER) {
+ print_filter(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWTCLASS || n->nlmsg_type == RTM_DELTCLASS) {
+ print_class(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWQDISC || n->nlmsg_type == RTM_DELQDISC) {
+ print_qdisc(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_GETACTION || n->nlmsg_type == RTM_NEWACTION ||
+ n->nlmsg_type == RTM_DELACTION) {
+ print_action(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
+ n->nlmsg_type != NLMSG_DONE) {
+ fprintf(fp, "Unknown message: length %08d type %08x flags %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ }
+ return 0;
+}
+
+int do_tcmonitor(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ char *file = NULL;
+ unsigned groups = nl_mgrp(RTNLGRP_TC);
+
+ while (argc > 0) {
+ if (matches(*argv, "file") == 0) {
+ NEXT_ARG();
+ file = *argv;
+ } else {
+ if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Argument \"%s\" is unknown, try \"tc monitor help\".\n", *argv);
+ exit(-1);
+ }
+ }
+ argc--; argv++;
+ }
+
+ if (file) {
+ FILE *fp;
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ perror("Cannot fopen");
+ exit(-1);
+ }
+ return rtnl_from_file(fp, accept_tcmsg, (void*)stdout);
+ }
+
+ if (rtnl_open(&rth, groups) < 0)
+ exit(1);
+
+ ll_init_map(&rth);
+
+ if (rtnl_listen(&rth, accept_tcmsg, (void*)stdout) < 0) {
+ rtnl_close(&rth);
+ exit(2);
+ }
+
+ rtnl_close(&rth);
+ exit(0);
+}
#include <arpa/inet.h>
#include <string.h>
#include <math.h>
+#include <malloc.h>
#include "utils.h"
#include "tc_util.h"
static int usage(void)
{
- fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | get ] dev STRING\n");
+ fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | show ] dev STRING\n");
fprintf(stderr, " [ handle QHANDLE ] [ root | ingress | parent CLASSID ]\n");
fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
+ fprintf(stderr, " [ stab [ help | STAB_OPTIONS] ]\n");
fprintf(stderr, " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n");
fprintf(stderr, "\n");
fprintf(stderr, " tc qdisc show [ dev STRING ] [ingress]\n");
fprintf(stderr, "Where:\n");
fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n");
fprintf(stderr, "OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help\n");
+ fprintf(stderr, "STAB_OPTIONS := ... try tc qdisc add stab help\n");
return -1;
}
{
struct qdisc_util *q = NULL;
struct tc_estimator est;
+ struct {
+ struct tc_sizespec szopts;
+ __u16 *data;
+ } stab;
char d[16];
char k[16];
struct {
} req;
memset(&req, 0, sizeof(req));
+ memset(&stab, 0, sizeof(stab));
memset(&est, 0, sizeof(est));
memset(&d, 0, sizeof(d));
memset(&k, 0, sizeof(k));
} else if (matches(*argv, "estimator") == 0) {
if (parse_estimator(&argc, &argv, &est))
return -1;
+ } else if (matches(*argv, "stab") == 0) {
+ if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
+ return -1;
+ continue;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
}
}
+ if (check_size_table_opts(&stab.szopts)) {
+ struct rtattr *tail;
+
+ if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
+ fprintf(stderr, "failed to calculate size table.\n");
+ return -1;
+ }
+
+ tail = NLMSG_TAIL(&req.n);
+ addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
+ addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
+ sizeof(stab.szopts));
+ if (stab.data)
+ addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
+ stab.szopts.tsize * sizeof(__u16));
+ tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
+ if (stab.data)
+ free(stab.data);
+ }
+
if (d[0]) {
int idx;
req.t.tcm_ifindex = idx;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
return 2;
return 0;
static int filter_ifindex;
-static int print_qdisc(const struct sockaddr_nl *who,
- struct nlmsghdr *n,
+int print_qdisc(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
void *arg)
{
FILE *fp = (FILE*)arg;
if (t->tcm_info != 1) {
fprintf(fp, "refcnt %d ", t->tcm_info);
}
- /* pfifo_fast is generic enough to warrant the hardcoding --JHS */
-
+ /* pfifo_fast is generic enough to warrant the hardcoding --JHS */
+
if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])))
q = get_qdisc_kind("prio");
else
q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));
-
+
if (tb[TCA_OPTIONS]) {
if (q)
q->print_qopt(q, fp, tb[TCA_OPTIONS]);
fprintf(fp, "[cannot parse qdisc parameters]");
}
fprintf(fp, "\n");
+ if (show_details && tb[TCA_STAB]) {
+ print_size_table(fp, " ", tb[TCA_STAB]);
+ fprintf(fp, "\n");
+ }
if (show_stats) {
struct rtattr *xstats = NULL;
memset(&t, 0, sizeof(t));
t.tcm_family = AF_UNSPEC;
memset(&d, 0, sizeof(d));
-
+
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return tc_qdisc_list(argc-1, argv+1);
- if (matches(*argv, "help") == 0)
+ if (matches(*argv, "help") == 0) {
usage();
+ return 0;
+ }
fprintf(stderr, "Command \"%s\" is unknown, try \"tc qdisc help\".\n", *argv);
return -1;
}
int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf)
{
- double xmit_time = tc_core_usec2tick(1000000*(double)avpkt/bps);
+ double xmit_time = tc_calc_xmittime(bps, avpkt);
double lW = -log(1.0 - 1.0/(1<<Wlog))/xmit_time;
double maxtime = 31/lW;
int clog;
--- /dev/null
+/*
+ * tc_stab.c "tc qdisc ... stab *".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Jussi Kivilinna, <jussi.kivilinna@mbnet.fi>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_core.h"
+#include "tc_common.h"
+
+static void stab_help(void)
+{
+ fprintf(stderr,
+ "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ] \n"
+ " [ overhead BYTES ] [ linklayer TYPE ] ...\n"
+ " mtu : max packet size we create rate map for {2047}\n"
+ " tsize : how many slots should size table have {512}\n"
+ " mpu : minimum packet size used in rate computations\n"
+ " overhead : per-packet size overhead used in rate computations\n"
+ " linklayer : adapting to a linklayer e.g. atm\n"
+ "Example: ... stab overhead 20 linklayer atm\n");
+
+ return;
+}
+
+int check_size_table_opts(struct tc_sizespec *s)
+{
+ return s->linklayer >= LINKLAYER_ETHERNET || s->mpu != 0 ||
+ s->overhead != 0;
+}
+
+int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp)
+{
+ char **argv = *argvp;
+ int argc = *argcp;
+ struct tc_sizespec s;
+
+ memset(&s, 0, sizeof(s));
+
+ NEXT_ARG();
+ if (matches(*argv, "help") == 0) {
+ stab_help();
+ return -1;
+ }
+ while (argc > 0) {
+ if (matches(*argv, "mtu") == 0) {
+ NEXT_ARG();
+ if (s.mtu)
+ duparg("mtu", *argv);
+ if (get_u32(&s.mtu, *argv, 10)) {
+ invarg("mtu", "invalid mtu");
+ return -1;
+ }
+ } else if (matches(*argv, "mpu") == 0) {
+ NEXT_ARG();
+ if (s.mpu)
+ duparg("mpu", *argv);
+ if (get_u32(&s.mpu, *argv, 10)) {
+ invarg("mpu", "invalid mpu");
+ return -1;
+ }
+ } else if (matches(*argv, "overhead") == 0) {
+ NEXT_ARG();
+ if (s.overhead)
+ duparg("overhead", *argv);
+ if (get_integer(&s.overhead, *argv, 10)) {
+ invarg("overhead", "invalid overhead");
+ return -1;
+ }
+ } else if (matches(*argv, "tsize") == 0) {
+ NEXT_ARG();
+ if (s.tsize)
+ duparg("tsize", *argv);
+ if (get_u32(&s.tsize, *argv, 10)) {
+ invarg("tsize", "invalid table size");
+ return -1;
+ }
+ } else if (matches(*argv, "linklayer") == 0) {
+ NEXT_ARG();
+ if (s.linklayer != LINKLAYER_UNSPEC)
+ duparg("linklayer", *argv);
+ if (get_linklayer(&s.linklayer, *argv)) {
+ invarg("linklayer", "invalid linklayer");
+ return -1;
+ }
+ } else
+ break;
+ argc--; argv++;
+ }
+
+ if (!check_size_table_opts(&s))
+ return -1;
+
+ *sp = s;
+ *argvp = argv;
+ *argcp = argc;
+ return 0;
+}
+
+void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta)
+{
+ struct rtattr *tb[TCA_STAB_MAX + 1];
+ SPRINT_BUF(b1);
+
+ parse_rtattr_nested(tb, TCA_STAB_MAX, rta);
+
+ if (tb[TCA_STAB_BASE]) {
+ struct tc_sizespec s = {0};
+ memcpy(&s, RTA_DATA(tb[TCA_STAB_BASE]),
+ MIN(RTA_PAYLOAD(tb[TCA_STAB_BASE]), sizeof(s)));
+
+ fprintf(fp, "%s", prefix);
+ if (s.linklayer)
+ fprintf(fp, "linklayer %s ",
+ sprint_linklayer(s.linklayer, b1));
+ if (s.overhead)
+ fprintf(fp, "overhead %d ", s.overhead);
+ if (s.mpu)
+ fprintf(fp, "mpu %u ", s.mpu);
+ if (s.mtu)
+ fprintf(fp, "mtu %u ", s.mtu);
+ if (s.tsize)
+ fprintf(fp, "tsize %u ", s.tsize);
+ }
+
+#if 0
+ if (tb[TCA_STAB_DATA]) {
+ unsigned i, j, dlen;
+ __u16 *data = RTA_DATA(tb[TCA_STAB_DATA]);
+ dlen = RTA_PAYLOAD(tb[TCA_STAB_DATA]) / sizeof(__u16);
+
+ fprintf(fp, "\n%sstab data:", prefix);
+ for (i = 0; i < dlen/12; i++) {
+ fprintf(fp, "\n%s %3u:", prefix, i * 12);
+ for (j = 0; i * 12 + j < dlen; j++)
+ fprintf(fp, " %05x", data[i * 12 + j]);
+ }
+ }
+#endif
+}
+
#include "utils.h"
#include "tc_util.h"
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+const char *get_tc_lib(void)
+{
+ const char *lib_dir;
+
+ lib_dir = getenv("TC_LIB_DIR");
+ if (!lib_dir)
+ lib_dir = LIBDIR "/tc/";
+
+ return lib_dir;
+}
+
int get_qdisc_handle(__u32 *h, const char *str)
{
__u32 maj;
return buf;
}
-int get_usecs(unsigned *usecs, const char *str)
+int get_time(unsigned *time, const char *str)
{
double t;
char *p;
if (*p) {
if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
strcasecmp(p, "secs")==0)
- t *= 1000000;
+ t *= TIME_UNITS_PER_SEC;
else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
strcasecmp(p, "msecs") == 0)
- t *= 1000;
+ t *= TIME_UNITS_PER_SEC/1000;
else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
strcasecmp(p, "usecs") == 0)
- t *= 1;
+ t *= TIME_UNITS_PER_SEC/1000000;
else
return -1;
}
- *usecs = t;
+ *time = t;
return 0;
}
-void print_usecs(char *buf, int len, __u32 usec)
+void print_time(char *buf, int len, __u32 time)
{
- double tmp = usec;
+ double tmp = time;
- if (tmp >= 1000000)
- snprintf(buf, len, "%.1fs", tmp/1000000);
- else if (tmp >= 1000)
- snprintf(buf, len, "%.1fms", tmp/1000);
+ if (tmp >= TIME_UNITS_PER_SEC)
+ snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
+ else if (tmp >= TIME_UNITS_PER_SEC/1000)
+ snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
else
- snprintf(buf, len, "%uus", usec);
+ snprintf(buf, len, "%uus", time);
}
-char * sprint_usecs(__u32 usecs, char *buf)
+char * sprint_time(__u32 time, char *buf)
{
- print_usecs(buf, SPRINT_BSIZE-1, usecs);
+ print_time(buf, SPRINT_BSIZE-1, time);
return buf;
}
+char * sprint_ticks(__u32 ticks, char *buf)
+{
+ return sprint_time(tc_core_tick2time(ticks), buf);
+}
+
int get_size(unsigned *size, const char *str)
{
double sz;
return 0;
}
+int get_linklayer(unsigned *val, const char *arg)
+{
+ int res;
+
+ if (matches(arg, "ethernet") == 0)
+ res = LINKLAYER_ETHERNET;
+ else if (matches(arg, "atm") == 0)
+ res = LINKLAYER_ATM;
+ else if (matches(arg, "adsl") == 0)
+ res = LINKLAYER_ATM;
+ else
+ return -1; /* Indicate error */
+
+ *val = res;
+ return 0;
+}
+
+void print_linklayer(char *buf, int len, unsigned linklayer)
+{
+ switch (linklayer) {
+ case LINKLAYER_UNSPEC:
+ snprintf(buf, len, "%s", "unspec");
+ return;
+ case LINKLAYER_ETHERNET:
+ snprintf(buf, len, "%s", "ethernet");
+ return;
+ case LINKLAYER_ATM:
+ snprintf(buf, len, "%s", "atm");
+ return;
+ default:
+ snprintf(buf, len, "%s", "unknown");
+ return;
+ }
+}
+
+char *sprint_linklayer(unsigned linklayer, char *buf)
+{
+ print_linklayer(buf, SPRINT_BSIZE-1, linklayer);
+ return buf;
+}
+
void print_tm(FILE * f, const struct tcf_t *tm)
{
int hz = get_user_hz();
fprintf(fp, " (dropped %u, overlimits %u requeues %u) ",
q.drops, q.overlimits, q.requeues);
}
-
+
if (tbs[TCA_STATS_RATE_EST]) {
struct gnet_stats_rate_est re = {0};
memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re)));
memcpy(&st, RTA_DATA(tb[TCA_STATS]), MIN(RTA_PAYLOAD(tb[TCA_STATS]), sizeof(st)));
fprintf(fp, "%sSent %llu bytes %u pkts (dropped %u, overlimits %u) ",
- prefix, (unsigned long long)st.bytes, st.packets, st.drops,
+ prefix, (unsigned long long)st.bytes, st.packets, st.drops,
st.overlimits);
if (st.bps || st.pps || st.qlen || st.backlog) {
#include <linux/gen_stats.h>
#include "tc_core.h"
+/* This is the deprecated multiqueue interface */
+#ifndef TCA_PRIO_MAX
+enum
+{
+ TCA_PRIO_UNSPEC,
+ TCA_PRIO_MQ,
+ __TCA_PRIO_MAX
+};
+
+#define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1)
+#endif
+
struct qdisc_util
{
struct qdisc_util *next;
int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
};
+extern __u16 f_proto;
struct filter_util
{
struct filter_util *next;
char id[16];
- int (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc,
+ int (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc,
char **argv, struct nlmsghdr *n);
int (*print_fopt)(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle);
};
{
struct action_util *next;
char id[16];
- int (*parse_aopt)(struct action_util *a, int *argc, char ***argv,
+ int (*parse_aopt)(struct action_util *a, int *argc, char ***argv,
int code, struct nlmsghdr *n);
int (*print_aopt)(struct action_util *au, FILE *f, struct rtattr *opt);
int (*print_xstats)(struct action_util *au, FILE *f, struct rtattr *xstats);
};
+extern const char *get_tc_lib(void);
+
extern struct qdisc_util *get_qdisc_kind(const char *str);
extern struct filter_util *get_filter_kind(const char *str);
extern int get_percent(unsigned *percent, const char *str);
extern int get_size(unsigned *size, const char *str);
extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
-extern int get_usecs(unsigned *usecs, const char *str);
+extern int get_time(unsigned *time, const char *str);
+extern int get_linklayer(unsigned *val, const char *arg);
+
extern void print_rate(char *buf, int len, __u32 rate);
extern void print_size(char *buf, int len, __u32 size);
extern void print_percent(char *buf, int len, __u32 percent);
extern void print_qdisc_handle(char *buf, int len, __u32 h);
-extern void print_usecs(char *buf, int len, __u32 usecs);
+extern void print_time(char *buf, int len, __u32 time);
+extern void print_linklayer(char *buf, int len, unsigned linklayer);
extern char * sprint_rate(__u32 rate, char *buf);
extern char * sprint_size(__u32 size, char *buf);
extern char * sprint_qdisc_handle(__u32 h, char *buf);
extern char * sprint_tc_classid(__u32 h, char *buf);
-extern char * sprint_usecs(__u32 usecs, char *buf);
+extern char * sprint_time(__u32 time, char *buf);
+extern char * sprint_ticks(__u32 ticks, char *buf);
extern char * sprint_percent(__u32 percent, char *buf);
+extern char * sprint_linklayer(unsigned linklayer, char *buf);
extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats);
extern void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats);
extern char *action_n2a(int action, char *buf, int len);
extern int action_a2n(char *arg, int *result);
extern int act_parse_police(struct action_util *a,int *, char ***, int, struct nlmsghdr *);
-extern int print_police(struct action_util *a, FILE *f,
+extern int print_police(struct action_util *a, FILE *f,
struct rtattr *tb);
-extern int police_print_xstats(struct action_util *a,FILE *f,
+extern int police_print_xstats(struct action_util *a,FILE *f,
struct rtattr *tb);
extern int tc_print_action(FILE *f, const struct rtattr *tb);
extern int tc_print_ipt(FILE *f, const struct rtattr *tb);