Coverage Report

Created: 2025-07-14 06:48

/src/frr/bgpd/bgp_pbr.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * BGP pbr
4
 * Copyright (C) 6WIND
5
 */
6
7
#include "zebra.h"
8
#include "prefix.h"
9
#include "zclient.h"
10
#include "jhash.h"
11
#include "pbr.h"
12
13
#include "lib/printfrr.h"
14
15
#include "bgpd/bgpd.h"
16
#include "bgpd/bgp_pbr.h"
17
#include "bgpd/bgp_debug.h"
18
#include "bgpd/bgp_flowspec_util.h"
19
#include "bgpd/bgp_ecommunity.h"
20
#include "bgpd/bgp_route.h"
21
#include "bgpd/bgp_attr.h"
22
#include "bgpd/bgp_zebra.h"
23
#include "bgpd/bgp_mplsvpn.h"
24
#include "bgpd/bgp_flowspec_private.h"
25
#include "bgpd/bgp_errors.h"
26
27
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry");
28
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match");
29
DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action");
30
DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule");
31
DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context");
32
DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value");
33
34
/* chain strings too long to fit in one line */
35
#define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
36
0
#define IPV6_FRAGMENT_INVALID "fragment not valid for IPv6 for this implementation"
37
38
RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
39
      id_entry, bgp_pbr_interface_compare);
40
struct bgp_pbr_interface_head ifaces_by_name_ipv4 =
41
  RB_INITIALIZER(&ifaces_by_name_ipv4);
42
43
static int bgp_pbr_match_counter_unique;
44
static int bgp_pbr_match_entry_counter_unique;
45
static int bgp_pbr_action_counter_unique;
46
static int bgp_pbr_match_iptable_counter_unique;
47
48
struct bgp_pbr_match_iptable_unique {
49
  uint32_t unique;
50
  struct bgp_pbr_match *bpm_found;
51
};
52
53
struct bgp_pbr_match_entry_unique {
54
  uint32_t unique;
55
  struct bgp_pbr_match_entry *bpme_found;
56
};
57
58
struct bgp_pbr_action_unique {
59
  uint32_t unique;
60
  struct bgp_pbr_action *bpa_found;
61
};
62
63
struct bgp_pbr_rule_unique {
64
  uint32_t unique;
65
  struct bgp_pbr_rule *bpr_found;
66
};
67
68
static int bgp_pbr_rule_walkcb(struct hash_bucket *bucket, void *arg)
69
0
{
70
0
  struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)bucket->data;
71
0
  struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *)
72
0
    arg;
73
0
  uint32_t unique = bpru->unique;
74
75
0
  if (bpr->unique == unique) {
76
0
    bpru->bpr_found = bpr;
77
0
    return HASHWALK_ABORT;
78
0
  }
79
0
  return HASHWALK_CONTINUE;
80
0
}
81
82
static int bgp_pbr_action_walkcb(struct hash_bucket *bucket, void *arg)
83
0
{
84
0
  struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)bucket->data;
85
0
  struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *)
86
0
    arg;
87
0
  uint32_t unique = bpau->unique;
88
89
0
  if (bpa->unique == unique) {
90
0
    bpau->bpa_found = bpa;
91
0
    return HASHWALK_ABORT;
92
0
  }
93
0
  return HASHWALK_CONTINUE;
94
0
}
95
96
static int bgp_pbr_match_entry_walkcb(struct hash_bucket *bucket, void *arg)
97
0
{
98
0
  struct bgp_pbr_match_entry *bpme =
99
0
    (struct bgp_pbr_match_entry *)bucket->data;
100
0
  struct bgp_pbr_match_entry_unique *bpmeu =
101
0
    (struct bgp_pbr_match_entry_unique *)arg;
102
0
  uint32_t unique = bpmeu->unique;
103
104
0
  if (bpme->unique == unique) {
105
0
    bpmeu->bpme_found = bpme;
106
0
    return HASHWALK_ABORT;
107
0
  }
108
0
  return HASHWALK_CONTINUE;
109
0
}
110
111
struct bgp_pbr_match_ipsetname {
112
  char *ipsetname;
113
  struct bgp_pbr_match *bpm_found;
114
};
115
116
static int bgp_pbr_match_pername_walkcb(struct hash_bucket *bucket, void *arg)
117
0
{
118
0
  struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
119
0
  struct bgp_pbr_match_ipsetname *bpmi =
120
0
    (struct bgp_pbr_match_ipsetname *)arg;
121
0
  char *ipset_name = bpmi->ipsetname;
122
123
0
  if (!strncmp(ipset_name, bpm->ipset_name,
124
0
         ZEBRA_IPSET_NAME_SIZE)) {
125
0
    bpmi->bpm_found = bpm;
126
0
    return HASHWALK_ABORT;
127
0
  }
128
0
  return HASHWALK_CONTINUE;
129
0
}
130
131
static int bgp_pbr_match_iptable_walkcb(struct hash_bucket *bucket, void *arg)
132
0
{
133
0
  struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
134
0
  struct bgp_pbr_match_iptable_unique *bpmiu =
135
0
    (struct bgp_pbr_match_iptable_unique *)arg;
136
0
  uint32_t unique = bpmiu->unique;
137
138
0
  if (bpm->unique2 == unique) {
139
0
    bpmiu->bpm_found = bpm;
140
0
    return HASHWALK_ABORT;
141
0
  }
142
0
  return HASHWALK_CONTINUE;
143
0
}
144
145
struct bgp_pbr_match_unique {
146
  uint32_t unique;
147
  struct bgp_pbr_match *bpm_found;
148
};
149
150
static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg)
151
0
{
152
0
  struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
153
0
  struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *)
154
0
    arg;
155
0
  uint32_t unique = bpmu->unique;
156
157
0
  if (bpm->unique == unique) {
158
0
    bpmu->bpm_found = bpm;
159
0
    return HASHWALK_ABORT;
160
0
  }
161
0
  return HASHWALK_CONTINUE;
162
0
}
163
164
static int snprintf_bgp_pbr_match_val(char *str, int len,
165
              struct bgp_pbr_match_val *mval,
166
              const char *prepend)
167
0
{
168
0
  char *ptr = str;
169
0
  int delta;
170
171
0
  if (prepend) {
172
0
    delta = snprintf(ptr, len, "%s", prepend);
173
0
    ptr += delta;
174
0
    len -= delta;
175
0
  } else {
176
0
    if (mval->unary_operator & OPERATOR_UNARY_OR) {
177
0
      delta = snprintf(ptr, len, ", or ");
178
0
      ptr += delta;
179
0
      len -= delta;
180
0
    }
181
0
    if (mval->unary_operator & OPERATOR_UNARY_AND) {
182
0
      delta = snprintf(ptr, len, ", and ");
183
0
      ptr += delta;
184
0
      len -= delta;
185
0
    }
186
0
  }
187
0
  if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) {
188
0
    delta = snprintf(ptr, len, "<");
189
0
    ptr += delta;
190
0
    len -= delta;
191
0
  }
192
0
  if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) {
193
0
    delta = snprintf(ptr, len, ">");
194
0
    ptr += delta;
195
0
    len -= delta;
196
0
  }
197
0
  if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) {
198
0
    delta = snprintf(ptr, len, "=");
199
0
    ptr += delta;
200
0
    len -= delta;
201
0
  }
202
0
  if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) {
203
0
    delta = snprintf(ptr, len, "match");
204
0
    ptr += delta;
205
0
    len -= delta;
206
0
  }
207
0
  ptr += snprintf(ptr, len, " %u", mval->value);
208
0
  return (int)(ptr - str);
209
0
}
210
211
0
#define INCREMENT_DISPLAY(_ptr, _cnt, _len) do { \
212
0
    int sn_delta;       \
213
0
              \
214
0
    if (_cnt) {       \
215
0
      sn_delta = snprintf((_ptr), (_len), "; ");\
216
0
      (_len) -= sn_delta;   \
217
0
      (_ptr) += sn_delta;   \
218
0
    }        \
219
0
    (_cnt)++; \
220
0
  } while (0)
221
222
/* this structure can be used for port range,
223
 * but also for other values range like packet length range
224
 */
225
struct bgp_pbr_range_port {
226
  uint16_t min_port;
227
  uint16_t max_port;
228
};
229
230
/* this structure can be used to filter with a mask
231
 * for instance it supports not instructions like for
232
 * tcpflags
233
 */
234
struct bgp_pbr_val_mask {
235
  uint16_t val;
236
  uint16_t mask;
237
};
238
239
/* this structure is used to pass instructs
240
 * so that BGP can create pbr instructions to ZEBRA
241
 */
242
struct bgp_pbr_filter {
243
  uint8_t type;
244
  vrf_id_t vrf_id;
245
  uint8_t family;
246
  struct prefix *src;
247
  struct prefix *dst;
248
  uint8_t bitmask_iprule;
249
  uint8_t protocol;
250
  struct bgp_pbr_range_port *pkt_len;
251
  struct bgp_pbr_range_port *src_port;
252
  struct bgp_pbr_range_port *dst_port;
253
  struct bgp_pbr_val_mask *tcp_flags;
254
  struct bgp_pbr_val_mask *dscp;
255
  struct bgp_pbr_val_mask *flow_label;
256
  struct bgp_pbr_val_mask *pkt_len_val;
257
  struct bgp_pbr_val_mask *fragment;
258
};
259
260
/* this structure is used to contain OR instructions
261
 * so that BGP can create multiple pbr instructions
262
 * to ZEBRA
263
 */
264
struct bgp_pbr_or_filter {
265
  struct list *tcpflags;
266
  struct list *dscp;
267
  struct list *flowlabel;
268
  struct list *pkt_len;
269
  struct list *fragment;
270
  struct list *icmp_type;
271
  struct list *icmp_code;
272
};
273
274
static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
275
              struct bgp_path_info *path,
276
              struct bgp_pbr_filter *bpf,
277
              struct nexthop *nh,
278
              float *rate);
279
280
static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add);
281
282
static bool bgp_pbr_extract_enumerate_unary_opposite(
283
         uint8_t unary_operator,
284
         struct bgp_pbr_val_mask *and_valmask,
285
         struct list *or_valmask, uint32_t value,
286
         uint8_t type_entry)
287
0
{
288
0
  if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
289
0
    if (type_entry == FLOWSPEC_TCP_FLAGS) {
290
0
      and_valmask->mask |=
291
0
        TCP_HEADER_ALL_FLAGS &
292
0
        ~(value);
293
0
    } else if (type_entry == FLOWSPEC_DSCP ||
294
0
         type_entry == FLOWSPEC_FLOW_LABEL ||
295
0
         type_entry == FLOWSPEC_PKT_LEN ||
296
0
         type_entry == FLOWSPEC_FRAGMENT) {
297
0
      and_valmask->val = value;
298
0
      and_valmask->mask = 1; /* inverse */
299
0
    }
300
0
  } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
301
0
    and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
302
0
              sizeof(struct bgp_pbr_val_mask));
303
0
    if (type_entry == FLOWSPEC_TCP_FLAGS) {
304
0
      and_valmask->val = TCP_HEADER_ALL_FLAGS;
305
0
      and_valmask->mask |=
306
0
        TCP_HEADER_ALL_FLAGS &
307
0
        ~(value);
308
0
    } else if (type_entry == FLOWSPEC_DSCP ||
309
0
         type_entry == FLOWSPEC_FLOW_LABEL ||
310
0
         type_entry == FLOWSPEC_FRAGMENT ||
311
0
         type_entry == FLOWSPEC_PKT_LEN) {
312
0
      and_valmask->val = value;
313
0
      and_valmask->mask = 1; /* inverse */
314
0
    }
315
0
    listnode_add(or_valmask, and_valmask);
316
0
  } else if (type_entry == FLOWSPEC_ICMP_CODE ||
317
0
       type_entry == FLOWSPEC_ICMP_TYPE)
318
0
    return false;
319
0
  return true;
320
0
}
321
322
/* TCP : FIN and SYN -> val = ALL; mask = 3
323
 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
324
 * other variables type: dscp, pkt len, fragment, flow label
325
 * - value is copied in bgp_pbr_val_mask->val value
326
 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
327
 */
328
static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
329
              int num, uint8_t unary_operator,
330
              void *valmask, uint8_t type_entry)
331
0
{
332
0
  int i = 0;
333
0
  struct bgp_pbr_val_mask *and_valmask = NULL;
334
0
  struct list *or_valmask = NULL;
335
0
  bool ret;
336
337
0
  if (valmask) {
338
0
    if (unary_operator == OPERATOR_UNARY_AND) {
339
0
      and_valmask = (struct bgp_pbr_val_mask *)valmask;
340
0
      memset(and_valmask, 0, sizeof(struct bgp_pbr_val_mask));
341
0
    } else if (unary_operator == OPERATOR_UNARY_OR) {
342
0
      or_valmask = (struct list *)valmask;
343
0
    }
344
0
  }
345
0
  for (i = 0; i < num; i++) {
346
0
    if (i != 0 && list[i].unary_operator !=
347
0
        unary_operator)
348
0
      return false;
349
0
    if (!(list[i].compare_operator &
350
0
        OPERATOR_COMPARE_EQUAL_TO) &&
351
0
        !(list[i].compare_operator &
352
0
          OPERATOR_COMPARE_EXACT_MATCH)) {
353
0
      if ((list[i].compare_operator &
354
0
           OPERATOR_COMPARE_LESS_THAN) &&
355
0
          (list[i].compare_operator &
356
0
           OPERATOR_COMPARE_GREATER_THAN)) {
357
0
        ret = bgp_pbr_extract_enumerate_unary_opposite(
358
0
             unary_operator, and_valmask,
359
0
             or_valmask, list[i].value,
360
0
             type_entry);
361
0
        if (!ret)
362
0
          return ret;
363
0
        continue;
364
0
      }
365
0
      return false;
366
0
    }
367
0
    if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
368
0
      if (type_entry == FLOWSPEC_TCP_FLAGS)
369
0
        and_valmask->mask |=
370
0
          TCP_HEADER_ALL_FLAGS & list[i].value;
371
0
    } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
372
0
      and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
373
0
                sizeof(struct bgp_pbr_val_mask));
374
0
      if (type_entry == FLOWSPEC_TCP_FLAGS) {
375
0
        and_valmask->val = TCP_HEADER_ALL_FLAGS;
376
0
        and_valmask->mask |=
377
0
          TCP_HEADER_ALL_FLAGS & list[i].value;
378
0
      } else if (type_entry == FLOWSPEC_DSCP ||
379
0
           type_entry == FLOWSPEC_FLOW_LABEL ||
380
0
           type_entry == FLOWSPEC_ICMP_TYPE ||
381
0
           type_entry == FLOWSPEC_ICMP_CODE ||
382
0
           type_entry == FLOWSPEC_FRAGMENT ||
383
0
           type_entry == FLOWSPEC_PKT_LEN)
384
0
        and_valmask->val = list[i].value;
385
0
      listnode_add(or_valmask, and_valmask);
386
0
    }
387
0
  }
388
0
  if (unary_operator == OPERATOR_UNARY_AND && and_valmask
389
0
      && type_entry == FLOWSPEC_TCP_FLAGS)
390
0
    and_valmask->val = TCP_HEADER_ALL_FLAGS;
391
0
  return true;
392
0
}
393
394
/* if unary operator can either be UNARY_OR/AND/OR-AND.
395
 * in the latter case, combinationf of both is not handled
396
 */
397
static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
398
              int num, uint8_t unary_operator,
399
              void *valmask, uint8_t type_entry)
