diff -urN iproute2-2.6.31.orig/include/linux/tc_act/tc_cpu.h iproute2-2.6.31/include/linux/tc_act/tc_cpu.h --- iproute2-2.6.31.orig/include/linux/tc_act/tc_cpu.h 1970-01-01 08:00:00.000000000 +0800 +++ iproute2-2.6.31/include/linux/tc_act/tc_cpu.h 2010-07-02 16:57:10.000000000 +0800 @@ -0,0 +1,31 @@ +#ifndef __LINUX_TC_CPU_H +#define __LINUX_TC_CPU_H + +#include +#include + +#define TCA_ACT_CPU 12 + +enum { + TCA_CPU_UNSPEC, + TCA_CPU_PARMS, + TCA_CPU_TM, + __TCA_CPU_MAX +}; +#define TCA_CPU_MAX (__TCA_CPU_MAX - 1) + +enum { + TCA_CPU_TYPE_MAP, + TCA_CPU_TYPE_CPUID, + TCA_CPU_TYPE_SOCKET, + __TCA_CPU_TYPE_MAX +}; +#define TCA_CPU_TYPE_MAX (__TCA_CPU_TYPE_MAX - 1) + +struct tc_cpu { + tc_gen; + __u32 type; + __u32 value; +}; + +#endif /* __LINUX_TC_CPU_H */ diff -urN iproute2-2.6.31.orig/tc/Makefile iproute2-2.6.31/tc/Makefile --- iproute2-2.6.31.orig/tc/Makefile 2010-07-14 11:21:05.000000000 +0800 +++ iproute2-2.6.31/tc/Makefile 2010-07-02 16:56:41.000000000 +0800 @@ -32,6 +32,7 @@ TCMODULES += m_gact.o TCMODULES += m_mirred.o TCMODULES += m_nat.o +TCMODULES += m_cpu.o TCMODULES += m_pedit.o TCMODULES += m_skbedit.o TCMODULES += p_ip.o diff -urN iproute2-2.6.31.orig/tc/m_cpu.c iproute2-2.6.31/tc/m_cpu.c --- iproute2-2.6.31.orig/tc/m_cpu.c 1970-01-01 08:00:00.000000000 +0800 +++ iproute2-2.6.31/tc/m_cpu.c 2010-07-12 16:38:56.000000000 +0800 @@ -0,0 +1,186 @@ +/* + * m_cpu.c Packet distributing 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: Changli Gao + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "tc_util.h" +#include + +static void +explain(void) +{ + fprintf(stderr, "Usage: ... cpu METHOD\n" + "METHOD := { CPUID-SPEC | MAP-SPEC | SOCKET-SPEC }\n" + "CPUID-SPEC := cpuid CPUID\n" + "MAP-SPEC := map OFFSET\n" + "SOCKET-SPEC := socket\n"); +} + +static void +usage(void) +{ + explain(); + exit(-1); +} + +static int +parse_cpu_args(int *argc_p, char ***argv_p,struct tc_cpu *sel) +{ + int argc = *argc_p; + char **argv = *argv_p; + + if (argc <= 0) + return -1; + + if (matches(*argv, "map") == 0) + sel->type = TCA_CPU_TYPE_MAP; + else if (matches(*argv, "cpuid") == 0) + sel->type = TCA_CPU_TYPE_CPUID; + else if (matches(*argv, "socket") == 0) { + sel->type = TCA_CPU_TYPE_SOCKET; + goto out; + } else + return -1; + + NEXT_ARG(); + + if (get_u32(&sel->value, *argv, 10)) { + fprintf(stderr, "Cpu: Illegal \"%s\"\n", + sel->type == TCA_CPU_TYPE_CPUID ? "CPUID" : "OFFSET"); + return -1; + } + +out: + argc--; + argv++; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int +parse_cpu(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +{ + struct tc_cpu sel; + int argc = *argc_p; + char **argv = *argv_p; + struct rtattr *tail; + + memset(&sel, 0, sizeof(sel)); + sel.action = TC_ACT_STOLEN; + + if (argc <= 0) { + explain(); + return -1; + } + + if (matches(*argv, "cpu") == 0) { + NEXT_ARG(); + } else { + fprintf(stderr, "cpu bad arguments %s\n", *argv); + return -1; + } + + if (matches(*argv, "help") == 0) + usage(); + if (parse_cpu_args(&argc, &argv, &sel)) { + fprintf(stderr, "Illegal cpu construct (%s) \n", *argv); + explain(); + return -1; + } + + while (argc > 0) { + if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + /* I have set it above */ + argc--; + argv++; + continue; + } else if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&sel.index, *argv, 10)) { + fprintf(stderr, "Cpu: Illegal \"index\"\n"); + return -1; + } + argc--; + argv++; + } else { + fprintf(stderr, "Invalid option: %s\n", *argv); + usage(); + } + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_CPU_PARMS, &sel, sizeof(sel)); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int +print_cpu(struct action_util *au,FILE * f, struct rtattr *arg) +{ + struct tc_cpu *sel; + struct rtattr *tb[TCA_CPU_MAX + 1]; + char buf[12]; + const static char *type_str[] = { + [TCA_CPU_TYPE_MAP] = "map", + [TCA_CPU_TYPE_CPUID] = "cpuid", + [TCA_CPU_TYPE_SOCKET] = "socket" + }; + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_CPU_MAX, arg); + + if (tb[TCA_CPU_PARMS] == NULL) { + fprintf(f, "[NULL cpu parameters]"); + return -1; + } + sel = RTA_DATA(tb[TCA_CPU_PARMS]); + + if (sel->type != TCA_CPU_TYPE_SOCKET) + sprintf(buf, "%u", sel->value); + else + buf[0] = '\0'; + + fprintf(f, " cpu %s%s%s", type_str[sel->type], + sel->type == TCA_CPU_TYPE_SOCKET ? "" : " ", buf); + + if (show_stats) { + if (tb[TCA_CPU_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_CPU_TM]); + print_tm(f,tm); + } + } + + return 0; +} + +struct action_util cpu_action_util = { + .id = "cpu", + .parse_aopt = parse_cpu, + .print_aopt = print_cpu, +};