]>
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 |
087f46ee JHS |
12 | * the simple instance is hit. |
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 \ | |
29 | u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP" | |
30 | ||
31 | hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff: | |
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 | |
35 | match 00010000/00ff0000 at 8 | |
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 | ||
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: | |
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 | |
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: | |
62 | Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0) | |
63 | backlog 0b 0p requeues 0 | |
64 | */ | |
65 | ||
66 | #include <stdio.h> | |
67 | #include <stdlib.h> | |
68 | #include <unistd.h> | |
69 | #include <syslog.h> | |
70 | #include <fcntl.h> | |
71 | #include <sys/socket.h> | |
72 | #include <netinet/in.h> | |
73 | #include <arpa/inet.h> | |
74 | #include <string.h> | |
75 | #include "utils.h" | |
76 | #include "tc_util.h" | |
77 | #include <linux/tc_act/tc_defact.h> | |
78 | ||
79 | #ifndef SIMP_MAX_DATA | |
80 | #define SIMP_MAX_DATA 32 | |
81 | #endif | |
82 | static void explain(void) | |
83 | { | |
84 | fprintf(stderr, "Usage: ... simple STRING\n" | |
85 | "STRING being an arbitrary string\n" | |
86 | "example: \"simple blah\"\n"); | |
87 | } | |
88 | ||
89 | static void usage(void) | |
90 | { | |
91 | explain(); | |
92 | exit(-1); | |
93 | } | |
94 | ||
95 | static int | |
96 | parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, | |
97 | struct nlmsghdr *n) | |
98 | { | |
99 | struct tc_defact sel = {}; | |
100 | int argc = *argc_p; | |
101 | char **argv = *argv_p; | |
102 | int ok = 0; | |
103 | struct rtattr *tail; | |
104 | char *simpdata = NULL; | |
105 | ||
106 | ||
107 | while (argc > 0) { | |
108 | if (matches(*argv, "simple") == 0) { | |
109 | NEXT_ARG(); | |
110 | simpdata = *argv; | |
111 | ok = 1; | |
112 | argc--; | |
113 | argv++; | |
114 | break; | |
115 | } else if (matches(*argv, "help") == 0) { | |
116 | usage(); | |
117 | } else { | |
118 | break; | |
119 | } | |
120 | ||
121 | } | |
122 | ||
123 | if (!ok) { | |
124 | explain(); | |
125 | return -1; | |
126 | } | |
127 | ||
128 | if (argc) { | |
129 | if (matches(*argv, "index") == 0) { | |
130 | NEXT_ARG(); | |
131 | if (get_u32(&sel.index, *argv, 10)) { | |
132 | fprintf(stderr, "simple: Illegal \"index\"\n"); | |
133 | return -1; | |
134 | } | |
135 | argc--; | |
136 | argv++; | |
137 | } | |
138 | } | |
139 | ||
140 | if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { | |
141 | fprintf(stderr, "simple: Illegal string len %ld <%s> \n", | |
142 | strlen(simpdata), simpdata); | |
143 | return -1; | |
144 | } | |
145 | ||
146 | sel.action = TC_ACT_PIPE; | |
147 | ||
148 | tail = NLMSG_TAIL(n); | |
149 | addattr_l(n, MAX_MSG, tca_id, NULL, 0); | |
150 | addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); | |
151 | addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); | |
152 | tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; | |
153 | ||
154 | *argc_p = argc; | |
155 | *argv_p = argv; | |
156 | return 0; | |
157 | } | |
158 | ||
159 | static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) | |
160 | { | |
161 | struct tc_defact *sel; | |
162 | struct rtattr *tb[TCA_DEF_MAX + 1]; | |
163 | char *simpdata; | |
164 | ||
165 | if (arg == NULL) | |
166 | return -1; | |
167 | ||
168 | parse_rtattr_nested(tb, TCA_DEF_MAX, arg); | |
169 | ||
170 | if (tb[TCA_DEF_PARMS] == NULL) { | |
171 | fprintf(f, "[NULL simple parameters]"); | |
172 | return -1; | |
173 | } | |
174 | sel = RTA_DATA(tb[TCA_DEF_PARMS]); | |
175 | ||
176 | if (tb[TCA_DEF_DATA] == NULL) { | |
177 | fprintf(f, "[missing simple string]"); | |
178 | return -1; | |
179 | } | |
180 | ||
181 | simpdata = RTA_DATA(tb[TCA_DEF_DATA]); | |
182 | ||
183 | fprintf(f, "Simple <%s>\n", simpdata); | |
184 | fprintf(f, "\t index %d ref %d bind %d", sel->index, | |
185 | sel->refcnt, sel->bindcnt); | |
186 | ||
187 | if (show_stats) { | |
188 | if (tb[TCA_DEF_TM]) { | |
189 | struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]); | |
190 | print_tm(f, tm); | |
087f46ee JHS |
191 | } |
192 | } | |
352f6f97 | 193 | fprintf(f, "\n"); |
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 | }; |