400
0
{
401
0
  bool ret;
402
0
  uint8_t unary_operator_val;
403
0
  bool double_check = false;
404
405
0
  if ((unary_operator & OPERATOR_UNARY_OR) &&
406
0
      (unary_operator & OPERATOR_UNARY_AND)) {
407
0
    unary_operator_val = OPERATOR_UNARY_AND;
408
0
    double_check = true;
409
0
  } else
410
0
    unary_operator_val = unary_operator;
411
0
  ret = bgp_pbr_extract_enumerate_unary(list, num, unary_operator_val,
412
0
                valmask, type_entry);
413
0
  if (!ret && double_check)
414
0
    ret = bgp_pbr_extract_enumerate_unary(list, num,
415
0
                  OPERATOR_UNARY_OR,
416
0
                  valmask,
417
0
                  type_entry);
418
0
  return ret;
419
0
}
420
421
/* returns the unary operator that is in the list
422
 * return 0 if both operators are used
423
 */
424
static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
425
                int num)
426
427
0
{
428
0
  int i;
429
0
  uint8_t unary_operator = OPERATOR_UNARY_AND;
430
431
0
  for (i = 0; i < num; i++) {
432
0
    if (i == 0)
433
0
      continue;
434
0
    if (list[i].unary_operator & OPERATOR_UNARY_OR)
435
0
      unary_operator = OPERATOR_UNARY_OR;
436
0
    if ((list[i].unary_operator & OPERATOR_UNARY_AND
437
0
         && unary_operator == OPERATOR_UNARY_OR) ||
438
0
        (list[i].unary_operator & OPERATOR_UNARY_OR
439
0
         && unary_operator == OPERATOR_UNARY_AND))
440
0
      return 0;
441
0
  }
442
0
  return unary_operator;
443
0
}
444
445
446
/* return true if extraction ok
447
 */
448
static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
449
          int num,
450
          struct bgp_pbr_range_port *range)
451
0
{
452
0
  int i = 0;
453
0
  bool exact_match = false;
454
455
0
  if (range)
456
0
    memset(range, 0, sizeof(struct bgp_pbr_range_port));
457
458
0
  if (num > 2)
459
0
    return false;
460
0
  for (i = 0; i < num; i++) {
461
0
    if (i != 0 && (list[i].compare_operator ==
462
0
             OPERATOR_COMPARE_EQUAL_TO))
463
0
      return false;
464
0
    if (i == 0 && (list[i].compare_operator ==
465
0
             OPERATOR_COMPARE_EQUAL_TO)) {
466
0
      if (range)
467
0
        range->min_port = list[i].value;
468
0
      exact_match = true;
469
0
    }
470
0
    if (exact_match && i > 0)
471
0
      return false;
472
0
    if (list[i].compare_operator ==
473
0
        (OPERATOR_COMPARE_GREATER_THAN +
474
0
         OPERATOR_COMPARE_EQUAL_TO)) {
475
0
      if (range)
476
0
        range->min_port = list[i].value;
477
0
    } else if (list[i].compare_operator ==
478
0
         (OPERATOR_COMPARE_LESS_THAN +
479
0
          OPERATOR_COMPARE_EQUAL_TO)) {
480
0
      if (range)
481
0
        range->max_port = list[i].value;
482
0
    } else if (list[i].compare_operator ==
483
0
         OPERATOR_COMPARE_LESS_THAN) {
484
0
      if (range)
485
0
        range->max_port = list[i].value - 1;
486
0
    } else if (list[i].compare_operator ==
487
0
         OPERATOR_COMPARE_GREATER_THAN) {
488
0
      if (range)
489
0
        range->min_port = list[i].value + 1;
490
0
    }
491
0
  }
492
0
  return true;
493
0
}
494
495
static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
496
0
{
497
0
  bool enumerate_icmp = false;
498
499
0
  if (api->type ==  BGP_PBR_UNDEFINED) {
500
0
    if (BGP_DEBUG(pbr, PBR))
501
0
      zlog_debug("BGP: pbr entry undefined. cancel.");
502
0
    return 0;
503
0
  }
504
  /* because bgp pbr entry may contain unsupported
505
   * combinations, a message will be displayed here if
506
   * not supported.
507
   * for now, only match/set supported is
508
   * - combination src/dst => redirect nexthop [ + rate]
509
   * - combination src/dst => redirect VRF [ + rate]
510
   * - combination src/dst => drop
511
   * - combination srcport + @IP
512
   */
513
0
  if (api->match_protocol_num > 1) {
514
0
    if (BGP_DEBUG(pbr, PBR))
515
0
      zlog_debug("BGP: match protocol operations:multiple protocols ( %d). ignoring.",
516
0
         api->match_protocol_num);
517
0
    return 0;
518
0
  }
519
0
  if (api->src_prefix_offset > 0 ||
520
0
      api->dst_prefix_offset > 0) {
521
0
    if (BGP_DEBUG(pbr, PBR))
522
0
      zlog_debug("BGP: match prefix offset:"
523
0
           "implementation does not support it.");
524
0
    return 0;
525
0
  }
526
0
  if (api->match_protocol_num == 1 &&
527
0
      api->protocol[0].value != PROTOCOL_UDP &&
528
0
      api->protocol[0].value != PROTOCOL_ICMP &&
529
0
      api->protocol[0].value != PROTOCOL_ICMPV6 &&
530
0
      api->protocol[0].value != PROTOCOL_TCP) {
531
0
    if (BGP_DEBUG(pbr, PBR))
532
0
      zlog_debug("BGP: match protocol operations:protocol (%d) not supported. ignoring",
533
0
           api->match_protocol_num);
534
0
    return 0;
535
0
  }
536
0
  if (!bgp_pbr_extract(api->src_port, api->match_src_port_num, NULL)) {
537
0
    if (BGP_DEBUG(pbr, PBR))
538
0
      zlog_debug("BGP: match src port operations:too complex. ignoring.");
539
0
    return 0;
540
0
  }
541
0
  if (!bgp_pbr_extract(api->dst_port, api->match_dst_port_num, NULL)) {
542
0
    if (BGP_DEBUG(pbr, PBR))
543
0
      zlog_debug("BGP: match dst port operations:too complex. ignoring.");
544
0
    return 0;
545
0
  }
546
0
  if (!bgp_pbr_extract_enumerate(api->tcpflags,
547
0
               api->match_tcpflags_num,
548
0
               OPERATOR_UNARY_AND |
549
0
               OPERATOR_UNARY_OR, NULL,
550
0
               FLOWSPEC_TCP_FLAGS)) {
551
0
    if (BGP_DEBUG(pbr, PBR))
552
0
      zlog_debug("BGP: match tcp flags:too complex. ignoring.");
553
0
    return 0;
554
0
  }
555
0
  if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
556
0
    if (!bgp_pbr_extract_enumerate(api->icmp_type,
557
0
                 api->match_icmp_type_num,
558
0
                 OPERATOR_UNARY_OR, NULL,
559
0
                 FLOWSPEC_ICMP_TYPE)) {
560
0
      if (BGP_DEBUG(pbr, PBR))
561
0
        zlog_debug("BGP: match icmp type operations:too complex. ignoring.");
562
0
      return 0;
563
0
    }
564
0
    enumerate_icmp = true;
565
0
  }
566
0
  if (!bgp_pbr_extract(api->icmp_code, api->match_icmp_code_num, NULL)) {
567
0
    if (!bgp_pbr_extract_enumerate(api->icmp_code,
568
0
                 api->match_icmp_code_num,
569
0
                 OPERATOR_UNARY_OR, NULL,
570
0
                 FLOWSPEC_ICMP_CODE)) {
571
0
      if (BGP_DEBUG(pbr, PBR))
572
0
        zlog_debug("BGP: match icmp code operations:too complex. ignoring.");
573
0
      return 0;
574
0
    } else if (api->match_icmp_type_num > 1 &&
575
0
         !enumerate_icmp) {
576
0
      if (BGP_DEBUG(pbr, PBR))
577
0
        zlog_debug("BGP: match icmp code is enumerate, and icmp type is not. too complex. ignoring.");
578
0
      return 0;
579
0
    }
580
0
  }
581
0
  if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
582
0
    if (BGP_DEBUG(pbr, PBR))
583
0
      zlog_debug("BGP: match port operations:too complex. ignoring.");
584
0
    return 0;
585
0
  }
586
0
  if (api->match_packet_length_num) {
587
0
    bool ret;
588
589
0
    ret = bgp_pbr_extract(api->packet_length,
590
0
              api->match_packet_length_num, NULL);
591
0
    if (!ret)
592
0
      ret = bgp_pbr_extract_enumerate(api->packet_length,
593
0
            api->match_packet_length_num,
594
0
            OPERATOR_UNARY_OR
595
0
            | OPERATOR_UNARY_AND,
596
0
            NULL, FLOWSPEC_PKT_LEN);
597
0
    if (!ret) {
598
0
      if (BGP_DEBUG(pbr, PBR))
599
0
        zlog_debug("BGP: match packet length operations:too complex. ignoring.");
600
0
      return 0;
601
0
    }
602
0
  }
603
0
  if (api->match_dscp_num) {
604
0
    if (!bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
605
0
        OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
606
0
                 NULL, FLOWSPEC_DSCP)) {
607
0
      if (BGP_DEBUG(pbr, PBR))
608
0
        zlog_debug("BGP: match DSCP operations:too complex. ignoring.");
609
0
      return 0;
610
0
    }
611
0
  }
612
0
  if (api->match_flowlabel_num) {
613
0
    if (api->afi == AFI_IP) {
614
0
      if (BGP_DEBUG(pbr, PBR))
615
0
        zlog_debug("BGP: match Flow Label operations:"
616
0
             "Not for IPv4.");
617
0
      return 0;
618
0
    }
619
0
    if (!bgp_pbr_extract_enumerate(api->flow_label,
620
0
                 api->match_flowlabel_num,
621
0
        OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
622
0
                 NULL, FLOWSPEC_FLOW_LABEL)) {
623
0
      if (BGP_DEBUG(pbr, PBR))
624
0
        zlog_debug("BGP: match FlowLabel operations:"
625
0
             "too complex. ignoring.");
626
0
      return 0;
627
0
    }
628
0
    if (BGP_DEBUG(pbr, PBR))
629
0
      zlog_debug("BGP: match FlowLabel operations "
630
0
           "not supported. ignoring.");
631
0
    return 0;
632
0
  }
633
0
  if (api->match_fragment_num) {
634
0
    char fail_str[64];
635
0
    bool success;
636
637
0
    success = bgp_pbr_extract_enumerate(api->fragment,
638
0
                api->match_fragment_num,
639
0
                OPERATOR_UNARY_OR
640
0
                | OPERATOR_UNARY_AND,
641
0
                NULL, FLOWSPEC_FRAGMENT);
642
0
    if (success) {
643
0
      int i;
644
645
0
      for (i = 0; i < api->match_fragment_num; i++) {
646
0
        if (api->fragment[i].value != 1 &&
647
0
            api->fragment[i].value != 2 &&
648
0
            api->fragment[i].value != 4 &&
649
0
            api->fragment[i].value != 8) {
650
0
          success = false;
651
0
          snprintf(
652
0
            fail_str, sizeof(fail_str),
653
0
            "Value not valid (%d) for this implementation",
654
0
            api->fragment[i].value);
655
0
        }
656
0
        if (api->afi == AFI_IP6 &&
657
0
            api->fragment[i].value == 1) {
658
0
          success = false;
659
0
          snprintf(fail_str, sizeof(fail_str),
660
0
             "IPv6 dont fragment match invalid (%d)",
661
0
             api->fragment[i].value);
662
0
        }
663
0
      }
664
0
      if (api->afi == AFI_IP6) {
665
0
        success = false;
666
0
        snprintf(fail_str, sizeof(fail_str),
667
0
           "%s", IPV6_FRAGMENT_INVALID);
668
0
      }
669
0
    } else
670
0
      snprintf(fail_str, sizeof(fail_str),
671
0
         "too complex. ignoring");
672
0
    if (!success) {
673
0
      if (BGP_DEBUG(pbr, PBR))
674
0
        zlog_debug("BGP: match fragment operation (%d) %s",
675
0
             api->match_fragment_num,
676
0
             fail_str);
677
0
      return 0;
678
0
    }
679
0
  }
680
681
  /* no combinations with both src_port and dst_port
682
   * or port with src_port and dst_port
683
   */
684
0
  if (api->match_src_port_num + api->match_dst_port_num +
685
0
      api->match_port_num > 3) {
686
0
    if (BGP_DEBUG(pbr, PBR))
687
0
      zlog_debug("BGP: match multiple port operations: too complex. ignoring.");
688
0
    return 0;
689
0
  }
690
0
  if ((api->match_src_port_num || api->match_dst_port_num
691
0
       || api->match_port_num) && (api->match_icmp_type_num
692
0
           || api->match_icmp_code_num)) {
693
0
    if (BGP_DEBUG(pbr, PBR))
694
0
      zlog_debug("BGP: match multiple port/imcp operations: too complex. ignoring.");
695
0
    return 0;
696
0
  }
697
  /* iprule only supports redirect IP */
698
0
  if (api->type == BGP_PBR_IPRULE) {
699
0
    int i;
700
701
0
    for (i = 0; i < api->action_num; i++) {
702
0
      if (api->actions[i].action == ACTION_TRAFFICRATE &&
703
0
          api->actions[i].u.r.rate == 0) {
704
0
        if (BGP_DEBUG(pbr, PBR)) {
705
0
          bgp_pbr_print_policy_route(api);
706
0
          zlog_debug("BGP: iprule match actions drop not supported");
707
0
        }
708
0
        return 0;
709
0
      }
710
0
      if (api->actions[i].action == ACTION_MARKING) {
711
0
        if (BGP_DEBUG(pbr, PBR)) {
712
0
          bgp_pbr_print_policy_route(api);
713
0
          zlog_warn("PBR: iprule set DSCP/Flow Label %u not supported",
714
0
            api->actions[i].u.marking_dscp);
715
0
        }
716
0
      }
717
0
      if (api->actions[i].action == ACTION_REDIRECT) {
718
0
        if (BGP_DEBUG(pbr, PBR)) {
719
0
          bgp_pbr_print_policy_route(api);
720
0
          zlog_warn("PBR: iprule redirect VRF %u not supported",
721
0
            api->actions[i].u.redirect_vrf);
722
0
        }
723
0
      }
724
0
    }
725
726
0
  } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
727
0
       !(api->match_bitmask & PREFIX_DST_PRESENT)) {
728
0
    if (BGP_DEBUG(pbr, PBR)) {
729
0
      bgp_pbr_print_policy_route(api);
730
0
      zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
731
0
    }
732
0
    return 0;
733
0
  }
734
0
  return 1;
735
0
}
736
737
/* return -1 if build or validation failed */
738
739
int bgp_pbr_build_and_validate_entry(const struct prefix *p,
740
             struct bgp_path_info *path,
741
             struct bgp_pbr_entry_main *api)
742
0
{
743
0
  int ret;
744
0
  uint32_t i, action_count = 0;
745
0
  struct ecommunity *ecom;
746
0
  struct ecommunity_val *ecom_eval;
747
0
  struct bgp_pbr_entry_action *api_action;
748
0
  struct prefix *src = NULL, *dst = NULL;
749
0
  int valid_prefix = 0;
750
0
  struct bgp_pbr_entry_action *api_action_redirect_ip = NULL;
751
0
  bool discard_action_found = false;
752
0
  afi_t afi = family2afi(p->u.prefix_flowspec.family);
753
754
  /* extract match from flowspec entries */
755
0
  ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr,
756
0
              p->u.prefix_flowspec.prefixlen, api, afi);
757
0
  if (ret < 0)
