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_bucket
*bucket
, void *arg
)
77 struct bgp_pbr_rule
*bpr
= (struct bgp_pbr_rule
*)bucket
->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_bucket
*bucket
, void *arg
)
91 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)bucket
->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_bucket
*bucket
, void *arg
)
105 struct bgp_pbr_match_entry
*bpme
=
106 (struct bgp_pbr_match_entry
*)bucket
->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_bucket
*bucket
, void *arg
)
125 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->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_bucket
*bucket
, void *arg
)
140 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->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_bucket
*bucket
, void *arg
)
159 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->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
&& 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 &&
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
;
701 bool discard_action_found
= false;
703 /* extract match from flowspec entries */
704 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
705 p
->u
.prefix_flowspec
.prefixlen
, api
);
708 /* extract actiosn from flowspec ecom list */
709 if (path
&& path
->attr
->ecommunity
) {
710 ecom
= path
->attr
->ecommunity
;
711 for (i
= 0; i
< ecom
->size
; i
++) {
712 ecom_eval
= (struct ecommunity_val
*)
713 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
715 if (action_count
> ACTIONS_MAX_NUM
) {
716 if (BGP_DEBUG(pbr
, PBR_ERROR
))
718 EC_BGP_FLOWSPEC_PACKET
,
719 "%s: flowspec actions exceeds limit (max %u)",
720 __func__
, action_count
);
723 api_action
= &api
->actions
[action_count
- 1];
725 if ((ecom_eval
->val
[1] ==
726 (char)ECOMMUNITY_REDIRECT_VRF
) &&
727 (ecom_eval
->val
[0] ==
728 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
730 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
732 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
733 struct ecommunity
*eckey
= ecommunity_new();
734 struct ecommunity_val ecom_copy
;
736 memcpy(&ecom_copy
, ecom_eval
,
737 sizeof(struct ecommunity_val
));
739 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
740 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
741 ecommunity_add_val(eckey
, &ecom_copy
);
743 api_action
->action
= ACTION_REDIRECT
;
744 api_action
->u
.redirect_vrf
=
745 get_first_vrf_for_redirect_with_rt(
747 ecommunity_free(&eckey
);
748 } else if ((ecom_eval
->val
[0] ==
749 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
750 (ecom_eval
->val
[1] ==
751 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
752 /* in case the 2 ecom present,
754 * draft-ietf-idr-flowspec-redirect
756 if (api_action_redirect_ip
) {
757 if (api_action_redirect_ip
->u
.zr
758 .redirect_ip_v4
.s_addr
761 if (path
->attr
->nexthop
.s_addr
764 api_action_redirect_ip
->u
.zr
765 .redirect_ip_v4
.s_addr
=
766 path
->attr
->nexthop
.s_addr
;
767 api_action_redirect_ip
->u
.zr
.duplicate
771 api_action
->action
= ACTION_REDIRECT_IP
;
772 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
773 path
->attr
->nexthop
.s_addr
;
774 api_action
->u
.zr
.duplicate
=
776 api_action_redirect_ip
= api_action
;
778 } else if ((ecom_eval
->val
[0] ==
779 (char)ECOMMUNITY_ENCODE_IP
) &&
780 (ecom_eval
->val
[1] ==
781 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
782 /* in case the 2 ecom present,
783 * overwrite simpson draft
784 * update redirect ip fields
786 if (api_action_redirect_ip
) {
787 memcpy(&(api_action_redirect_ip
->u
788 .zr
.redirect_ip_v4
.s_addr
),
789 (ecom_eval
->val
+2), 4);
790 api_action_redirect_ip
->u
795 api_action
->action
= ACTION_REDIRECT_IP
;
796 memcpy(&(api_action
->u
797 .zr
.redirect_ip_v4
.s_addr
),
798 (ecom_eval
->val
+2), 4);
799 api_action
->u
.zr
.duplicate
=
801 api_action_redirect_ip
= api_action
;
804 if (ecom_eval
->val
[0] !=
805 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
807 ret
= ecommunity_fill_pbr_action(ecom_eval
,
811 if ((api_action
->action
== ACTION_TRAFFICRATE
) &&
812 api
->actions
[i
].u
.r
.rate
== 0)
813 discard_action_found
= true;
818 /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
819 * then reduce the API action list to that action
821 if (api
->action_num
> 1 && discard_action_found
) {
823 memset(&api
->actions
[0], 0,
824 sizeof(struct bgp_pbr_entry_action
));
825 api
->actions
[0].action
= ACTION_TRAFFICRATE
;
828 /* validate if incoming matc/action is compatible
829 * with our policy routing engine
831 if (!bgp_pbr_validate_policy_route(api
))
834 /* check inconsistency in the match rule */
835 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
836 src
= &api
->src_prefix
;
837 afi
= family2afi(src
->family
);
840 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
841 dst
= &api
->dst_prefix
;
842 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
843 if (BGP_DEBUG(pbr
, PBR
)) {
844 bgp_pbr_print_policy_route(api
);
845 zlog_debug("%s: inconsistency:"
846 " no match for afi src and dst (%u/%u)",
847 __func__
, afi
, family2afi(dst
->family
));
855 static void bgp_pbr_match_entry_free(void *arg
)
857 struct bgp_pbr_match_entry
*bpme
;
859 bpme
= (struct bgp_pbr_match_entry
*)arg
;
861 if (bpme
->installed
) {
862 bgp_send_pbr_ipset_entry_match(bpme
, false);
863 bpme
->installed
= false;
864 bpme
->backpointer
= NULL
;
866 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
869 static void bgp_pbr_match_free(void *arg
)
871 struct bgp_pbr_match
*bpm
;
873 bpm
= (struct bgp_pbr_match
*)arg
;
875 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
877 if (hashcount(bpm
->entry_hash
) == 0) {
878 /* delete iptable entry first */
879 /* then delete ipset match */
880 if (bpm
->installed
) {
881 if (bpm
->installed_in_iptable
) {
882 bgp_send_pbr_iptable(bpm
->action
,
884 bpm
->installed_in_iptable
= false;
885 bpm
->action
->refcnt
--;
887 bgp_send_pbr_ipset_match(bpm
, false);
888 bpm
->installed
= false;
892 hash_free(bpm
->entry_hash
);
894 XFREE(MTYPE_PBR_MATCH
, bpm
);
897 static void *bgp_pbr_match_alloc_intern(void *arg
)
899 struct bgp_pbr_match
*bpm
, *new;
901 bpm
= (struct bgp_pbr_match
*)arg
;
903 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
904 memcpy(new, bpm
, sizeof(*bpm
));
909 static void bgp_pbr_rule_free(void *arg
)
911 struct bgp_pbr_rule
*bpr
;
913 bpr
= (struct bgp_pbr_rule
*)arg
;
916 if (bpr
->installed
) {
917 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
918 bpr
->installed
= false;
919 bpr
->action
->refcnt
--;
922 XFREE(MTYPE_PBR_RULE
, bpr
);
925 static void *bgp_pbr_rule_alloc_intern(void *arg
)
927 struct bgp_pbr_rule
*bpr
, *new;
929 bpr
= (struct bgp_pbr_rule
*)arg
;
931 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
932 memcpy(new, bpr
, sizeof(*bpr
));
937 static void bgp_pbr_action_free(void *arg
)
939 struct bgp_pbr_action
*bpa
;
941 bpa
= (struct bgp_pbr_action
*)arg
;
943 if (bpa
->refcnt
== 0) {
944 if (bpa
->installed
&& bpa
->table_id
!= 0) {
945 bgp_send_pbr_rule_action(bpa
, NULL
, false);
946 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
950 bpa
->installed
= false;
953 XFREE(MTYPE_PBR_ACTION
, bpa
);
956 static void *bgp_pbr_action_alloc_intern(void *arg
)
958 struct bgp_pbr_action
*bpa
, *new;
960 bpa
= (struct bgp_pbr_action
*)arg
;
962 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
964 memcpy(new, bpa
, sizeof(*bpa
));
969 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
971 struct bgp_pbr_match_entry
*bpme
, *new;
973 bpme
= (struct bgp_pbr_match_entry
*)arg
;
975 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
977 memcpy(new, bpme
, sizeof(*bpme
));
982 uint32_t bgp_pbr_match_hash_key(const void *arg
)
984 const struct bgp_pbr_match
*pbm
= arg
;
987 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
988 key
= jhash_1word(pbm
->flags
, key
);
989 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
990 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
991 key
= jhash(&pbm
->tcp_flags
, 2, key
);
992 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
993 key
= jhash(&pbm
->dscp_value
, 1, key
);
994 key
= jhash(&pbm
->fragment
, 1, key
);
995 key
= jhash(&pbm
->protocol
, 1, key
);
996 return jhash_1word(pbm
->type
, key
);
999 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
1001 const struct bgp_pbr_match
*r1
, *r2
;
1003 r1
= (const struct bgp_pbr_match
*)arg1
;
1004 r2
= (const struct bgp_pbr_match
*)arg2
;
1006 if (r1
->vrf_id
!= r2
->vrf_id
)
1009 if (r1
->type
!= r2
->type
)
1012 if (r1
->flags
!= r2
->flags
)
1015 if (r1
->action
!= r2
->action
)
1018 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1021 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1024 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1027 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1030 if (r1
->dscp_value
!= r2
->dscp_value
)
1033 if (r1
->fragment
!= r2
->fragment
)
1036 if (r1
->protocol
!= r2
->protocol
)
1041 uint32_t bgp_pbr_rule_hash_key(const void *arg
)
1043 const struct bgp_pbr_rule
*pbr
= arg
;
1046 key
= prefix_hash_key(&pbr
->src
);
1047 key
= jhash_1word(pbr
->vrf_id
, key
);
1048 key
= jhash_1word(pbr
->flags
, key
);
1049 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1052 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1054 const struct bgp_pbr_rule
*r1
, *r2
;
1056 r1
= (const struct bgp_pbr_rule
*)arg1
;
1057 r2
= (const struct bgp_pbr_rule
*)arg2
;
1059 if (r1
->vrf_id
!= r2
->vrf_id
)
1062 if (r1
->flags
!= r2
->flags
)
1065 if (r1
->action
!= r2
->action
)
1068 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1069 !prefix_same(&r1
->src
, &r2
->src
))
1072 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1073 !prefix_same(&r1
->dst
, &r2
->dst
))
1079 uint32_t bgp_pbr_match_entry_hash_key(const void *arg
)
1081 const struct bgp_pbr_match_entry
*pbme
;
1085 key
= prefix_hash_key(&pbme
->src
);
1086 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1087 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1088 key
= jhash(&pbme
->src_port_min
, 2, key
);
1089 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1090 key
= jhash(&pbme
->src_port_max
, 2, key
);
1091 key
= jhash(&pbme
->proto
, 1, key
);
1096 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1098 const struct bgp_pbr_match_entry
*r1
, *r2
;
1100 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1101 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1104 * on updates, comparing backpointer is not necessary
1105 * unique value is self calculated
1106 * rate is ignored for now
1109 if (!prefix_same(&r1
->src
, &r2
->src
))
1112 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1115 if (r1
->src_port_min
!= r2
->src_port_min
)
1118 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1121 if (r1
->src_port_max
!= r2
->src_port_max
)
1124 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1127 if (r1
->proto
!= r2
->proto
)
1133 uint32_t bgp_pbr_action_hash_key(const void *arg
)
1135 const struct bgp_pbr_action
*pbra
;
1139 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1140 key
= jhash_1word(pbra
->fwmark
, key
);
1144 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1146 const struct bgp_pbr_action
*r1
, *r2
;
1148 r1
= (const struct bgp_pbr_action
*)arg1
;
1149 r2
= (const struct bgp_pbr_action
*)arg2
;
1151 /* unique value is self calculated
1152 * table and fwmark is self calculated
1155 if (r1
->vrf_id
!= r2
->vrf_id
)
1158 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1164 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1167 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1168 struct bgp_pbr_rule_unique bpru
;
1170 if (!bgp
|| unique
== 0)
1172 bpru
.unique
= unique
;
1173 bpru
.bpr_found
= NULL
;
1174 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1175 return bpru
.bpr_found
;
1178 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1181 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1182 struct bgp_pbr_action_unique bpau
;
1184 if (!bgp
|| unique
== 0)
1186 bpau
.unique
= unique
;
1187 bpau
.bpa_found
= NULL
;
1188 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1189 return bpau
.bpa_found
;
1192 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1195 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1196 struct bgp_pbr_match_unique bpmu
;
1198 if (!bgp
|| unique
== 0)
1200 bpmu
.unique
= unique
;
1201 bpmu
.bpm_found
= NULL
;
1202 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1203 return bpmu
.bpm_found
;
1206 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1210 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1211 struct bgp_pbr_match_entry_unique bpmeu
;
1212 struct bgp_pbr_match_ipsetname bpmi
;
1214 if (!bgp
|| unique
== 0)
1216 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1217 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1218 bpmi
.bpm_found
= NULL
;
1219 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1220 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1221 if (!bpmi
.bpm_found
)
1223 bpmeu
.bpme_found
= NULL
;
1224 bpmeu
.unique
= unique
;
1225 hash_walk(bpmi
.bpm_found
->entry_hash
,
1226 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1227 return bpmeu
.bpme_found
;
1230 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1233 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1234 struct bgp_pbr_match_iptable_unique bpmiu
;
1236 if (!bgp
|| unique
== 0)
1238 bpmiu
.unique
= unique
;
1239 bpmiu
.bpm_found
= NULL
;
1240 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1241 return bpmiu
.bpm_found
;
1244 void bgp_pbr_cleanup(struct bgp
*bgp
)
1246 if (bgp
->pbr_match_hash
) {
1247 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1248 hash_free(bgp
->pbr_match_hash
);
1249 bgp
->pbr_match_hash
= NULL
;
1251 if (bgp
->pbr_rule_hash
) {
1252 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1253 hash_free(bgp
->pbr_rule_hash
);
1254 bgp
->pbr_rule_hash
= NULL
;
1256 if (bgp
->pbr_action_hash
) {
1257 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1258 hash_free(bgp
->pbr_action_hash
);
1259 bgp
->pbr_action_hash
= NULL
;
1261 if (bgp
->bgp_pbr_cfg
== NULL
)
1263 bgp_pbr_reset(bgp
, AFI_IP
);
1264 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1267 void bgp_pbr_init(struct bgp
*bgp
)
1269 bgp
->pbr_match_hash
=
1270 hash_create_size(8, bgp_pbr_match_hash_key
,
1271 bgp_pbr_match_hash_equal
,
1273 bgp
->pbr_action_hash
=
1274 hash_create_size(8, bgp_pbr_action_hash_key
,
1275 bgp_pbr_action_hash_equal
,
1276 "Match Hash Entry");
1278 bgp
->pbr_rule_hash
=
1279 hash_create_size(8, bgp_pbr_rule_hash_key
,
1280 bgp_pbr_rule_hash_equal
,
1283 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1284 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1287 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1290 char return_string
[512];
1291 char *ptr
= return_string
;
1295 ptr
+= sprintf(ptr
, "MATCH : ");
1296 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1297 struct prefix
*p
= &(api
->src_prefix
);
1299 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1300 INCREMENT_DISPLAY(ptr
, nb_items
);
1302 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1303 struct prefix
*p
= &(api
->dst_prefix
);
1305 INCREMENT_DISPLAY(ptr
, nb_items
);
1306 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1309 if (api
->match_protocol_num
)
1310 INCREMENT_DISPLAY(ptr
, nb_items
);
1311 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1312 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1313 i
> 0 ? NULL
: "@proto ");
1315 if (api
->match_src_port_num
)
1316 INCREMENT_DISPLAY(ptr
, nb_items
);
1317 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1318 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1319 i
> 0 ? NULL
: "@srcport ");
1321 if (api
->match_dst_port_num
)
1322 INCREMENT_DISPLAY(ptr
, nb_items
);
1323 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1324 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1325 i
> 0 ? NULL
: "@dstport ");
1327 if (api
->match_port_num
)
1328 INCREMENT_DISPLAY(ptr
, nb_items
);
1329 for (i
= 0; i
< api
->match_port_num
; i
++)
1330 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1331 i
> 0 ? NULL
: "@port ");
1333 if (api
->match_icmp_type_num
)
1334 INCREMENT_DISPLAY(ptr
, nb_items
);
1335 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1336 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1337 i
> 0 ? NULL
: "@icmptype ");
1339 if (api
->match_icmp_code_num
)
1340 INCREMENT_DISPLAY(ptr
, nb_items
);
1341 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1342 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1343 i
> 0 ? NULL
: "@icmpcode ");
1345 if (api
->match_packet_length_num
)
1346 INCREMENT_DISPLAY(ptr
, nb_items
);
1347 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1348 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1349 i
> 0 ? NULL
: "@plen ");
1351 if (api
->match_dscp_num
)
1352 INCREMENT_DISPLAY(ptr
, nb_items
);
1353 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1354 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1355 i
> 0 ? NULL
: "@dscp ");
1357 if (api
->match_tcpflags_num
)
1358 INCREMENT_DISPLAY(ptr
, nb_items
);
1359 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1360 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1361 i
> 0 ? NULL
: "@tcpflags ");
1363 if (api
->match_fragment_num
)
1364 INCREMENT_DISPLAY(ptr
, nb_items
);
1365 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1366 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1367 i
> 0 ? NULL
: "@fragment ");
1369 ptr
= return_string
;
1371 ptr
+= sprintf(ptr
, "; ");
1372 if (api
->action_num
)
1373 ptr
+= sprintf(ptr
, "SET : ");
1375 for (i
= 0; i
< api
->action_num
; i
++) {
1376 switch (api
->actions
[i
].action
) {
1377 case ACTION_TRAFFICRATE
:
1378 INCREMENT_DISPLAY(ptr
, nb_items
);
1379 ptr
+= sprintf(ptr
, "@set rate %f",
1380 api
->actions
[i
].u
.r
.rate
);
1382 case ACTION_TRAFFIC_ACTION
:
1383 INCREMENT_DISPLAY(ptr
, nb_items
);
1384 ptr
+= sprintf(ptr
, "@action ");
1385 if (api
->actions
[i
].u
.za
.filter
1386 & TRAFFIC_ACTION_TERMINATE
)
1388 " terminate (apply filter(s))");
1389 if (api
->actions
[i
].u
.za
.filter
1390 & TRAFFIC_ACTION_DISTRIBUTE
)
1391 ptr
+= sprintf(ptr
, " distribute");
1392 if (api
->actions
[i
].u
.za
.filter
1393 & TRAFFIC_ACTION_SAMPLE
)
1394 ptr
+= sprintf(ptr
, " sample");
1396 case ACTION_REDIRECT_IP
:
1397 INCREMENT_DISPLAY(ptr
, nb_items
);
1398 char local_buff
[INET_ADDRSTRLEN
];
1400 if (inet_ntop(AF_INET
,
1401 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1402 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1404 "@redirect ip nh %s", local_buff
);
1406 case ACTION_REDIRECT
:
1407 INCREMENT_DISPLAY(ptr
, nb_items
);
1408 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1409 api
->actions
[i
].u
.redirect_vrf
);
1411 case ACTION_MARKING
:
1412 INCREMENT_DISPLAY(ptr
, nb_items
);
1413 ptr
+= sprintf(ptr
, "@set dscp %u",
1414 api
->actions
[i
].u
.marking_dscp
);
1420 zlog_info("%s", return_string
);
1423 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1424 struct bgp_pbr_rule
*bpr
)
1426 /* if bpr is null, do nothing
1430 if (bpr
->installed
) {
1431 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1432 bpr
->installed
= false;
1433 bpr
->action
->refcnt
--;
1436 struct bgp_path_info
*path
;
1437 struct bgp_path_info_extra
*extra
;
1439 /* unlink path to bpme */
1440 path
= (struct bgp_path_info
*)bpr
->path
;
1441 extra
= bgp_path_info_extra_get(path
);
1442 if (extra
->bgp_fs_iprule
)
1443 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1447 hash_release(bgp
->pbr_rule_hash
, bpr
);
1448 if (bpa
->refcnt
== 0) {
1449 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1450 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1451 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1455 bpa
->installed
= false;
1460 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1461 struct bgp_pbr_match
*bpm
,
1462 struct bgp_pbr_match_entry
*bpme
)
1464 /* if bpme is null, bpm is also null
1468 /* ipset del entry */
1469 if (bpme
->installed
) {
1470 bgp_send_pbr_ipset_entry_match(bpme
, false);
1471 bpme
->installed
= false;
1472 bpme
->backpointer
= NULL
;
1474 struct bgp_path_info
*path
;
1475 struct bgp_path_info_extra
*extra
;
1477 /* unlink path to bpme */
1478 path
= (struct bgp_path_info
*)bpme
->path
;
1479 extra
= bgp_path_info_extra_get(path
);
1480 if (extra
->bgp_fs_pbr
)
1481 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1485 hash_release(bpm
->entry_hash
, bpme
);
1486 if (hashcount(bpm
->entry_hash
) == 0) {
1487 /* delete iptable entry first */
1488 /* then delete ipset match */
1489 if (bpm
->installed
) {
1490 if (bpm
->installed_in_iptable
) {
1491 bgp_send_pbr_iptable(bpm
->action
,
1493 bpm
->installed_in_iptable
= false;
1494 bpm
->action
->refcnt
--;
1496 bgp_send_pbr_ipset_match(bpm
, false);
1497 bpm
->installed
= false;
1500 hash_release(bgp
->pbr_match_hash
, bpm
);
1501 /* XXX release pbr_match_action if not used
1502 * note that drop does not need to call send_pbr_action
1505 if (bpa
->refcnt
== 0) {
1506 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1507 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1508 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1512 bpa
->installed
= false;
1517 struct bgp_pbr_match_entry_remain
{
1518 struct bgp_pbr_match_entry
*bpme_to_match
;
1519 struct bgp_pbr_match_entry
*bpme_found
;
1522 struct bgp_pbr_rule_remain
{
1523 struct bgp_pbr_rule
*bpr_to_match
;
1524 struct bgp_pbr_rule
*bpr_found
;
1527 static int bgp_pbr_get_same_rule(struct hash_bucket
*bucket
, void *arg
)
1529 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)bucket
->data
;
1530 struct bgp_pbr_rule_remain
*ctxt
=
1531 (struct bgp_pbr_rule_remain
*)arg
;
1532 struct bgp_pbr_rule
*r2
;
1534 r2
= ctxt
->bpr_to_match
;
1536 if (r1
->vrf_id
!= r2
->vrf_id
)
1537 return HASHWALK_CONTINUE
;
1539 if (r1
->flags
!= r2
->flags
)
1540 return HASHWALK_CONTINUE
;
1542 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1543 !prefix_same(&r1
->src
, &r2
->src
))
1544 return HASHWALK_CONTINUE
;
1546 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1547 !prefix_same(&r1
->dst
, &r2
->dst
))
1548 return HASHWALK_CONTINUE
;
1550 /* this function is used for two cases:
1551 * - remove an entry upon withdraw request
1552 * (case r2->action is null)
1553 * - replace an old iprule with different action
1554 * (case r2->action is != null)
1555 * the old one is removed after the new one
1556 * this is to avoid disruption in traffic
1558 if (r2
->action
== NULL
||
1559 r1
->action
!= r2
->action
) {
1560 ctxt
->bpr_found
= r1
;
1561 return HASHWALK_ABORT
;
1563 return HASHWALK_CONTINUE
;
1566 static int bgp_pbr_get_remaining_entry(struct hash_bucket
*bucket
, void *arg
)
1568 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
1569 struct bgp_pbr_match_entry_remain
*bpmer
=
1570 (struct bgp_pbr_match_entry_remain
*)arg
;
1571 struct bgp_pbr_match
*bpm_temp
;
1572 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1574 if (!bpme
->backpointer
||
1575 bpm
== bpme
->backpointer
||
1576 bpme
->backpointer
->action
== bpm
->action
)
1577 return HASHWALK_CONTINUE
;
1578 /* ensure bpm other characteristics are equal */
1579 bpm_temp
= bpme
->backpointer
;
1580 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1581 bpm_temp
->type
!= bpm
->type
||
1582 bpm_temp
->flags
!= bpm
->flags
||
1583 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1584 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1585 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1586 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1587 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1588 bpm_temp
->fragment
!= bpm
->fragment
)
1589 return HASHWALK_CONTINUE
;
1591 /* look for remaining bpme */
1592 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1593 if (!bpmer
->bpme_found
)
1594 return HASHWALK_CONTINUE
;
1595 return HASHWALK_ABORT
;
1598 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1599 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1601 struct bgp_pbr_match temp
;
1602 struct bgp_pbr_match_entry temp2
;
1603 struct bgp_pbr_rule pbr_rule
;
1604 struct bgp_pbr_rule
*bpr
;
1605 struct bgp_pbr_match
*bpm
;
1606 struct bgp_pbr_match_entry
*bpme
;
1607 struct bgp_pbr_match_entry_remain bpmer
;
1608 struct bgp_pbr_range_port
*src_port
;
1609 struct bgp_pbr_range_port
*dst_port
;
1610 struct bgp_pbr_range_port
*pkt_len
;
1611 struct bgp_pbr_rule_remain bprr
;
1615 src_port
= bpf
->src_port
;
1616 dst_port
= bpf
->dst_port
;
1617 pkt_len
= bpf
->pkt_len
;
1619 if (BGP_DEBUG(zebra
, ZEBRA
))
1620 bgp_pbr_dump_entry(bpf
, false);
1622 /* as we don't know information from EC
1623 * look for bpm that have the bpm
1624 * with vrf_id characteristics
1626 memset(&temp2
, 0, sizeof(temp2
));
1627 memset(&temp
, 0, sizeof(temp
));
1629 if (bpf
->type
== BGP_PBR_IPRULE
) {
1630 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1631 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1633 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1634 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1637 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1638 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1641 /* A previous entry may already exist
1642 * flush previous entry if necessary
1644 bprr
.bpr_to_match
= bpr
;
1645 bprr
.bpr_found
= NULL
;
1646 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1647 if (bprr
.bpr_found
) {
1648 static struct bgp_pbr_rule
*local_bpr
;
1649 static struct bgp_pbr_action
*local_bpa
;
1651 local_bpr
= bprr
.bpr_found
;
1652 local_bpa
= local_bpr
->action
;
1653 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1660 temp
.flags
|= MATCH_IP_SRC_SET
;
1661 prefix_copy(&temp2
.src
, bpf
->src
);
1663 temp2
.src
.family
= AF_INET
;
1665 temp
.flags
|= MATCH_IP_DST_SET
;
1666 prefix_copy(&temp2
.dst
, bpf
->dst
);
1668 temp2
.dst
.family
= AF_INET
;
1669 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1670 if (bpf
->protocol
== IPPROTO_ICMP
)
1671 temp
.flags
|= MATCH_ICMP_SET
;
1672 temp
.flags
|= MATCH_PORT_SRC_SET
;
1673 temp2
.src_port_min
= src_port
->min_port
;
1674 if (src_port
->max_port
) {
1675 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1676 temp2
.src_port_max
= src_port
->max_port
;
1679 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1680 if (bpf
->protocol
== IPPROTO_ICMP
)
1681 temp
.flags
|= MATCH_ICMP_SET
;
1682 temp
.flags
|= MATCH_PORT_DST_SET
;
1683 temp2
.dst_port_min
= dst_port
->min_port
;
1684 if (dst_port
->max_port
) {
1685 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1686 temp2
.dst_port_max
= dst_port
->max_port
;
1689 temp2
.proto
= bpf
->protocol
;
1692 temp
.pkt_len_min
= pkt_len
->min_port
;
1693 if (pkt_len
->max_port
)
1694 temp
.pkt_len_max
= pkt_len
->max_port
;
1695 } else if (bpf
->pkt_len_val
) {
1696 if (bpf
->pkt_len_val
->mask
)
1697 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1698 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1700 if (bpf
->tcp_flags
) {
1701 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1702 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1705 if (bpf
->dscp
->mask
)
1706 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1708 temp
.flags
|= MATCH_DSCP_SET
;
1709 temp
.dscp_value
= bpf
->dscp
->val
;
1711 if (bpf
->fragment
) {
1712 if (bpf
->fragment
->mask
)
1713 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1714 temp
.fragment
= bpf
->fragment
->val
;
1717 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1718 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1719 temp
.type
= IPSET_NET_PORT
;
1721 temp
.type
= IPSET_NET
;
1723 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1724 temp
.type
= IPSET_NET_PORT_NET
;
1726 temp
.type
= IPSET_NET_NET
;
1728 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1729 temp
.vrf_id
= VRF_DEFAULT
;
1731 temp
.vrf_id
= bpf
->vrf_id
;
1734 bpme
->backpointer
= bpm
;
1735 /* right now, a previous entry may already exist
1736 * flush previous entry if necessary
1738 bpmer
.bpme_to_match
= bpme
;
1739 bpmer
.bpme_found
= NULL
;
1740 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1741 if (bpmer
.bpme_found
) {
1742 static struct bgp_pbr_match
*local_bpm
;
1743 static struct bgp_pbr_action
*local_bpa
;
1745 local_bpm
= bpmer
.bpme_found
->backpointer
;
1746 local_bpa
= local_bpm
->action
;
1747 bgp_pbr_flush_entry(bgp
, local_bpa
,
1748 local_bpm
, bpmer
.bpme_found
);
1752 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1754 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1755 return FLOWSPEC_DSCP
;
1756 if (type_entry
== FLOWSPEC_DSCP
)
1757 return FLOWSPEC_PKT_LEN
;
1758 if (type_entry
== FLOWSPEC_PKT_LEN
)
1759 return FLOWSPEC_FRAGMENT
;
1760 if (type_entry
== FLOWSPEC_FRAGMENT
)
1761 return FLOWSPEC_ICMP_TYPE
;
1765 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1766 struct bgp_pbr_filter
*bpf
,
1767 struct bgp_pbr_or_filter
*bpof
, bool add
,
1768 struct nexthop
*nh
, float *rate
)
1770 struct bgp_pbr_range_port srcp
, dstp
;
1771 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1772 struct listnode
*tnode
, *cnode
;
1776 if (bpf
->protocol
!= IPPROTO_ICMP
)
1778 bpf
->src_port
= &srcp
;
1779 bpf
->dst_port
= &dstp
;
1780 /* parse icmp type and lookup appropriate icmp code
1781 * if no icmp code found, create as many entryes as
1782 * there are listed icmp codes for that icmp type
1784 if (!bpof
->icmp_type
) {
1786 srcp
.max_port
= 255;
1787 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1788 dstp
.min_port
= icmp_code
->val
;
1790 bgp_pbr_policyroute_add_to_zebra_unit(
1791 bgp
, path
, bpf
, nh
, rate
);
1793 bgp_pbr_policyroute_remove_from_zebra_unit(
1798 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1799 srcp
.min_port
= icmp_type
->val
;
1802 /* only icmp type. create an entry only with icmp type */
1803 if (!bpof
->icmp_code
) {
1804 /* icmp type is not one of the above
1805 * forge an entry only based on the icmp type
1808 dstp
.max_port
= 255;
1810 bgp_pbr_policyroute_add_to_zebra_unit(
1811 bgp
, path
, bpf
, nh
, rate
);
1813 bgp_pbr_policyroute_remove_from_zebra_unit(
1817 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1818 dstp
.min_port
= icmp_code
->val
;
1820 bgp_pbr_policyroute_add_to_zebra_unit(
1821 bgp
, path
, bpf
, nh
, rate
);
1823 bgp_pbr_policyroute_remove_from_zebra_unit(
1829 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1830 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1831 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1833 struct listnode
*node
, *nnode
;
1834 struct bgp_pbr_val_mask
*valmask
;
1835 uint8_t next_type_entry
;
1836 struct list
*orig_list
;
1837 struct bgp_pbr_val_mask
**target_val
;
1839 if (type_entry
== 0) {
1840 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1843 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1844 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1845 orig_list
= bpof
->tcpflags
;
1846 target_val
= &bpf
->tcp_flags
;
1847 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1848 orig_list
= bpof
->dscp
;
1849 target_val
= &bpf
->dscp
;
1850 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1851 orig_list
= bpof
->pkt_len
;
1852 target_val
= &bpf
->pkt_len_val
;
1853 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1854 orig_list
= bpof
->fragment
;
1855 target_val
= &bpf
->fragment
;
1856 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1857 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1858 /* enumerate list for icmp - must be last one */
1859 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1862 bgp_pbr_policyroute_remove_from_zebra_recursive(
1863 bgp
, path
, bpf
, bpof
, next_type_entry
);
1866 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1867 *target_val
= valmask
;
1868 bgp_pbr_policyroute_remove_from_zebra_recursive(
1869 bgp
, path
, bpf
, bpof
, next_type_entry
);
1873 static void bgp_pbr_policyroute_remove_from_zebra(
1874 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1875 struct bgp_pbr_or_filter
*bpof
)
1878 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1882 bgp_pbr_policyroute_remove_from_zebra_recursive(
1883 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1884 else if (bpof
->dscp
)
1885 bgp_pbr_policyroute_remove_from_zebra_recursive(
1886 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1887 else if (bpof
->pkt_len
)
1888 bgp_pbr_policyroute_remove_from_zebra_recursive(
1889 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1890 else if (bpof
->fragment
)
1891 bgp_pbr_policyroute_remove_from_zebra_recursive(
1892 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1893 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1894 bgp_pbr_policyroute_remove_from_zebra_recursive(
1895 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1897 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1900 list_delete_all_node(bpof
->tcpflags
);
1902 list_delete_all_node(bpof
->dscp
);
1904 list_delete_all_node(bpof
->pkt_len
);
1906 list_delete_all_node(bpof
->fragment
);
1909 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1911 struct bgp_pbr_range_port
*src_port
;
1912 struct bgp_pbr_range_port
*dst_port
;
1913 struct bgp_pbr_range_port
*pkt_len
;
1914 char bufsrc
[64], bufdst
[64];
1916 int remaining_len
= 0;
1917 char protocol_str
[16];
1921 src_port
= bpf
->src_port
;
1922 dst_port
= bpf
->dst_port
;
1923 pkt_len
= bpf
->pkt_len
;
1925 protocol_str
[0] = '\0';
1926 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1927 bpf
->protocol
= IPPROTO_TCP
;
1929 snprintf(protocol_str
, sizeof(protocol_str
),
1930 "proto %d", bpf
->protocol
);
1932 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1933 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1936 dst_port
->min_port
);
1937 else if (bpf
->protocol
== IPPROTO_UDP
||
1938 bpf
->protocol
== IPPROTO_TCP
) {
1940 if (src_port
&& src_port
->min_port
)
1941 remaining_len
+= snprintf(buffer
,
1945 src_port
->max_port
?
1946 src_port
->max_port
:
1947 src_port
->min_port
);
1948 if (dst_port
&& dst_port
->min_port
)
1949 remaining_len
+= snprintf(buffer
+
1955 dst_port
->max_port
?
1956 dst_port
->max_port
:
1957 dst_port
->min_port
);
1959 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1960 remaining_len
+= snprintf(buffer
+ remaining_len
,
1968 } else if (bpf
->pkt_len_val
) {
1969 remaining_len
+= snprintf(buffer
+ remaining_len
,
1973 bpf
->pkt_len_val
->mask
1975 bpf
->pkt_len_val
->val
);
1977 if (bpf
->tcp_flags
) {
1978 remaining_len
+= snprintf(buffer
+ remaining_len
,
1982 bpf
->tcp_flags
->val
,
1983 bpf
->tcp_flags
->mask
);
1986 snprintf(buffer
+ remaining_len
,
1994 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1995 add
? "adding" : "removing",
1996 bpf
->src
== NULL
? "<all>" :
1997 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1998 bpf
->dst
== NULL
? "<all>" :
1999 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
2000 protocol_str
, buffer
);
2004 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
2005 struct bgp_path_info
*path
,
2006 struct bgp_pbr_filter
*bpf
,
2010 struct bgp_pbr_match temp
;
2011 struct bgp_pbr_match_entry temp2
;
2012 struct bgp_pbr_match
*bpm
;
2013 struct bgp_pbr_match_entry
*bpme
= NULL
;
2014 struct bgp_pbr_action temp3
;
2015 struct bgp_pbr_action
*bpa
= NULL
;
2016 struct bgp_pbr_match_entry_remain bpmer
;
2017 struct bgp_pbr_rule_remain bprr
;
2018 struct bgp_pbr_range_port
*src_port
;
2019 struct bgp_pbr_range_port
*dst_port
;
2020 struct bgp_pbr_range_port
*pkt_len
;
2021 struct bgp_pbr_rule pbr_rule
;
2022 struct bgp_pbr_rule
*bpr
;
2023 bool bpr_found
= false;
2024 bool bpme_found
= false;
2028 src_port
= bpf
->src_port
;
2029 dst_port
= bpf
->dst_port
;
2030 pkt_len
= bpf
->pkt_len
;
2032 if (BGP_DEBUG(zebra
, ZEBRA
))
2033 bgp_pbr_dump_entry(bpf
, true);
2035 /* look for bpa first */
2036 memset(&temp3
, 0, sizeof(temp3
));
2040 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2041 temp3
.vrf_id
= bpf
->vrf_id
;
2042 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2043 bgp_pbr_action_alloc_intern
);
2045 if (bpa
->fwmark
== 0) {
2046 /* drop is handled by iptable */
2047 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2049 bpa
->installed
= true;
2051 bpa
->fwmark
= bgp_zebra_tm_get_id();
2052 bpa
->table_id
= bpa
->fwmark
;
2053 bpa
->installed
= false;
2056 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2057 /* 0 value is forbidden */
2058 bpa
->install_in_progress
= false;
2060 if (bpf
->type
== BGP_PBR_IPRULE
) {
2061 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2062 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2063 pbr_rule
.priority
= 20;
2065 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2066 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2069 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2070 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2072 pbr_rule
.action
= bpa
;
2073 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2074 bgp_pbr_rule_alloc_intern
);
2075 if (bpr
&& bpr
->unique
== 0) {
2076 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2077 bpr
->installed
= false;
2078 bpr
->install_in_progress
= false;
2079 /* link bgp info to bpr */
2080 bpr
->path
= (void *)path
;
2083 /* already installed */
2084 if (bpr_found
&& bpr
) {
2085 struct bgp_path_info_extra
*extra
=
2086 bgp_path_info_extra_get(path
);
2089 listnode_lookup_nocheck(extra
->bgp_fs_iprule
,
2091 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2092 zlog_err("%s: entry %p/%p already "
2093 "installed in bgp pbr iprule",
2094 __func__
, path
, bpr
);
2098 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2099 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2100 bgp_zebra_announce_default(bgp
, nh
,
2101 AFI_IP
, bpa
->table_id
, true);
2104 if (bpr
&& !bpr
->installed
)
2105 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2107 /* A previous entry may already exist
2108 * flush previous entry if necessary
2110 bprr
.bpr_to_match
= bpr
;
2111 bprr
.bpr_found
= NULL
;
2112 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2113 if (bprr
.bpr_found
) {
2114 static struct bgp_pbr_rule
*local_bpr
;
2115 static struct bgp_pbr_action
*local_bpa
;
2117 local_bpr
= bprr
.bpr_found
;
2118 local_bpa
= local_bpr
->action
;
2119 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2124 /* then look for bpm */
2125 memset(&temp
, 0, sizeof(temp
));
2126 temp
.vrf_id
= bpf
->vrf_id
;
2128 temp
.flags
|= MATCH_IP_SRC_SET
;
2130 temp
.flags
|= MATCH_IP_DST_SET
;
2132 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2133 if (bpf
->protocol
== IPPROTO_ICMP
)
2134 temp
.flags
|= MATCH_ICMP_SET
;
2135 temp
.flags
|= MATCH_PORT_SRC_SET
;
2137 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2138 if (bpf
->protocol
== IPPROTO_ICMP
)
2139 temp
.flags
|= MATCH_ICMP_SET
;
2140 temp
.flags
|= MATCH_PORT_DST_SET
;
2142 if (src_port
&& src_port
->max_port
)
2143 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2144 if (dst_port
&& dst_port
->max_port
)
2145 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2147 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2148 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2149 temp
.type
= IPSET_NET_PORT
;
2151 temp
.type
= IPSET_NET
;
2153 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2154 temp
.type
= IPSET_NET_PORT_NET
;
2156 temp
.type
= IPSET_NET_NET
;
2159 temp
.pkt_len_min
= pkt_len
->min_port
;
2160 if (pkt_len
->max_port
)
2161 temp
.pkt_len_max
= pkt_len
->max_port
;
2162 } else if (bpf
->pkt_len_val
) {
2163 if (bpf
->pkt_len_val
->mask
)
2164 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2165 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2167 if (bpf
->tcp_flags
) {
2168 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2169 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2172 if (bpf
->dscp
->mask
)
2173 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2175 temp
.flags
|= MATCH_DSCP_SET
;
2176 temp
.dscp_value
= bpf
->dscp
->val
;
2178 if (bpf
->fragment
) {
2179 if (bpf
->fragment
->mask
)
2180 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2181 temp
.fragment
= bpf
->fragment
->val
;
2183 if (bpf
->protocol
) {
2184 temp
.protocol
= bpf
->protocol
;
2185 temp
.flags
|= MATCH_PROTOCOL_SET
;
2188 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2189 bgp_pbr_match_alloc_intern
);
2191 /* new, then self allocate ipset_name and unique */
2192 if (bpm
->unique
== 0) {
2193 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2194 /* 0 value is forbidden */
2195 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2196 bpm
->entry_hash
= hash_create_size(8,
2197 bgp_pbr_match_entry_hash_key
,
2198 bgp_pbr_match_entry_hash_equal
,
2199 "Match Entry Hash");
2200 bpm
->installed
= false;
2202 /* unique2 should be updated too */
2203 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2204 bpm
->installed_in_iptable
= false;
2205 bpm
->install_in_progress
= false;
2206 bpm
->install_iptable_in_progress
= false;
2209 memset(&temp2
, 0, sizeof(temp2
));
2211 prefix_copy(&temp2
.src
, bpf
->src
);
2213 temp2
.src
.family
= AF_INET
;
2215 prefix_copy(&temp2
.dst
, bpf
->dst
);
2217 temp2
.dst
.family
= AF_INET
;
2218 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2219 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2220 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2221 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2222 temp2
.proto
= bpf
->protocol
;
2223 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2224 bgp_pbr_match_entry_alloc_intern
);
2225 if (bpme
->unique
== 0) {
2226 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2227 /* 0 value is forbidden */
2228 bpme
->backpointer
= bpm
;
2229 bpme
->installed
= false;
2230 bpme
->install_in_progress
= false;
2231 /* link bgp info to bpme */
2232 bpme
->path
= (void *)path
;
2236 /* already installed */
2238 struct bgp_path_info_extra
*extra
=
2239 bgp_path_info_extra_get(path
);
2242 listnode_lookup_nocheck(extra
->bgp_fs_pbr
, bpme
)) {
2243 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2245 "%s: entry %p/%p already installed in bgp pbr",
2246 __func__
, path
, bpme
);
2250 /* BGP FS: append entry to zebra
2251 * - policies are not routing entries and as such
2252 * route replace semantics don't necessarily follow
2253 * through to policy entries
2254 * - because of that, not all policing information will be stored
2255 * into zebra. and non selected policies will be suppressed from zebra
2256 * - as consequence, in order to bring consistency
2257 * a policy will be added, then ifan ecmp policy exists,
2258 * it will be suppressed subsequently
2261 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2262 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2263 bgp_zebra_announce_default(bgp
, nh
,
2264 AFI_IP
, bpa
->table_id
, true);
2268 if (!bpm
->installed
)
2269 bgp_send_pbr_ipset_match(bpm
, true);
2271 if (!bpme
->installed
)
2272 bgp_send_pbr_ipset_entry_match(bpme
, true);
2275 if (!bpm
->installed_in_iptable
)
2276 bgp_send_pbr_iptable(bpa
, bpm
, true);
2278 /* A previous entry may already exist
2279 * flush previous entry if necessary
2281 bpmer
.bpme_to_match
= bpme
;
2282 bpmer
.bpme_found
= NULL
;
2283 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2284 if (bpmer
.bpme_found
) {
2285 static struct bgp_pbr_match
*local_bpm
;
2286 static struct bgp_pbr_action
*local_bpa
;
2288 local_bpm
= bpmer
.bpme_found
->backpointer
;
2289 local_bpa
= local_bpm
->action
;
2290 bgp_pbr_flush_entry(bgp
, local_bpa
,
2291 local_bpm
, bpmer
.bpme_found
);
2297 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2298 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2299 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2302 struct listnode
*node
, *nnode
;
2303 struct bgp_pbr_val_mask
*valmask
;
2304 uint8_t next_type_entry
;
2305 struct list
*orig_list
;
2306 struct bgp_pbr_val_mask
**target_val
;
2308 if (type_entry
== 0) {
2309 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2312 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2313 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2314 orig_list
= bpof
->tcpflags
;
2315 target_val
= &bpf
->tcp_flags
;
2316 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2317 orig_list
= bpof
->dscp
;
2318 target_val
= &bpf
->dscp
;
2319 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2320 orig_list
= bpof
->pkt_len
;
2321 target_val
= &bpf
->pkt_len_val
;
2322 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2323 orig_list
= bpof
->fragment
;
2324 target_val
= &bpf
->fragment
;
2325 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2326 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2327 /* enumerate list for icmp - must be last one */
2328 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2331 bgp_pbr_policyroute_add_to_zebra_recursive(
2332 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2335 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2336 *target_val
= valmask
;
2337 bgp_pbr_policyroute_add_to_zebra_recursive(
2338 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2342 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2343 struct bgp_path_info
*path
,
2344 struct bgp_pbr_filter
*bpf
,
2345 struct bgp_pbr_or_filter
*bpof
,
2346 struct nexthop
*nh
, float *rate
)
2349 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2353 bgp_pbr_policyroute_add_to_zebra_recursive(
2354 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2355 else if (bpof
->dscp
)
2356 bgp_pbr_policyroute_add_to_zebra_recursive(
2357 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2358 else if (bpof
->pkt_len
)
2359 bgp_pbr_policyroute_add_to_zebra_recursive(
2360 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2361 else if (bpof
->fragment
)
2362 bgp_pbr_policyroute_add_to_zebra_recursive(
2363 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2364 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2365 bgp_pbr_policyroute_add_to_zebra_recursive(
2366 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2368 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2371 list_delete_all_node(bpof
->tcpflags
);
2373 list_delete_all_node(bpof
->dscp
);
2375 list_delete_all_node(bpof
->pkt_len
);
2377 list_delete_all_node(bpof
->fragment
);
2378 if (bpof
->icmp_type
)
2379 list_delete_all_node(bpof
->icmp_type
);
2380 if (bpof
->icmp_code
)
2381 list_delete_all_node(bpof
->icmp_code
);
2384 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2385 struct bgp_pbr_entry_main
*api
, bool add
)
2389 int continue_loop
= 1;
2391 struct prefix
*src
= NULL
, *dst
= NULL
;
2393 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2394 struct bgp_pbr_range_port range
, range_icmp_code
;
2395 struct bgp_pbr_range_port pkt_len
;
2396 struct bgp_pbr_filter bpf
;
2398 struct bgp_pbr_or_filter bpof
;
2399 struct bgp_pbr_val_mask bpvm
;
2401 memset(&nh
, 0, sizeof(struct nexthop
));
2402 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2403 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2404 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2405 (api
->type
== BGP_PBR_IPRULE
&&
2406 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2407 src
= &api
->src_prefix
;
2408 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2409 (api
->type
== BGP_PBR_IPRULE
&&
2410 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2411 dst
= &api
->dst_prefix
;
2412 if (api
->type
== BGP_PBR_IPRULE
)
2413 bpf
.type
= api
->type
;
2414 memset(&nh
, 0, sizeof(struct nexthop
));
2415 nh
.vrf_id
= VRF_UNKNOWN
;
2416 if (api
->match_protocol_num
)
2417 proto
= (uint8_t)api
->protocol
[0].value
;
2418 /* if match_port is selected, then either src or dst port will be parsed
2419 * but not both at the same time
2421 if (api
->match_port_num
>= 1) {
2422 bgp_pbr_extract(api
->port
,
2423 api
->match_port_num
,
2425 srcp
= dstp
= &range
;
2426 } else if (api
->match_src_port_num
>= 1) {
2427 bgp_pbr_extract(api
->src_port
,
2428 api
->match_src_port_num
,
2432 } else if (api
->match_dst_port_num
>= 1) {
2433 bgp_pbr_extract(api
->dst_port
,
2434 api
->match_dst_port_num
,
2439 if (api
->match_icmp_type_num
>= 1) {
2440 proto
= IPPROTO_ICMP
;
2441 if (bgp_pbr_extract(api
->icmp_type
,
2442 api
->match_icmp_type_num
,
2446 bpof
.icmp_type
= list_new();
2447 bgp_pbr_extract_enumerate(api
->icmp_type
,
2448 api
->match_icmp_type_num
,
2451 FLOWSPEC_ICMP_TYPE
);
2454 if (api
->match_icmp_code_num
>= 1) {
2455 proto
= IPPROTO_ICMP
;
2456 if (bgp_pbr_extract(api
->icmp_code
,
2457 api
->match_icmp_code_num
,
2459 dstp
= &range_icmp_code
;
2461 bpof
.icmp_code
= list_new();
2462 bgp_pbr_extract_enumerate(api
->icmp_code
,
2463 api
->match_icmp_code_num
,
2466 FLOWSPEC_ICMP_CODE
);
2470 if (api
->match_tcpflags_num
) {
2471 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2472 api
->match_tcpflags_num
);
2473 if (kind_enum
== OPERATOR_UNARY_AND
) {
2474 bpf
.tcp_flags
= &bpvm
;
2475 bgp_pbr_extract_enumerate(api
->tcpflags
,
2476 api
->match_tcpflags_num
,
2479 FLOWSPEC_TCP_FLAGS
);
2480 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2481 bpof
.tcpflags
= list_new();
2482 bgp_pbr_extract_enumerate(api
->tcpflags
,
2483 api
->match_tcpflags_num
,
2486 FLOWSPEC_TCP_FLAGS
);
2489 if (api
->match_packet_length_num
) {
2492 ret
= bgp_pbr_extract(api
->packet_length
,
2493 api
->match_packet_length_num
,
2496 bpf
.pkt_len
= &pkt_len
;
2498 bpof
.pkt_len
= list_new();
2499 bgp_pbr_extract_enumerate(api
->packet_length
,
2500 api
->match_packet_length_num
,
2506 if (api
->match_dscp_num
>= 1) {
2507 bpof
.dscp
= list_new();
2508 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2510 bpof
.dscp
, FLOWSPEC_DSCP
);
2512 if (api
->match_fragment_num
) {
2513 bpof
.fragment
= list_new();
2514 bgp_pbr_extract_enumerate(api
->fragment
,
2515 api
->match_fragment_num
,
2520 bpf
.vrf_id
= api
->vrf_id
;
2523 bpf
.protocol
= proto
;
2524 bpf
.src_port
= srcp
;
2525 bpf
.dst_port
= dstp
;
2527 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2530 /* no action for add = true */
2531 for (i
= 0; i
< api
->action_num
; i
++) {
2532 switch (api
->actions
[i
].action
) {
2533 case ACTION_TRAFFICRATE
:
2535 if (api
->actions
[i
].u
.r
.rate
== 0) {
2536 nh
.vrf_id
= api
->vrf_id
;
2537 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2538 bgp_pbr_policyroute_add_to_zebra(
2539 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2541 /* update rate. can be reentrant */
2542 rate
= api
->actions
[i
].u
.r
.rate
;
2543 if (BGP_DEBUG(pbr
, PBR
)) {
2544 bgp_pbr_print_policy_route(api
);
2545 zlog_warn("PBR: ignoring Set action rate %f",
2546 api
->actions
[i
].u
.r
.rate
);
2550 case ACTION_TRAFFIC_ACTION
:
2551 if (api
->actions
[i
].u
.za
.filter
2552 & TRAFFIC_ACTION_SAMPLE
) {
2553 if (BGP_DEBUG(pbr
, PBR
)) {
2554 bgp_pbr_print_policy_route(api
);
2555 zlog_warn("PBR: Sample action Ignored");
2559 if (api
->actions
[i
].u
.za
.filter
2560 & TRAFFIC_ACTION_DISTRIBUTE
) {
2561 if (BGP_DEBUG(pbr
, PBR
)) {
2562 bgp_pbr_print_policy_route(api
);
2563 zlog_warn("PBR: Distribute action Applies");
2566 /* continue forwarding entry as before
2570 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2571 /* terminate action: run other filters
2574 case ACTION_REDIRECT_IP
:
2575 nh
.type
= NEXTHOP_TYPE_IPV4
;
2576 nh
.gate
.ipv4
.s_addr
=
2577 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2578 nh
.vrf_id
= api
->vrf_id
;
2579 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2581 /* XXX combination with REDIRECT_VRF
2582 * + REDIRECT_NH_IP not done
2586 case ACTION_REDIRECT
:
2587 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2588 nh
.type
= NEXTHOP_TYPE_IPV4
;
2589 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2593 case ACTION_MARKING
:
2594 if (BGP_DEBUG(pbr
, PBR
)) {
2595 bgp_pbr_print_policy_route(api
);
2596 zlog_warn("PBR: Set DSCP %u Ignored",
2597 api
->actions
[i
].u
.marking_dscp
);
2603 if (continue_loop
== 0)
2608 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2609 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2612 struct bgp_pbr_entry_main api
;
2615 return; /* IPv6 not supported */
2616 if (safi
!= SAFI_FLOWSPEC
)
2617 return; /* not supported */
2618 /* Make Zebra API structure. */
2619 memset(&api
, 0, sizeof(api
));
2620 api
.vrf_id
= bgp
->vrf_id
;
2623 if (!bgp_zebra_tm_chunk_obtained()) {
2624 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2625 flog_err(EC_BGP_TABLE_CHUNK
,
2626 "%s: table chunk not obtained yet", __func__
);
2630 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2631 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2632 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2633 "%s: cancel updating entry %p in bgp pbr",
2637 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2640 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2641 const struct bgp_pbr_interface
*b
)
2643 return strcmp(a
->name
, b
->name
);
2646 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2647 struct bgp_pbr_interface_head
*head
)
2649 struct bgp_pbr_interface pbr_if
;
2651 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2652 return (RB_FIND(bgp_pbr_interface_head
,
2656 /* this function resets to the default policy routing
2657 * go back to default status
2659 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2661 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2662 struct bgp_pbr_interface_head
*head
;
2663 struct bgp_pbr_interface
*pbr_if
;
2665 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2667 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2669 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2670 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2671 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2672 XFREE(MTYPE_TMP
, pbr_if
);