Merge branch 'for-2.6.39' of /home/shemminger/iproute2-net-next

Conflicts:
	include/linux/xfrm.h
	ip/iplink.c
This commit is contained in:
Stephen Hemminger 2011-04-12 14:42:20 -07:00
commit 4d91e4f168
28 changed files with 715 additions and 67 deletions

View File

@ -33,11 +33,10 @@ CCOPTS = -D_GNU_SOURCE -O2 -Wstrict-prototypes -Wall
CFLAGS = $(CCOPTS) -I../include $(DEFINES)
YACCFLAGS = -d -t -v
LDLIBS += -L../lib -lnetlink -lutil
SUBDIRS=lib ip tc misc netem genl
LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
LDLIBS += $(LIBNETLINK)
all: Config
@set -e; \

25
README
View File

@ -1,15 +1,17 @@
Primary site is:
http://developer.osdl.org/dev/iproute2
This is a set of utilities for Linux networking.
Original FTP site is:
ftp://ftp.inr.ac.ru/ip-routing/
Information:
http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
Download:
http://devresources.linuxfoundation.org/dev/iproute2/download
Repository:
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
How to compile this.
--------------------
1. Look at start of Makefile and set correct values for:
KERNEL_INCLUDE should point to correct linux kernel include directory.
Default (/usr/src/linux/include) is right as rule.
1. libdbm
arpd needs to have the db4 development libraries. For debian
users this is the package with a name like libdb4.x-dev.
@ -29,8 +31,13 @@ contains whether or not ATM is available, etc.
and make there. It assumes, that latex, dvips and psnup
are in your path.
4. This package includes matching sanitized kernel headers because
the build environment may not have up to date versions. See Makefile
if you have special requirements and need to point at different
kernel include files.
Stephen Hemminger
shemminger@osdl.org
shemminger@linux-foundation.org
Alexey Kuznetsov
kuznet@ms2.inr.ac.ru

15
README.devel Normal file
View File

@ -0,0 +1,15 @@
Iproute2 development is closely tied to Linux kernel networking
development. Most new features require a kernel and a utility component.
Please submit both the the Linux networking mailing list
<netdev@vger.kernel.org>
The current source is in the git repository:
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
The master branch contains the source corresponding to the current
code in the mainline Linux kernel (ie follows Linus). The net-next
branch is a temporary branch that tracks the code intended for the
next release; it corresponds with networking development branch in
the kernel.

View File

@ -15,6 +15,7 @@ PAGESPERPAGE=2
HTMLFILES=$(subst .sgml,.html,$(shell echo *.sgml))
DVIFILES=$(subst .ps,.dvi,$(PSFILES))
PDFFILES=$(subst .ps,.pdf,$(PSFILES))
all: pstwocol
@ -25,6 +26,8 @@ html: $(HTMLFILES)
dvi: $(DVIFILES)
pdf: $(PDFFILES)
print: $(PSFILES)
$(LPR) $(PSFILES)
@ -41,6 +44,11 @@ print: $(PSFILES)
echo "Re-running LaTeX $<, $${pass}d pass"; pass=$$[$$pass + 1]; \
done
#%.pdf: %.tex
# pdflatex $<
%.pdf: %.ps
ps2pdf $<
%.ps: %.dvi
$(DVIPS) $< -o $@

View File

@ -3,6 +3,8 @@ GENLOBJ=genl.o
include ../Config
SHARED_LIBS ?= y
CFLAGS += -fno-strict-aliasing
GENLMODULES :=
GENLMODULES += ctrl.o

View File

@ -151,5 +151,6 @@ 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);
char **name, char **type, char **link, char **dev,
int *group);
#endif /* __UTILS_H__ */

View File

@ -262,8 +262,11 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
}
/* skip two lines at the begenning of the file */
fgets(buf, sizeof(buf), fp);
fgets(buf, sizeof(buf), fp);
if (!fgets(buf, sizeof(buf), fp) ||
!fgets(buf, sizeof(buf), fp)) {
fprintf(stderr, "/proc/net/dev read error\n");
return -1;
}
while (fgets(buf, sizeof(buf), fp) != NULL) {
char name[IFNAMSIZ];

View File

@ -278,12 +278,10 @@ int print_linkinfo(const struct sockaddr_nl *who,
fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
if (tb[IFLA_QDISC])
fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
#ifdef IFLA_MASTER
if (tb[IFLA_MASTER]) {
SPRINT_BUF(b1);
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]));