758
0
    return -1;
759
  /* extract actiosn from flowspec ecom list */
760
0
  if (path && bgp_attr_get_ecommunity(path->attr)) {
761
0
    ecom = bgp_attr_get_ecommunity(path->attr);
762
0
    for (i = 0; i < ecom->size; i++) {
763
0
      ecom_eval = (struct ecommunity_val *)
764
0
        (ecom->val + (i * ECOMMUNITY_SIZE));
765
0
      action_count++;
766
0
      if (action_count > ACTIONS_MAX_NUM) {
767
0
        if (BGP_DEBUG(pbr, PBR_ERROR))
768
0
          flog_err(
769
0
            EC_BGP_FLOWSPEC_PACKET,
770
0
            "%s: %s (max %u)",
771
0
            __func__,
772
0
            FSPEC_ACTION_EXCEED_LIMIT,
773
0
            action_count);
774
0
        break;
775
0
      }
776
0
      api_action = &api->actions[action_count - 1];
777
778
0
      if ((ecom_eval->val[1] ==
779
0
           (char)ECOMMUNITY_REDIRECT_VRF) &&
780
0
          (ecom_eval->val[0] ==
781
0
           (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
782
0
           ecom_eval->val[0] ==
783
0
           (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
784
0
           ecom_eval->val[0] ==
785
0
           (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
786
0
        struct ecommunity *eckey = ecommunity_new();
787
0
        struct ecommunity_val ecom_copy;
788
789
0
        memcpy(&ecom_copy, ecom_eval,
790
0
               sizeof(struct ecommunity_val));
791
0
        ecom_copy.val[0] &=
792
0
          ~ECOMMUNITY_ENCODE_TRANS_EXP;
793
0
        ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
794
0
        ecommunity_add_val(eckey, &ecom_copy,
795
0
               false, false);
796
797
0
        api_action->action = ACTION_REDIRECT;
798
0
        api_action->u.redirect_vrf =
799
0
          get_first_vrf_for_redirect_with_rt(
800
0
                eckey);
801
0
        ecommunity_free(&eckey);
802
0
      } else if ((ecom_eval->val[0] ==
803
0
            (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
804
0
           (ecom_eval->val[1] ==
805
0
            (char)ECOMMUNITY_REDIRECT_IP_NH)) {
806
        /* in case the 2 ecom present,
807
         * do not overwrite
808
         * draft-ietf-idr-flowspec-redirect
809
         */
810
0
        if (api_action_redirect_ip &&
811
0
            p->u.prefix_flowspec.family == AF_INET) {
812
0
          if (api_action_redirect_ip->u
813
0
              .zr.redirect_ip_v4.s_addr
814
0
              != INADDR_ANY)
815
0
            continue;
816
0
          if (path->attr->nexthop.s_addr
817
0
              == INADDR_ANY)
818
0
            continue;
819
0
          api_action_redirect_ip->u.zr
820
0
            .redirect_ip_v4.s_addr =
821
0
            path->attr->nexthop.s_addr;
822
0
          api_action_redirect_ip->u.zr.duplicate
823
0
            = ecom_eval->val[7];
824
0
          continue;
825
0
        } else if (api_action_redirect_ip &&
826
0
            p->u.prefix_flowspec.family == AF_INET6) {
827
0
          if (memcmp(&api_action_redirect_ip->u
828
0
               .zr.redirect_ip_v6,
829
0
               &in6addr_any,
830
0
               sizeof(struct in6_addr)))
831
0
            continue;
832
0
          if (path->attr->mp_nexthop_len == 0 ||
833
0
              path->attr->mp_nexthop_len ==
834
0
              BGP_ATTR_NHLEN_IPV4 ||
835
0
              path->attr->mp_nexthop_len ==
836
0
              BGP_ATTR_NHLEN_VPNV4)
837
0
            continue;
838
0
          memcpy(&api_action_redirect_ip->u
839
0
                 .zr.redirect_ip_v6,
840
0
                 &path->attr->mp_nexthop_global,
841
0
                 sizeof(struct in6_addr));
842
0
          api_action_redirect_ip->u.zr.duplicate
843
0
            = ecom_eval->val[7];
844
0
          continue;
845
0
        } else if (p->u.prefix_flowspec.family ==
846
0
             AF_INET) {
847
0
          api_action->action = ACTION_REDIRECT_IP;
848
0
          api_action->u.zr.redirect_ip_v4.s_addr =
849
0
            path->attr->nexthop.s_addr;
850
0
          api_action->u.zr.duplicate =
851
0
            ecom_eval->val[7];
852
0
          api_action_redirect_ip = api_action;
853
0
        } else if (p->u.prefix_flowspec.family ==
854
0
             AF_INET6) {
855
0
          api_action->action = ACTION_REDIRECT_IP;
856
0
          memcpy(&api_action->u
857
0
                 .zr.redirect_ip_v6,
858
0
                 &path->attr->mp_nexthop_global,
859
0
                 sizeof(struct in6_addr));
860
0
          api_action->u.zr.duplicate
861
0
            = ecom_eval->val[7];
862
0
          api_action_redirect_ip = api_action;
863
0
        }
864
0
      } else if ((ecom_eval->val[0] ==
865
0
            (char)ECOMMUNITY_ENCODE_IP) &&
866
0
           (ecom_eval->val[1] ==
867
0
            (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
868
        /* in case the 2 ecom present,
869
         * overwrite simpson draft
870
         * update redirect ip fields
871
         */
872
0
        if (api_action_redirect_ip) {
873
0
          memcpy(&(api_action_redirect_ip->u
874
0
             .zr.redirect_ip_v4.s_addr),
875
0
                 (ecom_eval->val+2), 4);
876
0
          api_action_redirect_ip->u
877
0
            .zr.duplicate =
878
0
            ecom_eval->val[7];
879
0
          continue;
880
0
        } else {
881
0
          api_action->action = ACTION_REDIRECT_IP;
882
0
          memcpy(&(api_action->u
883
0
             .zr.redirect_ip_v4.s_addr),
884
0
                 (ecom_eval->val+2), 4);
885
0
          api_action->u.zr.duplicate =
886
0
            ecom_eval->val[7];
887
0
          api_action_redirect_ip = api_action;
888
0
        }
889
0
      } else {
890
0
        if (ecom_eval->val[0] !=
891
0
            (char)ECOMMUNITY_ENCODE_TRANS_EXP)
892
0
          continue;
893
0
        ret = ecommunity_fill_pbr_action(ecom_eval,
894
0
                 api_action,
895
0
                 afi);
896
0
        if (ret != 0)
897
0
          continue;
898
0
        if ((api_action->action == ACTION_TRAFFICRATE)
899
0
            && api->actions[i].u.r.rate == 0)
900
0
          discard_action_found = true;
901
0
      }
902
0
      api->action_num++;
903
0
    }
904
0
  }
905
0
  if (path && path->attr && bgp_attr_get_ipv6_ecommunity(path->attr)) {
906
0
    struct ecommunity_val_ipv6 *ipv6_ecom_eval;
907
908
0
    ecom = bgp_attr_get_ipv6_ecommunity(path->attr);
909
0
    for (i = 0; i < ecom->size; i++) {
910
0
      ipv6_ecom_eval = (struct ecommunity_val_ipv6 *)
911
0
        (ecom->val + (i * ecom->unit_size));
912
0
      action_count++;
913
0
      if (action_count > ACTIONS_MAX_NUM) {
914
0
        if (BGP_DEBUG(pbr, PBR_ERROR))
915
0
          flog_err(
916
0
            EC_BGP_FLOWSPEC_PACKET,
917
0
            "%s: flowspec actions exceeds limit (max %u)",
918
0
            __func__, action_count);
919
0
        break;
920
0
      }
921
0
      api_action = &api->actions[action_count - 1];
922
0
      if ((ipv6_ecom_eval->val[1] ==
923
0
           (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
924
0
          (ipv6_ecom_eval->val[0] ==
925
0
           (char)ECOMMUNITY_ENCODE_TRANS_EXP)) {
926
0
        struct ecommunity *eckey = ecommunity_new();
927
0
        struct ecommunity_val_ipv6 ecom_copy;
928
929
0
        eckey->unit_size = IPV6_ECOMMUNITY_SIZE;
930
0
        memcpy(&ecom_copy, ipv6_ecom_eval,
931
0
               sizeof(struct ecommunity_val_ipv6));
932
0
        ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
933
0
        ecommunity_add_val_ipv6(eckey, &ecom_copy,
934
0
              false, false);
935
0
        api_action->action = ACTION_REDIRECT;
936
0
        api_action->u.redirect_vrf =
937
0
          get_first_vrf_for_redirect_with_rt(
938
0
                eckey);
939
0
        ecommunity_free(&eckey);
940
0
        api->action_num++;
941
0
      }
942
0
    }
943
0
  }
944
  /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
945
   * then reduce the API action list to that action
946
   */
947
0
  if (api->action_num > 1 && discard_action_found) {
948
0
    api->action_num = 1;
949
0
    memset(&api->actions[0], 0,
950
0
           sizeof(struct bgp_pbr_entry_action));
951
0
    api->actions[0].action = ACTION_TRAFFICRATE;
952
0
  }
953
954
  /* validate if incoming matc/action is compatible
955
   * with our policy routing engine
956
   */
957
0
  if (!bgp_pbr_validate_policy_route(api))
958
0
    return -1;
959
960
  /* check inconsistency in the match rule */
961
0
  if (api->match_bitmask & PREFIX_SRC_PRESENT) {
962
0
    src = &api->src_prefix;
963
0
    afi = family2afi(src->family);
964
0
    valid_prefix = 1;
965
0
  }
966
0
  if (api->match_bitmask & PREFIX_DST_PRESENT) {
967
0
    dst = &api->dst_prefix;
968
0
    if (valid_prefix && afi != family2afi(dst->family)) {
969
0
      if (BGP_DEBUG(pbr, PBR)) {
970
0
        bgp_pbr_print_policy_route(api);
971
0
        zlog_debug("%s: inconsistency: no match for afi src and dst (%u/%u)",
972
0
             __func__, afi, family2afi(dst->family));
973
0
      }
974
0
      return -1;
975
0
    }
976
0
  }
977
0
  return 0;
978
0
}
979
980
static void bgp_pbr_match_entry_free(void *arg)
981
0
{
982
0
  struct bgp_pbr_match_entry *bpme;
983
984
0
  bpme = (struct bgp_pbr_match_entry *)arg;
985
986
0
  if (bpme->installed) {
987
0
    bgp_send_pbr_ipset_entry_match(bpme, false);
988
0
    bpme->installed = false;
989
0
    bpme->backpointer = NULL;
990
0
  }
991
0
  XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
992
0
}
993
994
static void bgp_pbr_match_free(void *arg)
995
0
{
996
0
  struct bgp_pbr_match *bpm;
997
998
0
  bpm = (struct bgp_pbr_match *)arg;
999
1000
0
  hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
1001
1002
0
  if (hashcount(bpm->entry_hash) == 0) {
1003
    /* delete iptable entry first */
1004
    /* then delete ipset match */
1005
0
    if (bpm->installed) {
1006
0
      if (bpm->installed_in_iptable) {
1007
0
        bgp_send_pbr_iptable(bpm->action,
1008
0
                 bpm, false);
1009
0
        bpm->installed_in_iptable = false;
1010
0
        bpm->action->refcnt--;
1011
0
      }
1012
0
      bgp_send_pbr_ipset_match(bpm, false);
1013
0
      bpm->installed = false;
1014
0
      bpm->action = NULL;
1015
0
    }
1016
0
  }
1017
0
  hash_clean_and_free(&bpm->entry_hash, NULL);
1018
1019
0
  XFREE(MTYPE_PBR_MATCH, bpm);
1020
0
}
1021
1022
static void *bgp_pbr_match_alloc_intern(void *arg)
1023
0
{
1024
0
  struct bgp_pbr_match *bpm, *new;
1025
1026
0
  bpm = (struct bgp_pbr_match *)arg;
1027
1028
0
  new = XCALLOC(MTYPE_PBR_MATCH, sizeof(*new));
1029
0
  memcpy(new, bpm, sizeof(*bpm));
1030
1031
0
  return new;
1032
0
}
1033
1034
static void bgp_pbr_rule_free(void *arg)
1035
0
{
1036
0
  struct bgp_pbr_rule *bpr;
1037
1038
0
  bpr = (struct bgp_pbr_rule *)arg;
1039
1040
  /* delete iprule */
1041
0
  if (bpr->installed) {
1042
0
    bgp_send_pbr_rule_action(bpr->action, bpr, false);
1043
0
    bpr->installed = false;
1044
0
    bpr->action->refcnt--;
1045
0
    bpr->action = NULL;
1046
0
  }
1047
0
  XFREE(MTYPE_PBR_RULE, bpr);
1048
0
}
1049
1050
static void *bgp_pbr_rule_alloc_intern(void *arg)
1051
0
{
1052
0
  struct bgp_pbr_rule *bpr, *new;
1053
1054
0
  bpr = (struct bgp_pbr_rule *)arg;
1055
1056
0
  new = XCALLOC(MTYPE_PBR_RULE, sizeof(*new));
1057
0
  memcpy(new, bpr, sizeof(*bpr));
1058
1059
0
  return new;
1060
0
}
1061
1062
static void bgp_pbr_bpa_remove(struct bgp_pbr_action *bpa)
1063
0
{
1064
0
  if ((bpa->refcnt == 0) && bpa->installed && bpa->table_id != 0) {
1065
0
    bgp_send_pbr_rule_action(bpa, NULL, false);
1066
0
    bgp_zebra_announce_default(bpa->bgp, &bpa->nh, bpa->afi,
1067
0
             bpa->table_id, false);
1068
0
    bpa->installed = false;
1069
0
  }
1070
0
}
1071
1072
static void bgp_pbr_bpa_add(struct bgp_pbr_action *bpa)
1073
0
{
1074
0
  if (!bpa->installed && !bpa->install_in_progress) {
1075
0
    bgp_send_pbr_rule_action(bpa, NULL, true);
1076
0
    bgp_zebra_announce_default(bpa->bgp, &bpa->nh, bpa->afi,
1077
0
             bpa->table_id, true);
1078
0
  }
1079
0
}
1080
1081
static void bgp_pbr_action_free(void *arg)
1082
0
{
1083
0
  struct bgp_pbr_action *bpa = arg;
1084
1085
0
  bgp_pbr_bpa_remove(bpa);
1086
1087
0
  XFREE(MTYPE_PBR_ACTION, bpa);
1088
0
}
1089
1090
static void *bgp_pbr_action_alloc_intern(void *arg)
1091
0
{
1092
0
  struct bgp_pbr_action *bpa, *new;
1093
1094
0
  bpa = (struct bgp_pbr_action *)arg;
1095
1096
0
  new = XCALLOC(MTYPE_PBR_ACTION, sizeof(*new));
1097
1098
0
  memcpy(new, bpa, sizeof(*bpa));
1099
1100
0
  return new;
1101
0
}
1102
1103
static void *bgp_pbr_match_entry_alloc_intern(void *arg)
1104
0
{
1105
0
  struct bgp_pbr_match_entry *bpme, *new;
1106
1107
0
  bpme = (struct bgp_pbr_match_entry *)arg;
1108
1109
0
  new = XCALLOC(MTYPE_PBR_MATCH_ENTRY, sizeof(*new));
1110
1111
0
  memcpy(new, bpme, sizeof(*bpme));
1112
1113
0
  return new;
1114
0
}
1115
1116
uint32_t bgp_pbr_match_hash_key(const void *arg)
1117
0
{
1118
0
  const struct bgp_pbr_match *pbm = arg;
1119
0
  uint32_t key;
1120
1121
0
  key = jhash_1word(pbm->vrf_id, 0x4312abde);
1122
0
  key = jhash_1word(pbm->flags, key);
1123
0
  key = jhash_1word(pbm->family, key);
1124
0
  key = jhash(&pbm->pkt_len_min, 2, key);
1125
0
  key = jhash(&pbm->pkt_len_max, 2, key);
1126
0
  key = jhash(&pbm->tcp_flags, 2, key);
1127
0
  key = jhash(&pbm->tcp_mask_flags, 2, key);
1128
0
  key = jhash(&pbm->dscp_value, 1, key);
1129
0
  key = jhash(&pbm->flow_label, 2, key);
1130
0
  key = jhash(&pbm->fragment, 1, key);
1131
0
  key = jhash(&pbm->protocol, 1, key);
1132
0
  return jhash_1word(pbm->type, key);
1133
0
}
1134
1135
bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
1136
0
{
1137
0
  const struct bgp_pbr_match *r1, *r2;
1138
1139
0
  r1 = (const struct bgp_pbr_match *)arg1;
1140
0
  r2 = (const struct bgp_pbr_match *)arg2;
1141
1142
0
  if (r1->vrf_id != r2->vrf_id)
1143
0
    return false;
1144
1145
0
  if (r1->family != r2->family)
1146
0
    return false;
1147
1148
0
  if (r1->type != r2->type)
1149
0
    return false;
1150
1151
0
  if (r1->flags != r2->flags)
1152
0
    return false;
1153
1154
0
  if (r1->action != r2->action)
1155
0
    return false;
1156
1157
0
  if (r1->pkt_len_min != r2->pkt_len_min)
1158
0
    return false;
1159
1160
0
  if (r1->pkt_len_max != r2->pkt_len_max)
1161
0
    return false;
1162
1163
0
  if (r1->tcp_flags != r2->tcp_flags)
1164
0
    return false;
1165
1166
0
  if (r1->tcp_mask_flags != r2->tcp_mask_flags)
1167
0
    return false;
1168
1169
0
  if (r1->dscp_value != r2->dscp_value)
1170
0
    return false;
1171
1172
0
  if (r1->flow_label != r2->flow_label)
1173
0
    return false;
1174
1175
0
  if (r1->fragment != r2->fragment)
1176
0
    return false;
1177
1178
0
  if (r1->protocol != r2->protocol)
1179
0
    return false;
1180
0
  return true;
1181
0
}
1182
1183
uint32_t bgp_pbr_rule_hash_key(const void *arg)
1184
0
{
1185
0
  const struct bgp_pbr_rule *pbr = arg;
1186
0
  uint32_t key;
1187
1188
0
  key = prefix_hash_key(&pbr->src);
1189
0
  key = jhash_1word(pbr->vrf_id, key);
1190
0
  key = jhash_1word(pbr->flags, key);
1191
0
  return jhash_1word(prefix_hash_key(&pbr->dst), key);
1192
0
}
1193
1194
bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
1195
0
{
1196
0
  const struct bgp_pbr_rule *r1, *r2;
1197
1198
0
  r1 = (const struct bgp_pbr_rule *)arg1;
1199
0
  r2 = (const struct bgp_pbr_rule *)arg2;
1200
1201
0
  if (r1->vrf_id != r2->vrf_id)
1202
0
    return false;
1203
1204
0
  if (r1->flags != r2->flags)
1205
0
    return false;
1206
1207
0
  if (r1->action != r2->action)
1208
0
    return false;
1209
1210
0
  if ((r1->flags & MATCH_IP_SRC_SET) &&
1211
0
      !prefix_same(&r1->src, &r2->src))
1212
0
    return false;
1213
1214
0
  if ((r1->flags & MATCH_IP_DST_SET) &&
1215
0
      !prefix_same(&r1->dst, &r2->dst))
1216
0
    return false;
1217
1218
0
  return true;
1219
0
}
1220
1221
uint32_t bgp_pbr_match_entry_hash_key(const void *arg)
1222
0
{
1223
0
  const struct bgp_pbr_match_entry *pbme;
1224
0
  uint32_t key;
1225
1226
0
  pbme = arg;
1227
0
  key = prefix_hash_key(&pbme->src);
1228
0
  key = jhash_1word(prefix_hash_key(&pbme->dst), key);
1229
0
  key = jhash(&pbme->dst_port_min, 2, key);
1230
0
  key = jhash(&pbme->src_port_min, 2, key);
1231
0
  key = jhash(&pbme->dst_port_max, 2, key);
1232
0
  key = jhash(&pbme->src_port_max, 2, key);
1233
0
  key = jhash(&pbme->proto, 1, key);
1234
1235
0
  return key;
1236
0
}
1237
1238
bool bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
1239
0
{
1240
0
  const struct bgp_pbr_match_entry *r1, *r2;
1241
1242
0
  r1 = (const struct bgp_pbr_match_entry *)arg1;
1243
0
  r2 = (const struct bgp_pbr_match_entry *)arg2;
1244
1245
  /*
1246
   * on updates, comparing backpointer is not necessary
1247
   * unique value is self calculated
1248
   * rate is ignored for now
1249
   */
1250
1251
0
  if (!prefix_same(&r1->src, &r2->src))
1252
0
    return false;
1253
1254
0
  if (!prefix_same(&r1->dst, &r2->dst))
1255
0
    return false;
1256
1257
0
  if (r1->src_port_min != r2->src_port_min)
1258
0
    return false;
1259
1260
0
  if (r1->dst_port_min != r2->dst_port_min)
1261
0
    return false;
1262
1263
0
  if (r1->src_port_max != r2->src_port_max)
1264
0
    return false;
1265
1266
0
  if (r1->dst_port_max != r2->dst_port_max)
1267
0
    return false;
1268
1269
0
  if (r1->proto != r2->proto)
1270
0
    return false;
1271
1272
0
  return true;
1273
0
}
1274
1275
uint32_t bgp_pbr_action_hash_key(const void *arg)
1276
0
{
1277
0
  const struct bgp_pbr_action *pbra;
1278
0
  uint32_t key;
1279
1280
0
  pbra = arg;
1281
0
  key = jhash_1word(pbra->table_id, 0x4312abde);
1282
0
  key = jhash_1word(pbra->fwmark, key);
1283
0
  key = jhash_1word(pbra->afi, key);
1284
0
  return key;
1285
0
}
1286
1287
bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
1288
0
{
1289
0
  const struct bgp_pbr_action *r1, *r2;
1290
1291
0
  r1 = (const struct bgp_pbr_action *)arg1;
1292
0
  r2 = (const struct bgp_pbr_action *)arg2;
1293
1294
  /* unique value is self calculated
1295
   * table and fwmark is self calculated
1296
   * rate is ignored
1297
   */
1298
0
  if (r1->vrf_id != r2->vrf_id)
1299
0
    return false;
1300
1301
0
  if (r1->afi != r2->afi)
1302
0
    return false;
1303
1304
0
  return nexthop_same(&r1->nh, &r2->nh);
1305
0
}
1306
1307
struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,
1308
           uint32_t unique)
1309
0
{
1310
0
  struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1311
0
  struct bgp_pbr_rule_unique bpru;
1312
1313
0
  if (!bgp || unique == 0)
1314
0
    return NULL;
1315
0
  bpru.unique = unique;
1316
0
  bpru.bpr_found = NULL;
1317
0
  hash_walk(bgp->pbr_rule_hash, bgp_pbr_rule_walkcb, &bpru);
1318
0
  return bpru.bpr_found;
1319
0
}
1320
1321
struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
1322
              uint32_t unique)
1323
0
{
1324
0
  struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1325
0
  struct bgp_pbr_action_unique bpau;
1326
1327
0
  if (!bgp || unique == 0)
1328
0
    return NULL;
1329
0
  bpau.unique = unique;
1330
0
  bpau.bpa_found = NULL;
1331
0
  hash_walk(bgp->pbr_action_hash, bgp_pbr_action_walkcb, &bpau);
1332
0
  return bpau.bpa_found;
1333
0
}
1334
1335
struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
1336
             uint32_t unique)
1337
0
{
1338
0
  struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1339
0
  struct bgp_pbr_match_unique bpmu;
1340
1341
0
  if (!bgp || unique == 0)
1342
0
    return NULL;
1343
0
  bpmu.unique = unique;
1344
0
  bpmu.bpm_found = NULL;
1345
0
  hash_walk(bgp->pbr_match_hash, bgp_pbr_match_walkcb, &bpmu);
1346
0
  return bpmu.bpm_found;
1347
0
}
1348
1349
struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id,
1350
                   char *ipset_name,
1351
                   uint32_t unique)
1352
0
{
1353
0
  struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1354
0
  struct bgp_pbr_match_entry_unique bpmeu;
1355
0
  struct bgp_pbr_match_ipsetname bpmi;
1356
1357
0
  if (!bgp || unique == 0)
1358
0
    return NULL;
1359
0
  bpmi.ipsetname = XCALLOC(MTYPE_TMP, ZEBRA_IPSET_NAME_SIZE);
1360
0
  snprintf(bpmi.ipsetname, ZEBRA_IPSET_NAME_SIZE, "%s", ipset_name);
1361
0
  bpmi.bpm_found = NULL;
1362
0
  hash_walk(bgp->pbr_match_hash, bgp_pbr_match_pername_walkcb, &bpmi);
1363
0
  XFREE(MTYPE_TMP, bpmi.ipsetname);
1364
0
  if (!bpmi.bpm_found)
1365
0
    return NULL;
1366
0
  bpmeu.bpme_found = NULL;
1367
0
  bpmeu.unique = unique;
1368
0
  hash_walk(bpmi.bpm_found->entry_hash,
1369
0
      bgp_pbr_match_entry_walkcb, &bpmeu);
1370
0
  return bpmeu.bpme_found;
1371
0
}
1372
1373
struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
1374
               uint32_t unique)
1375
0
{
1376
0
  struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1377
0
  struct bgp_pbr_match_iptable_unique bpmiu;
1378
1379
0
  if (!bgp || unique == 0)
1380
0
    return NULL;
1381
0
  bpmiu.unique = unique;
1382
0
  bpmiu.bpm_found = NULL;
1383
0
  hash_walk(bgp->pbr_match_hash, bgp_pbr_match_iptable_walkcb, &bpmiu);
1384
0
  return bpmiu.bpm_found;
1385
0
}
1386
1387
void bgp_pbr_cleanup(struct bgp *bgp)
1388
0
{
1389
0
  hash_clean_and_free(&bgp->pbr_match_hash, bgp_pbr_match_free);
1390
0
  hash_clean_and_free(&bgp->pbr_rule_hash, bgp_pbr_rule_free);
1391
0
  hash_clean_and_free(&bgp->pbr_action_hash, bgp_pbr_action_free);
1392
1393
0
  if (bgp->bgp_pbr_cfg == NULL)
1394
0
    return;
1395
1396
0
  bgp_pbr_reset(bgp, AFI_IP);
1397
0
  bgp_pbr_reset(bgp, AFI_IP6);
1398
0
  XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
1399
0
}
1400
1401
void bgp_pbr_init(struct bgp *bgp)
1402
1
{
1403
1
  bgp->pbr_match_hash =
1404
1
    hash_create_size(8, bgp_pbr_match_hash_key,
1405
1
         bgp_pbr_match_hash_equal,
1406
1
         "Match Hash");
1407
1
  bgp->pbr_action_hash =
1408
1
    hash_create_size(8, bgp_pbr_action_hash_key,
1409
1
         bgp_pbr_action_hash_equal,
1410
1
         "Match Hash Entry");
1411
1412
1
  bgp->pbr_rule_hash =
1413
1
    hash_create_size(8, bgp_pbr_rule_hash_key,
1414
1
         bgp_pbr_rule_hash_equal,
1415
1
         "Match Rule");
1416
1417
1
  bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
1418
1
  bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
1419
1
}
1420
1421
void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
1422
0
{
1423
0
  int i = 0;
1424
0
  char return_string[512];
1425
0
  char *ptr = return_string;
1426
0
  int nb_items = 0;
1427
0
  int delta, len = sizeof(return_string);
1428
1429
0
  delta = snprintf(ptr, sizeof(return_string),  "MATCH : ");
1430
0
  len -= delta;
1431
0
  ptr += delta;
1432
0
  if (api->match_bitmask & PREFIX_SRC_PRESENT) {
1433
0
    struct prefix *p = &(api->src_prefix);
1434
1435
0
    if (api->src_prefix_offset)
1436
0
      delta = snprintfrr(ptr, len, "@src %pFX/off%u", p,
1437
0
             api->src_prefix_offset);
1438
0
    else
1439
0
      delta = snprintfrr(ptr, len, "@src %pFX", p);
1440
0
    len -= delta;
1441
0
    ptr += delta;
1442
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1443
0
  }
1444
0
  if (api->match_bitmask & PREFIX_DST_PRESENT) {
1445
0
    struct prefix *p = &(api->dst_prefix);
1446
1447
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1448
0
    if (api->dst_prefix_offset)
1449
0
      delta = snprintfrr(ptr, len, "@dst %pFX/off%u", p,
1450
0
             api->dst_prefix_offset);
1451
0
    else
1452
0
      delta = snprintfrr(ptr, len, "@dst %pFX", p);
1453
0
    len -= delta;
1454
0
    ptr += delta;
1455
0
  }
1456
1457
0
  if (api->match_protocol_num)
1458
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1459
0
  for (i = 0; i < api->match_protocol_num; i++) {
1460
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->protocol[i],
1461
0
               i > 0 ? NULL : "@proto ");
1462
0
    len -= delta;
1463
0
    ptr += delta;
1464
0
  }
1465
1466
0
  if (api->match_src_port_num)
1467
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1468
0
  for (i = 0; i < api->match_src_port_num; i++) {
1469
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->src_port[i],
1470
0
               i > 0 ? NULL : "@srcport ");
1471
0
    len -= delta;
1472
0
    ptr += delta;
1473
0
  }
1474
1475
0
  if (api->match_dst_port_num)
1476
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1477
0
  for (i = 0; i < api->match_dst_port_num; i++) {
1478
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dst_port[i],
1479
0
               i > 0 ? NULL : "@dstport ");
1480
0
    len -= delta;
1481
0
    ptr += delta;
1482
0
  }
1483
1484
0
  if (api->match_port_num)
1485
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1486
0
  for (i = 0; i < api->match_port_num; i++) {
1487
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->port[i],
1488
0
               i > 0 ? NULL : "@port ");
1489
0
    len -= delta;
1490
0
    ptr += delta;
1491
0
  }
1492
1493
0
  if (api->match_icmp_type_num)
1494
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1495
0
  for (i = 0; i < api->match_icmp_type_num; i++) {
1496
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_type[i],
1497
0
               i > 0 ? NULL : "@icmptype ");
1498
0
    len -= delta;
1499
0
    ptr += delta;
1500
0
  }
