1/*
2 * m_skbedit.c		SKB Editing module
3 *
4 * Copyright (c) 2008, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 * Authors:	Alexander Duyck <alexander.h.duyck@intel.com>
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <string.h>
27#include "utils.h"
28#include "tc_util.h"
29#include <linux/tc_act/tc_skbedit.h>
30
31static void
32explain(void)
33{
34 	fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM]>\n"
35		"QM = queue_mapping QUEUE_MAPPING\n"
36		"PM = priority PRIORITY \n"
37		"MM = mark MARK \n"
38		"QUEUE_MAPPING = device transmit queue to use\n"
39		"PRIORITY = classID to assign to priority field\n"
40		"MARK = firewall mark to set\n");
41}
42
43static void
44usage(void)
45{
46	explain();
47	exit(-1);
48}
49
50static int
51parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
52	      struct nlmsghdr *n)
53{
54	int argc = *argc_p;
55	char **argv = *argv_p;
56	int ok = 0;
57	struct rtattr *tail;
58	unsigned int tmp;
59	__u16 queue_mapping;
60	__u32 flags = 0, priority, mark;
61	struct tc_skbedit sel = { 0 };
62
63	if (matches(*argv, "skbedit") != 0)
64		return -1;
65
66	NEXT_ARG();
67
68	while (argc > 0) {
69		if (matches(*argv, "queue_mapping") == 0) {
70			flags |= SKBEDIT_F_QUEUE_MAPPING;
71			NEXT_ARG();
72			if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) {
73				fprintf(stderr, "Illegal queue_mapping\n");
74				return -1;
75			}
76			queue_mapping = tmp;
77			ok++;
78		} else if (matches(*argv, "priority") == 0) {
79			flags |= SKBEDIT_F_PRIORITY;
80			NEXT_ARG();
81			if (get_tc_classid(&priority, *argv)) {
82				fprintf(stderr, "Illegal priority\n");
83				return -1;
84			}
85			ok++;
86		} else if (matches(*argv, "mark") == 0) {
87			flags |= SKBEDIT_F_MARK;
88			NEXT_ARG();
89			if (get_u32(&mark, *argv, 0)) {
90				fprintf(stderr, "Illegal mark\n");
91				return -1;
92			}
93			ok++;
94		} else if (matches(*argv, "help") == 0) {
95			usage();
96		} else {
97			break;
98		}
99		argc--;
100		argv++;
101	}
102
103	if (argc) {
104		if (matches(*argv, "reclassify") == 0) {
105			sel.action = TC_ACT_RECLASSIFY;
106			NEXT_ARG();
107		} else if (matches(*argv, "pipe") == 0) {
108			sel.action = TC_ACT_PIPE;
109			NEXT_ARG();
110		} else if (matches(*argv, "drop") == 0 ||
111			matches(*argv, "shot") == 0) {
112			sel.action = TC_ACT_SHOT;
113			NEXT_ARG();
114		} else if (matches(*argv, "continue") == 0) {
115			sel.action = TC_ACT_UNSPEC;
116			NEXT_ARG();
117		} else if (matches(*argv, "pass") == 0) {
118			sel.action = TC_ACT_OK;
119			NEXT_ARG();
120		}
121	}
122
123	if (argc) {
124		if (matches(*argv, "index") == 0) {
125			NEXT_ARG();
126			if (get_u32(&sel.index, *argv, 10)) {
127				fprintf(stderr, "Pedit: Illegal \"index\"\n");
128				return -1;
129			}
130			argc--;
131			argv++;
132			ok++;
133		}
134	}
135
136	if (!ok) {
137		explain();
138		return -1;
139	}
140
141
142	tail = NLMSG_TAIL(n);
143	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
144	addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
145	if (flags & SKBEDIT_F_QUEUE_MAPPING)
146		addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
147			  &queue_mapping, sizeof(queue_mapping));
148	if (flags & SKBEDIT_F_PRIORITY)
149		addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY,
150			  &priority, sizeof(priority));
151	if (flags & SKBEDIT_F_MARK)
152		addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK,
153			  &mark, sizeof(mark));
154	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
155
156	*argc_p = argc;
157	*argv_p = argv;
158	return 0;
159}
160
161static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
162{
163	struct rtattr *tb[TCA_SKBEDIT_MAX + 1];
164	SPRINT_BUF(b1);
165	__u32 *priority;
166	__u32 *mark;
167	__u16 *queue_mapping;
168
169	if (arg == NULL)
170		return -1;
171
172	parse_rtattr_nested(tb, TCA_SKBEDIT_MAX, arg);
173
174	if (tb[TCA_SKBEDIT_PARMS] == NULL) {
175		fprintf(f, "[NULL skbedit parameters]");
176		return -1;
177	}
178
179	fprintf(f, " skbedit");
180
181	if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
182		queue_mapping = RTA_DATA(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
183		fprintf(f, " queue_mapping %u", *queue_mapping);
184	}
185	if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
186		priority = RTA_DATA(tb[TCA_SKBEDIT_PRIORITY]);
187		fprintf(f, " priority %s", sprint_tc_classid(*priority, b1));
188	}
189	if (tb[TCA_SKBEDIT_MARK] != NULL) {
190		mark = RTA_DATA(tb[TCA_SKBEDIT_MARK]);
191		fprintf(f, " mark %d", *mark);
192	}
193
194	if (show_stats) {
195		if (tb[TCA_SKBEDIT_TM]) {
196			struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]);
197			print_tm(f, tm);
198		}
199	}
200
201	return 0;
202}
203
204struct action_util skbedit_action_util = {
205	.id = "skbedit",
206	.parse_aopt = parse_skbedit,
207	.print_aopt = print_skbedit,
208};
209