View File

@ -51,7 +51,7 @@ void iplink_usage(void)
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");
fprintf(stderr, " ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
} else
fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
@ -71,6 +71,8 @@ void iplink_usage(void)
fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
fprintf(stderr, " [ rate TXRATE ] ] \n");
fprintf(stderr, " [ master DEVICE ]\n");
fprintf(stderr, " [ nomaster ]\n");
fprintf(stderr, " ip link show [ DEVICE | group GROUP ]\n");
if (iplink_have_newlink()) {
@ -244,7 +246,7 @@ int iplink_parse_vf(int vf, int *argcp, char ***argvp,
int iplink_parse(int argc, char **argv, struct iplink_req *req,
char **name, char **type, char **link, char **dev)
char **name, char **type, char **link, char **dev, int *group)
{
int ret, len;
char abuf[32];
@ -253,6 +255,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
int netns = -1;
int vf = -1;
*group = -1;
ret = argc;
while (argc > 0) {
@ -361,7 +364,18 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
if (len < 0)
return -1;
addattr_nest_end(&req->n, vflist);
#ifdef IFF_DYNAMIC
} else if (matches(*argv, "master") == 0) {
int ifindex;
NEXT_ARG();
ifindex = ll_name_to_index(*argv);
if (!ifindex)
invarg("Device does not exist\n", *argv);
addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
&ifindex, 4);
} else if (matches(*argv, "nomaster") == 0) {
int ifindex = 0;
addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
&ifindex, 4);
} else if (matches(*argv, "dynamic") == 0) {
NEXT_ARG();
req->i.ifi_change |= IFF_DYNAMIC;
@ -371,7 +385,6 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
req->i.ifi_flags &= ~IFF_DYNAMIC;
} else
return on_off("dynamic");
#endif
} else if (matches(*argv, "type") == 0) {
NEXT_ARG();
*type = *argv;
@ -383,6 +396,12 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
*argv, strlen(*argv));
argc--; argv++;
break;
} else if (strcmp(*argv, "group") == 0) {
NEXT_ARG();
if (*group != -1)
duparg("group", *argv);
if (rtnl_group_a2n(group, *argv))
invarg("Invalid \"group\" value\n", *argv);
} else {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
@ -406,6 +425,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
char *name = NULL;
char *link = NULL;
char *type = NULL;
int group;
struct link_util *lu = NULL;
struct iplink_req req;
int ret;
@ -417,12 +437,38 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
req.n.nlmsg_type = cmd;
req.i.ifi_family = preferred_family;
ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev);
ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
if (ret < 0)
return ret;
argc -= ret;
argv += ret;
if (group != -1) {
if (dev)
addattr_l(&req.n, sizeof(req), IFLA_GROUP,
&group, sizeof(group));
else {
if (argc) {
fprintf(stderr, "Garbage instead of arguments "
"\"%s ...\". Try \"ip link "
"help\".\n", *argv);
return -1;
}
if (flags & NLM_F_CREATE) {
fprintf(stderr, "group cannot be used when "
"creating devices.\n");
return -1;
}
req.i.ifi_index = 0;
addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
exit(2);
return 0;
}
}
ll_init_map(&rth);
if (type) {
@ -779,7 +825,6 @@ static int do_set(int argc, char **argv)
flags |= IFF_NOARP;
} else
return on_off("noarp");
#ifdef IFF_DYNAMIC
} else if (matches(*argv, "dynamic") == 0) {
NEXT_ARG();
mask |= IFF_DYNAMIC;
@ -789,7 +834,6 @@ static int do_set(int argc, char **argv)
flags &= ~IFF_DYNAMIC;
} else
return on_off("dynamic");
#endif
} else {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();

View File

@ -128,14 +128,15 @@ void read_igmp(struct ma_info **result_p)
if (!fp)
return;
memset(&m, 0, sizeof(m));
fgets(buf, sizeof(buf), fp);
if (!fgets(buf, sizeof(buf), fp))
return;
m.addr.family = AF_INET;
m.addr.bitlen = 32;
m.addr.bytelen = 4;
while (fgets(buf, sizeof(buf), fp)) {
struct ma_info *ma = malloc(sizeof(m));
struct ma_info *ma;
if (buf[0] != '\t') {
sscanf(buf, "%d%s", &m.index, m.name);

View File

@ -58,7 +58,8 @@ static void read_viftable(void)
if (!fp)
return;
fgets(buf, sizeof(buf), fp);
if (!fgets(buf, sizeof(buf), fp))
return;
while (fgets(buf, sizeof(buf), fp)) {
int vifi;
@ -83,7 +84,8 @@ static void read_mroute_list(FILE *ofp)
if (!fp)
return;
fgets(buf, sizeof(buf), fp);
if (!fgets(buf, sizeof(buf), fp))
return;
while (fgets(buf, sizeof(buf), fp)) {
inet_prefix maddr, msrc;

View File

@ -277,12 +277,10 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
ci->ndm_confirmed/hz, ci->ndm_updated/hz);
}
#ifdef NDA_PROBES
if (tb[NDA_PROBES] && show_stats) {
__u32 p = *(__u32 *) RTA_DATA(tb[NDA_PROBES]);
fprintf(fp, " probes %u", p);
}
#endif
if (r->ndm_state) {
int nud = r->ndm_state;

View File

@ -478,12 +478,11 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (ci->rta_lastuse != 0)
fprintf(fp, " age %dsec", ci->rta_lastuse/hz);
}
#ifdef RTNETLINK_HAVE_PEERINFO
if (ci->rta_id)
fprintf(fp, " ipid 0x%04x", ci->rta_id);
if (ci->rta_ts || ci->rta_tsage)
fprintf(fp, " ts 0x%x tsage %dsec", ci->rta_ts, ci->rta_tsage);
#endif
fprintf(fp, " ts 0x%x tsage %dsec",
ci->rta_ts, ci->rta_tsage);
}
} else if (r->rtm_family == AF_INET6) {
struct rta_cacheinfo *ci = NULL;
@ -792,7 +791,6 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (get_unsigned(&mtu, *argv, 0))
invarg("\"mtu\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
#ifdef RTAX_HOPLIMIT
} else if (strcmp(*argv, "hoplimit") == 0) {
unsigned hoplimit;
NEXT_ARG();
@ -803,8 +801,6 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (get_unsigned(&hoplimit, *argv, 0))
invarg("\"hoplimit\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
#endif
#ifdef RTAX_ADVMSS
} else if (strcmp(*argv, "advmss") == 0) {
unsigned mss;
NEXT_ARG();
@ -815,8 +811,6 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (get_unsigned(&mss, *argv, 0))
invarg("\"mss\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
#endif
#ifdef RTAX_REORDERING
} else if (matches(*argv, "reordering") == 0) {
unsigned reord;
NEXT_ARG();
@ -827,7 +821,6 @@ int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (get_unsigned(&reord, *argv, 0))
invarg("\"reordering\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
#endif
} else if (strcmp(*argv, "rtt") == 0) {
unsigned rtt;
NEXT_ARG();

View File

@ -407,8 +407,12 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
return -1;
}
fgets(buf, sizeof(buf), fp);
fgets(buf, sizeof(buf), fp);
/* skip header lines */
if (!fgets(buf, sizeof(buf), fp) ||
!fgets(buf, sizeof(buf), fp)) {
fprintf(stderr, "/proc/net/dev read error\n");
return -1;
}
while (fgets(buf, sizeof(buf), fp) != NULL) {
int index, type;

View File

@ -854,6 +854,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ICMP, "icmp");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_AF_UNSPEC, "af-unspec");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ALIGN4, "align4");
if (flags)
fprintf(fp, "%x", flags);
}
@ -980,6 +981,7 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
fprintf(fp, "flag ");
XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_LOCALOK, "localok");
XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_ICMP, "icmp");
if (flags)
fprintf(fp, "%x", flags);
}

