@@ -0,0 +1,31 @@
+#ifndef __LINUX_TC_CPU_H
+#define __LINUX_TC_CPU_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#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 */
@@ -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
@@ -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 <xiaosuo@gmail.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 <linux/tc_act/tc_cpu.h>
+
+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,
+};