1501
1502
0
  if (api->match_icmp_code_num)
1503
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1504
0
  for (i = 0; i < api->match_icmp_code_num; i++) {
1505
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_code[i],
1506
0
               i > 0 ? NULL : "@icmpcode ");
1507
0
    len -= delta;
1508
0
    ptr += delta;
1509
0
  }
1510
1511
0
  if (api->match_packet_length_num)
1512
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1513
0
  for (i = 0; i < api->match_packet_length_num; i++) {
1514
0
    delta = snprintf_bgp_pbr_match_val(ptr, len,
1515
0
               &api->packet_length[i],
1516
0
               i > 0 ? NULL : "@plen ");
1517
0
    len -= delta;
1518
0
    ptr += delta;
1519
0
  }
1520
1521
0
  if (api->match_dscp_num)
1522
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1523
0
  for (i = 0; i < api->match_dscp_num; i++) {
1524
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dscp[i],
1525
0
               i > 0 ? NULL : "@dscp ");
1526
0
    len -= delta;
1527
0
    ptr += delta;
1528
0
  }
1529
1530
0
  if (api->match_flowlabel_num)
1531
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1532
0
  for (i = 0; i < api->match_flowlabel_num; i++) {
1533
0
    delta = snprintf_bgp_pbr_match_val(ptr, len,
1534
0
              &api->flow_label[i],
1535
0
              i > 0 ? NULL : "@flowlabel ");
1536
0
    len -= delta;
1537
0
    ptr += delta;
1538
0
  }
