Merge branch 'master' into net-next
diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h
new file mode 100644
index 0000000..d648ff6
--- /dev/null
+++ b/include/linux/tc_act/tc_ife.h
@@ -0,0 +1,38 @@
+#ifndef __UAPI_TC_IFE_H
+#define __UAPI_TC_IFE_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_IFE 25
+/* Flag bits for now just encoding/decoding; mutually exclusive */
+#define IFE_ENCODE 1
+#define IFE_DECODE 0
+
+struct tc_ife {
+	tc_gen;
+	__u16 flags;
+};
+
+/*XXX: We need to encode the total number of bytes consumed */
+enum {
+	TCA_IFE_UNSPEC,
+	TCA_IFE_PARMS,
+	TCA_IFE_TM,
+	TCA_IFE_DMAC,
+	TCA_IFE_SMAC,
+	TCA_IFE_TYPE,
+	TCA_IFE_METALST,
+	__TCA_IFE_MAX
+};
+#define TCA_IFE_MAX (__TCA_IFE_MAX - 1)
+
+#define IFE_META_SKBMARK 1
+#define IFE_META_HASHID 2
+#define	IFE_META_PRIO 3
+#define	IFE_META_QMAP 4
+/*Can be overridden at runtime by module option*/
+#define	__IFE_META_MAX 5
+#define IFE_META_MAX (__IFE_META_MAX - 1)
+
+#endif
diff --git a/tc/Makefile b/tc/Makefile
index f5bea87..20f5110 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -43,6 +43,7 @@
 TCMODULES += m_mirred.o
 TCMODULES += m_nat.o
 TCMODULES += m_pedit.o
+TCMODULES += m_ife.o
 TCMODULES += m_skbedit.o
 TCMODULES += m_csum.o
 TCMODULES += m_simple.o
diff --git a/tc/m_connmark.c b/tc/m_connmark.c
index b1c7d3a..143d75d 100644
--- a/tc/m_connmark.c
+++ b/tc/m_connmark.c
@@ -99,7 +99,8 @@
 			sel.action = TC_ACT_UNSPEC;
 			argc--;
 			argv++;
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			sel.action = TC_ACT_OK;
 			argc--;
 			argv++;
diff --git a/tc/m_csum.c b/tc/m_csum.c
index 36181fa..fb1183a 100644
--- a/tc/m_csum.c
+++ b/tc/m_csum.c
@@ -140,7 +140,8 @@
 			sel.action = TC_ACT_UNSPEC;
 			argc--;
 			argv++;
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			sel.action = TC_ACT_OK;
 			argc--;
 			argv++;
