summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/tc_ematch/tc_em_meta.h89
-rw-r--r--include/netlink/route/cls/ematch.h1
-rw-r--r--include/netlink/route/cls/ematch/meta.h41
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/route/cls/ematch.c14
-rw-r--r--lib/route/cls/ematch/meta.c291
-rw-r--r--lib/route/cls/ematch_grammar.l56
-rw-r--r--lib/route/cls/ematch_syntax.y154
8 files changed, 644 insertions, 3 deletions
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
new file mode 100644
index 0000000..fe815e2
--- /dev/null
+++ b/include/linux/tc_ematch/tc_em_meta.h
@@ -0,0 +1,89 @@
+#ifndef __LINUX_TC_EM_META_H
+#define __LINUX_TC_EM_META_H
+
+enum {
+ TCA_EM_META_UNSPEC,
+ TCA_EM_META_HDR,
+ TCA_EM_META_LVALUE,
+ TCA_EM_META_RVALUE,
+ __TCA_EM_META_MAX
+};
+#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1)
+
+struct tcf_meta_val {
+ __u16 kind;
+ __u8 shift;
+ __u8 op;
+};
+
+#define TCF_META_TYPE_MASK (0xf << 12)
+#define TCF_META_TYPE(kind) (((kind) & TCF_META_TYPE_MASK) >> 12)
+#define TCF_META_ID_MASK 0x7ff
+#define TCF_META_ID(kind) ((kind) & TCF_META_ID_MASK)
+
+enum {
+ TCF_META_TYPE_VAR,
+ TCF_META_TYPE_INT,
+ __TCF_META_TYPE_MAX
+};
+#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1)
+
+enum {
+ TCF_META_ID_VALUE,
+ TCF_META_ID_RANDOM,
+ TCF_META_ID_LOADAVG_0,
+ TCF_META_ID_LOADAVG_1,
+ TCF_META_ID_LOADAVG_2,
+ TCF_META_ID_DEV,
+ TCF_META_ID_PRIORITY,
+ TCF_META_ID_PROTOCOL,
+ TCF_META_ID_PKTTYPE,
+ TCF_META_ID_PKTLEN,
+ TCF_META_ID_DATALEN,
+ TCF_META_ID_MACLEN,
+ TCF_META_ID_NFMARK,
+ TCF_META_ID_TCINDEX,
+ TCF_META_ID_RTCLASSID,
+ TCF_META_ID_RTIIF,
+ TCF_META_ID_SK_FAMILY,
+ TCF_META_ID_SK_STATE,
+ TCF_META_ID_SK_REUSE,
+ TCF_META_ID_SK_BOUND_IF,
+ TCF_META_ID_SK_REFCNT,
+ TCF_META_ID_SK_SHUTDOWN,
+ TCF_META_ID_SK_PROTO,
+ TCF_META_ID_SK_TYPE,
+ TCF_META_ID_SK_RCVBUF,
+ TCF_META_ID_SK_RMEM_ALLOC,
+ TCF_META_ID_SK_WMEM_ALLOC,
+ TCF_META_ID_SK_OMEM_ALLOC,
+ TCF_META_ID_SK_WMEM_QUEUED,
+ TCF_META_ID_SK_RCV_QLEN,
+ TCF_META_ID_SK_SND_QLEN,
+ TCF_META_ID_SK_ERR_QLEN,
+ TCF_META_ID_SK_FORWARD_ALLOCS,
+ TCF_META_ID_SK_SNDBUF,
+ TCF_META_ID_SK_ALLOCS,
+ TCF_META_ID_SK_ROUTE_CAPS,
+ TCF_META_ID_SK_HASH,
+ TCF_META_ID_SK_LINGERTIME,
+ TCF_META_ID_SK_ACK_BACKLOG,
+ TCF_META_ID_SK_MAX_ACK_BACKLOG,
+ TCF_META_ID_SK_PRIO,
+ TCF_META_ID_SK_RCVLOWAT,
+ TCF_META_ID_SK_RCVTIMEO,
+ TCF_META_ID_SK_SNDTIMEO,
+ TCF_META_ID_SK_SENDMSG_OFF,
+ TCF_META_ID_SK_WRITE_PENDING,
+ TCF_META_ID_VLAN_TAG,
+ TCF_META_ID_RXHASH,
+ __TCF_META_ID_MAX
+};
+#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
+
+struct tcf_meta_hdr {
+ struct tcf_meta_val left;
+ struct tcf_meta_val right;
+};
+
+#endif
diff --git a/include/netlink/route/cls/ematch.h b/include/netlink/route/cls/ematch.h
index 52c4750..13f9c32 100644
--- a/include/netlink/route/cls/ematch.h
+++ b/include/netlink/route/cls/ematch.h
@@ -86,6 +86,7 @@ extern int rtnl_ematch_parse_expr(const char *, char **,
extern char * rtnl_ematch_offset2txt(uint8_t, uint16_t,
char *, size_t);
+extern char * rtnl_ematch_opnd2txt(uint8_t, char *, size_t);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/cls/ematch/meta.h b/include/netlink/route/cls/ematch/meta.h
new file mode 100644
index 0000000..2fe5899
--- /dev/null
+++ b/include/netlink/route/cls/ematch/meta.h
@@ -0,0 +1,41 @@
+/*
+ * netlink/route/cls/ematch/meta.h Metadata Match
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_META_H_
+#define NETLINK_CLS_EMATCH_META_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_meta.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_meta_value;
+
+extern struct rtnl_meta_value * rtnl_meta_value_alloc_int(uint64_t);
+extern struct rtnl_meta_value * rtnl_meta_value_alloc_var(void *, size_t);
+extern struct rtnl_meta_value * rtnl_meta_value_alloc_id(uint8_t, uint16_t,
+ uint8_t, uint64_t);
+extern void rtnl_meta_value_put(struct rtnl_meta_value *);
+
+extern void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *,
+ struct rtnl_meta_value *);
+void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *,
+ struct rtnl_meta_value *);
+extern void rtnl_ematch_meta_set_operand(struct rtnl_ematch *, uint8_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7c869dc..6cfce33 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -56,6 +56,7 @@ libnl_route_la_SOURCES = \
route/cls/ematch.c \
route/cls/ematch/container.c route/cls/ematch/cmp.c \
route/cls/ematch/nbyte.c route/cls/ematch/text.c \
+ route/cls/ematch/meta.c \
\
route/link/api.c route/link/vlan.c \
\
diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c
index 76c34be..e2719c2 100644
--- a/lib/route/cls/ematch.c
+++ b/lib/route/cls/ematch.c
@@ -682,4 +682,18 @@ char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t l
return buf;
}
+static const char *operand_txt[] = {
+ [TCF_EM_OPND_EQ] = "=",
+ [TCF_EM_OPND_LT] = "<",
+ [TCF_EM_OPND_GT] = ">",
+};
+
+char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
+{
+ snprintf(buf, len, "%s",
+ opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");
+
+ return buf;
+}
+
/** @} */
diff --git a/lib/route/cls/ematch/meta.c b/lib/route/cls/ematch/meta.c
new file mode 100644
index 0000000..5752c75
--- /dev/null
+++ b/lib/route/cls/ematch/meta.c
@@ -0,0 +1,291 @@
+/*
+ * lib/route/cls/ematch/meta.c Metadata Match
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_meta Metadata Match
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+struct rtnl_meta_value
+{
+ uint8_t mv_type;
+ uint8_t mv_shift;
+ uint16_t mv_id;
+ size_t mv_len;
+};
+
+struct meta_data
+{
+ struct rtnl_meta_value * left;
+ struct rtnl_meta_value * right;
+ uint8_t opnd;
+};
+
+static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id,
+ uint8_t shift, void *data,
+ size_t len)
+{
+ struct rtnl_meta_value *value;
+
+ if (!(value = calloc(1, sizeof(*value) + len)))
+ return NULL;
+
+ value->mv_type = type;
+ value->mv_id = id;
+ value->mv_shift = shift;
+ value->mv_len = len;
+
+ memcpy(value + 1, data, len);
+
+ return value;
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_int(uint64_t value)
+{
+ return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_var(void *data, size_t len)
+{
+ return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t id,
+ uint8_t shift, uint64_t mask)
+{
+ size_t masklen = 0;
+
+ if (id > TCF_META_ID_MAX)
+ return NULL;
+
+ if (mask) {
+ if (type == TCF_META_TYPE_VAR)
+ return NULL;
+
+ masklen = 8;
+ }
+
+ return meta_alloc(type, id, shift, &mask, masklen);
+}
+
+void rtnl_meta_value_put(struct rtnl_meta_value *mv)
+{
+ free(mv);
+}
+
+void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ m->left = v;
+}
+
+void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ m->right = v;
+}
+
+void rtnl_ematch_meta_set_operand(struct rtnl_ematch *e, uint8_t opnd)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ m->opnd = opnd;
+}
+
+static struct nla_policy meta_policy[TCA_EM_META_MAX+1] = {
+ [TCA_EM_META_HDR] = { .minlen = sizeof(struct tcf_meta_hdr) },
+ [TCA_EM_META_LVALUE] = { .minlen = 1, },
+ [TCA_EM_META_RVALUE] = { .minlen = 1, },
+};
+
+static int meta_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ struct nlattr *tb[TCA_EM_META_MAX+1];
+ struct rtnl_meta_value *v;
+ struct tcf_meta_hdr *hdr;
+ void *vdata = NULL;
+ size_t vlen = 0;
+ int err;
+
+ if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0)
+ return err;
+
+ if (!tb[TCA_EM_META_HDR])
+ return -NLE_MISSING_ATTR;
+
+ hdr = nla_data(tb[TCA_EM_META_HDR]);
+
+ if (tb[TCA_EM_META_LVALUE]) {
+ vdata = nla_data(tb[TCA_EM_META_LVALUE]);
+ vlen = nla_len(tb[TCA_EM_META_LVALUE]);
+ }
+
+ v = meta_alloc(TCF_META_TYPE(hdr->left.kind),
+ TCF_META_ID(hdr->left.kind),
+ hdr->left.shift, vdata, vlen);
+ if (!v)
+ return -NLE_NOMEM;
+
+ m->left = v;
+
+ vlen = 0;
+ if (tb[TCA_EM_META_RVALUE]) {
+ vdata = nla_data(tb[TCA_EM_META_RVALUE]);
+ vlen = nla_len(tb[TCA_EM_META_RVALUE]);
+ }
+
+ v = meta_alloc(TCF_META_TYPE(hdr->right.kind),
+ TCF_META_ID(hdr->right.kind),
+ hdr->right.shift, vdata, vlen);
+ if (!v) {
+ rtnl_meta_value_put(m->left);
+ return -NLE_NOMEM;
+ }
+
+ m->right = v;
+ m->opnd = hdr->left.op;
+
+ return 0;
+}
+
+static struct trans_tbl meta_int[] = {
+ __ADD(TCF_META_ID_VLAN_TAG, vlan)
+ __ADD(TCF_META_ID_PKTLEN, pktlen)
+};
+
+static char *int_id2str(int id, char *buf, size_t size)
+{
+ return __type2str(id, buf, size, meta_int, ARRAY_SIZE(meta_int));
+}
+
+static struct trans_tbl meta_var[] = {
+ __ADD(TCF_META_ID_DEV,devname)
+ __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if)
+};
+
+static char *var_id2str(int id, char *buf, size_t size)
+{
+ return __type2str(id, buf, size, meta_var, ARRAY_SIZE(meta_var));
+}
+
+static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p)
+{
+ char buf[32];
+
+ switch (v->mv_type) {
+ case TCF_META_TYPE_INT:
+ if (v->mv_id == TCF_META_ID_VALUE) {
+ nl_dump(p, "%u",
+ *(uint32_t *) (v + 1));
+ } else {
+ nl_dump(p, "%s",
+ int_id2str(v->mv_id, buf, sizeof(buf)));
+
+ if (v->mv_shift)
+ nl_dump(p, " >> %u", v->mv_shift);
+
+ if (v->mv_len == 4)
+ nl_dump(p, " & %#x", *(uint32_t *) (v + 1));
+ else if (v->mv_len == 8)
+ nl_dump(p, " & %#x", *(uint64_t *) (v + 1));
+ }
+ break;
+
+ case TCF_META_TYPE_VAR:
+ if (v->mv_id == TCF_META_ID_VALUE) {
+ nl_dump(p, "%s", (char *) (v + 1));
+ } else {
+ nl_dump(p, "%s",
+ var_id2str(v->mv_id, buf, sizeof(buf)));
+
+ if (v->mv_shift)
+ nl_dump(p, " >> %u", v->mv_shift);
+ }
+ break;
+ }
+}
+
+static void meta_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ char buf[32];
+
+ nl_dump(p, "meta(");
+ dump_value(m->left, p);
+
+ nl_dump(p, " %s ", rtnl_ematch_opnd2txt(m->opnd, buf, sizeof(buf)));
+
+ dump_value(m->right, p);
+ nl_dump(p, ")");
+}
+
+static int meta_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ struct tcf_meta_hdr hdr;
+
+ if (!(m->left && m->right))
+ return -NLE_MISSING_ATTR;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.left.kind = (m->left->mv_type << 12) & TCF_META_TYPE_MASK;
+ hdr.left.kind |= m->left->mv_id & TCF_META_ID_MASK;
+ hdr.left.shift = m->left->mv_shift;
+ hdr.left.op = m->opnd;
+ hdr.right.kind = (m->right->mv_type << 12) & TCF_META_TYPE_MASK;
+ hdr.right.kind |= m->right->mv_id & TCF_META_ID_MASK;
+
+ NLA_PUT(msg, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+
+ if (m->left->mv_len)
+ NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1));
+
+ if (m->right->mv_len)
+ NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1));
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+static void meta_free(struct rtnl_ematch *e)
+{
+ struct meta_data *m = rtnl_ematch_data(e);
+ free(m->left);
+ free(m->right);
+}
+
+static struct rtnl_ematch_ops meta_ops = {
+ .eo_kind = TCF_EM_META,
+ .eo_name = "meta",
+ .eo_minlen = sizeof(struct tcf_meta_hdr),
+ .eo_datalen = sizeof(struct meta_data),
+ .eo_parse = meta_parse,
+ .eo_dump = meta_dump,
+ .eo_fill = meta_fill,
+ .eo_free = meta_free,
+};
+
+static void __init meta_init(void)
+{
+ rtnl_ematch_register(&meta_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l
index 998e867..07e7e8c 100644
--- a/lib/route/cls/ematch_grammar.l
+++ b/lib/route/cls/ematch_grammar.l
@@ -78,10 +78,14 @@ lt |
[cC][mM][pP] { yylval->i = TCF_EM_CMP; return EMATCH_CMP; }
[pP][aA][tT][tT][eE][rR][nN] { yylval->i = TCF_EM_NBYTE; return EMATCH_NBYTE; }
[tT][eE][xX][tT] { yylval->i = TCF_EM_TEXT; return EMATCH_TEXT; }
+[mM][eE][tT][aA] { yylval->i = TCF_EM_META; return EMATCH_META; }
"(" return KW_OPEN;
")" return KW_CLOSE;
-[mM][aA][sS][kK] return KW_MASK;
+[mM][aA][sS][kK] |
+"&" return KW_MASK;
+[sS][hH][iI][fF][tT] |
+">>" return KW_SHIFT;
[aA][tT] return KW_AT;
"+" return KW_PLUS;
[fF][rR][oO][mM] return KW_FROM;
@@ -99,6 +103,56 @@ lt |
[tT][rR][aA][nN][sS][pP][oO][rR][tT] |
[tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+random return META_RANDOM;
+loadavg_0 return META_LOADAVG_0;
+loadavg_1 return META_LOADAVG_1;
+loadavg_2 return META_LOADAVG_2;
+dev return META_DEV;
+prio return META_PRIO;
+proto return META_PROTO;
+pkttype return META_PKTTYPE;
+pktlen return META_PKTLEN;
+datalen return META_DATALEN;
+maclen return META_MACLEN;
+mark return META_MARK;
+tcindex return META_TCINDEX;
+rtclassid return META_RTCLASSID;
+rtiif return META_RTIIF;
+sk_family return META_SK_FAMILY;
+sk_state return META_SK_STATE;
+sk_reuse return META_SK_REUSE;
+sk_refcnt return META_SK_REFCNT;
+sk_rcvbuf return META_SK_RCVBUF;
+sk_sndbuf return META_SK_SNDBUF;
+sk_shutdown return META_SK_SHUTDOWN;
+sk_proto return META_SK_PROTO;
+sk_type return META_SK_TYPE;
+sk_rmem_alloc return META_SK_RMEM_ALLOC;
+sk_wmem_alloc return META_SK_WMEM_ALLOC;
+sk_wmem_queued return META_SK_WMEM_QUEUED;
+sk_rcv_qlen return META_SK_RCV_QLEN;
+sk_snd_qlen return META_SK_SND_QLEN;
+sk_err_qlen return META_SK_ERR_QLEN;
+sk_forward_allocs return META_SK_FORWARD_ALLOCS;
+sk_allocs return META_SK_ALLOCS;
+sk_route_caps return META_SK_ROUTE_CAPS;
+sk_hash return META_SK_HASH;
+sk_lingertime return META_SK_LINGERTIME;
+sk_ack_backlog return META_SK_ACK_BACKLOG;
+sk_max_ack_backlog return META_SK_MAX_ACK_BACKLOG;
+sk_prio return META_SK_PRIO;
+sk_rcvlowat return META_SK_RCVLOWAT;
+sk_rcvtimeo return META_SK_RCVTIMEO;
+sk_sndtimeo return META_SK_SNDTIMEO;
+sk_sendmsg_off return META_SK_SENDMSG_OFF;
+sk_write_pending return META_SK_WRITE_PENDING;
+vlan return META_VLAN;
+rxhash return META_RXHASH;
+
+devname return META_DEVNAME;
+sk_bound_if return META_SK_BOUND_IF;
+
+
[^ \t\r\n+()=<>&|\"]+ {
yylval->s = strdup(yytext);
if (yylval->s == NULL)
diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y
index 26642a3..61c91d1 100644
--- a/lib/route/cls/ematch_syntax.y
+++ b/lib/route/cls/ematch_syntax.y
@@ -19,6 +19,12 @@
#include <netlink/route/cls/ematch/cmp.h>
#include <netlink/route/cls/ematch/nbyte.h>
#include <netlink/route/cls/ematch/text.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+#define META_ALLOC rtnl_meta_value_alloc_id
+#define META_ID(name) TCF_META_ID_##name
+#define META_INT TCF_META_TYPE_INT
+#define META_VAR TCF_META_TYPE_VAR
%}
%error-verbose
@@ -35,7 +41,9 @@
struct ematch_quoted q;
struct rtnl_ematch * e;
struct rtnl_pktloc * loc;
+ struct rtnl_meta_value *mv;
uint32_t i;
+ uint64_t i64;
char * s;
}
@@ -54,29 +62,82 @@ static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const
%token <i> KW_CLOSE ")"
%token <i> KW_PLUS "+"
%token <i> KW_MASK "mask"
+%token <i> KW_SHIFT ">>"
%token <i> KW_AT "at"
%token <i> EMATCH_CMP "cmp"
%token <i> EMATCH_NBYTE "pattern"
%token <i> EMATCH_TEXT "text"
+%token <i> EMATCH_META "meta"
%token <i> KW_EQ "="
%token <i> KW_GT ">"
%token <i> KW_LT "<"
%token <i> KW_FROM "from"
%token <i> KW_TO "to"
+%token <i> META_RANDOM "random"
+%token <i> META_LOADAVG_0 "loadavg_0"
+%token <i> META_LOADAVG_1 "loadavg_1"
+%token <i> META_LOADAVG_2 "loadavg_2"
+%token <i> META_DEV "dev"
+%token <i> META_PRIO "prio"
+%token <i> META_PROTO "proto"
+%token <i> META_PKTTYPE "pkttype"
+%token <i> META_PKTLEN "pktlen"
+%token <i> META_DATALEN "datalen"
+%token <i> META_MACLEN "maclen"
+%token <i> META_MARK "mark"
+%token <i> META_TCINDEX "tcindex"
+%token <i> META_RTCLASSID "rtclassid"
+%token <i> META_RTIIF "rtiif"
+%token <i> META_SK_FAMILY "sk_family"
+%token <i> META_SK_STATE "sk_state"
+%token <i> META_SK_REUSE "sk_reuse"
+%token <i> META_SK_REFCNT "sk_refcnt"
+%token <i> META_SK_RCVBUF "sk_rcvbuf"
+%token <i> META_SK_SNDBUF "sk_sndbuf"
+%token <i> META_SK_SHUTDOWN "sk_shutdown"
+%token <i> META_SK_PROTO "sk_proto"
+%token <i> META_SK_TYPE "sk_type"
+%token <i> META_SK_RMEM_ALLOC "sk_rmem_alloc"
+%token <i> META_SK_WMEM_ALLOC "sk_wmem_alloc"
+%token <i> META_SK_WMEM_QUEUED "sk_wmem_queued"
+%token <i> META_SK_RCV_QLEN "sk_rcv_qlen"
+%token <i> META_SK_SND_QLEN "sk_snd_qlen"
+%token <i> META_SK_ERR_QLEN "sk_err_qlen"
+%token <i> META_SK_FORWARD_ALLOCS "sk_forward_allocs"
+%token <i> META_SK_ALLOCS "sk_allocs"
+%token <i> META_SK_ROUTE_CAPS "sk_route_caps"
+%token <i> META_SK_HASH "sk_hash"
+%token <i> META_SK_LINGERTIME "sk_lingertime"
+%token <i> META_SK_ACK_BACKLOG "sk_ack_backlog"
+%token <i> META_SK_MAX_ACK_BACKLOG "sk_max_ack_backlog"
+%token <i> META_SK_PRIO "sk_prio"
+%token <i> META_SK_RCVLOWAT "sk_rcvlowat"
+%token <i> META_SK_RCVTIMEO "sk_rcvtimeo"
+%token <i> META_SK_SNDTIMEO "sk_sndtimeo"
+%token <i> META_SK_SENDMSG_OFF "sk_sendmsg_off"
+%token <i> META_SK_WRITE_PENDING "sk_write_pending"
+%token <i> META_VLAN "vlan"
+%token <i> META_RXHASH "rxhash"
+%token <i> META_DEVNAME "devname"
+%token <i> META_SK_BOUND_IF "sk_bound_if"
+
%token <s> STR
%token <q> QUOTED
-%type <i> mask align operand
+%type <i> align operand shift meta_int_id meta_var_id
+%type <i64> mask
%type <e> expr match ematch
%type <cmp> cmp_expr cmp_match
%type <loc> pktloc text_from text_to
%type <q> pattern
+%type <mv> meta_value
%destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
%destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } <loc>
%destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } <q>
+%destructor { rtnl_meta_value_put($$); NL_DBG(2, "meta value destructor\n"); } <mv>
%start input
@@ -180,6 +241,24 @@ ematch:
$$ = e;
}
+ | EMATCH_META "(" meta_value operand meta_value ")"
+ {
+ struct rtnl_ematch *e;
+
+ if (!(e = rtnl_ematch_alloc())) {
+ asprintf(errp, "Unable to allocate ematch object");
+ YYABORT;
+ }
+
+ if (rtnl_ematch_set_kind(e, TCF_EM_META) < 0)
+ BUG();
+
+ rtnl_ematch_meta_set_lvalue(e, $3);
+ rtnl_ematch_meta_set_rvalue(e, $5);
+ rtnl_ematch_meta_set_operand(e, $4);
+
+ $$ = e;
+ }
/* CONTAINER */
| "(" expr ")"
{
@@ -249,6 +328,70 @@ text_to:
{ $$ = $2; }
;
+meta_value:
+ QUOTED
+ { $$ = rtnl_meta_value_alloc_var($1.data, $1.len); }
+ | NUMBER
+ { $$ = rtnl_meta_value_alloc_int($1); }
+ | meta_int_id shift mask
+ { $$ = META_ALLOC(META_INT, $1, $2, $3); }
+ | meta_var_id shift
+ { $$ = META_ALLOC(META_VAR, $1, $2, 0); }
+ ;
+
+meta_int_id:
+ META_RANDOM { $$ = META_ID(RANDOM); }
+ |META_LOADAVG_0 { $$ = META_ID(LOADAVG_0); }
+ |META_LOADAVG_1 { $$ = META_ID(LOADAVG_1); }
+ |META_LOADAVG_2 { $$ = META_ID(LOADAVG_2); }
+ | META_DEV { $$ = META_ID(DEV); }
+ | META_PRIO { $$ = META_ID(PRIORITY); }
+ | META_PROTO { $$ = META_ID(PROTOCOL); }
+ | META_PKTTYPE { $$ = META_ID(PKTTYPE); }
+ | META_PKTLEN { $$ = META_ID(PKTLEN); }
+ | META_DATALEN { $$ = META_ID(DATALEN); }
+ | META_MACLEN { $$ = META_ID(MACLEN); }
+ | META_MARK { $$ = META_ID(NFMARK); }
+ | META_TCINDEX { $$ = META_ID(TCINDEX); }
+ | META_RTCLASSID { $$ = META_ID(RTCLASSID); }
+ | META_RTIIF { $$ = META_ID(RTIIF); }
+ | META_SK_FAMILY { $$ = META_ID(SK_FAMILY); }
+ | META_SK_STATE { $$ = META_ID(SK_STATE); }
+ | META_SK_REUSE { $$ = META_ID(SK_REUSE); }
+ | META_SK_REFCNT { $$ = META_ID(SK_REFCNT); }
+ | META_SK_RCVBUF { $$ = META_ID(SK_RCVBUF); }
+ | META_SK_SNDBUF { $$ = META_ID(SK_SNDBUF); }
+ | META_SK_SHUTDOWN { $$ = META_ID(SK_SHUTDOWN); }
+ | META_SK_PROTO { $$ = META_ID(SK_PROTO); }
+ | META_SK_TYPE { $$ = META_ID(SK_TYPE); }
+ | META_SK_RMEM_ALLOC { $$ = META_ID(SK_RMEM_ALLOC); }
+ | META_SK_WMEM_ALLOC { $$ = META_ID(SK_WMEM_ALLOC); }
+ | META_SK_WMEM_QUEUED { $$ = META_ID(SK_WMEM_QUEUED); }
+ | META_SK_RCV_QLEN { $$ = META_ID(SK_RCV_QLEN); }
+ | META_SK_SND_QLEN { $$ = META_ID(SK_SND_QLEN); }
+ | META_SK_ERR_QLEN { $$ = META_ID(SK_ERR_QLEN); }
+ | META_SK_FORWARD_ALLOCS { $$ = META_ID(SK_FORWARD_ALLOCS); }
+ | META_SK_ALLOCS { $$ = META_ID(SK_ALLOCS); }
+ | META_SK_ROUTE_CAPS { $$ = META_ID(SK_ROUTE_CAPS); }
+ | META_SK_HASH { $$ = META_ID(SK_HASH); }
+ | META_SK_LINGERTIME { $$ = META_ID(SK_LINGERTIME); }
+ | META_SK_ACK_BACKLOG { $$ = META_ID(SK_ACK_BACKLOG); }
+ | META_SK_MAX_ACK_BACKLOG { $$ = META_ID(SK_MAX_ACK_BACKLOG); }
+ | META_SK_PRIO { $$ = META_ID(SK_PRIO); }
+ | META_SK_RCVLOWAT { $$ = META_ID(SK_RCVLOWAT); }
+ | META_SK_RCVTIMEO { $$ = META_ID(SK_RCVTIMEO); }
+ | META_SK_SNDTIMEO { $$ = META_ID(SK_SNDTIMEO); }
+ | META_SK_SENDMSG_OFF { $$ = META_ID(SK_SENDMSG_OFF); }
+ | META_SK_WRITE_PENDING { $$ = META_ID(SK_WRITE_PENDING); }
+ | META_VLAN { $$ = META_ID(VLAN_TAG); }
+ | META_RXHASH { $$ = META_ID(RXHASH); }
+ ;
+
+meta_var_id:
+ META_DEVNAME { $$ = META_ID(DEV); }
+ | META_SK_BOUND_IF { $$ = META_ID(SK_BOUND_IF); }
+ ;
+
/*
* pattern
*/
@@ -333,7 +476,14 @@ align:
mask:
/* empty */
{ $$ = 0; }
- | "mask" NUMBER
+ | KW_MASK NUMBER
+ { $$ = $2; }
+ ;
+
+shift:
+ /* empty */
+ { $$ = 0; }
+ | KW_SHIFT NUMBER
{ $$ = $2; }
;