]>
Commit | Line | Data |
---|---|---|
942bf97b | 1 | /* Zebra Policy Based Routing (PBR) main handling. |
2 | * Copyright (C) 2018 Cumulus Networks, Inc. | |
3 | * | |
4 | * This file is part of FRR. | |
5 | * | |
6 | * FRR is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * FRR is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with FRR; see the file COPYING. If not, write to the Free | |
18 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | * 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | ||
43fe6a2a DS |
24 | #include <jhash.h> |
25 | #include <hash.h> | |
f80ec7e3 | 26 | #include <memory.h> |
73a829f7 | 27 | #include <hook.h> |
43fe6a2a | 28 | |
942bf97b | 29 | #include "zebra/zebra_pbr.h" |
30 | #include "zebra/rt.h" | |
bf094f69 | 31 | #include "zebra/zapi_msg.h" |
f80ec7e3 | 32 | #include "zebra/zebra_memory.h" |
c0ea1ae7 | 33 | #include "zebra/zserv.h" |
f80ec7e3 PG |
34 | |
35 | /* definitions */ | |
36 | DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list") | |
942bf97b | 37 | |
38 | /* definitions */ | |
586f4ccf PG |
39 | static const struct message ipset_type_msg[] = { |
40 | {IPSET_NET_PORT_NET, "net,port,net"}, | |
41 | {IPSET_NET_PORT, "net,port"}, | |
42 | {IPSET_NET_NET, "net,net"}, | |
43 | {IPSET_NET, "net"}, | |
44 | {0} | |
45 | }; | |
942bf97b | 46 | |
be729dd7 PG |
47 | const struct message icmp_typecode_str[] = { |
48 | { 0 << 8, "echo-reply"}, | |
49 | { 0 << 8, "pong"}, | |
50 | { 3 << 8, "network-unreachable"}, | |
51 | { (3 << 8) + 1, "host-unreachable"}, | |
52 | { (3 << 8) + 2, "protocol-unreachable"}, | |
53 | { (3 << 8) + 3, "port-unreachable"}, | |
54 | { (3 << 8) + 4, "fragmentation-needed"}, | |
55 | { (3 << 8) + 5, "source-route-failed"}, | |
56 | { (3 << 8) + 6, "network-unknown"}, | |
57 | { (3 << 8) + 7, "host-unknown"}, | |
58 | { (3 << 8) + 9, "network-prohibited"}, | |
59 | { (3 << 8) + 10, "host-prohibited"}, | |
60 | { (3 << 8) + 11, "TOS-network-unreachable"}, | |
61 | { (3 << 8) + 12, "TOS-host-unreachable"}, | |
62 | { (3 << 8) + 13, "communication-prohibited"}, | |
63 | { (3 << 8) + 14, "host-precedence-violation"}, | |
64 | { (3 << 8) + 15, "precedence-cutoff"}, | |
65 | { 4 << 8, "source-quench"}, | |
66 | { 5 << 8, "network-redirect"}, | |
67 | { (5 << 8) + 1, "host-redirect"}, | |
68 | { (5 << 8) + 2, "TOS-network-redirect"}, | |
69 | { (5 << 8) + 3, "TOS-host-redirect"}, | |
70 | { 8 << 8, "echo-request"}, | |
71 | { 8 << 8, "ping"}, | |
72 | { 9 << 8, "router-advertisement"}, | |
73 | { 10 << 8, "router-solicitation"}, | |
74 | { 11 << 8, "ttl-zero-during-transit"}, | |
75 | { (11 << 8) + 1, "ttl-zero-during-reassembly"}, | |
76 | { 12 << 8, "ip-header-bad"}, | |
77 | { (12 << 8) + 1, "required-option-missing"}, | |
78 | { 13 << 8, "timestamp-request"}, | |
79 | { 14 << 8, "timestamp-reply"}, | |
80 | { 17 << 8, "address-mask-request"}, | |
81 | { 18 << 8, "address-mask-reply"}, | |
82 | {0} | |
83 | }; | |
84 | ||
dc993e76 PG |
85 | /* definitions */ |
86 | static const struct message tcp_value_str[] = { | |
87 | {TCP_HEADER_FIN, "FIN"}, | |
88 | {TCP_HEADER_SYN, "SYN"}, | |
89 | {TCP_HEADER_RST, "RST"}, | |
90 | {TCP_HEADER_PSH, "PSH"}, | |
91 | {TCP_HEADER_ACK, "ACK"}, | |
92 | {TCP_HEADER_URG, "URG"}, | |
93 | {0} | |
94 | }; | |
95 | ||
942bf97b | 96 | /* static function declarations */ |
73a829f7 PG |
97 | DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns, |
98 | struct zebra_pbr_ipset_entry *ipset, | |
99 | uint64_t *pkts, uint64_t *bytes), | |
100 | (zns, ipset, pkts, bytes)) | |
101 | ||
102 | DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns, | |
103 | struct zebra_pbr_iptable *iptable, | |
104 | uint64_t *pkts, uint64_t *bytes), | |
105 | (zns, iptable, pkts, bytes)) | |
106 | ||
107 | DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns, | |
108 | int cmd, | |
109 | struct zebra_pbr_iptable *iptable), | |
110 | (zns, cmd, iptable)); | |
111 | ||
112 | DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns, | |
113 | int cmd, | |
114 | struct zebra_pbr_ipset_entry *ipset), | |
115 | (zns, cmd, ipset)); | |
116 | ||
117 | DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns, | |
118 | int cmd, | |
119 | struct zebra_pbr_ipset *ipset), | |
120 | (zns, cmd, ipset)); | |
942bf97b | 121 | |
122 | /* Private functions */ | |
123 | ||
124 | /* Public functions */ | |
43fe6a2a | 125 | void zebra_pbr_rules_free(void *arg) |
1fbfe5a5 | 126 | { |
43fe6a2a DS |
127 | struct zebra_pbr_rule *rule; |
128 | ||
129 | rule = (struct zebra_pbr_rule *)arg; | |
130 | ||
ebecd649 | 131 | (void)kernel_del_pbr_rule(rule); |
43fe6a2a DS |
132 | XFREE(MTYPE_TMP, rule); |
133 | } | |
134 | ||
135 | uint32_t zebra_pbr_rules_hash_key(void *arg) | |
136 | { | |
137 | struct zebra_pbr_rule *rule; | |
138 | uint32_t key; | |
139 | ||
140 | rule = (struct zebra_pbr_rule *)arg; | |
5dd0722d PG |
141 | key = jhash_3words(rule->rule.seq, rule->rule.priority, |
142 | rule->rule.action.table, | |
143 | prefix_hash_key(&rule->rule.filter.src_ip)); | |
a0321978 DS |
144 | if (rule->ifp) |
145 | key = jhash_1word(rule->ifp->ifindex, key); | |
146 | else | |
147 | key = jhash_1word(0, key); | |
148 | ||
5dd0722d PG |
149 | if (rule->rule.filter.fwmark) |
150 | key = jhash_1word(rule->rule.filter.fwmark, key); | |
1907e4b8 PG |
151 | else |
152 | key = jhash_1word(0, key); | |
5dd0722d PG |
153 | return jhash_3words(rule->rule.filter.src_port, |
154 | rule->rule.filter.dst_port, | |
155 | prefix_hash_key(&rule->rule.filter.dst_ip), | |
156 | jhash_1word(rule->rule.unique, key)); | |
43fe6a2a DS |
157 | } |
158 | ||
159 | int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) | |
160 | { | |
161 | const struct zebra_pbr_rule *r1, *r2; | |
162 | ||
163 | r1 = (const struct zebra_pbr_rule *)arg1; | |
164 | r2 = (const struct zebra_pbr_rule *)arg2; | |
165 | ||
5dd0722d | 166 | if (r1->rule.seq != r2->rule.seq) |
43fe6a2a DS |
167 | return 0; |
168 | ||
5dd0722d | 169 | if (r1->rule.priority != r2->rule.priority) |
43fe6a2a DS |
170 | return 0; |
171 | ||
5dd0722d | 172 | if (r1->rule.unique != r2->rule.unique) |
b6c5d343 DS |
173 | return 0; |
174 | ||
5dd0722d | 175 | if (r1->rule.action.table != r2->rule.action.table) |
43fe6a2a DS |
176 | return 0; |
177 | ||
5dd0722d | 178 | if (r1->rule.filter.src_port != r2->rule.filter.src_port) |
43fe6a2a DS |
179 | return 0; |
180 | ||
5dd0722d | 181 | if (r1->rule.filter.dst_port != r2->rule.filter.dst_port) |
43fe6a2a DS |
182 | return 0; |
183 | ||
5dd0722d | 184 | if (r1->rule.filter.fwmark != r2->rule.filter.fwmark) |
1907e4b8 PG |
185 | return 0; |
186 | ||
5dd0722d | 187 | if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip)) |
43fe6a2a DS |
188 | return 0; |
189 | ||
5dd0722d | 190 | if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) |
43fe6a2a DS |
191 | return 0; |
192 | ||
a0321978 DS |
193 | if (r1->ifp != r2->ifp) |
194 | return 0; | |
195 | ||
43fe6a2a DS |
196 | return 1; |
197 | } | |
198 | ||
f46bbab4 | 199 | struct pbr_rule_unique_lookup { |
8c3cd6c6 DS |
200 | struct zebra_pbr_rule *rule; |
201 | uint32_t unique; | |
37c606ff | 202 | struct interface *ifp; |
8c3cd6c6 DS |
203 | }; |
204 | ||
205 | static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) | |
206 | { | |
f46bbab4 | 207 | struct pbr_rule_unique_lookup *pul = data; |
8c3cd6c6 DS |
208 | struct zebra_pbr_rule *rule = b->data; |
209 | ||
37c606ff | 210 | if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) { |
8c3cd6c6 DS |
211 | pul->rule = rule; |
212 | return HASHWALK_ABORT; | |
213 | } | |
214 | ||
215 | return HASHWALK_CONTINUE; | |
216 | } | |
217 | ||
218 | static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns, | |
37c606ff DS |
219 | uint32_t unique, |
220 | struct interface *ifp) | |
8c3cd6c6 | 221 | { |
f46bbab4 | 222 | struct pbr_rule_unique_lookup pul; |
8c3cd6c6 DS |
223 | |
224 | pul.unique = unique; | |
37c606ff | 225 | pul.ifp = ifp; |
8c3cd6c6 DS |
226 | pul.rule = NULL; |
227 | hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul); | |
228 | ||
229 | return pul.rule; | |
230 | } | |
231 | ||
7661461a PG |
232 | void zebra_pbr_ipset_free(void *arg) |
233 | { | |
234 | struct zebra_pbr_ipset *ipset; | |
73a829f7 | 235 | struct zebra_ns *zns; |
7661461a PG |
236 | |
237 | ipset = (struct zebra_pbr_ipset *)arg; | |
73a829f7 PG |
238 | if (vrf_is_backend_netns()) |
239 | zns = zebra_ns_lookup(ipset->vrf_id); | |
240 | else | |
241 | zns = zebra_ns_lookup(NS_DEFAULT); | |
242 | hook_call(zebra_pbr_ipset_wrap_script_update, | |
243 | zns, 0, ipset); | |
7661461a PG |
244 | XFREE(MTYPE_TMP, ipset); |
245 | } | |
246 | ||
247 | uint32_t zebra_pbr_ipset_hash_key(void *arg) | |
248 | { | |
249 | struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg; | |
425bdd6b | 250 | uint32_t *pnt = (uint32_t *)&ipset->ipset_name; |
7661461a | 251 | |
425bdd6b | 252 | return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de); |
7661461a PG |
253 | } |
254 | ||
255 | int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) | |
256 | { | |
257 | const struct zebra_pbr_ipset *r1, *r2; | |
258 | ||
259 | r1 = (const struct zebra_pbr_ipset *)arg1; | |
260 | r2 = (const struct zebra_pbr_ipset *)arg2; | |
261 | ||
262 | if (r1->type != r2->type) | |
263 | return 0; | |
264 | if (r1->unique != r2->unique) | |
265 | return 0; | |
266 | if (strncmp(r1->ipset_name, r2->ipset_name, | |
267 | ZEBRA_IPSET_NAME_SIZE)) | |
268 | return 0; | |
269 | return 1; | |
270 | } | |
271 | ||
272 | void zebra_pbr_ipset_entry_free(void *arg) | |
273 | { | |
274 | struct zebra_pbr_ipset_entry *ipset; | |
73a829f7 | 275 | struct zebra_ns *zns; |
7661461a PG |
276 | |
277 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
73a829f7 PG |
278 | if (ipset->backpointer && vrf_is_backend_netns()) { |
279 | struct zebra_pbr_ipset *ips = ipset->backpointer; | |
280 | ||
281 | zns = zebra_ns_lookup((ns_id_t)ips->vrf_id); | |
282 | } else | |
283 | zns = zebra_ns_lookup(NS_DEFAULT); | |
284 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, | |
285 | zns, 0, ipset); | |
7661461a PG |
286 | |
287 | XFREE(MTYPE_TMP, ipset); | |
288 | } | |
289 | ||
290 | uint32_t zebra_pbr_ipset_entry_hash_key(void *arg) | |
291 | { | |
292 | struct zebra_pbr_ipset_entry *ipset; | |
293 | uint32_t key; | |
294 | ||
295 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
296 | key = prefix_hash_key(&ipset->src); | |
297 | key = jhash_1word(ipset->unique, key); | |
298 | key = jhash_1word(prefix_hash_key(&ipset->dst), key); | |
25d760c5 PG |
299 | key = jhash(&ipset->dst_port_min, 2, key); |
300 | key = jhash(&ipset->dst_port_max, 2, key); | |
301 | key = jhash(&ipset->src_port_min, 2, key); | |
302 | key = jhash(&ipset->src_port_max, 2, key); | |
303 | key = jhash(&ipset->proto, 1, key); | |
7661461a PG |
304 | |
305 | return key; | |
306 | } | |
307 | ||
308 | int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) | |
309 | { | |
310 | const struct zebra_pbr_ipset_entry *r1, *r2; | |
311 | ||
312 | r1 = (const struct zebra_pbr_ipset_entry *)arg1; | |
313 | r2 = (const struct zebra_pbr_ipset_entry *)arg2; | |
314 | ||
315 | if (r1->unique != r2->unique) | |
316 | return 0; | |
317 | ||
318 | if (!prefix_same(&r1->src, &r2->src)) | |
319 | return 0; | |
320 | ||
321 | if (!prefix_same(&r1->dst, &r2->dst)) | |
322 | return 0; | |
323 | ||
25d760c5 PG |
324 | if (r1->src_port_min != r2->src_port_min) |
325 | return 0; | |
326 | ||
327 | if (r1->src_port_max != r2->src_port_max) | |
328 | return 0; | |
329 | ||
330 | if (r1->dst_port_min != r2->dst_port_min) | |
331 | return 0; | |
332 | ||
333 | if (r1->dst_port_max != r2->dst_port_max) | |
334 | return 0; | |
335 | ||
336 | if (r1->proto != r2->proto) | |
337 | return 0; | |
7661461a PG |
338 | return 1; |
339 | } | |
340 | ||
7abd6c4f PG |
341 | void zebra_pbr_iptable_free(void *arg) |
342 | { | |
343 | struct zebra_pbr_iptable *iptable; | |
f80ec7e3 PG |
344 | struct listnode *node, *nnode; |
345 | char *name; | |
73a829f7 | 346 | struct zebra_ns *zns; |
7abd6c4f PG |
347 | |
348 | iptable = (struct zebra_pbr_iptable *)arg; | |
73a829f7 PG |
349 | if (vrf_is_backend_netns()) |
350 | zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id); | |
351 | else | |
352 | zns = zebra_ns_lookup(NS_DEFAULT); | |
353 | hook_call(zebra_pbr_iptable_wrap_script_update, | |
354 | zns, 0, iptable); | |
7abd6c4f | 355 | |
f80ec7e3 PG |
356 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, |
357 | node, nnode, name)) { | |
358 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
359 | list_delete_node(iptable->interface_name_list, | |
360 | node); | |
361 | } | |
7abd6c4f PG |
362 | XFREE(MTYPE_TMP, iptable); |
363 | } | |
364 | ||
365 | uint32_t zebra_pbr_iptable_hash_key(void *arg) | |
366 | { | |
367 | struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg; | |
368 | uint32_t *pnt = (uint32_t *)&(iptable->ipset_name); | |
369 | uint32_t key; | |
370 | ||
371 | key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, | |
372 | 0x63ab42de); | |
373 | key = jhash_1word(iptable->fwmark, key); | |
e7f7dad4 PG |
374 | key = jhash_1word(iptable->pkt_len_min, key); |
375 | key = jhash_1word(iptable->pkt_len_max, key); | |
dc993e76 PG |
376 | key = jhash_1word(iptable->tcp_flags, key); |
377 | key = jhash_1word(iptable->tcp_mask_flags, key); | |
7abd6c4f PG |
378 | return jhash_3words(iptable->filter_bm, iptable->type, |
379 | iptable->unique, key); | |
380 | } | |
381 | ||
382 | int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) | |
383 | { | |
384 | const struct zebra_pbr_iptable *r1, *r2; | |
385 | ||
386 | r1 = (const struct zebra_pbr_iptable *)arg1; | |
387 | r2 = (const struct zebra_pbr_iptable *)arg2; | |
388 | ||
389 | if (r1->type != r2->type) | |
390 | return 0; | |
391 | if (r1->unique != r2->unique) | |
392 | return 0; | |
393 | if (r1->filter_bm != r2->filter_bm) | |
394 | return 0; | |
395 | if (r1->fwmark != r2->fwmark) | |
396 | return 0; | |
397 | if (r1->action != r2->action) | |
398 | return 0; | |
399 | if (strncmp(r1->ipset_name, r2->ipset_name, | |
400 | ZEBRA_IPSET_NAME_SIZE)) | |
401 | return 0; | |
e7f7dad4 PG |
402 | if (r1->pkt_len_min != r2->pkt_len_min) |
403 | return 0; | |
404 | if (r1->pkt_len_max != r2->pkt_len_max) | |
405 | return 0; | |
dc993e76 PG |
406 | if (r1->tcp_flags != r2->tcp_flags) |
407 | return 0; | |
408 | if (r1->tcp_mask_flags != r2->tcp_mask_flags) | |
409 | return 0; | |
7abd6c4f PG |
410 | return 1; |
411 | } | |
412 | ||
43fe6a2a DS |
413 | static void *pbr_rule_alloc_intern(void *arg) |
414 | { | |
415 | struct zebra_pbr_rule *zpr; | |
416 | struct zebra_pbr_rule *new; | |
417 | ||
418 | zpr = (struct zebra_pbr_rule *)arg; | |
419 | ||
420 | new = XCALLOC(MTYPE_TMP, sizeof(*new)); | |
421 | ||
422 | memcpy(new, zpr, sizeof(*zpr)); | |
423 | ||
424 | return new; | |
425 | } | |
426 | ||
a0321978 | 427 | void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
43fe6a2a | 428 | { |
8c3cd6c6 | 429 | struct zebra_pbr_rule *unique = |
37c606ff | 430 | pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp); |
8c3cd6c6 | 431 | |
43fe6a2a | 432 | (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern); |
ebecd649 | 433 | (void)kernel_add_pbr_rule(rule); |
8c3cd6c6 DS |
434 | /* |
435 | * Rule Replace semantics, if we have an old, install the | |
436 | * new rule, look above, and then delete the old | |
437 | */ | |
438 | if (unique) | |
439 | zebra_pbr_del_rule(zns, unique); | |
1fbfe5a5 DS |
440 | } |
441 | ||
a0321978 | 442 | void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
1fbfe5a5 | 443 | { |
43fe6a2a DS |
444 | struct zebra_pbr_rule *lookup; |
445 | ||
446 | lookup = hash_lookup(zns->rules_hash, rule); | |
ebecd649 | 447 | (void)kernel_del_pbr_rule(rule); |
43fe6a2a | 448 | |
d5c52f76 DS |
449 | if (lookup) { |
450 | hash_release(zns->rules_hash, lookup); | |
43fe6a2a | 451 | XFREE(MTYPE_TMP, lookup); |
d5c52f76 | 452 | } else |
43fe6a2a DS |
453 | zlog_warn("%s: Rule being deleted we know nothing about", |
454 | __PRETTY_FUNCTION__); | |
1fbfe5a5 DS |
455 | } |
456 | ||
e69aa084 DS |
457 | static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) |
458 | { | |
459 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
460 | struct zebra_pbr_rule *rule = b->data; | |
461 | int *sock = data; | |
462 | ||
463 | if (rule->sock == *sock) { | |
ebecd649 | 464 | (void)kernel_del_pbr_rule(rule); |
e69aa084 | 465 | hash_release(zns->rules_hash, rule); |
d5c52f76 | 466 | XFREE(MTYPE_TMP, rule); |
e69aa084 DS |
467 | } |
468 | } | |
469 | ||
c2ef5232 PG |
470 | static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) |
471 | { | |
472 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
473 | struct zebra_pbr_ipset *ipset = b->data; | |
474 | int *sock = data; | |
475 | ||
73a829f7 PG |
476 | if (ipset->sock == *sock) { |
477 | hook_call(zebra_pbr_ipset_wrap_script_update, | |
478 | zns, 0, ipset); | |
c2ef5232 | 479 | hash_release(zns->ipset_hash, ipset); |
73a829f7 | 480 | } |
c2ef5232 PG |
481 | } |
482 | ||
483 | static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) | |
484 | { | |
485 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
486 | struct zebra_pbr_ipset_entry *ipset = b->data; | |
487 | int *sock = data; | |
488 | ||
73a829f7 PG |
489 | if (ipset->sock == *sock) { |
490 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, | |
491 | zns, 0, ipset); | |
c2ef5232 | 492 | hash_release(zns->ipset_entry_hash, ipset); |
73a829f7 | 493 | } |
c2ef5232 PG |
494 | } |
495 | ||
496 | static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) | |
497 | { | |
498 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
499 | struct zebra_pbr_iptable *iptable = b->data; | |
500 | int *sock = data; | |
501 | ||
73a829f7 PG |
502 | if (iptable->sock == *sock) { |
503 | hook_call(zebra_pbr_iptable_wrap_script_update, | |
504 | zns, 0, iptable); | |
c2ef5232 | 505 | hash_release(zns->iptable_hash, iptable); |
73a829f7 | 506 | } |
c2ef5232 PG |
507 | } |
508 | ||
4c0ec639 | 509 | static int zebra_pbr_client_close_cleanup(struct zserv *client) |
e69aa084 | 510 | { |
4c0ec639 | 511 | int sock = client->sock; |
e69aa084 DS |
512 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); |
513 | ||
4c0ec639 PG |
514 | if (!sock) |
515 | return 0; | |
e69aa084 | 516 | hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock); |
c2ef5232 PG |
517 | hash_iterate(zns->iptable_hash, |
518 | zebra_pbr_cleanup_iptable, &sock); | |
519 | hash_iterate(zns->ipset_entry_hash, | |
520 | zebra_pbr_cleanup_ipset_entry, &sock); | |
521 | hash_iterate(zns->ipset_hash, | |
522 | zebra_pbr_cleanup_ipset, &sock); | |
4c0ec639 PG |
523 | return 1; |
524 | } | |
525 | ||
526 | void zebra_pbr_init(void) | |
527 | { | |
c0ea1ae7 | 528 | hook_register(zserv_client_close, zebra_pbr_client_close_cleanup); |
e69aa084 DS |
529 | } |
530 | ||
7661461a PG |
531 | static void *pbr_ipset_alloc_intern(void *arg) |
532 | { | |
533 | struct zebra_pbr_ipset *zpi; | |
534 | struct zebra_pbr_ipset *new; | |
535 | ||
536 | zpi = (struct zebra_pbr_ipset *)arg; | |
537 | ||
538 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset)); | |
539 | ||
540 | memcpy(new, zpi, sizeof(*zpi)); | |
541 | ||
542 | return new; | |
543 | } | |
544 | ||
545 | void zebra_pbr_create_ipset(struct zebra_ns *zns, | |
546 | struct zebra_pbr_ipset *ipset) | |
547 | { | |
73a829f7 PG |
548 | int ret; |
549 | ||
7661461a | 550 | (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern); |
73a829f7 PG |
551 | ret = hook_call(zebra_pbr_ipset_wrap_script_update, |
552 | zns, 1, ipset); | |
553 | kernel_pbr_ipset_add_del_status(ipset, | |
215181cb DS |
554 | ret ? DP_INSTALL_SUCCESS |
555 | : DP_INSTALL_FAILURE); | |
7661461a PG |
556 | } |
557 | ||
558 | void zebra_pbr_destroy_ipset(struct zebra_ns *zns, | |
559 | struct zebra_pbr_ipset *ipset) | |
560 | { | |
561 | struct zebra_pbr_ipset *lookup; | |
562 | ||
563 | lookup = hash_lookup(zns->ipset_hash, ipset); | |
73a829f7 PG |
564 | hook_call(zebra_pbr_ipset_wrap_script_update, |
565 | zns, 0, ipset); | |
de67547d PG |
566 | if (lookup) { |
567 | hash_release(zns->ipset_hash, lookup); | |
7661461a | 568 | XFREE(MTYPE_TMP, lookup); |
de67547d | 569 | } else |
425bdd6b | 570 | zlog_warn("%s: IPSet Entry being deleted we know nothing about", |
7661461a PG |
571 | __PRETTY_FUNCTION__); |
572 | } | |
573 | ||
ed78b7c8 PG |
574 | struct pbr_ipset_name_lookup { |
575 | struct zebra_pbr_ipset *ipset; | |
576 | char ipset_name[ZEBRA_IPSET_NAME_SIZE]; | |
577 | }; | |
578 | ||
5b0d92b8 | 579 | const char *zebra_pbr_ipset_type2str(uint32_t type) |
586f4ccf PG |
580 | { |
581 | return lookup_msg(ipset_type_msg, type, | |
582 | "Unrecognized IPset Type"); | |
583 | } | |
584 | ||
ed78b7c8 PG |
585 | static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) |
586 | { | |
587 | struct pbr_ipset_name_lookup *pinl = | |
588 | (struct pbr_ipset_name_lookup *)arg; | |
589 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
590 | ||
591 | if (!strncmp(pinl->ipset_name, zpi->ipset_name, | |
592 | ZEBRA_IPSET_NAME_SIZE)) { | |
593 | pinl->ipset = zpi; | |
594 | return HASHWALK_ABORT; | |
595 | } | |
596 | return HASHWALK_CONTINUE; | |
597 | } | |
598 | ||
d59c13af PG |
599 | struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns, |
600 | char *ipsetname) | |
601 | { | |
ed78b7c8 PG |
602 | struct pbr_ipset_name_lookup pinl; |
603 | struct pbr_ipset_name_lookup *ptr = &pinl; | |
604 | ||
d59c13af PG |
605 | if (!ipsetname) |
606 | return NULL; | |
ed78b7c8 PG |
607 | memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup)); |
608 | snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s", | |
609 | ipsetname); | |
610 | hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr); | |
611 | return ptr->ipset; | |
d59c13af PG |
612 | } |
613 | ||
7661461a PG |
614 | static void *pbr_ipset_entry_alloc_intern(void *arg) |
615 | { | |
616 | struct zebra_pbr_ipset_entry *zpi; | |
617 | struct zebra_pbr_ipset_entry *new; | |
618 | ||
619 | zpi = (struct zebra_pbr_ipset_entry *)arg; | |
620 | ||
621 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry)); | |
622 | ||
623 | memcpy(new, zpi, sizeof(*zpi)); | |
624 | ||
625 | return new; | |
626 | } | |
627 | ||
628 | void zebra_pbr_add_ipset_entry(struct zebra_ns *zns, | |
629 | struct zebra_pbr_ipset_entry *ipset) | |
630 | { | |
73a829f7 PG |
631 | int ret; |
632 | ||
7661461a PG |
633 | (void)hash_get(zns->ipset_entry_hash, ipset, |
634 | pbr_ipset_entry_alloc_intern); | |
73a829f7 PG |
635 | ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update, |
636 | zns, 1, ipset); | |
637 | kernel_pbr_ipset_entry_add_del_status(ipset, | |
215181cb DS |
638 | ret ? DP_INSTALL_SUCCESS |
639 | : DP_INSTALL_FAILURE); | |
7661461a PG |
640 | } |
641 | ||
642 | void zebra_pbr_del_ipset_entry(struct zebra_ns *zns, | |
643 | struct zebra_pbr_ipset_entry *ipset) | |
644 | { | |
645 | struct zebra_pbr_ipset_entry *lookup; | |
646 | ||
425bdd6b | 647 | lookup = hash_lookup(zns->ipset_entry_hash, ipset); |
73a829f7 PG |
648 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, |
649 | zns, 0, ipset); | |
de67547d PG |
650 | if (lookup) { |
651 | hash_release(zns->ipset_entry_hash, lookup); | |
7661461a | 652 | XFREE(MTYPE_TMP, lookup); |
de67547d | 653 | } else |
7661461a PG |
654 | zlog_warn("%s: IPSet being deleted we know nothing about", |
655 | __PRETTY_FUNCTION__); | |
656 | } | |
657 | ||
7abd6c4f PG |
658 | static void *pbr_iptable_alloc_intern(void *arg) |
659 | { | |
660 | struct zebra_pbr_iptable *zpi; | |
661 | struct zebra_pbr_iptable *new; | |
662 | ||
663 | zpi = (struct zebra_pbr_iptable *)arg; | |
664 | ||
665 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); | |
666 | ||
667 | memcpy(new, zpi, sizeof(*zpi)); | |
668 | ||
669 | return new; | |
670 | } | |
671 | ||
672 | void zebra_pbr_add_iptable(struct zebra_ns *zns, | |
673 | struct zebra_pbr_iptable *iptable) | |
674 | { | |
73a829f7 PG |
675 | int ret; |
676 | ||
7abd6c4f PG |
677 | (void)hash_get(zns->iptable_hash, iptable, |
678 | pbr_iptable_alloc_intern); | |
73a829f7 PG |
679 | ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable); |
680 | kernel_pbr_iptable_add_del_status(iptable, | |
215181cb DS |
681 | ret ? DP_INSTALL_SUCCESS |
682 | : DP_INSTALL_FAILURE); | |
7abd6c4f PG |
683 | } |
684 | ||
685 | void zebra_pbr_del_iptable(struct zebra_ns *zns, | |
686 | struct zebra_pbr_iptable *iptable) | |
687 | { | |
f80ec7e3 | 688 | struct zebra_pbr_iptable *lookup; |
7abd6c4f PG |
689 | |
690 | lookup = hash_lookup(zns->iptable_hash, iptable); | |
73a829f7 | 691 | hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable); |
f80ec7e3 PG |
692 | if (lookup) { |
693 | struct listnode *node, *nnode; | |
694 | char *name; | |
695 | ||
696 | hash_release(zns->iptable_hash, lookup); | |
697 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, | |
698 | node, nnode, name)) { | |
699 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
700 | list_delete_node(iptable->interface_name_list, | |
701 | node); | |
702 | } | |
7abd6c4f | 703 | XFREE(MTYPE_TMP, lookup); |
f80ec7e3 | 704 | } else |
7abd6c4f PG |
705 | zlog_warn("%s: IPTable being deleted we know nothing about", |
706 | __PRETTY_FUNCTION__); | |
707 | } | |
708 | ||
942bf97b | 709 | /* |
710 | * Handle success or failure of rule (un)install in the kernel. | |
711 | */ | |
712 | void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, | |
215181cb | 713 | enum dp_results res) |
942bf97b | 714 | { |
b6c5d343 | 715 | switch (res) { |
215181cb | 716 | case DP_INSTALL_SUCCESS: |
b6c5d343 DS |
717 | zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED); |
718 | break; | |
215181cb | 719 | case DP_INSTALL_FAILURE: |
b6c5d343 DS |
720 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL); |
721 | break; | |
215181cb | 722 | case DP_DELETE_SUCCESS: |
0f03639d | 723 | zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED); |
b6c5d343 | 724 | break; |
215181cb | 725 | case DP_DELETE_FAILURE: |
34d9d5be | 726 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE); |
b6c5d343 DS |
727 | break; |
728 | } | |
942bf97b | 729 | } |
730 | ||
425bdd6b PG |
731 | /* |
732 | * Handle success or failure of ipset (un)install in the kernel. | |
733 | */ | |
734 | void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, | |
215181cb | 735 | enum dp_results res) |
425bdd6b PG |
736 | { |
737 | switch (res) { | |
215181cb | 738 | case DP_INSTALL_SUCCESS: |
425bdd6b PG |
739 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED); |
740 | break; | |
215181cb | 741 | case DP_INSTALL_FAILURE: |
425bdd6b PG |
742 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); |
743 | break; | |
215181cb | 744 | case DP_DELETE_SUCCESS: |
4c550bcf PG |
745 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); |
746 | break; | |
215181cb | 747 | case DP_DELETE_FAILURE: |
34d9d5be | 748 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); |
425bdd6b PG |
749 | break; |
750 | } | |
751 | } | |
752 | ||
753 | /* | |
754 | * Handle success or failure of ipset (un)install in the kernel. | |
755 | */ | |
756 | void kernel_pbr_ipset_entry_add_del_status( | |
757 | struct zebra_pbr_ipset_entry *ipset, | |
215181cb | 758 | enum dp_results res) |
425bdd6b PG |
759 | { |
760 | switch (res) { | |
215181cb | 761 | case DP_INSTALL_SUCCESS: |
425bdd6b PG |
762 | zsend_ipset_entry_notify_owner(ipset, |
763 | ZAPI_IPSET_ENTRY_INSTALLED); | |
764 | break; | |
215181cb | 765 | case DP_INSTALL_FAILURE: |
425bdd6b PG |
766 | zsend_ipset_entry_notify_owner(ipset, |
767 | ZAPI_IPSET_ENTRY_FAIL_INSTALL); | |
768 | break; | |
215181cb | 769 | case DP_DELETE_SUCCESS: |
4c550bcf PG |
770 | zsend_ipset_entry_notify_owner(ipset, |
771 | ZAPI_IPSET_ENTRY_REMOVED); | |
772 | break; | |
215181cb | 773 | case DP_DELETE_FAILURE: |
4c550bcf | 774 | zsend_ipset_entry_notify_owner(ipset, |
34d9d5be | 775 | ZAPI_IPSET_ENTRY_FAIL_REMOVE); |
425bdd6b PG |
776 | break; |
777 | } | |
778 | } | |
779 | ||
7abd6c4f PG |
780 | /* |
781 | * Handle success or failure of ipset (un)install in the kernel. | |
782 | */ | |
783 | void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, | |
215181cb | 784 | enum dp_results res) |
7abd6c4f PG |
785 | { |
786 | switch (res) { | |
215181cb | 787 | case DP_INSTALL_SUCCESS: |
7abd6c4f PG |
788 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED); |
789 | break; | |
215181cb | 790 | case DP_INSTALL_FAILURE: |
7abd6c4f PG |
791 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); |
792 | break; | |
215181cb | 793 | case DP_DELETE_SUCCESS: |
4c550bcf PG |
794 | zsend_iptable_notify_owner(iptable, |
795 | ZAPI_IPTABLE_REMOVED); | |
796 | break; | |
215181cb | 797 | case DP_DELETE_FAILURE: |
4c550bcf | 798 | zsend_iptable_notify_owner(iptable, |
34d9d5be | 799 | ZAPI_IPTABLE_FAIL_REMOVE); |
7abd6c4f PG |
800 | break; |
801 | } | |
802 | } | |
803 | ||
942bf97b | 804 | /* |
805 | * Handle rule delete notification from kernel. | |
806 | */ | |
a0321978 | 807 | int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) |
942bf97b | 808 | { |
809 | return 0; | |
810 | } | |
586f4ccf PG |
811 | |
812 | struct zebra_pbr_ipset_entry_unique_display { | |
813 | struct zebra_pbr_ipset *zpi; | |
814 | struct vty *vty; | |
73a829f7 | 815 | struct zebra_ns *zns; |
586f4ccf PG |
816 | }; |
817 | ||
818 | struct zebra_pbr_env_display { | |
819 | struct zebra_ns *zns; | |
820 | struct vty *vty; | |
821 | }; | |
822 | ||
823 | static const char *zebra_pbr_prefix2str(union prefixconstptr pu, | |
824 | char *str, int size) | |
825 | { | |
826 | const struct prefix *p = pu.p; | |
827 | char buf[PREFIX2STR_BUFFER]; | |
828 | ||
829 | if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) { | |
830 | snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, | |
831 | buf, PREFIX2STR_BUFFER)); | |
832 | return str; | |
833 | } | |
834 | return prefix2str(pu, str, size); | |
835 | } | |
836 | ||
be729dd7 PG |
837 | static void zebra_pbr_display_icmp(struct vty *vty, |
838 | struct zebra_pbr_ipset_entry *zpie) | |
839 | { | |
840 | char decoded_str[20]; | |
841 | uint16_t port; | |
842 | ||
843 | /* range icmp type */ | |
844 | if (zpie->src_port_max || zpie->dst_port_max) { | |
845 | vty_out(vty, ":icmp:[type <%d:%d>;code <%d:%d>", | |
846 | zpie->src_port_min, zpie->src_port_max, | |
847 | zpie->dst_port_min, zpie->dst_port_max); | |
848 | } else { | |
849 | port = ((zpie->src_port_min << 8) & 0xff00) + | |
850 | (zpie->dst_port_min & 0xff); | |
851 | memset(decoded_str, 0, sizeof(decoded_str)); | |
852 | sprintf(decoded_str, "%d/%d", | |
853 | zpie->src_port_min, | |
854 | zpie->dst_port_min); | |
855 | vty_out(vty, ":icmp:%s", | |
856 | lookup_msg(icmp_typecode_str, | |
857 | port, decoded_str)); | |
858 | } | |
859 | } | |
860 | ||
25d760c5 PG |
861 | static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, |
862 | uint16_t port_min, uint16_t port_max, | |
863 | uint8_t proto) | |
864 | { | |
865 | if (!(filter_bm & PBR_FILTER_PROTO)) { | |
866 | if (port_max) | |
867 | vty_out(vty, ":udp/tcp:%d-%d", | |
868 | port_min, port_max); | |
869 | else | |
870 | vty_out(vty, ":udp/tcp:%d", | |
871 | port_min); | |
872 | } else { | |
873 | if (port_max) | |
874 | vty_out(vty, ":proto %d:%d-%d", | |
875 | proto, port_min, port_max); | |
876 | else | |
877 | vty_out(vty, ":proto %d:%d", | |
878 | proto, port_min); | |
879 | } | |
880 | } | |
881 | ||
586f4ccf PG |
882 | static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, |
883 | void *arg) | |
884 | { | |
885 | struct zebra_pbr_ipset_entry_unique_display *unique = | |
886 | (struct zebra_pbr_ipset_entry_unique_display *)arg; | |
887 | struct zebra_pbr_ipset *zpi = unique->zpi; | |
888 | struct vty *vty = unique->vty; | |
889 | struct zebra_pbr_ipset_entry *zpie = | |
890 | (struct zebra_pbr_ipset_entry *)backet->data; | |
73a829f7 PG |
891 | uint64_t pkts = 0, bytes = 0; |
892 | struct zebra_ns *zns = unique->zns; | |
893 | int ret = 0; | |
586f4ccf PG |
894 | |
895 | if (zpie->backpointer != zpi) | |
896 | return HASHWALK_CONTINUE; | |
897 | ||
25d760c5 PG |
898 | if ((zpi->type == IPSET_NET_NET) || |
899 | (zpi->type == IPSET_NET_PORT_NET)) { | |
586f4ccf PG |
900 | char buf[PREFIX_STRLEN]; |
901 | ||
902 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
903 | vty_out(vty, "\tfrom %s", buf); | |
be729dd7 PG |
904 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
905 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
906 | zebra_pbr_display_port(vty, zpie->filter_bm, |
907 | zpie->src_port_min, | |
908 | zpie->src_port_max, | |
909 | zpie->proto); | |
586f4ccf PG |
910 | vty_out(vty, " to "); |
911 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
912 | vty_out(vty, "%s", buf); | |
be729dd7 PG |
913 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
914 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
915 | zebra_pbr_display_port(vty, zpie->filter_bm, |
916 | zpie->dst_port_min, | |
917 | zpie->dst_port_max, | |
918 | zpie->proto); | |
be729dd7 PG |
919 | if (zpie->proto == IPPROTO_ICMP) |
920 | zebra_pbr_display_icmp(vty, zpie); | |
25d760c5 PG |
921 | } else if ((zpi->type == IPSET_NET) || |
922 | (zpi->type == IPSET_NET_PORT)) { | |
586f4ccf PG |
923 | char buf[PREFIX_STRLEN]; |
924 | ||
925 | if (zpie->filter_bm & PBR_FILTER_SRC_IP) { | |
926 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
927 | vty_out(vty, "\tfrom %s", buf); | |
928 | } | |
be729dd7 PG |
929 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
930 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
931 | zebra_pbr_display_port(vty, zpie->filter_bm, |
932 | zpie->src_port_min, | |
933 | zpie->src_port_max, | |
934 | zpie->proto); | |
586f4ccf PG |
935 | if (zpie->filter_bm & PBR_FILTER_DST_IP) { |
936 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
937 | vty_out(vty, "\tto %s", buf); | |
938 | } | |
be729dd7 PG |
939 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
940 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
941 | zebra_pbr_display_port(vty, zpie->filter_bm, |
942 | zpie->dst_port_min, | |
943 | zpie->dst_port_max, | |
944 | zpie->proto); | |
be729dd7 PG |
945 | if (zpie->proto == IPPROTO_ICMP) |
946 | zebra_pbr_display_icmp(vty, zpie); | |
586f4ccf PG |
947 | } |
948 | vty_out(vty, " (%u)\n", zpie->unique); | |
949 | ||
73a829f7 PG |
950 | ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat, |
951 | zns, zpie, &pkts, &bytes); | |
952 | if (ret && pkts > 0) | |
953 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
954 | pkts, bytes); | |
586f4ccf PG |
955 | return HASHWALK_CONTINUE; |
956 | } | |
957 | ||
958 | static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) | |
959 | { | |
960 | struct zebra_pbr_env_display *uniqueipset = | |
961 | (struct zebra_pbr_env_display *)arg; | |
962 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
963 | struct zebra_pbr_ipset_entry_unique_display unique; | |
964 | struct vty *vty = uniqueipset->vty; | |
965 | struct zebra_ns *zns = uniqueipset->zns; | |
966 | ||
967 | vty_out(vty, "IPset %s type %s\n", zpi->ipset_name, | |
968 | zebra_pbr_ipset_type2str(zpi->type)); | |
969 | unique.vty = vty; | |
970 | unique.zpi = zpi; | |
73a829f7 | 971 | unique.zns = zns; |
586f4ccf PG |
972 | hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb, |
973 | &unique); | |
974 | vty_out(vty, "\n"); | |
975 | return HASHWALK_CONTINUE; | |
976 | } | |
977 | ||
dc993e76 PG |
978 | size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len, |
979 | uint16_t tcp_val) | |
980 | { | |
981 | size_t len_written = 0; | |
982 | static struct message nt = {0}; | |
983 | const struct message *pnt; | |
984 | int incr = 0; | |
985 | ||
986 | for (pnt = tcp_value_str; | |
987 | memcmp(pnt, &nt, sizeof(struct message)); pnt++) | |
988 | if (pnt->key & tcp_val) { | |
989 | len_written += snprintf(buffer + len_written, | |
990 | len - len_written, | |
991 | "%s%s", incr ? | |
992 | ",":"", pnt->str); | |
993 | incr++; | |
994 | } | |
995 | return len_written; | |
996 | } | |
997 | ||
586f4ccf PG |
998 | /* |
999 | */ | |
1000 | void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) | |
1001 | { | |
1002 | struct zebra_pbr_ipset *zpi; | |
1003 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
1004 | struct zebra_pbr_ipset_entry_unique_display unique; | |
1005 | struct zebra_pbr_env_display uniqueipset; | |
1006 | ||
1007 | if (ipsetname) { | |
1008 | zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname); | |
1009 | if (!zpi) { | |
1010 | vty_out(vty, "No IPset %s found\n", ipsetname); | |
1011 | return; | |
1012 | } | |
1013 | vty_out(vty, "IPset %s type %s\n", ipsetname, | |
1014 | zebra_pbr_ipset_type2str(zpi->type)); | |
1015 | ||
1016 | unique.vty = vty; | |
1017 | unique.zpi = zpi; | |
73a829f7 | 1018 | unique.zns = zns; |
586f4ccf PG |
1019 | hash_walk(zns->ipset_entry_hash, |
1020 | zebra_pbr_show_ipset_entry_walkcb, | |
1021 | &unique); | |
1022 | return; | |
1023 | } | |
1024 | uniqueipset.zns = zns; | |
1025 | uniqueipset.vty = vty; | |
1026 | hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb, | |
1027 | &uniqueipset); | |
1028 | } | |
1029 | ||
1030 | struct pbr_rule_fwmark_lookup { | |
1031 | struct zebra_pbr_rule *ptr; | |
1032 | uint32_t fwmark; | |
1033 | }; | |
1034 | ||
1035 | static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, | |
1036 | void *arg) | |
1037 | { | |
1038 | struct pbr_rule_fwmark_lookup *iprule = | |
1039 | (struct pbr_rule_fwmark_lookup *)arg; | |
1040 | struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; | |
1041 | ||
1042 | if (iprule->fwmark == zpr->rule.filter.fwmark) { | |
1043 | iprule->ptr = zpr; | |
1044 | return HASHWALK_ABORT; | |
1045 | } | |
1046 | return HASHWALK_CONTINUE; | |
1047 | } | |
1048 | ||
1049 | static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) | |
1050 | { | |
1051 | struct zebra_pbr_iptable *iptable = | |
1052 | (struct zebra_pbr_iptable *)backet->data; | |
1053 | struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; | |
1054 | struct vty *vty = env->vty; | |
1055 | struct zebra_ns *zns = env->zns; | |
73a829f7 PG |
1056 | int ret; |
1057 | uint64_t pkts = 0, bytes = 0; | |
586f4ccf PG |
1058 | |
1059 | vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, | |
1060 | iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", | |
1061 | iptable->unique); | |
e7f7dad4 PG |
1062 | if (iptable->pkt_len_min || iptable->pkt_len_max) { |
1063 | if (!iptable->pkt_len_max) | |
1064 | vty_out(vty, "\t pkt len %u\n", | |
1065 | iptable->pkt_len_min); | |
1066 | else | |
1067 | vty_out(vty, "\t pkt len [%u;%u]\n", | |
1068 | iptable->pkt_len_min, | |
1069 | iptable->pkt_len_max); | |
1070 | } | |
dc993e76 PG |
1071 | if (iptable->tcp_flags || iptable->tcp_mask_flags) { |
1072 | char tcp_flag_str[64]; | |
1073 | char tcp_flag_mask_str[64]; | |
1074 | ||
1075 | zebra_pbr_tcpflags_snprintf(tcp_flag_str, | |
1076 | sizeof(tcp_flag_str), | |
1077 | iptable->tcp_flags); | |
1078 | zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str, | |
1079 | sizeof(tcp_flag_mask_str), | |
1080 | iptable->tcp_mask_flags); | |
1081 | vty_out(vty, "\t tcpflags [%s/%s]\n", | |
1082 | tcp_flag_str, tcp_flag_mask_str); | |
1083 | } | |
73a829f7 PG |
1084 | ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat, |
1085 | zns, iptable, &pkts, &bytes); | |
1086 | if (ret && pkts > 0) | |
1087 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
1088 | pkts, bytes); | |
586f4ccf PG |
1089 | if (iptable->action != ZEBRA_IPTABLES_DROP) { |
1090 | struct pbr_rule_fwmark_lookup prfl; | |
1091 | ||
1092 | prfl.fwmark = iptable->fwmark; | |
1093 | prfl.ptr = NULL; | |
1094 | hash_walk(zns->rules_hash, | |
1095 | &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl); | |
1096 | if (prfl.ptr) { | |
1097 | struct zebra_pbr_rule *zpr = prfl.ptr; | |
1098 | ||
1099 | vty_out(vty, "\t table %u, fwmark %u\n", | |
1100 | zpr->rule.action.table, | |
1101 | prfl.fwmark); | |
1102 | } | |
1103 | } | |
1104 | return HASHWALK_CONTINUE; | |
1105 | } | |
1106 | ||
1107 | void zebra_pbr_show_iptable(struct vty *vty) | |
1108 | { | |
1109 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
1110 | struct zebra_pbr_env_display env; | |
1111 | ||
1112 | env.vty = vty; | |
1113 | env.zns = zns; | |
1114 | ||
1115 | hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb, | |
1116 | &env); | |
1117 | } | |
f80ec7e3 PG |
1118 | |
1119 | void zebra_pbr_iptable_update_interfacelist(struct stream *s, | |
1120 | struct zebra_pbr_iptable *zpi) | |
1121 | { | |
1122 | uint32_t i = 0, index; | |
1123 | struct interface *ifp; | |
1124 | char *name; | |
1125 | ||
1126 | for (i = 0; i < zpi->nb_interface; i++) { | |
1127 | STREAM_GETL(s, index); | |
1128 | ifp = if_lookup_by_index(index, zpi->vrf_id); | |
1129 | if (!ifp) | |
1130 | continue; | |
1131 | name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name); | |
1132 | listnode_add(zpi->interface_name_list, name); | |
1133 | } | |
1134 | stream_failure: | |
1135 | return; | |
1136 | } |