diff --git a/tc/m_ife.c b/tc/m_ife.c
new file mode 100644
index 0000000..ed01ff7
--- /dev/null
+++ b/tc/m_ife.c
@@ -0,0 +1,342 @@
+/*
+ * m_ife.c	IFE 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 (jhs@mojatatu.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 <linux/netdevice.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_ife.h>
+
+static void ife_explain(void)
+{
+	fprintf(stderr,
+		"Usage:... ife {decode|encode} {ALLOW|USE} [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n");
+	fprintf(stderr,
+		"\tALLOW := Encode direction. Allows encoding specified metadata\n"
+		"\t\t e.g \"allow mark\"\n"
+		"\tUSE := Encode direction. Enforce Static encoding of specified metadata\n"
+		"\t\t e.g \"use mark 0x12\"\n"
+		"\tDMAC := 6 byte Destination MAC address to encode\n"
+		"\tSMAC := optional 6 byte Source MAC address to encode\n"
+		"\tTYPE := optional 16 bit ethertype to encode\n"
+		"\tCONTROL := reclassify|pipe|drop|continue|ok\n"
+		"\tINDEX := optional IFE table index value used\n");
+	fprintf(stderr, "encode is used for sending IFE packets\n");
+	fprintf(stderr, "decode is used for receiving IFE packets\n");
+}
+
+static void ife_usage(void)
+{
+	ife_explain();
+	exit(-1);
+}
+
+static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
+		     int tca_id, struct nlmsghdr *n)
+{
+	int argc = *argc_p;
+	char **argv = *argv_p;
+	int ok = 0;
+	struct tc_ife p;
+	struct rtattr *tail;
+	struct rtattr *tail2;
+	char dbuf[ETH_ALEN];
+	char sbuf[ETH_ALEN];
+	__u16 ife_type = 0;
+	__u32 ife_prio = 0;
+	__u32 ife_prio_v = 0;
+	__u32 ife_mark = 0;
+	__u32 ife_mark_v = 0;
+	char *daddr = NULL;
+	char *saddr = NULL;
+
+	memset(&p, 0, sizeof(p));
+	p.action = TC_ACT_PIPE;	/* good default */
+
+	if (argc <= 0)
+		return -1;
+
+	while (argc > 0) {
+		if (matches(*argv, "ife") == 0) {
+			NEXT_ARG();
+			continue;
+		} else if (matches(*argv, "decode") == 0) {
+			p.flags = IFE_DECODE; /* readability aid */
+			ok++;
+		} else if (matches(*argv, "encode") == 0) {
+			p.flags = IFE_ENCODE;
+			ok++;
+		} else if (matches(*argv, "allow") == 0) {
+			NEXT_ARG();
+			if (matches(*argv, "mark") == 0) {
+				ife_mark = IFE_META_SKBMARK;
+			} else if (matches(*argv, "prio") == 0) {
+				ife_prio = IFE_META_PRIO;
+			} else {
+				fprintf(stderr, "Illegal meta define <%s>\n",
+					*argv);
+				return -1;
+			}
+		} else if (matches(*argv, "use") == 0) {
+			NEXT_ARG();
+			if (matches(*argv, "mark") == 0) {
+				NEXT_ARG();
+				if (get_u32(&ife_mark_v, *argv, 0))
+					invarg("ife mark val is invalid",
+					       *argv);
+			} else if (matches(*argv, "prio") == 0) {
+				NEXT_ARG();
+				if (get_u32(&ife_prio_v, *argv, 0))
+					invarg("ife prio val is invalid",
+					       *argv);
+			} else {
+				fprintf(stderr, "Illegal meta use type <%s>\n",
+					*argv);
+				return -1;
+			}
+		} else if (matches(*argv, "type") == 0) {
+			NEXT_ARG();
+			if (get_u16(&ife_type, *argv, 0))
+				invarg("ife type is invalid", *argv);
+			fprintf(stderr, "IFE type 0x%x\n", ife_type);
+		} else if (matches(*argv, "dst") == 0) {
+			NEXT_ARG();
+			daddr = *argv;
+			if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+				   dbuf, dbuf + 1, dbuf + 2,
+				   dbuf + 3, dbuf + 4, dbuf + 5) != 6) {
+				fprintf(stderr, "Invalid mac address %s\n",
+					daddr);
+			}
+			fprintf(stderr, "dst MAC address <%s>\n", daddr);
+
+		} else if (matches(*argv, "src") == 0) {
+			NEXT_ARG();
+			saddr = *argv;
+			if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+				   sbuf, sbuf + 1, sbuf + 2,
+				   sbuf + 3, sbuf + 4, sbuf + 5) != 6) {
+				fprintf(stderr, "Invalid mac address %s\n",
+					saddr);
+			}
+			fprintf(stderr, "src MAC address <%s>\n", saddr);
+		} else if (matches(*argv, "help") == 0) {
+			ife_usage();
+		} else {
+			break;
+		}
+
+		argc--;
+		argv++;
+	}
+
+	if (argc) {
+		if (matches(*argv, "reclassify") == 0) {
+			p.action = TC_ACT_RECLASSIFY;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "pipe") == 0) {
+			p.action = TC_ACT_PIPE;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "drop") == 0 ||
+			   matches(*argv, "shot") == 0) {
+			p.action = TC_ACT_SHOT;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "continue") == 0) {
+			p.action = TC_ACT_UNSPEC;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
+			p.action = TC_ACT_OK;
+			argc--;
+			argv++;
+		}
+	}
+
+	if (argc) {
+		if (matches(*argv, "index") == 0) {
+			NEXT_ARG();
+			if (get_u32(&p.index, *argv, 10)) {
+				fprintf(stderr, "ife: Illegal \"index\"\n");
+				return -1;
+			}
+			argc--;
+			argv++;
+		}
+	}
+
+	if (!ok) {
+		fprintf(stderr, "IFE requires decode/encode specified\n");
+		ife_usage();
+	}
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+	addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p));
+
+	if (!(p.flags & IFE_ENCODE))
+		goto skip_encode;
+
+	if (daddr)
+		addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN);
+	if (ife_type)
+		addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2);
+	if (saddr)
+		addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN);
+
+	tail2 = NLMSG_TAIL(n);
+	addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0);
+	if (ife_mark || ife_mark_v) {
+		if (ife_mark_v)
+			addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4);
+		else
+			addattr_l(n, MAX_MSG, IFE_META_SKBMARK, NULL, 0);
+	}
+	if (ife_prio || ife_prio_v) {
+		if (ife_prio_v)
+			addattr_l(n, MAX_MSG, IFE_META_PRIO, &ife_prio_v, 4);
+		else
+			addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0);
+	}
+
+	tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2;
+
+skip_encode:
+	tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+
+	*argc_p = argc;
+	*argv_p = argv;
+	return 0;
+}
+
+static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
+{
+	struct tc_ife *p = NULL;
+	struct rtattr *tb[TCA_IFE_MAX + 1];
+	__u16 ife_type = 0;
+	__u32 mmark = 0;
+	__u32 mhash = 0;
+	__u32 mprio = 0;
+	int has_optional = 0;
+	SPRINT_BUF(b1);
+	SPRINT_BUF(b2);
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, TCA_IFE_MAX, arg);
+
+	if (tb[TCA_IFE_PARMS] == NULL) {
+		fprintf(f, "[NULL ife parameters]");
+		return -1;
+	}
+	p = RTA_DATA(tb[TCA_IFE_PARMS]);
+
+	fprintf(f, "ife %s action %s ",
+		(p->flags & IFE_ENCODE) ? "encode" : "decode",
+		action_n2a(p->action, b1, sizeof(b1)));
+
+	if (tb[TCA_IFE_TYPE]) {
+		ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]);
+		has_optional = 1;
+		fprintf(f, "type 0x%X ", ife_type);
+	}
+
+	if (has_optional)
+		fprintf(f, "\n\t ");
+
+	if (tb[TCA_IFE_METALST]) {
+		struct rtattr *metalist[IFE_META_MAX + 1];
+		int len = 0;
+
+		parse_rtattr_nested(metalist, IFE_META_MAX,
+				    tb[TCA_IFE_METALST]);
+
+		if (metalist[IFE_META_SKBMARK]) {
+			len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]);
+			if (len) {
+				mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]);
+				fprintf(f, "use mark %d ", mmark);
+			} else
+				fprintf(f, "allow mark ");
+		}
+
+		if (metalist[IFE_META_HASHID]) {
+			len = RTA_PAYLOAD(metalist[IFE_META_HASHID]);
+			if (len) {
+				mhash = rta_getattr_u32(metalist[IFE_META_HASHID]);
+				fprintf(f, "use hash %d ", mhash);
+			} else
+				fprintf(f, "allow hash ");
+		}
+
+		if (metalist[IFE_META_PRIO]) {
+			len = RTA_PAYLOAD(metalist[IFE_META_PRIO]);
+			if (len) {
+				mprio = rta_getattr_u32(metalist[IFE_META_PRIO]);
+				fprintf(f, "use prio %d ", mprio);
+			} else
+				fprintf(f, "allow prio ");
+		}
+
+	}
+
+	if (tb[TCA_IFE_DMAC]) {
+		has_optional = 1;
+		fprintf(f, "dst %s ",
+			ll_addr_n2a(RTA_DATA(tb[TCA_IFE_DMAC]),
+				    RTA_PAYLOAD(tb[TCA_IFE_DMAC]), 0, b2,
+				    sizeof(b2)));
+
+	}
+
+	if (tb[TCA_IFE_SMAC]) {
+		has_optional = 1;
+		fprintf(f, "src %s ",
+			ll_addr_n2a(RTA_DATA(tb[TCA_IFE_SMAC]),
+				    RTA_PAYLOAD(tb[TCA_IFE_SMAC]), 0, b2,
+				    sizeof(b2)));
+	}
+
+	fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt,
+		p->bindcnt);
+	if (show_stats) {
+		if (tb[TCA_IFE_TM]) {
+			struct tcf_t *tm = RTA_DATA(tb[TCA_IFE_TM]);
+
+			print_tm(f, tm);
+		}
+	}
+
+	fprintf(f, "\n");
+
+	return 0;
+}
+
+struct action_util ife_action_util = {
+	.id = "ife",
+	.parse_aopt = parse_ife,
+	.print_aopt = print_ife,
+};
diff --git a/tc/m_mirred.c b/tc/m_mirred.c
index e7e69df..64aad4d 100644
--- a/tc/m_mirred.c
+++ b/tc/m_mirred.c
@@ -172,7 +172,8 @@
 		} else if (matches(*argv, "continue") == 0) {
 			p.action = TC_POLICE_UNSPEC;
 			NEXT_ARG();
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			p.action = TC_POLICE_OK;
 			NEXT_ARG();
 		}
