Blame tc/em_meta.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * em_meta.c		Metadata Ematch
Packit Service 3880ab
 *
Packit Service 3880ab
 *		This program is free software; you can distribute it and/or
Packit Service 3880ab
 *		modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *		as published by the Free Software Foundation; either version
Packit Service 3880ab
 *		2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:	Thomas Graf <tgraf@suug.ch>
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <stdlib.h>
Packit Service 3880ab
#include <unistd.h>
Packit Service 3880ab
#include <fcntl.h>
Packit Service 3880ab
#include <sys/socket.h>
Packit Service 3880ab
#include <netinet/in.h>
Packit Service 3880ab
#include <arpa/inet.h>
Packit Service 3880ab
#include <string.h>
Packit Service 3880ab
#include <errno.h>
Packit Service 3880ab
Packit Service 3880ab
#include "m_ematch.h"
Packit Service 3880ab
#include <linux/tc_ematch/tc_em_meta.h>
Packit Service 3880ab
Packit Service 3880ab
extern struct ematch_util meta_ematch_util;
Packit Service 3880ab
Packit Service 3880ab
static void meta_print_usage(FILE *fd)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(fd,
Packit Service 3880ab
	    "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
Packit Service 3880ab
	    "where: OBJECT  := { META_ID | VALUE }\n" \
Packit Service 3880ab
	    "       META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
Packit Service 3880ab
	    "\n" \
Packit Service 3880ab
	    "Example: meta(nf_mark gt 24)\n" \
Packit Service 3880ab
	    "         meta(indev shift 1 eq \"ppp\")\n" \
Packit Service 3880ab
	    "         meta(tcindex mask 0xf0 eq 0xf0)\n" \
Packit Service 3880ab
	    "\n" \
Packit Service 3880ab
	    "For a list of meta identifiers, use meta(list).\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const struct meta_entry {
Packit Service 3880ab
	int		id;
Packit Service 3880ab
	char *kind;
Packit Service 3880ab
	char *mask;
Packit Service 3880ab
	char *desc;
Packit Service 3880ab
} meta_table[] = {
Packit Service 3880ab
#define TCF_META_ID_SECTION 0
Packit Service 3880ab
#define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
Packit Service 3880ab
	__A(SECTION,		"Generic", "", ""),
Packit Service 3880ab
	__A(RANDOM,		"random",	"i",
Packit Service 3880ab
				"Random value (32 bit)"),
Packit Service 3880ab
	__A(LOADAVG_0,		"loadavg_1",	"i",
Packit Service 3880ab
				"Load average in last minute"),
Packit Service 3880ab
	__A(LOADAVG_1,		"loadavg_5",	"i",
Packit Service 3880ab
				"Load average in last 5 minutes"),
Packit Service 3880ab
	__A(LOADAVG_2,		"loadavg_15",	"i",
Packit Service 3880ab
				"Load average in last 15 minutes"),
Packit Service 3880ab
Packit Service 3880ab
	__A(SECTION,		"Interfaces", "", ""),
Packit Service 3880ab
	__A(DEV,		"dev",		"iv",
Packit Service 3880ab
				"Device the packet is on"),
Packit Service 3880ab
	__A(SECTION,		"Packet attributes", "", ""),
Packit Service 3880ab
	__A(PRIORITY,		"priority",	"i",
Packit Service 3880ab
				"Priority of packet"),
Packit Service 3880ab
	__A(PROTOCOL,		"protocol",	"i",
Packit Service 3880ab
				"Link layer protocol"),
Packit Service 3880ab
	__A(PKTTYPE,		"pkt_type",	"i",
Packit Service 3880ab
				"Packet type (uni|multi|broad|...)cast"),
Packit Service 3880ab
	__A(PKTLEN,		"pkt_len",	"i",
Packit Service 3880ab
				"Length of packet"),
Packit Service 3880ab
	__A(DATALEN,		"data_len",	"i",
Packit Service 3880ab
				"Length of data in packet"),
Packit Service 3880ab
	__A(MACLEN,		"mac_len",	"i",
Packit Service 3880ab
				"Length of link layer header"),
Packit Service 3880ab
Packit Service 3880ab
	__A(SECTION,		"Netfilter", "", ""),
Packit Service 3880ab
	__A(NFMARK,		"nf_mark",	"i",
Packit Service 3880ab
				"Netfilter mark"),
Packit Service 3880ab
	__A(NFMARK,		"fwmark",	"i",
Packit Service 3880ab
				"Alias for nf_mark"),
Packit Service 3880ab
Packit Service 3880ab
	__A(SECTION,		"Traffic Control", "", ""),
Packit Service 3880ab
	__A(TCINDEX,		"tc_index",	"i",	"TC Index"),
Packit Service 3880ab
	__A(SECTION,		"Routing", "", ""),
Packit Service 3880ab
	__A(RTCLASSID,		"rt_classid",	"i",
Packit Service 3880ab
				"Routing ClassID (cls_route)"),
Packit Service 3880ab
	__A(RTIIF,		"rt_iif",	"i",
Packit Service 3880ab
				"Incoming interface index"),
Packit Service 3880ab
	__A(VLAN_TAG,		"vlan",		"i",	"Vlan tag"),
Packit Service 3880ab
Packit Service 3880ab
	__A(SECTION,		"Sockets", "", ""),
Packit Service 3880ab
	__A(SK_FAMILY,		"sk_family",	"i",	"Address family"),
Packit Service 3880ab
	__A(SK_STATE,		"sk_state",	"i",	"State"),
Packit Service 3880ab
	__A(SK_REUSE,		"sk_reuse",	"i",	"Reuse Flag"),
Packit Service 3880ab
	__A(SK_BOUND_IF,	"sk_bind_if",	"iv",	"Bound interface"),
Packit Service 3880ab
	__A(SK_REFCNT,		"sk_refcnt",	"i",	"Reference counter"),
Packit Service 3880ab
	__A(SK_SHUTDOWN,	"sk_shutdown",	"i",	"Shutdown mask"),
Packit Service 3880ab
	__A(SK_PROTO,		"sk_proto",	"i",	"Protocol"),
Packit Service 3880ab
	__A(SK_TYPE,		"sk_type",	"i",	"Type"),
Packit Service 3880ab
	__A(SK_RCVBUF,		"sk_rcvbuf",	"i",	"Receive buffer size"),
Packit Service 3880ab
	__A(SK_RMEM_ALLOC,	"sk_rmem",	"i",	"RMEM"),
Packit Service 3880ab
	__A(SK_WMEM_ALLOC,	"sk_wmem",	"i",	"WMEM"),
Packit Service 3880ab
	__A(SK_OMEM_ALLOC,	"sk_omem",	"i",	"OMEM"),
Packit Service 3880ab
	__A(SK_WMEM_QUEUED,	"sk_wmem_queue", "i",	"WMEM queue"),
Packit Service 3880ab
	__A(SK_SND_QLEN,	"sk_snd_queue",	"i",	"Send queue length"),
Packit Service 3880ab
	__A(SK_RCV_QLEN,	"sk_rcv_queue",	"i",	"Receive queue length"),
Packit Service 3880ab
	__A(SK_ERR_QLEN,	"sk_err_queue",	"i",	"Error queue length"),
Packit Service 3880ab
	__A(SK_FORWARD_ALLOCS,	"sk_fwd_alloc",	"i",	"Forward allocations"),
Packit Service 3880ab
	__A(SK_SNDBUF,		"sk_sndbuf",	"i",	"Send buffer size"),
Packit Service 3880ab
#undef __A
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static inline int map_type(char k)
Packit Service 3880ab
{
Packit Service 3880ab
	switch (k) {
Packit Service 3880ab
		case 'i': return TCF_META_TYPE_INT;
Packit Service 3880ab
		case 'v': return TCF_META_TYPE_VAR;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
Packit Service 3880ab
	return INT_MAX;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const struct meta_entry *lookup_meta_entry(struct bstr *kind)
Packit Service 3880ab
{
Packit Service 3880ab
	int i;
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < ARRAY_SIZE(meta_table); i++)
Packit Service 3880ab
		if (!bstrcmp(kind, meta_table[i].kind) &&
Packit Service 3880ab
		    meta_table[i].id != 0)
Packit Service 3880ab
			return &meta_table[i];
Packit Service 3880ab
Packit Service 3880ab
	return NULL;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const struct meta_entry *lookup_meta_entry_byid(int id)
Packit Service 3880ab
{
Packit Service 3880ab
	int i;
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < ARRAY_SIZE(meta_table); i++)
Packit Service 3880ab
		if (meta_table[i].id == id)
Packit Service 3880ab
			return &meta_table[i];
Packit Service 3880ab
Packit Service 3880ab
	return NULL;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
Packit Service 3880ab
			      struct tcf_meta_val *hdr)
Packit Service 3880ab
{
Packit Service 3880ab
	__u32 t;
Packit Service 3880ab
Packit Service 3880ab
	switch (TCF_META_TYPE(hdr->kind)) {
Packit Service 3880ab
		case TCF_META_TYPE_INT:
Packit Service 3880ab
			t = val;
Packit Service 3880ab
			addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
Packit Service 3880ab
			break;
Packit Service 3880ab
Packit Service 3880ab
		case TCF_META_TYPE_VAR:
Packit Service 3880ab
			if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) {
Packit Service 3880ab
				struct bstr *a = (struct bstr *) val;
Packit Service 3880ab
Packit Service 3880ab
				addattr_l(n, MAX_MSG, tlv, a->data, a->len);
Packit Service 3880ab
			}
Packit Service 3880ab
			break;
Packit Service 3880ab
	}
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static inline int is_compatible(struct tcf_meta_val *what,
Packit Service 3880ab
				struct tcf_meta_val *needed)
Packit Service 3880ab
{
Packit Service 3880ab
	const struct meta_entry *entry;
Packit Service 3880ab
	char *p;
Packit Service 3880ab
Packit Service 3880ab
	entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
Packit Service 3880ab
Packit Service 3880ab
	if (entry == NULL)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	for (p = entry->mask; p; p++)
Packit Service 3880ab
		if (map_type(*p) == TCF_META_TYPE(needed->kind))
Packit Service 3880ab
			return 1;
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void list_meta_ids(FILE *fd)
Packit Service 3880ab
{
Packit Service 3880ab
	int i;
Packit Service 3880ab
Packit Service 3880ab
	fprintf(fd,
Packit Service 3880ab
	    "--------------------------------------------------------\n" \
Packit Service 3880ab
	    "  ID               Type       Description\n" \
Packit Service 3880ab
	    "--------------------------------------------------------");
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < ARRAY_SIZE(meta_table); i++) {
Packit Service 3880ab
		if (meta_table[i].id == TCF_META_ID_SECTION) {
Packit Service 3880ab
			fprintf(fd, "\n%s:\n", meta_table[i].kind);
Packit Service 3880ab
		} else {
Packit Service 3880ab
			char *p = meta_table[i].mask;
Packit Service 3880ab
			char buf[64] = {0};
Packit Service 3880ab
Packit Service 3880ab
			fprintf(fd, "  %-16s ", meta_table[i].kind);
Packit Service 3880ab
Packit Service 3880ab
			while (*p) {
Packit Service 3880ab
				int type = map_type(*p);
Packit Service 3880ab
Packit Service 3880ab
				switch (type) {
Packit Service 3880ab
					case TCF_META_TYPE_INT:
Packit Service 3880ab
						strcat(buf, "INT");
Packit Service 3880ab
						break;
Packit Service 3880ab
Packit Service 3880ab
					case TCF_META_TYPE_VAR:
Packit Service 3880ab
						strcat(buf, "VAR");
Packit Service 3880ab
						break;
Packit Service 3880ab
				}
Packit Service 3880ab
Packit Service 3880ab
				if (*(++p))
Packit Service 3880ab
					strcat(buf, ",");
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	fprintf(fd,
Packit Service 3880ab
	    "--------------------------------------------------------\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
#undef TCF_META_ID_SECTION
Packit Service 3880ab
Packit Service 3880ab
#define PARSE_FAILURE ((void *) (-1))
Packit Service 3880ab
Packit Service 3880ab
#define PARSE_ERR(CARG, FMT, ARGS...) \
Packit Service 3880ab
	em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT, ##ARGS)
Packit Service 3880ab
Packit Service 3880ab
static inline int can_adopt(struct tcf_meta_val *val)
Packit Service 3880ab
{
Packit Service 3880ab
	return !!TCF_META_ID(val->kind);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static inline int overwrite_type(struct tcf_meta_val *src,
Packit Service 3880ab
				 struct tcf_meta_val *dst)
Packit Service 3880ab
{
Packit Service 3880ab
	return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
Packit Service 3880ab
static inline struct bstr *
Packit Service 3880ab
parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
Packit Service 3880ab
	     unsigned long *dst, struct tcf_meta_val *left)
Packit Service 3880ab
{
Packit Service 3880ab
	const struct meta_entry *entry;
Packit Service 3880ab
	unsigned long num;
Packit Service 3880ab
	struct bstr *a;
Packit Service 3880ab
Packit Service 3880ab
	if (arg->quoted) {
Packit Service 3880ab
		obj->kind = TCF_META_TYPE_VAR << 12;
Packit Service 3880ab
		obj->kind |= TCF_META_ID_VALUE;
Packit Service 3880ab
		*dst = (unsigned long) arg;
Packit Service 3880ab
		return bstr_next(arg);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	num = bstrtoul(arg);
Packit Service 3880ab
	if (num != ULONG_MAX) {
Packit Service 3880ab
		obj->kind = TCF_META_TYPE_INT << 12;
Packit Service 3880ab
		obj->kind |= TCF_META_ID_VALUE;
Packit Service 3880ab
		*dst = (unsigned long) num;
Packit Service 3880ab
		return bstr_next(arg);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	entry = lookup_meta_entry(arg);
Packit Service 3880ab
Packit Service 3880ab
	if (entry == NULL) {
Packit Service 3880ab
		PARSE_ERR(arg, "meta: unknown meta id\n");
Packit Service 3880ab
		return PARSE_FAILURE;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
Packit Service 3880ab
Packit Service 3880ab
	if (left) {
Packit Service 3880ab
		struct tcf_meta_val *right = obj;
Packit Service 3880ab
Packit Service 3880ab
		if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
Packit Service 3880ab
			goto compatible;
Packit Service 3880ab
Packit Service 3880ab
		if (can_adopt(left) && !can_adopt(right)) {
Packit Service 3880ab
			if (is_compatible(left, right))
Packit Service 3880ab
				left->kind = overwrite_type(left, right);
Packit Service 3880ab
			else
Packit Service 3880ab
				goto not_compatible;
Packit Service 3880ab
		} else if (can_adopt(right) && !can_adopt(left)) {
Packit Service 3880ab
			if (is_compatible(right, left))
Packit Service 3880ab
				right->kind = overwrite_type(right, left);
Packit Service 3880ab
			else
Packit Service 3880ab
				goto not_compatible;
Packit Service 3880ab
		} else if (can_adopt(left) && can_adopt(right)) {
Packit Service 3880ab
			if (is_compatible(left, right))
Packit Service 3880ab
				left->kind = overwrite_type(left, right);
Packit Service 3880ab
			else if (is_compatible(right, left))
Packit Service 3880ab
				right->kind = overwrite_type(right, left);
Packit Service 3880ab
			else
Packit Service 3880ab
				goto not_compatible;
Packit Service 3880ab
		} else
Packit Service 3880ab
			goto not_compatible;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
compatible:
Packit Service 3880ab
Packit Service 3880ab
	a = bstr_next(arg);
Packit Service 3880ab
Packit Service 3880ab
	while (a) {
Packit Service 3880ab
		if (!bstrcmp(a, "shift")) {
Packit Service 3880ab
			unsigned long shift;
Packit Service 3880ab
Packit Service 3880ab
			if (a->next == NULL) {
Packit Service 3880ab
				PARSE_ERR(a, "meta: missing argument");
Packit Service 3880ab
				return PARSE_FAILURE;
Packit Service 3880ab
			}
Packit Service 3880ab
			a = bstr_next(a);
Packit Service 3880ab
Packit Service 3880ab
			shift = bstrtoul(a);
Packit Service 3880ab
			if (shift == ULONG_MAX) {
Packit Service 3880ab
				PARSE_ERR(a, "meta: invalid shift, must " \
Packit Service 3880ab
				    "be numeric");
Packit Service 3880ab
				return PARSE_FAILURE;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			obj->shift = (__u8) shift;
Packit Service 3880ab
			a = bstr_next(a);
Packit Service 3880ab
		} else if (!bstrcmp(a, "mask")) {
Packit Service 3880ab
			unsigned long mask;
Packit Service 3880ab
Packit Service 3880ab
			if (a->next == NULL) {
Packit Service 3880ab
				PARSE_ERR(a, "meta: missing argument");
Packit Service 3880ab
				return PARSE_FAILURE;
Packit Service 3880ab
			}
Packit Service 3880ab
			a = bstr_next(a);
Packit Service 3880ab
Packit Service 3880ab
			mask = bstrtoul(a);
Packit Service 3880ab
			if (mask == ULONG_MAX) {
Packit Service 3880ab
				PARSE_ERR(a, "meta: invalid mask, must be " \
Packit Service 3880ab
				    "numeric");
Packit Service 3880ab
				return PARSE_FAILURE;
Packit Service 3880ab
			}
Packit Service 3880ab
			*dst = (unsigned long) mask;
Packit Service 3880ab
			a = bstr_next(a);
Packit Service 3880ab
		} else
Packit Service 3880ab
			break;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return a;
Packit Service 3880ab
Packit Service 3880ab
not_compatible:
Packit Service 3880ab
	PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
Packit Service 3880ab
	return PARSE_FAILURE;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
Packit Service 3880ab
			   struct bstr *args)
Packit Service 3880ab
{
Packit Service 3880ab
	int opnd;
Packit Service 3880ab
	struct bstr *a;
Packit Service 3880ab
	struct tcf_meta_hdr meta_hdr = {};
Packit Service 3880ab
	unsigned long lvalue = 0, rvalue = 0;
Packit Service 3880ab
Packit Service 3880ab
	if (args == NULL)
Packit Service 3880ab
		return PARSE_ERR(args, "meta: missing arguments");
Packit Service 3880ab
Packit Service 3880ab
	if (!bstrcmp(args, "list")) {
Packit Service 3880ab
		list_meta_ids(stderr);
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
Packit Service 3880ab
	if (a == PARSE_FAILURE)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	else if (a == NULL)
Packit Service 3880ab
		return PARSE_ERR(args, "meta: missing operand");
Packit Service 3880ab
Packit Service 3880ab
	if (!bstrcmp(a, "eq"))
Packit Service 3880ab
		opnd = TCF_EM_OPND_EQ;
Packit Service 3880ab
	else if (!bstrcmp(a, "gt"))
Packit Service 3880ab
		opnd = TCF_EM_OPND_GT;
Packit Service 3880ab
	else if (!bstrcmp(a, "lt"))
Packit Service 3880ab
		opnd = TCF_EM_OPND_LT;
Packit Service 3880ab
	else
Packit Service 3880ab
		return PARSE_ERR(a, "meta: invalid operand");
Packit Service 3880ab
Packit Service 3880ab
	meta_hdr.left.op = (__u8) opnd;
Packit Service 3880ab
Packit Service 3880ab
	if (a->next == NULL)
Packit Service 3880ab
		return PARSE_ERR(args, "meta: missing rvalue");
Packit Service 3880ab
	a = bstr_next(a);
Packit Service 3880ab
Packit Service 3880ab
	a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
Packit Service 3880ab
	if (a == PARSE_FAILURE)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	else if (a != NULL)
Packit Service 3880ab
		return PARSE_ERR(a, "meta: unexpected trailer");
Packit Service 3880ab
Packit Service 3880ab
Packit Service 3880ab
	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
Packit Service 3880ab
Packit Service 3880ab
	addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
Packit Service 3880ab
Packit Service 3880ab
	dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
Packit Service 3880ab
	dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
#undef PARSE_ERR
Packit Service 3880ab
Packit Service 3880ab
static inline void print_binary(FILE *fd, unsigned char *str, int len)
Packit Service 3880ab
{
Packit Service 3880ab
	int i;
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < len; i++)
Packit Service 3880ab
		if (!isprint(str[i]))
Packit Service 3880ab
			goto binary;
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < len; i++)
Packit Service 3880ab
		fprintf(fd, "%c", str[i]);
Packit Service 3880ab
	return;
Packit Service 3880ab
Packit Service 3880ab
binary:
Packit Service 3880ab
	for (i = 0; i < len; i++)
Packit Service 3880ab
		fprintf(fd, "%02x ", str[i]);
Packit Service 3880ab
Packit Service 3880ab
	fprintf(fd, "\"");
Packit Service 3880ab
	for (i = 0; i < len; i++)
Packit Service 3880ab
		fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
Packit Service 3880ab
	fprintf(fd, "\"");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static inline int print_value(FILE *fd, int type, struct rtattr *rta)
Packit Service 3880ab
{
Packit Service 3880ab
	if (rta == NULL) {
Packit Service 3880ab
		fprintf(stderr, "Missing value TLV\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	switch (type) {
Packit Service 3880ab
		case TCF_META_TYPE_INT:
Packit Service 3880ab
			if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
Packit Service 3880ab
				fprintf(stderr, "meta int type value TLV " \
Packit Service 3880ab
				    "size mismatch.\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			fprintf(fd, "%d", rta_getattr_u32(rta));
Packit Service 3880ab
			break;
Packit Service 3880ab
Packit Service 3880ab
		case TCF_META_TYPE_VAR:
Packit Service 3880ab
			print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
Packit Service 3880ab
			break;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
Packit Service 3880ab
{
Packit Service 3880ab
	int id = TCF_META_ID(obj->kind);
Packit Service 3880ab
	int type = TCF_META_TYPE(obj->kind);
Packit Service 3880ab
	const struct meta_entry *entry;
Packit Service 3880ab
Packit Service 3880ab
	if (id == TCF_META_ID_VALUE)
Packit Service 3880ab
		return print_value(fd, type, rta);
Packit Service 3880ab
Packit Service 3880ab
	entry = lookup_meta_entry_byid(id);
Packit Service 3880ab
Packit Service 3880ab
	if (entry == NULL)
Packit Service 3880ab
		fprintf(fd, "[unknown meta id %d]", id);
Packit Service 3880ab
	else
Packit Service 3880ab
		fprintf(fd, "%s", entry->kind);
Packit Service 3880ab
Packit Service 3880ab
	if (obj->shift)
Packit Service 3880ab
		fprintf(fd, " shift %d", obj->shift);
Packit Service 3880ab
Packit Service 3880ab
	switch (type) {
Packit Service 3880ab
		case TCF_META_TYPE_INT:
Packit Service 3880ab
			if (rta) {
Packit Service 3880ab
				if (RTA_PAYLOAD(rta) < sizeof(__u32))
Packit Service 3880ab
					goto size_mismatch;
Packit Service 3880ab
Packit Service 3880ab
				if (rta_getattr_u32(rta))
Packit Service 3880ab
					fprintf(fd, " mask 0x%08x",
Packit Service 3880ab
						rta_getattr_u32(rta));
Packit Service 3880ab
			}
Packit Service 3880ab
			break;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
Packit Service 3880ab
size_mismatch:
Packit Service 3880ab
	fprintf(stderr, "meta int type mask TLV size mismatch\n");
Packit Service 3880ab
	return -1;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
Packit Service 3880ab
static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
Packit Service 3880ab
			   int data_len)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_EM_META_MAX+1];
Packit Service 3880ab
	struct tcf_meta_hdr *meta_hdr;
Packit Service 3880ab
Packit Service 3880ab
	if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_EM_META_HDR] == NULL) {
Packit Service 3880ab
		fprintf(stderr, "Missing meta header\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
Packit Service 3880ab
		fprintf(stderr, "Meta header size mismatch\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
Packit Service 3880ab
Packit Service 3880ab
	if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	switch (meta_hdr->left.op) {
Packit Service 3880ab
		case TCF_EM_OPND_EQ:
Packit Service 3880ab
			fprintf(fd, " eq ");
Packit Service 3880ab
			break;
Packit Service 3880ab
		case TCF_EM_OPND_LT:
Packit Service 3880ab
			fprintf(fd, " lt ");
Packit Service 3880ab
			break;
Packit Service 3880ab
		case TCF_EM_OPND_GT:
Packit Service 3880ab
			fprintf(fd, " gt ");
Packit Service 3880ab
			break;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct ematch_util meta_ematch_util = {
Packit Service 3880ab
	.kind = "meta",
Packit Service 3880ab
	.kind_num = TCF_EM_META,
Packit Service 3880ab
	.parse_eopt = meta_parse_eopt,
Packit Service 3880ab
	.print_eopt = meta_print_eopt,
Packit Service 3880ab
	.print_usage = meta_print_usage
Packit Service 3880ab
};