Line data Source code
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 :
24 : #include <jhash.h>
25 : #include <hash.h>
26 : #include <memory.h>
27 : #include <hook.h>
28 :
29 : #include "zebra/zebra_router.h"
30 : #include "zebra/zebra_pbr.h"
31 : #include "zebra/rt.h"
32 : #include "zebra/zapi_msg.h"
33 : #include "zebra/zserv.h"
34 : #include "zebra/debug.h"
35 : #include "zebra/zebra_neigh.h"
36 :
37 : /* definitions */
38 6 : DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
39 6 : DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
40 :
41 : /* definitions */
42 : static const struct message ipset_type_msg[] = {
43 : {IPSET_NET_PORT_NET, "net,port,net"},
44 : {IPSET_NET_PORT, "net,port"},
45 : {IPSET_NET_NET, "net,net"},
46 : {IPSET_NET, "net"},
47 : {0}
48 : };
49 :
50 : const struct message icmp_typecode_str[] = {
51 : { 0 << 8, "echo-reply"},
52 : { 0 << 8, "pong"},
53 : { 3 << 8, "network-unreachable"},
54 : { (3 << 8) + 1, "host-unreachable"},
55 : { (3 << 8) + 2, "protocol-unreachable"},
56 : { (3 << 8) + 3, "port-unreachable"},
57 : { (3 << 8) + 4, "fragmentation-needed"},
58 : { (3 << 8) + 5, "source-route-failed"},
59 : { (3 << 8) + 6, "network-unknown"},
60 : { (3 << 8) + 7, "host-unknown"},
61 : { (3 << 8) + 9, "network-prohibited"},
62 : { (3 << 8) + 10, "host-prohibited"},
63 : { (3 << 8) + 11, "TOS-network-unreachable"},
64 : { (3 << 8) + 12, "TOS-host-unreachable"},
65 : { (3 << 8) + 13, "communication-prohibited"},
66 : { (3 << 8) + 14, "host-precedence-violation"},
67 : { (3 << 8) + 15, "precedence-cutoff"},
68 : { 4 << 8, "source-quench"},
69 : { 5 << 8, "network-redirect"},
70 : { (5 << 8) + 1, "host-redirect"},
71 : { (5 << 8) + 2, "TOS-network-redirect"},
72 : { (5 << 8) + 3, "TOS-host-redirect"},
73 : { 8 << 8, "echo-request"},
74 : { 8 << 8, "ping"},
75 : { 9 << 8, "router-advertisement"},
76 : { 10 << 8, "router-solicitation"},
77 : { 11 << 8, "ttl-zero-during-transit"},
78 : { (11 << 8) + 1, "ttl-zero-during-reassembly"},
79 : { 12 << 8, "ip-header-bad"},
80 : { (12 << 8) + 1, "required-option-missing"},
81 : { 13 << 8, "timestamp-request"},
82 : { 14 << 8, "timestamp-reply"},
83 : { 17 << 8, "address-mask-request"},
84 : { 18 << 8, "address-mask-reply"},
85 : {0}
86 : };
87 :
88 : const struct message icmpv6_typecode_str[] = {
89 : { 128 << 8, "echo-request"},
90 : { 129 << 8, "echo-reply"},
91 : { 1 << 8, "no-route"},
92 : { (1 << 8) + 1, "communication-prohibited"},
93 : { (1 << 8) + 3, "address-unreachable"},
94 : { (1 << 8) + 4, "port-unreachable"},
95 : { (2 << 8), "packet-too-big"},
96 : { 3 << 0, "ttl-zero-during-transit"},
97 : { (3 << 8) + 1, "ttl-zero-during-reassembly"},
98 : { 4 << 0, "bad-header"},
99 : { (4 << 0) + 1, "unknown-header-type"},
100 : { (4 << 0) + 2, "unknown-option"},
101 : { 133 << 8, "router-solicitation"},
102 : { 134 << 8, "router-advertisement"},
103 : { 135 << 8, "neighbor-solicitation"},
104 : { 136 << 8, "neighbor-advertisement"},
105 : { 137 << 8, "redirect"},
106 : {0}
107 : };
108 :
109 : /* definitions */
110 : static const struct message tcp_value_str[] = {
111 : {TCP_HEADER_FIN, "FIN"},
112 : {TCP_HEADER_SYN, "SYN"},
113 : {TCP_HEADER_RST, "RST"},
114 : {TCP_HEADER_PSH, "PSH"},
115 : {TCP_HEADER_ACK, "ACK"},
116 : {TCP_HEADER_URG, "URG"},
117 : {0}
118 : };
119 :
120 : static const struct message fragment_value_str[] = {
121 : {1, "dont-fragment"},
122 : {2, "is-fragment"},
123 : {4, "first-fragment"},
124 : {8, "last-fragment"},
125 : {0}
126 : };
127 :
128 : struct zebra_pbr_env_display {
129 : struct zebra_ns *zns;
130 : struct vty *vty;
131 : char *name;
132 : };
133 :
134 : /* static function declarations */
135 0 : DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
136 : (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
137 : uint64_t *bytes),
138 : (ipset, pkts, bytes));
139 :
140 0 : DEFINE_HOOK(zebra_pbr_iptable_get_stat,
141 : (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
142 : uint64_t *bytes),
143 : (iptable, pkts, bytes));
144 :
145 0 : DEFINE_HOOK(zebra_pbr_iptable_update,
146 : (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
147 :
148 0 : DEFINE_HOOK(zebra_pbr_ipset_entry_update,
149 : (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset));
150 :
151 0 : DEFINE_HOOK(zebra_pbr_ipset_update,
152 : (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
153 :
154 : /* resolve nexthop for dataplane (dpdk) programming */
155 : static bool zebra_pbr_expand_action;
156 :
157 : /* Private functions */
158 :
159 : /* Public functions */
160 0 : void zebra_pbr_rules_free(void *arg)
161 : {
162 0 : struct zebra_pbr_rule *rule;
163 :
164 0 : rule = (struct zebra_pbr_rule *)arg;
165 :
166 0 : (void)dplane_pbr_rule_delete(rule);
167 0 : XFREE(MTYPE_PBR_OBJ, rule);
168 0 : }
169 :
170 0 : uint32_t zebra_pbr_rules_hash_key(const void *arg)
171 : {
172 0 : const struct zebra_pbr_rule *rule;
173 0 : uint32_t key;
174 :
175 0 : rule = arg;
176 0 : key = jhash_3words(rule->rule.seq, rule->rule.priority,
177 0 : rule->rule.action.table,
178 0 : prefix_hash_key(&rule->rule.filter.src_ip));
179 :
180 0 : key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
181 0 : rule->rule.filter.ip_proto, key);
182 :
183 0 : key = jhash(rule->ifname, strlen(rule->ifname), key);
184 :
185 0 : return jhash_3words(rule->rule.filter.src_port,
186 0 : rule->rule.filter.dst_port,
187 0 : prefix_hash_key(&rule->rule.filter.dst_ip),
188 0 : jhash_1word(rule->rule.unique, key));
189 : }
190 :
191 0 : bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
192 : {
193 0 : const struct zebra_pbr_rule *r1, *r2;
194 :
195 0 : r1 = (const struct zebra_pbr_rule *)arg1;
196 0 : r2 = (const struct zebra_pbr_rule *)arg2;
197 :
198 0 : if (r1->rule.seq != r2->rule.seq)
199 : return false;
200 :
201 0 : if (r1->rule.priority != r2->rule.priority)
202 : return false;
203 :
204 0 : if (r1->rule.unique != r2->rule.unique)
205 : return false;
206 :
207 0 : if (r1->rule.action.table != r2->rule.action.table)
208 : return false;
209 :
210 0 : if (r1->rule.filter.src_port != r2->rule.filter.src_port)
211 : return false;
212 :
213 0 : if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
214 : return false;
215 :
216 0 : if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
217 : return false;
218 :
219 0 : if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto)
220 : return false;
221 :
222 0 : if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
223 : return false;
224 :
225 0 : if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
226 : return false;
227 :
228 0 : if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0)
229 : return false;
230 :
231 0 : if (r1->vrf_id != r2->vrf_id)
232 : return false;
233 :
234 : return true;
235 : }
236 :
237 : struct pbr_rule_unique_lookup {
238 : struct zebra_pbr_rule *rule;
239 : uint32_t unique;
240 : char ifname[INTERFACE_NAMSIZ + 1];
241 : vrf_id_t vrf_id;
242 : };
243 :
244 0 : static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
245 : {
246 0 : struct pbr_rule_unique_lookup *pul = data;
247 0 : struct zebra_pbr_rule *rule = b->data;
248 :
249 0 : if (pul->unique == rule->rule.unique
250 0 : && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0
251 0 : && pul->vrf_id == rule->vrf_id) {
252 0 : pul->rule = rule;
253 0 : return HASHWALK_ABORT;
254 : }
255 :
256 : return HASHWALK_CONTINUE;
257 : }
258 :
259 : static struct zebra_pbr_rule *
260 0 : pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
261 : {
262 0 : struct pbr_rule_unique_lookup pul;
263 :
264 0 : pul.unique = zrule->rule.unique;
265 0 : strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ);
266 0 : pul.rule = NULL;
267 0 : pul.vrf_id = zrule->vrf_id;
268 0 : hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
269 :
270 0 : return pul.rule;
271 : }
272 :
273 0 : void zebra_pbr_ipset_free(void *arg)
274 : {
275 0 : struct zebra_pbr_ipset *ipset;
276 :
277 0 : ipset = (struct zebra_pbr_ipset *)arg;
278 0 : hook_call(zebra_pbr_ipset_update, 0, ipset);
279 0 : XFREE(MTYPE_PBR_OBJ, ipset);
280 0 : }
281 :
282 0 : uint32_t zebra_pbr_ipset_hash_key(const void *arg)
283 : {
284 0 : const struct zebra_pbr_ipset *ipset = arg;
285 0 : uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
286 0 : uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
287 :
288 0 : key = jhash_1word(ipset->family, key);
289 :
290 0 : return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key);
291 : }
292 :
293 0 : bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
294 : {
295 0 : const struct zebra_pbr_ipset *r1, *r2;
296 :
297 0 : r1 = (const struct zebra_pbr_ipset *)arg1;
298 0 : r2 = (const struct zebra_pbr_ipset *)arg2;
299 :
300 0 : if (r1->type != r2->type)
301 : return false;
302 0 : if (r1->unique != r2->unique)
303 : return false;
304 0 : if (r1->vrf_id != r2->vrf_id)
305 : return false;
306 0 : if (r1->family != r2->family)
307 : return false;
308 :
309 0 : if (strncmp(r1->ipset_name, r2->ipset_name,
310 : ZEBRA_IPSET_NAME_SIZE))
311 0 : return false;
312 : return true;
313 : }
314 :
315 0 : void zebra_pbr_ipset_entry_free(void *arg)
316 : {
317 0 : struct zebra_pbr_ipset_entry *ipset;
318 :
319 0 : ipset = (struct zebra_pbr_ipset_entry *)arg;
320 :
321 0 : hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
322 :
323 0 : XFREE(MTYPE_PBR_OBJ, ipset);
324 0 : }
325 :
326 0 : uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
327 : {
328 0 : const struct zebra_pbr_ipset_entry *ipset;
329 0 : uint32_t key;
330 :
331 0 : ipset = arg;
332 0 : key = prefix_hash_key(&ipset->src);
333 0 : key = jhash_1word(ipset->unique, key);
334 0 : key = jhash_1word(prefix_hash_key(&ipset->dst), key);
335 0 : key = jhash(&ipset->dst_port_min, 2, key);
336 0 : key = jhash(&ipset->dst_port_max, 2, key);
337 0 : key = jhash(&ipset->src_port_min, 2, key);
338 0 : key = jhash(&ipset->src_port_max, 2, key);
339 0 : key = jhash(&ipset->proto, 1, key);
340 :
341 0 : return key;
342 : }
343 :
344 0 : bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
345 : {
346 0 : const struct zebra_pbr_ipset_entry *r1, *r2;
347 :
348 0 : r1 = (const struct zebra_pbr_ipset_entry *)arg1;
349 0 : r2 = (const struct zebra_pbr_ipset_entry *)arg2;
350 :
351 0 : if (r1->unique != r2->unique)
352 : return false;
353 :
354 0 : if (!prefix_same(&r1->src, &r2->src))
355 : return false;
356 :
357 0 : if (!prefix_same(&r1->dst, &r2->dst))
358 : return false;
359 :
360 0 : if (r1->src_port_min != r2->src_port_min)
361 : return false;
362 :
363 0 : if (r1->src_port_max != r2->src_port_max)
364 : return false;
365 :
366 0 : if (r1->dst_port_min != r2->dst_port_min)
367 : return false;
368 :
369 0 : if (r1->dst_port_max != r2->dst_port_max)
370 : return false;
371 :
372 0 : if (r1->proto != r2->proto)
373 : return false;
374 : return true;
375 : }
376 :
377 : /* this function gives option to flush plugin memory contexts
378 : * with all parameter. set it to true to flush all
379 : * set it to false to flush only passed arg argument
380 : */
381 0 : static void _zebra_pbr_iptable_free_all(void *arg, bool all)
382 : {
383 0 : struct zebra_pbr_iptable *iptable;
384 0 : struct listnode *node, *nnode;
385 0 : char *name;
386 :
387 0 : iptable = (struct zebra_pbr_iptable *)arg;
388 :
389 0 : if (all)
390 0 : hook_call(zebra_pbr_iptable_update, 0, iptable);
391 :
392 0 : if (iptable->interface_name_list) {
393 0 : for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node,
394 : nnode, name)) {
395 0 : XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
396 0 : list_delete_node(iptable->interface_name_list, node);
397 : }
398 0 : list_delete(&iptable->interface_name_list);
399 : }
400 0 : XFREE(MTYPE_PBR_OBJ, iptable);
401 0 : }
402 :
403 0 : void zebra_pbr_iptable_free(void *arg)
404 : {
405 0 : _zebra_pbr_iptable_free_all(arg, false);
406 0 : }
407 :
408 0 : uint32_t zebra_pbr_iptable_hash_key(const void *arg)
409 : {
410 0 : const struct zebra_pbr_iptable *iptable = arg;
411 0 : uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
412 0 : uint32_t key;
413 :
414 0 : key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
415 : 0x63ab42de);
416 0 : key = jhash_1word(iptable->fwmark, key);
417 0 : key = jhash_1word(iptable->family, key);
418 0 : key = jhash_1word(iptable->flow_label, key);
419 0 : key = jhash_1word(iptable->pkt_len_min, key);
420 0 : key = jhash_1word(iptable->pkt_len_max, key);
421 0 : key = jhash_1word(iptable->tcp_flags, key);
422 0 : key = jhash_1word(iptable->tcp_mask_flags, key);
423 0 : key = jhash_1word(iptable->dscp_value, key);
424 0 : key = jhash_1word(iptable->protocol, key);
425 0 : key = jhash_1word(iptable->fragment, key);
426 0 : key = jhash_1word(iptable->vrf_id, key);
427 :
428 0 : return jhash_3words(iptable->filter_bm, iptable->type,
429 0 : iptable->unique, key);
430 : }
431 :
432 0 : bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
433 : {
434 0 : const struct zebra_pbr_iptable *r1, *r2;
435 :
436 0 : r1 = (const struct zebra_pbr_iptable *)arg1;
437 0 : r2 = (const struct zebra_pbr_iptable *)arg2;
438 :
439 0 : if (r1->vrf_id != r2->vrf_id)
440 : return false;
441 0 : if (r1->type != r2->type)
442 : return false;
443 0 : if (r1->unique != r2->unique)
444 : return false;
445 0 : if (r1->filter_bm != r2->filter_bm)
446 : return false;
447 0 : if (r1->fwmark != r2->fwmark)
448 : return false;
449 0 : if (r1->action != r2->action)
450 : return false;
451 0 : if (strncmp(r1->ipset_name, r2->ipset_name,
452 : ZEBRA_IPSET_NAME_SIZE))
453 : return false;
454 0 : if (r1->family != r2->family)
455 : return false;
456 0 : if (r1->flow_label != r2->flow_label)
457 : return false;
458 0 : if (r1->pkt_len_min != r2->pkt_len_min)
459 : return false;
460 0 : if (r1->pkt_len_max != r2->pkt_len_max)
461 : return false;
462 0 : if (r1->tcp_flags != r2->tcp_flags)
463 : return false;
464 0 : if (r1->tcp_mask_flags != r2->tcp_mask_flags)
465 : return false;
466 0 : if (r1->dscp_value != r2->dscp_value)
467 : return false;
468 0 : if (r1->fragment != r2->fragment)
469 : return false;
470 0 : if (r1->protocol != r2->protocol)
471 0 : return false;
472 : return true;
473 : }
474 :
475 0 : static void *pbr_rule_alloc_intern(void *arg)
476 : {
477 0 : struct zebra_pbr_rule *zpr;
478 0 : struct zebra_pbr_rule *new;
479 :
480 0 : zpr = (struct zebra_pbr_rule *)arg;
481 :
482 0 : new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
483 :
484 0 : memcpy(new, zpr, sizeof(*zpr));
485 :
486 0 : return new;
487 : }
488 :
489 0 : static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
490 : bool free_data)
491 : {
492 0 : if (hash_data->action.neigh)
493 0 : zebra_neigh_deref(hash_data);
494 0 : hash_release(zrouter.rules_hash, hash_data);
495 0 : if (free_data) {
496 0 : XFREE(MTYPE_PBR_OBJ, hash_data);
497 0 : return NULL;
498 : }
499 :
500 : return hash_data;
501 : }
502 :
503 0 : static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule,
504 : bool free_data)
505 : {
506 0 : struct zebra_pbr_rule *lookup;
507 :
508 0 : lookup = hash_lookup(zrouter.rules_hash, rule);
509 :
510 0 : if (!lookup)
511 : return NULL;
512 :
513 0 : return pbr_rule_free(lookup, free_data);
514 : }
515 :
516 0 : void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
517 : {
518 0 : struct pbr_rule *prule = &rule->rule;
519 0 : struct zebra_pbr_action *zaction = &rule->action;
520 :
521 0 : vty_out(vty, "Rules if %s\n", rule->ifname);
522 0 : vty_out(vty, " Seq %u pri %u\n", prule->seq, prule->priority);
523 0 : if (prule->filter.filter_bm & PBR_FILTER_SRC_IP)
524 0 : vty_out(vty, " SRC IP Match: %pFX\n", &prule->filter.src_ip);
525 0 : if (prule->filter.filter_bm & PBR_FILTER_DST_IP)
526 0 : vty_out(vty, " DST IP Match: %pFX\n", &prule->filter.dst_ip);
527 0 : if (prule->filter.filter_bm & PBR_FILTER_IP_PROTOCOL)
528 0 : vty_out(vty, " IP protocol Match: %u\n",
529 0 : prule->filter.ip_proto);
530 0 : if (prule->filter.filter_bm & PBR_FILTER_SRC_PORT)
531 0 : vty_out(vty, " SRC Port Match: %u\n", prule->filter.src_port);
532 0 : if (prule->filter.filter_bm & PBR_FILTER_DST_PORT)
533 0 : vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port);
534 :
535 0 : if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) {
536 0 : vty_out(vty, " DSCP Match: %u\n",
537 0 : (prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2);
538 0 : vty_out(vty, " ECN Match: %u\n",
539 0 : prule->filter.dsfield & PBR_DSFIELD_ECN);
540 : }
541 :
542 0 : if (prule->filter.filter_bm & PBR_FILTER_FWMARK)
543 0 : vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark);
544 :
545 0 : vty_out(vty, " Tableid: %u\n", prule->action.table);
546 0 : if (zaction->afi == AFI_IP)
547 0 : vty_out(vty, " Action: nh: %pI4 intf: %s\n",
548 : &zaction->gate.ipv4,
549 : ifindex2ifname(zaction->ifindex, rule->vrf_id));
550 0 : if (zaction->afi == AFI_IP6)
551 0 : vty_out(vty, " Action: nh: %pI6 intf: %s\n",
552 : &zaction->gate.ipv6,
553 : ifindex2ifname(zaction->ifindex, rule->vrf_id));
554 0 : if (zaction->neigh && (zaction->neigh->flags & ZEBRA_NEIGH_ENT_ACTIVE))
555 0 : vty_out(vty, " Action: mac: %pEA\n", &zaction->neigh->mac);
556 0 : }
557 :
558 0 : static int zebra_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
559 : {
560 0 : struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
561 0 : struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
562 0 : struct vty *vty = env->vty;
563 :
564 0 : zebra_pbr_show_rule_unit(rule, vty);
565 :
566 0 : return HASHWALK_CONTINUE;
567 : }
568 :
569 0 : void zebra_pbr_show_rule(struct vty *vty)
570 : {
571 0 : struct zebra_pbr_env_display env;
572 :
573 0 : env.vty = vty;
574 0 : hash_walk(zrouter.rules_hash, zebra_pbr_show_rules_walkcb, &env);
575 0 : }
576 :
577 0 : void zebra_pbr_config_write(struct vty *vty)
578 : {
579 0 : if (zebra_pbr_expand_action)
580 0 : vty_out(vty, "pbr nexthop-resolve\n");
581 0 : }
582 :
583 0 : void zebra_pbr_expand_action_update(bool enable)
584 : {
585 0 : zebra_pbr_expand_action = enable;
586 0 : }
587 :
588 0 : static void zebra_pbr_expand_rule(struct zebra_pbr_rule *rule)
589 : {
590 0 : struct prefix p;
591 0 : struct route_table *table;
592 0 : struct route_node *rn;
593 0 : rib_dest_t *dest;
594 0 : struct route_entry *re;
595 0 : const struct nexthop_group *nhg;
596 0 : const struct nexthop *nexthop;
597 0 : struct zebra_pbr_action *action = &rule->action;
598 0 : struct ipaddr ip;
599 :
600 0 : if (!zebra_pbr_expand_action)
601 0 : return;
602 :
603 0 : table = zebra_vrf_get_table_with_table_id(
604 : AFI_IP, SAFI_UNICAST, VRF_DEFAULT, rule->rule.action.table);
605 0 : if (!table)
606 : return;
607 :
608 0 : memset(&p, 0, sizeof(p));
609 0 : p.family = AF_INET;
610 :
611 0 : rn = route_node_lookup(table, &p);
612 0 : if (!rn)
613 : return;
614 :
615 0 : dest = rib_dest_from_rnode(rn);
616 0 : re = dest->selected_fib;
617 0 : if (!re) {
618 0 : route_unlock_node(rn);
619 0 : return;
620 : }
621 :
622 0 : nhg = rib_get_fib_nhg(re);
623 0 : if (!nhg) {
624 : route_unlock_node(rn);
625 : return;
626 : }
627 :
628 0 : nexthop = nhg->nexthop;
629 0 : if (nexthop) {
630 0 : switch (nexthop->type) {
631 0 : case NEXTHOP_TYPE_IPV4:
632 : case NEXTHOP_TYPE_IPV4_IFINDEX:
633 0 : action->afi = AFI_IP;
634 0 : action->gate.ipv4 = nexthop->gate.ipv4;
635 0 : action->ifindex = nexthop->ifindex;
636 0 : ip.ipa_type = AF_INET;
637 0 : ip.ipaddr_v4 = action->gate.ipv4;
638 0 : zebra_neigh_ref(action->ifindex, &ip, rule);
639 0 : break;
640 :
641 0 : case NEXTHOP_TYPE_IPV6:
642 : case NEXTHOP_TYPE_IPV6_IFINDEX:
643 0 : action->afi = AFI_IP6;
644 0 : action->gate.ipv6 = nexthop->gate.ipv6;
645 0 : action->ifindex = nexthop->ifindex;
646 0 : ip.ipa_type = AF_INET6;
647 0 : ip.ipaddr_v6 = action->gate.ipv6;
648 0 : zebra_neigh_ref(action->ifindex, &ip, rule);
649 0 : break;
650 :
651 0 : case NEXTHOP_TYPE_BLACKHOLE:
652 : case NEXTHOP_TYPE_IFINDEX:
653 0 : action->afi = AFI_UNSPEC;
654 : }
655 : }
656 :
657 0 : route_unlock_node(rn);
658 : }
659 :
660 0 : void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
661 : {
662 0 : struct zebra_pbr_rule *found;
663 0 : struct zebra_pbr_rule *old;
664 0 : struct zebra_pbr_rule *new;
665 :
666 : /**
667 : * Check if we already have it (this checks via a unique ID, walking
668 : * over the hash table, not via a hash operation).
669 : */
670 0 : found = pbr_rule_lookup_unique(rule);
671 :
672 : /* If found, this is an update */
673 0 : if (found) {
674 0 : if (IS_ZEBRA_DEBUG_PBR)
675 0 : zlog_debug(
676 : "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- update",
677 : __func__, rule->rule.seq, rule->rule.priority,
678 : rule->rule.unique, rule->rule.ifname);
679 :
680 : /* remove the old entry from the hash but don't free the hash
681 : * data yet as we need it for the dplane update
682 : */
683 0 : old = pbr_rule_release(found, false);
684 :
685 : /* insert new entry into hash */
686 0 : new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
687 : /* expand the action if needed */
688 0 : zebra_pbr_expand_rule(new);
689 : /* update dataplane */
690 0 : (void)dplane_pbr_rule_update(found, new);
691 : /* release the old hash data */
692 0 : if (old)
693 0 : XFREE(MTYPE_PBR_OBJ, old);
694 : } else {
695 0 : if (IS_ZEBRA_DEBUG_PBR)
696 0 : zlog_debug(
697 : "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- new",
698 : __func__, rule->rule.seq, rule->rule.priority,
699 : rule->rule.unique, rule->rule.ifname);
700 :
701 : /* insert new entry into hash */
702 0 : new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
703 : /* expand the action if needed */
704 0 : zebra_pbr_expand_rule(new);
705 0 : (void)dplane_pbr_rule_add(new);
706 : }
707 :
708 0 : }
709 :
710 0 : void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
711 : {
712 0 : if (IS_ZEBRA_DEBUG_PBR)
713 0 : zlog_debug("%s: seq: %d, prior: %d, unique: %d, ifname: %s",
714 : __func__, rule->rule.seq, rule->rule.priority,
715 : rule->rule.unique, rule->rule.ifname);
716 :
717 0 : (void)dplane_pbr_rule_delete(rule);
718 :
719 0 : if (pbr_rule_release(rule, true))
720 0 : zlog_debug("%s: Rule being deleted we know nothing about",
721 : __func__);
722 0 : }
723 :
724 0 : void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx)
725 : {
726 0 : int mode, ret = 0;
727 0 : struct zebra_pbr_iptable ipt;
728 :
729 0 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD)
730 : mode = 1;
731 : else
732 0 : mode = 0;
733 :
734 0 : dplane_ctx_get_pbr_iptable(ctx, &ipt);
735 :
736 0 : ret = hook_call(zebra_pbr_iptable_update, mode, &ipt);
737 0 : if (ret)
738 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
739 : else
740 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
741 0 : }
742 :
743 0 : void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx)
744 : {
745 0 : int mode, ret = 0;
746 0 : struct zebra_pbr_ipset ipset;
747 :
748 0 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD)
749 : mode = 1;
750 : else
751 0 : mode = 0;
752 :
753 0 : dplane_ctx_get_pbr_ipset(ctx, &ipset);
754 :
755 0 : ret = hook_call(zebra_pbr_ipset_update, mode, &ipset);
756 0 : if (ret)
757 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
758 : else
759 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
760 0 : }
761 :
762 0 : void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx)
763 : {
764 0 : int mode, ret = 0;
765 0 : struct zebra_pbr_ipset_entry ipset_entry;
766 0 : struct zebra_pbr_ipset ipset;
767 :
768 0 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD)
769 : mode = 1;
770 : else
771 0 : mode = 0;
772 :
773 0 : dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry);
774 0 : dplane_ctx_get_pbr_ipset(ctx, &ipset);
775 :
776 0 : ipset_entry.backpointer = &ipset;
777 :
778 0 : ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry);
779 0 : if (ret)
780 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
781 : else
782 0 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
783 0 : }
784 :
785 0 : static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
786 : {
787 0 : struct zebra_pbr_rule *rule = b->data;
788 0 : int *sock = data;
789 :
790 0 : if (rule->sock == *sock) {
791 0 : (void)dplane_pbr_rule_delete(rule);
792 0 : pbr_rule_free(rule, true);
793 : }
794 0 : }
795 :
796 0 : static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
797 : {
798 0 : struct zebra_pbr_ipset *ipset = b->data;
799 0 : int *sock = data;
800 :
801 0 : if (ipset->sock == *sock) {
802 0 : if (hash_release(zrouter.ipset_hash, ipset))
803 0 : zebra_pbr_ipset_free(ipset);
804 : else
805 0 : hook_call(zebra_pbr_ipset_update, 0, ipset);
806 : }
807 0 : }
808 :
809 0 : static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
810 : {
811 0 : struct zebra_pbr_ipset_entry *ipset = b->data;
812 0 : int *sock = data;
813 :
814 0 : if (ipset->sock == *sock) {
815 0 : if (hash_release(zrouter.ipset_entry_hash, ipset))
816 0 : zebra_pbr_ipset_entry_free(ipset);
817 : else
818 0 : hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
819 : }
820 0 : }
821 :
822 0 : static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
823 : {
824 0 : struct zebra_pbr_iptable *iptable = b->data;
825 0 : int *sock = data;
826 :
827 0 : if (iptable->sock == *sock) {
828 0 : if (hash_release(zrouter.iptable_hash, iptable))
829 0 : _zebra_pbr_iptable_free_all(iptable, true);
830 : else
831 0 : hook_call(zebra_pbr_iptable_update, 0, iptable);
832 : }
833 0 : }
834 :
835 4 : static int zebra_pbr_client_close_cleanup(struct zserv *client)
836 : {
837 4 : int sock = client->sock;
838 :
839 4 : if (!sock)
840 : return 0;
841 4 : hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock);
842 4 : hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock);
843 4 : hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry,
844 : &sock);
845 4 : hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock);
846 4 : return 1;
847 : }
848 :
849 2 : void zebra_pbr_init(void)
850 : {
851 2 : hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
852 2 : }
853 :
854 0 : static void *pbr_ipset_alloc_intern(void *arg)
855 : {
856 0 : struct zebra_pbr_ipset *zpi;
857 0 : struct zebra_pbr_ipset *new;
858 :
859 0 : zpi = (struct zebra_pbr_ipset *)arg;
860 :
861 0 : new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
862 :
863 0 : memcpy(new, zpi, sizeof(*zpi));
864 :
865 0 : return new;
866 : }
867 :
868 0 : void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset)
869 : {
870 0 : (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern);
871 0 : (void)dplane_pbr_ipset_add(ipset);
872 0 : }
873 :
874 0 : void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
875 : {
876 0 : struct zebra_pbr_ipset *lookup;
877 :
878 0 : lookup = hash_lookup(zrouter.ipset_hash, ipset);
879 0 : (void)dplane_pbr_ipset_delete(ipset);
880 0 : if (lookup) {
881 0 : hash_release(zrouter.ipset_hash, lookup);
882 0 : XFREE(MTYPE_PBR_OBJ, lookup);
883 : } else
884 0 : zlog_debug(
885 : "%s: IPSet Entry being deleted we know nothing about",
886 : __func__);
887 0 : }
888 :
889 : struct pbr_ipset_name_lookup {
890 : struct zebra_pbr_ipset *ipset;
891 : char ipset_name[ZEBRA_IPSET_NAME_SIZE];
892 : };
893 :
894 0 : const char *zebra_pbr_ipset_type2str(uint32_t type)
895 : {
896 0 : return lookup_msg(ipset_type_msg, type,
897 : "Unrecognized IPset Type");
898 : }
899 :
900 0 : static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg)
901 : {
902 0 : struct pbr_ipset_name_lookup *pinl =
903 : (struct pbr_ipset_name_lookup *)arg;
904 0 : struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
905 :
906 0 : if (!strncmp(pinl->ipset_name, zpi->ipset_name,
907 : ZEBRA_IPSET_NAME_SIZE)) {
908 0 : pinl->ipset = zpi;
909 0 : return HASHWALK_ABORT;
910 : }
911 : return HASHWALK_CONTINUE;
912 : }
913 :
914 0 : struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname)
915 : {
916 0 : struct pbr_ipset_name_lookup pinl;
917 0 : struct pbr_ipset_name_lookup *ptr = &pinl;
918 :
919 0 : if (!ipsetname)
920 : return NULL;
921 0 : memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
922 0 : snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
923 : ipsetname);
924 0 : hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
925 0 : return ptr->ipset;
926 : }
927 :
928 0 : static void *pbr_ipset_entry_alloc_intern(void *arg)
929 : {
930 0 : struct zebra_pbr_ipset_entry *zpi;
931 0 : struct zebra_pbr_ipset_entry *new;
932 :
933 0 : zpi = (struct zebra_pbr_ipset_entry *)arg;
934 :
935 0 : new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
936 :
937 0 : memcpy(new, zpi, sizeof(*zpi));
938 :
939 0 : return new;
940 : }
941 :
942 0 : void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
943 : {
944 0 : (void)hash_get(zrouter.ipset_entry_hash, ipset,
945 : pbr_ipset_entry_alloc_intern);
946 0 : (void)dplane_pbr_ipset_entry_add(ipset);
947 0 : }
948 :
949 0 : void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
950 : {
951 0 : struct zebra_pbr_ipset_entry *lookup;
952 :
953 0 : lookup = hash_lookup(zrouter.ipset_entry_hash, ipset);
954 0 : (void)dplane_pbr_ipset_entry_delete(ipset);
955 0 : if (lookup) {
956 0 : hash_release(zrouter.ipset_entry_hash, lookup);
957 0 : XFREE(MTYPE_PBR_OBJ, lookup);
958 : } else
959 0 : zlog_debug("%s: IPSet being deleted we know nothing about",
960 : __func__);
961 0 : }
962 :
963 0 : static void *pbr_iptable_alloc_intern(void *arg)
964 : {
965 0 : struct zebra_pbr_iptable *zpi;
966 0 : struct zebra_pbr_iptable *new;
967 0 : struct listnode *ln;
968 0 : char *ifname;
969 :
970 0 : zpi = (struct zebra_pbr_iptable *)arg;
971 :
972 0 : new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
973 :
974 : /* Deep structure copy */
975 0 : memcpy(new, zpi, sizeof(*zpi));
976 0 : new->interface_name_list = list_new();
977 :
978 0 : if (zpi->interface_name_list) {
979 0 : for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname))
980 0 : listnode_add(new->interface_name_list,
981 : XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname));
982 : }
983 :
984 0 : return new;
985 : }
986 :
987 0 : void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable)
988 : {
989 0 : struct zebra_pbr_iptable *ipt_hash;
990 :
991 0 : ipt_hash = hash_get(zrouter.iptable_hash, iptable,
992 : pbr_iptable_alloc_intern);
993 0 : (void)dplane_pbr_iptable_add(ipt_hash);
994 0 : }
995 :
996 0 : void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
997 : {
998 0 : struct zebra_pbr_iptable *lookup;
999 :
1000 0 : lookup = hash_lookup(zrouter.iptable_hash, iptable);
1001 0 : (void)dplane_pbr_iptable_delete(iptable);
1002 0 : if (lookup) {
1003 0 : struct listnode *node, *nnode;
1004 0 : char *name;
1005 :
1006 0 : hash_release(zrouter.iptable_hash, lookup);
1007 0 : for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
1008 : node, nnode, name)) {
1009 0 : XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
1010 0 : list_delete_node(iptable->interface_name_list,
1011 : node);
1012 : }
1013 0 : list_delete(&iptable->interface_name_list);
1014 0 : XFREE(MTYPE_PBR_OBJ, lookup);
1015 : } else
1016 0 : zlog_debug("%s: IPTable being deleted we know nothing about",
1017 : __func__);
1018 0 : }
1019 :
1020 : /*
1021 : * Handle success or failure of rule (un)install in the kernel.
1022 : */
1023 0 : void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx)
1024 : {
1025 0 : enum zebra_dplane_result res;
1026 0 : enum dplane_op_e op;
1027 :
1028 0 : res = dplane_ctx_get_status(ctx);
1029 0 : op = dplane_ctx_get_op(ctx);
1030 0 : if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE)
1031 0 : zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1032 : ? ZAPI_RULE_INSTALLED
1033 : : ZAPI_RULE_FAIL_INSTALL);
1034 0 : else if (op == DPLANE_OP_RULE_DELETE)
1035 0 : zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1036 : ? ZAPI_RULE_REMOVED
1037 : : ZAPI_RULE_FAIL_REMOVE);
1038 : else if (op == DPLANE_OP_IPTABLE_ADD)
1039 0 : zsend_iptable_notify_owner(ctx,
1040 : res == ZEBRA_DPLANE_REQUEST_SUCCESS
1041 : ? ZAPI_IPTABLE_INSTALLED
1042 : : ZAPI_IPTABLE_FAIL_INSTALL);
1043 : else if (op == DPLANE_OP_IPTABLE_DELETE)
1044 0 : zsend_iptable_notify_owner(ctx,
1045 : res == ZEBRA_DPLANE_REQUEST_SUCCESS
1046 : ? ZAPI_IPTABLE_REMOVED
1047 : : ZAPI_IPTABLE_FAIL_REMOVE);
1048 : else if (op == DPLANE_OP_IPSET_ADD)
1049 0 : zsend_ipset_notify_owner(ctx,
1050 : res == ZEBRA_DPLANE_REQUEST_SUCCESS
1051 : ? ZAPI_IPSET_INSTALLED
1052 : : ZAPI_IPSET_FAIL_INSTALL);
1053 : else if (op == DPLANE_OP_IPSET_DELETE)
1054 0 : zsend_ipset_notify_owner(ctx,
1055 : res == ZEBRA_DPLANE_REQUEST_SUCCESS
1056 : ? ZAPI_IPSET_REMOVED
1057 : : ZAPI_IPSET_FAIL_REMOVE);
1058 : else if (op == DPLANE_OP_IPSET_ENTRY_ADD)
1059 0 : zsend_ipset_entry_notify_owner(
1060 : ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1061 : ? ZAPI_IPSET_ENTRY_INSTALLED
1062 : : ZAPI_IPSET_ENTRY_FAIL_INSTALL);
1063 : else if (op == DPLANE_OP_IPSET_ENTRY_DELETE)
1064 0 : zsend_ipset_entry_notify_owner(
1065 : ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1066 : ? ZAPI_IPSET_ENTRY_REMOVED
1067 : : ZAPI_IPSET_ENTRY_FAIL_REMOVE);
1068 : else
1069 0 : flog_err(
1070 : EC_ZEBRA_PBR_RULE_UPDATE,
1071 : "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
1072 : op);
1073 0 : }
1074 :
1075 : /*
1076 : * Handle rule delete notification from kernel.
1077 : */
1078 0 : int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
1079 : {
1080 0 : return 0;
1081 : }
1082 :
1083 : struct zebra_pbr_ipset_entry_unique_display {
1084 : struct zebra_pbr_ipset *zpi;
1085 : struct vty *vty;
1086 : struct zebra_ns *zns;
1087 : };
1088 :
1089 :
1090 0 : static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
1091 : char *str, int size)
1092 : {
1093 0 : const struct prefix *p = pu.p;
1094 0 : char buf[PREFIX2STR_BUFFER];
1095 :
1096 0 : if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_BITLEN)
1097 0 : || (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_BITLEN)) {
1098 0 : snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
1099 : buf, PREFIX2STR_BUFFER));
1100 0 : return str;
1101 : }
1102 0 : return prefix2str(pu, str, size);
1103 : }
1104 :
1105 0 : static void zebra_pbr_display_icmp(struct vty *vty,
1106 : struct zebra_pbr_ipset_entry *zpie)
1107 : {
1108 0 : char decoded_str[20];
1109 0 : uint16_t port;
1110 0 : struct zebra_pbr_ipset *zpi;
1111 :
1112 0 : zpi = zpie->backpointer;
1113 :
1114 : /* range icmp type */
1115 0 : if (zpie->src_port_max || zpie->dst_port_max) {
1116 0 : vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>",
1117 0 : zpie->src_port_min, zpie->src_port_max,
1118 0 : zpie->dst_port_min, zpie->dst_port_max);
1119 : } else {
1120 0 : port = ((zpie->src_port_min << 8) & 0xff00) +
1121 0 : (zpie->dst_port_min & 0xff);
1122 0 : memset(decoded_str, 0, sizeof(decoded_str));
1123 0 : snprintf(decoded_str, sizeof(decoded_str), "%u/%u",
1124 : zpie->src_port_min, zpie->dst_port_min);
1125 0 : vty_out(vty, ":%s:%s",
1126 0 : zpi->family == AF_INET6 ? "ipv6-icmp" : "icmp",
1127 0 : lookup_msg(zpi->family == AF_INET6 ?
1128 : icmpv6_typecode_str : icmp_typecode_str,
1129 : port, decoded_str));
1130 : }
1131 0 : }
1132 :
1133 0 : static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
1134 : uint16_t port_min, uint16_t port_max,
1135 : uint8_t proto)
1136 : {
1137 0 : if (!(filter_bm & PBR_FILTER_PROTO)) {
1138 0 : if (port_max)
1139 0 : vty_out(vty, ":udp/tcp:%d-%d",
1140 : port_min, port_max);
1141 : else
1142 0 : vty_out(vty, ":udp/tcp:%d",
1143 : port_min);
1144 : } else {
1145 0 : if (port_max)
1146 0 : vty_out(vty, ":proto %d:%d-%d",
1147 : proto, port_min, port_max);
1148 : else
1149 0 : vty_out(vty, ":proto %d:%d",
1150 : proto, port_min);
1151 : }
1152 0 : }
1153 :
1154 0 : static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket,
1155 : void *arg)
1156 : {
1157 0 : struct zebra_pbr_ipset_entry_unique_display *unique =
1158 : (struct zebra_pbr_ipset_entry_unique_display *)arg;
1159 0 : struct zebra_pbr_ipset *zpi = unique->zpi;
1160 0 : struct vty *vty = unique->vty;
1161 0 : struct zebra_pbr_ipset_entry *zpie =
1162 : (struct zebra_pbr_ipset_entry *)bucket->data;
1163 0 : uint64_t pkts = 0, bytes = 0;
1164 0 : int ret = 0;
1165 :
1166 0 : if (zpie->backpointer != zpi)
1167 : return HASHWALK_CONTINUE;
1168 :
1169 0 : if ((zpi->type == IPSET_NET_NET) ||
1170 : (zpi->type == IPSET_NET_PORT_NET)) {
1171 0 : char buf[PREFIX_STRLEN];
1172 :
1173 0 : zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
1174 0 : vty_out(vty, "\tfrom %s", buf);
1175 0 : if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1176 0 : zpie->proto != IPPROTO_ICMP)
1177 0 : zebra_pbr_display_port(vty, zpie->filter_bm,
1178 0 : zpie->src_port_min,
1179 0 : zpie->src_port_max,
1180 : zpie->proto);
1181 0 : vty_out(vty, " to ");
1182 0 : zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
1183 0 : vty_out(vty, "%s", buf);
1184 0 : if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1185 0 : zpie->proto != IPPROTO_ICMP)
1186 0 : zebra_pbr_display_port(vty, zpie->filter_bm,
1187 0 : zpie->dst_port_min,
1188 0 : zpie->dst_port_max,
1189 : zpie->proto);
1190 0 : if (zpie->proto == IPPROTO_ICMP)
1191 0 : zebra_pbr_display_icmp(vty, zpie);
1192 0 : } else if ((zpi->type == IPSET_NET) ||
1193 : (zpi->type == IPSET_NET_PORT)) {
1194 0 : char buf[PREFIX_STRLEN];
1195 :
1196 0 : if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
1197 0 : zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
1198 0 : vty_out(vty, "\tfrom %s", buf);
1199 : }
1200 0 : if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1201 0 : zpie->proto != IPPROTO_ICMP)
1202 0 : zebra_pbr_display_port(vty, zpie->filter_bm,
1203 0 : zpie->src_port_min,
1204 0 : zpie->src_port_max,
1205 : zpie->proto);
1206 0 : if (zpie->filter_bm & PBR_FILTER_DST_IP) {
1207 0 : zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
1208 0 : vty_out(vty, "\tto %s", buf);
1209 : }
1210 0 : if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1211 0 : zpie->proto != IPPROTO_ICMP)
1212 0 : zebra_pbr_display_port(vty, zpie->filter_bm,
1213 0 : zpie->dst_port_min,
1214 0 : zpie->dst_port_max,
1215 : zpie->proto);
1216 0 : if (zpie->proto == IPPROTO_ICMP)
1217 0 : zebra_pbr_display_icmp(vty, zpie);
1218 : }
1219 0 : vty_out(vty, " (%u)\n", zpie->unique);
1220 :
1221 0 : ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts,
1222 : &bytes);
1223 0 : if (ret && pkts > 0)
1224 0 : vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1225 : pkts, bytes);
1226 : return HASHWALK_CONTINUE;
1227 : }
1228 :
1229 0 : static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg)
1230 : {
1231 0 : struct zebra_pbr_env_display *uniqueipset =
1232 : (struct zebra_pbr_env_display *)arg;
1233 0 : struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
1234 0 : struct zebra_pbr_ipset_entry_unique_display unique;
1235 0 : struct vty *vty = uniqueipset->vty;
1236 0 : struct zebra_ns *zns = uniqueipset->zns;
1237 :
1238 0 : vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name,
1239 : zebra_pbr_ipset_type2str(zpi->type),
1240 0 : family2str(zpi->family));
1241 0 : unique.vty = vty;
1242 0 : unique.zpi = zpi;
1243 0 : unique.zns = zns;
1244 0 : hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
1245 : &unique);
1246 0 : vty_out(vty, "\n");
1247 0 : return HASHWALK_CONTINUE;
1248 : }
1249 :
1250 0 : size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
1251 : uint16_t tcp_val)
1252 : {
1253 0 : size_t len_written = 0;
1254 0 : static struct message nt = {0};
1255 0 : const struct message *pnt;
1256 0 : int incr = 0;
1257 :
1258 0 : for (pnt = tcp_value_str;
1259 0 : memcmp(pnt, &nt, sizeof(struct message)); pnt++)
1260 0 : if (pnt->key & tcp_val) {
1261 0 : len_written += snprintf(buffer + len_written,
1262 : len - len_written,
1263 : "%s%s", incr ?
1264 0 : ",":"", pnt->str);
1265 0 : incr++;
1266 : }
1267 0 : return len_written;
1268 : }
1269 :
1270 : /*
1271 : */
1272 0 : void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
1273 : {
1274 0 : struct zebra_pbr_ipset *zpi;
1275 0 : struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1276 0 : struct zebra_pbr_ipset_entry_unique_display unique;
1277 0 : struct zebra_pbr_env_display uniqueipset;
1278 :
1279 0 : if (ipsetname) {
1280 0 : zpi = zebra_pbr_lookup_ipset_pername(ipsetname);
1281 0 : if (!zpi) {
1282 0 : vty_out(vty, "No IPset %s found\n", ipsetname);
1283 0 : return;
1284 : }
1285 0 : vty_out(vty, "IPset %s type %s family %s\n", ipsetname,
1286 : zebra_pbr_ipset_type2str(zpi->type),
1287 0 : family2str(zpi->family));
1288 0 : unique.vty = vty;
1289 0 : unique.zpi = zpi;
1290 0 : unique.zns = zns;
1291 0 : hash_walk(zrouter.ipset_entry_hash,
1292 : zebra_pbr_show_ipset_entry_walkcb, &unique);
1293 0 : return;
1294 : }
1295 0 : uniqueipset.zns = zns;
1296 0 : uniqueipset.vty = vty;
1297 0 : uniqueipset.name = NULL;
1298 0 : hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb,
1299 : &uniqueipset);
1300 : }
1301 :
1302 : struct pbr_rule_fwmark_lookup {
1303 : struct zebra_pbr_rule *ptr;
1304 : uint32_t fwmark;
1305 : };
1306 :
1307 0 : static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket,
1308 : void *arg)
1309 : {
1310 0 : struct pbr_rule_fwmark_lookup *iprule =
1311 : (struct pbr_rule_fwmark_lookup *)arg;
1312 0 : struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data;
1313 :
1314 0 : if (iprule->fwmark == zpr->rule.filter.fwmark) {
1315 0 : iprule->ptr = zpr;
1316 0 : return HASHWALK_ABORT;
1317 : }
1318 : return HASHWALK_CONTINUE;
1319 : }
1320 :
1321 0 : static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable,
1322 : struct vty *vty,
1323 : struct zebra_ns *zns)
1324 : {
1325 0 : int ret;
1326 0 : uint64_t pkts = 0, bytes = 0;
1327 :
1328 0 : vty_out(vty, "IPtable %s family %s action %s (%u)\n",
1329 0 : iptable->ipset_name,
1330 0 : family2str(iptable->family),
1331 0 : iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
1332 : iptable->unique);
1333 0 : if (iptable->type == IPSET_NET_PORT ||
1334 : iptable->type == IPSET_NET_PORT_NET) {
1335 0 : if (!(iptable->filter_bm & MATCH_ICMP_SET)) {
1336 0 : if (iptable->filter_bm & PBR_FILTER_DST_PORT)
1337 0 : vty_out(vty, "\t lookup dst port\n");
1338 0 : else if (iptable->filter_bm & PBR_FILTER_SRC_PORT)
1339 0 : vty_out(vty, "\t lookup src port\n");
1340 : }
1341 : }
1342 0 : if (iptable->pkt_len_min || iptable->pkt_len_max) {
1343 0 : if (!iptable->pkt_len_max)
1344 0 : vty_out(vty, "\t pkt len %u\n",
1345 0 : iptable->pkt_len_min);
1346 : else
1347 0 : vty_out(vty, "\t pkt len [%u;%u]\n",
1348 0 : iptable->pkt_len_min,
1349 : iptable->pkt_len_max);
1350 : }
1351 0 : if (iptable->tcp_flags || iptable->tcp_mask_flags) {
1352 0 : char tcp_flag_str[64];
1353 0 : char tcp_flag_mask_str[64];
1354 :
1355 0 : zebra_pbr_tcpflags_snprintf(tcp_flag_str,
1356 : sizeof(tcp_flag_str),
1357 0 : iptable->tcp_flags);
1358 0 : zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
1359 : sizeof(tcp_flag_mask_str),
1360 0 : iptable->tcp_mask_flags);
1361 0 : vty_out(vty, "\t tcpflags [%s/%s]\n",
1362 : tcp_flag_str, tcp_flag_mask_str);
1363 : }
1364 0 : if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
1365 0 : vty_out(vty, "\t dscp %s %d\n",
1366 0 : iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
1367 0 : "not" : "", iptable->dscp_value);
1368 : }
1369 0 : if (iptable->filter_bm & (MATCH_FLOW_LABEL_SET |
1370 : MATCH_FLOW_LABEL_INVERSE_SET)) {
1371 0 : vty_out(vty, "\t flowlabel %s %d\n",
1372 0 : iptable->filter_bm & MATCH_FLOW_LABEL_INVERSE_SET ?
1373 0 : "not" : "", iptable->flow_label);
1374 : }
1375 0 : if (iptable->fragment) {
1376 0 : char val_str[10];
1377 :
1378 0 : snprintf(val_str, sizeof(val_str), "%d", iptable->fragment);
1379 0 : vty_out(vty, "\t fragment%s %s\n",
1380 0 : iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
1381 : " not" : "", lookup_msg(fragment_value_str,
1382 0 : iptable->fragment, val_str));
1383 : }
1384 0 : if (iptable->protocol) {
1385 0 : vty_out(vty, "\t protocol %d\n",
1386 : iptable->protocol);
1387 : }
1388 0 : ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts,
1389 : &bytes);
1390 0 : if (ret && pkts > 0)
1391 0 : vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1392 : pkts, bytes);
1393 0 : if (iptable->action != ZEBRA_IPTABLES_DROP) {
1394 0 : struct pbr_rule_fwmark_lookup prfl;
1395 :
1396 0 : prfl.fwmark = iptable->fwmark;
1397 0 : prfl.ptr = NULL;
1398 0 : hash_walk(zrouter.rules_hash,
1399 : &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
1400 0 : if (prfl.ptr) {
1401 0 : struct zebra_pbr_rule *zpr = prfl.ptr;
1402 :
1403 0 : vty_out(vty, "\t table %u, fwmark %u\n",
1404 : zpr->rule.action.table,
1405 : prfl.fwmark);
1406 : }
1407 : }
1408 0 : }
1409 :
1410 0 : static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg)
1411 : {
1412 0 : struct zebra_pbr_iptable *iptable =
1413 : (struct zebra_pbr_iptable *)bucket->data;
1414 0 : struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
1415 0 : struct vty *vty = env->vty;
1416 0 : struct zebra_ns *zns = env->zns;
1417 0 : char *iptable_name = env->name;
1418 :
1419 0 : if (!iptable_name)
1420 0 : zebra_pbr_show_iptable_unit(iptable, vty, zns);
1421 0 : else if (!strncmp(iptable_name,
1422 0 : iptable->ipset_name,
1423 : ZEBRA_IPSET_NAME_SIZE))
1424 0 : zebra_pbr_show_iptable_unit(iptable, vty, zns);
1425 0 : return HASHWALK_CONTINUE;
1426 : }
1427 :
1428 0 : void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name)
1429 : {
1430 0 : struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1431 0 : struct zebra_pbr_env_display env;
1432 :
1433 0 : env.vty = vty;
1434 0 : env.zns = zns;
1435 0 : env.name = iptable_name;
1436 0 : hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env);
1437 0 : }
1438 :
1439 0 : void zebra_pbr_iptable_update_interfacelist(struct stream *s,
1440 : struct zebra_pbr_iptable *zpi)
1441 : {
1442 0 : uint32_t i = 0, index;
1443 0 : struct interface *ifp;
1444 0 : char *name;
1445 :
1446 0 : for (i = 0; i < zpi->nb_interface; i++) {
1447 0 : STREAM_GETL(s, index);
1448 0 : ifp = if_lookup_by_index(index, zpi->vrf_id);
1449 0 : if (!ifp)
1450 0 : continue;
1451 0 : name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
1452 0 : listnode_add(zpi->interface_name_list, name);
1453 : }
1454 0 : stream_failure:
1455 0 : return;
1456 : }
|