1539
1540
0
  if (api->match_tcpflags_num)
1541
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1542
0
  for (i = 0; i < api->match_tcpflags_num; i++) {
1543
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->tcpflags[i],
1544
0
               i > 0 ? NULL : "@tcpflags ");
1545
0
    len -= delta;
1546
0
    ptr += delta;
1547
0
  }
1548
1549
0
  if (api->match_fragment_num)
1550
0
    INCREMENT_DISPLAY(ptr, nb_items, len);
1551
0
  for (i = 0; i < api->match_fragment_num; i++) {
1552
0
    delta = snprintf_bgp_pbr_match_val(ptr, len, &api->fragment[i],
1553
0
               i > 0 ? NULL : "@fragment ");
1554
0
    len -= delta;
1555
0
    ptr += delta;
1556
0
  }
1557
1558
0
  len = sizeof(return_string);
1559
0
  if (!nb_items) {
1560
0
    ptr = return_string;
1561
0
  } else {
1562
0
    len -= (ptr - return_string);
1563
0
    delta = snprintf(ptr, len, "; ");
1564
0
    len -= delta;
1565
0
    ptr += delta;
1566
0
  }
1567
0
  if (api->action_num) {
1568
0
    delta = snprintf(ptr, len, "SET : ");
1569
0
    len -= delta;
1570
0
    ptr += delta;
1571
0
  }
1572
0
  nb_items = 0;
1573
0
  for (i = 0; i < api->action_num; i++) {
1574
0
    switch (api->actions[i].action) {
1575
0
    case ACTION_TRAFFICRATE:
1576
0
      INCREMENT_DISPLAY(ptr, nb_items, len);
1577
0
      delta = snprintf(ptr, len, "@set rate %f",
1578
0
          api->actions[i].u.r.rate);
1579
0
      len -= delta;
1580
0
      ptr += delta;
1581
0
      break;
1582
0
    case ACTION_TRAFFIC_ACTION:
1583
0
      INCREMENT_DISPLAY(ptr, nb_items, len);
1584
0
      delta = snprintf(ptr, len, "@action ");
1585
0
      len -= delta;
1586
0
      ptr += delta;
1587
0
      if (api->actions[i].u.za.filter
1588
0
          & TRAFFIC_ACTION_TERMINATE) {
1589
0
        delta = snprintf(ptr, len,
1590
0
             " terminate (apply filter(s))");
1591
0
        len -= delta;
1592
0
        ptr += delta;
1593
0
      }
1594
0
      if (api->actions[i].u.za.filter
1595
0
          & TRAFFIC_ACTION_DISTRIBUTE) {
1596
0
        delta = snprintf(ptr, len, " distribute");
1597
0
        len -= delta;
1598
0
        ptr += delta;
1599
0
      }
1600
0
      if (api->actions[i].u.za.filter
1601
0
          & TRAFFIC_ACTION_SAMPLE) {
1602
0
        delta = snprintf(ptr, len, " sample");
1603
0
        len -= delta;
1604
0
        ptr += delta;
1605
0
      }
1606
0
      break;
1607
0
    case ACTION_REDIRECT_IP: {
1608
0
      char local_buff[INET6_ADDRSTRLEN];
1609
0
      void *ptr_ip;
1610
1611
0
      INCREMENT_DISPLAY(ptr, nb_items, len);
1612
0
      if (api->afi == AF_INET)
1613
0
        ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
1614
0
      else
1615
0
        ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
1616
0
      if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff,
1617
0
              sizeof(local_buff)) != NULL) {
1618
0
        delta = snprintf(ptr, len,
1619
0
            "@redirect ip nh %s", local_buff);
1620
0
        len -= delta;
1621
0
        ptr += delta;
1622
0
      }
1623
0
      break;
1624
0
    }
1625
0
    case ACTION_REDIRECT: {
1626
0
      struct vrf *vrf;
1627
1628
0
      vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf);
1629
0
      INCREMENT_DISPLAY(ptr, nb_items, len);
1630
0
      delta = snprintf(ptr, len, "@redirect vrf %s(%u)",
1631
0
           VRF_LOGNAME(vrf),
1632
0
           api->actions[i].u.redirect_vrf);
1633
0
      len -= delta;
1634
0
      ptr += delta;
1635
0
      break;
1636
0
    }
1637
0
    case ACTION_MARKING:
1638
0
      INCREMENT_DISPLAY(ptr, nb_items, len);
1639
0
      delta = snprintf(ptr, len, "@set dscp/flowlabel %u",
1640
0
           api->actions[i].u.marking_dscp);
1641
0
      len -= delta;
1642
0
      ptr += delta;
1643
0
      break;
1644
0
    default:
1645
0
      break;
1646
0
    }
1647
0
  }
1648
0
  zlog_info("%s", return_string);
1649
0
}
1650
1651
static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa,
1652
          struct bgp_pbr_rule *bpr)
1653
0
{
1654
  /* if bpr is null, do nothing
1655
   */
1656
0
  if (bpr == NULL)
1657
0
    return;
1658
0
  if (bpr->installed) {
1659
0
    bgp_send_pbr_rule_action(bpa, bpr, false);
1660
0
    bpr->installed = false;
1661
0
    bpr->action->refcnt--;
1662
0
    bpr->action = NULL;
1663
0
    if (bpr->path) {
1664
0
      struct bgp_path_info *path;
1665
0
      struct bgp_path_info_extra *extra;
1666
1667
      /* unlink path to bpme */
1668
0
      path = (struct bgp_path_info *)bpr->path;
1669
0
      extra = bgp_path_info_extra_get(path);
1670
0
      if (extra->bgp_fs_iprule)
1671
0
        listnode_delete(extra->bgp_fs_iprule, bpr);
1672
0
      bpr->path = NULL;
1673
0
    }
1674
0
  }
1675
0
  hash_release(bgp->pbr_rule_hash, bpr);
1676
0
  bgp_pbr_bpa_remove(bpa);
1677
0
}
1678
1679
static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
1680
        struct bgp_pbr_match *bpm,
1681
        struct bgp_pbr_match_entry *bpme)
1682
0
{
1683
  /* if bpme is null, bpm is also null
1684
   */
1685
0
  if (bpme == NULL)
1686
0
    return;
1687
  /* ipset del entry */
1688
0
  if (bpme->installed) {
1689
0
    bgp_send_pbr_ipset_entry_match(bpme, false);
1690
0
    bpme->installed = false;
1691
0
    bpme->backpointer = NULL;
1692
0
    if (bpme->path) {
1693
0
      struct bgp_path_info *path;
1694
0
      struct bgp_path_info_extra *extra;
1695
1696
      /* unlink path to bpme */
1697
0
      path = (struct bgp_path_info *)bpme->path;
1698
0
      extra = bgp_path_info_extra_get(path);
1699
0
      if (extra->bgp_fs_pbr)
1700
0
        listnode_delete(extra->bgp_fs_pbr, bpme);
1701
0
      bpme->path = NULL;
1702
0
    }
1703
0
  }
1704
0
  hash_release(bpm->entry_hash, bpme);
1705
0
  if (hashcount(bpm->entry_hash) == 0) {
1706
    /* delete iptable entry first */
1707
    /* then delete ipset match */
1708
0
    if (bpm->installed) {
1709
0
      if (bpm->installed_in_iptable) {
1710
0
        bgp_send_pbr_iptable(bpm->action,
1711
0
                 bpm, false);
1712
0
        bpm->installed_in_iptable = false;
1713
0
        bpm->action->refcnt--;
1714
0
      }
1715
0
      bgp_send_pbr_ipset_match(bpm, false);
1716
0
      bpm->installed = false;
1717
0
      bpm->action = NULL;
1718
0
    }
1719
0
    hash_release(bgp->pbr_match_hash, bpm);
1720
    /* XXX release pbr_match_action if not used
1721
     * note that drop does not need to call send_pbr_action
1722
     */
1723
0
  }
1724
0
  bgp_pbr_bpa_remove(bpa);
1725
0
}
1726
1727
struct bgp_pbr_match_entry_remain {
1728
  struct bgp_pbr_match_entry *bpme_to_match;
1729
  struct bgp_pbr_match_entry *bpme_found;
1730
};
1731
1732
struct bgp_pbr_rule_remain {
1733
  struct bgp_pbr_rule *bpr_to_match;
1734
  struct bgp_pbr_rule *bpr_found;
1735
};
1736
1737
static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
1738
0
{
1739
0
  struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data;
1740
0
  struct bgp_pbr_rule_remain *ctxt =
1741
0
    (struct bgp_pbr_rule_remain *)arg;
1742
0
  struct bgp_pbr_rule *r2;
1743
1744
0
  r2 = ctxt->bpr_to_match;
1745
1746
0
  if (r1->vrf_id != r2->vrf_id)
1747
0
    return HASHWALK_CONTINUE;
1748
1749
0
  if (r1->flags != r2->flags)
1750
0
    return HASHWALK_CONTINUE;
1751
1752
0
  if ((r1->flags & MATCH_IP_SRC_SET) &&
1753
0
      !prefix_same(&r1->src, &r2->src))
1754
0
    return HASHWALK_CONTINUE;
1755
1756
0
  if ((r1->flags & MATCH_IP_DST_SET) &&
1757
0
      !prefix_same(&r1->dst, &r2->dst))
1758
0
    return HASHWALK_CONTINUE;
1759
1760
  /* this function is used for two cases:
1761
   * - remove an entry upon withdraw request
1762
   * (case r2->action is null)
1763
   * - replace an old iprule with different action
1764
   * (case r2->action is != null)
1765
   * the old one is removed after the new one
1766
   * this is to avoid disruption in traffic
1767
   */
1768
0
  if (r2->action == NULL ||
1769
0
      r1->action != r2->action) {
1770
0
    ctxt->bpr_found = r1;
1771
0
    return HASHWALK_ABORT;
1772
0
  }
1773
0
  return HASHWALK_CONTINUE;
1774
0
}
1775
1776
static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg)
1777
0
{
1778
0
  struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
1779
0
  struct bgp_pbr_match_entry_remain *bpmer =
1780
0
    (struct bgp_pbr_match_entry_remain *)arg;
1781
0
  struct bgp_pbr_match *bpm_temp;
1782
0
  struct bgp_pbr_match_entry *bpme = bpmer->bpme_to_match;
1783
1784
0
  if (!bpme->backpointer ||
1785
0
      bpm == bpme->backpointer ||
1786
0
      bpme->backpointer->action == bpm->action)
1787
0
    return HASHWALK_CONTINUE;
1788
  /* ensure bpm other characteristics are equal */
1789
0
  bpm_temp = bpme->backpointer;
1790
0
  if (bpm_temp->vrf_id != bpm->vrf_id ||
1791
0
      bpm_temp->type != bpm->type ||
1792
0
      bpm_temp->flags != bpm->flags ||
1793
0
      bpm_temp->tcp_flags != bpm->tcp_flags ||
1794
0
      bpm_temp->tcp_mask_flags != bpm->tcp_mask_flags ||
1795
0
      bpm_temp->pkt_len_min != bpm->pkt_len_min ||
1796
0
      bpm_temp->pkt_len_max != bpm->pkt_len_max ||
1797
0
      bpm_temp->dscp_value != bpm->dscp_value ||
1798
0
      bpm_temp->flow_label != bpm->flow_label ||
1799
0
      bpm_temp->family != bpm->family ||
1800
0
      bpm_temp->fragment != bpm->fragment)
1801
0
    return HASHWALK_CONTINUE;
1802
1803
  /* look for remaining bpme */
1804
0
  bpmer->bpme_found = hash_lookup(bpm->entry_hash, bpme);
1805
0
  if (!bpmer->bpme_found)
1806
0
    return HASHWALK_CONTINUE;
1807
0
  return HASHWALK_ABORT;
1808
0
}
1809
1810
static void bgp_pbr_policyroute_remove_from_zebra_unit(
1811
  struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf)
1812
0
{
1813
0
  struct bgp_pbr_match temp;
1814
0
  struct bgp_pbr_match_entry temp2;
1815
0
  struct bgp_pbr_rule pbr_rule;
1816
0
  struct bgp_pbr_rule *bpr;
1817
0
  struct bgp_pbr_match *bpm;
1818
0
  struct bgp_pbr_match_entry *bpme;
1819
0
  struct bgp_pbr_match_entry_remain bpmer;
1820
0
  struct bgp_pbr_range_port *src_port;
1821
0
  struct bgp_pbr_range_port *dst_port;
1822
0
  struct bgp_pbr_range_port *pkt_len;
1823
0
  struct bgp_pbr_rule_remain bprr;
1824
1825
0
  if (!bpf)
1826
0
    return;
1827
0
  src_port = bpf->src_port;
1828
0
  dst_port = bpf->dst_port;
1829
0
  pkt_len = bpf->pkt_len;
1830
1831
0
  if (BGP_DEBUG(zebra, ZEBRA))
1832
0
    bgp_pbr_dump_entry(bpf, false);
1833
1834
  /* as we don't know information from EC
1835
   * look for bpm that have the bpm
1836
   * with vrf_id characteristics
1837
   */
1838
0
  memset(&temp2, 0, sizeof(temp2));
1839
0
  memset(&temp, 0, sizeof(temp));
1840
1841
0
  if (bpf->type == BGP_PBR_IPRULE) {
1842
0
    memset(&pbr_rule, 0, sizeof(pbr_rule));
1843
0
    pbr_rule.vrf_id = bpf->vrf_id;
1844
0
    if (bpf->src) {
1845
0
      prefix_copy(&pbr_rule.src, bpf->src);
1846
0
      pbr_rule.flags |= MATCH_IP_SRC_SET;
1847
0
    }
1848
0
    if (bpf->dst) {
1849
0
      prefix_copy(&pbr_rule.dst, bpf->dst);
1850
0
      pbr_rule.flags |= MATCH_IP_DST_SET;
1851
0
    }
1852
0
    bpr = &pbr_rule;
1853
    /* A previous entry may already exist
1854
     * flush previous entry if necessary
1855
     */
1856
0
    bprr.bpr_to_match = bpr;
1857
0
    bprr.bpr_found = NULL;
1858
0
    hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
1859
0
    if (bprr.bpr_found) {
1860
0
      static struct bgp_pbr_rule *local_bpr;
1861
0
      static struct bgp_pbr_action *local_bpa;
1862
1863
0
      local_bpr = bprr.bpr_found;
1864
0
      local_bpa = local_bpr->action;
1865
0
      bgp_pbr_flush_iprule(bgp, local_bpa,
1866
0
               local_bpr);
1867
0
    }
1868
0
    return;
1869
0
  }
1870
1871
0
  temp.family = bpf->family;
1872
0
  if (bpf->src) {
1873
0
    temp.flags |= MATCH_IP_SRC_SET;
1874
0
    prefix_copy(&temp2.src, bpf->src);
1875
0
  } else
1876
0
    temp2.src.family = bpf->family;
1877
0
  if (bpf->dst) {
1878
0
    temp.flags |= MATCH_IP_DST_SET;
1879
0
    prefix_copy(&temp2.dst, bpf->dst);
1880
0
  } else
1881
0
    temp2.dst.family = bpf->family;
1882
0
  if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
1883
0
    if (bpf->protocol == IPPROTO_ICMP)
1884
0
      temp.flags |= MATCH_ICMP_SET;
1885
0
    temp.flags |= MATCH_PORT_SRC_SET;
1886
0
    temp2.src_port_min = src_port->min_port;
1887
0
    if (src_port->max_port) {
1888
0
      temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1889
0
      temp2.src_port_max = src_port->max_port;
1890
0
    }
1891
0
  }
