1 /* SPDX-License-Identifier: GPL-2.0 */
3 * m_ctinfo.c netfilter ctinfo mark action
5 * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
14 #include <linux/tc_act/tc_ctinfo.h>
20 "Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] [CONTROL] [index <INDEX>]\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");
38 parse_ctinfo(struct action_util
*a
, int *argc_p
, char ***argv_p
, int tca_id
,
41 unsigned int cpmarkmask
= 0, dscpmask
= 0, dscpstatemask
= 0;
42 struct tc_ctinfo sel
= {};
43 unsigned short zone
= 0;
44 char **argv
= *argv_p
;
51 if (matches(*argv
, "ctinfo") == 0) {
54 } else if (matches(*argv
, "help") == 0) {
68 if (matches(*argv
, "dscp") == 0) {
70 if (get_u32(&dscpmask
, *argv
, 0)) {
72 "ctinfo: Illegal dscp \"mask\"\n");
77 if (!get_u32(&dscpstatemask
, *argv
, 0))
78 NEXT_ARG_FWD(); /* was a statemask */
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 */
89 if (matches(*argv
, "cpmark") == 0) {
93 if (!get_u32(&cpmarkmask
, *argv
, 0))
94 NEXT_ARG_FWD(); /* was a mask */
102 if (matches(*argv
, "zone") == 0) {
104 if (get_u16(&zone
, *argv
, 10)) {
105 fprintf(stderr
, "ctinfo: Illegal \"zone\"\n");
112 parse_action_control_dflt(&argc
, &argv
, &sel
.action
,
116 if (matches(*argv
, "index") == 0) {
118 if (get_u32(&sel
.index
, *argv
, 10)) {
119 fprintf(stderr
, "ctinfo: Illegal \"index\"\n");
126 if (dscpmask
& dscpstatemask
) {
128 "ctinfo: dscp mask & statemask must NOT overlap\n");
133 if (i
&& ((~0 & (dscpmask
>> (i
- 1))) != 0x3f)) {
135 "ctinfo: dscp mask must be 6 contiguous bits long\n");
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
);
144 addattr32(n
, MAX_MSG
,
145 TCA_CTINFO_PARMS_DSCP_MASK
, dscpmask
);
148 addattr32(n
, MAX_MSG
,
149 TCA_CTINFO_PARMS_DSCP_STATEMASK
, dscpstatemask
);
152 addattr32(n
, MAX_MSG
,
153 TCA_CTINFO_PARMS_CPMARK_MASK
, cpmarkmask
);
155 addattr_nest_end(n
, tail
);
162 static void print_ctinfo_stats(FILE *f
, struct rtattr
*tb
[TCA_CTINFO_MAX
+ 1])
166 if (tb
[TCA_CTINFO_TM
]) {
167 tm
= RTA_DATA(tb
[TCA_CTINFO_TM
]);
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
]));
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
]));
184 static int print_ctinfo(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
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
;
191 print_string(PRINT_ANY
, "kind", "%s ", "ctinfo");
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]");
202 ci
= RTA_DATA(tb
[TCA_CTINFO_ACT
]);
204 if (tb
[TCA_CTINFO_PARMS_DSCP_MASK
]) {
205 if (RTA_PAYLOAD(tb
[TCA_CTINFO_PARMS_DSCP_MASK
]) >=
207 dscpmask
= rta_getattr_u32(
208 tb
[TCA_CTINFO_PARMS_DSCP_MASK
]);
210 print_string(PRINT_FP
, NULL
, "%s",
211 "[invalid dscp mask parameter]");
214 if (tb
[TCA_CTINFO_PARMS_DSCP_STATEMASK
]) {
215 if (RTA_PAYLOAD(tb
[TCA_CTINFO_PARMS_DSCP_STATEMASK
]) >=
217 dscpstatemask
= rta_getattr_u32(
218 tb
[TCA_CTINFO_PARMS_DSCP_STATEMASK
]);
220 print_string(PRINT_FP
, NULL
, "%s",
221 "[invalid dscp statemask parameter]");
224 if (tb
[TCA_CTINFO_PARMS_CPMARK_MASK
]) {
225 if (RTA_PAYLOAD(tb
[TCA_CTINFO_PARMS_CPMARK_MASK
]) >=
227 cpmarkmask
= rta_getattr_u32(
228 tb
[TCA_CTINFO_PARMS_CPMARK_MASK
]);
230 print_string(PRINT_FP
, NULL
, "%s",
231 "[invalid cpmark mask parameter]");
234 if (tb
[TCA_CTINFO_ZONE
] && RTA_PAYLOAD(tb
[TCA_CTINFO_ZONE
]) >=
236 zone
= rta_getattr_u16(tb
[TCA_CTINFO_ZONE
]);
238 print_hu(PRINT_ANY
, "zone", "zone %u", zone
);
239 print_action_control(f
, " ", ci
->action
, "");
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
);
246 if (tb
[TCA_CTINFO_PARMS_DSCP_MASK
]) {
247 print_0xhex(PRINT_ANY
, "dscpmask", " dscp %#010llx", dscpmask
);
248 print_0xhex(PRINT_ANY
, "dscpstatemask", " %#010llx",
252 if (tb
[TCA_CTINFO_PARMS_CPMARK_MASK
])
253 print_0xhex(PRINT_ANY
, "cpmark", " cpmark %#010llx",
257 print_ctinfo_stats(f
, tb
);
264 struct action_util ctinfo_action_util
= {
266 .parse_aopt
= parse_ctinfo
,
267 .print_aopt
= print_ctinfo
,