]>
Commit | Line | Data |
---|---|---|
b3a091d1 | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
087f46ee JHS |
2 | /* |
3 | * m_simple.c simple action | |
4 | * | |
087f46ee JHS |
5 | * Authors: J Hadi Salim <jhs@mojatatu.com> |
6 | * | |
b2e116d6 | 7 | * Pedagogical example. Adds a string that will be printed every time |
3d0b7439 | 8 | * the simple instance is hit. |
087f46ee JHS |
9 | * Use this as a skeleton action and keep modifying it to meet your needs. |
10 | * Look at linux/tc_act/tc_defact.h for the different components ids and | |
11 | * definitions used in this actions | |
12 | * | |
13 | * example use, yell "Incoming ICMP!" every time you see an incoming ICMP on | |
14 | * eth0. Steps are: | |
15 | * 1) Add an ingress qdisc point to eth0 | |
16 | * 2) Start a chain on ingress of eth0 that first matches ICMP then invokes | |
17 | * the simple action to shout. | |
18 | * 3) display stats and show that no packet has been seen by the action | |
19 | * 4) Send one ping packet to google (expect to receive a response back) | |
20 | * 5) grep the logs to see the logged message | |
21 | * 6) display stats again and observe increment by 1 | |
22 | * | |
23 | hadi@noma1:$ tc qdisc add dev eth0 ingress | |
24 | hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \ | |
3d0b7439 SH |
25 | u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP" |
26 | ||
087f46ee | 27 | hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff: |
3d0b7439 SH |
28 | filter protocol ip pref 5 u32 |
29 | filter protocol ip pref 5 u32 fh 800: ht divisor 1 | |
30 | filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 | |
087f46ee | 31 | match 00010000/00ff0000 at 8 |
3d0b7439 SH |
32 | action order 1: Simple <Incoming ICMP> |
33 | index 4 ref 1 bind 1 installed 29 sec used 29 sec | |
34 | Action statistics: | |
35 | Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) | |
36 | backlog 0b 0p requeues 0 | |
37 | ||
38 | ||
087f46ee JHS |
39 | hadi@noma1$ ping -c 1 www.google.ca |
40 | PING www.google.ca (74.125.225.120) 56(84) bytes of data. | |
41 | 64 bytes from ord08s08-in-f24.1e100.net (74.125.225.120): icmp_req=1 ttl=53 time=31.3 ms | |
42 | ||
43 | --- www.google.ca ping statistics --- | |
44 | 1 packets transmitted, 1 received, 0% packet loss, time 0ms | |
45 | rtt min/avg/max/mdev = 31.316/31.316/31.316/0.000 ms | |
46 | ||
47 | hadi@noma1$ dmesg | grep simple | |
48 | [135354.473951] simple: Incoming ICMP_1 | |
49 | ||
50 | hadi@noma1$ sudo tc/tc -s filter ls dev eth0 parent ffff: | |
3d0b7439 SH |
51 | filter protocol ip pref 5 u32 |
52 | filter protocol ip pref 5 u32 fh 800: ht divisor 1 | |
53 | filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 | |
087f46ee JHS |
54 | match 00010000/00ff0000 at 8 |
55 | action order 1: Simple <Incoming ICMP> | |
56 | index 4 ref 1 bind 1 installed 206 sec used 67 sec | |
57 | Action statistics: | |
3d0b7439 SH |
58 | Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0) |
59 | backlog 0b 0p requeues 0 | |
087f46ee JHS |
60 | */ |
61 | ||
62 | #include <stdio.h> | |
63 | #include <stdlib.h> | |
64 | #include <unistd.h> | |
087f46ee JHS |
65 | #include <fcntl.h> |
66 | #include <sys/socket.h> | |
67 | #include <netinet/in.h> | |
68 | #include <arpa/inet.h> | |
69 | #include <string.h> | |
70 | #include "utils.h" | |
71 | #include "tc_util.h" | |
72 | #include <linux/tc_act/tc_defact.h> | |
73 | ||
74 | #ifndef SIMP_MAX_DATA | |
75 | #define SIMP_MAX_DATA 32 | |
76 | #endif | |
77 | static void explain(void) | |
78 | { | |
8589eb4e MC |
79 | fprintf(stderr, |
80 | "Usage:... simple [sdata STRING] [index INDEX] [CONTROL]\n" | |
81 | "\tSTRING being an arbitrary string\n" | |
620fc669 SH |
82 | "\tINDEX := optional index value used\n" |
83 | "\tCONTROL := reclassify|pipe|drop|continue|ok\n"); | |
087f46ee JHS |
84 | } |
85 | ||
86 | static void usage(void) | |
87 | { | |
88 | explain(); | |
89 | exit(-1); | |
90 | } | |
91 | ||
92 | static int | |
38b0e6c1 | 93 | parse_simple(const struct action_util *a, int *argc_p, char ***argv_p, int tca_id, |
087f46ee JHS |
94 | struct nlmsghdr *n) |
95 | { | |
96 | struct tc_defact sel = {}; | |
97 | int argc = *argc_p; | |
98 | char **argv = *argv_p; | |
e70b9f16 | 99 | int ok = 0; |
087f46ee JHS |
100 | struct rtattr *tail; |
101 | char *simpdata = NULL; | |
102 | ||
087f46ee JHS |
103 | while (argc > 0) { |
104 | if (matches(*argv, "simple") == 0) { | |
105 | NEXT_ARG(); | |
fdf1bdd0 JHS |
106 | } else if (matches(*argv, "sdata") == 0) { |
107 | NEXT_ARG(); | |
108 | ok += 1; | |
087f46ee | 109 | simpdata = *argv; |
087f46ee JHS |
110 | argc--; |
111 | argv++; | |
087f46ee JHS |
112 | } else if (matches(*argv, "help") == 0) { |
113 | usage(); | |
114 | } else { | |
115 | break; | |
116 | } | |
087f46ee JHS |
117 | } |
118 | ||
0ee4d179 DC |
119 | parse_action_control_dflt(&argc, &argv, &sel.action, false, |
120 | TC_ACT_PIPE); | |
121 | ||
087f46ee JHS |
122 | if (argc) { |
123 | if (matches(*argv, "index") == 0) { | |
124 | NEXT_ARG(); | |
125 | if (get_u32(&sel.index, *argv, 10)) { | |
e70b9f16 | 126 | fprintf(stderr, "simple: Illegal \"index\" (%s)\n", |
fdf1bdd0 | 127 | *argv); |
087f46ee JHS |
128 | return -1; |
129 | } | |
fdf1bdd0 | 130 | ok += 1; |
087f46ee JHS |
131 | argc--; |
132 | argv++; | |
133 | } | |
134 | } | |
135 | ||
fdf1bdd0 JHS |
136 | if (!ok) { |
137 | explain(); | |
138 | return -1; | |
139 | } | |
140 | ||
141 | if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) { | |
32a121cb | 142 | fprintf(stderr, "simple: Illegal string len %zu <%s>\n", |
087f46ee JHS |
143 | strlen(simpdata), simpdata); |
144 | return -1; | |
145 | } | |
146 | ||
c14f9d92 | 147 | tail = addattr_nest(n, MAX_MSG, tca_id); |
087f46ee | 148 | addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); |
fdf1bdd0 JHS |
149 | if (simpdata) |
150 | addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); | |
c14f9d92 | 151 | addattr_nest_end(n, tail); |
087f46ee JHS |
152 | |
153 | *argc_p = argc; | |
154 | *argv_p = argv; | |
155 | return 0; | |
156 | } | |
157 | ||
38b0e6c1 | 158 | static int print_simple(const struct action_util *au, FILE *f, struct rtattr *arg) |
087f46ee JHS |
159 | { |
160 | struct tc_defact *sel; | |
161 | struct rtattr *tb[TCA_DEF_MAX + 1]; | |
162 | char *simpdata; | |
163 | ||
164 | if (arg == NULL) | |
a99ebeee | 165 | return 0; |
087f46ee JHS |
166 | |
167 | parse_rtattr_nested(tb, TCA_DEF_MAX, arg); | |
168 | ||
169 | if (tb[TCA_DEF_PARMS] == NULL) { | |
d5ddb441 | 170 | fprintf(stderr, "Missing simple parameters\n"); |
087f46ee JHS |
171 | return -1; |
172 | } | |
173 | sel = RTA_DATA(tb[TCA_DEF_PARMS]); | |
174 | ||
175 | if (tb[TCA_DEF_DATA] == NULL) { | |
d5ddb441 | 176 | fprintf(stderr, "Missing simple string\n"); |
087f46ee JHS |
177 | return -1; |
178 | } | |
179 | ||
180 | simpdata = RTA_DATA(tb[TCA_DEF_DATA]); | |
181 | ||
182 | fprintf(f, "Simple <%s>\n", simpdata); | |
53075318 | 183 | fprintf(f, "\t index %u ref %d bind %d", sel->index, |
087f46ee JHS |
184 | sel->refcnt, sel->bindcnt); |
185 | ||
186 | if (show_stats) { | |
187 | if (tb[TCA_DEF_TM]) { | |
188 | struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]); | |
32a121cb | 189 | |
087f46ee | 190 | print_tm(f, tm); |
087f46ee JHS |
191 | } |
192 | } | |
7b0d424a | 193 | print_nl(); |
087f46ee JHS |
194 | |
195 | return 0; | |
196 | } | |
197 | ||
198 | struct action_util simple_action_util = { | |
199 | .id = "simple", | |
200 | .parse_aopt = parse_simple, | |
201 | .print_aopt = print_simple, | |
202 | }; |