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 struct bgp_pbr_rule_unique
{
72 struct bgp_pbr_rule
*bpr_found
;
75 static int bgp_pbr_rule_walkcb(struct hash_backet
*backet
, void *arg
)
77 struct bgp_pbr_rule
*bpr
= (struct bgp_pbr_rule
*)backet
->data
;
78 struct bgp_pbr_rule_unique
*bpru
= (struct bgp_pbr_rule_unique
*)
80 uint32_t unique
= bpru
->unique
;
82 if (bpr
->unique
== unique
) {
83 bpru
->bpr_found
= bpr
;
84 return HASHWALK_ABORT
;
86 return HASHWALK_CONTINUE
;
89 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
91 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
92 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
94 uint32_t unique
= bpau
->unique
;
96 if (bpa
->unique
== unique
) {
97 bpau
->bpa_found
= bpa
;
98 return HASHWALK_ABORT
;
100 return HASHWALK_CONTINUE
;
103 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
105 struct bgp_pbr_match_entry
*bpme
=
106 (struct bgp_pbr_match_entry
*)backet
->data
;
107 struct bgp_pbr_match_entry_unique
*bpmeu
=
108 (struct bgp_pbr_match_entry_unique
*)arg
;
109 uint32_t unique
= bpmeu
->unique
;
111 if (bpme
->unique
== unique
) {
112 bpmeu
->bpme_found
= bpme
;
113 return HASHWALK_ABORT
;
115 return HASHWALK_CONTINUE
;
118 struct bgp_pbr_match_ipsetname
{
120 struct bgp_pbr_match
*bpm_found
;
123 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
125 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
126 struct bgp_pbr_match_ipsetname
*bpmi
=
127 (struct bgp_pbr_match_ipsetname
*)arg
;
128 char *ipset_name
= bpmi
->ipsetname
;
130 if (!strncmp(ipset_name
, bpm
->ipset_name
,
131 ZEBRA_IPSET_NAME_SIZE
)) {
132 bpmi
->bpm_found
= bpm
;
133 return HASHWALK_ABORT
;
135 return HASHWALK_CONTINUE
;
138 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
140 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
141 struct bgp_pbr_match_iptable_unique
*bpmiu
=
142 (struct bgp_pbr_match_iptable_unique
*)arg
;
143 uint32_t unique
= bpmiu
->unique
;
145 if (bpm
->unique2
== unique
) {
146 bpmiu
->bpm_found
= bpm
;
147 return HASHWALK_ABORT
;
149 return HASHWALK_CONTINUE
;
152 struct bgp_pbr_match_unique
{
154 struct bgp_pbr_match
*bpm_found
;
157 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
159 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
160 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
162 uint32_t unique
= bpmu
->unique
;
164 if (bpm
->unique
== unique
) {
165 bpmu
->bpm_found
= bpm
;
166 return HASHWALK_ABORT
;
168 return HASHWALK_CONTINUE
;
171 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
177 ptr
+= sprintf(ptr
, "%s", prepend
);
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 ");
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
);
196 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
198 (_ptr) += sprintf((_ptr), "; "); \
202 /* this structure can be used for port range,
203 * but also for other values range like packet length range
205 struct bgp_pbr_range_port
{
210 /* this structure can be used to filter with a mask
211 * for instance it supports not instructions like for
214 struct bgp_pbr_val_mask
{
219 /* this structure is used to pass instructs
220 * so that BGP can create pbr instructions to ZEBRA
222 struct bgp_pbr_filter
{
227 uint8_t bitmask_iprule
;
229 struct bgp_pbr_range_port
*pkt_len
;
230 struct bgp_pbr_range_port
*src_port
;
231 struct bgp_pbr_range_port
*dst_port
;
232 struct bgp_pbr_val_mask
*tcp_flags
;
233 struct bgp_pbr_val_mask
*dscp
;
234 struct bgp_pbr_val_mask
*pkt_len_val
;
235 struct bgp_pbr_val_mask
*fragment
;
238 /* this structure is used to contain OR instructions
239 * so that BGP can create multiple pbr instructions
242 struct bgp_pbr_or_filter
{
243 struct list
*tcpflags
;
245 struct list
*pkt_len
;
246 struct list
*fragment
;
247 struct list
*icmp_type
;
248 struct list
*icmp_code
;
251 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
252 struct bgp_path_info
*path
,
253 struct bgp_pbr_filter
*bpf
,
257 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
259 static 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
,
265 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
266 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
268 TCP_HEADER_ALL_FLAGS
&
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 */
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
;
282 TCP_HEADER_ALL_FLAGS
&
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 */
290 listnode_add(or_valmask
, and_valmask
);
291 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
292 type_entry
== FLOWSPEC_ICMP_TYPE
)
297 /* TCP : FIN and SYN -> val = ALL; mask = 3
298 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
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
303 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
304 int num
, uint8_t unary_operator
,
305 void *valmask
, uint8_t type_entry
)
308 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
309 struct list
*or_valmask
= NULL
;
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
;
320 for (i
= 0; i
< num
; i
++) {
321 if (i
!= 0 && list
[i
].unary_operator
!=
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
)) {
332 ret
= bgp_pbr_extract_enumerate_unary_opposite(
333 unary_operator
, and_valmask
,
334 or_valmask
, list
[i
].value
,
342 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
343 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
345 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
346 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
347 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
348 sizeof(struct bgp_pbr_val_mask
));
349 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
350 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
352 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
353 } else if (type_entry
== FLOWSPEC_DSCP
||
354 type_entry
== FLOWSPEC_ICMP_TYPE
||
355 type_entry
== FLOWSPEC_ICMP_CODE
||
356 type_entry
== FLOWSPEC_FRAGMENT
||
357 type_entry
== FLOWSPEC_PKT_LEN
)
358 and_valmask
->val
= list
[i
].value
;
359 listnode_add(or_valmask
, and_valmask
);
362 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
363 && type_entry
== FLOWSPEC_TCP_FLAGS
)
364 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
368 /* if unary operator can either be UNARY_OR/AND/OR-AND.
369 * in the latter case, combinationf of both is not handled
371 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
372 int num
, uint8_t unary_operator
,
373 void *valmask
, uint8_t type_entry
)
376 uint8_t unary_operator_val
;
377 bool double_check
= false;
379 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
380 (unary_operator
& OPERATOR_UNARY_AND
)) {
381 unary_operator_val
= OPERATOR_UNARY_AND
;
384 unary_operator_val
= unary_operator
;
385 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
386 valmask
, type_entry
);
387 if (!ret
&& double_check
)
388 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
395 /* returns the unary operator that is in the list
396 * return 0 if both operators are used
398 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
403 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
405 for (i
= 0; i
< num
; i
++) {
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
))
416 return unary_operator
;
420 /* return true if extraction ok
422 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
424 struct bgp_pbr_range_port
*range
)
427 bool exact_match
= false;
430 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
434 for (i
= 0; i
< num
; i
++) {
435 if (i
!= 0 && (list
[i
].compare_operator
==
436 OPERATOR_COMPARE_EQUAL_TO
))
438 if (i
== 0 && (list
[i
].compare_operator
==
439 OPERATOR_COMPARE_EQUAL_TO
)) {
441 range
->min_port
= list
[i
].value
;
444 if (exact_match
== true && i
> 0)
446 if (list
[i
].compare_operator
==
447 (OPERATOR_COMPARE_GREATER_THAN
+
448 OPERATOR_COMPARE_EQUAL_TO
)) {
450 range
->min_port
= list
[i
].value
;
451 } else if (list
[i
].compare_operator
==
452 (OPERATOR_COMPARE_LESS_THAN
+
453 OPERATOR_COMPARE_EQUAL_TO
)) {
455 range
->max_port
= list
[i
].value
;
456 } else if (list
[i
].compare_operator
==
457 OPERATOR_COMPARE_LESS_THAN
) {
459 range
->max_port
= list
[i
].value
- 1;
460 } else if (list
[i
].compare_operator
==
461 OPERATOR_COMPARE_GREATER_THAN
) {
463 range
->min_port
= list
[i
].value
+ 1;
469 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
471 bool enumerate_icmp
= false;
473 if (api
->type
== BGP_PBR_UNDEFINED
) {
474 if (BGP_DEBUG(pbr
, PBR
))
475 zlog_debug("BGP: pbr entry undefined. cancel.");
478 /* because bgp pbr entry may contain unsupported
479 * combinations, a message will be displayed here if
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
485 * - combination srcport + @IP
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
);
494 if (api
->match_protocol_num
== 1 &&
495 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
496 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
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
);
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.");
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.");
516 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
517 api
->match_tcpflags_num
,
519 OPERATOR_UNARY_OR
, NULL
,
520 FLOWSPEC_TCP_FLAGS
)) {
521 if (BGP_DEBUG(pbr
, PBR
))
522 zlog_debug("BGP: match tcp flags:"
523 "too complex. ignoring.");
526 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
527 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
528 api
->match_icmp_type_num
,
529 OPERATOR_UNARY_OR
, NULL
,
530 FLOWSPEC_ICMP_TYPE
)) {
531 if (BGP_DEBUG(pbr
, PBR
))
532 zlog_debug("BGP: match icmp type operations:"
533 "too complex. ignoring.");
536 enumerate_icmp
= true;
538 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
539 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
540 api
->match_icmp_code_num
,
541 OPERATOR_UNARY_OR
, NULL
,
542 FLOWSPEC_ICMP_CODE
)) {
543 if (BGP_DEBUG(pbr
, PBR
))
544 zlog_debug("BGP: match icmp code operations:"
545 "too complex. ignoring.");
547 } else if (api
->match_icmp_type_num
> 1 &&
548 enumerate_icmp
== false) {
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.");
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.");
562 if (api
->match_packet_length_num
) {
565 ret
= bgp_pbr_extract(api
->packet_length
,
566 api
->match_packet_length_num
, NULL
);
568 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
569 api
->match_packet_length_num
,
571 | OPERATOR_UNARY_AND
,
572 NULL
, FLOWSPEC_PKT_LEN
);
574 if (BGP_DEBUG(pbr
, PBR
))
575 zlog_debug("BGP: match packet length operations:"
576 "too complex. ignoring.");
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.");
590 if (api
->match_fragment_num
) {
594 success
= bgp_pbr_extract_enumerate(api
->fragment
,
595 api
->match_fragment_num
,
597 | OPERATOR_UNARY_AND
,
598 NULL
, FLOWSPEC_FRAGMENT
);
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) {
609 "Value not valid (%d) for this implementation",
610 api
->fragment
[i
].value
);
614 sprintf(fail_str
, "too complex. ignoring");
616 if (BGP_DEBUG(pbr
, PBR
))
617 zlog_debug("BGP: match fragment operation (%d) %s",
618 api
->match_fragment_num
,
624 /* no combinations with both src_port and dst_port
625 * or port with src_port and dst_port
627 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
628 api
->match_port_num
> 3) {
629 if (BGP_DEBUG(pbr
, PBR
))
630 zlog_debug("BGP: match multiple port operations:"
631 " too complex. ignoring.");
634 if ((api
->match_src_port_num
|| api
->match_dst_port_num
635 || api
->match_port_num
) && (api
->match_icmp_type_num
636 || api
->match_icmp_code_num
)) {
637 if (BGP_DEBUG(pbr
, PBR
))
638 zlog_debug("BGP: match multiple port/imcp operations:"
639 " too complex. ignoring.");
642 /* iprule only supports redirect IP */
643 if (api
->type
== BGP_PBR_IPRULE
) {
646 for (i
= 0; i
< api
->action_num
; i
++) {
647 if (api
->actions
[i
].action
== ACTION_TRAFFICRATE
&&
648 api
->actions
[i
].u
.r
.rate
== 0) {
649 if (BGP_DEBUG(pbr
, PBR
)) {
650 bgp_pbr_print_policy_route(api
);
651 zlog_debug("BGP: iprule match actions"
652 " drop not supported");
656 if (api
->actions
[i
].action
== ACTION_MARKING
) {
657 if (BGP_DEBUG(pbr
, PBR
)) {
658 bgp_pbr_print_policy_route(api
);
659 zlog_warn("PBR: iprule set DSCP %u"
661 api
->actions
[i
].u
.marking_dscp
);
664 if (api
->actions
[i
].action
== ACTION_REDIRECT
) {
665 if (BGP_DEBUG(pbr
, PBR
)) {
666 bgp_pbr_print_policy_route(api
);
667 zlog_warn("PBR: iprule redirect VRF %u"
669 api
->actions
[i
].u
.redirect_vrf
);
674 } else if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
675 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
676 if (BGP_DEBUG(pbr
, PBR
)) {
677 bgp_pbr_print_policy_route(api
);
678 zlog_debug("BGP: match actions without src"
679 " or dst address can not operate."
687 /* return -1 if build or validation failed */
688 int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
689 struct bgp_path_info
*path
,
690 struct bgp_pbr_entry_main
*api
)
693 int i
, action_count
= 0;
694 struct ecommunity
*ecom
;
695 struct ecommunity_val
*ecom_eval
;
696 struct bgp_pbr_entry_action
*api_action
;
697 struct prefix
*src
= NULL
, *dst
= NULL
;
698 int valid_prefix
= 0;
700 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
702 /* extract match from flowspec entries */
703 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
704 p
->u
.prefix_flowspec
.prefixlen
, api
);
707 /* extract actiosn from flowspec ecom list */
708 if (path
&& path
->attr
&& path
->attr
->ecommunity
) {
709 ecom
= path
->attr
->ecommunity
;
710 for (i
= 0; i
< ecom
->size
; i
++) {
711 ecom_eval
= (struct ecommunity_val
*)
712 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
714 if (action_count
> ACTIONS_MAX_NUM
) {
715 if (BGP_DEBUG(pbr
, PBR_ERROR
))
717 EC_BGP_FLOWSPEC_PACKET
,
718 "%s: flowspec actions exceeds limit (max %u)",
719 __func__
, action_count
);
722 api_action
= &api
->actions
[action_count
- 1];
724 if ((ecom_eval
->val
[1] ==
725 (char)ECOMMUNITY_REDIRECT_VRF
) &&
726 (ecom_eval
->val
[0] ==
727 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
729 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
731 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
732 struct ecommunity
*eckey
= ecommunity_new();
733 struct ecommunity_val ecom_copy
;
735 memcpy(&ecom_copy
, ecom_eval
,
736 sizeof(struct ecommunity_val
));
738 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
739 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
740 ecommunity_add_val(eckey
, &ecom_copy
);
742 api_action
->action
= ACTION_REDIRECT
;
743 api_action
->u
.redirect_vrf
=
744 get_first_vrf_for_redirect_with_rt(
746 ecommunity_free(&eckey
);
747 } else if ((ecom_eval
->val
[0] ==
748 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
749 (ecom_eval
->val
[1] ==
750 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
751 /* in case the 2 ecom present,
753 * draft-ietf-idr-flowspec-redirect
755 if (api_action_redirect_ip
) {
756 if (api_action_redirect_ip
->u
757 .zr
.redirect_ip_v4
.s_addr
)
759 if (!path
->attr
->nexthop
.s_addr
)
761 api_action_redirect_ip
->u
762 .zr
.redirect_ip_v4
.s_addr
=
763 path
->attr
->nexthop
.s_addr
;
764 api_action_redirect_ip
->u
.zr
.duplicate
768 api_action
->action
= ACTION_REDIRECT_IP
;
769 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
770 path
->attr
->nexthop
.s_addr
;
771 api_action
->u
.zr
.duplicate
=
773 api_action_redirect_ip
= api_action
;
775 } else if ((ecom_eval
->val
[0] ==
776 (char)ECOMMUNITY_ENCODE_IP
) &&
777 (ecom_eval
->val
[1] ==
778 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
779 /* in case the 2 ecom present,
780 * overwrite simpson draft
781 * update redirect ip fields
783 if (api_action_redirect_ip
) {
784 memcpy(&(api_action_redirect_ip
->u
785 .zr
.redirect_ip_v4
.s_addr
),
786 (ecom_eval
->val
+2), 4);
787 api_action_redirect_ip
->u
792 api_action
->action
= ACTION_REDIRECT_IP
;
793 memcpy(&(api_action
->u
794 .zr
.redirect_ip_v4
.s_addr
),
795 (ecom_eval
->val
+2), 4);
796 api_action
->u
.zr
.duplicate
=
798 api_action_redirect_ip
= api_action
;
801 if (ecom_eval
->val
[0] !=
802 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
804 ret
= ecommunity_fill_pbr_action(ecom_eval
,
813 /* validate if incoming matc/action is compatible
814 * with our policy routing engine
816 if (!bgp_pbr_validate_policy_route(api
))
819 /* check inconsistency in the match rule */
820 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
821 src
= &api
->src_prefix
;
822 afi
= family2afi(src
->family
);
825 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
826 dst
= &api
->dst_prefix
;
827 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
828 if (BGP_DEBUG(pbr
, PBR
)) {
829 bgp_pbr_print_policy_route(api
);
830 zlog_debug("%s: inconsistency:"
831 " no match for afi src and dst (%u/%u)",
832 __func__
, afi
, family2afi(dst
->family
));
840 static void bgp_pbr_match_entry_free(void *arg
)
842 struct bgp_pbr_match_entry
*bpme
;
844 bpme
= (struct bgp_pbr_match_entry
*)arg
;
846 if (bpme
->installed
) {
847 bgp_send_pbr_ipset_entry_match(bpme
, false);
848 bpme
->installed
= false;
849 bpme
->backpointer
= NULL
;
851 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
854 static void bgp_pbr_match_free(void *arg
)
856 struct bgp_pbr_match
*bpm
;
858 bpm
= (struct bgp_pbr_match
*)arg
;
860 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
862 if (hashcount(bpm
->entry_hash
) == 0) {
863 /* delete iptable entry first */
864 /* then delete ipset match */
865 if (bpm
->installed
) {
866 if (bpm
->installed_in_iptable
) {
867 bgp_send_pbr_iptable(bpm
->action
,
869 bpm
->installed_in_iptable
= false;
870 bpm
->action
->refcnt
--;
872 bgp_send_pbr_ipset_match(bpm
, false);
873 bpm
->installed
= false;
877 hash_free(bpm
->entry_hash
);
879 XFREE(MTYPE_PBR_MATCH
, bpm
);
882 static void *bgp_pbr_match_alloc_intern(void *arg
)
884 struct bgp_pbr_match
*bpm
, *new;
886 bpm
= (struct bgp_pbr_match
*)arg
;
888 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
889 memcpy(new, bpm
, sizeof(*bpm
));
894 static void bgp_pbr_rule_free(void *arg
)
896 struct bgp_pbr_rule
*bpr
;
898 bpr
= (struct bgp_pbr_rule
*)arg
;
901 if (bpr
->installed
) {
902 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
903 bpr
->installed
= false;
904 bpr
->action
->refcnt
--;
907 XFREE(MTYPE_PBR_RULE
, bpr
);
910 static void *bgp_pbr_rule_alloc_intern(void *arg
)
912 struct bgp_pbr_rule
*bpr
, *new;
914 bpr
= (struct bgp_pbr_rule
*)arg
;
916 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
917 memcpy(new, bpr
, sizeof(*bpr
));
922 static void bgp_pbr_action_free(void *arg
)
924 struct bgp_pbr_action
*bpa
;
926 bpa
= (struct bgp_pbr_action
*)arg
;
928 if (bpa
->refcnt
== 0) {
929 if (bpa
->installed
&& bpa
->table_id
!= 0) {
930 bgp_send_pbr_rule_action(bpa
, NULL
, false);
931 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
935 bpa
->installed
= false;
938 XFREE(MTYPE_PBR_ACTION
, bpa
);
941 static void *bgp_pbr_action_alloc_intern(void *arg
)
943 struct bgp_pbr_action
*bpa
, *new;
945 bpa
= (struct bgp_pbr_action
*)arg
;
947 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
949 memcpy(new, bpa
, sizeof(*bpa
));
954 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
956 struct bgp_pbr_match_entry
*bpme
, *new;
958 bpme
= (struct bgp_pbr_match_entry
*)arg
;
960 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
962 memcpy(new, bpme
, sizeof(*bpme
));
967 uint32_t bgp_pbr_match_hash_key(void *arg
)
969 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
972 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
973 key
= jhash_1word(pbm
->flags
, key
);
974 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
975 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
976 key
= jhash(&pbm
->tcp_flags
, 2, key
);
977 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
978 key
= jhash(&pbm
->dscp_value
, 1, key
);
979 key
= jhash(&pbm
->fragment
, 1, key
);
980 return jhash_1word(pbm
->type
, key
);
983 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
985 const struct bgp_pbr_match
*r1
, *r2
;
987 r1
= (const struct bgp_pbr_match
*)arg1
;
988 r2
= (const struct bgp_pbr_match
*)arg2
;
990 if (r1
->vrf_id
!= r2
->vrf_id
)
993 if (r1
->type
!= r2
->type
)
996 if (r1
->flags
!= r2
->flags
)
999 if (r1
->action
!= r2
->action
)
1002 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1005 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1008 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1011 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1014 if (r1
->dscp_value
!= r2
->dscp_value
)
1017 if (r1
->fragment
!= r2
->fragment
)
1022 uint32_t bgp_pbr_rule_hash_key(void *arg
)
1024 struct bgp_pbr_rule
*pbr
= (struct bgp_pbr_rule
*)arg
;
1027 key
= prefix_hash_key(&pbr
->src
);
1028 key
= jhash_1word(pbr
->vrf_id
, key
);
1029 key
= jhash_1word(pbr
->flags
, key
);
1030 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1033 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1035 const struct bgp_pbr_rule
*r1
, *r2
;
1037 r1
= (const struct bgp_pbr_rule
*)arg1
;
1038 r2
= (const struct bgp_pbr_rule
*)arg2
;
1040 if (r1
->vrf_id
!= r2
->vrf_id
)
1043 if (r1
->flags
!= r2
->flags
)
1046 if (r1
->action
!= r2
->action
)
1049 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1050 !prefix_same(&r1
->src
, &r2
->src
))
1053 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1054 !prefix_same(&r1
->dst
, &r2
->dst
))
1060 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
1062 struct bgp_pbr_match_entry
*pbme
;
1065 pbme
= (struct bgp_pbr_match_entry
*)arg
;
1066 key
= prefix_hash_key(&pbme
->src
);
1067 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1068 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1069 key
= jhash(&pbme
->src_port_min
, 2, key
);
1070 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1071 key
= jhash(&pbme
->src_port_max
, 2, key
);
1072 key
= jhash(&pbme
->proto
, 1, key
);
1077 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1079 const struct bgp_pbr_match_entry
*r1
, *r2
;
1081 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1082 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1085 * on updates, comparing backpointer is not necessary
1086 * unique value is self calculated
1087 * rate is ignored for now
1090 if (!prefix_same(&r1
->src
, &r2
->src
))
1093 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1096 if (r1
->src_port_min
!= r2
->src_port_min
)
1099 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1102 if (r1
->src_port_max
!= r2
->src_port_max
)
1105 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1108 if (r1
->proto
!= r2
->proto
)
1114 uint32_t bgp_pbr_action_hash_key(void *arg
)
1116 struct bgp_pbr_action
*pbra
;
1119 pbra
= (struct bgp_pbr_action
*)arg
;
1120 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1121 key
= jhash_1word(pbra
->fwmark
, key
);
1125 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1127 const struct bgp_pbr_action
*r1
, *r2
;
1129 r1
= (const struct bgp_pbr_action
*)arg1
;
1130 r2
= (const struct bgp_pbr_action
*)arg2
;
1132 /* unique value is self calculated
1133 * table and fwmark is self calculated
1136 if (r1
->vrf_id
!= r2
->vrf_id
)
1139 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1145 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1148 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1149 struct bgp_pbr_rule_unique bpru
;
1151 if (!bgp
|| unique
== 0)
1153 bpru
.unique
= unique
;
1154 bpru
.bpr_found
= NULL
;
1155 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1156 return bpru
.bpr_found
;
1159 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1162 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1163 struct bgp_pbr_action_unique bpau
;
1165 if (!bgp
|| unique
== 0)
1167 bpau
.unique
= unique
;
1168 bpau
.bpa_found
= NULL
;
1169 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1170 return bpau
.bpa_found
;
1173 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1176 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1177 struct bgp_pbr_match_unique bpmu
;
1179 if (!bgp
|| unique
== 0)
1181 bpmu
.unique
= unique
;
1182 bpmu
.bpm_found
= NULL
;
1183 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1184 return bpmu
.bpm_found
;
1187 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1191 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1192 struct bgp_pbr_match_entry_unique bpmeu
;
1193 struct bgp_pbr_match_ipsetname bpmi
;
1195 if (!bgp
|| unique
== 0)
1197 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1198 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1199 bpmi
.bpm_found
= NULL
;
1200 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1201 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1202 if (!bpmi
.bpm_found
)
1204 bpmeu
.bpme_found
= NULL
;
1205 bpmeu
.unique
= unique
;
1206 hash_walk(bpmi
.bpm_found
->entry_hash
,
1207 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1208 return bpmeu
.bpme_found
;
1211 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1214 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1215 struct bgp_pbr_match_iptable_unique bpmiu
;
1217 if (!bgp
|| unique
== 0)
1219 bpmiu
.unique
= unique
;
1220 bpmiu
.bpm_found
= NULL
;
1221 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1222 return bpmiu
.bpm_found
;
1225 void bgp_pbr_cleanup(struct bgp
*bgp
)
1227 if (bgp
->pbr_match_hash
) {
1228 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1229 hash_free(bgp
->pbr_match_hash
);
1230 bgp
->pbr_match_hash
= NULL
;
1232 if (bgp
->pbr_rule_hash
) {
1233 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1234 hash_free(bgp
->pbr_rule_hash
);
1235 bgp
->pbr_rule_hash
= NULL
;
1237 if (bgp
->pbr_action_hash
) {
1238 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1239 hash_free(bgp
->pbr_action_hash
);
1240 bgp
->pbr_action_hash
= NULL
;
1242 if (bgp
->bgp_pbr_cfg
== NULL
)
1244 bgp_pbr_reset(bgp
, AFI_IP
);
1245 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1246 bgp
->bgp_pbr_cfg
= NULL
;
1249 void bgp_pbr_init(struct bgp
*bgp
)
1251 bgp
->pbr_match_hash
=
1252 hash_create_size(8, bgp_pbr_match_hash_key
,
1253 bgp_pbr_match_hash_equal
,
1255 bgp
->pbr_action_hash
=
1256 hash_create_size(8, bgp_pbr_action_hash_key
,
1257 bgp_pbr_action_hash_equal
,
1258 "Match Hash Entry");
1260 bgp
->pbr_rule_hash
=
1261 hash_create_size(8, bgp_pbr_rule_hash_key
,
1262 bgp_pbr_rule_hash_equal
,
1265 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1266 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1269 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1272 char return_string
[512];
1273 char *ptr
= return_string
;
1277 ptr
+= sprintf(ptr
, "MATCH : ");
1278 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1279 struct prefix
*p
= &(api
->src_prefix
);
1281 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1282 INCREMENT_DISPLAY(ptr
, nb_items
);
1284 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1285 struct prefix
*p
= &(api
->dst_prefix
);
1287 INCREMENT_DISPLAY(ptr
, nb_items
);
1288 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1291 if (api
->match_protocol_num
)
1292 INCREMENT_DISPLAY(ptr
, nb_items
);
1293 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1294 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1295 i
> 0 ? NULL
: "@proto ");
1297 if (api
->match_src_port_num
)
1298 INCREMENT_DISPLAY(ptr
, nb_items
);
1299 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1300 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1301 i
> 0 ? NULL
: "@srcport ");
1303 if (api
->match_dst_port_num
)
1304 INCREMENT_DISPLAY(ptr
, nb_items
);
1305 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1306 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1307 i
> 0 ? NULL
: "@dstport ");
1309 if (api
->match_port_num
)
1310 INCREMENT_DISPLAY(ptr
, nb_items
);
1311 for (i
= 0; i
< api
->match_port_num
; i
++)
1312 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1313 i
> 0 ? NULL
: "@port ");
1315 if (api
->match_icmp_type_num
)
1316 INCREMENT_DISPLAY(ptr
, nb_items
);
1317 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1318 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1319 i
> 0 ? NULL
: "@icmptype ");
1321 if (api
->match_icmp_code_num
)
1322 INCREMENT_DISPLAY(ptr
, nb_items
);
1323 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1324 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1325 i
> 0 ? NULL
: "@icmpcode ");
1327 if (api
->match_packet_length_num
)
1328 INCREMENT_DISPLAY(ptr
, nb_items
);
1329 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1330 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1331 i
> 0 ? NULL
: "@plen ");
1333 if (api
->match_dscp_num
)
1334 INCREMENT_DISPLAY(ptr
, nb_items
);
1335 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1336 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1337 i
> 0 ? NULL
: "@dscp ");
1339 if (api
->match_tcpflags_num
)
1340 INCREMENT_DISPLAY(ptr
, nb_items
);
1341 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1342 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1343 i
> 0 ? NULL
: "@tcpflags ");
1345 if (api
->match_fragment_num
)
1346 INCREMENT_DISPLAY(ptr
, nb_items
);
1347 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1348 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1349 i
> 0 ? NULL
: "@fragment ");
1351 ptr
= return_string
;
1353 ptr
+= sprintf(ptr
, "; ");
1354 if (api
->action_num
)
1355 ptr
+= sprintf(ptr
, "SET : ");
1357 for (i
= 0; i
< api
->action_num
; i
++) {
1358 switch (api
->actions
[i
].action
) {
1359 case ACTION_TRAFFICRATE
:
1360 INCREMENT_DISPLAY(ptr
, nb_items
);
1361 ptr
+= sprintf(ptr
, "@set rate %f",
1362 api
->actions
[i
].u
.r
.rate
);
1364 case ACTION_TRAFFIC_ACTION
:
1365 INCREMENT_DISPLAY(ptr
, nb_items
);
1366 ptr
+= sprintf(ptr
, "@action ");
1367 if (api
->actions
[i
].u
.za
.filter
1368 & TRAFFIC_ACTION_TERMINATE
)
1370 " terminate (apply filter(s))");
1371 if (api
->actions
[i
].u
.za
.filter
1372 & TRAFFIC_ACTION_DISTRIBUTE
)
1373 ptr
+= sprintf(ptr
, " distribute");
1374 if (api
->actions
[i
].u
.za
.filter
1375 & TRAFFIC_ACTION_SAMPLE
)
1376 ptr
+= sprintf(ptr
, " sample");
1378 case ACTION_REDIRECT_IP
:
1379 INCREMENT_DISPLAY(ptr
, nb_items
);
1380 char local_buff
[INET_ADDRSTRLEN
];
1382 if (inet_ntop(AF_INET
,
1383 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1384 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1386 "@redirect ip nh %s", local_buff
);
1388 case ACTION_REDIRECT
:
1389 INCREMENT_DISPLAY(ptr
, nb_items
);
1390 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1391 api
->actions
[i
].u
.redirect_vrf
);
1393 case ACTION_MARKING
:
1394 INCREMENT_DISPLAY(ptr
, nb_items
);
1395 ptr
+= sprintf(ptr
, "@set dscp %u",
1396 api
->actions
[i
].u
.marking_dscp
);
1402 zlog_info("%s", return_string
);
1405 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1406 struct bgp_pbr_rule
*bpr
)
1408 /* if bpr is null, do nothing
1412 if (bpr
->installed
) {
1413 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1414 bpr
->installed
= false;
1415 bpr
->action
->refcnt
--;
1418 hash_release(bgp
->pbr_rule_hash
, bpr
);
1419 if (bpa
->refcnt
== 0) {
1420 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1421 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1422 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1426 bpa
->installed
= false;
1431 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1432 struct bgp_pbr_match
*bpm
,
1433 struct bgp_pbr_match_entry
*bpme
)
1435 /* if bpme is null, bpm is also null
1439 /* ipset del entry */
1440 if (bpme
->installed
) {
1441 bgp_send_pbr_ipset_entry_match(bpme
, false);
1442 bpme
->installed
= false;
1443 bpme
->backpointer
= NULL
;
1445 struct bgp_path_info
*path
;
1446 struct bgp_path_info_extra
*extra
;
1448 /* unlink bgp_path_info to bpme */
1449 path
= (struct bgp_path_info
*)bpme
->path
;
1450 extra
= bgp_path_info_extra_get(path
);
1451 if (extra
->bgp_fs_pbr
)
1452 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1456 hash_release(bpm
->entry_hash
, bpme
);
1457 if (hashcount(bpm
->entry_hash
) == 0) {
1458 /* delete iptable entry first */
1459 /* then delete ipset match */
1460 if (bpm
->installed
) {
1461 if (bpm
->installed_in_iptable
) {
1462 bgp_send_pbr_iptable(bpm
->action
,
1464 bpm
->installed_in_iptable
= false;
1465 bpm
->action
->refcnt
--;
1467 bgp_send_pbr_ipset_match(bpm
, false);
1468 bpm
->installed
= false;
1471 hash_release(bgp
->pbr_match_hash
, bpm
);
1472 /* XXX release pbr_match_action if not used
1473 * note that drop does not need to call send_pbr_action
1476 if (bpa
->refcnt
== 0) {
1477 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1478 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1479 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1483 bpa
->installed
= false;
1488 struct bgp_pbr_match_entry_remain
{
1489 struct bgp_pbr_match_entry
*bpme_to_match
;
1490 struct bgp_pbr_match_entry
*bpme_found
;
1493 struct bgp_pbr_rule_remain
{
1494 struct bgp_pbr_rule
*bpr_to_match
;
1495 struct bgp_pbr_rule
*bpr_found
;
1498 static int bgp_pbr_get_same_rule(struct hash_backet
*backet
, void *arg
)
1500 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)backet
->data
;
1501 struct bgp_pbr_rule_remain
*ctxt
=
1502 (struct bgp_pbr_rule_remain
*)arg
;
1503 struct bgp_pbr_rule
*r2
;
1505 r2
= ctxt
->bpr_to_match
;
1507 if (r1
->vrf_id
!= r2
->vrf_id
)
1508 return HASHWALK_CONTINUE
;
1510 if (r1
->flags
!= r2
->flags
)
1511 return HASHWALK_CONTINUE
;
1513 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1514 !prefix_same(&r1
->src
, &r2
->src
))
1515 return HASHWALK_CONTINUE
;
1517 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1518 !prefix_same(&r1
->dst
, &r2
->dst
))
1519 return HASHWALK_CONTINUE
;
1521 /* this function is used for two cases:
1522 * - remove an entry upon withdraw request
1523 * (case r2->action is null)
1524 * - replace an old iprule with different action
1525 * (case r2->action is != null)
1526 * the old one is removed after the new one
1527 * this is to avoid disruption in traffic
1529 if (r2
->action
== NULL
||
1530 r1
->action
!= r2
->action
) {
1531 ctxt
->bpr_found
= r1
;
1532 return HASHWALK_ABORT
;
1534 return HASHWALK_CONTINUE
;
1537 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1539 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1540 struct bgp_pbr_match_entry_remain
*bpmer
=
1541 (struct bgp_pbr_match_entry_remain
*)arg
;
1542 struct bgp_pbr_match
*bpm_temp
;
1543 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1545 if (!bpme
->backpointer
||
1546 bpm
== bpme
->backpointer
||
1547 bpme
->backpointer
->action
== bpm
->action
)
1548 return HASHWALK_CONTINUE
;
1549 /* ensure bpm other characteristics are equal */
1550 bpm_temp
= bpme
->backpointer
;
1551 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1552 bpm_temp
->type
!= bpm
->type
||
1553 bpm_temp
->flags
!= bpm
->flags
||
1554 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1555 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1556 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1557 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1558 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1559 bpm_temp
->fragment
!= bpm
->fragment
)
1560 return HASHWALK_CONTINUE
;
1562 /* look for remaining bpme */
1563 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1564 if (!bpmer
->bpme_found
)
1565 return HASHWALK_CONTINUE
;
1566 return HASHWALK_ABORT
;
1569 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1570 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1572 struct bgp_pbr_match temp
;
1573 struct bgp_pbr_match_entry temp2
;
1574 struct bgp_pbr_rule pbr_rule
;
1575 struct bgp_pbr_rule
*bpr
;
1576 struct bgp_pbr_match
*bpm
;
1577 struct bgp_pbr_match_entry
*bpme
;
1578 struct bgp_pbr_match_entry_remain bpmer
;
1579 struct bgp_pbr_range_port
*src_port
;
1580 struct bgp_pbr_range_port
*dst_port
;
1581 struct bgp_pbr_range_port
*pkt_len
;
1582 struct bgp_pbr_rule_remain bprr
;
1586 src_port
= bpf
->src_port
;
1587 dst_port
= bpf
->dst_port
;
1588 pkt_len
= bpf
->pkt_len
;
1590 if (BGP_DEBUG(zebra
, ZEBRA
))
1591 bgp_pbr_dump_entry(bpf
, false);
1593 /* as we don't know information from EC
1594 * look for bpm that have the bpm
1595 * with vrf_id characteristics
1597 memset(&temp2
, 0, sizeof(temp2
));
1598 memset(&temp
, 0, sizeof(temp
));
1600 if (bpf
->type
== BGP_PBR_IPRULE
) {
1601 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1602 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1604 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1605 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1608 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1609 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1612 /* A previous entry may already exist
1613 * flush previous entry if necessary
1615 bprr
.bpr_to_match
= bpr
;
1616 bprr
.bpr_found
= NULL
;
1617 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1618 if (bprr
.bpr_found
) {
1619 static struct bgp_pbr_rule
*local_bpr
;
1620 static struct bgp_pbr_action
*local_bpa
;
1622 local_bpr
= bprr
.bpr_found
;
1623 local_bpa
= local_bpr
->action
;
1624 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1631 temp
.flags
|= MATCH_IP_SRC_SET
;
1632 prefix_copy(&temp2
.src
, bpf
->src
);
1634 temp2
.src
.family
= AF_INET
;
1636 temp
.flags
|= MATCH_IP_DST_SET
;
1637 prefix_copy(&temp2
.dst
, bpf
->dst
);
1639 temp2
.dst
.family
= AF_INET
;
1640 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1641 if (bpf
->protocol
== IPPROTO_ICMP
)
1642 temp
.flags
|= MATCH_ICMP_SET
;
1643 temp
.flags
|= MATCH_PORT_SRC_SET
;
1644 temp2
.src_port_min
= src_port
->min_port
;
1645 if (src_port
->max_port
) {
1646 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1647 temp2
.src_port_max
= src_port
->max_port
;
1650 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1651 if (bpf
->protocol
== IPPROTO_ICMP
)
1652 temp
.flags
|= MATCH_ICMP_SET
;
1653 temp
.flags
|= MATCH_PORT_DST_SET
;
1654 temp2
.dst_port_min
= dst_port
->min_port
;
1655 if (dst_port
->max_port
) {
1656 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1657 temp2
.dst_port_max
= dst_port
->max_port
;
1660 temp2
.proto
= bpf
->protocol
;
1663 temp
.pkt_len_min
= pkt_len
->min_port
;
1664 if (pkt_len
->max_port
)
1665 temp
.pkt_len_max
= pkt_len
->max_port
;
1666 } else if (bpf
->pkt_len_val
) {
1667 if (bpf
->pkt_len_val
->mask
)
1668 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1669 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1671 if (bpf
->tcp_flags
) {
1672 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1673 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1676 if (bpf
->dscp
->mask
)
1677 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1679 temp
.flags
|= MATCH_DSCP_SET
;
1680 temp
.dscp_value
= bpf
->dscp
->val
;
1682 if (bpf
->fragment
) {
1683 if (bpf
->fragment
->mask
)
1684 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1685 temp
.fragment
= bpf
->fragment
->val
;
1688 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1689 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1690 temp
.type
= IPSET_NET_PORT
;
1692 temp
.type
= IPSET_NET
;
1694 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1695 temp
.type
= IPSET_NET_PORT_NET
;
1697 temp
.type
= IPSET_NET_NET
;
1699 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1702 temp
.vrf_id
= bpf
->vrf_id
;
1705 bpme
->backpointer
= bpm
;
1706 /* right now, a previous entry may already exist
1707 * flush previous entry if necessary
1709 bpmer
.bpme_to_match
= bpme
;
1710 bpmer
.bpme_found
= NULL
;
1711 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1712 if (bpmer
.bpme_found
) {
1713 static struct bgp_pbr_match
*local_bpm
;
1714 static struct bgp_pbr_action
*local_bpa
;
1716 local_bpm
= bpmer
.bpme_found
->backpointer
;
1717 local_bpa
= local_bpm
->action
;
1718 bgp_pbr_flush_entry(bgp
, local_bpa
,
1719 local_bpm
, bpmer
.bpme_found
);
1723 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1725 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1726 return FLOWSPEC_DSCP
;
1727 if (type_entry
== FLOWSPEC_DSCP
)
1728 return FLOWSPEC_PKT_LEN
;
1729 if (type_entry
== FLOWSPEC_PKT_LEN
)
1730 return FLOWSPEC_FRAGMENT
;
1731 if (type_entry
== FLOWSPEC_FRAGMENT
)
1732 return FLOWSPEC_ICMP_TYPE
;
1736 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1737 struct bgp_pbr_filter
*bpf
,
1738 struct bgp_pbr_or_filter
*bpof
, bool add
,
1739 struct nexthop
*nh
, float *rate
)
1741 struct bgp_pbr_range_port srcp
, dstp
;
1742 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1743 struct listnode
*tnode
, *cnode
;
1747 if (bpf
->protocol
!= IPPROTO_ICMP
)
1749 bpf
->src_port
= &srcp
;
1750 bpf
->dst_port
= &dstp
;
1751 /* parse icmp type and lookup appropriate icmp code
1752 * if no icmp code found, create as many entryes as
1753 * there are listed icmp codes for that icmp type
1755 if (!bpof
->icmp_type
) {
1757 srcp
.max_port
= 255;
1758 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1759 dstp
.min_port
= icmp_code
->val
;
1761 bgp_pbr_policyroute_add_to_zebra_unit(
1762 bgp
, path
, bpf
, nh
, rate
);
1764 bgp_pbr_policyroute_remove_from_zebra_unit(
1769 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1770 srcp
.min_port
= icmp_type
->val
;
1773 /* only icmp type. create an entry only with icmp type */
1774 if (!bpof
->icmp_code
) {
1775 /* icmp type is not one of the above
1776 * forge an entry only based on the icmp type
1779 dstp
.max_port
= 255;
1781 bgp_pbr_policyroute_add_to_zebra_unit(
1782 bgp
, path
, bpf
, nh
, rate
);
1784 bgp_pbr_policyroute_remove_from_zebra_unit(
1788 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1789 dstp
.min_port
= icmp_code
->val
;
1791 bgp_pbr_policyroute_add_to_zebra_unit(
1792 bgp
, path
, bpf
, nh
, rate
);
1794 bgp_pbr_policyroute_remove_from_zebra_unit(
1800 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1801 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1802 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1804 struct listnode
*node
, *nnode
;
1805 struct bgp_pbr_val_mask
*valmask
;
1806 uint8_t next_type_entry
;
1807 struct list
*orig_list
;
1808 struct bgp_pbr_val_mask
**target_val
;
1810 if (type_entry
== 0) {
1811 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1814 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1815 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1816 orig_list
= bpof
->tcpflags
;
1817 target_val
= &bpf
->tcp_flags
;
1818 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1819 orig_list
= bpof
->dscp
;
1820 target_val
= &bpf
->dscp
;
1821 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1822 orig_list
= bpof
->pkt_len
;
1823 target_val
= &bpf
->pkt_len_val
;
1824 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1825 orig_list
= bpof
->fragment
;
1826 target_val
= &bpf
->fragment
;
1827 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1828 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1829 /* enumerate list for icmp - must be last one */
1830 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1833 bgp_pbr_policyroute_remove_from_zebra_recursive(
1834 bgp
, path
, bpf
, bpof
, next_type_entry
);
1837 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1838 *target_val
= valmask
;
1839 bgp_pbr_policyroute_remove_from_zebra_recursive(
1840 bgp
, path
, bpf
, bpof
, next_type_entry
);
1844 static void bgp_pbr_policyroute_remove_from_zebra(
1845 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1846 struct bgp_pbr_or_filter
*bpof
)
1849 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1853 bgp_pbr_policyroute_remove_from_zebra_recursive(
1854 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1855 else if (bpof
->dscp
)
1856 bgp_pbr_policyroute_remove_from_zebra_recursive(
1857 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1858 else if (bpof
->pkt_len
)
1859 bgp_pbr_policyroute_remove_from_zebra_recursive(
1860 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1861 else if (bpof
->fragment
)
1862 bgp_pbr_policyroute_remove_from_zebra_recursive(
1863 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1864 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1865 bgp_pbr_policyroute_remove_from_zebra_recursive(
1866 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1868 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1871 list_delete_all_node(bpof
->tcpflags
);
1873 list_delete_all_node(bpof
->dscp
);
1875 list_delete_all_node(bpof
->pkt_len
);
1877 list_delete_all_node(bpof
->fragment
);
1880 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1882 struct bgp_pbr_range_port
*src_port
;
1883 struct bgp_pbr_range_port
*dst_port
;
1884 struct bgp_pbr_range_port
*pkt_len
;
1885 char bufsrc
[64], bufdst
[64];
1887 int remaining_len
= 0;
1888 char protocol_str
[16];
1892 src_port
= bpf
->src_port
;
1893 dst_port
= bpf
->dst_port
;
1894 pkt_len
= bpf
->pkt_len
;
1896 protocol_str
[0] = '\0';
1897 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1898 bpf
->protocol
= IPPROTO_TCP
;
1900 snprintf(protocol_str
, sizeof(protocol_str
),
1901 "proto %d", bpf
->protocol
);
1903 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1904 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1907 dst_port
->min_port
);
1908 else if (bpf
->protocol
== IPPROTO_UDP
||
1909 bpf
->protocol
== IPPROTO_TCP
) {
1911 if (src_port
&& src_port
->min_port
)
1912 remaining_len
+= snprintf(buffer
,
1916 src_port
->max_port
?
1917 src_port
->max_port
:
1918 src_port
->min_port
);
1919 if (dst_port
&& dst_port
->min_port
)
1920 remaining_len
+= snprintf(buffer
+
1926 dst_port
->max_port
?
1927 dst_port
->max_port
:
1928 dst_port
->min_port
);
1930 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1931 remaining_len
+= snprintf(buffer
+ remaining_len
,
1939 } else if (bpf
->pkt_len_val
) {
1940 remaining_len
+= snprintf(buffer
+ remaining_len
,
1944 bpf
->pkt_len_val
->mask
1946 bpf
->pkt_len_val
->val
);
1948 if (bpf
->tcp_flags
) {
1949 remaining_len
+= snprintf(buffer
+ remaining_len
,
1953 bpf
->tcp_flags
->val
,
1954 bpf
->tcp_flags
->mask
);
1957 snprintf(buffer
+ remaining_len
,
1965 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1966 add
? "adding" : "removing",
1967 bpf
->src
== NULL
? "<all>" :
1968 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1969 bpf
->dst
== NULL
? "<all>" :
1970 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1971 protocol_str
, buffer
);
1975 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1976 struct bgp_path_info
*path
,
1977 struct bgp_pbr_filter
*bpf
,
1981 struct bgp_pbr_match temp
;
1982 struct bgp_pbr_match_entry temp2
;
1983 struct bgp_pbr_match
*bpm
;
1984 struct bgp_pbr_match_entry
*bpme
= NULL
;
1985 struct bgp_pbr_action temp3
;
1986 struct bgp_pbr_action
*bpa
= NULL
;
1987 struct bgp_pbr_match_entry_remain bpmer
;
1988 struct bgp_pbr_rule_remain bprr
;
1989 struct bgp_pbr_range_port
*src_port
;
1990 struct bgp_pbr_range_port
*dst_port
;
1991 struct bgp_pbr_range_port
*pkt_len
;
1992 struct bgp_pbr_rule pbr_rule
;
1993 struct bgp_pbr_rule
*bpr
;
1994 bool bpme_found
= false;
1998 src_port
= bpf
->src_port
;
1999 dst_port
= bpf
->dst_port
;
2000 pkt_len
= bpf
->pkt_len
;
2002 if (BGP_DEBUG(zebra
, ZEBRA
))
2003 bgp_pbr_dump_entry(bpf
, true);
2005 /* look for bpa first */
2006 memset(&temp3
, 0, sizeof(temp3
));
2010 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2011 temp3
.vrf_id
= bpf
->vrf_id
;
2012 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2013 bgp_pbr_action_alloc_intern
);
2015 if (bpa
->fwmark
== 0) {
2016 /* drop is handled by iptable */
2017 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2019 bpa
->installed
= true;
2021 bpa
->fwmark
= bgp_zebra_tm_get_id();
2022 bpa
->table_id
= bpa
->fwmark
;
2023 bpa
->installed
= false;
2026 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2027 /* 0 value is forbidden */
2028 bpa
->install_in_progress
= false;
2030 if (bpf
->type
== BGP_PBR_IPRULE
) {
2031 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2032 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2034 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2035 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2038 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2039 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2041 pbr_rule
.action
= bpa
;
2042 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2043 bgp_pbr_rule_alloc_intern
);
2044 if (bpr
&& bpr
->unique
== 0) {
2045 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2046 bpr
->installed
= false;
2047 bpr
->install_in_progress
= false;
2049 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2050 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2051 bgp_zebra_announce_default(bgp
, nh
,
2052 AFI_IP
, bpa
->table_id
, true);
2055 if (bpr
&& !bpr
->installed
)
2056 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2058 /* A previous entry may already exist
2059 * flush previous entry if necessary
2061 bprr
.bpr_to_match
= bpr
;
2062 bprr
.bpr_found
= NULL
;
2063 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2064 if (bprr
.bpr_found
) {
2065 static struct bgp_pbr_rule
*local_bpr
;
2066 static struct bgp_pbr_action
*local_bpa
;
2068 local_bpr
= bprr
.bpr_found
;
2069 local_bpa
= local_bpr
->action
;
2070 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2075 /* then look for bpm */
2076 memset(&temp
, 0, sizeof(temp
));
2077 temp
.vrf_id
= bpf
->vrf_id
;
2079 temp
.flags
|= MATCH_IP_SRC_SET
;
2081 temp
.flags
|= MATCH_IP_DST_SET
;
2083 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2084 if (bpf
->protocol
== IPPROTO_ICMP
)
2085 temp
.flags
|= MATCH_ICMP_SET
;
2086 temp
.flags
|= MATCH_PORT_SRC_SET
;
2088 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2089 if (bpf
->protocol
== IPPROTO_ICMP
)
2090 temp
.flags
|= MATCH_ICMP_SET
;
2091 temp
.flags
|= MATCH_PORT_DST_SET
;
2093 if (src_port
&& src_port
->max_port
)
2094 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2095 if (dst_port
&& dst_port
->max_port
)
2096 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2098 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2099 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2100 temp
.type
= IPSET_NET_PORT
;
2102 temp
.type
= IPSET_NET
;
2104 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2105 temp
.type
= IPSET_NET_PORT_NET
;
2107 temp
.type
= IPSET_NET_NET
;
2110 temp
.pkt_len_min
= pkt_len
->min_port
;
2111 if (pkt_len
->max_port
)
2112 temp
.pkt_len_max
= pkt_len
->max_port
;
2113 } else if (bpf
->pkt_len_val
) {
2114 if (bpf
->pkt_len_val
->mask
)
2115 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2116 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2118 if (bpf
->tcp_flags
) {
2119 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2120 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2123 if (bpf
->dscp
->mask
)
2124 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2126 temp
.flags
|= MATCH_DSCP_SET
;
2127 temp
.dscp_value
= bpf
->dscp
->val
;
2129 if (bpf
->fragment
) {
2130 if (bpf
->fragment
->mask
)
2131 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2132 temp
.fragment
= bpf
->fragment
->val
;
2135 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2136 bgp_pbr_match_alloc_intern
);
2138 /* new, then self allocate ipset_name and unique */
2139 if (bpm
->unique
== 0) {
2140 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2141 /* 0 value is forbidden */
2142 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2143 bpm
->entry_hash
= hash_create_size(8,
2144 bgp_pbr_match_entry_hash_key
,
2145 bgp_pbr_match_entry_hash_equal
,
2146 "Match Entry Hash");
2147 bpm
->installed
= false;
2149 /* unique2 should be updated too */
2150 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2151 bpm
->installed_in_iptable
= false;
2152 bpm
->install_in_progress
= false;
2153 bpm
->install_iptable_in_progress
= false;
2156 memset(&temp2
, 0, sizeof(temp2
));
2158 prefix_copy(&temp2
.src
, bpf
->src
);
2160 temp2
.src
.family
= AF_INET
;
2162 prefix_copy(&temp2
.dst
, bpf
->dst
);
2164 temp2
.dst
.family
= AF_INET
;
2165 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2166 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2167 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2168 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2169 temp2
.proto
= bpf
->protocol
;
2170 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2171 bgp_pbr_match_entry_alloc_intern
);
2172 if (bpme
->unique
== 0) {
2173 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2174 /* 0 value is forbidden */
2175 bpme
->backpointer
= bpm
;
2176 bpme
->installed
= false;
2177 bpme
->install_in_progress
= false;
2178 /* link bgp info to bpme */
2179 bpme
->path
= (void *)path
;
2183 /* already installed */
2185 struct bgp_path_info_extra
*extra
=
2186 bgp_path_info_extra_get(path
);
2188 if (extra
&& extra
->bgp_fs_pbr
&&
2189 listnode_lookup(extra
->bgp_fs_pbr
, bpme
)) {
2190 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2192 "%s: entry %p/%p already installed in bgp pbr",
2193 __func__
, path
, bpme
);
2197 /* BGP FS: append entry to zebra
2198 * - policies are not routing entries and as such
2199 * route replace semantics don't necessarily follow
2200 * through to policy entries
2201 * - because of that, not all policing information will be stored
2202 * into zebra. and non selected policies will be suppressed from zebra
2203 * - as consequence, in order to bring consistency
2204 * a policy will be added, then ifan ecmp policy exists,
2205 * it will be suppressed subsequently
2208 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2209 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2210 bgp_zebra_announce_default(bgp
, nh
,
2211 AFI_IP
, bpa
->table_id
, true);
2215 if (!bpm
->installed
)
2216 bgp_send_pbr_ipset_match(bpm
, true);
2218 if (!bpme
->installed
)
2219 bgp_send_pbr_ipset_entry_match(bpme
, true);
2222 if (!bpm
->installed_in_iptable
)
2223 bgp_send_pbr_iptable(bpa
, bpm
, true);
2225 /* A previous entry may already exist
2226 * flush previous entry if necessary
2228 bpmer
.bpme_to_match
= bpme
;
2229 bpmer
.bpme_found
= NULL
;
2230 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2231 if (bpmer
.bpme_found
) {
2232 static struct bgp_pbr_match
*local_bpm
;
2233 static struct bgp_pbr_action
*local_bpa
;
2235 local_bpm
= bpmer
.bpme_found
->backpointer
;
2236 local_bpa
= local_bpm
->action
;
2237 bgp_pbr_flush_entry(bgp
, local_bpa
,
2238 local_bpm
, bpmer
.bpme_found
);
2244 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2245 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2246 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2249 struct listnode
*node
, *nnode
;
2250 struct bgp_pbr_val_mask
*valmask
;
2251 uint8_t next_type_entry
;
2252 struct list
*orig_list
;
2253 struct bgp_pbr_val_mask
**target_val
;
2255 if (type_entry
== 0) {
2256 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2259 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2260 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2261 orig_list
= bpof
->tcpflags
;
2262 target_val
= &bpf
->tcp_flags
;
2263 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2264 orig_list
= bpof
->dscp
;
2265 target_val
= &bpf
->dscp
;
2266 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2267 orig_list
= bpof
->pkt_len
;
2268 target_val
= &bpf
->pkt_len_val
;
2269 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2270 orig_list
= bpof
->fragment
;
2271 target_val
= &bpf
->fragment
;
2272 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2273 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2274 /* enumerate list for icmp - must be last one */
2275 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2278 bgp_pbr_policyroute_add_to_zebra_recursive(
2279 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2282 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2283 *target_val
= valmask
;
2284 bgp_pbr_policyroute_add_to_zebra_recursive(
2285 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2289 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2290 struct bgp_path_info
*path
,
2291 struct bgp_pbr_filter
*bpf
,
2292 struct bgp_pbr_or_filter
*bpof
,
2293 struct nexthop
*nh
, float *rate
)
2296 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2300 bgp_pbr_policyroute_add_to_zebra_recursive(
2301 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2302 else if (bpof
->dscp
)
2303 bgp_pbr_policyroute_add_to_zebra_recursive(
2304 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2305 else if (bpof
->pkt_len
)
2306 bgp_pbr_policyroute_add_to_zebra_recursive(
2307 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2308 else if (bpof
->fragment
)
2309 bgp_pbr_policyroute_add_to_zebra_recursive(
2310 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2311 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2312 bgp_pbr_policyroute_add_to_zebra_recursive(
2313 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2315 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2318 list_delete_all_node(bpof
->tcpflags
);
2320 list_delete_all_node(bpof
->dscp
);
2322 list_delete_all_node(bpof
->pkt_len
);
2324 list_delete_all_node(bpof
->fragment
);
2325 if (bpof
->icmp_type
)
2326 list_delete_all_node(bpof
->icmp_type
);
2327 if (bpof
->icmp_code
)
2328 list_delete_all_node(bpof
->icmp_code
);
2331 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2332 struct bgp_pbr_entry_main
*api
, bool add
)
2336 int continue_loop
= 1;
2338 struct prefix
*src
= NULL
, *dst
= NULL
;
2340 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2341 struct bgp_pbr_range_port range
, range_icmp_code
;
2342 struct bgp_pbr_range_port pkt_len
;
2343 struct bgp_pbr_filter bpf
;
2345 struct bgp_pbr_or_filter bpof
;
2346 struct bgp_pbr_val_mask bpvm
;
2348 memset(&nh
, 0, sizeof(struct nexthop
));
2349 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2350 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2351 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2352 (api
->type
== BGP_PBR_IPRULE
&&
2353 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2354 src
= &api
->src_prefix
;
2355 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2356 (api
->type
== BGP_PBR_IPRULE
&&
2357 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2358 dst
= &api
->dst_prefix
;
2359 if (api
->type
== BGP_PBR_IPRULE
)
2360 bpf
.type
= api
->type
;
2361 memset(&nh
, 0, sizeof(struct nexthop
));
2362 nh
.vrf_id
= VRF_UNKNOWN
;
2363 if (api
->match_protocol_num
)
2364 proto
= (uint8_t)api
->protocol
[0].value
;
2365 /* if match_port is selected, then either src or dst port will be parsed
2366 * but not both at the same time
2368 if (api
->match_port_num
>= 1) {
2369 bgp_pbr_extract(api
->port
,
2370 api
->match_port_num
,
2372 srcp
= dstp
= &range
;
2373 } else if (api
->match_src_port_num
>= 1) {
2374 bgp_pbr_extract(api
->src_port
,
2375 api
->match_src_port_num
,
2379 } else if (api
->match_dst_port_num
>= 1) {
2380 bgp_pbr_extract(api
->dst_port
,
2381 api
->match_dst_port_num
,
2386 if (api
->match_icmp_type_num
>= 1) {
2387 proto
= IPPROTO_ICMP
;
2388 if (bgp_pbr_extract(api
->icmp_type
,
2389 api
->match_icmp_type_num
,
2393 bpof
.icmp_type
= list_new();
2394 bgp_pbr_extract_enumerate(api
->icmp_type
,
2395 api
->match_icmp_type_num
,
2398 FLOWSPEC_ICMP_TYPE
);
2401 if (api
->match_icmp_code_num
>= 1) {
2402 proto
= IPPROTO_ICMP
;
2403 if (bgp_pbr_extract(api
->icmp_code
,
2404 api
->match_icmp_code_num
,
2406 dstp
= &range_icmp_code
;
2408 bpof
.icmp_code
= list_new();
2409 bgp_pbr_extract_enumerate(api
->icmp_code
,
2410 api
->match_icmp_code_num
,
2413 FLOWSPEC_ICMP_CODE
);
2417 if (api
->match_tcpflags_num
) {
2418 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2419 api
->match_tcpflags_num
);
2420 if (kind_enum
== OPERATOR_UNARY_AND
) {
2421 bpf
.tcp_flags
= &bpvm
;
2422 bgp_pbr_extract_enumerate(api
->tcpflags
,
2423 api
->match_tcpflags_num
,
2426 FLOWSPEC_TCP_FLAGS
);
2427 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2428 bpof
.tcpflags
= list_new();
2429 bgp_pbr_extract_enumerate(api
->tcpflags
,
2430 api
->match_tcpflags_num
,
2433 FLOWSPEC_TCP_FLAGS
);
2436 if (api
->match_packet_length_num
) {
2439 ret
= bgp_pbr_extract(api
->packet_length
,
2440 api
->match_packet_length_num
,
2443 bpf
.pkt_len
= &pkt_len
;
2445 bpof
.pkt_len
= list_new();
2446 bgp_pbr_extract_enumerate(api
->packet_length
,
2447 api
->match_packet_length_num
,
2453 if (api
->match_dscp_num
>= 1) {
2454 bpof
.dscp
= list_new();
2455 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2457 bpof
.dscp
, FLOWSPEC_DSCP
);
2459 if (api
->match_fragment_num
) {
2460 bpof
.fragment
= list_new();
2461 bgp_pbr_extract_enumerate(api
->fragment
,
2462 api
->match_fragment_num
,
2467 bpf
.vrf_id
= api
->vrf_id
;
2470 bpf
.protocol
= proto
;
2471 bpf
.src_port
= srcp
;
2472 bpf
.dst_port
= dstp
;
2474 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2477 /* no action for add = true */
2478 for (i
= 0; i
< api
->action_num
; i
++) {
2479 switch (api
->actions
[i
].action
) {
2480 case ACTION_TRAFFICRATE
:
2482 if (api
->actions
[i
].u
.r
.rate
== 0) {
2483 nh
.vrf_id
= api
->vrf_id
;
2484 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2485 bgp_pbr_policyroute_add_to_zebra(
2486 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2488 /* update rate. can be reentrant */
2489 rate
= api
->actions
[i
].u
.r
.rate
;
2490 if (BGP_DEBUG(pbr
, PBR
)) {
2491 bgp_pbr_print_policy_route(api
);
2492 zlog_warn("PBR: ignoring Set action rate %f",
2493 api
->actions
[i
].u
.r
.rate
);
2497 case ACTION_TRAFFIC_ACTION
:
2498 if (api
->actions
[i
].u
.za
.filter
2499 & TRAFFIC_ACTION_SAMPLE
) {
2500 if (BGP_DEBUG(pbr
, PBR
)) {
2501 bgp_pbr_print_policy_route(api
);
2502 zlog_warn("PBR: Sample action Ignored");
2506 if (api
->actions
[i
].u
.za
.filter
2507 & TRAFFIC_ACTION_DISTRIBUTE
) {
2508 if (BGP_DEBUG(pbr
, PBR
)) {
2509 bgp_pbr_print_policy_route(api
);
2510 zlog_warn("PBR: Distribute action Applies");
2513 /* continue forwarding entry as before
2517 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2518 /* terminate action: run other filters
2521 case ACTION_REDIRECT_IP
:
2522 nh
.type
= NEXTHOP_TYPE_IPV4
;
2523 nh
.gate
.ipv4
.s_addr
=
2524 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2525 nh
.vrf_id
= api
->vrf_id
;
2526 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2528 /* XXX combination with REDIRECT_VRF
2529 * + REDIRECT_NH_IP not done
2533 case ACTION_REDIRECT
:
2534 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2535 nh
.type
= NEXTHOP_TYPE_IPV4
;
2536 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2540 case ACTION_MARKING
:
2541 if (BGP_DEBUG(pbr
, PBR
)) {
2542 bgp_pbr_print_policy_route(api
);
2543 zlog_warn("PBR: Set DSCP %u Ignored",
2544 api
->actions
[i
].u
.marking_dscp
);
2550 if (continue_loop
== 0)
2555 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2556 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2559 struct bgp_pbr_entry_main api
;
2562 return; /* IPv6 not supported */
2563 if (safi
!= SAFI_FLOWSPEC
)
2564 return; /* not supported */
2565 /* Make Zebra API structure. */
2566 memset(&api
, 0, sizeof(api
));
2567 api
.vrf_id
= bgp
->vrf_id
;
2570 if (!bgp_zebra_tm_chunk_obtained()) {
2571 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2572 flog_err(EC_BGP_TABLE_CHUNK
,
2573 "%s: table chunk not obtained yet", __func__
);
2577 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2578 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2579 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2580 "%s: cancel updating entry %p in bgp pbr",
2584 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2587 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2588 const struct bgp_pbr_interface
*b
)
2590 return strcmp(a
->name
, b
->name
);
2593 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2594 struct bgp_pbr_interface_head
*head
)
2596 struct bgp_pbr_interface pbr_if
;
2598 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2599 return (RB_FIND(bgp_pbr_interface_head
,
2603 /* this function resets to the default policy routing
2604 * go back to default status
2606 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2608 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2609 struct bgp_pbr_interface_head
*head
;
2610 struct bgp_pbr_interface
*pbr_if
;
2612 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2614 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2616 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2617 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2618 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2619 XFREE(MTYPE_TMP
, pbr_if
);