View File

@ -30,6 +30,7 @@ static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
char *name, *type, *link, *dev;
int err, len;
struct rtattr * data;
int group;
if (strcmp(argv[0], "peer") != 0) {
usage();
@ -42,7 +43,7 @@ static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
hdr->nlmsg_len += sizeof(struct ifinfomsg);
err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
&name, &type, &link, &dev);
&name, &type, &link, &dev, &group);
if (err < 0)
return err;

View File

@ -77,7 +77,7 @@ static void usage(void)
//fprintf(stderr, "PRIORITY - priority value(default=0)\n");
fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
fprintf(stderr, "FLAG := [ localok ]\n");
fprintf(stderr, "FLAG := [ localok | icmp ]\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");
@ -156,6 +156,8 @@ static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp)
while (1) {
if (strcmp(*argv, "localok") == 0)
*flags |= XFRM_POLICY_LOCALOK;
else if (strcmp(*argv, "icmp") == 0)
*flags |= XFRM_POLICY_ICMP;
else {
PREV_ARG(); /* back track */
break;

View File

@ -84,7 +84,7 @@ static void usage(void)
//fprintf(stderr, "REQID - number(default=0)\n");
fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec ]\n");
fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 ]\n");
fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
@ -216,6 +216,8 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
*flags |= XFRM_STATE_ICMP;
else if (strcmp(*argv, "af-unspec") == 0)
*flags |= XFRM_STATE_AF_UNSPEC;
else if (strcmp(*argv, "align4") == 0)
*flags |= XFRM_STATE_ALIGN4;
else {
PREV_ARG(); /* back track */
break;

View File

@ -36,19 +36,13 @@ static struct {
} llproto_names[] = {
__PF(LOOP,loop)
__PF(PUP,pup)
#ifdef ETH_P_PUPAT
__PF(PUPAT,pupat)
#endif
__PF(IP,ip)
__PF(X25,x25)
__PF(ARP,arp)
__PF(BPQ,bpq)
#ifdef ETH_P_IEEEPUP
__PF(IEEEPUP,ieeepup)
#endif
#ifdef ETH_P_IEEEPUPAT
__PF(IEEEPUPAT,ieeepupat)
#endif
__PF(DEC,dec)
__PF(DNA_DL,dna_dl)
__PF(DNA_RC,dna_rc)
@ -62,19 +56,10 @@ __PF(ATALK,atalk)
__PF(AARP,aarp)
__PF(IPX,ipx)
__PF(IPV6,ipv6)
#ifdef ETH_P_PPP_DISC
__PF(PPP_DISC,ppp_disc)
#endif
#ifdef ETH_P_PPP_SES
__PF(PPP_SES,ppp_ses)
#endif
#ifdef ETH_P_ATMMPOA
__PF(ATMMPOA,atmmpoa)
#endif
#ifdef ETH_P_ATMFATE
__PF(ATMFATE,atmfate)
#endif
__PF(802_3,802_3)
__PF(AX25,ax25)
__PF(ALL,all)
@ -90,9 +75,7 @@ __PF(TR_802_2,tr_802_2)
__PF(MOBITEX,mobitex)
__PF(CONTROL,control)
__PF(IRDA,irda)
#ifdef ETH_P_ECONET
__PF(ECONET,econet)
#endif
__PF(TIPC,tipc)
__PF(AOE,aoe)

View File

@ -55,8 +55,10 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
.RI "[ " ARGS " ]"
.ti -8
.BI "ip link set " DEVICE
.RB "{ " up " | " down " | " arp " { " on " | " off " } |"
.BR "ip link set " {
.IR DEVICE " | "
.BI "group " GROUP
.RB "} { " up " | " down " | " arp " { " on " | " off " } |"
.br
.BR promisc " { " on " | " off " } |"
.br
@ -95,7 +97,12 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
.B qos
.IR VLAN-QOS " ] ] ["
.B rate
.IR TXRATE " ]"
.IR TXRATE " ] |"
.br
.B master
.IR DEVICE
.br
.B nomaster
.ti -8
.B ip link show
@ -929,6 +936,13 @@ specifies network device to operate on. When configuring SR-IOV Virtual Fuction
(VF) devices, this keyword should specify the associated Physical Function (PF)
device.
.TP
.BI group " GROUP "
.I GROUP
has a dual role: If both group and dev are present, then move the device to the
specified group. If only a group is specified, then the command operates on
all devices in that group.
.TP
.BR up " and " down
change the state of the device to
@ -995,6 +1009,12 @@ move the device to the network namespace associated with the process
.BI alias " NAME"
give the device a symbolic name for easy reference.
.TP
.BI group " GROUP"
specify the group the device belongs to.
The available groups are listed in file
.BR "/etc/iproute2/group" .
.TP
.BI vf " NUM"
specify a Virtual Function device to be configured. The associated PF device
@ -1040,6 +1060,14 @@ Setting this parameter to 0 disables rate limiting. The
parameter must be specified.
.in -8
.TP
.BI master " DEVICE"
set master device of the device (enslave device).
.TP
.BI nomaster
unset master device of the device (release device).
.PP
.B Warning:
If multiple parameter changes are requested,

View File

@ -535,7 +535,7 @@ int main(int argc, char *argv[])
}
if (getenv("RTACCT_HISTORY"))
snprintf(hist_name, sizeof(hist_name), getenv("RTACCT_HISTORY"));
snprintf(hist_name, sizeof(hist_name), "%s", getenv("RTACCT_HISTORY"));
else
sprintf(hist_name, "/tmp/.rtacct.u%d", getuid());
@ -563,7 +563,10 @@ int main(int argc, char *argv[])
exit(-1);
}
if (stb.st_size != sizeof(*hist_db))
write(fd, kern_db, sizeof(*hist_db));
if (write(fd, kern_db, sizeof(*hist_db)) < 0) {
perror("rtacct: write history file");
exit(-1);
}
hist_db = mmap(NULL, sizeof(*hist_db),
PROT_READ|PROT_WRITE,

View File

@ -15,6 +15,8 @@ TCMODULES += q_cbq.o
TCMODULES += q_rr.o
TCMODULES += q_multiq.o
TCMODULES += q_netem.o
TCMODULES += q_choke.o
TCMODULES += q_sfb.o
TCMODULES += f_rsvp.o
TCMODULES += f_u32.o
TCMODULES += f_route.o
@ -43,6 +45,7 @@ TCMODULES += em_nbyte.o
TCMODULES += em_cmp.o
TCMODULES += em_u32.o
TCMODULES += em_meta.o
TCMODULES += q_mqprio.o
TCSO :=
ifeq ($(TC_CONFIG_ATM),y)

View File

@ -432,7 +432,8 @@ static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
key = htonl(key);
mask = htonl(mask);
if (res = pack_key(sel, key, mask, off, offmask) < 0)
res = pack_key(sel, key, mask, off, offmask);
if (res < 0)
return -1;
*argc_p = argc;

215
tc/q_choke.c Normal file
View File

@ -0,0 +1,215 @@
/*
* q_choke.c CHOKE.
*
* 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: Stephen Hemminger <shemminger@vyatta.com>
*/
#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"
#include "tc_red.h"
static void explain(void)
{
fprintf(stderr, "Usage: ... choke limit PACKETS bandwidth KBPS [ecn]\n");
fprintf(stderr, " [ min PACKETS ] [ max PACKETS ] [ burst PACKETS ]\n");
}
static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n)
{
struct tc_red_qopt opt;
unsigned burst = 0;
unsigned avpkt = 1000;
double probability = 0.02;
unsigned rate = 0;
int ecn_ok = 0;
int wlog;
__u8 sbuf[256];
struct rtattr *tail;
memset(&opt, 0, sizeof(opt));
while (argc > 0) {
if (strcmp(*argv, "limit") == 0) {
NEXT_ARG();
if (get_unsigned(&opt.limit, *argv, 0)) {
fprintf(stderr, "Illegal \"limit\"\n");
return -1;
}
} else if (strcmp(*argv, "bandwidth") == 0) {
NEXT_ARG();
if (get_rate(&rate, *argv)) {
fprintf(stderr, "Illegal \"bandwidth\"\n");
return -1;
}
} else if (strcmp(*argv, "ecn") == 0) {
ecn_ok = 1;
} else if (strcmp(*argv, "min") == 0) {
NEXT_ARG();
if (get_unsigned(&opt.qth_min, *argv, 0)) {
fprintf(stderr, "Illegal \"min\"\n");
return -1;
}
} else if (strcmp(*argv, "max") == 0) {
NEXT_ARG();
if (get_unsigned(&opt.qth_max, *argv, 0)) {
fprintf(stderr, "Illegal \"max\"\n");
return -1;
}
} else if (strcmp(*argv, "burst") == 0) {
NEXT_ARG();
if (get_unsigned(&burst, *argv, 0)) {
fprintf(stderr, "Illegal \"burst\"\n");
return -1;
}
} else if (strcmp(*argv, "avpkt") == 0) {
NEXT_ARG();
if (get_size(&avpkt, *argv)) {
fprintf(stderr, "Illegal \"avpkt\"\n");
return -1;
}
} else if (strcmp(*argv, "probability") == 0) {
NEXT_ARG();
if (sscanf(*argv, "%lg", &probability) != 1) {
fprintf(stderr, "Illegal \"probability\"\n");
return -1;
}
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
} else {
fprintf(stderr, "What is \"%s\"?\n", *argv);
explain();
return -1;
}
argc--; argv++;
}
if (!rate || !opt.limit) {
fprintf(stderr, "Required parameter (bandwidth, limit) is missing\n");
return -1;
}
/* Compute default min/max thresholds based on
Sally Floyd's recommendations:
http://www.icir.org/floyd/REDparameters.txt
*/
if (!opt.qth_max)
opt.qth_max = opt.limit / 4;
if (!opt.qth_min)
opt.qth_min = opt.qth_max / 3;
if (!burst)
burst = (2 * opt.qth_min + opt.qth_max) / 3;
if (opt.qth_max > opt.limit) {
fprintf(stderr, "\"max\" is larger than \"limit\"\n");
return -1;
}
if (opt.qth_min > opt.qth_min) {
fprintf(stderr, "\"min\" is not smaller than \"max\"\n");
return -1;
}
wlog = tc_red_eval_ewma(opt.qth_min*avpkt, burst, avpkt);
if (wlog < 0) {
fprintf(stderr, "CHOKE: failed to calculate EWMA constant.\n");
return -1;
}
if (wlog >= 10)
fprintf(stderr, "CHOKE: WARNING. Burst %d seems to be to large.\n", burst);
opt.Wlog = wlog;
wlog = tc_red_eval_P(opt.qth_min*avpkt, opt.qth_max*avpkt, probability);
if (wlog < 0) {
fprintf(stderr, "CHOKE: failed to calculate probability.\n");
return -1;
}
opt.Plog = wlog;
wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf);
if (wlog < 0) {
fprintf(stderr, "CHOKE: failed to calculate idle damping table.\n");
return -1;
}
opt.Scell_log = wlog;
if (ecn_ok)
opt.flags |= TC_RED_ECN;
tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
addattr_l(n, 1024, TCA_CHOKE_PARMS, &opt, sizeof(opt));
addattr_l(n, 1024, TCA_CHOKE_STAB, sbuf, 256);
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
return 0;
}
static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[TCA_CHOKE_STAB+1];
const struct tc_red_qopt *qopt;
if (opt == NULL)
return 0;
parse_rtattr_nested(tb, TCA_CHOKE_STAB, opt);
if (tb[TCA_CHOKE_PARMS] == NULL)
return -1;
qopt = RTA_DATA(tb[TCA_CHOKE_PARMS]);
if (RTA_PAYLOAD(tb[TCA_CHOKE_PARMS]) < sizeof(*qopt))
return -1;
fprintf(f, "limit %up min %up max %up ",
qopt->limit, qopt->qth_min, qopt->qth_max);
if (qopt->flags & TC_RED_ECN)
fprintf(f, "ecn ");
if (show_details) {
fprintf(f, "ewma %u Plog %u Scell_log %u",
qopt->Wlog, qopt->Plog, qopt->Scell_log);
}
return 0;
}
static int choke_print_xstats(struct qdisc_util *qu, FILE *f,
struct rtattr *xstats)
{
struct tc_choke_xstats *st;
if (xstats == NULL)
return 0;
if (RTA_PAYLOAD(xstats) < sizeof(*st))
return -1;
st = RTA_DATA(xstats);
fprintf(f, " marked %u early %u pdrop %u other %u matched %u",
st->marked, st->early, st->pdrop, st->other, st->matched);
return 0;
}
struct qdisc_util choke_qdisc_util = {
.id = "choke",
.parse_qopt = choke_parse_opt,
.print_qopt = choke_print_opt,
.print_xstats = choke_print_xstats,
};

