xref: /aosp_15_r20/external/iproute2/tc/m_csum.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * m_csum.c	checksum updating action
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Authors: Gregoire Baron <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  */
11*de1e4e89SAndroid Build Coastguard Worker 
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
16*de1e4e89SAndroid Build Coastguard Worker 
17*de1e4e89SAndroid Build Coastguard Worker #include <linux/tc_act/tc_csum.h>
18*de1e4e89SAndroid Build Coastguard Worker 
19*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
20*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
21*de1e4e89SAndroid Build Coastguard Worker 
22*de1e4e89SAndroid Build Coastguard Worker static void
explain(void)23*de1e4e89SAndroid Build Coastguard Worker explain(void)
24*de1e4e89SAndroid Build Coastguard Worker {
25*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: ... csum <UPDATE>\n"
26*de1e4e89SAndroid Build Coastguard Worker 			"Where: UPDATE := <TARGET> [<UPDATE>]\n"
27*de1e4e89SAndroid Build Coastguard Worker 			"       TARGET := { ip4h | icmp | igmp | tcp | udp | udplite | sctp | <SWEETS> }\n"
28*de1e4e89SAndroid Build Coastguard Worker 			"       SWEETS := { and | or | \'+\' }\n");
29*de1e4e89SAndroid Build Coastguard Worker }
30*de1e4e89SAndroid Build Coastguard Worker 
31*de1e4e89SAndroid Build Coastguard Worker static void
usage(void)32*de1e4e89SAndroid Build Coastguard Worker usage(void)
33*de1e4e89SAndroid Build Coastguard Worker {
34*de1e4e89SAndroid Build Coastguard Worker 	explain();
35*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
36*de1e4e89SAndroid Build Coastguard Worker }
37*de1e4e89SAndroid Build Coastguard Worker 
38*de1e4e89SAndroid Build Coastguard Worker static int
parse_csum_args(int * argc_p,char *** argv_p,struct tc_csum * sel)39*de1e4e89SAndroid Build Coastguard Worker parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel)
40*de1e4e89SAndroid Build Coastguard Worker {
41*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
42*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
43*de1e4e89SAndroid Build Coastguard Worker 
44*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
45*de1e4e89SAndroid Build Coastguard Worker 		return -1;
46*de1e4e89SAndroid Build Coastguard Worker 
47*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
48*de1e4e89SAndroid Build Coastguard Worker 		if ((matches(*argv, "iph") == 0) ||
49*de1e4e89SAndroid Build Coastguard Worker 		    (matches(*argv, "ip4h") == 0) ||
50*de1e4e89SAndroid Build Coastguard Worker 		    (matches(*argv, "ipv4h") == 0))
51*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;
52*de1e4e89SAndroid Build Coastguard Worker 
53*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "icmp") == 0)
54*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;
55*de1e4e89SAndroid Build Coastguard Worker 
56*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "igmp") == 0)
57*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IGMP;
58*de1e4e89SAndroid Build Coastguard Worker 
59*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "tcp") == 0)
60*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;
61*de1e4e89SAndroid Build Coastguard Worker 
62*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "udp") == 0)
63*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
64*de1e4e89SAndroid Build Coastguard Worker 
65*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "udplite") == 0)
66*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE;
67*de1e4e89SAndroid Build Coastguard Worker 
68*de1e4e89SAndroid Build Coastguard Worker 		else if (matches(*argv, "sctp") == 0)
69*de1e4e89SAndroid Build Coastguard Worker 			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_SCTP;
70*de1e4e89SAndroid Build Coastguard Worker 
71*de1e4e89SAndroid Build Coastguard Worker 		else if ((matches(*argv, "and") == 0) ||
72*de1e4e89SAndroid Build Coastguard Worker 			 (matches(*argv, "or") == 0) ||
73*de1e4e89SAndroid Build Coastguard Worker 			 (matches(*argv, "+") == 0))
74*de1e4e89SAndroid Build Coastguard Worker 			; /* just ignore: ... csum iph and tcp or udp */
75*de1e4e89SAndroid Build Coastguard Worker 		else
76*de1e4e89SAndroid Build Coastguard Worker 			break;
77*de1e4e89SAndroid Build Coastguard Worker 		argc--;
78*de1e4e89SAndroid Build Coastguard Worker 		argv++;
79*de1e4e89SAndroid Build Coastguard Worker 	}
80*de1e4e89SAndroid Build Coastguard Worker 
81*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
82*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
83*de1e4e89SAndroid Build Coastguard Worker 
84*de1e4e89SAndroid Build Coastguard Worker 	return 0;
85*de1e4e89SAndroid Build Coastguard Worker }
86*de1e4e89SAndroid Build Coastguard Worker 
87*de1e4e89SAndroid Build Coastguard Worker static int
parse_csum(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)88*de1e4e89SAndroid Build Coastguard Worker parse_csum(struct action_util *a, int *argc_p,
89*de1e4e89SAndroid Build Coastguard Worker 	   char ***argv_p, int tca_id, struct nlmsghdr *n)
90*de1e4e89SAndroid Build Coastguard Worker {
91*de1e4e89SAndroid Build Coastguard Worker 	struct tc_csum sel = {};
92*de1e4e89SAndroid Build Coastguard Worker 
93*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
94*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
95*de1e4e89SAndroid Build Coastguard Worker 	int ok = 0;
96*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail;
97*de1e4e89SAndroid Build Coastguard Worker 
98*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
99*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "csum") == 0) {
100*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
101*de1e4e89SAndroid Build Coastguard Worker 			if (parse_csum_args(&argc, &argv, &sel)) {
102*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal csum construct (%s)\n",
103*de1e4e89SAndroid Build Coastguard Worker 					*argv);
104*de1e4e89SAndroid Build Coastguard Worker 				explain();
105*de1e4e89SAndroid Build Coastguard Worker 				return -1;
106*de1e4e89SAndroid Build Coastguard Worker 			}
107*de1e4e89SAndroid Build Coastguard Worker 			ok++;
108*de1e4e89SAndroid Build Coastguard Worker 			continue;
109*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "help") == 0) {
110*de1e4e89SAndroid Build Coastguard Worker 			usage();
111*de1e4e89SAndroid Build Coastguard Worker 		} else {
112*de1e4e89SAndroid Build Coastguard Worker 			break;
113*de1e4e89SAndroid Build Coastguard Worker 		}
114*de1e4e89SAndroid Build Coastguard Worker 	}
115*de1e4e89SAndroid Build Coastguard Worker 
116*de1e4e89SAndroid Build Coastguard Worker 	if (!ok) {
117*de1e4e89SAndroid Build Coastguard Worker 		explain();
118*de1e4e89SAndroid Build Coastguard Worker 		return -1;
119*de1e4e89SAndroid Build Coastguard Worker 	}
120*de1e4e89SAndroid Build Coastguard Worker 
121*de1e4e89SAndroid Build Coastguard Worker 	if (sel.update_flags == 0) {
122*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal csum construct, empty <UPDATE> list\n");
123*de1e4e89SAndroid Build Coastguard Worker 		return -1;
124*de1e4e89SAndroid Build Coastguard Worker 	}
125*de1e4e89SAndroid Build Coastguard Worker 
126*de1e4e89SAndroid Build Coastguard Worker 	parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
127*de1e4e89SAndroid Build Coastguard Worker 
128*de1e4e89SAndroid Build Coastguard Worker 	if (argc) {
129*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "index") == 0) {
130*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
131*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&sel.index, *argv, 10)) {
132*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"index\" (%s) <csum>\n",
133*de1e4e89SAndroid Build Coastguard Worker 					*argv);
134*de1e4e89SAndroid Build Coastguard Worker 				return -1;
135*de1e4e89SAndroid Build Coastguard Worker 			}
136*de1e4e89SAndroid Build Coastguard Worker 			argc--;
137*de1e4e89SAndroid Build Coastguard Worker 			argv++;
138*de1e4e89SAndroid Build Coastguard Worker 		}
139*de1e4e89SAndroid Build Coastguard Worker 	}
140*de1e4e89SAndroid Build Coastguard Worker 
141*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(n);
142*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
143*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel));
144*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
145*de1e4e89SAndroid Build Coastguard Worker 
146*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
147*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
148*de1e4e89SAndroid Build Coastguard Worker 
149*de1e4e89SAndroid Build Coastguard Worker 	return 0;
150*de1e4e89SAndroid Build Coastguard Worker }
151*de1e4e89SAndroid Build Coastguard Worker 
152*de1e4e89SAndroid Build Coastguard Worker static int
print_csum(struct action_util * au,FILE * f,struct rtattr * arg)153*de1e4e89SAndroid Build Coastguard Worker print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
154*de1e4e89SAndroid Build Coastguard Worker {
155*de1e4e89SAndroid Build Coastguard Worker 	struct tc_csum *sel;
156*de1e4e89SAndroid Build Coastguard Worker 
157*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_CSUM_MAX + 1];
158*de1e4e89SAndroid Build Coastguard Worker 
159*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_1 = "";
160*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_2 = "";
161*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_3 = "";
162*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_4 = "";
163*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_5 = "";
164*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_6 = "";
165*de1e4e89SAndroid Build Coastguard Worker 	char *uflag_7 = "";
166*de1e4e89SAndroid Build Coastguard Worker 
167*de1e4e89SAndroid Build Coastguard Worker 	int uflag_count = 0;
168*de1e4e89SAndroid Build Coastguard Worker 
169*de1e4e89SAndroid Build Coastguard Worker 	if (arg == NULL)
170*de1e4e89SAndroid Build Coastguard Worker 		return -1;
171*de1e4e89SAndroid Build Coastguard Worker 
172*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_CSUM_MAX, arg);
173*de1e4e89SAndroid Build Coastguard Worker 
174*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_CSUM_PARMS] == NULL) {
175*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "[NULL csum parameters]");
176*de1e4e89SAndroid Build Coastguard Worker 		return -1;
177*de1e4e89SAndroid Build Coastguard Worker 	}
178*de1e4e89SAndroid Build Coastguard Worker 	sel = RTA_DATA(tb[TCA_CSUM_PARMS]);
179*de1e4e89SAndroid Build Coastguard Worker 
180*de1e4e89SAndroid Build Coastguard Worker 	if (sel->update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
181*de1e4e89SAndroid Build Coastguard Worker 		uflag_1 = "iph";
182*de1e4e89SAndroid Build Coastguard Worker 		uflag_count++;
183*de1e4e89SAndroid Build Coastguard Worker 	}
184*de1e4e89SAndroid Build Coastguard Worker 	#define CSUM_UFLAG_BUFFER(flag_buffer, flag_value, flag_string)	\
185*de1e4e89SAndroid Build Coastguard Worker 		do {							\
186*de1e4e89SAndroid Build Coastguard Worker 			if (sel->update_flags & flag_value) {		\
187*de1e4e89SAndroid Build Coastguard Worker 				flag_buffer = uflag_count > 0 ?		\
188*de1e4e89SAndroid Build Coastguard Worker 					", " flag_string : flag_string; \
189*de1e4e89SAndroid Build Coastguard Worker 				uflag_count++;				\
190*de1e4e89SAndroid Build Coastguard Worker 			}						\
191*de1e4e89SAndroid Build Coastguard Worker 		} while (0)
192*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp");
193*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp");
194*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tcp");
195*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_5, TCA_CSUM_UPDATE_FLAG_UDP, "udp");
196*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_6, TCA_CSUM_UPDATE_FLAG_UDPLITE, "udplite");
197*de1e4e89SAndroid Build Coastguard Worker 	CSUM_UFLAG_BUFFER(uflag_7, TCA_CSUM_UPDATE_FLAG_SCTP, "sctp");
198*de1e4e89SAndroid Build Coastguard Worker 	if (!uflag_count) {
199*de1e4e89SAndroid Build Coastguard Worker 		uflag_1 = "?empty";
200*de1e4e89SAndroid Build Coastguard Worker 	}
201*de1e4e89SAndroid Build Coastguard Worker 
202*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "csum (%s%s%s%s%s%s%s) ",
203*de1e4e89SAndroid Build Coastguard Worker 		uflag_1, uflag_2, uflag_3,
204*de1e4e89SAndroid Build Coastguard Worker 		uflag_4, uflag_5, uflag_6, uflag_7);
205*de1e4e89SAndroid Build Coastguard Worker 	print_action_control(f, "action ", sel->action, "\n");
206*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\tindex %u ref %d bind %d", sel->index, sel->refcnt,
207*de1e4e89SAndroid Build Coastguard Worker 		sel->bindcnt);
208*de1e4e89SAndroid Build Coastguard Worker 
209*de1e4e89SAndroid Build Coastguard Worker 	if (show_stats) {
210*de1e4e89SAndroid Build Coastguard Worker 		if (tb[TCA_CSUM_TM]) {
211*de1e4e89SAndroid Build Coastguard Worker 			struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]);
212*de1e4e89SAndroid Build Coastguard Worker 
213*de1e4e89SAndroid Build Coastguard Worker 			print_tm(f, tm);
214*de1e4e89SAndroid Build Coastguard Worker 		}
215*de1e4e89SAndroid Build Coastguard Worker 	}
216*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\n");
217*de1e4e89SAndroid Build Coastguard Worker 
218*de1e4e89SAndroid Build Coastguard Worker 	return 0;
219*de1e4e89SAndroid Build Coastguard Worker }
220*de1e4e89SAndroid Build Coastguard Worker 
221*de1e4e89SAndroid Build Coastguard Worker struct action_util csum_action_util = {
222*de1e4e89SAndroid Build Coastguard Worker 	.id = "csum",
223*de1e4e89SAndroid Build Coastguard Worker 	.parse_aopt = parse_csum,
224*de1e4e89SAndroid Build Coastguard Worker 	.print_aopt = print_csum,
225*de1e4e89SAndroid Build Coastguard Worker };
226