]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_ctinfo.c
tc: q_red: Implement has_block for RED
[mirror_iproute2.git] / tc / m_ctinfo.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * m_ctinfo.c netfilter ctinfo mark action
4 *
5 * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include "utils.h"
13 #include "tc_util.h"
14 #include <linux/tc_act/tc_ctinfo.h>
15
16 static void
17 explain(void)
18 {
19 fprintf(stderr,
20 "Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] [CONTROL] [index <INDEX>]\n"
21 "where :\n"
22 "\tdscp MASK bitmask location of stored DSCP\n"
23 "\t STATEMASK bitmask to determine conditional restoring\n"
24 "\tcpmark MASK mask applied to mark on restoration\n"
25 "\tZONE is the conntrack zone\n"
26 "\tCONTROL := reclassify | pipe | drop | continue | ok |\n"
27 "\t goto chain <CHAIN_INDEX>\n");
28 }
29
30 static void
31 usage(void)
32 {
33 explain();
34 exit(-1);
35 }
36
37 static int
38 parse_ctinfo(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
39 struct nlmsghdr *n)
40 {
41 unsigned int cpmarkmask = 0, dscpmask = 0, dscpstatemask = 0;
42 struct tc_ctinfo sel = {};
43 unsigned short zone = 0;
44 char **argv = *argv_p;
45 struct rtattr *tail;
46 int argc = *argc_p;
47 int ok = 0;
48 __u8 i;
49
50 while (argc > 0) {
51 if (matches(*argv, "ctinfo") == 0) {
52 ok = 1;
53 NEXT_ARG_FWD();
54 } else if (matches(*argv, "help") == 0) {
55 usage();
56 } else {
57 break;
58 }
59
60 }
61
62 if (!ok) {
63 explain();
64 return -1;
65 }
66
67 if (argc) {
68 if (matches(*argv, "dscp") == 0) {
69 NEXT_ARG();
70 if (get_u32(&dscpmask, *argv, 0)) {
71 fprintf(stderr,
72 "ctinfo: Illegal dscp \"mask\"\n");
73 return -1;
74 }
75 if (NEXT_ARG_OK()) {
76 NEXT_ARG_FWD();
77 if (!get_u32(&dscpstatemask, *argv, 0))
78 NEXT_ARG_FWD(); /* was a statemask */
79 } else {
80 NEXT_ARG_FWD();
81 }
82 }
83 }
84
85 /* cpmark has optional mask parameter, so the next arg might not */
86 /* exist, or it might be the next option, or it may actually be a */
87 /* 32bit mask */
88 if (argc) {
89 if (matches(*argv, "cpmark") == 0) {
90 cpmarkmask = ~0;
91 if (NEXT_ARG_OK()) {
92 NEXT_ARG_FWD();
93 if (!get_u32(&cpmarkmask, *argv, 0))
94 NEXT_ARG_FWD(); /* was a mask */
95 } else {
96 NEXT_ARG_FWD();
97 }
98 }
99 }
100
101 if (argc) {
102 if (matches(*argv, "zone") == 0) {
103 NEXT_ARG();
104 if (get_u16(&zone, *argv, 10)) {
105 fprintf(stderr, "ctinfo: Illegal \"zone\"\n");
106 return -1;
107 }
108 NEXT_ARG_FWD();
109 }
110 }
111
112 parse_action_control_dflt(&argc, &argv, &sel.action,
113 false, TC_ACT_PIPE);
114
115 if (argc) {
116 if (matches(*argv, "index") == 0) {
117 NEXT_ARG();
118 if (get_u32(&sel.index, *argv, 10)) {
119 fprintf(stderr, "ctinfo: Illegal \"index\"\n");
120 return -1;
121 }
122 NEXT_ARG_FWD();
123 }
124 }
125
126 if (dscpmask & dscpstatemask) {
127 fprintf(stderr,
128 "ctinfo: dscp mask & statemask must NOT overlap\n");
129 return -1;
130 }
131
132 i = ffs(dscpmask);
133 if (i && ((~0 & (dscpmask >> (i - 1))) != 0x3f)) {
134 fprintf(stderr,
135 "ctinfo: dscp mask must be 6 contiguous bits long\n");
136 return -1;
137 }
138
139 tail = addattr_nest(n, MAX_MSG, tca_id);
140 addattr_l(n, MAX_MSG, TCA_CTINFO_ACT, &sel, sizeof(sel));
141 addattr16(n, MAX_MSG, TCA_CTINFO_ZONE, zone);
142
143 if (dscpmask)
144 addattr32(n, MAX_MSG,
145 TCA_CTINFO_PARMS_DSCP_MASK, dscpmask);
146
147 if (dscpstatemask)
148 addattr32(n, MAX_MSG,
149 TCA_CTINFO_PARMS_DSCP_STATEMASK, dscpstatemask);
150
151 if (cpmarkmask)
152 addattr32(n, MAX_MSG,
153 TCA_CTINFO_PARMS_CPMARK_MASK, cpmarkmask);
154
155 addattr_nest_end(n, tail);
156
157 *argc_p = argc;
158 *argv_p = argv;
159 return 0;
160 }
161
162 static void print_ctinfo_stats(FILE *f, struct rtattr *tb[TCA_CTINFO_MAX + 1])
163 {
164 struct tcf_t *tm;
165
166 if (tb[TCA_CTINFO_TM]) {
167 tm = RTA_DATA(tb[TCA_CTINFO_TM]);
168
169 print_tm(f, tm);
170 }
171
172 if (tb[TCA_CTINFO_STATS_DSCP_SET])
173 print_lluint(PRINT_ANY, "dscpset", " DSCP set %llu",
174 rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_SET]));
175 if (tb[TCA_CTINFO_STATS_DSCP_ERROR])
176 print_lluint(PRINT_ANY, "dscperror", " error %llu",
177 rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_ERROR]));
178
179 if (tb[TCA_CTINFO_STATS_CPMARK_SET])
180 print_lluint(PRINT_ANY, "cpmarkset", " CPMARK set %llu",
181 rta_getattr_u64(tb[TCA_CTINFO_STATS_CPMARK_SET]));
182 }
183
184 static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg)
185 {
186 unsigned int cpmarkmask = ~0, dscpmask = 0, dscpstatemask = 0;
187 struct rtattr *tb[TCA_CTINFO_MAX + 1];
188 unsigned short zone = 0;
189 struct tc_ctinfo *ci;
190
191 if (arg == NULL)
192 return -1;
193
194 parse_rtattr_nested(tb, TCA_CTINFO_MAX, arg);
195 if (!tb[TCA_CTINFO_ACT]) {
196 print_string(PRINT_FP, NULL, "%s",
197 "[NULL ctinfo action parameters]");
198 return -1;
199 }
200
201 ci = RTA_DATA(tb[TCA_CTINFO_ACT]);
202
203 if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
204 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_MASK]) >=
205 sizeof(__u32))
206 dscpmask = rta_getattr_u32(
207 tb[TCA_CTINFO_PARMS_DSCP_MASK]);
208 else
209 print_string(PRINT_FP, NULL, "%s",
210 "[invalid dscp mask parameter]");
211 }
212
213 if (tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) {
214 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) >=
215 sizeof(__u32))
216 dscpstatemask = rta_getattr_u32(
217 tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]);
218 else
219 print_string(PRINT_FP, NULL, "%s",
220 "[invalid dscp statemask parameter]");
221 }
222
223 if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) {
224 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_CPMARK_MASK]) >=
225 sizeof(__u32))
226 cpmarkmask = rta_getattr_u32(
227 tb[TCA_CTINFO_PARMS_CPMARK_MASK]);
228 else
229 print_string(PRINT_FP, NULL, "%s",
230 "[invalid cpmark mask parameter]");
231 }
232
233 if (tb[TCA_CTINFO_ZONE] && RTA_PAYLOAD(tb[TCA_CTINFO_ZONE]) >=
234 sizeof(__u16))
235 zone = rta_getattr_u16(tb[TCA_CTINFO_ZONE]);
236
237 print_string(PRINT_ANY, "kind", "%s ", "ctinfo");
238 print_hu(PRINT_ANY, "zone", "zone %u", zone);
239 print_action_control(f, " ", ci->action, "");
240
241 print_nl();
242 print_uint(PRINT_ANY, "index", "\t index %u", ci->index);
243 print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt);
244 print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt);
245
246 if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
247 print_0xhex(PRINT_ANY, "dscpmask", " dscp %#010llx", dscpmask);
248 print_0xhex(PRINT_ANY, "dscpstatemask", " %#010llx",
249 dscpstatemask);
250 }
251
252 if (tb[TCA_CTINFO_PARMS_CPMARK_MASK])
253 print_0xhex(PRINT_ANY, "cpmark", " cpmark %#010llx",
254 cpmarkmask);
255
256 if (show_stats)
257 print_ctinfo_stats(f, tb);
258
259 print_nl();
260
261 return 0;
262 }
263
264 struct action_util ctinfo_action_util = {
265 .id = "ctinfo",
266 .parse_aopt = parse_ctinfo,
267 .print_aopt = print_ctinfo,
268 };