1892
0
  if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
1893
0
    if (bpf->protocol == IPPROTO_ICMP)
1894
0
      temp.flags |= MATCH_ICMP_SET;
1895
0
    temp.flags |= MATCH_PORT_DST_SET;
1896
0
    temp2.dst_port_min = dst_port->min_port;
1897
0
    if (dst_port->max_port) {
1898
0
      temp.flags |= MATCH_PORT_DST_RANGE_SET;
1899
0
      temp2.dst_port_max = dst_port->max_port;
1900
0
    }
1901
0
  }
1902
0
  temp2.proto = bpf->protocol;
1903
1904
0
  if (pkt_len) {
1905
0
    temp.pkt_len_min = pkt_len->min_port;
1906
0
    if (pkt_len->max_port)
1907
0
      temp.pkt_len_max = pkt_len->max_port;
1908
0
  } else if (bpf->pkt_len_val) {
1909
0
    if (bpf->pkt_len_val->mask)
1910
0
      temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
1911
0
    temp.pkt_len_min = bpf->pkt_len_val->val;
1912
0
  }
1913
0
  if (bpf->tcp_flags) {
1914
0
    temp.tcp_flags = bpf->tcp_flags->val;
1915
0
    temp.tcp_mask_flags = bpf->tcp_flags->mask;
1916
0
  }
1917
0
  if (bpf->dscp) {
1918
0
    if (bpf->dscp->mask)
1919
0
      temp.flags |= MATCH_DSCP_INVERSE_SET;
1920
0
    else
1921
0
      temp.flags |= MATCH_DSCP_SET;
1922
0
    temp.dscp_value = bpf->dscp->val;
1923
0
  }
1924
0
  if (bpf->flow_label) {
1925
0
    if (bpf->flow_label->mask)
1926
0
      temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
1927
0
    else
1928
0
      temp.flags |= MATCH_FLOW_LABEL_SET;
1929
0
    temp.flow_label = bpf->flow_label->val;
1930
0
  }
1931
1932
0
  if (bpf->fragment) {
1933
0
    if (bpf->fragment->mask)
1934
0
      temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
1935
0
    temp.fragment = bpf->fragment->val;
1936
0
  }
1937
1938
0
  if (bpf->src == NULL || bpf->dst == NULL) {
1939
0
    if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1940
0
      temp.type = IPSET_NET_PORT;
1941
0
    else
1942
0
      temp.type = IPSET_NET;
1943
0
  } else {
1944
0
    if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1945
0
      temp.type = IPSET_NET_PORT_NET;
1946
0
    else
1947
0
      temp.type = IPSET_NET_NET;
1948
0
  }
1949
0
  if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
1950
0
    temp.vrf_id = VRF_DEFAULT;
1951
0
  else
1952
0
    temp.vrf_id = bpf->vrf_id;
1953
0
  bpme = &temp2;
1954
0
  bpm = &temp;
1955
0
  bpme->backpointer = bpm;
1956
  /* right now, a previous entry may already exist
1957
   * flush previous entry if necessary
1958
   */
1959
0
  bpmer.bpme_to_match = bpme;
1960
0
  bpmer.bpme_found = NULL;
1961
0
  hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1962
0
  if (bpmer.bpme_found) {
1963
0
    static struct bgp_pbr_match *local_bpm;
1964
0
    static struct bgp_pbr_action *local_bpa;
1965
1966
0
    local_bpm = bpmer.bpme_found->backpointer;
1967
0
    local_bpa = local_bpm->action;
1968
0
    bgp_pbr_flush_entry(bgp, local_bpa,
1969
0
            local_bpm, bpmer.bpme_found);
1970
0
  }
1971
0
}
1972
1973
static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
1974
0
{
1975
0
  if (type_entry == FLOWSPEC_TCP_FLAGS)
1976
0
    return FLOWSPEC_DSCP;
1977
0
  if (type_entry == FLOWSPEC_DSCP)
1978
0
    return FLOWSPEC_FLOW_LABEL;
1979
0
  if (type_entry == FLOWSPEC_FLOW_LABEL)
1980
0
    return FLOWSPEC_PKT_LEN;
1981
0
  if (type_entry == FLOWSPEC_PKT_LEN)
1982
0
    return FLOWSPEC_FRAGMENT;
1983
0
  if (type_entry == FLOWSPEC_FRAGMENT)
1984
0
    return FLOWSPEC_ICMP_TYPE;
1985
0
  return 0;
1986
0
}
1987
1988
static void bgp_pbr_icmp_action(struct bgp *bgp, struct bgp_path_info *path,
1989
        struct bgp_pbr_filter *bpf,
1990
        struct bgp_pbr_or_filter *bpof, bool add,
1991
        struct nexthop *nh, float *rate)
1992
0
{
1993
0
  struct bgp_pbr_range_port srcp, dstp;
1994
0
  struct bgp_pbr_val_mask *icmp_type, *icmp_code;
1995
0
  struct listnode *tnode, *cnode;
1996
1997
0
  if (!bpf)
1998
0
    return;
1999
0
  if (bpf->protocol != IPPROTO_ICMP)
2000
0
    return;
2001
2002
0
  memset(&srcp, 0, sizeof(srcp));
2003
0
  memset(&dstp, 0, sizeof(dstp));
2004
0
  bpf->src_port = &srcp;
2005
0
  bpf->dst_port = &dstp;
2006
  /* parse icmp type and lookup appropriate icmp code
2007
   * if no icmp code found, create as many entryes as
2008
   * there are listed icmp codes for that icmp type
2009
   */
2010
0
  if (!bpof->icmp_type) {
2011
0
    srcp.min_port = 0;
2012
0
    srcp.max_port = 255;
2013
0
    for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
2014
0
      dstp.min_port = icmp_code->val;
2015
0
      if (add)
2016
0
        bgp_pbr_policyroute_add_to_zebra_unit(
2017
0
          bgp, path, bpf, nh, rate);
2018
0
      else
2019
0
        bgp_pbr_policyroute_remove_from_zebra_unit(
2020
0
          bgp, path, bpf);
2021
0
    }
2022
0
    return;
2023
0
  }
2024
0
  for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
2025
0
    srcp.min_port = icmp_type->val;
2026
0
    srcp.max_port = 0;
2027
0
    dstp.max_port = 0;
2028
    /* only icmp type. create an entry only with icmp type */
2029
0
    if (!bpof->icmp_code) {
2030
      /* icmp type is not one of the above
2031
       * forge an entry only based on the icmp type
2032
       */
2033
0
      dstp.min_port = 0;
2034
0
      dstp.max_port = 255;
2035
0
      if (add)
2036
0
        bgp_pbr_policyroute_add_to_zebra_unit(
2037
0
          bgp, path, bpf, nh, rate);
2038
0
      else
2039
0
        bgp_pbr_policyroute_remove_from_zebra_unit(
2040
0
          bgp, path, bpf);
2041
0
      continue;
2042
0
    }
2043
0
    for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
2044
0
      dstp.min_port = icmp_code->val;
2045
0
      if (add)
2046
0
        bgp_pbr_policyroute_add_to_zebra_unit(
2047
0
          bgp, path, bpf, nh, rate);
2048
0
      else
2049
0
        bgp_pbr_policyroute_remove_from_zebra_unit(
2050
0
          bgp, path, bpf);
2051
0
    }
2052
0
  }
2053
2054
0
  bpf->src_port = NULL;
2055
0
  bpf->dst_port = NULL;
2056
0
}
2057
2058
static void bgp_pbr_policyroute_remove_from_zebra_recursive(
2059
  struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2060
  struct bgp_pbr_or_filter *bpof, uint8_t type_entry)
2061
0
{
2062
0
  struct listnode *node, *nnode;
2063
0
  struct bgp_pbr_val_mask *valmask;
2064
0
  uint8_t next_type_entry;
2065
0
  struct list *orig_list;
2066
0
  struct bgp_pbr_val_mask **target_val;
2067
2068
0
  if (type_entry == 0) {
2069
0
    bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
2070
0
    return;
2071
0
  }
2072
0
  next_type_entry = bgp_pbr_next_type_entry(type_entry);
2073
0
  if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
2074
0
    orig_list = bpof->tcpflags;
2075
0
    target_val = &bpf->tcp_flags;
2076
0
  } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
2077
0
    orig_list = bpof->dscp;
2078
0
    target_val = &bpf->dscp;
2079
0
  } else if (type_entry == FLOWSPEC_FLOW_LABEL && bpof->flowlabel) {
2080
0
    orig_list = bpof->flowlabel;
2081
0
    target_val = &bpf->flow_label;
2082
0
  } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
2083
0
    orig_list = bpof->pkt_len;
2084
0
    target_val = &bpf->pkt_len_val;
2085
0
  } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
2086
0
    orig_list = bpof->fragment;
2087
0
    target_val = &bpf->fragment;
2088
0
  } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
2089
0
       (bpof->icmp_type || bpof->icmp_code)) {
2090
    /* enumerate list for icmp - must be last one  */
2091
0
    bgp_pbr_icmp_action(bgp, path, bpf, bpof, false, NULL, NULL);
2092
0
    return;
2093
0
  } else {
2094
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2095
0
      bgp, path, bpf, bpof, next_type_entry);
2096
0
    return;
2097
0
  }
2098
0
  for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
2099
0
    *target_val = valmask;
2100
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2101
0
      bgp, path, bpf, bpof, next_type_entry);
2102
0
  }
2103
0
}
2104
2105
static void bgp_pbr_policyroute_remove_from_zebra(
2106
  struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2107
  struct bgp_pbr_or_filter *bpof)
2108
0
{
2109
0
  if (!bpof) {
2110
0
    bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
2111
0
    return;
2112
0
  }
2113
0
  if (bpof->tcpflags)
2114
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2115
0
      bgp, path, bpf, bpof, FLOWSPEC_TCP_FLAGS);
2116
0
  else if (bpof->dscp)
2117
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2118
0
      bgp, path, bpf, bpof, FLOWSPEC_DSCP);
2119
0
  else if (bpof->flowlabel)
2120
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2121
0
      bgp, path, bpf, bpof, FLOWSPEC_FLOW_LABEL);
2122
0
  else if (bpof->pkt_len)
2123
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2124
0
      bgp, path, bpf, bpof, FLOWSPEC_PKT_LEN);
2125
0
  else if (bpof->fragment)
2126
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2127
0
      bgp, path, bpf, bpof, FLOWSPEC_FRAGMENT);
2128
0
  else if (bpof->icmp_type || bpof->icmp_code)
2129
0
    bgp_pbr_policyroute_remove_from_zebra_recursive(
2130
0
      bgp, path, bpf, bpof, FLOWSPEC_ICMP_TYPE);
2131
0
  else
2132
0
    bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
2133
  /* flush bpof */
2134
0
  if (bpof->tcpflags)
2135
0
    list_delete_all_node(bpof->tcpflags);
2136
0
  if (bpof->dscp)
2137
0
    list_delete_all_node(bpof->dscp);
2138
0
  if (bpof->flowlabel)
2139
0
    list_delete_all_node(bpof->flowlabel);
2140
0
  if (bpof->pkt_len)
2141
0
    list_delete_all_node(bpof->pkt_len);
2142
0
  if (bpof->fragment)
2143
0
    list_delete_all_node(bpof->fragment);
2144
0
}
2145
2146
static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add)
2147
0
{
2148
0
  struct bgp_pbr_range_port *src_port;
2149
0
  struct bgp_pbr_range_port *dst_port;
2150
0
  struct bgp_pbr_range_port *pkt_len;
2151
0
  char bufsrc[64], bufdst[64];
2152
0
  char buffer[64];
2153
0
  int remaining_len = 0;
2154
0
  char protocol_str[16];
2155
2156
0
  if (!bpf)
2157
0
    return;
2158
0
  src_port = bpf->src_port;
2159
0
  dst_port = bpf->dst_port;
2160
0
  pkt_len = bpf->pkt_len;
2161
2162
0
  protocol_str[0] = '\0';
2163
0
  if (bpf->tcp_flags && bpf->tcp_flags->mask)
2164
0
    bpf->protocol = IPPROTO_TCP;
2165
0
  if (bpf->protocol)
2166
0
    snprintf(protocol_str, sizeof(protocol_str),
2167
0
       "proto %d", bpf->protocol);
2168
0
  buffer[0] = '\0';
2169
0
  if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
2170
0
    remaining_len += snprintf(buffer, sizeof(buffer),
2171
0
            "type %d, code %d",
2172
0
            src_port->min_port,
2173
0
            dst_port->min_port);
2174
0
  else if (bpf->protocol == IPPROTO_UDP ||
2175
0
     bpf->protocol == IPPROTO_TCP) {
2176
2177
0
    if (src_port && src_port->min_port)
2178
0
      remaining_len += snprintf(buffer,
2179
0
              sizeof(buffer),
2180
0
              "from [%u:%u]",
2181
0
              src_port->min_port,
2182
0
              src_port->max_port ?
2183
0
              src_port->max_port :
2184
0
              src_port->min_port);
2185
0
    if (dst_port && dst_port->min_port)
2186
0
      remaining_len += snprintf(buffer +
2187
0
              remaining_len,
2188
0
              sizeof(buffer)
2189
0
              - remaining_len,
2190
0
              "to [%u:%u]",
2191
0
              dst_port->min_port,
2192
0
              dst_port->max_port ?
2193
0
              dst_port->max_port :
2194
0
              dst_port->min_port);
2195
0
  }
2196
0
  if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
2197
0
    remaining_len += snprintf(buffer + remaining_len,
2198
0
            sizeof(buffer)
2199
0
            - remaining_len,
2200
0
            " len [%u:%u]",
2201
0
            pkt_len->min_port,
2202
0
            pkt_len->max_port ?
2203
0
            pkt_len->max_port :
2204
0
            pkt_len->min_port);
2205
0
  } else if (bpf->pkt_len_val) {
2206
0
    remaining_len += snprintf(buffer + remaining_len,
2207
0
            sizeof(buffer)
2208
0
            - remaining_len,
2209
0
            " %s len %u",
2210
0
            bpf->pkt_len_val->mask
2211
0
            ? "!" : "",
2212
0
            bpf->pkt_len_val->val);
2213
0
  }
2214
0
  if (bpf->tcp_flags) {
2215
0
    remaining_len += snprintf(buffer + remaining_len,
2216
0
            sizeof(buffer)
2217
0
            - remaining_len,
2218
0
            "tcpflags %x/%x",
2219
0
            bpf->tcp_flags->val,
2220
0
            bpf->tcp_flags->mask);
2221
0
  }
2222
0
  if (bpf->dscp) {
2223
0
    snprintf(buffer + remaining_len,
2224
0
       sizeof(buffer)
2225
0
       - remaining_len,
2226
0
       "%s dscp %d",
2227
0
       bpf->dscp->mask
2228
0
       ? "!" : "",
2229
0
       bpf->dscp->val);
2230
0
  }