diff --git a/tc/m_nat.c b/tc/m_nat.c
index 4b90121..4d1b1ed 100644
--- a/tc/m_nat.c
+++ b/tc/m_nat.c
@@ -135,7 +135,8 @@
 			sel.action = TC_ACT_UNSPEC;
 			argc--;
 			argv++;
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			sel.action = TC_ACT_OK;
 			argc--;
 			argv++;
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
index 2a94dfb..a539b68 100644
--- a/tc/m_pedit.c
+++ b/tc/m_pedit.c
@@ -495,7 +495,8 @@
 		} else if (matches(*argv, "continue") == 0) {
 			sel.sel.action = TC_ACT_UNSPEC;
 			NEXT_ARG();
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			sel.sel.action = TC_ACT_OK;
 			NEXT_ARG();
 		}
diff --git a/tc/m_simple.c b/tc/m_simple.c
index e167cca..feba61b 100644
--- a/tc/m_simple.c
+++ b/tc/m_simple.c
@@ -81,9 +81,10 @@
 #endif
 static void explain(void)
 {
-	fprintf(stderr, "Usage: ... simple STRING\n"
-		"STRING being an arbitrary string\n"
-		"example: \"simple blah\"\n");
+	fprintf(stderr, "Usage:... simple [sdata STRING] [CONTROL] [index INDEX]\n");
+	fprintf(stderr, "\tSTRING being an arbitrary string\n"
+		"\tCONTROL := reclassify|pipe|drop|continue|ok\n"
+		"\tINDEX := optional index value used\n");
 }
 
 static void usage(void)
