Coverage Report

Created: 2025-08-26 06:20

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