summaryrefslogtreecommitdiff
path: root/lib/route/cls/ematch/cmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/cls/ematch/cmp.c')
-rw-r--r--lib/route/cls/ematch/cmp.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c
new file mode 100644
index 0000000..ec25320
--- /dev/null
+++ b/lib/route/cls/ematch/cmp.c
@@ -0,0 +1,116 @@
+/*
+ * lib/route/cls/ematch/cmp.c Simple packet data comparison ematch
+ *
+ * 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_cmp Simple packet data comparison
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+void rtnl_ematch_cmp_set(struct rtnl_ematch *ematch,
+ struct tcf_em_cmp *cfg)
+{
+ memcpy(rtnl_ematch_data(ematch), cfg, sizeof(*cfg));
+}
+
+struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *ematch)
+{
+ return rtnl_ematch_data(ematch);
+}
+
+static const char *align_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->align) {
+ case TCF_EM_ALIGN_U8:
+ return "u8";
+ case TCF_EM_ALIGN_U16:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h16" : "u16";
+ case TCF_EM_ALIGN_U32:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h32" : "u32";
+ default:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h?" : "u?";
+ }
+}
+
+static const char *layer_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->layer) {
+ case TCF_LAYER_LINK:
+ return "link";
+ case TCF_LAYER_NETWORK:
+ return "network";
+ case TCF_LAYER_TRANSPORT:
+ return "transport";
+ default:
+ return "?";
+ }
+}
+
+static const char *relation_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->opnd) {
+ case TCF_EM_OPND_EQ:
+ return "eq";
+ case TCF_EM_OPND_LT:
+ return "lt";
+ case TCF_EM_OPND_GT:
+ return "gt";
+ default:
+ return "?";
+ }
+}
+
+static int cmp_parse(struct rtnl_ematch *m, void *data, size_t len)
+{
+ memcpy(rtnl_ematch_data(m), data, len);
+
+ return 0;
+}
+
+static void cmp_dump(struct rtnl_ematch *m, struct nl_dump_params *p)
+{
+ struct tcf_em_cmp *cmp = rtnl_ematch_data(m);
+
+ nl_dump(p, "%s at %s+%u ",
+ align_txt(cmp), layer_txt(cmp), cmp->off);
+
+ if (cmp->mask)
+ nl_dump(p, "& 0x%x ", cmp->mask);
+
+ nl_dump(p, "%s %u", relation_txt(cmp), cmp->val);
+}
+
+static struct rtnl_ematch_ops cmp_ops = {
+ .eo_kind = TCF_EM_CMP,
+ .eo_name = "cmp",
+ .eo_datalen = sizeof(struct tcf_em_cmp),
+ .eo_parse = cmp_parse,
+ .eo_dump = cmp_dump,
+};
+
+static void __init cmp_init(void)
+{
+ rtnl_ematch_register(&cmp_ops);
+}
+
+static void __exit cmp_exit(void)
+{
+ rtnl_ematch_unregister(&cmp_ops);
+}
+
+/** @} */