@@ -99,25 +100,64 @@
 	struct tc_defact sel = {};
 	int argc = *argc_p;
 	char **argv = *argv_p;
-	int ok = 0;
+	int ok = 0, maybe_bind = 0;
 	struct rtattr *tail;
 	char *simpdata = NULL;
 
-
 	while (argc > 0) {
 		if (matches(*argv, "simple") == 0) {
 			NEXT_ARG();
+		} else if (matches(*argv, "sdata") == 0) {
+			NEXT_ARG();
+			ok += 1;
 			simpdata = *argv;
-			ok = 1;
 			argc--;
 			argv++;
-			break;
 		} else if (matches(*argv, "help") == 0) {
 			usage();
 		} else {
 			break;
 		}
+	}
 
+	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 ||
+			   matches(*argv, "ok") == 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, "simple: Illegal \"index\"\n",
+					*argv);
+				return -1;
+			}
+			ok += 1;
+			argc--;
+			argv++;
+		}
 	}
 
 	if (!ok) {
@@ -125,30 +165,20 @@
 		return -1;
 	}
 
-	if (argc) {
-		if (matches(*argv, "index") == 0) {
-			NEXT_ARG();
-			if (get_u32(&sel.index, *argv, 10)) {
-				fprintf(stderr, "simple: Illegal \"index\"\n");
-				return -1;
-			}
-			argc--;
-			argv++;
-		}
-	}
-
-	if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) {
+	if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) {
 		fprintf(stderr, "simple: Illegal string len %zu <%s>\n",
 			strlen(simpdata), simpdata);
 		return -1;
 	}
 
+
 	sel.action = TC_ACT_PIPE;
 
 	tail = NLMSG_TAIL(n);
 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
 	addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel));
-	addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
+	if (simpdata)
+		addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
 
 	*argc_p = argc;
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
index 180b9cb..9ba288c 100644
--- a/tc/m_skbedit.c
+++ b/tc/m_skbedit.c
@@ -114,7 +114,8 @@
 		} else if (matches(*argv, "continue") == 0) {
 			sel.action = TC_ACT_UNSPEC;
 			NEXT_ARG();
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			sel.action = TC_ACT_OK;
 			NEXT_ARG();
 		}
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index 3233d20..c268446 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -119,7 +119,8 @@
 			parm.action = TC_ACT_UNSPEC;
 			argc--;
 			argv++;
-		} else if (matches(*argv, "pass") == 0) {
+		} else if (matches(*argv, "pass") == 0 ||
+			   matches(*argv, "ok") == 0) {
 			parm.action = TC_ACT_OK;
 			argc--;
 			argv++;