From 292117e876e2e3b7fe1d2ce206371c98cd16a3b8 Mon Sep 17 00:00:00 2001
From: Corey Hickey <bugfood-ml@fatooh.org>
Date: Sun, 27 Jan 2008 23:20:36 -0800
Subject: [PATCH 4/4] Add hash type selection.

Signed-off-by: Corey Hickey <bugfood-ml@fatooh.org>
---
 include/linux/pkt_sched.h |   18 ++++++++++
 tc/q_sfq.c                |   81 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index b1a1a52..244bae8 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -157,11 +157,29 @@ enum
 	TCA_SFQ_LIMIT,
 	TCA_SFQ_DIVISOR,
 	TCA_SFQ_FLOWS,
+	TCA_SFQ_HASH,
 	__TCA_SFQ_MAX,
 };
 
 #define TCA_SFQ_MAX (__TCA_SFQ_MAX - 1)
 
+enum
+{
+        TCA_SFQ_HASH_CLASSIC,
+        TCA_SFQ_HASH_DST,
+        TCA_SFQ_HASH_SRC,
+        TCA_SFQ_HASH_FWMARK,
+	/* conntrack */
+        TCA_SFQ_HASH_CTORIGDST,
+        TCA_SFQ_HASH_CTORIGSRC,
+        TCA_SFQ_HASH_CTREPLDST,
+        TCA_SFQ_HASH_CTREPLSRC,
+        TCA_SFQ_HASH_CTNATCHG,
+	__TCA_SFQ_HASH_MAX,
+};
+
+#define TCA_SFQ_HASH_MAX (__TCA_SFQ_HASH_MAX - 1)
+
 /* RED section */
 
 enum
diff --git a/tc/q_sfq.c b/tc/q_sfq.c
index 69f17c8..f40f87c 100644
--- a/tc/q_sfq.c
+++ b/tc/q_sfq.c
@@ -25,7 +25,11 @@
 
 static void explain(void)
 {
-	fprintf(stderr, "Usage: ... sfq [ limit NUMBER ] [ depth FLOWS ] [ divisor HASHBITS ] [ perturb SECS ] [ quantum BYTES ]\n");
+	fprintf(stderr,
+	    "Usage: ... sfq [ limit NUMBER ] [ depth FLOWS ] [ divisor HASHBITS ] [ perturb SECS ] [ quantum BYTES ] [ hash HASHTYPE ]\n"
+	    "Where: \n"
+	    "HASHTYPE := { classic | src | dst | fwmark | ctorigdst | ctorigsrc | ctrepldst | ctreplsrc | ctnatchg}\n"
+	);
 }
 
 #define usage() return(-1)
@@ -90,6 +94,32 @@ static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
 			}
 			addattr32(n, 1024, TCA_SFQ_DIVISOR, opt.divisor);
 			ok++;
+		} else if (strcmp(*argv, "hash") == 0) {
+			NEXT_ARG();
+			if (strcmp(*argv, "classic") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CLASSIC);
+			} else if (strcmp(*argv, "dst") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_DST);
+			} else if (strcmp(*argv, "src") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_SRC);
+			} else if (strcmp(*argv, "fwmark") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_FWMARK);
+			} else if (strcmp(*argv, "ctorigsrc") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CTORIGSRC);
+			} else if (strcmp(*argv, "ctorigdst") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CTORIGDST);
+			} else if (strcmp(*argv, "ctreplsrc") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CTREPLSRC);
+			} else if (strcmp(*argv, "ctrepldst") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CTREPLDST);
+			} else if (strcmp(*argv, "ctnatchg") == 0) {
+				addattr32(n, 1024, TCA_SFQ_HASH, TCA_SFQ_HASH_CTNATCHG);
+			} else {
+				fprintf(stderr, "Illegal \"hash\"\n");
+				explain();
+				return -1;
+			}
+			ok++;
 		} else if (strcmp(*argv, "help") == 0) {
 			explain();
 			return -1;
@@ -114,14 +144,16 @@ static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
 static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
 	struct tc_sfq_qopt *qopt;
+	struct rtattr *tb[TCA_SFQ_MAX+1];
 	SPRINT_BUF(b1);
 
 	if (opt == NULL)
 		return 0;
 
-	if (RTA_PAYLOAD(opt)  < sizeof(*qopt))
+	if (parse_rtattr_nested_compat(tb, TCA_SFQ_MAX, opt, qopt,
+	    sizeof(*qopt)))
 		return -1;
-	qopt = RTA_DATA(opt);
+
 	fprintf(f, "limit %up ", qopt->limit);
 	fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1));
 	if (show_details) {
@@ -129,6 +161,49 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 	}
 	if (qopt->perturb_period)
 		fprintf(f, "perturb %usec ", qopt->perturb_period);
+	fprintf(f, "hash: ");
+	if (RTA_PAYLOAD(tb[TCA_SFQ_HASH]) < sizeof(unsigned))
+		fprintf(f, "unknown");
+	else {
+		unsigned hash = *(unsigned *)RTA_DATA(tb[TCA_SFQ_HASH]);
+		switch (hash) {
+		case TCA_SFQ_HASH_CLASSIC:
+			fprintf(f, "classic");
+			break;
+		case TCA_SFQ_HASH_DST:
+			fprintf(f, "dst");
+			break;
+
+		case TCA_SFQ_HASH_SRC:
+			fprintf(f, "src");
+			break;
+
+		case TCA_SFQ_HASH_FWMARK:
+			fprintf(f, "fwmark");
+			break;
+		case TCA_SFQ_HASH_CTORIGDST:
+			fprintf(f, "ctorigdst");
+			break;
+
+		case TCA_SFQ_HASH_CTORIGSRC:
+			fprintf(f, "ctorigsrc");
+			break;
+
+		case TCA_SFQ_HASH_CTREPLDST:
+			fprintf(f, "ctrepldst");
+			break;
+
+		case TCA_SFQ_HASH_CTREPLSRC:
+			fprintf(f, "ctreplsrc");
+			break;
+
+		case TCA_SFQ_HASH_CTNATCHG:
+			fprintf(f, "ctnatchg");
+			break;
+		default:
+			fprintf(f, "unknown_%u", hash);
+		}
+	}
 	return 0;
 }
 
-- 
1.5.3.8

