]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_ctinfo.c
Merge branch 'main' into next
[mirror_iproute2.git] / tc / m_ctinfo.c
CommitLineData
d7f2bccd
KDB
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
16static void
17explain(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
30static void
31usage(void)
32{
33 explain();
34 exit(-1);
35}
36
37static int
38parse_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
162static 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
184static 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
a99ebeee 191 print_string(PRINT_ANY, "kind", "%s ", "ctinfo");
d7f2bccd 192 if (arg == NULL)
a99ebeee 193 return 0;
d7f2bccd
KDB
194
195 parse_rtattr_nested(tb, TCA_CTINFO_MAX, arg);
196 if (!tb[TCA_CTINFO_ACT]) {
197 print_string(PRINT_FP, NULL, "%s",
198 "[NULL ctinfo action parameters]");
199 return -1;
200 }
201
202 ci = RTA_DATA(tb[TCA_CTINFO_ACT]);
203
204 if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
205 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_MASK]) >=
206 sizeof(__u32))
207 dscpmask = rta_getattr_u32(
208 tb[TCA_CTINFO_PARMS_DSCP_MASK]);
209 else
210 print_string(PRINT_FP, NULL, "%s",
211 "[invalid dscp mask parameter]");
212 }
213
214 if (tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) {
215 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) >=
216 sizeof(__u32))
217 dscpstatemask = rta_getattr_u32(
218 tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]);
219 else
220 print_string(PRINT_FP, NULL, "%s",
221 "[invalid dscp statemask parameter]");
222 }
223
224 if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) {
225 if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_CPMARK_MASK]) >=
226 sizeof(__u32))
227 cpmarkmask = rta_getattr_u32(
228 tb[TCA_CTINFO_PARMS_CPMARK_MASK]);
229 else
230 print_string(PRINT_FP, NULL, "%s",
231 "[invalid cpmark mask parameter]");
232 }
233
234 if (tb[TCA_CTINFO_ZONE] && RTA_PAYLOAD(tb[TCA_CTINFO_ZONE]) >=
235 sizeof(__u16))
236 zone = rta_getattr_u16(tb[TCA_CTINFO_ZONE]);
237
d7f2bccd
KDB
238 print_hu(PRINT_ANY, "zone", "zone %u", zone);
239 print_action_control(f, " ", ci->action, "");
240
0501fe73 241 print_nl();
d7f2bccd
KDB
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
0501fe73 259 print_nl();
d7f2bccd
KDB
260
261 return 0;
262}
263
264struct action_util ctinfo_action_util = {
265 .id = "ctinfo",
266 .parse_aopt = parse_ctinfo,
267 .print_aopt = print_ctinfo,
268};