Blame tc/m_tunnel_key.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * m_tunnel_key.c	ip tunnel manipulation module
Packit Service 3880ab
 *
Packit Service 3880ab
 *              This program is free software; you can redistribute 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:     Amir Vadai <amir@vadai.me>
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 <string.h>
Packit Service 3880ab
#include <linux/if_ether.h>
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
#include "rt_names.h"
Packit Service 3880ab
#include "tc_util.h"
Packit Service 3880ab
#include <linux/tc_act/tc_tunnel_key.h>
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: tunnel_key unset\n"
Packit Service 3880ab
		"       tunnel_key set <TUNNEL_KEY>\n"
Packit Service 3880ab
		"Where TUNNEL_KEY is a combination of:\n"
Packit Service 3880ab
		"id <TUNNELID>\n"
Packit Service 3880ab
		"src_ip <IP> (mandatory)\n"
Packit Service 3880ab
		"dst_ip <IP> (mandatory)\n"
Packit Service 3880ab
		"dst_port <UDP_PORT>\n"
Packit Service 3880ab
		"geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
Packit Service 3880ab
		"csum | nocsum (default is \"csum\")\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void usage(void)
Packit Service 3880ab
{
Packit Service 3880ab
	explain();
Packit Service 3880ab
	exit(-1);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_ip_addr(const char *str, int addr4_type,
Packit Service 3880ab
				    int addr6_type, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	inet_prefix addr;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_addr(&addr, str, AF_UNSPEC);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
Packit Service 3880ab
		  addr.data, addr.bytelen);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_key_id(const char *str, int type,
Packit Service 3880ab
				   struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	__be32 key_id;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_be32(&key_id, str, 10);
Packit Service 3880ab
	if (!ret)
Packit Service 3880ab
		addattr32(n, MAX_MSG, type, key_id);
Packit Service 3880ab
Packit Service 3880ab
	return ret;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	int ret;
Packit Service 3880ab
	__be16 dst_port;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_be16(&dst_port, str, 10);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	addattr16(n, MAX_MSG, type, dst_port);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_be16(char *str, int base, int type,
Packit Service 3880ab
				 struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	int ret;
Packit Service 3880ab
	__be16 value;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_be16(&value, str, base);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr16(n, MAX_MSG, type, value);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_be32(char *str, int base, int type,
Packit Service 3880ab
				 struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	__be32 value;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_be32(&value, str, base);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr32(n, MAX_MSG, type, value);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_u8(char *str, int base, int type,
Packit Service 3880ab
			       struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	int ret;
Packit Service 3880ab
	__u8 value;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_u8(&value, str, base);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr8(n, MAX_MSG, type, value);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_u32(char *str, int base, int type,
Packit Service 3880ab
				struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	__u32 value;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_u32(&value, str, base);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr32(n, MAX_MSG, type, value);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	char *token, *saveptr = NULL;
Packit Service 3880ab
	struct rtattr *nest;
Packit Service 3880ab
	int i, ret;
Packit Service 3880ab
Packit Service 3880ab
	nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
Packit Service 3880ab
Packit Service 3880ab
	token = strtok_r(str, ":", &saveptr);
Packit Service 3880ab
	i = 1;
Packit Service 3880ab
	while (token) {
Packit Service 3880ab
		switch (i) {
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_be16(token, 16, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_u8(token, 16, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
Packit Service 3880ab
		{
Packit Service 3880ab
			size_t token_len = strlen(token);
Packit Service 3880ab
			uint8_t *opts;
Packit Service 3880ab
Packit Service 3880ab
			opts = malloc(token_len / 2);
Packit Service 3880ab
			if (!opts)
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			if (hex2mem(token, opts, token_len / 2) < 0) {
Packit Service 3880ab
				free(opts);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			addattr_l(n, MAX_MSG, i, opts, token_len / 2);
Packit Service 3880ab
			free(opts);
Packit Service 3880ab
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		default:
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		token = strtok_r(NULL, ":", &saveptr);
Packit Service 3880ab
		i++;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	addattr_nest_end(n, nest);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	char *token, *saveptr = NULL;
Packit Service 3880ab
	struct rtattr *nest;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
Packit Service 3880ab
Packit Service 3880ab
	token = strtok_r(str, ",", &saveptr);
Packit Service 3880ab
	while (token) {
Packit Service 3880ab
		ret = tunnel_key_parse_geneve_opt(token, n);
Packit Service 3880ab
		if (ret)
Packit Service 3880ab
			return ret;
Packit Service 3880ab
Packit Service 3880ab
		token = strtok_r(NULL, ",", &saveptr);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	addattr_nest_end(n, nest);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *encap, *nest;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
Packit Service 3880ab
	encap = addattr_nest(n, MAX_MSG,
Packit Service 3880ab
			     TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
Packit Service 3880ab
	nest = addattr_nest(n, MAX_MSG,
Packit Service 3880ab
			    TCA_TUNNEL_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED);
Packit Service 3880ab
Packit Service 3880ab
	ret = tunnel_key_parse_u32(str, 0,
Packit Service 3880ab
				   TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return ret;
Packit Service 3880ab
Packit Service 3880ab
	addattr_nest_end(n, nest);
Packit Service 3880ab
	addattr_nest_end(n, encap);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	char *token, *saveptr = NULL;
Packit Service 3880ab
	struct rtattr *encap, *nest;
Packit Service 3880ab
	int i, ret;
Packit Service 3880ab
Packit Service 3880ab
	encap = addattr_nest(n, MAX_MSG,
Packit Service 3880ab
			     TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
Packit Service 3880ab
	nest = addattr_nest(n, MAX_MSG,
Packit Service 3880ab
			    TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
Packit Service 3880ab
Packit Service 3880ab
	token = strtok_r(str, ":", &saveptr);
Packit Service 3880ab
	i = 1;
Packit Service 3880ab
	while (token) {
Packit Service 3880ab
		switch (i) {
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_u8(token, 0, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_be32(token, 0, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_u8(token, 0, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
Packit Service 3880ab
		{
Packit Service 3880ab
			ret = tunnel_key_parse_u8(token, 0, i, n);
Packit Service 3880ab
			if (ret)
Packit Service 3880ab
				return ret;
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		default:
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		token = strtok_r(NULL, ":", &saveptr);
Packit Service 3880ab
		i++;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	addattr_nest_end(n, nest);
Packit Service 3880ab
	addattr_nest_end(n, encap);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	int ret;
Packit Service 3880ab
	__u8 val;
Packit Service 3880ab
Packit Service 3880ab
	ret = get_u8(&val, str, 10);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		ret = get_u8(&val, str, 16);
Packit Service 3880ab
	if (ret)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	addattr8(n, MAX_MSG, type, val);
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
Packit Service 3880ab
			    int tca_id, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	struct tc_tunnel_key parm = {};
Packit Service 3880ab
	char **argv = *argv_p;
Packit Service 3880ab
	int argc = *argc_p;
Packit Service 3880ab
	struct rtattr *tail;
Packit Service 3880ab
	int action = 0;
Packit Service 3880ab
	int ret;
Packit Service 3880ab
	int has_src_ip = 0;
Packit Service 3880ab
	int has_dst_ip = 0;
Packit Service 3880ab
	int csum = 1;
Packit Service 3880ab
Packit Service 3880ab
	if (matches(*argv, "tunnel_key") != 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	tail = addattr_nest(n, MAX_MSG, tca_id);
Packit Service 3880ab
Packit Service 3880ab
	NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
Packit Service 3880ab
		if (matches(*argv, "unset") == 0) {
Packit Service 3880ab
			if (action) {
Packit Service 3880ab
				fprintf(stderr, "unexpected \"%s\" - action already specified\n",
Packit Service 3880ab
					*argv);
Packit Service 3880ab
				explain();
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			action = TCA_TUNNEL_KEY_ACT_RELEASE;
Packit Service 3880ab
		} else if (matches(*argv, "set") == 0) {
Packit Service 3880ab
			if (action) {
Packit Service 3880ab
				fprintf(stderr, "unexpected \"%s\" - action already specified\n",
Packit Service 3880ab
					*argv);
Packit Service 3880ab
				explain();
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			action = TCA_TUNNEL_KEY_ACT_SET;
Packit Service 3880ab
		} else if (matches(*argv, "src_ip") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_ip_addr(*argv,
Packit Service 3880ab
						       TCA_TUNNEL_KEY_ENC_IPV4_SRC,
Packit Service 3880ab
						       TCA_TUNNEL_KEY_ENC_IPV6_SRC,
Packit Service 3880ab
						       n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"src_ip\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			has_src_ip = 1;
Packit Service 3880ab
		} else if (matches(*argv, "dst_ip") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_ip_addr(*argv,
Packit Service 3880ab
						       TCA_TUNNEL_KEY_ENC_IPV4_DST,
Packit Service 3880ab
						       TCA_TUNNEL_KEY_ENC_IPV6_DST,
Packit Service 3880ab
						       n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"dst_ip\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			has_dst_ip = 1;
Packit Service 3880ab
		} else if (matches(*argv, "id") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"id\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "dst_port") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_dst_port(*argv,
Packit Service 3880ab
							TCA_TUNNEL_KEY_ENC_DST_PORT, n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"dst port\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "geneve_opts") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (tunnel_key_parse_geneve_opts(*argv, n)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"geneve_opts\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "vxlan_opts") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (tunnel_key_parse_vxlan_opt(*argv, n)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "erspan_opts") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (tunnel_key_parse_erspan_opt(*argv, n)) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"erspan_opts\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "tos") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_tos_ttl(*argv,
Packit Service 3880ab
							TCA_TUNNEL_KEY_ENC_TOS, n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"tos\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "ttl") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			ret = tunnel_key_parse_tos_ttl(*argv,
Packit Service 3880ab
							TCA_TUNNEL_KEY_ENC_TTL, n);
Packit Service 3880ab
			if (ret < 0) {
Packit Service 3880ab
				fprintf(stderr, "Illegal \"ttl\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "csum") == 0) {
Packit Service 3880ab
			csum = 1;
Packit Service 3880ab
		} else if (matches(*argv, "nocsum") == 0) {
Packit Service 3880ab
			csum = 0;
Packit Service 3880ab
		} else if (matches(*argv, "help") == 0) {
Packit Service 3880ab
			usage();
Packit Service 3880ab
		} else {
Packit Service 3880ab
			break;
Packit Service 3880ab
		}
Packit Service 3880ab
		NEXT_ARG_FWD();
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
Packit Service 3880ab
Packit Service 3880ab
	parse_action_control_dflt(&argc, &argv, &parm.action,
Packit Service 3880ab
				  false, TC_ACT_PIPE);
Packit Service 3880ab
Packit Service 3880ab
	if (argc) {
Packit Service 3880ab
		if (matches(*argv, "index") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&parm.index, *argv, 10)) {
Packit Service 3880ab
				fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG_FWD();
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (action == TCA_TUNNEL_KEY_ACT_SET &&
Packit Service 3880ab
	    (!has_src_ip || !has_dst_ip)) {
Packit Service 3880ab
		fprintf(stderr, "set needs tunnel_key parameters\n");
Packit Service 3880ab
		explain();
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	parm.t_action = action;
Packit Service 3880ab
	addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
Packit Service 3880ab
	addattr_nest_end(n, tail);
Packit Service 3880ab
Packit Service 3880ab
	*argc_p = argc;
Packit Service 3880ab
	*argv_p = argv;
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_ip_addr(FILE *f, const char *name,
Packit Service 3880ab
				     struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	int family;
Packit Service 3880ab
	size_t len;
Packit Service 3880ab
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	len = RTA_PAYLOAD(attr);
Packit Service 3880ab
Packit Service 3880ab
	if (len == 4)
Packit Service 3880ab
		family = AF_INET;
Packit Service 3880ab
	else if (len == 16)
Packit Service 3880ab
		family = AF_INET6;
Packit Service 3880ab
	else
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	if (matches(name, "src_ip") == 0)
Packit Service 3880ab
		print_string(PRINT_ANY, "src_ip", "\tsrc_ip %s",
Packit Service 3880ab
			     rt_addr_n2a_rta(family, attr));
Packit Service 3880ab
	else if (matches(name, "dst_ip") == 0)
Packit Service 3880ab
		print_string(PRINT_ANY, "dst_ip", "\tdst_ip %s",
Packit Service 3880ab
			     rt_addr_n2a_rta(family, attr));
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_key_id(FILE *f, const char *name,
Packit Service 3880ab
				    struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_dst_port(FILE *f, char *name,
Packit Service 3880ab
				      struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
Packit Service 3880ab
		   rta_getattr_be16(attr));
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_flag(FILE *f, const char *name_on,
Packit Service 3880ab
				  const char *name_off,
Packit Service 3880ab
				  struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_string(PRINT_ANY, "flag", "\t%s",
Packit Service 3880ab
		     rta_getattr_u8(attr) ? name_on : name_off);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_geneve_options(struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
Packit Service 3880ab
	struct rtattr *i = RTA_DATA(attr);
Packit Service 3880ab
	int ii, data_len = 0, offset = 0;
Packit Service 3880ab
	int rem = RTA_PAYLOAD(attr);
Packit Service 3880ab
	char *name = "geneve_opts";
Packit Service 3880ab
	char strbuf[rem * 2 + 1];
Packit Service 3880ab
	char data[rem * 2 + 1];
Packit Service 3880ab
	uint8_t data_r[rem];
Packit Service 3880ab
	uint16_t clss;
Packit Service 3880ab
	uint8_t type;
Packit Service 3880ab
Packit Service 3880ab
	open_json_array(PRINT_JSON, name);
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_string(PRINT_FP, name, "\t%s ", name);
Packit Service 3880ab
Packit Service 3880ab
	while (rem) {
Packit Service 3880ab
		parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
Packit Service 3880ab
		clss = rta_getattr_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
Packit Service 3880ab
		type = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
Packit Service 3880ab
		data_len = RTA_PAYLOAD(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
Packit Service 3880ab
		hexstring_n2a(RTA_DATA(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]),
Packit Service 3880ab
			      data_len, data, sizeof(data));
Packit Service 3880ab
		hex2mem(data, data_r, data_len);
Packit Service 3880ab
		offset += data_len + 20;
Packit Service 3880ab
		rem -= data_len + 20;
Packit Service 3880ab
		i = RTA_DATA(attr) + offset;
Packit Service 3880ab
Packit Service 3880ab
		open_json_object(NULL);
Packit Service 3880ab
		print_uint(PRINT_JSON, "class", NULL, clss);
Packit Service 3880ab
		print_uint(PRINT_JSON, "type", NULL, type);
Packit Service 3880ab
		open_json_array(PRINT_JSON, "data");
Packit Service 3880ab
		for (ii = 0; ii < data_len; ii++)
Packit Service 3880ab
			print_uint(PRINT_JSON, NULL, NULL, data_r[ii]);
Packit Service 3880ab
		close_json_array(PRINT_JSON, "data");
Packit Service 3880ab
		close_json_object();
Packit Service 3880ab
Packit Service 3880ab
		sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
Packit Service 3880ab
		if (rem)
Packit Service 3880ab
			print_string(PRINT_FP, NULL, "%s,", strbuf);
Packit Service 3880ab
		else
Packit Service 3880ab
			print_string(PRINT_FP, NULL, "%s", strbuf);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	close_json_array(PRINT_JSON, name);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_vxlan_options(struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
Packit Service 3880ab
	struct rtattr *i = RTA_DATA(attr);
Packit Service 3880ab
	int rem = RTA_PAYLOAD(attr);
Packit Service 3880ab
	char *name = "vxlan_opts";
Packit Service 3880ab
	__u32 gbp;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, i, rem);
Packit Service 3880ab
	gbp = rta_getattr_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
Packit Service 3880ab
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_string(PRINT_FP, name, "\t%s ", name);
Packit Service 3880ab
	open_json_array(PRINT_JSON, name);
Packit Service 3880ab
	open_json_object(NULL);
Packit Service 3880ab
	print_uint(PRINT_ANY, "gbp", "%u", gbp);
Packit Service 3880ab
	close_json_object();
Packit Service 3880ab
	close_json_array(PRINT_JSON, name);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_erspan_options(struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
Packit Service 3880ab
	struct rtattr *i = RTA_DATA(attr);
Packit Service 3880ab
	int rem = RTA_PAYLOAD(attr);
Packit Service 3880ab
	char *name = "erspan_opts";
Packit Service 3880ab
	__u8 ver, hwid, dir;
Packit Service 3880ab
	__u32 idx;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem);
Packit Service 3880ab
	ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
Packit Service 3880ab
	if (ver == 1) {
Packit Service 3880ab
		idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
Packit Service 3880ab
		dir = 0;
Packit Service 3880ab
		hwid = 0;
Packit Service 3880ab
	} else {
Packit Service 3880ab
		idx = 0;
Packit Service 3880ab
		dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]);
Packit Service 3880ab
		hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_string(PRINT_FP, name, "\t%s ", name);
Packit Service 3880ab
	open_json_array(PRINT_JSON, name);
Packit Service 3880ab
	open_json_object(NULL);
Packit Service 3880ab
	print_uint(PRINT_ANY, "ver", "%u", ver);
Packit Service 3880ab
	print_uint(PRINT_ANY, "index", ":%u", idx);
Packit Service 3880ab
	print_uint(PRINT_ANY, "dir", ":%u", dir);
Packit Service 3880ab
	print_uint(PRINT_ANY, "hwid", ":%u", hwid);
Packit Service 3880ab
	close_json_object();
Packit Service 3880ab
	close_json_array(PRINT_JSON, name);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_key_opt(struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
Packit Service 3880ab
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
Packit Service 3880ab
	if (tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE])
Packit Service 3880ab
		tunnel_key_print_geneve_options(
Packit Service 3880ab
			tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
Packit Service 3880ab
	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
Packit Service 3880ab
		tunnel_key_print_vxlan_options(
Packit Service 3880ab
			tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
Packit Service 3880ab
	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
Packit Service 3880ab
		tunnel_key_print_erspan_options(
Packit Service 3880ab
			tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void tunnel_key_print_tos_ttl(FILE *f, char *name,
Packit Service 3880ab
				     struct rtattr *attr)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!attr)
Packit Service 3880ab
		return;
Packit Service 3880ab
Packit Service 3880ab
	if (matches(name, "tos") == 0 && rta_getattr_u8(attr) != 0) {
Packit Service 3880ab
		print_nl();
Packit Service 3880ab
		print_uint(PRINT_ANY, "tos", "\ttos 0x%x",
Packit Service 3880ab
			   rta_getattr_u8(attr));
Packit Service 3880ab
	} else if (matches(name, "ttl") == 0 && rta_getattr_u8(attr) != 0) {
Packit Service 3880ab
		print_nl();
Packit Service 3880ab
		print_uint(PRINT_ANY, "ttl", "\tttl %u",
Packit Service 3880ab
			   rta_getattr_u8(attr));
Packit Service 3880ab
	}
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
Packit Service 3880ab
	struct tc_tunnel_key *parm;
Packit Service 3880ab
Packit Service 3880ab
	if (!arg)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
Packit Service 3880ab
Packit Service 3880ab
	if (!tb[TCA_TUNNEL_KEY_PARMS]) {
Packit Service 3880ab
		fprintf(stderr, "Missing tunnel_key parameters\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
	parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
Packit Service 3880ab
Packit Service 3880ab
	print_string(PRINT_ANY, "kind", "%s ", "tunnel_key");
Packit Service 3880ab
Packit Service 3880ab
	switch (parm->t_action) {
Packit Service 3880ab
	case TCA_TUNNEL_KEY_ACT_RELEASE:
Packit Service 3880ab
		print_string(PRINT_ANY, "mode", " %s", "unset");
Packit Service 3880ab
		break;
Packit Service 3880ab
	case TCA_TUNNEL_KEY_ACT_SET:
Packit Service 3880ab
		print_string(PRINT_ANY, "mode", " %s", "set");
Packit Service 3880ab
		tunnel_key_print_ip_addr(f, "src_ip",
Packit Service 3880ab
					 tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
Packit Service 3880ab
		tunnel_key_print_ip_addr(f, "dst_ip",
Packit Service 3880ab
					 tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
Packit Service 3880ab
		tunnel_key_print_ip_addr(f, "src_ip",
Packit Service 3880ab
					 tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
Packit Service 3880ab
		tunnel_key_print_ip_addr(f, "dst_ip",
Packit Service 3880ab
					 tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
Packit Service 3880ab
		tunnel_key_print_key_id(f, "key_id",
Packit Service 3880ab
					tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
Packit Service 3880ab
		tunnel_key_print_dst_port(f, "dst_port",
Packit Service 3880ab
					  tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
Packit Service 3880ab
		tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
Packit Service 3880ab
		tunnel_key_print_flag(f, "nocsum", "csum",
Packit Service 3880ab
				      tb[TCA_TUNNEL_KEY_NO_CSUM]);
Packit Service 3880ab
		tunnel_key_print_tos_ttl(f, "tos",
Packit Service 3880ab
					  tb[TCA_TUNNEL_KEY_ENC_TOS]);
Packit Service 3880ab
		tunnel_key_print_tos_ttl(f, "ttl",
Packit Service 3880ab
					  tb[TCA_TUNNEL_KEY_ENC_TTL]);
Packit Service 3880ab
		break;
Packit Service 3880ab
	}
Packit Service 3880ab
	print_action_control(f, " ", parm->action, "");
Packit Service 3880ab
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
	print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
Packit Service 3880ab
	print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
Packit Service 3880ab
	print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
Packit Service 3880ab
Packit Service 3880ab
	if (show_stats) {
Packit Service 3880ab
		if (tb[TCA_TUNNEL_KEY_TM]) {
Packit Service 3880ab
			struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
Packit Service 3880ab
Packit Service 3880ab
			print_tm(f, tm);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_nl();
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct action_util tunnel_key_action_util = {
Packit Service 3880ab
	.id = "tunnel_key",
Packit Service 3880ab
	.parse_aopt = parse_tunnel_key,
Packit Service 3880ab
	.print_aopt = print_tunnel_key,
Packit Service 3880ab
};