2231
0
  if (bpf->flow_label) {
2232
0
    snprintf(buffer + remaining_len,
2233
0
       sizeof(buffer)
2234
0
       - remaining_len,
2235
0
       "%s flow_label %d",
2236
0
       bpf->flow_label->mask
2237
0
       ? "!" : "",
2238
0
       bpf->flow_label->val);
2239
0
  }
2240
0
  zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
2241
0
      add ? "adding" : "removing",
2242
0
      bpf->src == NULL ? "<all>" :
2243
0
      prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
2244
0
      bpf->dst == NULL ? "<all>" :
2245
0
      prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
2246
0
      protocol_str, buffer);
2247
2248
0
}
2249
2250
static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
2251
              struct bgp_path_info *path,
2252
              struct bgp_pbr_filter *bpf,
2253
              struct nexthop *nh,
2254
              float *rate)
2255
0
{
2256
0
  struct bgp_pbr_match temp;
2257
0
  struct bgp_pbr_match_entry temp2;
2258
0
  struct bgp_pbr_match *bpm;
2259
0
  struct bgp_pbr_match_entry *bpme = NULL;
2260
0
  struct bgp_pbr_action temp3;
2261
0
  struct bgp_pbr_action *bpa = NULL;
2262
0
  struct bgp_pbr_match_entry_remain bpmer;
2263
0
  struct bgp_pbr_rule_remain bprr;
2264
0
  struct bgp_pbr_range_port *src_port;
2265
0
  struct bgp_pbr_range_port *dst_port;
2266
0
  struct bgp_pbr_range_port *pkt_len;
2267
0
  struct bgp_pbr_rule pbr_rule;
2268
0
  struct bgp_pbr_rule *bpr;
2269
0
  bool bpr_found = false;
2270
0
  bool bpme_found = false;
2271
0
  struct vrf *vrf = NULL;
2272
2273
0
  if (!bpf)
2274
0
    return;
2275
0
  src_port = bpf->src_port;
2276
0
  dst_port = bpf->dst_port;
2277
0
  pkt_len = bpf->pkt_len;
2278
2279
0
  if (BGP_DEBUG(zebra, ZEBRA))
2280
0
    bgp_pbr_dump_entry(bpf, true);
2281
2282
  /* look for bpa first */
2283
0
  memset(&temp3, 0, sizeof(temp3));
2284
0
  if (rate)
2285
0
    temp3.rate = *rate;
2286
0
  if (nh)
2287
0
    memcpy(&temp3.nh, nh, sizeof(struct nexthop));
2288
0
  temp3.vrf_id = bpf->vrf_id;
2289
0
  temp3.afi = family2afi(bpf->family);
2290
0
  bpa = hash_get(bgp->pbr_action_hash, &temp3,
2291
0
           bgp_pbr_action_alloc_intern);
2292
2293
0
  if (nh)
2294
0
    vrf = vrf_lookup_by_id(nh->vrf_id);
2295
0
  if (bpa->fwmark == 0) {
2296
    /* drop is handled by iptable */
2297
0
    if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
2298
0
      bpa->table_id = 0;
2299
0
      bpa->installed = true;
2300
0
    } else {
2301
0
      bpa->fwmark = bgp_zebra_tm_get_id();
2302
      /* if action is redirect-vrf, then
2303
       * use directly table_id of vrf
2304
       */
2305
0
      if (nh && vrf && !vrf_is_backend_netns()
2306
0
          && bpf->vrf_id != vrf->vrf_id)
2307
0
        bpa->table_id = vrf->data.l.table_id;
2308
0
      else
2309
0
        bpa->table_id = bpa->fwmark;
2310
0
      bpa->installed = false;
2311
0
    }
2312
0
    bpa->bgp = bgp;
2313
0
    bpa->unique = ++bgp_pbr_action_counter_unique;
2314
    /* 0 value is forbidden */
2315
0
    bpa->install_in_progress = false;
2316
0
  }
2317
0
  if (bpf->type == BGP_PBR_IPRULE) {
2318
0
    memset(&pbr_rule, 0, sizeof(pbr_rule));
2319
0
    pbr_rule.vrf_id = bpf->vrf_id;
2320
0
    pbr_rule.priority = 20;
2321
0
    if (bpf->src) {
2322
0
      pbr_rule.flags |= MATCH_IP_SRC_SET;
2323
0
      prefix_copy(&pbr_rule.src, bpf->src);
2324
0
    }
2325
0
    if (bpf->dst) {
2326
0
      pbr_rule.flags |= MATCH_IP_DST_SET;
2327
0
      prefix_copy(&pbr_rule.dst, bpf->dst);
2328
0
    }
2329
0
    pbr_rule.action = bpa;
2330
0
    bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule,
2331
0
             bgp_pbr_rule_alloc_intern);
2332
0
    if (bpr->unique == 0) {
2333
0
      bpr->unique = ++bgp_pbr_action_counter_unique;
2334
0
      bpr->installed = false;
2335
0
      bpr->install_in_progress = false;
2336
      /* link bgp info to bpr */
2337
0
      bpr->path = (void *)path;
2338
0
    } else
2339
0
      bpr_found = true;
2340
    /* already installed */
2341
0
    if (bpr_found) {
2342
0
      struct bgp_path_info_extra *extra =
2343
0
        bgp_path_info_extra_get(path);
2344
2345
0
      if (extra &&
2346
0
          listnode_lookup_nocheck(extra->bgp_fs_iprule,
2347
0
                bpr)) {
2348
0
        if (BGP_DEBUG(pbr, PBR_ERROR))
2349
0
          zlog_err("%s: entry %p/%p already installed in bgp pbr iprule",
2350
0
             __func__, path, bpr);
2351
0
        return;
2352
0
      }
2353
0
    }
2354
2355
0
    bgp_pbr_bpa_add(bpa);
2356
2357
    /* ip rule add */
2358
0
    if (!bpr->installed)
2359
0
      bgp_send_pbr_rule_action(bpa, bpr, true);
2360
2361
    /* A previous entry may already exist
2362
     * flush previous entry if necessary
2363
     */
2364
0
    bprr.bpr_to_match = bpr;
2365
0
    bprr.bpr_found = NULL;
2366
0
    hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
2367
0
    if (bprr.bpr_found) {
2368
0
      static struct bgp_pbr_rule *local_bpr;
2369
0
      static struct bgp_pbr_action *local_bpa;
2370
2371
0
      local_bpr = bprr.bpr_found;
2372
0
      local_bpa = local_bpr->action;
2373
0
      bgp_pbr_flush_iprule(bgp, local_bpa,
2374
0
               local_bpr);
2375
0
    }
2376
0
    return;
2377
0
  }
2378
  /* then look for bpm */
2379
0
  memset(&temp, 0, sizeof(temp));
2380
0
  temp.vrf_id = bpf->vrf_id;
2381
0
  temp.family = bpf->family;
2382
0
  if (bpf->src)
2383
0
    temp.flags |= MATCH_IP_SRC_SET;
2384
0
  if (bpf->dst)
2385
0
    temp.flags |= MATCH_IP_DST_SET;
2386
2387
0
  if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2388
0
    if (bpf->protocol == IPPROTO_ICMP)
2389
0
      temp.flags |= MATCH_ICMP_SET;
2390
0
    temp.flags |= MATCH_PORT_SRC_SET;
2391
0
  }
2392
0
  if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2393
0
    if (bpf->protocol == IPPROTO_ICMP)
2394
0
      temp.flags |= MATCH_ICMP_SET;
2395
0
    temp.flags |= MATCH_PORT_DST_SET;
2396
0
  }
2397
0
  if (src_port && src_port->max_port)
2398
0
    temp.flags |= MATCH_PORT_SRC_RANGE_SET;
2399
0
  if (dst_port && dst_port->max_port)
2400
0
    temp.flags |= MATCH_PORT_DST_RANGE_SET;
2401
2402
0
  if (bpf->src == NULL || bpf->dst == NULL) {
2403
0
    if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2404
0
      temp.type = IPSET_NET_PORT;
2405
0
    else
2406
0
      temp.type = IPSET_NET;
2407
0
  } else {
2408
0
    if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2409
0
      temp.type = IPSET_NET_PORT_NET;
2410
0
    else
2411
0
      temp.type = IPSET_NET_NET;
2412
0
  }
2413
0
  if (pkt_len) {
2414
0
    temp.pkt_len_min = pkt_len->min_port;
2415
0
    if (pkt_len->max_port)
2416
0
      temp.pkt_len_max = pkt_len->max_port;
2417
0
  } else if (bpf->pkt_len_val) {
2418
0
    if (bpf->pkt_len_val->mask)
2419
0
      temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
2420
0
    temp.pkt_len_min = bpf->pkt_len_val->val;
2421
0
  }
2422
0
  if (bpf->tcp_flags) {
2423
0
    temp.tcp_flags = bpf->tcp_flags->val;
2424
0
    temp.tcp_mask_flags = bpf->tcp_flags->mask;
2425
0
  }
2426
0
  if (bpf->dscp) {
2427
0
    if (bpf->dscp->mask)
2428
0
      temp.flags |= MATCH_DSCP_INVERSE_SET;
2429
0
    else
2430
0
      temp.flags |= MATCH_DSCP_SET;
2431
0
    temp.dscp_value = bpf->dscp->val;
2432
0
  }
2433
0
  if (bpf->flow_label) {
2434
0
    if (bpf->flow_label->mask)
2435
0
      temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
2436
0
    else
2437
0
      temp.flags |= MATCH_FLOW_LABEL_SET;
2438
0
    temp.flow_label = bpf->flow_label->val;
2439
0
  }
2440
0
  if (bpf->fragment) {
2441
0
    if (bpf->fragment->mask)
2442
0
      temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
2443
0
    temp.fragment = bpf->fragment->val;
2444
0
  }
2445
0
  if (bpf->protocol) {
2446
0
    temp.protocol = bpf->protocol;
2447
0
    temp.flags |= MATCH_PROTOCOL_SET;
2448
0
  }
2449
0
  temp.action = bpa;
2450
0
  bpm = hash_get(bgp->pbr_match_hash, &temp,
2451
0
           bgp_pbr_match_alloc_intern);
2452
2453
  /* new, then self allocate ipset_name and unique */
2454
0
  if (bpm->unique == 0) {
2455
0
    bpm->unique = ++bgp_pbr_match_counter_unique;
2456
    /* 0 value is forbidden */
2457
0
    snprintf(bpm->ipset_name, sizeof(bpm->ipset_name),
2458
0
       "match%p", bpm);
2459
0
    bpm->entry_hash = hash_create_size(8,
2460
0
           bgp_pbr_match_entry_hash_key,
2461
0
           bgp_pbr_match_entry_hash_equal,
2462
0
           "Match Entry Hash");
2463
0
    bpm->installed = false;
2464
2465
    /* unique2 should be updated too */
2466
0
    bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
2467
0
    bpm->installed_in_iptable = false;
2468
0
    bpm->install_in_progress = false;
2469
0
    bpm->install_iptable_in_progress = false;
2470
0
  }
2471
2472
0
  memset(&temp2, 0, sizeof(temp2));
2473
0
  if (bpf->src)
2474
0
    prefix_copy(&temp2.src, bpf->src);
2475
0
  else
2476
0
    temp2.src.family = bpf->family;
2477
0
  if (bpf->dst)
2478
0
    prefix_copy(&temp2.dst, bpf->dst);
2479
0
  else
2480
0
    temp2.dst.family = bpf->family;
2481
0
  temp2.src_port_min = src_port ? src_port->min_port : 0;
2482
0
  temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
2483
0
  temp2.src_port_max = src_port ? src_port->max_port : 0;
2484
0
  temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
2485
0
  temp2.proto = bpf->protocol;
2486
0
  bpme = hash_get(bpm->entry_hash, &temp2,
2487
0
      bgp_pbr_match_entry_alloc_intern);
2488
0
  if (bpme->unique == 0) {
2489
0
    bpme->unique = ++bgp_pbr_match_entry_counter_unique;
2490
    /* 0 value is forbidden */
2491
0
    bpme->backpointer = bpm;
2492
0
    bpme->installed = false;
2493
0
    bpme->install_in_progress = false;
2494
    /* link bgp info to bpme */
2495
0
    bpme->path = (void *)path;
2496
0
  } else
2497
0
    bpme_found = true;
2498
2499
  /* already installed */
2500
0
  if (bpme_found) {
2501
0
    struct bgp_path_info_extra *extra =
2502
0
      bgp_path_info_extra_get(path);
2503
2504
0
    if (extra &&
2505
0
        listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) {
2506
0
      if (BGP_DEBUG(pbr, PBR_ERROR))
2507
0
        zlog_err(
2508
0
          "%s: entry %p/%p already installed in bgp pbr",
2509
0
          __func__, path, bpme);
2510
0
      return;
2511
0
    }
2512
0
  }
2513
  /* BGP FS: append entry to zebra
2514
   * - policies are not routing entries and as such
2515
   * route replace semantics don't necessarily follow
2516
   * through to policy entries
2517
   * - because of that, not all policing information will be stored
2518
   * into zebra. and non selected policies will be suppressed from zebra
2519
   * - as consequence, in order to bring consistency
2520
   * a policy will be added, then ifan ecmp policy exists,
2521
   * it will be suppressed subsequently
2522
   */
2523
  /* ip rule add */
2524
0
  bgp_pbr_bpa_add(bpa);
2525
2526
  /* ipset create */
2527
0
  if (!bpm->installed)
2528
0
    bgp_send_pbr_ipset_match(bpm, true);
2529
  /* ipset add */
2530
0
  if (!bpme->installed)
2531
0
    bgp_send_pbr_ipset_entry_match(bpme, true);
2532
2533
  /* iptables */
2534
0
  if (!bpm->installed_in_iptable)
2535
0
    bgp_send_pbr_iptable(bpa, bpm, true);
2536
2537
  /* A previous entry may already exist
2538
   * flush previous entry if necessary
2539
   */
2540
0
  bpmer.bpme_to_match = bpme;
2541
0
  bpmer.bpme_found = NULL;
2542
0
  hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
2543
0
  if (bpmer.bpme_found) {
2544
0
    static struct bgp_pbr_match *local_bpm;
2545
0
    static struct bgp_pbr_action *local_bpa;
2546
2547
0
    local_bpm = bpmer.bpme_found->backpointer;
2548
0
    local_bpa = local_bpm->action;
2549
0
    bgp_pbr_flush_entry(bgp, local_bpa,
2550
0
            local_bpm, bpmer.bpme_found);
2551
0
  }
2552
2553
2554
0
}
2555
2556
static void bgp_pbr_policyroute_add_to_zebra_recursive(
2557
  struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2558
  struct bgp_pbr_or_filter *bpof, struct nexthop *nh, float *rate,
2559
  uint8_t type_entry)
2560
0
{
2561
0
  struct listnode *node, *nnode;
2562
0
  struct bgp_pbr_val_mask *valmask;
2563
0
  uint8_t next_type_entry;
2564
0
  struct list *orig_list;
2565
0
  struct bgp_pbr_val_mask **target_val;
2566
2567
0
  if (type_entry == 0) {
2568
0
    bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2569
0
    return;
2570
0
  }
2571
0
  next_type_entry = bgp_pbr_next_type_entry(type_entry);
2572
0
  if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
2573
0
    orig_list = bpof->tcpflags;
2574
0
    target_val = &bpf->tcp_flags;
2575
0
  } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
2576
0
    orig_list = bpof->dscp;
2577
0
    target_val = &bpf->dscp;
2578
0
  } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
2579
0
    orig_list = bpof->pkt_len;
