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