124
tc/q_mqprio.c Normal file
View File

@ -0,0 +1,124 @@
/*
* q_mqprio.c MQ prio qdisc
*
* 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.
*
* Author: John Fastabend, <john.r.fastabend@intel.com>
*/
#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: ... mqprio [num_tc NUMBER] [map P0 P1 ...]\n");
fprintf(stderr, " [offset txq0 txq1 ...] ");
fprintf(stderr, "[count cnt0,cnt1 ...] [hw 1|0]\n");
}
static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
char **argv, struct nlmsghdr *n)
{
int idx;
struct tc_mqprio_qopt opt = {
8,
{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3},
1,
};
while (argc > 0) {
idx = 0;
if (strcmp(*argv, "num_tc") == 0) {
NEXT_ARG();
if (get_u8(&opt.num_tc, *argv, 10)) {
fprintf(stderr, "Illegal \"num_tc\"\n");
return -1;
}
} else if (strcmp(*argv, "map") == 0) {
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
NEXT_ARG();
if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) {
PREV_ARG();
break;
}
idx++;
}
for ( ; idx < TC_QOPT_MAX_QUEUE; idx++)
opt.prio_tc_map[idx] = 0;
} else if (strcmp(*argv, "offset") == 0) {
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
NEXT_ARG();
if (get_u16(&opt.offset[idx], *argv, 10)) {
PREV_ARG();
break;
}
idx++;
}
} else if (strcmp(*argv, "count") == 0) {
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
NEXT_ARG();
if (get_u16(&opt.count[idx], *argv, 10)) {
PREV_ARG();
break;
}
idx++;
}
} else if (strcmp(*argv, "hw") == 0) {
NEXT_ARG();
if (get_u8(&opt.hw, *argv, 10)) {
fprintf(stderr, "Illegal \"hw\"\n");
return -1;
}
idx++;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
} else {
fprintf(stderr, "Unknown argument\n");
return -1;
}
argc--; argv++;
}
addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
return 0;
}
int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
int i;
struct tc_mqprio_qopt *qopt;
if (opt == NULL)
return 0;
qopt = RTA_DATA(opt);
fprintf(f, " tc %u map ", qopt->num_tc);
for (i = 0; i <= TC_PRIO_MAX; i++)
fprintf(f, "%d ", qopt->prio_tc_map[i]);
fprintf(f, "\n queues:");
for (i = 0; i < qopt->num_tc; i++)
fprintf(f, "(%i:%i) ", qopt->offset[i],
qopt->offset[i] + qopt->count[i] - 1);
return 0;
}
struct qdisc_util mqprio_qdisc_util = {
.id = "mqprio",
.parse_qopt = mqprio_parse_opt,
.print_qopt = mqprio_print_opt,
};

