Fix build break in 64bit architectures
[platform/upstream/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_string(PRINT_FP, NULL, "%s", _SL_);
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_string(PRINT_FP, NULL, "%s", _SL_);
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 };