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