View File

@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Stephen Hemminger <shemminger@osdl.org>
* Authors: Stephen Hemminger <shemminger@linux-foundation.org>
*
*/

200
tc/q_sfb.c Normal file
View File

@ -0,0 +1,200 @@
/*
* q_sfb.c Stochastic Fair Blue.
*
* 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: Juliusz Chroboczek <jch@pps.jussieu.fr>
*
*/
#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: ... sfb [ rehash SECS ] [ db SECS ]\n"
" [ limit PACKETS ] [ max PACKETS ] [ target PACKETS ]\n"
" [ increment FLOAT ] [ decrement FLOAT ]\n"
" [ penalty_rate PPS ] [ penalty_burst PACKETS ]\n");
}
static int get_prob(__u32 *val, const char *arg)
{
double d;
char *ptr;
if (!arg || !*arg)
return -1;
d = strtod(arg, &ptr);
if (!ptr || ptr == arg || d < 0.0 || d > 1.0)
return -1;
*val = (__u32)(d * SFB_MAX_PROB + 0.5);
return 0;
}
static int sfb_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n)
{
struct tc_sfb_qopt opt;
struct rtattr *tail;
memset(&opt, 0, sizeof(opt));
opt.rehash_interval = 600*1000;
opt.warmup_time = 60*1000;
opt.penalty_rate = 10;
opt.penalty_burst = 20;
opt.increment = (SFB_MAX_PROB + 1000) / 2000;
opt.decrement = (SFB_MAX_PROB + 10000) / 20000;
while (argc > 0) {
if (strcmp(*argv, "rehash") == 0) {
NEXT_ARG();
if (get_u32(&opt.rehash_interval, *argv, 0)) {
fprintf(stderr, "Illegal \"rehash\"\n");
return -1;
}
} else if (strcmp(*argv, "db") == 0) {
NEXT_ARG();
if (get_u32(&opt.warmup_time, *argv, 0)) {
fprintf(stderr, "Illegal \"db\"\n");
return -1;
}
} else if (strcmp(*argv, "limit") == 0) {
NEXT_ARG();
if (get_u32(&opt.limit, *argv, 0)) {
fprintf(stderr, "Illegal \"limit\"\n");
return -1;
}
} else if (strcmp(*argv, "max") == 0) {
NEXT_ARG();
if (get_u32(&opt.max, *argv, 0)) {
fprintf(stderr, "Illegal \"max\"\n");
return -1;
}
} else if (strcmp(*argv, "target") == 0) {
NEXT_ARG();
if (get_u32(&opt.bin_size, *argv, 0)) {
fprintf(stderr, "Illegal \"target\"\n");
return -1;
}
} else if (strcmp(*argv, "increment") == 0) {
NEXT_ARG();
if (get_prob(&opt.increment, *argv)) {
fprintf(stderr, "Illegal \"increment\"\n");
return -1;
}
} else if (strcmp(*argv, "decrement") == 0) {
NEXT_ARG();
if (get_prob(&opt.decrement, *argv)) {
fprintf(stderr, "Illegal \"decrement\"\n");
return -1;
}
} else if (strcmp(*argv, "penalty_rate") == 0) {
NEXT_ARG();
if (get_u32(&opt.penalty_rate, *argv, 0)) {
fprintf(stderr, "Illegal \"penalty_rate\"\n");
return -1;
}
} else if (strcmp(*argv, "penalty_burst") == 0) {
NEXT_ARG();
if (get_u32(&opt.penalty_burst, *argv, 0)) {
fprintf(stderr, "Illegal \"penalty_burst\"\n");
return -1;
}
} else {
fprintf(stderr, "What is \"%s\"?\n", *argv);
explain();
return -1;
}
argc--; argv++;
}
if (opt.max == 0) {
if (opt.bin_size >= 1)
opt.max = (opt.bin_size * 5 + 1) / 4;
else
opt.max = 25;
}
if (opt.bin_size == 0)
opt.bin_size = (opt.max * 4 + 3) / 5;
tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
addattr_l(n, 1024, TCA_SFB_PARMS, &opt, sizeof(opt));
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
return 0;
}
static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[__TCA_SFB_MAX];
struct tc_sfb_qopt *qopt;
if (opt == NULL)
return 0;
parse_rtattr_nested(tb, TCA_SFB_MAX, opt);
if (tb[TCA_SFB_PARMS] == NULL)
return -1;
qopt = RTA_DATA(tb[TCA_SFB_PARMS]);
if (RTA_PAYLOAD(tb[TCA_SFB_PARMS]) < sizeof(*qopt))
return -1;
fprintf(f,
"limit %d max %d target %d\n"
" increment %.5f decrement %.5f penalty rate %d burst %d "
"(%ums %ums)",
qopt->limit, qopt->max, qopt->bin_size,
(double)qopt->increment / SFB_MAX_PROB,
(double)qopt->decrement / SFB_MAX_PROB,
qopt->penalty_rate, qopt->penalty_burst,
qopt->rehash_interval, qopt->warmup_time);
return 0;
}
static int sfb_print_xstats(struct qdisc_util *qu, FILE *f,
struct rtattr *xstats)
{
struct tc_sfb_xstats *st;
if (xstats == NULL)
return 0;
if (RTA_PAYLOAD(xstats) < sizeof(*st))
return -1;
st = RTA_DATA(xstats);
fprintf(f,
" earlydrop %u penaltydrop %u bucketdrop %u queuedrop %u childdrop %u marked %u\n"
" maxqlen %u maxprob %.5f avgprob %.5f ",
st->earlydrop, st->penaltydrop, st->bucketdrop, st->queuedrop, st->childdrop,
st->marked,
st->maxqlen, (double)st->maxprob / SFB_MAX_PROB,
(double)st->avgprob / SFB_MAX_PROB);
return 0;
}
struct qdisc_util sfb_qdisc_util = {
.id = "sfb",
.parse_qopt = sfb_parse_opt,
.print_qopt = sfb_print_opt,
.print_xstats = sfb_print_xstats,
};

View File

@ -26,6 +26,7 @@
static void explain(void)
{
fprintf(stderr, "Usage: ... sfq [ limit NUMBER ] [ perturb SECS ] [ quantum BYTES ]\n");
fprintf(stderr, " [ divisor NUMBER ]\n");
}
static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
@ -61,6 +62,13 @@ static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
return -1;
}
ok++;
} else if (strcmp(*argv, "divisor") == 0) {
NEXT_ARG();
if (get_u32(&opt.divisor, *argv, 0)) {
fprintf(stderr, "Illegal \"divisor\"\n");
return -1;
}
ok++;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
@ -93,6 +101,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (show_details) {
fprintf(f, "flows %u/%u ", qopt->flows, qopt->divisor);
}
fprintf(f, "divisor %u ", qopt->divisor);
if (qopt->perturb_period)
fprintf(f, "perturb %dsec ", qopt->perturb_period);
return 0;