Imported Upstream version 5.5.0
[platform/upstream/iproute2.git] / tc / m_sample.c
1 /*
2  * m_sample.c           ingress/egress packet sampling module
3  *
4  *              This program is free software; you can distribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Yotam Gigi <yotamg@mellanox.com>
10  *
11  */
12
13 #include <stdio.h>
14 #include "utils.h"
15 #include "tc_util.h"
16 #include "tc_common.h"
17 #include <linux/tc_act/tc_sample.h>
18
19 static void explain(void)
20 {
21         fprintf(stderr,
22                 "Usage: sample SAMPLE_CONF\n"
23                 "where:\n"
24                 "\tSAMPLE_CONF := SAMPLE_PARAMS | SAMPLE_INDEX\n"
25                 "\tSAMPLE_PARAMS := rate RATE group GROUP [trunc SIZE] [SAMPLE_INDEX]\n"
26                 "\tSAMPLE_INDEX := index INDEX\n"
27                 "\tRATE := The ratio of packets observed at the data source to the samples generated.\n"
28                 "\tGROUP := the psample sampling group\n"
29                 "\tSIZE := the truncation size\n"
30                 "\tINDEX := integer index of the sample action\n");
31 }
32
33 static void usage(void)
34 {
35         explain();
36         exit(-1);
37 }
38
39 static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
40                         int tca_id, struct nlmsghdr *n)
41 {
42         struct tc_sample p = { 0 };
43         bool trunc_set = false;
44         bool group_set = false;
45         bool rate_set = false;
46         char **argv = *argv_p;
47         struct rtattr *tail;
48         int argc = *argc_p;
49         __u32 trunc;
50         __u32 group;
51         __u32 rate;
52
53         if (argc <= 1) {
54                 fprintf(stderr, "sample bad argument count %d\n", argc);
55                 usage();
56                 return -1;
57         }
58
59         if (matches(*argv, "sample") == 0) {
60                 NEXT_ARG();
61         } else {
62                 fprintf(stderr, "sample bad argument %s\n", *argv);
63                 return -1;
64         }
65
66         while (argc > 0) {
67                 if (matches(*argv, "rate") == 0) {
68                         NEXT_ARG();
69                         if (get_u32(&rate, *argv, 10) != 0) {
70                                 fprintf(stderr, "Illegal rate %s\n", *argv);
71                                 usage();
72                                 return -1;
73                         }
74                         rate_set = true;
75                 } else if (matches(*argv, "group") == 0) {
76                         NEXT_ARG();
77                         if (get_u32(&group, *argv, 10) != 0) {
78                                 fprintf(stderr, "Illegal group num %s\n",
79                                         *argv);
80                                 usage();
81                                 return -1;
82                         }
83                         group_set = true;
84                 } else if (matches(*argv, "trunc") == 0) {
85                         NEXT_ARG();
86                         if (get_u32(&trunc, *argv, 10) != 0) {
87                                 fprintf(stderr, "Illegal truncation size %s\n",
88                                         *argv);
89                                 usage();
90                                 return -1;
91                         }
92                         trunc_set = true;
93                 } else if (matches(*argv, "help") == 0) {
94                         usage();
95                 } else {
96                         break;
97                 }
98
99                 NEXT_ARG_FWD();
100         }
101
102         parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
103
104         if (argc) {
105                 if (matches(*argv, "index") == 0) {
106                         NEXT_ARG();
107                         if (get_u32(&p.index, *argv, 10)) {
108                                 fprintf(stderr, "sample: Illegal \"index\"\n");
109                                 return -1;
110                         }
111                         NEXT_ARG_FWD();
112                 }
113         }
114
115         if (!p.index && !group_set) {
116                 fprintf(stderr, "param \"group\" not set\n");
117                 usage();
118         }
119
120         if (!p.index && !rate_set) {
121                 fprintf(stderr, "param \"rate\" not set\n");
122                 usage();
123         }
124
125         tail = addattr_nest(n, MAX_MSG, tca_id);
126         addattr_l(n, MAX_MSG, TCA_SAMPLE_PARMS, &p, sizeof(p));
127         if (rate_set)
128                 addattr32(n, MAX_MSG, TCA_SAMPLE_RATE, rate);
129         if (group_set)
130                 addattr32(n, MAX_MSG, TCA_SAMPLE_PSAMPLE_GROUP, group);
131         if (trunc_set)
132                 addattr32(n, MAX_MSG, TCA_SAMPLE_TRUNC_SIZE, trunc);
133
134         addattr_nest_end(n, tail);
135
136         *argc_p = argc;
137         *argv_p = argv;
138         return 0;
139 }
140
141 static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg)
142 {
143         struct rtattr *tb[TCA_SAMPLE_MAX + 1];
144         struct tc_sample *p;
145
146         if (arg == NULL)
147                 return -1;
148
149         parse_rtattr_nested(tb, TCA_SAMPLE_MAX, arg);
150
151         if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
152             !tb[TCA_SAMPLE_PSAMPLE_GROUP]) {
153                 fprintf(stderr, "Missing sample parameters\n");
154                 return -1;
155         }
156         p = RTA_DATA(tb[TCA_SAMPLE_PARMS]);
157
158         print_string(PRINT_ANY, "kind", "%s ", "sample");
159         print_uint(PRINT_ANY, "rate", "rate 1/%u ",
160                    rta_getattr_u32(tb[TCA_SAMPLE_RATE]));
161         print_uint(PRINT_ANY, "group", "group %u",
162                    rta_getattr_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]));
163
164         if (tb[TCA_SAMPLE_TRUNC_SIZE])
165                 print_uint(PRINT_ANY, "trunc_size", " trunc_size %u",
166                            rta_getattr_u32(tb[TCA_SAMPLE_TRUNC_SIZE]));
167
168         print_action_control(f, " ", p->action, "");
169
170         print_string(PRINT_FP, NULL, "%s", _SL_);
171         print_uint(PRINT_ANY, "index", "\t index %u", p->index);
172         print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
173         print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
174
175         if (show_stats) {
176                 if (tb[TCA_SAMPLE_TM]) {
177                         struct tcf_t *tm = RTA_DATA(tb[TCA_SAMPLE_TM]);
178
179                         print_tm(f, tm);
180                 }
181         }
182         print_string(PRINT_FP, NULL, "%s", _SL_);
183         return 0;
184 }
185
186 struct action_util sample_action_util = {
187         .id = "sample",
188         .parse_aopt = parse_sample,
189         .print_aopt = print_sample,
190 };