]>
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" |
f80ec7e3 PG |
33 | |
34 | /* definitions */ | |
35 | DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list") | |
942bf97b | 36 | |
37 | /* definitions */ | |
586f4ccf PG |
38 | static const struct message ipset_type_msg[] = { |
39 | {IPSET_NET_PORT_NET, "net,port,net"}, | |
40 | {IPSET_NET_PORT, "net,port"}, | |
41 | {IPSET_NET_NET, "net,net"}, | |
42 | {IPSET_NET, "net"}, | |
43 | {0} | |
44 | }; | |
942bf97b | 45 | |
46 | /* static function declarations */ | |
73a829f7 PG |
47 | DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns, |
48 | struct zebra_pbr_ipset_entry *ipset, | |
49 | uint64_t *pkts, uint64_t *bytes), | |
50 | (zns, ipset, pkts, bytes)) | |
51 | ||
52 | DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns, | |
53 | struct zebra_pbr_iptable *iptable, | |
54 | uint64_t *pkts, uint64_t *bytes), | |
55 | (zns, iptable, pkts, bytes)) | |
56 | ||
57 | DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns, | |
58 | int cmd, | |
59 | struct zebra_pbr_iptable *iptable), | |
60 | (zns, cmd, iptable)); | |
61 | ||
62 | DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns, | |
63 | int cmd, | |
64 | struct zebra_pbr_ipset_entry *ipset), | |
65 | (zns, cmd, ipset)); | |
66 | ||
67 | DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns, | |
68 | int cmd, | |
69 | struct zebra_pbr_ipset *ipset), | |
70 | (zns, cmd, ipset)); | |
942bf97b | 71 | |
72 | /* Private functions */ | |
73 | ||
74 | /* Public functions */ | |
43fe6a2a | 75 | void zebra_pbr_rules_free(void *arg) |
1fbfe5a5 | 76 | { |
43fe6a2a DS |
77 | struct zebra_pbr_rule *rule; |
78 | ||
79 | rule = (struct zebra_pbr_rule *)arg; | |
80 | ||
a0321978 | 81 | kernel_del_pbr_rule(rule); |
43fe6a2a DS |
82 | XFREE(MTYPE_TMP, rule); |
83 | } | |
84 | ||
85 | uint32_t zebra_pbr_rules_hash_key(void *arg) | |
86 | { | |
87 | struct zebra_pbr_rule *rule; | |
88 | uint32_t key; | |
89 | ||
90 | rule = (struct zebra_pbr_rule *)arg; | |
5dd0722d PG |
91 | key = jhash_3words(rule->rule.seq, rule->rule.priority, |
92 | rule->rule.action.table, | |
93 | prefix_hash_key(&rule->rule.filter.src_ip)); | |
a0321978 DS |
94 | if (rule->ifp) |
95 | key = jhash_1word(rule->ifp->ifindex, key); | |
96 | else | |
97 | key = jhash_1word(0, key); | |
98 | ||
5dd0722d PG |
99 | if (rule->rule.filter.fwmark) |
100 | key = jhash_1word(rule->rule.filter.fwmark, key); | |
1907e4b8 PG |
101 | else |
102 | key = jhash_1word(0, key); | |
5dd0722d PG |
103 | return jhash_3words(rule->rule.filter.src_port, |
104 | rule->rule.filter.dst_port, | |
105 | prefix_hash_key(&rule->rule.filter.dst_ip), | |
106 | jhash_1word(rule->rule.unique, key)); | |
43fe6a2a DS |
107 | } |
108 | ||
109 | int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) | |
110 | { | |
111 | const struct zebra_pbr_rule *r1, *r2; | |
112 | ||
113 | r1 = (const struct zebra_pbr_rule *)arg1; | |
114 | r2 = (const struct zebra_pbr_rule *)arg2; | |
115 | ||
5dd0722d | 116 | if (r1->rule.seq != r2->rule.seq) |
43fe6a2a DS |
117 | return 0; |
118 | ||
5dd0722d | 119 | if (r1->rule.priority != r2->rule.priority) |
43fe6a2a DS |
120 | return 0; |
121 | ||
5dd0722d | 122 | if (r1->rule.unique != r2->rule.unique) |
b6c5d343 DS |
123 | return 0; |
124 | ||
5dd0722d | 125 | if (r1->rule.action.table != r2->rule.action.table) |
43fe6a2a DS |
126 | return 0; |
127 | ||
5dd0722d | 128 | if (r1->rule.filter.src_port != r2->rule.filter.src_port) |
43fe6a2a DS |
129 | return 0; |
130 | ||
5dd0722d | 131 | if (r1->rule.filter.dst_port != r2->rule.filter.dst_port) |
43fe6a2a DS |
132 | return 0; |
133 | ||
5dd0722d | 134 | if (r1->rule.filter.fwmark != r2->rule.filter.fwmark) |
1907e4b8 PG |
135 | return 0; |
136 | ||
5dd0722d | 137 | if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip)) |
43fe6a2a DS |
138 | return 0; |
139 | ||
5dd0722d | 140 | if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) |
43fe6a2a DS |
141 | return 0; |
142 | ||
a0321978 DS |
143 | if (r1->ifp != r2->ifp) |
144 | return 0; | |
145 | ||
43fe6a2a DS |
146 | return 1; |
147 | } | |
148 | ||
f46bbab4 | 149 | struct pbr_rule_unique_lookup { |
8c3cd6c6 DS |
150 | struct zebra_pbr_rule *rule; |
151 | uint32_t unique; | |
37c606ff | 152 | struct interface *ifp; |
8c3cd6c6 DS |
153 | }; |
154 | ||
155 | static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) | |
156 | { | |
f46bbab4 | 157 | struct pbr_rule_unique_lookup *pul = data; |
8c3cd6c6 DS |
158 | struct zebra_pbr_rule *rule = b->data; |
159 | ||
37c606ff | 160 | if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) { |
8c3cd6c6 DS |
161 | pul->rule = rule; |
162 | return HASHWALK_ABORT; | |
163 | } | |
164 | ||
165 | return HASHWALK_CONTINUE; | |
166 | } | |
167 | ||
168 | static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns, | |
37c606ff DS |
169 | uint32_t unique, |
170 | struct interface *ifp) | |
8c3cd6c6 | 171 | { |
f46bbab4 | 172 | struct pbr_rule_unique_lookup pul; |
8c3cd6c6 DS |
173 | |
174 | pul.unique = unique; | |
37c606ff | 175 | pul.ifp = ifp; |
8c3cd6c6 DS |
176 | pul.rule = NULL; |
177 | hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul); | |
178 | ||
179 | return pul.rule; | |
180 | } | |
181 | ||
7661461a PG |
182 | void zebra_pbr_ipset_free(void *arg) |
183 | { | |
184 | struct zebra_pbr_ipset *ipset; | |
73a829f7 | 185 | struct zebra_ns *zns; |
7661461a PG |
186 | |
187 | ipset = (struct zebra_pbr_ipset *)arg; | |
73a829f7 PG |
188 | if (vrf_is_backend_netns()) |
189 | zns = zebra_ns_lookup(ipset->vrf_id); | |
190 | else | |
191 | zns = zebra_ns_lookup(NS_DEFAULT); | |
192 | hook_call(zebra_pbr_ipset_wrap_script_update, | |
193 | zns, 0, ipset); | |
7661461a PG |
194 | XFREE(MTYPE_TMP, ipset); |
195 | } | |
196 | ||
197 | uint32_t zebra_pbr_ipset_hash_key(void *arg) | |
198 | { | |
199 | struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg; | |
425bdd6b | 200 | uint32_t *pnt = (uint32_t *)&ipset->ipset_name; |
7661461a | 201 | |
425bdd6b | 202 | return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de); |
7661461a PG |
203 | } |
204 | ||
205 | int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) | |
206 | { | |
207 | const struct zebra_pbr_ipset *r1, *r2; | |
208 | ||
209 | r1 = (const struct zebra_pbr_ipset *)arg1; | |
210 | r2 = (const struct zebra_pbr_ipset *)arg2; | |
211 | ||
212 | if (r1->type != r2->type) | |
213 | return 0; | |
214 | if (r1->unique != r2->unique) | |
215 | return 0; | |
216 | if (strncmp(r1->ipset_name, r2->ipset_name, | |
217 | ZEBRA_IPSET_NAME_SIZE)) | |
218 | return 0; | |
219 | return 1; | |
220 | } | |
221 | ||
222 | void zebra_pbr_ipset_entry_free(void *arg) | |
223 | { | |
224 | struct zebra_pbr_ipset_entry *ipset; | |
73a829f7 | 225 | struct zebra_ns *zns; |
7661461a PG |
226 | |
227 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
73a829f7 PG |
228 | if (ipset->backpointer && vrf_is_backend_netns()) { |
229 | struct zebra_pbr_ipset *ips = ipset->backpointer; | |
230 | ||
231 | zns = zebra_ns_lookup((ns_id_t)ips->vrf_id); | |
232 | } else | |
233 | zns = zebra_ns_lookup(NS_DEFAULT); | |
234 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, | |
235 | zns, 0, ipset); | |
7661461a PG |
236 | |
237 | XFREE(MTYPE_TMP, ipset); | |
238 | } | |
239 | ||
240 | uint32_t zebra_pbr_ipset_entry_hash_key(void *arg) | |
241 | { | |
242 | struct zebra_pbr_ipset_entry *ipset; | |
243 | uint32_t key; | |
244 | ||
245 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
246 | key = prefix_hash_key(&ipset->src); | |
247 | key = jhash_1word(ipset->unique, key); | |
248 | key = jhash_1word(prefix_hash_key(&ipset->dst), key); | |
25d760c5 PG |
249 | key = jhash(&ipset->dst_port_min, 2, key); |
250 | key = jhash(&ipset->dst_port_max, 2, key); | |
251 | key = jhash(&ipset->src_port_min, 2, key); | |
252 | key = jhash(&ipset->src_port_max, 2, key); | |
253 | key = jhash(&ipset->proto, 1, key); | |
7661461a PG |
254 | |
255 | return key; | |
256 | } | |
257 | ||
258 | int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) | |
259 | { | |
260 | const struct zebra_pbr_ipset_entry *r1, *r2; | |
261 | ||
262 | r1 = (const struct zebra_pbr_ipset_entry *)arg1; | |
263 | r2 = (const struct zebra_pbr_ipset_entry *)arg2; | |
264 | ||
265 | if (r1->unique != r2->unique) | |
266 | return 0; | |
267 | ||
268 | if (!prefix_same(&r1->src, &r2->src)) | |
269 | return 0; | |
270 | ||
271 | if (!prefix_same(&r1->dst, &r2->dst)) | |
272 | return 0; | |
273 | ||
25d760c5 PG |
274 | if (r1->src_port_min != r2->src_port_min) |
275 | return 0; | |
276 | ||
277 | if (r1->src_port_max != r2->src_port_max) | |
278 | return 0; | |
279 | ||
280 | if (r1->dst_port_min != r2->dst_port_min) | |
281 | return 0; | |
282 | ||
283 | if (r1->dst_port_max != r2->dst_port_max) | |
284 | return 0; | |
285 | ||
286 | if (r1->proto != r2->proto) | |
287 | return 0; | |
7661461a PG |
288 | return 1; |
289 | } | |
290 | ||
7abd6c4f PG |
291 | void zebra_pbr_iptable_free(void *arg) |
292 | { | |
293 | struct zebra_pbr_iptable *iptable; | |
f80ec7e3 PG |
294 | struct listnode *node, *nnode; |
295 | char *name; | |
73a829f7 | 296 | struct zebra_ns *zns; |
7abd6c4f PG |
297 | |
298 | iptable = (struct zebra_pbr_iptable *)arg; | |
73a829f7 PG |
299 | if (vrf_is_backend_netns()) |
300 | zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id); | |
301 | else | |
302 | zns = zebra_ns_lookup(NS_DEFAULT); | |
303 | hook_call(zebra_pbr_iptable_wrap_script_update, | |
304 | zns, 0, iptable); | |
7abd6c4f | 305 | |
f80ec7e3 PG |
306 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, |
307 | node, nnode, name)) { | |
308 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
309 | list_delete_node(iptable->interface_name_list, | |
310 | node); | |
311 | } | |
7abd6c4f PG |
312 | XFREE(MTYPE_TMP, iptable); |
313 | } | |
314 | ||
315 | uint32_t zebra_pbr_iptable_hash_key(void *arg) | |
316 | { | |
317 | struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg; | |
318 | uint32_t *pnt = (uint32_t *)&(iptable->ipset_name); | |
319 | uint32_t key; | |
320 | ||
321 | key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, | |
322 | 0x63ab42de); | |
323 | key = jhash_1word(iptable->fwmark, key); | |
324 | return jhash_3words(iptable->filter_bm, iptable->type, | |
325 | iptable->unique, key); | |
326 | } | |
327 | ||
328 | int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) | |
329 | { | |
330 | const struct zebra_pbr_iptable *r1, *r2; | |
331 | ||
332 | r1 = (const struct zebra_pbr_iptable *)arg1; | |
333 | r2 = (const struct zebra_pbr_iptable *)arg2; | |
334 | ||
335 | if (r1->type != r2->type) | |
336 | return 0; | |
337 | if (r1->unique != r2->unique) | |
338 | return 0; | |
339 | if (r1->filter_bm != r2->filter_bm) | |
340 | return 0; | |
341 | if (r1->fwmark != r2->fwmark) | |
342 | return 0; | |
343 | if (r1->action != r2->action) | |
344 | return 0; | |
345 | if (strncmp(r1->ipset_name, r2->ipset_name, | |
346 | ZEBRA_IPSET_NAME_SIZE)) | |
347 | return 0; | |
348 | return 1; | |
349 | } | |
350 | ||
43fe6a2a DS |
351 | static void *pbr_rule_alloc_intern(void *arg) |
352 | { | |
353 | struct zebra_pbr_rule *zpr; | |
354 | struct zebra_pbr_rule *new; | |
355 | ||
356 | zpr = (struct zebra_pbr_rule *)arg; | |
357 | ||
358 | new = XCALLOC(MTYPE_TMP, sizeof(*new)); | |
359 | ||
360 | memcpy(new, zpr, sizeof(*zpr)); | |
361 | ||
362 | return new; | |
363 | } | |
364 | ||
a0321978 | 365 | void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
43fe6a2a | 366 | { |
8c3cd6c6 | 367 | struct zebra_pbr_rule *unique = |
37c606ff | 368 | pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp); |
8c3cd6c6 | 369 | |
43fe6a2a | 370 | (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern); |
a0321978 | 371 | kernel_add_pbr_rule(rule); |
8c3cd6c6 DS |
372 | /* |
373 | * Rule Replace semantics, if we have an old, install the | |
374 | * new rule, look above, and then delete the old | |
375 | */ | |
376 | if (unique) | |
377 | zebra_pbr_del_rule(zns, unique); | |
1fbfe5a5 DS |
378 | } |
379 | ||
a0321978 | 380 | void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
1fbfe5a5 | 381 | { |
43fe6a2a DS |
382 | struct zebra_pbr_rule *lookup; |
383 | ||
384 | lookup = hash_lookup(zns->rules_hash, rule); | |
a0321978 | 385 | kernel_del_pbr_rule(rule); |
43fe6a2a | 386 | |
d5c52f76 DS |
387 | if (lookup) { |
388 | hash_release(zns->rules_hash, lookup); | |
43fe6a2a | 389 | XFREE(MTYPE_TMP, lookup); |
d5c52f76 | 390 | } else |
43fe6a2a DS |
391 | zlog_warn("%s: Rule being deleted we know nothing about", |
392 | __PRETTY_FUNCTION__); | |
1fbfe5a5 DS |
393 | } |
394 | ||
e69aa084 DS |
395 | static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) |
396 | { | |
397 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
398 | struct zebra_pbr_rule *rule = b->data; | |
399 | int *sock = data; | |
400 | ||
401 | if (rule->sock == *sock) { | |
402 | kernel_del_pbr_rule(rule); | |
403 | hash_release(zns->rules_hash, rule); | |
d5c52f76 | 404 | XFREE(MTYPE_TMP, rule); |
e69aa084 DS |
405 | } |
406 | } | |
407 | ||
c2ef5232 PG |
408 | static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) |
409 | { | |
410 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
411 | struct zebra_pbr_ipset *ipset = b->data; | |
412 | int *sock = data; | |
413 | ||
73a829f7 PG |
414 | if (ipset->sock == *sock) { |
415 | hook_call(zebra_pbr_ipset_wrap_script_update, | |
416 | zns, 0, ipset); | |
c2ef5232 | 417 | hash_release(zns->ipset_hash, ipset); |
73a829f7 | 418 | } |
c2ef5232 PG |
419 | } |
420 | ||
421 | static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) | |
422 | { | |
423 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
424 | struct zebra_pbr_ipset_entry *ipset = b->data; | |
425 | int *sock = data; | |
426 | ||
73a829f7 PG |
427 | if (ipset->sock == *sock) { |
428 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, | |
429 | zns, 0, ipset); | |
c2ef5232 | 430 | hash_release(zns->ipset_entry_hash, ipset); |
73a829f7 | 431 | } |
c2ef5232 PG |
432 | } |
433 | ||
434 | static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) | |
435 | { | |
436 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
437 | struct zebra_pbr_iptable *iptable = b->data; | |
438 | int *sock = data; | |
439 | ||
73a829f7 PG |
440 | if (iptable->sock == *sock) { |
441 | hook_call(zebra_pbr_iptable_wrap_script_update, | |
442 | zns, 0, iptable); | |
c2ef5232 | 443 | hash_release(zns->iptable_hash, iptable); |
73a829f7 | 444 | } |
c2ef5232 PG |
445 | } |
446 | ||
4c0ec639 | 447 | static int zebra_pbr_client_close_cleanup(struct zserv *client) |
e69aa084 | 448 | { |
4c0ec639 | 449 | int sock = client->sock; |
e69aa084 DS |
450 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); |
451 | ||
4c0ec639 PG |
452 | if (!sock) |
453 | return 0; | |
e69aa084 | 454 | hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock); |
c2ef5232 PG |
455 | hash_iterate(zns->iptable_hash, |
456 | zebra_pbr_cleanup_iptable, &sock); | |
457 | hash_iterate(zns->ipset_entry_hash, | |
458 | zebra_pbr_cleanup_ipset_entry, &sock); | |
459 | hash_iterate(zns->ipset_hash, | |
460 | zebra_pbr_cleanup_ipset, &sock); | |
4c0ec639 PG |
461 | return 1; |
462 | } | |
463 | ||
464 | void zebra_pbr_init(void) | |
465 | { | |
466 | hook_register(zapi_client_close, zebra_pbr_client_close_cleanup); | |
e69aa084 DS |
467 | } |
468 | ||
7661461a PG |
469 | static void *pbr_ipset_alloc_intern(void *arg) |
470 | { | |
471 | struct zebra_pbr_ipset *zpi; | |
472 | struct zebra_pbr_ipset *new; | |
473 | ||
474 | zpi = (struct zebra_pbr_ipset *)arg; | |
475 | ||
476 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset)); | |
477 | ||
478 | memcpy(new, zpi, sizeof(*zpi)); | |
479 | ||
480 | return new; | |
481 | } | |
482 | ||
483 | void zebra_pbr_create_ipset(struct zebra_ns *zns, | |
484 | struct zebra_pbr_ipset *ipset) | |
485 | { | |
73a829f7 PG |
486 | int ret; |
487 | ||
7661461a | 488 | (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern); |
73a829f7 PG |
489 | ret = hook_call(zebra_pbr_ipset_wrap_script_update, |
490 | zns, 1, ipset); | |
491 | kernel_pbr_ipset_add_del_status(ipset, | |
492 | ret ? SOUTHBOUND_INSTALL_SUCCESS | |
493 | : SOUTHBOUND_INSTALL_FAILURE); | |
7661461a PG |
494 | } |
495 | ||
496 | void zebra_pbr_destroy_ipset(struct zebra_ns *zns, | |
497 | struct zebra_pbr_ipset *ipset) | |
498 | { | |
499 | struct zebra_pbr_ipset *lookup; | |
500 | ||
501 | lookup = hash_lookup(zns->ipset_hash, ipset); | |
73a829f7 PG |
502 | hook_call(zebra_pbr_ipset_wrap_script_update, |
503 | zns, 0, ipset); | |
de67547d PG |
504 | if (lookup) { |
505 | hash_release(zns->ipset_hash, lookup); | |
7661461a | 506 | XFREE(MTYPE_TMP, lookup); |
de67547d | 507 | } else |
425bdd6b | 508 | zlog_warn("%s: IPSet Entry being deleted we know nothing about", |
7661461a PG |
509 | __PRETTY_FUNCTION__); |
510 | } | |
511 | ||
ed78b7c8 PG |
512 | struct pbr_ipset_name_lookup { |
513 | struct zebra_pbr_ipset *ipset; | |
514 | char ipset_name[ZEBRA_IPSET_NAME_SIZE]; | |
515 | }; | |
516 | ||
586f4ccf PG |
517 | static const char *zebra_pbr_ipset_type2str(uint32_t type) |
518 | { | |
519 | return lookup_msg(ipset_type_msg, type, | |
520 | "Unrecognized IPset Type"); | |
521 | } | |
522 | ||
ed78b7c8 PG |
523 | static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) |
524 | { | |
525 | struct pbr_ipset_name_lookup *pinl = | |
526 | (struct pbr_ipset_name_lookup *)arg; | |
527 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
528 | ||
529 | if (!strncmp(pinl->ipset_name, zpi->ipset_name, | |
530 | ZEBRA_IPSET_NAME_SIZE)) { | |
531 | pinl->ipset = zpi; | |
532 | return HASHWALK_ABORT; | |
533 | } | |
534 | return HASHWALK_CONTINUE; | |
535 | } | |
536 | ||
d59c13af PG |
537 | struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns, |
538 | char *ipsetname) | |
539 | { | |
ed78b7c8 PG |
540 | struct pbr_ipset_name_lookup pinl; |
541 | struct pbr_ipset_name_lookup *ptr = &pinl; | |
542 | ||
d59c13af PG |
543 | if (!ipsetname) |
544 | return NULL; | |
ed78b7c8 PG |
545 | memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup)); |
546 | snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s", | |
547 | ipsetname); | |
548 | hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr); | |
549 | return ptr->ipset; | |
d59c13af PG |
550 | } |
551 | ||
7661461a PG |
552 | static void *pbr_ipset_entry_alloc_intern(void *arg) |
553 | { | |
554 | struct zebra_pbr_ipset_entry *zpi; | |
555 | struct zebra_pbr_ipset_entry *new; | |
556 | ||
557 | zpi = (struct zebra_pbr_ipset_entry *)arg; | |
558 | ||
559 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry)); | |
560 | ||
561 | memcpy(new, zpi, sizeof(*zpi)); | |
562 | ||
563 | return new; | |
564 | } | |
565 | ||
566 | void zebra_pbr_add_ipset_entry(struct zebra_ns *zns, | |
567 | struct zebra_pbr_ipset_entry *ipset) | |
568 | { | |
73a829f7 PG |
569 | int ret; |
570 | ||
7661461a PG |
571 | (void)hash_get(zns->ipset_entry_hash, ipset, |
572 | pbr_ipset_entry_alloc_intern); | |
73a829f7 PG |
573 | ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update, |
574 | zns, 1, ipset); | |
575 | kernel_pbr_ipset_entry_add_del_status(ipset, | |
576 | ret ? SOUTHBOUND_INSTALL_SUCCESS | |
577 | : SOUTHBOUND_INSTALL_FAILURE); | |
7661461a PG |
578 | } |
579 | ||
580 | void zebra_pbr_del_ipset_entry(struct zebra_ns *zns, | |
581 | struct zebra_pbr_ipset_entry *ipset) | |
582 | { | |
583 | struct zebra_pbr_ipset_entry *lookup; | |
584 | ||
425bdd6b | 585 | lookup = hash_lookup(zns->ipset_entry_hash, ipset); |
73a829f7 PG |
586 | hook_call(zebra_pbr_ipset_entry_wrap_script_update, |
587 | zns, 0, ipset); | |
de67547d PG |
588 | if (lookup) { |
589 | hash_release(zns->ipset_entry_hash, lookup); | |
7661461a | 590 | XFREE(MTYPE_TMP, lookup); |
de67547d | 591 | } else |
7661461a PG |
592 | zlog_warn("%s: IPSet being deleted we know nothing about", |
593 | __PRETTY_FUNCTION__); | |
594 | } | |
595 | ||
7abd6c4f PG |
596 | static void *pbr_iptable_alloc_intern(void *arg) |
597 | { | |
598 | struct zebra_pbr_iptable *zpi; | |
599 | struct zebra_pbr_iptable *new; | |
600 | ||
601 | zpi = (struct zebra_pbr_iptable *)arg; | |
602 | ||
603 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); | |
604 | ||
605 | memcpy(new, zpi, sizeof(*zpi)); | |
606 | ||
607 | return new; | |
608 | } | |
609 | ||
610 | void zebra_pbr_add_iptable(struct zebra_ns *zns, | |
611 | struct zebra_pbr_iptable *iptable) | |
612 | { | |
73a829f7 PG |
613 | int ret; |
614 | ||
7abd6c4f PG |
615 | (void)hash_get(zns->iptable_hash, iptable, |
616 | pbr_iptable_alloc_intern); | |
73a829f7 PG |
617 | ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable); |
618 | kernel_pbr_iptable_add_del_status(iptable, | |
619 | ret ? SOUTHBOUND_INSTALL_SUCCESS | |
620 | : SOUTHBOUND_INSTALL_FAILURE); | |
7abd6c4f PG |
621 | } |
622 | ||
623 | void zebra_pbr_del_iptable(struct zebra_ns *zns, | |
624 | struct zebra_pbr_iptable *iptable) | |
625 | { | |
f80ec7e3 | 626 | struct zebra_pbr_iptable *lookup; |
7abd6c4f PG |
627 | |
628 | lookup = hash_lookup(zns->iptable_hash, iptable); | |
73a829f7 | 629 | hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable); |
f80ec7e3 PG |
630 | if (lookup) { |
631 | struct listnode *node, *nnode; | |
632 | char *name; | |
633 | ||
634 | hash_release(zns->iptable_hash, lookup); | |
635 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, | |
636 | node, nnode, name)) { | |
637 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
638 | list_delete_node(iptable->interface_name_list, | |
639 | node); | |
640 | } | |
7abd6c4f | 641 | XFREE(MTYPE_TMP, lookup); |
f80ec7e3 | 642 | } else |
7abd6c4f PG |
643 | zlog_warn("%s: IPTable being deleted we know nothing about", |
644 | __PRETTY_FUNCTION__); | |
645 | } | |
646 | ||
942bf97b | 647 | /* |
648 | * Handle success or failure of rule (un)install in the kernel. | |
649 | */ | |
650 | void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, | |
942bf97b | 651 | enum southbound_results res) |
652 | { | |
b6c5d343 DS |
653 | switch (res) { |
654 | case SOUTHBOUND_INSTALL_SUCCESS: | |
655 | zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED); | |
656 | break; | |
657 | case SOUTHBOUND_INSTALL_FAILURE: | |
658 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL); | |
659 | break; | |
660 | case SOUTHBOUND_DELETE_SUCCESS: | |
0f03639d | 661 | zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED); |
b6c5d343 DS |
662 | break; |
663 | case SOUTHBOUND_DELETE_FAILURE: | |
34d9d5be | 664 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE); |
b6c5d343 DS |
665 | break; |
666 | } | |
942bf97b | 667 | } |
668 | ||
425bdd6b PG |
669 | /* |
670 | * Handle success or failure of ipset (un)install in the kernel. | |
671 | */ | |
672 | void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, | |
673 | enum southbound_results res) | |
674 | { | |
675 | switch (res) { | |
676 | case SOUTHBOUND_INSTALL_SUCCESS: | |
677 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED); | |
678 | break; | |
679 | case SOUTHBOUND_INSTALL_FAILURE: | |
680 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); | |
681 | break; | |
682 | case SOUTHBOUND_DELETE_SUCCESS: | |
4c550bcf PG |
683 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); |
684 | break; | |
425bdd6b | 685 | case SOUTHBOUND_DELETE_FAILURE: |
34d9d5be | 686 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); |
425bdd6b PG |
687 | break; |
688 | } | |
689 | } | |
690 | ||
691 | /* | |
692 | * Handle success or failure of ipset (un)install in the kernel. | |
693 | */ | |
694 | void kernel_pbr_ipset_entry_add_del_status( | |
695 | struct zebra_pbr_ipset_entry *ipset, | |
696 | enum southbound_results res) | |
697 | { | |
698 | switch (res) { | |
699 | case SOUTHBOUND_INSTALL_SUCCESS: | |
700 | zsend_ipset_entry_notify_owner(ipset, | |
701 | ZAPI_IPSET_ENTRY_INSTALLED); | |
702 | break; | |
703 | case SOUTHBOUND_INSTALL_FAILURE: | |
704 | zsend_ipset_entry_notify_owner(ipset, | |
705 | ZAPI_IPSET_ENTRY_FAIL_INSTALL); | |
706 | break; | |
707 | case SOUTHBOUND_DELETE_SUCCESS: | |
4c550bcf PG |
708 | zsend_ipset_entry_notify_owner(ipset, |
709 | ZAPI_IPSET_ENTRY_REMOVED); | |
710 | break; | |
425bdd6b | 711 | case SOUTHBOUND_DELETE_FAILURE: |
4c550bcf | 712 | zsend_ipset_entry_notify_owner(ipset, |
34d9d5be | 713 | ZAPI_IPSET_ENTRY_FAIL_REMOVE); |
425bdd6b PG |
714 | break; |
715 | } | |
716 | } | |
717 | ||
7abd6c4f PG |
718 | /* |
719 | * Handle success or failure of ipset (un)install in the kernel. | |
720 | */ | |
721 | void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, | |
722 | enum southbound_results res) | |
723 | { | |
724 | switch (res) { | |
725 | case SOUTHBOUND_INSTALL_SUCCESS: | |
726 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED); | |
727 | break; | |
728 | case SOUTHBOUND_INSTALL_FAILURE: | |
729 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); | |
730 | break; | |
731 | case SOUTHBOUND_DELETE_SUCCESS: | |
4c550bcf PG |
732 | zsend_iptable_notify_owner(iptable, |
733 | ZAPI_IPTABLE_REMOVED); | |
734 | break; | |
7abd6c4f | 735 | case SOUTHBOUND_DELETE_FAILURE: |
4c550bcf | 736 | zsend_iptable_notify_owner(iptable, |
34d9d5be | 737 | ZAPI_IPTABLE_FAIL_REMOVE); |
7abd6c4f PG |
738 | break; |
739 | } | |
740 | } | |
741 | ||
942bf97b | 742 | /* |
743 | * Handle rule delete notification from kernel. | |
744 | */ | |
a0321978 | 745 | int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) |
942bf97b | 746 | { |
747 | return 0; | |
748 | } | |
586f4ccf PG |
749 | |
750 | struct zebra_pbr_ipset_entry_unique_display { | |
751 | struct zebra_pbr_ipset *zpi; | |
752 | struct vty *vty; | |
73a829f7 | 753 | struct zebra_ns *zns; |
586f4ccf PG |
754 | }; |
755 | ||
756 | struct zebra_pbr_env_display { | |
757 | struct zebra_ns *zns; | |
758 | struct vty *vty; | |
759 | }; | |
760 | ||
761 | static const char *zebra_pbr_prefix2str(union prefixconstptr pu, | |
762 | char *str, int size) | |
763 | { | |
764 | const struct prefix *p = pu.p; | |
765 | char buf[PREFIX2STR_BUFFER]; | |
766 | ||
767 | if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) { | |
768 | snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, | |
769 | buf, PREFIX2STR_BUFFER)); | |
770 | return str; | |
771 | } | |
772 | return prefix2str(pu, str, size); | |
773 | } | |
774 | ||
25d760c5 PG |
775 | static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, |
776 | uint16_t port_min, uint16_t port_max, | |
777 | uint8_t proto) | |
778 | { | |
779 | if (!(filter_bm & PBR_FILTER_PROTO)) { | |
780 | if (port_max) | |
781 | vty_out(vty, ":udp/tcp:%d-%d", | |
782 | port_min, port_max); | |
783 | else | |
784 | vty_out(vty, ":udp/tcp:%d", | |
785 | port_min); | |
786 | } else { | |
787 | if (port_max) | |
788 | vty_out(vty, ":proto %d:%d-%d", | |
789 | proto, port_min, port_max); | |
790 | else | |
791 | vty_out(vty, ":proto %d:%d", | |
792 | proto, port_min); | |
793 | } | |
794 | } | |
795 | ||
586f4ccf PG |
796 | static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, |
797 | void *arg) | |
798 | { | |
799 | struct zebra_pbr_ipset_entry_unique_display *unique = | |
800 | (struct zebra_pbr_ipset_entry_unique_display *)arg; | |
801 | struct zebra_pbr_ipset *zpi = unique->zpi; | |
802 | struct vty *vty = unique->vty; | |
803 | struct zebra_pbr_ipset_entry *zpie = | |
804 | (struct zebra_pbr_ipset_entry *)backet->data; | |
73a829f7 PG |
805 | uint64_t pkts = 0, bytes = 0; |
806 | struct zebra_ns *zns = unique->zns; | |
807 | int ret = 0; | |
586f4ccf PG |
808 | |
809 | if (zpie->backpointer != zpi) | |
810 | return HASHWALK_CONTINUE; | |
811 | ||
25d760c5 PG |
812 | if ((zpi->type == IPSET_NET_NET) || |
813 | (zpi->type == IPSET_NET_PORT_NET)) { | |
586f4ccf PG |
814 | char buf[PREFIX_STRLEN]; |
815 | ||
816 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
817 | vty_out(vty, "\tfrom %s", buf); | |
25d760c5 PG |
818 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT) |
819 | zebra_pbr_display_port(vty, zpie->filter_bm, | |
820 | zpie->src_port_min, | |
821 | zpie->src_port_max, | |
822 | zpie->proto); | |
586f4ccf PG |
823 | vty_out(vty, " to "); |
824 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
825 | vty_out(vty, "%s", buf); | |
25d760c5 PG |
826 | if (zpie->filter_bm & PBR_FILTER_DST_PORT) |
827 | zebra_pbr_display_port(vty, zpie->filter_bm, | |
828 | zpie->dst_port_min, | |
829 | zpie->dst_port_max, | |
830 | zpie->proto); | |
831 | } else if ((zpi->type == IPSET_NET) || | |
832 | (zpi->type == IPSET_NET_PORT)) { | |
586f4ccf PG |
833 | char buf[PREFIX_STRLEN]; |
834 | ||
835 | if (zpie->filter_bm & PBR_FILTER_SRC_IP) { | |
836 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
837 | vty_out(vty, "\tfrom %s", buf); | |
838 | } | |
25d760c5 PG |
839 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT) |
840 | zebra_pbr_display_port(vty, zpie->filter_bm, | |
841 | zpie->src_port_min, | |
842 | zpie->src_port_max, | |
843 | zpie->proto); | |
586f4ccf PG |
844 | if (zpie->filter_bm & PBR_FILTER_DST_IP) { |
845 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
846 | vty_out(vty, "\tto %s", buf); | |
847 | } | |
25d760c5 PG |
848 | if (zpie->filter_bm & PBR_FILTER_DST_PORT) |
849 | zebra_pbr_display_port(vty, zpie->filter_bm, | |
850 | zpie->dst_port_min, | |
851 | zpie->dst_port_max, | |
852 | zpie->proto); | |
586f4ccf PG |
853 | } |
854 | vty_out(vty, " (%u)\n", zpie->unique); | |
855 | ||
73a829f7 PG |
856 | ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat, |
857 | zns, zpie, &pkts, &bytes); | |
858 | if (ret && pkts > 0) | |
859 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
860 | pkts, bytes); | |
586f4ccf PG |
861 | return HASHWALK_CONTINUE; |
862 | } | |
863 | ||
864 | static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) | |
865 | { | |
866 | struct zebra_pbr_env_display *uniqueipset = | |
867 | (struct zebra_pbr_env_display *)arg; | |
868 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
869 | struct zebra_pbr_ipset_entry_unique_display unique; | |
870 | struct vty *vty = uniqueipset->vty; | |
871 | struct zebra_ns *zns = uniqueipset->zns; | |
872 | ||
873 | vty_out(vty, "IPset %s type %s\n", zpi->ipset_name, | |
874 | zebra_pbr_ipset_type2str(zpi->type)); | |
875 | unique.vty = vty; | |
876 | unique.zpi = zpi; | |
73a829f7 | 877 | unique.zns = zns; |
586f4ccf PG |
878 | hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb, |
879 | &unique); | |
880 | vty_out(vty, "\n"); | |
881 | return HASHWALK_CONTINUE; | |
882 | } | |
883 | ||
884 | /* | |
885 | */ | |
886 | void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) | |
887 | { | |
888 | struct zebra_pbr_ipset *zpi; | |
889 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
890 | struct zebra_pbr_ipset_entry_unique_display unique; | |
891 | struct zebra_pbr_env_display uniqueipset; | |
892 | ||
893 | if (ipsetname) { | |
894 | zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname); | |
895 | if (!zpi) { | |
896 | vty_out(vty, "No IPset %s found\n", ipsetname); | |
897 | return; | |
898 | } | |
899 | vty_out(vty, "IPset %s type %s\n", ipsetname, | |
900 | zebra_pbr_ipset_type2str(zpi->type)); | |
901 | ||
902 | unique.vty = vty; | |
903 | unique.zpi = zpi; | |
73a829f7 | 904 | unique.zns = zns; |
586f4ccf PG |
905 | hash_walk(zns->ipset_entry_hash, |
906 | zebra_pbr_show_ipset_entry_walkcb, | |
907 | &unique); | |
908 | return; | |
909 | } | |
910 | uniqueipset.zns = zns; | |
911 | uniqueipset.vty = vty; | |
912 | hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb, | |
913 | &uniqueipset); | |
914 | } | |
915 | ||
916 | struct pbr_rule_fwmark_lookup { | |
917 | struct zebra_pbr_rule *ptr; | |
918 | uint32_t fwmark; | |
919 | }; | |
920 | ||
921 | static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, | |
922 | void *arg) | |
923 | { | |
924 | struct pbr_rule_fwmark_lookup *iprule = | |
925 | (struct pbr_rule_fwmark_lookup *)arg; | |
926 | struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; | |
927 | ||
928 | if (iprule->fwmark == zpr->rule.filter.fwmark) { | |
929 | iprule->ptr = zpr; | |
930 | return HASHWALK_ABORT; | |
931 | } | |
932 | return HASHWALK_CONTINUE; | |
933 | } | |
934 | ||
935 | static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) | |
936 | { | |
937 | struct zebra_pbr_iptable *iptable = | |
938 | (struct zebra_pbr_iptable *)backet->data; | |
939 | struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; | |
940 | struct vty *vty = env->vty; | |
941 | struct zebra_ns *zns = env->zns; | |
73a829f7 PG |
942 | int ret; |
943 | uint64_t pkts = 0, bytes = 0; | |
586f4ccf PG |
944 | |
945 | vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, | |
946 | iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", | |
947 | iptable->unique); | |
948 | ||
73a829f7 PG |
949 | ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat, |
950 | zns, iptable, &pkts, &bytes); | |
951 | if (ret && pkts > 0) | |
952 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
953 | pkts, bytes); | |
586f4ccf PG |
954 | if (iptable->action != ZEBRA_IPTABLES_DROP) { |
955 | struct pbr_rule_fwmark_lookup prfl; | |
956 | ||
957 | prfl.fwmark = iptable->fwmark; | |
958 | prfl.ptr = NULL; | |
959 | hash_walk(zns->rules_hash, | |
960 | &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl); | |
961 | if (prfl.ptr) { | |
962 | struct zebra_pbr_rule *zpr = prfl.ptr; | |
963 | ||
964 | vty_out(vty, "\t table %u, fwmark %u\n", | |
965 | zpr->rule.action.table, | |
966 | prfl.fwmark); | |
967 | } | |
968 | } | |
969 | return HASHWALK_CONTINUE; | |
970 | } | |
971 | ||
972 | void zebra_pbr_show_iptable(struct vty *vty) | |
973 | { | |
974 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
975 | struct zebra_pbr_env_display env; | |
976 | ||
977 | env.vty = vty; | |
978 | env.zns = zns; | |
979 | ||
980 | hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb, | |
981 | &env); | |
982 | } | |
f80ec7e3 PG |
983 | |
984 | void zebra_pbr_iptable_update_interfacelist(struct stream *s, | |
985 | struct zebra_pbr_iptable *zpi) | |
986 | { | |
987 | uint32_t i = 0, index; | |
988 | struct interface *ifp; | |
989 | char *name; | |
990 | ||
991 | for (i = 0; i < zpi->nb_interface; i++) { | |
992 | STREAM_GETL(s, index); | |
993 | ifp = if_lookup_by_index(index, zpi->vrf_id); | |
994 | if (!ifp) | |
995 | continue; | |
996 | name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name); | |
997 | listnode_add(zpi->interface_name_list, name); | |
998 | } | |
999 | stream_failure: | |
1000 | return; | |
1001 | } |