2580
0
    target_val = &bpf->pkt_len_val;
2581
0
  } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
2582
0
    orig_list = bpof->fragment;
2583
0
    target_val = &bpf->fragment;
2584
0
  } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
2585
0
       (bpof->icmp_type || bpof->icmp_code)) {
2586
    /* enumerate list for icmp - must be last one  */
2587
0
    bgp_pbr_icmp_action(bgp, path, bpf, bpof, true, nh, rate);
2588
0
    return;
2589
0
  } else {
2590
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2591
0
      bgp, path, bpf, bpof, nh, rate, next_type_entry);
2592
0
    return;
2593
0
  }
2594
0
  for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
2595
0
    *target_val = valmask;
2596
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2597
0
      bgp, path, bpf, bpof, nh, rate, next_type_entry);
2598
0
  }
2599
0
}
2600
2601
static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
2602
               struct bgp_path_info *path,
2603
               struct bgp_pbr_filter *bpf,
2604
               struct bgp_pbr_or_filter *bpof,
2605
               struct nexthop *nh, float *rate)
2606
0
{
2607
0
  if (!bpof) {
2608
0
    bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2609
0
    return;
2610
0
  }
2611
0
  if (bpof->tcpflags)
2612
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2613
0
      bgp, path, bpf, bpof, nh, rate, FLOWSPEC_TCP_FLAGS);
2614
0
  else if (bpof->dscp)
2615
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2616
0
      bgp, path, bpf, bpof, nh, rate, FLOWSPEC_DSCP);
2617
0
  else if (bpof->pkt_len)
2618
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2619
0
      bgp, path, bpf, bpof, nh, rate, FLOWSPEC_PKT_LEN);
2620
0
  else if (bpof->fragment)
2621
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2622
0
      bgp, path, bpf, bpof, nh, rate, FLOWSPEC_FRAGMENT);
2623
0
  else if (bpof->icmp_type || bpof->icmp_code)
2624
0
    bgp_pbr_policyroute_add_to_zebra_recursive(
2625
0
      bgp, path, bpf, bpof, nh, rate, FLOWSPEC_ICMP_TYPE);
2626
0
  else
2627
0
    bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2628
  /* flush bpof */
2629
0
  if (bpof->tcpflags)
2630
0
    list_delete_all_node(bpof->tcpflags);
2631
0
  if (bpof->dscp)
2632
0
    list_delete_all_node(bpof->dscp);
2633
0
  if (bpof->pkt_len)
2634
0
    list_delete_all_node(bpof->pkt_len);
2635
0
  if (bpof->fragment)
2636
0
    list_delete_all_node(bpof->fragment);
2637
0
  if (bpof->icmp_type)
2638
0
    list_delete_all_node(bpof->icmp_type);
2639
0
  if (bpof->icmp_code)
2640
0
    list_delete_all_node(bpof->icmp_code);
2641
0
}
2642
2643
static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
2644
         struct bgp_pbr_entry_main *api, bool add)
2645
0
{
2646
0
  struct nexthop nh;
2647
0
  int i = 0;
2648
0
  int continue_loop = 1;
2649
0
  float rate = 0;
2650
0
  struct prefix *src = NULL, *dst = NULL;
2651
0
  uint8_t proto = 0;
2652
0
  struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
2653
0
  struct bgp_pbr_range_port range, range_icmp_code;
2654
0
  struct bgp_pbr_range_port pkt_len;
2655
0
  struct bgp_pbr_filter bpf;
2656
0
  uint8_t kind_enum;
2657
0
  struct bgp_pbr_or_filter bpof;
2658
0
  struct bgp_pbr_val_mask bpvm;
2659
2660
0
  memset(&range, 0, sizeof(range));
2661
0
  memset(&nh, 0, sizeof(nh));
2662
0
  memset(&bpf, 0, sizeof(bpf));
2663
0
  memset(&bpof, 0, sizeof(bpof));
2664
0
  if (api->match_bitmask & PREFIX_SRC_PRESENT ||
2665
0
      (api->type == BGP_PBR_IPRULE &&
2666
0
       api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
2667
0
    src = &api->src_prefix;
2668
0
  if (api->match_bitmask & PREFIX_DST_PRESENT ||
2669
0
      (api->type == BGP_PBR_IPRULE &&
2670
0
       api->match_bitmask_iprule & PREFIX_DST_PRESENT))
2671
0
    dst = &api->dst_prefix;
2672
0
  if (api->type == BGP_PBR_IPRULE)
2673
0
    bpf.type = api->type;
2674
0
  memset(&nh, 0, sizeof(nh));
2675
0
  nh.vrf_id = VRF_UNKNOWN;
2676
0
  if (api->match_protocol_num) {
2677
0
    proto = (uint8_t)api->protocol[0].value;
2678
0
    if (api->afi == AF_INET6 && proto == IPPROTO_ICMPV6)
2679
0
      proto = IPPROTO_ICMP;
2680
0
  }
2681
  /* if match_port is selected, then either src or dst port will be parsed
2682
   * but not both at the same time
2683
   */
2684
0
  if (api->match_port_num >= 1) {
2685
0
    bgp_pbr_extract(api->port,
2686
0
        api->match_port_num,
2687
0
        &range);
2688
0
    srcp = dstp = &range;
2689
0
  } else if (api->match_src_port_num >= 1) {
2690
0
    bgp_pbr_extract(api->src_port,
2691
0
        api->match_src_port_num,
2692
0
        &range);
2693
0
    srcp = &range;
2694
0
    dstp = NULL;
2695
0
  } else if (api->match_dst_port_num >= 1) {
2696
0
    bgp_pbr_extract(api->dst_port,
2697
0
        api->match_dst_port_num,
2698
0
        &range);
2699
0
    dstp = &range;
2700
0
    srcp = NULL;
2701
0
  }
2702
0
  if (api->match_icmp_type_num >= 1) {
2703
0
    proto = IPPROTO_ICMP;
2704
0
    if (bgp_pbr_extract(api->icmp_type,
2705
0
            api->match_icmp_type_num,
2706
0
            &range))
2707
0
      srcp = &range;
2708
0
    else {
2709
0
      bpof.icmp_type = list_new();
2710
0
      bgp_pbr_extract_enumerate(api->icmp_type,
2711
0
              api->match_icmp_type_num,
2712
0
              OPERATOR_UNARY_OR,
2713
0
              bpof.icmp_type,
2714
0
              FLOWSPEC_ICMP_TYPE);
2715
0
    }
2716
0
  }
2717
0
  if (api->match_icmp_code_num >= 1) {
2718
0
    proto = IPPROTO_ICMP;
2719
0
    if (bgp_pbr_extract(api->icmp_code,
2720
0
            api->match_icmp_code_num,
2721
0
            &range_icmp_code))
2722
0
      dstp = &range_icmp_code;
2723
0
    else {
2724
0
      bpof.icmp_code = list_new();
2725
0
      bgp_pbr_extract_enumerate(api->icmp_code,
2726
0
              api->match_icmp_code_num,
2727
0
              OPERATOR_UNARY_OR,
2728
0
              bpof.icmp_code,
2729
0
              FLOWSPEC_ICMP_CODE);
2730
0
    }
2731
0
  }
2732
2733
0
  if (api->match_tcpflags_num) {
2734
0
    kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
2735
0
               api->match_tcpflags_num);
2736
0
    if (kind_enum == OPERATOR_UNARY_AND) {
2737
0
      bpf.tcp_flags = &bpvm;
2738
0
      bgp_pbr_extract_enumerate(api->tcpflags,
2739
0
              api->match_tcpflags_num,
2740
0
              OPERATOR_UNARY_AND,
2741
0
              bpf.tcp_flags,
2742
0
              FLOWSPEC_TCP_FLAGS);
2743
0
    } else if (kind_enum == OPERATOR_UNARY_OR) {
2744
0
      bpof.tcpflags = list_new();
2745
0
      bgp_pbr_extract_enumerate(api->tcpflags,
2746
0
              api->match_tcpflags_num,
2747
0
              OPERATOR_UNARY_OR,
2748
0
              bpof.tcpflags,
2749
0
              FLOWSPEC_TCP_FLAGS);
2750
0
    }
2751
0
  }
2752
0
  if (api->match_packet_length_num) {
2753
0
    bool ret;
2754
2755
0
    ret = bgp_pbr_extract(api->packet_length,
2756
0
              api->match_packet_length_num,
2757
0
              &pkt_len);
2758
0
    if (ret)
2759
0
      bpf.pkt_len = &pkt_len;
2760
0
    else {
2761
0
      bpof.pkt_len = list_new();
2762
0
      bgp_pbr_extract_enumerate(api->packet_length,
2763
0
              api->match_packet_length_num,
2764
0
              OPERATOR_UNARY_OR,
2765
0
              bpof.pkt_len,
2766
0
              FLOWSPEC_PKT_LEN);
2767
0
    }
2768
0
  }
2769
0
  if (api->match_dscp_num >= 1) {
2770
0
    bpof.dscp = list_new();
2771
0
    bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
2772
0
            OPERATOR_UNARY_OR,
2773
0
            bpof.dscp, FLOWSPEC_DSCP);
2774
0
  }
2775
0
  if (api->match_fragment_num) {
2776
0
    bpof.fragment = list_new();
2777
0
    bgp_pbr_extract_enumerate(api->fragment,
2778
0
            api->match_fragment_num,
2779
0
            OPERATOR_UNARY_OR,
2780
0
            bpof.fragment,
2781
0
            FLOWSPEC_FRAGMENT);
2782
0
  }
2783
0
  bpf.vrf_id = api->vrf_id;
2784
0
  bpf.src = src;
2785
0
  bpf.dst = dst;
2786
0
  bpf.protocol = proto;
2787
0
  bpf.src_port = srcp;
2788
0
  bpf.dst_port = dstp;
2789
0
  bpf.family = afi2family(api->afi);
2790
0
  if (!add) {
2791
0
    bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
2792
0
    return;
2793
0
  }
2794
  /* no action for add = true */
2795
0
  for (i = 0; i < api->action_num; i++) {
2796
0
    switch (api->actions[i].action) {
2797
0
    case ACTION_TRAFFICRATE:
2798
      /* drop packet */
2799
0
      if (api->actions[i].u.r.rate == 0) {
2800
0
        nh.vrf_id = api->vrf_id;
2801
0
        nh.type = NEXTHOP_TYPE_BLACKHOLE;
2802
0
        bgp_pbr_policyroute_add_to_zebra(
2803
0
          bgp, path, &bpf, &bpof, &nh, &rate);
2804
0
      } else {
2805
        /* update rate. can be reentrant */
2806
0
        rate = api->actions[i].u.r.rate;
2807
0
        if (BGP_DEBUG(pbr, PBR)) {
2808
0
          bgp_pbr_print_policy_route(api);
2809
0
          zlog_warn("PBR: ignoring Set action rate %f",
2810
0
              api->actions[i].u.r.rate);
2811
0
        }
2812
0
      }
2813
0
      break;
2814
0
    case ACTION_TRAFFIC_ACTION:
2815
0
      if (api->actions[i].u.za.filter
2816
0
          & TRAFFIC_ACTION_SAMPLE) {
2817
0
        if (BGP_DEBUG(pbr, PBR)) {
2818
0
          bgp_pbr_print_policy_route(api);
2819
0
          zlog_warn("PBR: Sample action Ignored");
2820
0
        }
2821
0
      }
2822
      /* terminate action: run other filters
2823
       */
2824
0
      break;
2825
0
    case ACTION_REDIRECT_IP:
2826
0
      nh.vrf_id = api->vrf_id;
2827
0
      if (api->afi == AFI_IP) {
2828
0
        nh.type = NEXTHOP_TYPE_IPV4;
2829
0
        nh.gate.ipv4.s_addr =
2830
0
          api->actions[i].u.zr.
2831
0
          redirect_ip_v4.s_addr;
2832
0
      } else {
2833
0
        nh.type = NEXTHOP_TYPE_IPV6;
2834
0
        memcpy(&nh.gate.ipv6,
2835
0
               &api->actions[i].u.zr.redirect_ip_v6,
2836
0
               sizeof(struct in6_addr));
2837
0
      }
2838
0
      bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
2839
0
               &nh, &rate);
2840
      /* XXX combination with REDIRECT_VRF
2841
       * + REDIRECT_NH_IP not done
2842
       */
2843
0
      continue_loop = 0;
2844
0
      break;
2845
0
    case ACTION_REDIRECT:
2846
0
      if (api->afi == AFI_IP)
2847
0
        nh.type = NEXTHOP_TYPE_IPV4;
2848
0
      else
2849
0
        nh.type = NEXTHOP_TYPE_IPV6;
2850
0
      nh.vrf_id = api->actions[i].u.redirect_vrf;
2851
0
      bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
2852
0
               &nh, &rate);
2853
0
      continue_loop = 0;
2854
0
      break;
2855
0
    case ACTION_MARKING:
2856
0
      if (BGP_DEBUG(pbr, PBR)) {
2857
0
        bgp_pbr_print_policy_route(api);
2858
0
        zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
2859
0
            api->actions[i].u.marking_dscp);
2860
0
      }
2861
0
      break;
2862
0
    default:
2863
0
      break;
2864
0
    }
2865
0
    if (continue_loop == 0)
2866
0
      break;
2867
0
  }
2868
0
}
2869
2870
void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p,
2871
        struct bgp_path_info *info, afi_t afi, safi_t safi,
2872
        bool nlri_update)
2873
0
{
2874
0
  struct bgp_pbr_entry_main api;
2875
2876
0
  if (safi != SAFI_FLOWSPEC)
2877
0
    return; /* not supported */
2878
  /* Make Zebra API structure. */
2879
0
  memset(&api, 0, sizeof(api));
2880
0
  api.vrf_id = bgp->vrf_id;
2881
0
  api.afi = afi;
2882
2883
0
  if (!bgp_zebra_tm_chunk_obtained()) {
2884
0
    if (BGP_DEBUG(pbr, PBR_ERROR))
2885
0
      flog_err(EC_BGP_TABLE_CHUNK,
2886
0
         "%s: table chunk not obtained yet", __func__);
2887
0
    return;
2888
0
  }
2889
2890
0
  if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
2891
0
    if (BGP_DEBUG(pbr, PBR_ERROR))
2892
0
      flog_err(EC_BGP_FLOWSPEC_INSTALLATION,
2893
0
         "%s: cancel updating entry %p in bgp pbr",
2894
0
         __func__, info);
2895
0
    return;
2896
0
  }
2897
0
  bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
2898
0
}
2899
2900
int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
2901
        const struct bgp_pbr_interface *b)
2902
0
{
2903
0
  return strcmp(a->name, b->name);
2904
0
}
2905
2906
struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
2907
             struct bgp_pbr_interface_head *head)
2908
0
{
2909
0
  struct bgp_pbr_interface pbr_if;
2910
2911
0
  strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
2912
0
  return (RB_FIND(bgp_pbr_interface_head,
2913
0
      head, &pbr_if));
2914
0
}
2915
2916
/* this function resets to the default policy routing
2917
 * go back to default status
2918
 */
2919
void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
2920
0
{
2921
0
  struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
2922
0
  struct bgp_pbr_interface_head *head;
2923
0
  struct bgp_pbr_interface *pbr_if;
2924
2925
0
  if (!bgp_pbr_cfg)
2926
0
    return;
2927
0
  if (afi == AFI_IP)
2928
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
2929
0
  else
2930
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
2931
0
  while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
2932
0
    pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
2933
0
    RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
2934
0
    XFREE(MTYPE_TMP, pbr_if);
2935
0
  }
2936
0
}