Blame tc/m_gate.c

Packit Service 3880ab
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
Packit Service 3880ab
/* Copyright 2020 NXP */
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 "list.h"
Packit Service 3880ab
#include <linux/tc_act/tc_gate.h>
Packit Service 3880ab
Packit Service 3880ab
struct gate_entry {
Packit Service 3880ab
	struct list_head list;
Packit Service 3880ab
	uint8_t	gate_state;
Packit Service 3880ab
	uint32_t interval;
Packit Service 3880ab
	int32_t ipv;
Packit Service 3880ab
	int32_t maxoctets;
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
#define CLOCKID_INVALID (-1)
Packit Service 3880ab
static const struct clockid_table {
Packit Service 3880ab
	const char *name;
Packit Service 3880ab
	clockid_t clockid;
Packit Service 3880ab
} clockt_map[] = {
Packit Service 3880ab
	{ "REALTIME", CLOCK_REALTIME },
Packit Service 3880ab
	{ "TAI", CLOCK_TAI },
Packit Service 3880ab
	{ "BOOTTIME", CLOCK_BOOTTIME },
Packit Service 3880ab
	{ "MONOTONIC", CLOCK_MONOTONIC },
Packit Service 3880ab
	{ NULL }
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: gate [ priority PRIO-SPEC ] [ base-time BASE-TIME ]\n"
Packit Service 3880ab
		"       [ cycle-time CYCLE-TIME ]\n"
Packit Service 3880ab
		"       [ cycle-time-ext CYCLE-TIME-EXT ]\n"
Packit Service 3880ab
		"       [ clockid CLOCKID ] [flags FLAGS]\n"
Packit Service 3880ab
		"       [ sched-entry GATE0 INTERVAL [ INTERNAL-PRIO-VALUE MAX-OCTETS ] ]\n"
Packit Service 3880ab
		"       [ sched-entry GATE1 INTERVAL [ INTERNAL-PRIO-VALUE MAX-OCTETS ] ]\n"
Packit Service 3880ab
		"       ......\n"
Packit Service 3880ab
		"       [ sched-entry GATEn INTERVAL [ INTERNAL-PRIO-VALUE MAX-OCTETS ] ]\n"
Packit Service 3880ab
		"       [ CONTROL ]\n"
Packit Service 3880ab
		"       GATEn := open | close\n"
Packit Service 3880ab
		"       INTERVAL : nanoseconds period of gate slot\n"
Packit Service 3880ab
		"       INTERNAL-PRIO-VALUE : internal priority decide which\n"
Packit Service 3880ab
		"                             rx queue number direct to.\n"
Packit Service 3880ab
		"                             default to be -1 which means wildcard.\n"
Packit Service 3880ab
		"       MAX-OCTETS : maximum number of MSDU octets that are\n"
Packit Service 3880ab
		"                    permitted to pas the gate during the\n"
Packit Service 3880ab
		"                    specified TimeInterval.\n"
Packit Service 3880ab
		"                    default to be -1 which means wildcard.\n"
Packit Service 3880ab
		"       CONTROL := pipe | drop | continue | pass |\n"
Packit Service 3880ab
		"                  goto chain <CHAIN_INDEX>\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 void explain_entry_format(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr, "Usage: sched-entry <open | close> <interval> [ <interval ipv> <octets max bytes> ]\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int parse_gate(struct action_util *a, int *argc_p, char ***argv_p,
Packit Service 3880ab
		      int tca_id, struct nlmsghdr *n);
Packit Service 3880ab
static int print_gate(struct action_util *au, FILE *f, struct rtattr *arg);
Packit Service 3880ab
Packit Service 3880ab
struct action_util gate_action_util = {
Packit Service 3880ab
	.id = "gate",
Packit Service 3880ab
	.parse_aopt = parse_gate,
Packit Service 3880ab
	.print_aopt = print_gate,
Packit Service 3880ab
};
Packit Service 3880ab
Packit Service 3880ab
static int get_clockid(__s32 *val, const char *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	const struct clockid_table *c;
Packit Service 3880ab
Packit Service 3880ab
	if (strcasestr(arg, "CLOCK_") != NULL)
Packit Service 3880ab
		arg += sizeof("CLOCK_") - 1;
Packit Service 3880ab
Packit Service 3880ab
	for (c = clockt_map; c->name; c++) {
Packit Service 3880ab
		if (strcasecmp(c->name, arg) == 0) {
Packit Service 3880ab
			*val = c->clockid;
Packit Service 3880ab
			return 0;
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return -1;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static const char *get_clock_name(clockid_t clockid)
Packit Service 3880ab
{
Packit Service 3880ab
	const struct clockid_table *c;
Packit Service 3880ab
Packit Service 3880ab
	for (c = clockt_map; c->name; c++) {
Packit Service 3880ab
		if (clockid == c->clockid)
Packit Service 3880ab
			return c->name;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return "invalid";
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int get_gate_state(__u8 *val, const char *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	if (!strcasecmp("OPEN", arg)) {
Packit Service 3880ab
		*val = 1;
Packit Service 3880ab
		return 0;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (!strcasecmp("CLOSE", arg)) {
Packit Service 3880ab
		*val = 0;
Packit Service 3880ab
		return 0;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return -1;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static struct gate_entry *create_gate_entry(uint8_t gate_state,
Packit Service 3880ab
					    uint32_t interval,
Packit Service 3880ab
					    int32_t ipv,
Packit Service 3880ab
					    int32_t maxoctets)
Packit Service 3880ab
{
Packit Service 3880ab
	struct gate_entry *e;
Packit Service 3880ab
Packit Service 3880ab
	e = calloc(1, sizeof(*e));
Packit Service 3880ab
	if (!e)
Packit Service 3880ab
		return NULL;
Packit Service 3880ab
Packit Service 3880ab
	e->gate_state = gate_state;
Packit Service 3880ab
	e->interval = interval;
Packit Service 3880ab
	e->ipv = ipv;
Packit Service 3880ab
	e->maxoctets = maxoctets;
Packit Service 3880ab
Packit Service 3880ab
	return e;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int add_gate_list(struct list_head *gate_entries, struct nlmsghdr *n)
Packit Service 3880ab
{
Packit Service 3880ab
	struct gate_entry *e;
Packit Service 3880ab
Packit Service 3880ab
	list_for_each_entry(e, gate_entries, list) {
Packit Service 3880ab
		struct rtattr *a;
Packit Service 3880ab
Packit Service 3880ab
		a = addattr_nest(n, 1024, TCA_GATE_ONE_ENTRY | NLA_F_NESTED);
Packit Service 3880ab
Packit Service 3880ab
		if (e->gate_state)
Packit Service 3880ab
			addattr(n, MAX_MSG, TCA_GATE_ENTRY_GATE);
Packit Service 3880ab
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_ENTRY_INTERVAL,
Packit Service 3880ab
			  &e->interval, sizeof(e->interval));
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_ENTRY_IPV,
Packit Service 3880ab
			  &e->ipv, sizeof(e->ipv));
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_ENTRY_MAX_OCTETS,
Packit Service 3880ab
			  &e->maxoctets, sizeof(e->maxoctets));
Packit Service 3880ab
Packit Service 3880ab
		addattr_nest_end(n, a);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void free_entries(struct list_head *gate_entries)
Packit Service 3880ab
{
Packit Service 3880ab
	struct gate_entry *e, *n;
Packit Service 3880ab
Packit Service 3880ab
	list_for_each_entry_safe(e, n, gate_entries, list) {
Packit Service 3880ab
		list_del(&e->list);
Packit Service 3880ab
		free(e);
Packit Service 3880ab
	}
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int parse_gate(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_gate parm = {.action = TC_ACT_PIPE};
Packit Service 3880ab
	struct list_head gate_entries;
Packit Service 3880ab
	__s32 clockid = CLOCKID_INVALID;
Packit Service 3880ab
	struct rtattr *tail, *nle;
Packit Service 3880ab
	char **argv = *argv_p;
Packit Service 3880ab
	int argc = *argc_p;
Packit Service 3880ab
	__s64 base_time = 0;
Packit Service 3880ab
	__s64 cycle_time = 0;
Packit Service 3880ab
	__s64 cycle_time_ext = 0;
Packit Service 3880ab
	int entry_num = 0;
Packit Service 3880ab
	char *invalidarg;
Packit Service 3880ab
	__u32 flags = 0;
Packit Service 3880ab
	int prio = -1;
Packit Service 3880ab
Packit Service 3880ab
	int err;
Packit Service 3880ab
Packit Service 3880ab
	if (matches(*argv, "gate") != 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	NEXT_ARG();
Packit Service 3880ab
	if (argc <= 0)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	INIT_LIST_HEAD(&gate_entries);
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
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
				invalidarg = "index";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "priority") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_s32(&prio, *argv, 0)) {
Packit Service 3880ab
				invalidarg = "priority";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "base-time") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_s64(&base_time, *argv, 10) &&
Packit Service 3880ab
			    get_time64(&base_time, *argv)) {
Packit Service 3880ab
				invalidarg = "base-time";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "cycle-time") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_s64(&cycle_time, *argv, 10) &&
Packit Service 3880ab
			    get_time64(&cycle_time, *argv)) {
Packit Service 3880ab
				invalidarg = "cycle-time";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "cycle-time-ext") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_s64(&cycle_time_ext, *argv, 10) &&
Packit Service 3880ab
			    get_time64(&cycle_time_ext, *argv)) {
Packit Service 3880ab
				invalidarg = "cycle-time-ext";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "clockid") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_clockid(&clockid, *argv)) {
Packit Service 3880ab
				invalidarg = "clockid";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "flags") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&flags, *argv, 0)) {
Packit Service 3880ab
				invalidarg = "flags";
Packit Service 3880ab
				goto err_arg;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "sched-entry") == 0) {
Packit Service 3880ab
			unsigned int maxoctets_uint = 0;
Packit Service 3880ab
			int32_t maxoctets = -1;
Packit Service 3880ab
			struct gate_entry *e;
Packit Service 3880ab
			uint8_t gate_state = 0;
Packit Service 3880ab
			__s64 interval_s64 = 0;
Packit Service 3880ab
			uint32_t interval = 0;
Packit Service 3880ab
			int32_t ipv = -1;
Packit Service 3880ab
Packit Service 3880ab
			if (!NEXT_ARG_OK()) {
Packit Service 3880ab
				explain_entry_format();
Packit Service 3880ab
				fprintf(stderr, "\"sched-entry\" is imcomplete\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (get_gate_state(&gate_state, *argv)) {
Packit Service 3880ab
				explain_entry_format();
Packit Service 3880ab
				fprintf(stderr, "\"sched-entry\" is imcomplete\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			if (!NEXT_ARG_OK()) {
Packit Service 3880ab
				explain_entry_format();
Packit Service 3880ab
				fprintf(stderr, "\"sched-entry\" is imcomplete\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (get_u32(&interval, *argv, 0) &&
Packit Service 3880ab
			    get_time64(&interval_s64, *argv)) {
Packit Service 3880ab
				explain_entry_format();
Packit Service 3880ab
				fprintf(stderr, "\"sched-entry\" is imcomplete\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			if (interval_s64 > UINT_MAX) {
Packit Service 3880ab
				fprintf(stderr, "\"interval\" is too large\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			} else if (interval_s64) {
Packit Service 3880ab
				interval = interval_s64;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			if (!NEXT_ARG_OK())
Packit Service 3880ab
				goto create_entry;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (get_s32(&ipv, *argv, 0)) {
Packit Service 3880ab
				PREV_ARG();
Packit Service 3880ab
				goto create_entry;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			if (!gate_state)
Packit Service 3880ab
				ipv = -1;
Packit Service 3880ab
Packit Service 3880ab
			if (!NEXT_ARG_OK())
Packit Service 3880ab
				goto create_entry;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (get_s32(&maxoctets, *argv, 0) &&
Packit Service 3880ab
			    get_size(&maxoctets_uint, *argv))
Packit Service 3880ab
				PREV_ARG();
Packit Service 3880ab
Packit Service 3880ab
			if (maxoctets_uint > INT_MAX) {
Packit Service 3880ab
				fprintf(stderr, "\"maxoctets\" is too large\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			} else if (maxoctets_uint ) {
Packit Service 3880ab
				maxoctets = maxoctets_uint;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			if (!gate_state)
Packit Service 3880ab
				maxoctets = -1;
Packit Service 3880ab
Packit Service 3880ab
create_entry:
Packit Service 3880ab
			e = create_gate_entry(gate_state, interval,
Packit Service 3880ab
					      ipv, maxoctets);
Packit Service 3880ab
			if (!e) {
Packit Service 3880ab
				fprintf(stderr, "gate: not enough memory\n");
Packit Service 3880ab
				free_entries(&gate_entries);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
Packit Service 3880ab
			list_add_tail(&e->list, &gate_entries);
Packit Service 3880ab
			entry_num++;
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
Packit Service 3880ab
		argc--;
Packit Service 3880ab
		argv++;
Packit Service 3880ab
	}
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 (!entry_num && !parm.index) {
Packit Service 3880ab
		fprintf(stderr, "gate: must add at least one entry\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	tail = addattr_nest(n, MAX_MSG, tca_id | NLA_F_NESTED);
Packit Service 3880ab
	addattr_l(n, MAX_MSG, TCA_GATE_PARMS, &parm, sizeof(parm));
Packit Service 3880ab
Packit Service 3880ab
	if (prio != -1)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_PRIORITY, &prio, sizeof(prio));
Packit Service 3880ab
Packit Service 3880ab
	if (flags)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_FLAGS, &flags, sizeof(flags));
Packit Service 3880ab
Packit Service 3880ab
	if (base_time)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_BASE_TIME,
Packit Service 3880ab
			  &base_time, sizeof(base_time));
Packit Service 3880ab
Packit Service 3880ab
	if (cycle_time)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_CYCLE_TIME,
Packit Service 3880ab
			  &cycle_time, sizeof(cycle_time));
Packit Service 3880ab
Packit Service 3880ab
	if (cycle_time_ext)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_CYCLE_TIME_EXT,
Packit Service 3880ab
			  &cycle_time_ext, sizeof(cycle_time_ext));
Packit Service 3880ab
Packit Service 3880ab
	if (clockid != CLOCKID_INVALID)
Packit Service 3880ab
		addattr_l(n, MAX_MSG, TCA_GATE_CLOCKID,
Packit Service 3880ab
			  &clockid, sizeof(clockid));
Packit Service 3880ab
Packit Service 3880ab
	nle = addattr_nest(n, MAX_MSG, TCA_GATE_ENTRY_LIST | NLA_F_NESTED);
Packit Service 3880ab
	err = add_gate_list(&gate_entries, n);
Packit Service 3880ab
	if (err < 0) {
Packit Service 3880ab
		fprintf(stderr, "Could not add entries to netlink message\n");
Packit Service 3880ab
		free_entries(&gate_entries);
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	addattr_nest_end(n, nle);
Packit Service 3880ab
	addattr_nest_end(n, tail);
Packit Service 3880ab
	free_entries(&gate_entries);
Packit Service 3880ab
	*argc_p = argc;
Packit Service 3880ab
	*argv_p = argv;
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
err_arg:
Packit Service 3880ab
	invarg(invalidarg, *argv);
Packit Service 3880ab
	free_entries(&gate_entries);
Packit Service 3880ab
Packit Service 3880ab
	return -1;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int print_gate_list(struct rtattr *list)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *item;
Packit Service 3880ab
	int rem;
Packit Service 3880ab
Packit Service 3880ab
	rem = RTA_PAYLOAD(list);
Packit Service 3880ab
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "%s", _SL_);
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "\tschedule:%s", _SL_);
Packit Service 3880ab
	open_json_array(PRINT_JSON, "schedule");
Packit Service 3880ab
Packit Service 3880ab
	for (item = RTA_DATA(list);
Packit Service 3880ab
	     RTA_OK(item, rem);
Packit Service 3880ab
	     item = RTA_NEXT(item, rem)) {
Packit Service 3880ab
		struct rtattr *tb[TCA_GATE_ENTRY_MAX + 1];
Packit Service 3880ab
		__u32 index = 0, interval = 0;
Packit Service 3880ab
		__u8 gate_state = 0;
Packit Service 3880ab
		__s32 ipv = -1, maxoctets = -1;
Packit Service 3880ab
		char buf[22];
Packit Service 3880ab
Packit Service 3880ab
		parse_rtattr_nested(tb, TCA_GATE_ENTRY_MAX, item);
Packit Service 3880ab
Packit Service 3880ab
		if (tb[TCA_GATE_ENTRY_INDEX])
Packit Service 3880ab
			index = rta_getattr_u32(tb[TCA_GATE_ENTRY_INDEX]);
Packit Service 3880ab
Packit Service 3880ab
		if (tb[TCA_GATE_ENTRY_GATE])
Packit Service 3880ab
			gate_state = 1;
Packit Service 3880ab
Packit Service 3880ab
		if (tb[TCA_GATE_ENTRY_INTERVAL])
Packit Service 3880ab
			interval = rta_getattr_u32(tb[TCA_GATE_ENTRY_INTERVAL]);
Packit Service 3880ab
Packit Service 3880ab
		if (tb[TCA_GATE_ENTRY_IPV])
Packit Service 3880ab
			ipv = rta_getattr_s32(tb[TCA_GATE_ENTRY_IPV]);
Packit Service 3880ab
Packit Service 3880ab
		if (tb[TCA_GATE_ENTRY_MAX_OCTETS])
Packit Service 3880ab
			maxoctets = rta_getattr_s32(tb[TCA_GATE_ENTRY_MAX_OCTETS]);
Packit Service 3880ab
Packit Service 3880ab
		open_json_object(NULL);
Packit Service 3880ab
		print_uint(PRINT_ANY, "number", "\t number %4u", index);
Packit Service 3880ab
		print_string(PRINT_ANY, "gate_state", "\tgate-state %s ",
Packit Service 3880ab
			     gate_state ? "open" : "close");
Packit Service 3880ab
Packit Service 3880ab
		print_uint(PRINT_JSON, "interval", NULL, interval);
Packit Service 3880ab
Packit Service 3880ab
		memset(buf, 0, sizeof(buf));
Packit Service 3880ab
		print_string(PRINT_FP, NULL, "\tinterval %s",
Packit Service 3880ab
			     sprint_time64(interval, buf));
Packit Service 3880ab
Packit Service 3880ab
		if (ipv != -1) {
Packit Service 3880ab
			print_uint(PRINT_ANY, "ipv", "\t ipv %-10u", ipv);
Packit Service 3880ab
		} else {
Packit Service 3880ab
			print_int(PRINT_JSON, "ipv", NULL, ipv);
Packit Service 3880ab
			print_string(PRINT_FP, NULL, "\t ipv %s", "wildcard");
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		if (maxoctets != -1) {
Packit Service 3880ab
			memset(buf, 0, sizeof(buf));
Packit Service 3880ab
			print_uint(PRINT_JSON, "max_octets", NULL, maxoctets);
Packit Service 3880ab
			print_string(PRINT_FP, NULL, "\t max-octets %s",
Packit Service 3880ab
				     sprint_size(maxoctets, buf));
Packit Service 3880ab
		} else {
Packit Service 3880ab
			print_string(PRINT_FP, NULL,
Packit Service 3880ab
				     "\t max-octets %s", "wildcard");
Packit Service 3880ab
			print_int(PRINT_JSON, "max_octets", NULL, maxoctets);
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		close_json_object();
Packit Service 3880ab
		print_string(PRINT_FP, NULL, "%s", _SL_);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	close_json_array(PRINT_ANY, "");
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int print_gate(struct action_util *au, FILE *f, struct rtattr *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	struct tc_gate *parm;
Packit Service 3880ab
	struct rtattr *tb[TCA_GATE_MAX + 1];
Packit Service 3880ab
	__s32 clockid = CLOCKID_INVALID;
Packit Service 3880ab
	__s64 base_time = 0;
Packit Service 3880ab
	__s64 cycle_time = 0;
Packit Service 3880ab
	__s64 cycle_time_ext = 0;
Packit Service 3880ab
	char buf[22];
Packit Service 3880ab
	int prio = -1;
Packit Service 3880ab
Packit Service 3880ab
	if (arg == NULL)
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_GATE_MAX, arg);
Packit Service 3880ab
Packit Service 3880ab
	if (!tb[TCA_GATE_PARMS]) {
Packit Service 3880ab
		fprintf(stderr, "Missing gate parameters\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "%s", "\n");
Packit Service 3880ab
Packit Service 3880ab
	parm = RTA_DATA(tb[TCA_GATE_PARMS]);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_PRIORITY])
Packit Service 3880ab
		prio = rta_getattr_s32(tb[TCA_GATE_PRIORITY]);
Packit Service 3880ab
Packit Service 3880ab
	if (prio != -1) {
Packit Service 3880ab
		print_int(PRINT_ANY, "priority", "\tpriority %-8d", prio);
Packit Service 3880ab
	} else {
Packit Service 3880ab
		print_string(PRINT_FP, NULL, "\tpriority %s", "wildcard");
Packit Service 3880ab
		print_int(PRINT_JSON, "priority", NULL, prio);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_CLOCKID])
Packit Service 3880ab
		clockid = rta_getattr_s32(tb[TCA_GATE_CLOCKID]);
Packit Service 3880ab
	print_string(PRINT_ANY, "clockid", "\tclockid %s",
Packit Service 3880ab
		     get_clock_name(clockid));
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_FLAGS]) {
Packit Service 3880ab
		__u32 flags;
Packit Service 3880ab
Packit Service 3880ab
		flags = rta_getattr_u32(tb[TCA_GATE_FLAGS]);
Packit Service 3880ab
		print_0xhex(PRINT_ANY, "flags", "\tflags %#x", flags);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "%s", "\n");
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_BASE_TIME])
Packit Service 3880ab
		base_time = rta_getattr_s64(tb[TCA_GATE_BASE_TIME]);
Packit Service 3880ab
Packit Service 3880ab
	memset(buf, 0, sizeof(buf));
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "\tbase-time %s",
Packit Service 3880ab
		     sprint_time64(base_time, buf));
Packit Service 3880ab
	print_lluint(PRINT_JSON, "base_time", NULL, base_time);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_CYCLE_TIME])
Packit Service 3880ab
		cycle_time = rta_getattr_s64(tb[TCA_GATE_CYCLE_TIME]);
Packit Service 3880ab
Packit Service 3880ab
	memset(buf, 0, sizeof(buf));
Packit Service 3880ab
	print_string(PRINT_FP, NULL,
Packit Service 3880ab
		     "\tcycle-time %s", sprint_time64(cycle_time, buf));
Packit Service 3880ab
	print_lluint(PRINT_JSON, "cycle_time", NULL, cycle_time);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_CYCLE_TIME_EXT])
Packit Service 3880ab
		cycle_time_ext = rta_getattr_s64(tb[TCA_GATE_CYCLE_TIME_EXT]);
Packit Service 3880ab
Packit Service 3880ab
	memset(buf, 0, sizeof(buf));
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "\tcycle-time-ext %s",
Packit Service 3880ab
		     sprint_time64(cycle_time_ext, buf));
Packit Service 3880ab
	print_lluint(PRINT_JSON, "cycle_time_ext", NULL, cycle_time_ext);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_GATE_ENTRY_LIST])
Packit Service 3880ab
		print_gate_list(tb[TCA_GATE_ENTRY_LIST]);
Packit Service 3880ab
Packit Service 3880ab
	print_action_control(f, "\t", parm->action, "");
Packit Service 3880ab
Packit Service 3880ab
	print_uint(PRINT_ANY, "index", "\n\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_GATE_TM]) {
Packit Service 3880ab
			struct tcf_t *tm = RTA_DATA(tb[TCA_GATE_TM]);
Packit Service 3880ab
Packit Service 3880ab
			print_tm(f, tm);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	print_string(PRINT_FP, NULL, "%s", "\n");
Packit Service 3880ab
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}