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
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.
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
26 #include "bgpd/bgpd.h"
27 #include "bgpd/bgp_pbr.h"
28 #include "bgpd/bgp_debug.h"
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"
33 #include "bgpd/bgp_zebra.h"
34 #include "bgpd/bgp_mplsvpn.h"
35 #include "bgpd/bgp_flowspec_private.h"
36 #include "bgpd/bgp_errors.h"
38 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry")
39 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match")
40 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action")
41 DEFINE_MTYPE_STATIC(BGPD
, PBR_RULE
, "PBR rule")
42 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context")
43 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value")
45 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
46 id_entry
, bgp_pbr_interface_compare
);
47 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
48 RB_INITIALIZER(&ifaces_by_name_ipv4
);
50 static int bgp_pbr_match_counter_unique
;
51 static int bgp_pbr_match_entry_counter_unique
;
52 static int bgp_pbr_action_counter_unique
;
53 static int bgp_pbr_match_iptable_counter_unique
;
55 struct bgp_pbr_match_iptable_unique
{
57 struct bgp_pbr_match
*bpm_found
;
60 struct bgp_pbr_match_entry_unique
{
62 struct bgp_pbr_match_entry
*bpme_found
;
65 struct bgp_pbr_action_unique
{
67 struct bgp_pbr_action
*bpa_found
;
70 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
72 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
73 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
75 uint32_t unique
= bpau
->unique
;
77 if (bpa
->unique
== unique
) {
78 bpau
->bpa_found
= bpa
;
79 return HASHWALK_ABORT
;
81 return HASHWALK_CONTINUE
;
84 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
86 struct bgp_pbr_match_entry
*bpme
=
87 (struct bgp_pbr_match_entry
*)backet
->data
;
88 struct bgp_pbr_match_entry_unique
*bpmeu
=
89 (struct bgp_pbr_match_entry_unique
*)arg
;
90 uint32_t unique
= bpmeu
->unique
;
92 if (bpme
->unique
== unique
) {
93 bpmeu
->bpme_found
= bpme
;
94 return HASHWALK_ABORT
;
96 return HASHWALK_CONTINUE
;
99 struct bgp_pbr_match_ipsetname
{
101 struct bgp_pbr_match
*bpm_found
;
104 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
106 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
107 struct bgp_pbr_match_ipsetname
*bpmi
=
108 (struct bgp_pbr_match_ipsetname
*)arg
;
109 char *ipset_name
= bpmi
->ipsetname
;
111 if (!strncmp(ipset_name
, bpm
->ipset_name
,
112 ZEBRA_IPSET_NAME_SIZE
)) {
113 bpmi
->bpm_found
= bpm
;
114 return HASHWALK_ABORT
;
116 return HASHWALK_CONTINUE
;
119 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
121 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
122 struct bgp_pbr_match_iptable_unique
*bpmiu
=
123 (struct bgp_pbr_match_iptable_unique
*)arg
;
124 uint32_t unique
= bpmiu
->unique
;
126 if (bpm
->unique2
== unique
) {
127 bpmiu
->bpm_found
= bpm
;
128 return HASHWALK_ABORT
;
130 return HASHWALK_CONTINUE
;
133 struct bgp_pbr_match_unique
{
135 struct bgp_pbr_match
*bpm_found
;
138 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
140 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
141 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
143 uint32_t unique
= bpmu
->unique
;
145 if (bpm
->unique
== unique
) {
146 bpmu
->bpm_found
= bpm
;
147 return HASHWALK_ABORT
;
149 return HASHWALK_CONTINUE
;
152 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
158 ptr
+= sprintf(ptr
, "%s", prepend
);
160 if (mval
->unary_operator
& OPERATOR_UNARY_OR
)
161 ptr
+= sprintf(ptr
, ", or ");
162 if (mval
->unary_operator
& OPERATOR_UNARY_AND
)
163 ptr
+= sprintf(ptr
, ", and ");
165 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
)
166 ptr
+= sprintf(ptr
, "<");
167 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
)
168 ptr
+= sprintf(ptr
, ">");
169 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
)
170 ptr
+= sprintf(ptr
, "=");
171 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
)
172 ptr
+= sprintf(ptr
, "match");
173 ptr
+= sprintf(ptr
, " %u", mval
->value
);
174 return (int)(ptr
- str
);
177 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
179 (_ptr) += sprintf((_ptr), "; "); \
183 /* this structure can be used for port range,
184 * but also for other values range like packet length range
186 struct bgp_pbr_range_port
{
191 /* this structure can be used to filter with a mask
192 * for instance it supports not instructions like for
195 struct bgp_pbr_val_mask
{
200 /* this structure is used to pass instructs
201 * so that BGP can create pbr instructions to ZEBRA
203 struct bgp_pbr_filter
{
208 uint8_t bitmask_iprule
;
210 struct bgp_pbr_range_port
*pkt_len
;
211 struct bgp_pbr_range_port
*src_port
;
212 struct bgp_pbr_range_port
*dst_port
;
213 struct bgp_pbr_val_mask
*tcp_flags
;
214 struct bgp_pbr_val_mask
*dscp
;
215 struct bgp_pbr_val_mask
*pkt_len_val
;
216 struct bgp_pbr_val_mask
*fragment
;
219 /* this structure is used to contain OR instructions
220 * so that BGP can create multiple pbr instructions
223 struct bgp_pbr_or_filter
{
224 struct list
*tcpflags
;
226 struct list
*pkt_len
;
227 struct list
*fragment
;
228 struct list
*icmp_type
;
229 struct list
*icmp_code
;
232 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
233 struct bgp_path_info
*path
,
234 struct bgp_pbr_filter
*bpf
,
238 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
240 static bool bgp_pbr_extract_enumerate_unary_opposite(
241 uint8_t unary_operator
,
242 struct bgp_pbr_val_mask
*and_valmask
,
243 struct list
*or_valmask
, uint32_t value
,
246 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
247 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
249 TCP_HEADER_ALL_FLAGS
&
251 } else if (type_entry
== FLOWSPEC_DSCP
||
252 type_entry
== FLOWSPEC_PKT_LEN
||
253 type_entry
== FLOWSPEC_FRAGMENT
) {
254 and_valmask
->val
= value
;
255 and_valmask
->mask
= 1; /* inverse */
257 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
258 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
259 sizeof(struct bgp_pbr_val_mask
));
260 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
261 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
263 TCP_HEADER_ALL_FLAGS
&
265 } else if (type_entry
== FLOWSPEC_DSCP
||
266 type_entry
== FLOWSPEC_FRAGMENT
||
267 type_entry
== FLOWSPEC_PKT_LEN
) {
268 and_valmask
->val
= value
;
269 and_valmask
->mask
= 1; /* inverse */
271 listnode_add(or_valmask
, and_valmask
);
272 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
273 type_entry
== FLOWSPEC_ICMP_TYPE
)
278 /* TCP : FIN and SYN -> val = ALL; mask = 3
279 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
280 * other variables type: dscp, pkt len, fragment
281 * - value is copied in bgp_pbr_val_mask->val value
282 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
284 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
285 int num
, uint8_t unary_operator
,
286 void *valmask
, uint8_t type_entry
)
289 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
290 struct list
*or_valmask
= NULL
;
294 if (unary_operator
== OPERATOR_UNARY_AND
) {
295 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
296 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
297 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
298 or_valmask
= (struct list
*)valmask
;
301 for (i
= 0; i
< num
; i
++) {
302 if (i
!= 0 && list
[i
].unary_operator
!=
305 if (!(list
[i
].compare_operator
&
306 OPERATOR_COMPARE_EQUAL_TO
) &&
307 !(list
[i
].compare_operator
&
308 OPERATOR_COMPARE_EXACT_MATCH
)) {
309 if ((list
[i
].compare_operator
&
310 OPERATOR_COMPARE_LESS_THAN
) &&
311 (list
[i
].compare_operator
&
312 OPERATOR_COMPARE_GREATER_THAN
)) {
313 ret
= bgp_pbr_extract_enumerate_unary_opposite(
314 unary_operator
, and_valmask
,
315 or_valmask
, list
[i
].value
,
323 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
324 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
326 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
327 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
328 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
329 sizeof(struct bgp_pbr_val_mask
));
330 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
331 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
333 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
334 } else if (type_entry
== FLOWSPEC_DSCP
||
335 type_entry
== FLOWSPEC_ICMP_TYPE
||
336 type_entry
== FLOWSPEC_ICMP_CODE
||
337 type_entry
== FLOWSPEC_FRAGMENT
||
338 type_entry
== FLOWSPEC_PKT_LEN
)
339 and_valmask
->val
= list
[i
].value
;
340 listnode_add(or_valmask
, and_valmask
);
343 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
344 && type_entry
== FLOWSPEC_TCP_FLAGS
)
345 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
349 /* if unary operator can either be UNARY_OR/AND/OR-AND.
350 * in the latter case, combinationf of both is not handled
352 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
353 int num
, uint8_t unary_operator
,
354 void *valmask
, uint8_t type_entry
)
357 uint8_t unary_operator_val
;
358 bool double_check
= false;
360 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
361 (unary_operator
& OPERATOR_UNARY_AND
)) {
362 unary_operator_val
= OPERATOR_UNARY_AND
;
365 unary_operator_val
= unary_operator
;
366 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
367 valmask
, type_entry
);
368 if (!ret
&& double_check
)
369 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
376 /* returns the unary operator that is in the list
377 * return 0 if both operators are used
379 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
384 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
386 for (i
= 0; i
< num
; i
++) {
389 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
390 unary_operator
= OPERATOR_UNARY_OR
;
391 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
392 && unary_operator
== OPERATOR_UNARY_OR
) ||
393 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
394 && unary_operator
== OPERATOR_UNARY_AND
))
397 return unary_operator
;
401 /* return true if extraction ok
403 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
405 struct bgp_pbr_range_port
*range
)
408 bool exact_match
= false;
411 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
415 for (i
= 0; i
< num
; i
++) {
416 if (i
!= 0 && (list
[i
].compare_operator
==
417 OPERATOR_COMPARE_EQUAL_TO
))
419 if (i
== 0 && (list
[i
].compare_operator
==
420 OPERATOR_COMPARE_EQUAL_TO
)) {
422 range
->min_port
= list
[i
].value
;
425 if (exact_match
== true && i
> 0)
427 if (list
[i
].compare_operator
==
428 (OPERATOR_COMPARE_GREATER_THAN
+
429 OPERATOR_COMPARE_EQUAL_TO
)) {
431 range
->min_port
= list
[i
].value
;
432 } else if (list
[i
].compare_operator
==
433 (OPERATOR_COMPARE_LESS_THAN
+
434 OPERATOR_COMPARE_EQUAL_TO
)) {
436 range
->max_port
= list
[i
].value
;
437 } else if (list
[i
].compare_operator
==
438 OPERATOR_COMPARE_LESS_THAN
) {
440 range
->max_port
= list
[i
].value
- 1;
441 } else if (list
[i
].compare_operator
==
442 OPERATOR_COMPARE_GREATER_THAN
) {
444 range
->min_port
= list
[i
].value
+ 1;
450 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
452 bool enumerate_icmp
= false;
454 if (api
->type
== BGP_PBR_UNDEFINED
) {
455 if (BGP_DEBUG(pbr
, PBR
))
456 zlog_debug("BGP: pbr entry undefined. cancel.");
459 /* because bgp pbr entry may contain unsupported
460 * combinations, a message will be displayed here if
462 * for now, only match/set supported is
463 * - combination src/dst => redirect nexthop [ + rate]
464 * - combination src/dst => redirect VRF [ + rate]
465 * - combination src/dst => drop
466 * - combination srcport + @IP
468 if (api
->match_protocol_num
> 1) {
469 if (BGP_DEBUG(pbr
, PBR
))
470 zlog_debug("BGP: match protocol operations:"
471 "multiple protocols ( %d). ignoring.",
472 api
->match_protocol_num
);
475 if (api
->match_protocol_num
== 1 &&
476 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
477 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
478 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
479 if (BGP_DEBUG(pbr
, PBR
))
480 zlog_debug("BGP: match protocol operations:"
481 "protocol (%d) not supported. ignoring",
482 api
->match_protocol_num
);
485 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
486 if (BGP_DEBUG(pbr
, PBR
))
487 zlog_debug("BGP: match src port operations:"
488 "too complex. ignoring.");
491 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
492 if (BGP_DEBUG(pbr
, PBR
))
493 zlog_debug("BGP: match dst port operations:"
494 "too complex. ignoring.");
497 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
498 api
->match_tcpflags_num
,
500 OPERATOR_UNARY_OR
, NULL
,
501 FLOWSPEC_TCP_FLAGS
)) {
502 if (BGP_DEBUG(pbr
, PBR
))
503 zlog_debug("BGP: match tcp flags:"
504 "too complex. ignoring.");
507 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
508 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
509 api
->match_icmp_type_num
,
510 OPERATOR_UNARY_OR
, NULL
,
511 FLOWSPEC_ICMP_TYPE
)) {
512 if (BGP_DEBUG(pbr
, PBR
))
513 zlog_debug("BGP: match icmp type operations:"
514 "too complex. ignoring.");
517 enumerate_icmp
= true;
519 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
520 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
521 api
->match_icmp_code_num
,
522 OPERATOR_UNARY_OR
, NULL
,
523 FLOWSPEC_ICMP_CODE
)) {
524 if (BGP_DEBUG(pbr
, PBR
))
525 zlog_debug("BGP: match icmp code operations:"
526 "too complex. ignoring.");
528 } else if (api
->match_icmp_type_num
> 1 &&
529 enumerate_icmp
== false) {
530 if (BGP_DEBUG(pbr
, PBR
))
531 zlog_debug("BGP: match icmp code is enumerate"
532 ", and icmp type is not."
533 " too complex. ignoring.");
537 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
538 if (BGP_DEBUG(pbr
, PBR
))
539 zlog_debug("BGP: match port operations:"
540 "too complex. ignoring.");
543 if (api
->match_packet_length_num
) {
546 ret
= bgp_pbr_extract(api
->packet_length
,
547 api
->match_packet_length_num
, NULL
);
549 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
550 api
->match_packet_length_num
,
552 | OPERATOR_UNARY_AND
,
553 NULL
, FLOWSPEC_PKT_LEN
);
555 if (BGP_DEBUG(pbr
, PBR
))
556 zlog_debug("BGP: match packet length operations:"
557 "too complex. ignoring.");
561 if (api
->match_dscp_num
) {
562 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
563 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
564 NULL
, FLOWSPEC_DSCP
)) {
565 if (BGP_DEBUG(pbr
, PBR
))
566 zlog_debug("BGP: match DSCP operations:"
567 "too complex. ignoring.");
571 if (api
->match_fragment_num
) {
575 success
= bgp_pbr_extract_enumerate(api
->fragment
,
576 api
->match_fragment_num
,
578 | OPERATOR_UNARY_AND
,
579 NULL
, FLOWSPEC_FRAGMENT
);
583 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
584 if (api
->fragment
[i
].value
!= 1 &&
585 api
->fragment
[i
].value
!= 2 &&
586 api
->fragment
[i
].value
!= 4 &&
587 api
->fragment
[i
].value
!= 8) {
590 "Value not valid (%d) for this implementation",
591 api
->fragment
[i
].value
);
595 sprintf(fail_str
, "too complex. ignoring");
597 if (BGP_DEBUG(pbr
, PBR
))
598 zlog_debug("BGP: match fragment operation (%d) %s",
599 api
->match_fragment_num
,
605 /* no combinations with both src_port and dst_port
606 * or port with src_port and dst_port
608 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
609 api
->match_port_num
> 3) {
610 if (BGP_DEBUG(pbr
, PBR
))
611 zlog_debug("BGP: match multiple port operations:"
612 " too complex. ignoring.");
615 if ((api
->match_src_port_num
|| api
->match_dst_port_num
616 || api
->match_port_num
) && (api
->match_icmp_type_num
617 || api
->match_icmp_code_num
)) {
618 if (BGP_DEBUG(pbr
, PBR
))
619 zlog_debug("BGP: match multiple port/imcp operations:"
620 " too complex. ignoring.");
623 /* iprule only supports redirect IP */
624 if (api
->type
== BGP_PBR_IPRULE
) {
627 for (i
= 0; i
< api
->action_num
; i
++) {
628 if (api
->actions
[i
].action
== ACTION_TRAFFICRATE
&&
629 api
->actions
[i
].u
.r
.rate
== 0) {
630 if (BGP_DEBUG(pbr
, PBR
)) {
631 bgp_pbr_print_policy_route(api
);
632 zlog_debug("BGP: iprule match actions"
633 " drop not supported");
637 if (api
->actions
[i
].action
== ACTION_MARKING
) {
638 if (BGP_DEBUG(pbr
, PBR
)) {
639 bgp_pbr_print_policy_route(api
);
640 zlog_warn("PBR: iprule set DSCP %u"
642 api
->actions
[i
].u
.marking_dscp
);
645 if (api
->actions
[i
].action
== ACTION_REDIRECT
) {
646 if (BGP_DEBUG(pbr
, PBR
)) {
647 bgp_pbr_print_policy_route(api
);
648 zlog_warn("PBR: iprule redirect VRF %u"
650 api
->actions
[i
].u
.redirect_vrf
);
655 } else if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
656 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
657 if (BGP_DEBUG(pbr
, PBR
)) {
658 bgp_pbr_print_policy_route(api
);
659 zlog_debug("BGP: match actions without src"
660 " or dst address can not operate."
668 /* return -1 if build or validation failed */
669 int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
670 struct bgp_path_info
*path
,
671 struct bgp_pbr_entry_main
*api
)
674 int i
, action_count
= 0;
675 struct ecommunity
*ecom
;
676 struct ecommunity_val
*ecom_eval
;
677 struct bgp_pbr_entry_action
*api_action
;
678 struct prefix
*src
= NULL
, *dst
= NULL
;
679 int valid_prefix
= 0;
681 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
683 /* extract match from flowspec entries */
684 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
685 p
->u
.prefix_flowspec
.prefixlen
, api
);
688 /* extract actiosn from flowspec ecom list */
689 if (path
&& path
->attr
&& path
->attr
->ecommunity
) {
690 ecom
= path
->attr
->ecommunity
;
691 for (i
= 0; i
< ecom
->size
; i
++) {
692 ecom_eval
= (struct ecommunity_val
*)
693 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
695 if (action_count
> ACTIONS_MAX_NUM
) {
696 if (BGP_DEBUG(pbr
, PBR_ERROR
))
698 EC_BGP_FLOWSPEC_PACKET
,
699 "%s: flowspec actions exceeds limit (max %u)",
700 __func__
, action_count
);
703 api_action
= &api
->actions
[action_count
- 1];
705 if ((ecom_eval
->val
[1] ==
706 (char)ECOMMUNITY_REDIRECT_VRF
) &&
707 (ecom_eval
->val
[0] ==
708 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
710 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
712 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
713 struct ecommunity
*eckey
= ecommunity_new();
714 struct ecommunity_val ecom_copy
;
716 memcpy(&ecom_copy
, ecom_eval
,
717 sizeof(struct ecommunity_val
));
719 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
720 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
721 ecommunity_add_val(eckey
, &ecom_copy
);
723 api_action
->action
= ACTION_REDIRECT
;
724 api_action
->u
.redirect_vrf
=
725 get_first_vrf_for_redirect_with_rt(
727 ecommunity_free(&eckey
);
728 } else if ((ecom_eval
->val
[0] ==
729 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
730 (ecom_eval
->val
[1] ==
731 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
732 /* in case the 2 ecom present,
734 * draft-ietf-idr-flowspec-redirect
736 if (api_action_redirect_ip
) {
737 if (api_action_redirect_ip
->u
738 .zr
.redirect_ip_v4
.s_addr
)
740 if (!path
->attr
->nexthop
.s_addr
)
742 api_action_redirect_ip
->u
743 .zr
.redirect_ip_v4
.s_addr
=
744 path
->attr
->nexthop
.s_addr
;
745 api_action_redirect_ip
->u
.zr
.duplicate
749 api_action
->action
= ACTION_REDIRECT_IP
;
750 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
751 path
->attr
->nexthop
.s_addr
;
752 api_action
->u
.zr
.duplicate
=
754 api_action_redirect_ip
= api_action
;
756 } else if ((ecom_eval
->val
[0] ==
757 (char)ECOMMUNITY_ENCODE_IP
) &&
758 (ecom_eval
->val
[1] ==
759 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
760 /* in case the 2 ecom present,
761 * overwrite simpson draft
762 * update redirect ip fields
764 if (api_action_redirect_ip
) {
765 memcpy(&(api_action_redirect_ip
->u
766 .zr
.redirect_ip_v4
.s_addr
),
767 (ecom_eval
->val
+2), 4);
768 api_action_redirect_ip
->u
773 api_action
->action
= ACTION_REDIRECT_IP
;
774 memcpy(&(api_action
->u
775 .zr
.redirect_ip_v4
.s_addr
),
776 (ecom_eval
->val
+2), 4);
777 api_action
->u
.zr
.duplicate
=
779 api_action_redirect_ip
= api_action
;
782 if (ecom_eval
->val
[0] !=
783 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
785 ret
= ecommunity_fill_pbr_action(ecom_eval
,
794 /* validate if incoming matc/action is compatible
795 * with our policy routing engine
797 if (!bgp_pbr_validate_policy_route(api
))
800 /* check inconsistency in the match rule */
801 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
802 src
= &api
->src_prefix
;
803 afi
= family2afi(src
->family
);
806 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
807 dst
= &api
->dst_prefix
;
808 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
809 if (BGP_DEBUG(pbr
, PBR
)) {
810 bgp_pbr_print_policy_route(api
);
811 zlog_debug("%s: inconsistency:"
812 " no match for afi src and dst (%u/%u)",
813 __func__
, afi
, family2afi(dst
->family
));
821 static void bgp_pbr_match_entry_free(void *arg
)
823 struct bgp_pbr_match_entry
*bpme
;
825 bpme
= (struct bgp_pbr_match_entry
*)arg
;
827 if (bpme
->installed
) {
828 bgp_send_pbr_ipset_entry_match(bpme
, false);
829 bpme
->installed
= false;
830 bpme
->backpointer
= NULL
;
832 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
835 static void bgp_pbr_match_free(void *arg
)
837 struct bgp_pbr_match
*bpm
;
839 bpm
= (struct bgp_pbr_match
*)arg
;
841 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
843 if (hashcount(bpm
->entry_hash
) == 0) {
844 /* delete iptable entry first */
845 /* then delete ipset match */
846 if (bpm
->installed
) {
847 if (bpm
->installed_in_iptable
) {
848 bgp_send_pbr_iptable(bpm
->action
,
850 bpm
->installed_in_iptable
= false;
851 bpm
->action
->refcnt
--;
853 bgp_send_pbr_ipset_match(bpm
, false);
854 bpm
->installed
= false;
858 hash_free(bpm
->entry_hash
);
860 XFREE(MTYPE_PBR_MATCH
, bpm
);
863 static void *bgp_pbr_match_alloc_intern(void *arg
)
865 struct bgp_pbr_match
*bpm
, *new;
867 bpm
= (struct bgp_pbr_match
*)arg
;
869 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
870 memcpy(new, bpm
, sizeof(*bpm
));
875 static void bgp_pbr_rule_free(void *arg
)
877 struct bgp_pbr_rule
*bpr
;
879 bpr
= (struct bgp_pbr_rule
*)arg
;
882 if (bpr
->installed
) {
883 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
884 bpr
->installed
= false;
885 bpr
->action
->refcnt
--;
888 XFREE(MTYPE_PBR_RULE
, bpr
);
891 static void *bgp_pbr_rule_alloc_intern(void *arg
)
893 struct bgp_pbr_rule
*bpr
, *new;
895 bpr
= (struct bgp_pbr_rule
*)arg
;
897 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
898 memcpy(new, bpr
, sizeof(*bpr
));
903 static void bgp_pbr_action_free(void *arg
)
905 struct bgp_pbr_action
*bpa
;
907 bpa
= (struct bgp_pbr_action
*)arg
;
909 if (bpa
->refcnt
== 0) {
910 if (bpa
->installed
&& bpa
->table_id
!= 0) {
911 bgp_send_pbr_rule_action(bpa
, NULL
, false);
912 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
916 bpa
->installed
= false;
919 XFREE(MTYPE_PBR_ACTION
, bpa
);
922 static void *bgp_pbr_action_alloc_intern(void *arg
)
924 struct bgp_pbr_action
*bpa
, *new;
926 bpa
= (struct bgp_pbr_action
*)arg
;
928 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
930 memcpy(new, bpa
, sizeof(*bpa
));
935 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
937 struct bgp_pbr_match_entry
*bpme
, *new;
939 bpme
= (struct bgp_pbr_match_entry
*)arg
;
941 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
943 memcpy(new, bpme
, sizeof(*bpme
));
948 uint32_t bgp_pbr_match_hash_key(void *arg
)
950 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
953 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
954 key
= jhash_1word(pbm
->flags
, key
);
955 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
956 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
957 key
= jhash(&pbm
->tcp_flags
, 2, key
);
958 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
959 key
= jhash(&pbm
->dscp_value
, 1, key
);
960 key
= jhash(&pbm
->fragment
, 1, key
);
961 return jhash_1word(pbm
->type
, key
);
964 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
966 const struct bgp_pbr_match
*r1
, *r2
;
968 r1
= (const struct bgp_pbr_match
*)arg1
;
969 r2
= (const struct bgp_pbr_match
*)arg2
;
971 if (r1
->vrf_id
!= r2
->vrf_id
)
974 if (r1
->type
!= r2
->type
)
977 if (r1
->flags
!= r2
->flags
)
980 if (r1
->action
!= r2
->action
)
983 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
986 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
989 if (r1
->tcp_flags
!= r2
->tcp_flags
)
992 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
995 if (r1
->dscp_value
!= r2
->dscp_value
)
998 if (r1
->fragment
!= r2
->fragment
)
1003 uint32_t bgp_pbr_rule_hash_key(void *arg
)
1005 struct bgp_pbr_rule
*pbr
= (struct bgp_pbr_rule
*)arg
;
1008 key
= prefix_hash_key(&pbr
->src
);
1009 key
= jhash_1word(pbr
->vrf_id
, key
);
1010 key
= jhash_1word(pbr
->flags
, key
);
1011 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1014 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1016 const struct bgp_pbr_rule
*r1
, *r2
;
1018 r1
= (const struct bgp_pbr_rule
*)arg1
;
1019 r2
= (const struct bgp_pbr_rule
*)arg2
;
1021 if (r1
->vrf_id
!= r2
->vrf_id
)
1024 if (r1
->flags
!= r2
->flags
)
1027 if (r1
->action
!= r2
->action
)
1030 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1031 !prefix_same(&r1
->src
, &r2
->src
))
1034 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1035 !prefix_same(&r1
->dst
, &r2
->dst
))
1041 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
1043 struct bgp_pbr_match_entry
*pbme
;
1046 pbme
= (struct bgp_pbr_match_entry
*)arg
;
1047 key
= prefix_hash_key(&pbme
->src
);
1048 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1049 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1050 key
= jhash(&pbme
->src_port_min
, 2, key
);
1051 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1052 key
= jhash(&pbme
->src_port_max
, 2, key
);
1053 key
= jhash(&pbme
->proto
, 1, key
);
1058 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1060 const struct bgp_pbr_match_entry
*r1
, *r2
;
1062 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1063 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1066 * on updates, comparing backpointer is not necessary
1067 * unique value is self calculated
1068 * rate is ignored for now
1071 if (!prefix_same(&r1
->src
, &r2
->src
))
1074 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1077 if (r1
->src_port_min
!= r2
->src_port_min
)
1080 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1083 if (r1
->src_port_max
!= r2
->src_port_max
)
1086 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1089 if (r1
->proto
!= r2
->proto
)
1095 uint32_t bgp_pbr_action_hash_key(void *arg
)
1097 struct bgp_pbr_action
*pbra
;
1100 pbra
= (struct bgp_pbr_action
*)arg
;
1101 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1102 key
= jhash_1word(pbra
->fwmark
, key
);
1106 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1108 const struct bgp_pbr_action
*r1
, *r2
;
1110 r1
= (const struct bgp_pbr_action
*)arg1
;
1111 r2
= (const struct bgp_pbr_action
*)arg2
;
1113 /* unique value is self calculated
1114 * table and fwmark is self calculated
1117 if (r1
->vrf_id
!= r2
->vrf_id
)
1120 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1126 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1129 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1130 struct bgp_pbr_action_unique bpau
;
1132 if (!bgp
|| unique
== 0)
1134 bpau
.unique
= unique
;
1135 bpau
.bpa_found
= NULL
;
1136 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1137 return bpau
.bpa_found
;
1140 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1143 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1144 struct bgp_pbr_match_unique bpmu
;
1146 if (!bgp
|| unique
== 0)
1148 bpmu
.unique
= unique
;
1149 bpmu
.bpm_found
= NULL
;
1150 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1151 return bpmu
.bpm_found
;
1154 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1158 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1159 struct bgp_pbr_match_entry_unique bpmeu
;
1160 struct bgp_pbr_match_ipsetname bpmi
;
1162 if (!bgp
|| unique
== 0)
1164 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1165 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1166 bpmi
.bpm_found
= NULL
;
1167 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1168 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1169 if (!bpmi
.bpm_found
)
1171 bpmeu
.bpme_found
= NULL
;
1172 bpmeu
.unique
= unique
;
1173 hash_walk(bpmi
.bpm_found
->entry_hash
,
1174 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1175 return bpmeu
.bpme_found
;
1178 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1181 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1182 struct bgp_pbr_match_iptable_unique bpmiu
;
1184 if (!bgp
|| unique
== 0)
1186 bpmiu
.unique
= unique
;
1187 bpmiu
.bpm_found
= NULL
;
1188 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1189 return bpmiu
.bpm_found
;
1192 void bgp_pbr_cleanup(struct bgp
*bgp
)
1194 if (bgp
->pbr_match_hash
) {
1195 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1196 hash_free(bgp
->pbr_match_hash
);
1197 bgp
->pbr_match_hash
= NULL
;
1199 if (bgp
->pbr_rule_hash
) {
1200 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1201 hash_free(bgp
->pbr_rule_hash
);
1202 bgp
->pbr_rule_hash
= NULL
;
1204 if (bgp
->pbr_action_hash
) {
1205 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1206 hash_free(bgp
->pbr_action_hash
);
1207 bgp
->pbr_action_hash
= NULL
;
1209 if (bgp
->bgp_pbr_cfg
== NULL
)
1211 bgp_pbr_reset(bgp
, AFI_IP
);
1212 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1213 bgp
->bgp_pbr_cfg
= NULL
;
1216 void bgp_pbr_init(struct bgp
*bgp
)
1218 bgp
->pbr_match_hash
=
1219 hash_create_size(8, bgp_pbr_match_hash_key
,
1220 bgp_pbr_match_hash_equal
,
1222 bgp
->pbr_action_hash
=
1223 hash_create_size(8, bgp_pbr_action_hash_key
,
1224 bgp_pbr_action_hash_equal
,
1225 "Match Hash Entry");
1227 bgp
->pbr_rule_hash
=
1228 hash_create_size(8, bgp_pbr_rule_hash_key
,
1229 bgp_pbr_rule_hash_equal
,
1232 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1233 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1236 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1239 char return_string
[512];
1240 char *ptr
= return_string
;
1244 ptr
+= sprintf(ptr
, "MATCH : ");
1245 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1246 struct prefix
*p
= &(api
->src_prefix
);
1248 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1249 INCREMENT_DISPLAY(ptr
, nb_items
);
1251 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1252 struct prefix
*p
= &(api
->dst_prefix
);
1254 INCREMENT_DISPLAY(ptr
, nb_items
);
1255 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1258 if (api
->match_protocol_num
)
1259 INCREMENT_DISPLAY(ptr
, nb_items
);
1260 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1261 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1262 i
> 0 ? NULL
: "@proto ");
1264 if (api
->match_src_port_num
)
1265 INCREMENT_DISPLAY(ptr
, nb_items
);
1266 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1267 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1268 i
> 0 ? NULL
: "@srcport ");
1270 if (api
->match_dst_port_num
)
1271 INCREMENT_DISPLAY(ptr
, nb_items
);
1272 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1273 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1274 i
> 0 ? NULL
: "@dstport ");
1276 if (api
->match_port_num
)
1277 INCREMENT_DISPLAY(ptr
, nb_items
);
1278 for (i
= 0; i
< api
->match_port_num
; i
++)
1279 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1280 i
> 0 ? NULL
: "@port ");
1282 if (api
->match_icmp_type_num
)
1283 INCREMENT_DISPLAY(ptr
, nb_items
);
1284 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1285 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1286 i
> 0 ? NULL
: "@icmptype ");
1288 if (api
->match_icmp_code_num
)
1289 INCREMENT_DISPLAY(ptr
, nb_items
);
1290 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1291 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1292 i
> 0 ? NULL
: "@icmpcode ");
1294 if (api
->match_packet_length_num
)
1295 INCREMENT_DISPLAY(ptr
, nb_items
);
1296 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1297 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1298 i
> 0 ? NULL
: "@plen ");
1300 if (api
->match_dscp_num
)
1301 INCREMENT_DISPLAY(ptr
, nb_items
);
1302 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1303 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1304 i
> 0 ? NULL
: "@dscp ");
1306 if (api
->match_tcpflags_num
)
1307 INCREMENT_DISPLAY(ptr
, nb_items
);
1308 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1309 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1310 i
> 0 ? NULL
: "@tcpflags ");
1312 if (api
->match_fragment_num
)
1313 INCREMENT_DISPLAY(ptr
, nb_items
);
1314 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1315 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1316 i
> 0 ? NULL
: "@fragment ");
1318 ptr
= return_string
;
1320 ptr
+= sprintf(ptr
, "; ");
1321 if (api
->action_num
)
1322 ptr
+= sprintf(ptr
, "SET : ");
1324 for (i
= 0; i
< api
->action_num
; i
++) {
1325 switch (api
->actions
[i
].action
) {
1326 case ACTION_TRAFFICRATE
:
1327 INCREMENT_DISPLAY(ptr
, nb_items
);
1328 ptr
+= sprintf(ptr
, "@set rate %f",
1329 api
->actions
[i
].u
.r
.rate
);
1331 case ACTION_TRAFFIC_ACTION
:
1332 INCREMENT_DISPLAY(ptr
, nb_items
);
1333 ptr
+= sprintf(ptr
, "@action ");
1334 if (api
->actions
[i
].u
.za
.filter
1335 & TRAFFIC_ACTION_TERMINATE
)
1337 " terminate (apply filter(s))");
1338 if (api
->actions
[i
].u
.za
.filter
1339 & TRAFFIC_ACTION_DISTRIBUTE
)
1340 ptr
+= sprintf(ptr
, " distribute");
1341 if (api
->actions
[i
].u
.za
.filter
1342 & TRAFFIC_ACTION_SAMPLE
)
1343 ptr
+= sprintf(ptr
, " sample");
1345 case ACTION_REDIRECT_IP
:
1346 INCREMENT_DISPLAY(ptr
, nb_items
);
1347 char local_buff
[INET_ADDRSTRLEN
];
1349 if (inet_ntop(AF_INET
,
1350 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1351 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1353 "@redirect ip nh %s", local_buff
);
1355 case ACTION_REDIRECT
:
1356 INCREMENT_DISPLAY(ptr
, nb_items
);
1357 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1358 api
->actions
[i
].u
.redirect_vrf
);
1360 case ACTION_MARKING
:
1361 INCREMENT_DISPLAY(ptr
, nb_items
);
1362 ptr
+= sprintf(ptr
, "@set dscp %u",
1363 api
->actions
[i
].u
.marking_dscp
);
1369 zlog_info("%s", return_string
);
1372 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1373 struct bgp_pbr_rule
*bpr
)
1375 /* if bpr is null, do nothing
1379 if (bpr
->installed
) {
1380 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1381 bpr
->installed
= false;
1382 bpr
->action
->refcnt
--;
1385 hash_release(bgp
->pbr_rule_hash
, bpr
);
1386 if (bpa
->refcnt
== 0) {
1387 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1388 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1389 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1393 bpa
->installed
= false;
1398 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1399 struct bgp_pbr_match
*bpm
,
1400 struct bgp_pbr_match_entry
*bpme
)
1402 /* if bpme is null, bpm is also null
1406 /* ipset del entry */
1407 if (bpme
->installed
) {
1408 bgp_send_pbr_ipset_entry_match(bpme
, false);
1409 bpme
->installed
= false;
1410 bpme
->backpointer
= NULL
;
1412 struct bgp_path_info
*path
;
1413 struct bgp_path_info_extra
*extra
;
1415 /* unlink bgp_path_info to bpme */
1416 path
= (struct bgp_path_info
*)bpme
->path
;
1417 extra
= bgp_path_info_extra_get(path
);
1418 if (extra
->bgp_fs_pbr
)
1419 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1423 hash_release(bpm
->entry_hash
, bpme
);
1424 if (hashcount(bpm
->entry_hash
) == 0) {
1425 /* delete iptable entry first */
1426 /* then delete ipset match */
1427 if (bpm
->installed
) {
1428 if (bpm
->installed_in_iptable
) {
1429 bgp_send_pbr_iptable(bpm
->action
,
1431 bpm
->installed_in_iptable
= false;
1432 bpm
->action
->refcnt
--;
1434 bgp_send_pbr_ipset_match(bpm
, false);
1435 bpm
->installed
= false;
1438 hash_release(bgp
->pbr_match_hash
, bpm
);
1439 /* XXX release pbr_match_action if not used
1440 * note that drop does not need to call send_pbr_action
1443 if (bpa
->refcnt
== 0) {
1444 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1445 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1446 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1450 bpa
->installed
= false;
1455 struct bgp_pbr_match_entry_remain
{
1456 struct bgp_pbr_match_entry
*bpme_to_match
;
1457 struct bgp_pbr_match_entry
*bpme_found
;
1460 struct bgp_pbr_rule_remain
{
1461 struct bgp_pbr_rule
*bpr_to_match
;
1462 struct bgp_pbr_rule
*bpr_found
;
1465 static int bgp_pbr_get_same_rule(struct hash_backet
*backet
, void *arg
)
1467 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)backet
->data
;
1468 struct bgp_pbr_rule_remain
*ctxt
=
1469 (struct bgp_pbr_rule_remain
*)arg
;
1470 struct bgp_pbr_rule
*r2
;
1472 r2
= ctxt
->bpr_to_match
;
1474 if (r1
->vrf_id
!= r2
->vrf_id
)
1475 return HASHWALK_CONTINUE
;
1477 if (r1
->flags
!= r2
->flags
)
1478 return HASHWALK_CONTINUE
;
1480 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1481 !prefix_same(&r1
->src
, &r2
->src
))
1482 return HASHWALK_CONTINUE
;
1484 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1485 !prefix_same(&r1
->dst
, &r2
->dst
))
1486 return HASHWALK_CONTINUE
;
1488 /* this function is used for two cases:
1489 * - remove an entry upon withdraw request
1490 * (case r2->action is null)
1491 * - replace an old iprule with different action
1492 * (case r2->action is != null)
1493 * the old one is removed after the new one
1494 * this is to avoid disruption in traffic
1496 if (r2
->action
== NULL
||
1497 r1
->action
!= r2
->action
) {
1498 ctxt
->bpr_found
= r1
;
1499 return HASHWALK_ABORT
;
1501 return HASHWALK_CONTINUE
;
1504 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1506 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1507 struct bgp_pbr_match_entry_remain
*bpmer
=
1508 (struct bgp_pbr_match_entry_remain
*)arg
;
1509 struct bgp_pbr_match
*bpm_temp
;
1510 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1512 if (!bpme
->backpointer
||
1513 bpm
== bpme
->backpointer
||
1514 bpme
->backpointer
->action
== bpm
->action
)
1515 return HASHWALK_CONTINUE
;
1516 /* ensure bpm other characteristics are equal */
1517 bpm_temp
= bpme
->backpointer
;
1518 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1519 bpm_temp
->type
!= bpm
->type
||
1520 bpm_temp
->flags
!= bpm
->flags
||
1521 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1522 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1523 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1524 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1525 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1526 bpm_temp
->fragment
!= bpm
->fragment
)
1527 return HASHWALK_CONTINUE
;
1529 /* look for remaining bpme */
1530 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1531 if (!bpmer
->bpme_found
)
1532 return HASHWALK_CONTINUE
;
1533 return HASHWALK_ABORT
;
1536 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1537 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1539 struct bgp_pbr_match temp
;
1540 struct bgp_pbr_match_entry temp2
;
1541 struct bgp_pbr_rule pbr_rule
;
1542 struct bgp_pbr_rule
*bpr
;
1543 struct bgp_pbr_match
*bpm
;
1544 struct bgp_pbr_match_entry
*bpme
;
1545 struct bgp_pbr_match_entry_remain bpmer
;
1546 struct bgp_pbr_range_port
*src_port
;
1547 struct bgp_pbr_range_port
*dst_port
;
1548 struct bgp_pbr_range_port
*pkt_len
;
1549 struct bgp_pbr_rule_remain bprr
;
1553 src_port
= bpf
->src_port
;
1554 dst_port
= bpf
->dst_port
;
1555 pkt_len
= bpf
->pkt_len
;
1557 if (BGP_DEBUG(zebra
, ZEBRA
))
1558 bgp_pbr_dump_entry(bpf
, false);
1560 /* as we don't know information from EC
1561 * look for bpm that have the bpm
1562 * with vrf_id characteristics
1564 memset(&temp2
, 0, sizeof(temp2
));
1565 memset(&temp
, 0, sizeof(temp
));
1567 if (bpf
->type
== BGP_PBR_IPRULE
) {
1568 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1569 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1571 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1572 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1575 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1576 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1579 /* A previous entry may already exist
1580 * flush previous entry if necessary
1582 bprr
.bpr_to_match
= bpr
;
1583 bprr
.bpr_found
= NULL
;
1584 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1585 if (bprr
.bpr_found
) {
1586 static struct bgp_pbr_rule
*local_bpr
;
1587 static struct bgp_pbr_action
*local_bpa
;
1589 local_bpr
= bprr
.bpr_found
;
1590 local_bpa
= local_bpr
->action
;
1591 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1598 temp
.flags
|= MATCH_IP_SRC_SET
;
1599 prefix_copy(&temp2
.src
, bpf
->src
);
1601 temp2
.src
.family
= AF_INET
;
1603 temp
.flags
|= MATCH_IP_DST_SET
;
1604 prefix_copy(&temp2
.dst
, bpf
->dst
);
1606 temp2
.dst
.family
= AF_INET
;
1607 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1608 if (bpf
->protocol
== IPPROTO_ICMP
)
1609 temp
.flags
|= MATCH_ICMP_SET
;
1610 temp
.flags
|= MATCH_PORT_SRC_SET
;
1611 temp2
.src_port_min
= src_port
->min_port
;
1612 if (src_port
->max_port
) {
1613 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1614 temp2
.src_port_max
= src_port
->max_port
;
1617 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1618 if (bpf
->protocol
== IPPROTO_ICMP
)
1619 temp
.flags
|= MATCH_ICMP_SET
;
1620 temp
.flags
|= MATCH_PORT_DST_SET
;
1621 temp2
.dst_port_min
= dst_port
->min_port
;
1622 if (dst_port
->max_port
) {
1623 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1624 temp2
.dst_port_max
= dst_port
->max_port
;
1627 temp2
.proto
= bpf
->protocol
;
1630 temp
.pkt_len_min
= pkt_len
->min_port
;
1631 if (pkt_len
->max_port
)
1632 temp
.pkt_len_max
= pkt_len
->max_port
;
1633 } else if (bpf
->pkt_len_val
) {
1634 if (bpf
->pkt_len_val
->mask
)
1635 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1636 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1638 if (bpf
->tcp_flags
) {
1639 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1640 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1643 if (bpf
->dscp
->mask
)
1644 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1646 temp
.flags
|= MATCH_DSCP_SET
;
1647 temp
.dscp_value
= bpf
->dscp
->val
;
1649 if (bpf
->fragment
) {
1650 if (bpf
->fragment
->mask
)
1651 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1652 temp
.fragment
= bpf
->fragment
->val
;
1655 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1656 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1657 temp
.type
= IPSET_NET_PORT
;
1659 temp
.type
= IPSET_NET
;
1661 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1662 temp
.type
= IPSET_NET_PORT_NET
;
1664 temp
.type
= IPSET_NET_NET
;
1666 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1669 temp
.vrf_id
= bpf
->vrf_id
;
1672 bpme
->backpointer
= bpm
;
1673 /* right now, a previous entry may already exist
1674 * flush previous entry if necessary
1676 bpmer
.bpme_to_match
= bpme
;
1677 bpmer
.bpme_found
= NULL
;
1678 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1679 if (bpmer
.bpme_found
) {
1680 static struct bgp_pbr_match
*local_bpm
;
1681 static struct bgp_pbr_action
*local_bpa
;
1683 local_bpm
= bpmer
.bpme_found
->backpointer
;
1684 local_bpa
= local_bpm
->action
;
1685 bgp_pbr_flush_entry(bgp
, local_bpa
,
1686 local_bpm
, bpmer
.bpme_found
);
1690 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1692 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1693 return FLOWSPEC_DSCP
;
1694 if (type_entry
== FLOWSPEC_DSCP
)
1695 return FLOWSPEC_PKT_LEN
;
1696 if (type_entry
== FLOWSPEC_PKT_LEN
)
1697 return FLOWSPEC_FRAGMENT
;
1698 if (type_entry
== FLOWSPEC_FRAGMENT
)
1699 return FLOWSPEC_ICMP_TYPE
;
1703 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1704 struct bgp_pbr_filter
*bpf
,
1705 struct bgp_pbr_or_filter
*bpof
, bool add
,
1706 struct nexthop
*nh
, float *rate
)
1708 struct bgp_pbr_range_port srcp
, dstp
;
1709 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1710 struct listnode
*tnode
, *cnode
;
1714 if (bpf
->protocol
!= IPPROTO_ICMP
)
1716 bpf
->src_port
= &srcp
;
1717 bpf
->dst_port
= &dstp
;
1718 /* parse icmp type and lookup appropriate icmp code
1719 * if no icmp code found, create as many entryes as
1720 * there are listed icmp codes for that icmp type
1722 if (!bpof
->icmp_type
) {
1724 srcp
.max_port
= 255;
1725 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1726 dstp
.min_port
= icmp_code
->val
;
1728 bgp_pbr_policyroute_add_to_zebra_unit(
1729 bgp
, path
, bpf
, nh
, rate
);
1731 bgp_pbr_policyroute_remove_from_zebra_unit(
1736 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1737 srcp
.min_port
= icmp_type
->val
;
1740 /* only icmp type. create an entry only with icmp type */
1741 if (!bpof
->icmp_code
) {
1742 /* icmp type is not one of the above
1743 * forge an entry only based on the icmp type
1746 dstp
.max_port
= 255;
1748 bgp_pbr_policyroute_add_to_zebra_unit(
1749 bgp
, path
, bpf
, nh
, rate
);
1751 bgp_pbr_policyroute_remove_from_zebra_unit(
1755 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1756 dstp
.min_port
= icmp_code
->val
;
1758 bgp_pbr_policyroute_add_to_zebra_unit(
1759 bgp
, path
, bpf
, nh
, rate
);
1761 bgp_pbr_policyroute_remove_from_zebra_unit(
1767 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1768 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1769 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1771 struct listnode
*node
, *nnode
;
1772 struct bgp_pbr_val_mask
*valmask
;
1773 uint8_t next_type_entry
;
1774 struct list
*orig_list
;
1775 struct bgp_pbr_val_mask
**target_val
;
1777 if (type_entry
== 0) {
1778 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1781 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1782 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1783 orig_list
= bpof
->tcpflags
;
1784 target_val
= &bpf
->tcp_flags
;
1785 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1786 orig_list
= bpof
->dscp
;
1787 target_val
= &bpf
->dscp
;
1788 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1789 orig_list
= bpof
->pkt_len
;
1790 target_val
= &bpf
->pkt_len_val
;
1791 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1792 orig_list
= bpof
->fragment
;
1793 target_val
= &bpf
->fragment
;
1794 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1795 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1796 /* enumerate list for icmp - must be last one */
1797 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1800 bgp_pbr_policyroute_remove_from_zebra_recursive(
1801 bgp
, path
, bpf
, bpof
, next_type_entry
);
1804 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1805 *target_val
= valmask
;
1806 bgp_pbr_policyroute_remove_from_zebra_recursive(
1807 bgp
, path
, bpf
, bpof
, next_type_entry
);
1811 static void bgp_pbr_policyroute_remove_from_zebra(
1812 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1813 struct bgp_pbr_or_filter
*bpof
)
1816 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1820 bgp_pbr_policyroute_remove_from_zebra_recursive(
1821 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1822 else if (bpof
->dscp
)
1823 bgp_pbr_policyroute_remove_from_zebra_recursive(
1824 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1825 else if (bpof
->pkt_len
)
1826 bgp_pbr_policyroute_remove_from_zebra_recursive(
1827 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1828 else if (bpof
->fragment
)
1829 bgp_pbr_policyroute_remove_from_zebra_recursive(
1830 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1831 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1832 bgp_pbr_policyroute_remove_from_zebra_recursive(
1833 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1835 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1838 list_delete_all_node(bpof
->tcpflags
);
1840 list_delete_all_node(bpof
->dscp
);
1842 list_delete_all_node(bpof
->pkt_len
);
1844 list_delete_all_node(bpof
->fragment
);
1847 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1849 struct bgp_pbr_range_port
*src_port
;
1850 struct bgp_pbr_range_port
*dst_port
;
1851 struct bgp_pbr_range_port
*pkt_len
;
1852 char bufsrc
[64], bufdst
[64];
1854 int remaining_len
= 0;
1855 char protocol_str
[16];
1859 src_port
= bpf
->src_port
;
1860 dst_port
= bpf
->dst_port
;
1861 pkt_len
= bpf
->pkt_len
;
1863 protocol_str
[0] = '\0';
1864 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1865 bpf
->protocol
= IPPROTO_TCP
;
1867 snprintf(protocol_str
, sizeof(protocol_str
),
1868 "proto %d", bpf
->protocol
);
1870 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1871 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1874 dst_port
->min_port
);
1875 else if (bpf
->protocol
== IPPROTO_UDP
||
1876 bpf
->protocol
== IPPROTO_TCP
) {
1878 if (src_port
&& src_port
->min_port
)
1879 remaining_len
+= snprintf(buffer
,
1883 src_port
->max_port
?
1884 src_port
->max_port
:
1885 src_port
->min_port
);
1886 if (dst_port
&& dst_port
->min_port
)
1887 remaining_len
+= snprintf(buffer
+
1893 dst_port
->max_port
?
1894 dst_port
->max_port
:
1895 dst_port
->min_port
);
1897 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1898 remaining_len
+= snprintf(buffer
+ remaining_len
,
1906 } else if (bpf
->pkt_len_val
) {
1907 remaining_len
+= snprintf(buffer
+ remaining_len
,
1911 bpf
->pkt_len_val
->mask
1913 bpf
->pkt_len_val
->val
);
1915 if (bpf
->tcp_flags
) {
1916 remaining_len
+= snprintf(buffer
+ remaining_len
,
1920 bpf
->tcp_flags
->val
,
1921 bpf
->tcp_flags
->mask
);
1924 snprintf(buffer
+ remaining_len
,
1932 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1933 add
? "adding" : "removing",
1934 bpf
->src
== NULL
? "<all>" :
1935 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1936 bpf
->dst
== NULL
? "<all>" :
1937 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1938 protocol_str
, buffer
);
1942 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1943 struct bgp_path_info
*path
,
1944 struct bgp_pbr_filter
*bpf
,
1948 struct bgp_pbr_match temp
;
1949 struct bgp_pbr_match_entry temp2
;
1950 struct bgp_pbr_match
*bpm
;
1951 struct bgp_pbr_match_entry
*bpme
= NULL
;
1952 struct bgp_pbr_action temp3
;
1953 struct bgp_pbr_action
*bpa
= NULL
;
1954 struct bgp_pbr_match_entry_remain bpmer
;
1955 struct bgp_pbr_rule_remain bprr
;
1956 struct bgp_pbr_range_port
*src_port
;
1957 struct bgp_pbr_range_port
*dst_port
;
1958 struct bgp_pbr_range_port
*pkt_len
;
1959 struct bgp_pbr_rule pbr_rule
;
1960 struct bgp_pbr_rule
*bpr
;
1961 bool bpme_found
= false;
1965 src_port
= bpf
->src_port
;
1966 dst_port
= bpf
->dst_port
;
1967 pkt_len
= bpf
->pkt_len
;
1969 if (BGP_DEBUG(zebra
, ZEBRA
))
1970 bgp_pbr_dump_entry(bpf
, true);
1972 /* look for bpa first */
1973 memset(&temp3
, 0, sizeof(temp3
));
1977 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1978 temp3
.vrf_id
= bpf
->vrf_id
;
1979 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1980 bgp_pbr_action_alloc_intern
);
1982 if (bpa
->fwmark
== 0) {
1983 /* drop is handled by iptable */
1984 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1986 bpa
->installed
= true;
1988 bpa
->fwmark
= bgp_zebra_tm_get_id();
1989 bpa
->table_id
= bpa
->fwmark
;
1990 bpa
->installed
= false;
1993 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1994 /* 0 value is forbidden */
1995 bpa
->install_in_progress
= false;
1997 if (bpf
->type
== BGP_PBR_IPRULE
) {
1998 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1999 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2001 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2002 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2005 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2006 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2008 pbr_rule
.action
= bpa
;
2009 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2010 bgp_pbr_rule_alloc_intern
);
2011 if (bpr
&& bpr
->unique
== 0) {
2012 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2013 bpr
->installed
= false;
2014 bpr
->install_in_progress
= false;
2016 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2017 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2018 bgp_zebra_announce_default(bgp
, nh
,
2019 AFI_IP
, bpa
->table_id
, true);
2022 if (bpr
&& !bpr
->installed
)
2023 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2025 /* A previous entry may already exist
2026 * flush previous entry if necessary
2028 bprr
.bpr_to_match
= bpr
;
2029 bprr
.bpr_found
= NULL
;
2030 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2031 if (bprr
.bpr_found
) {
2032 static struct bgp_pbr_rule
*local_bpr
;
2033 static struct bgp_pbr_action
*local_bpa
;
2035 local_bpr
= bprr
.bpr_found
;
2036 local_bpa
= local_bpr
->action
;
2037 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2042 /* then look for bpm */
2043 memset(&temp
, 0, sizeof(temp
));
2044 temp
.vrf_id
= bpf
->vrf_id
;
2046 temp
.flags
|= MATCH_IP_SRC_SET
;
2048 temp
.flags
|= MATCH_IP_DST_SET
;
2050 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2051 if (bpf
->protocol
== IPPROTO_ICMP
)
2052 temp
.flags
|= MATCH_ICMP_SET
;
2053 temp
.flags
|= MATCH_PORT_SRC_SET
;
2055 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2056 if (bpf
->protocol
== IPPROTO_ICMP
)
2057 temp
.flags
|= MATCH_ICMP_SET
;
2058 temp
.flags
|= MATCH_PORT_DST_SET
;
2060 if (src_port
&& src_port
->max_port
)
2061 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2062 if (dst_port
&& dst_port
->max_port
)
2063 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2065 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2066 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2067 temp
.type
= IPSET_NET_PORT
;
2069 temp
.type
= IPSET_NET
;
2071 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2072 temp
.type
= IPSET_NET_PORT_NET
;
2074 temp
.type
= IPSET_NET_NET
;
2077 temp
.pkt_len_min
= pkt_len
->min_port
;
2078 if (pkt_len
->max_port
)
2079 temp
.pkt_len_max
= pkt_len
->max_port
;
2080 } else if (bpf
->pkt_len_val
) {
2081 if (bpf
->pkt_len_val
->mask
)
2082 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2083 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2085 if (bpf
->tcp_flags
) {
2086 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2087 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2090 if (bpf
->dscp
->mask
)
2091 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2093 temp
.flags
|= MATCH_DSCP_SET
;
2094 temp
.dscp_value
= bpf
->dscp
->val
;
2096 if (bpf
->fragment
) {
2097 if (bpf
->fragment
->mask
)
2098 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2099 temp
.fragment
= bpf
->fragment
->val
;
2102 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2103 bgp_pbr_match_alloc_intern
);
2105 /* new, then self allocate ipset_name and unique */
2106 if (bpm
->unique
== 0) {
2107 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2108 /* 0 value is forbidden */
2109 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2110 bpm
->entry_hash
= hash_create_size(8,
2111 bgp_pbr_match_entry_hash_key
,
2112 bgp_pbr_match_entry_hash_equal
,
2113 "Match Entry Hash");
2114 bpm
->installed
= false;
2116 /* unique2 should be updated too */
2117 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2118 bpm
->installed_in_iptable
= false;
2119 bpm
->install_in_progress
= false;
2120 bpm
->install_iptable_in_progress
= false;
2123 memset(&temp2
, 0, sizeof(temp2
));
2125 prefix_copy(&temp2
.src
, bpf
->src
);
2127 temp2
.src
.family
= AF_INET
;
2129 prefix_copy(&temp2
.dst
, bpf
->dst
);
2131 temp2
.dst
.family
= AF_INET
;
2132 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2133 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2134 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2135 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2136 temp2
.proto
= bpf
->protocol
;
2137 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2138 bgp_pbr_match_entry_alloc_intern
);
2139 if (bpme
->unique
== 0) {
2140 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2141 /* 0 value is forbidden */
2142 bpme
->backpointer
= bpm
;
2143 bpme
->installed
= false;
2144 bpme
->install_in_progress
= false;
2145 /* link bgp info to bpme */
2146 bpme
->path
= (void *)path
;
2150 /* already installed */
2152 struct bgp_path_info_extra
*extra
=
2153 bgp_path_info_extra_get(path
);
2155 if (extra
&& extra
->bgp_fs_pbr
&&
2156 listnode_lookup(extra
->bgp_fs_pbr
, bpme
)) {
2157 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2159 "%s: entry %p/%p already installed in bgp pbr",
2160 __func__
, path
, bpme
);
2164 /* BGP FS: append entry to zebra
2165 * - policies are not routing entries and as such
2166 * route replace semantics don't necessarily follow
2167 * through to policy entries
2168 * - because of that, not all policing information will be stored
2169 * into zebra. and non selected policies will be suppressed from zebra
2170 * - as consequence, in order to bring consistency
2171 * a policy will be added, then ifan ecmp policy exists,
2172 * it will be suppressed subsequently
2175 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2176 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2177 bgp_zebra_announce_default(bgp
, nh
,
2178 AFI_IP
, bpa
->table_id
, true);
2182 if (!bpm
->installed
)
2183 bgp_send_pbr_ipset_match(bpm
, true);
2185 if (!bpme
->installed
)
2186 bgp_send_pbr_ipset_entry_match(bpme
, true);
2189 if (!bpm
->installed_in_iptable
)
2190 bgp_send_pbr_iptable(bpa
, bpm
, true);
2192 /* A previous entry may already exist
2193 * flush previous entry if necessary
2195 bpmer
.bpme_to_match
= bpme
;
2196 bpmer
.bpme_found
= NULL
;
2197 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2198 if (bpmer
.bpme_found
) {
2199 static struct bgp_pbr_match
*local_bpm
;
2200 static struct bgp_pbr_action
*local_bpa
;
2202 local_bpm
= bpmer
.bpme_found
->backpointer
;
2203 local_bpa
= local_bpm
->action
;
2204 bgp_pbr_flush_entry(bgp
, local_bpa
,
2205 local_bpm
, bpmer
.bpme_found
);
2211 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2212 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2213 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2216 struct listnode
*node
, *nnode
;
2217 struct bgp_pbr_val_mask
*valmask
;
2218 uint8_t next_type_entry
;
2219 struct list
*orig_list
;
2220 struct bgp_pbr_val_mask
**target_val
;
2222 if (type_entry
== 0) {
2223 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2226 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2227 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2228 orig_list
= bpof
->tcpflags
;
2229 target_val
= &bpf
->tcp_flags
;
2230 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2231 orig_list
= bpof
->dscp
;
2232 target_val
= &bpf
->dscp
;
2233 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2234 orig_list
= bpof
->pkt_len
;
2235 target_val
= &bpf
->pkt_len_val
;
2236 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2237 orig_list
= bpof
->fragment
;
2238 target_val
= &bpf
->fragment
;
2239 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2240 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2241 /* enumerate list for icmp - must be last one */
2242 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2245 bgp_pbr_policyroute_add_to_zebra_recursive(
2246 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2249 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2250 *target_val
= valmask
;
2251 bgp_pbr_policyroute_add_to_zebra_recursive(
2252 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2256 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2257 struct bgp_path_info
*path
,
2258 struct bgp_pbr_filter
*bpf
,
2259 struct bgp_pbr_or_filter
*bpof
,
2260 struct nexthop
*nh
, float *rate
)
2263 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2267 bgp_pbr_policyroute_add_to_zebra_recursive(
2268 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2269 else if (bpof
->dscp
)
2270 bgp_pbr_policyroute_add_to_zebra_recursive(
2271 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2272 else if (bpof
->pkt_len
)
2273 bgp_pbr_policyroute_add_to_zebra_recursive(
2274 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2275 else if (bpof
->fragment
)
2276 bgp_pbr_policyroute_add_to_zebra_recursive(
2277 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2278 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2279 bgp_pbr_policyroute_add_to_zebra_recursive(
2280 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2282 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2285 list_delete_all_node(bpof
->tcpflags
);
2287 list_delete_all_node(bpof
->dscp
);
2289 list_delete_all_node(bpof
->pkt_len
);
2291 list_delete_all_node(bpof
->fragment
);
2292 if (bpof
->icmp_type
)
2293 list_delete_all_node(bpof
->icmp_type
);
2294 if (bpof
->icmp_code
)
2295 list_delete_all_node(bpof
->icmp_code
);
2298 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2299 struct bgp_pbr_entry_main
*api
, bool add
)
2303 int continue_loop
= 1;
2305 struct prefix
*src
= NULL
, *dst
= NULL
;
2307 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2308 struct bgp_pbr_range_port range
, range_icmp_code
;
2309 struct bgp_pbr_range_port pkt_len
;
2310 struct bgp_pbr_filter bpf
;
2312 struct bgp_pbr_or_filter bpof
;
2313 struct bgp_pbr_val_mask bpvm
;
2315 memset(&nh
, 0, sizeof(struct nexthop
));
2316 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2317 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2318 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2319 (api
->type
== BGP_PBR_IPRULE
&&
2320 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2321 src
= &api
->src_prefix
;
2322 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2323 (api
->type
== BGP_PBR_IPRULE
&&
2324 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2325 dst
= &api
->dst_prefix
;
2326 if (api
->type
== BGP_PBR_IPRULE
)
2327 bpf
.type
= api
->type
;
2328 memset(&nh
, 0, sizeof(struct nexthop
));
2329 nh
.vrf_id
= VRF_UNKNOWN
;
2330 if (api
->match_protocol_num
)
2331 proto
= (uint8_t)api
->protocol
[0].value
;
2332 /* if match_port is selected, then either src or dst port will be parsed
2333 * but not both at the same time
2335 if (api
->match_port_num
>= 1) {
2336 bgp_pbr_extract(api
->port
,
2337 api
->match_port_num
,
2339 srcp
= dstp
= &range
;
2340 } else if (api
->match_src_port_num
>= 1) {
2341 bgp_pbr_extract(api
->src_port
,
2342 api
->match_src_port_num
,
2346 } else if (api
->match_dst_port_num
>= 1) {
2347 bgp_pbr_extract(api
->dst_port
,
2348 api
->match_dst_port_num
,
2353 if (api
->match_icmp_type_num
>= 1) {
2354 proto
= IPPROTO_ICMP
;
2355 if (bgp_pbr_extract(api
->icmp_type
,
2356 api
->match_icmp_type_num
,
2360 bpof
.icmp_type
= list_new();
2361 bgp_pbr_extract_enumerate(api
->icmp_type
,
2362 api
->match_icmp_type_num
,
2365 FLOWSPEC_ICMP_TYPE
);
2368 if (api
->match_icmp_code_num
>= 1) {
2369 proto
= IPPROTO_ICMP
;
2370 if (bgp_pbr_extract(api
->icmp_code
,
2371 api
->match_icmp_code_num
,
2373 dstp
= &range_icmp_code
;
2375 bpof
.icmp_code
= list_new();
2376 bgp_pbr_extract_enumerate(api
->icmp_code
,
2377 api
->match_icmp_code_num
,
2380 FLOWSPEC_ICMP_CODE
);
2384 if (api
->match_tcpflags_num
) {
2385 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2386 api
->match_tcpflags_num
);
2387 if (kind_enum
== OPERATOR_UNARY_AND
) {
2388 bpf
.tcp_flags
= &bpvm
;
2389 bgp_pbr_extract_enumerate(api
->tcpflags
,
2390 api
->match_tcpflags_num
,
2393 FLOWSPEC_TCP_FLAGS
);
2394 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2395 bpof
.tcpflags
= list_new();
2396 bgp_pbr_extract_enumerate(api
->tcpflags
,
2397 api
->match_tcpflags_num
,
2400 FLOWSPEC_TCP_FLAGS
);
2403 if (api
->match_packet_length_num
) {
2406 ret
= bgp_pbr_extract(api
->packet_length
,
2407 api
->match_packet_length_num
,
2410 bpf
.pkt_len
= &pkt_len
;
2412 bpof
.pkt_len
= list_new();
2413 bgp_pbr_extract_enumerate(api
->packet_length
,
2414 api
->match_packet_length_num
,
2420 if (api
->match_dscp_num
>= 1) {
2421 bpof
.dscp
= list_new();
2422 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2424 bpof
.dscp
, FLOWSPEC_DSCP
);
2426 if (api
->match_fragment_num
) {
2427 bpof
.fragment
= list_new();
2428 bgp_pbr_extract_enumerate(api
->fragment
,
2429 api
->match_fragment_num
,
2434 bpf
.vrf_id
= api
->vrf_id
;
2437 bpf
.protocol
= proto
;
2438 bpf
.src_port
= srcp
;
2439 bpf
.dst_port
= dstp
;
2441 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2444 /* no action for add = true */
2445 for (i
= 0; i
< api
->action_num
; i
++) {
2446 switch (api
->actions
[i
].action
) {
2447 case ACTION_TRAFFICRATE
:
2449 if (api
->actions
[i
].u
.r
.rate
== 0) {
2450 nh
.vrf_id
= api
->vrf_id
;
2451 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2452 bgp_pbr_policyroute_add_to_zebra(
2453 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2455 /* update rate. can be reentrant */
2456 rate
= api
->actions
[i
].u
.r
.rate
;
2457 if (BGP_DEBUG(pbr
, PBR
)) {
2458 bgp_pbr_print_policy_route(api
);
2459 zlog_warn("PBR: ignoring Set action rate %f",
2460 api
->actions
[i
].u
.r
.rate
);
2464 case ACTION_TRAFFIC_ACTION
:
2465 if (api
->actions
[i
].u
.za
.filter
2466 & TRAFFIC_ACTION_SAMPLE
) {
2467 if (BGP_DEBUG(pbr
, PBR
)) {
2468 bgp_pbr_print_policy_route(api
);
2469 zlog_warn("PBR: Sample action Ignored");
2473 if (api
->actions
[i
].u
.za
.filter
2474 & TRAFFIC_ACTION_DISTRIBUTE
) {
2475 if (BGP_DEBUG(pbr
, PBR
)) {
2476 bgp_pbr_print_policy_route(api
);
2477 zlog_warn("PBR: Distribute action Applies");
2480 /* continue forwarding entry as before
2484 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2485 /* terminate action: run other filters
2488 case ACTION_REDIRECT_IP
:
2489 nh
.type
= NEXTHOP_TYPE_IPV4
;
2490 nh
.gate
.ipv4
.s_addr
=
2491 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2492 nh
.vrf_id
= api
->vrf_id
;
2493 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2495 /* XXX combination with REDIRECT_VRF
2496 * + REDIRECT_NH_IP not done
2500 case ACTION_REDIRECT
:
2501 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2502 nh
.type
= NEXTHOP_TYPE_IPV4
;
2503 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2507 case ACTION_MARKING
:
2508 if (BGP_DEBUG(pbr
, PBR
)) {
2509 bgp_pbr_print_policy_route(api
);
2510 zlog_warn("PBR: Set DSCP %u Ignored",
2511 api
->actions
[i
].u
.marking_dscp
);
2517 if (continue_loop
== 0)
2522 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2523 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2526 struct bgp_pbr_entry_main api
;
2529 return; /* IPv6 not supported */
2530 if (safi
!= SAFI_FLOWSPEC
)
2531 return; /* not supported */
2532 /* Make Zebra API structure. */
2533 memset(&api
, 0, sizeof(api
));
2534 api
.vrf_id
= bgp
->vrf_id
;
2537 if (!bgp_zebra_tm_chunk_obtained()) {
2538 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2539 flog_err(EC_BGP_TABLE_CHUNK
,
2540 "%s: table chunk not obtained yet", __func__
);
2544 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2545 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2546 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2547 "%s: cancel updating entry %p in bgp pbr",
2551 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2554 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2555 const struct bgp_pbr_interface
*b
)
2557 return strcmp(a
->name
, b
->name
);
2560 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2561 struct bgp_pbr_interface_head
*head
)
2563 struct bgp_pbr_interface pbr_if
;
2565 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2566 return (RB_FIND(bgp_pbr_interface_head
,
2570 /* this function resets to the default policy routing
2571 * go back to default status
2573 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2575 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2576 struct bgp_pbr_interface_head
*head
;
2577 struct bgp_pbr_interface
*pbr_if
;
2579 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2581 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2583 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2584 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2585 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2586 XFREE(MTYPE_TMP
, pbr_if
);