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
;
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 struct bgp_path_info
*path
;
1419 struct bgp_path_info_extra
*extra
;
1421 /* unlink path to bpme */
1422 path
= (struct bgp_path_info
*)bpr
->path
;
1423 extra
= bgp_path_info_extra_get(path
);
1424 if (extra
->bgp_fs_iprule
)
1425 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1429 hash_release(bgp
->pbr_rule_hash
, bpr
);
1430 if (bpa
->refcnt
== 0) {
1431 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1432 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1433 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1437 bpa
->installed
= false;
1442 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1443 struct bgp_pbr_match
*bpm
,
1444 struct bgp_pbr_match_entry
*bpme
)
1446 /* if bpme is null, bpm is also null
1450 /* ipset del entry */
1451 if (bpme
->installed
) {
1452 bgp_send_pbr_ipset_entry_match(bpme
, false);
1453 bpme
->installed
= false;
1454 bpme
->backpointer
= NULL
;
1456 struct bgp_path_info
*path
;
1457 struct bgp_path_info_extra
*extra
;
1459 /* unlink path to bpme */
1460 path
= (struct bgp_path_info
*)bpme
->path
;
1461 extra
= bgp_path_info_extra_get(path
);
1462 if (extra
->bgp_fs_pbr
)
1463 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1467 hash_release(bpm
->entry_hash
, bpme
);
1468 if (hashcount(bpm
->entry_hash
) == 0) {
1469 /* delete iptable entry first */
1470 /* then delete ipset match */
1471 if (bpm
->installed
) {
1472 if (bpm
->installed_in_iptable
) {
1473 bgp_send_pbr_iptable(bpm
->action
,
1475 bpm
->installed_in_iptable
= false;
1476 bpm
->action
->refcnt
--;
1478 bgp_send_pbr_ipset_match(bpm
, false);
1479 bpm
->installed
= false;
1482 hash_release(bgp
->pbr_match_hash
, bpm
);
1483 /* XXX release pbr_match_action if not used
1484 * note that drop does not need to call send_pbr_action
1487 if (bpa
->refcnt
== 0) {
1488 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1489 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1490 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1494 bpa
->installed
= false;
1499 struct bgp_pbr_match_entry_remain
{
1500 struct bgp_pbr_match_entry
*bpme_to_match
;
1501 struct bgp_pbr_match_entry
*bpme_found
;
1504 struct bgp_pbr_rule_remain
{
1505 struct bgp_pbr_rule
*bpr_to_match
;
1506 struct bgp_pbr_rule
*bpr_found
;
1509 static int bgp_pbr_get_same_rule(struct hash_bucket
*bucket
, void *arg
)
1511 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)bucket
->data
;
1512 struct bgp_pbr_rule_remain
*ctxt
=
1513 (struct bgp_pbr_rule_remain
*)arg
;
1514 struct bgp_pbr_rule
*r2
;
1516 r2
= ctxt
->bpr_to_match
;
1518 if (r1
->vrf_id
!= r2
->vrf_id
)
1519 return HASHWALK_CONTINUE
;
1521 if (r1
->flags
!= r2
->flags
)
1522 return HASHWALK_CONTINUE
;
1524 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1525 !prefix_same(&r1
->src
, &r2
->src
))
1526 return HASHWALK_CONTINUE
;
1528 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1529 !prefix_same(&r1
->dst
, &r2
->dst
))
1530 return HASHWALK_CONTINUE
;
1532 /* this function is used for two cases:
1533 * - remove an entry upon withdraw request
1534 * (case r2->action is null)
1535 * - replace an old iprule with different action
1536 * (case r2->action is != null)
1537 * the old one is removed after the new one
1538 * this is to avoid disruption in traffic
1540 if (r2
->action
== NULL
||
1541 r1
->action
!= r2
->action
) {
1542 ctxt
->bpr_found
= r1
;
1543 return HASHWALK_ABORT
;
1545 return HASHWALK_CONTINUE
;
1548 static int bgp_pbr_get_remaining_entry(struct hash_bucket
*bucket
, void *arg
)
1550 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
1551 struct bgp_pbr_match_entry_remain
*bpmer
=
1552 (struct bgp_pbr_match_entry_remain
*)arg
;
1553 struct bgp_pbr_match
*bpm_temp
;
1554 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1556 if (!bpme
->backpointer
||
1557 bpm
== bpme
->backpointer
||
1558 bpme
->backpointer
->action
== bpm
->action
)
1559 return HASHWALK_CONTINUE
;
1560 /* ensure bpm other characteristics are equal */
1561 bpm_temp
= bpme
->backpointer
;
1562 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1563 bpm_temp
->type
!= bpm
->type
||
1564 bpm_temp
->flags
!= bpm
->flags
||
1565 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1566 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1567 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1568 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1569 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1570 bpm_temp
->fragment
!= bpm
->fragment
)
1571 return HASHWALK_CONTINUE
;
1573 /* look for remaining bpme */
1574 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1575 if (!bpmer
->bpme_found
)
1576 return HASHWALK_CONTINUE
;
1577 return HASHWALK_ABORT
;
1580 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1581 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1583 struct bgp_pbr_match temp
;
1584 struct bgp_pbr_match_entry temp2
;
1585 struct bgp_pbr_rule pbr_rule
;
1586 struct bgp_pbr_rule
*bpr
;
1587 struct bgp_pbr_match
*bpm
;
1588 struct bgp_pbr_match_entry
*bpme
;
1589 struct bgp_pbr_match_entry_remain bpmer
;
1590 struct bgp_pbr_range_port
*src_port
;
1591 struct bgp_pbr_range_port
*dst_port
;
1592 struct bgp_pbr_range_port
*pkt_len
;
1593 struct bgp_pbr_rule_remain bprr
;
1597 src_port
= bpf
->src_port
;
1598 dst_port
= bpf
->dst_port
;
1599 pkt_len
= bpf
->pkt_len
;
1601 if (BGP_DEBUG(zebra
, ZEBRA
))
1602 bgp_pbr_dump_entry(bpf
, false);
1604 /* as we don't know information from EC
1605 * look for bpm that have the bpm
1606 * with vrf_id characteristics
1608 memset(&temp2
, 0, sizeof(temp2
));
1609 memset(&temp
, 0, sizeof(temp
));
1611 if (bpf
->type
== BGP_PBR_IPRULE
) {
1612 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1613 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1615 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1616 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1619 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1620 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1623 /* A previous entry may already exist
1624 * flush previous entry if necessary
1626 bprr
.bpr_to_match
= bpr
;
1627 bprr
.bpr_found
= NULL
;
1628 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1629 if (bprr
.bpr_found
) {
1630 static struct bgp_pbr_rule
*local_bpr
;
1631 static struct bgp_pbr_action
*local_bpa
;
1633 local_bpr
= bprr
.bpr_found
;
1634 local_bpa
= local_bpr
->action
;
1635 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1642 temp
.flags
|= MATCH_IP_SRC_SET
;
1643 prefix_copy(&temp2
.src
, bpf
->src
);
1645 temp2
.src
.family
= AF_INET
;
1647 temp
.flags
|= MATCH_IP_DST_SET
;
1648 prefix_copy(&temp2
.dst
, bpf
->dst
);
1650 temp2
.dst
.family
= AF_INET
;
1651 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1652 if (bpf
->protocol
== IPPROTO_ICMP
)
1653 temp
.flags
|= MATCH_ICMP_SET
;
1654 temp
.flags
|= MATCH_PORT_SRC_SET
;
1655 temp2
.src_port_min
= src_port
->min_port
;
1656 if (src_port
->max_port
) {
1657 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1658 temp2
.src_port_max
= src_port
->max_port
;
1661 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1662 if (bpf
->protocol
== IPPROTO_ICMP
)
1663 temp
.flags
|= MATCH_ICMP_SET
;
1664 temp
.flags
|= MATCH_PORT_DST_SET
;
1665 temp2
.dst_port_min
= dst_port
->min_port
;
1666 if (dst_port
->max_port
) {
1667 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1668 temp2
.dst_port_max
= dst_port
->max_port
;
1671 temp2
.proto
= bpf
->protocol
;
1674 temp
.pkt_len_min
= pkt_len
->min_port
;
1675 if (pkt_len
->max_port
)
1676 temp
.pkt_len_max
= pkt_len
->max_port
;
1677 } else if (bpf
->pkt_len_val
) {
1678 if (bpf
->pkt_len_val
->mask
)
1679 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1680 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1682 if (bpf
->tcp_flags
) {
1683 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1684 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1687 if (bpf
->dscp
->mask
)
1688 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1690 temp
.flags
|= MATCH_DSCP_SET
;
1691 temp
.dscp_value
= bpf
->dscp
->val
;
1693 if (bpf
->fragment
) {
1694 if (bpf
->fragment
->mask
)
1695 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1696 temp
.fragment
= bpf
->fragment
->val
;
1699 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1700 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1701 temp
.type
= IPSET_NET_PORT
;
1703 temp
.type
= IPSET_NET
;
1705 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1706 temp
.type
= IPSET_NET_PORT_NET
;
1708 temp
.type
= IPSET_NET_NET
;
1710 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1713 temp
.vrf_id
= bpf
->vrf_id
;
1716 bpme
->backpointer
= bpm
;
1717 /* right now, a previous entry may already exist
1718 * flush previous entry if necessary
1720 bpmer
.bpme_to_match
= bpme
;
1721 bpmer
.bpme_found
= NULL
;
1722 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1723 if (bpmer
.bpme_found
) {
1724 static struct bgp_pbr_match
*local_bpm
;
1725 static struct bgp_pbr_action
*local_bpa
;
1727 local_bpm
= bpmer
.bpme_found
->backpointer
;
1728 local_bpa
= local_bpm
->action
;
1729 bgp_pbr_flush_entry(bgp
, local_bpa
,
1730 local_bpm
, bpmer
.bpme_found
);
1734 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1736 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1737 return FLOWSPEC_DSCP
;
1738 if (type_entry
== FLOWSPEC_DSCP
)
1739 return FLOWSPEC_PKT_LEN
;
1740 if (type_entry
== FLOWSPEC_PKT_LEN
)
1741 return FLOWSPEC_FRAGMENT
;
1742 if (type_entry
== FLOWSPEC_FRAGMENT
)
1743 return FLOWSPEC_ICMP_TYPE
;
1747 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1748 struct bgp_pbr_filter
*bpf
,
1749 struct bgp_pbr_or_filter
*bpof
, bool add
,
1750 struct nexthop
*nh
, float *rate
)
1752 struct bgp_pbr_range_port srcp
, dstp
;
1753 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1754 struct listnode
*tnode
, *cnode
;
1758 if (bpf
->protocol
!= IPPROTO_ICMP
)
1760 bpf
->src_port
= &srcp
;
1761 bpf
->dst_port
= &dstp
;
1762 /* parse icmp type and lookup appropriate icmp code
1763 * if no icmp code found, create as many entryes as
1764 * there are listed icmp codes for that icmp type
1766 if (!bpof
->icmp_type
) {
1768 srcp
.max_port
= 255;
1769 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1770 dstp
.min_port
= icmp_code
->val
;
1772 bgp_pbr_policyroute_add_to_zebra_unit(
1773 bgp
, path
, bpf
, nh
, rate
);
1775 bgp_pbr_policyroute_remove_from_zebra_unit(
1780 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1781 srcp
.min_port
= icmp_type
->val
;
1784 /* only icmp type. create an entry only with icmp type */
1785 if (!bpof
->icmp_code
) {
1786 /* icmp type is not one of the above
1787 * forge an entry only based on the icmp type
1790 dstp
.max_port
= 255;
1792 bgp_pbr_policyroute_add_to_zebra_unit(
1793 bgp
, path
, bpf
, nh
, rate
);
1795 bgp_pbr_policyroute_remove_from_zebra_unit(
1799 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1800 dstp
.min_port
= icmp_code
->val
;
1802 bgp_pbr_policyroute_add_to_zebra_unit(
1803 bgp
, path
, bpf
, nh
, rate
);
1805 bgp_pbr_policyroute_remove_from_zebra_unit(
1811 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1812 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1813 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1815 struct listnode
*node
, *nnode
;
1816 struct bgp_pbr_val_mask
*valmask
;
1817 uint8_t next_type_entry
;
1818 struct list
*orig_list
;
1819 struct bgp_pbr_val_mask
**target_val
;
1821 if (type_entry
== 0) {
1822 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1825 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1826 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1827 orig_list
= bpof
->tcpflags
;
1828 target_val
= &bpf
->tcp_flags
;
1829 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1830 orig_list
= bpof
->dscp
;
1831 target_val
= &bpf
->dscp
;
1832 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1833 orig_list
= bpof
->pkt_len
;
1834 target_val
= &bpf
->pkt_len_val
;
1835 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1836 orig_list
= bpof
->fragment
;
1837 target_val
= &bpf
->fragment
;
1838 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1839 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1840 /* enumerate list for icmp - must be last one */
1841 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1844 bgp_pbr_policyroute_remove_from_zebra_recursive(
1845 bgp
, path
, bpf
, bpof
, next_type_entry
);
1848 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1849 *target_val
= valmask
;
1850 bgp_pbr_policyroute_remove_from_zebra_recursive(
1851 bgp
, path
, bpf
, bpof
, next_type_entry
);
1855 static void bgp_pbr_policyroute_remove_from_zebra(
1856 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1857 struct bgp_pbr_or_filter
*bpof
)
1860 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1864 bgp_pbr_policyroute_remove_from_zebra_recursive(
1865 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1866 else if (bpof
->dscp
)
1867 bgp_pbr_policyroute_remove_from_zebra_recursive(
1868 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1869 else if (bpof
->pkt_len
)
1870 bgp_pbr_policyroute_remove_from_zebra_recursive(
1871 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1872 else if (bpof
->fragment
)
1873 bgp_pbr_policyroute_remove_from_zebra_recursive(
1874 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1875 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1876 bgp_pbr_policyroute_remove_from_zebra_recursive(
1877 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1879 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1882 list_delete_all_node(bpof
->tcpflags
);
1884 list_delete_all_node(bpof
->dscp
);
1886 list_delete_all_node(bpof
->pkt_len
);
1888 list_delete_all_node(bpof
->fragment
);
1891 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1893 struct bgp_pbr_range_port
*src_port
;
1894 struct bgp_pbr_range_port
*dst_port
;
1895 struct bgp_pbr_range_port
*pkt_len
;
1896 char bufsrc
[64], bufdst
[64];
1898 int remaining_len
= 0;
1899 char protocol_str
[16];
1903 src_port
= bpf
->src_port
;
1904 dst_port
= bpf
->dst_port
;
1905 pkt_len
= bpf
->pkt_len
;
1907 protocol_str
[0] = '\0';
1908 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1909 bpf
->protocol
= IPPROTO_TCP
;
1911 snprintf(protocol_str
, sizeof(protocol_str
),
1912 "proto %d", bpf
->protocol
);
1914 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1915 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1918 dst_port
->min_port
);
1919 else if (bpf
->protocol
== IPPROTO_UDP
||
1920 bpf
->protocol
== IPPROTO_TCP
) {
1922 if (src_port
&& src_port
->min_port
)
1923 remaining_len
+= snprintf(buffer
,
1927 src_port
->max_port
?
1928 src_port
->max_port
:
1929 src_port
->min_port
);
1930 if (dst_port
&& dst_port
->min_port
)
1931 remaining_len
+= snprintf(buffer
+
1937 dst_port
->max_port
?
1938 dst_port
->max_port
:
1939 dst_port
->min_port
);
1941 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1942 remaining_len
+= snprintf(buffer
+ remaining_len
,
1950 } else if (bpf
->pkt_len_val
) {
1951 remaining_len
+= snprintf(buffer
+ remaining_len
,
1955 bpf
->pkt_len_val
->mask
1957 bpf
->pkt_len_val
->val
);
1959 if (bpf
->tcp_flags
) {
1960 remaining_len
+= snprintf(buffer
+ remaining_len
,
1964 bpf
->tcp_flags
->val
,
1965 bpf
->tcp_flags
->mask
);
1968 snprintf(buffer
+ remaining_len
,
1976 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1977 add
? "adding" : "removing",
1978 bpf
->src
== NULL
? "<all>" :
1979 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1980 bpf
->dst
== NULL
? "<all>" :
1981 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1982 protocol_str
, buffer
);
1986 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1987 struct bgp_path_info
*path
,
1988 struct bgp_pbr_filter
*bpf
,
1992 struct bgp_pbr_match temp
;
1993 struct bgp_pbr_match_entry temp2
;
1994 struct bgp_pbr_match
*bpm
;
1995 struct bgp_pbr_match_entry
*bpme
= NULL
;
1996 struct bgp_pbr_action temp3
;
1997 struct bgp_pbr_action
*bpa
= NULL
;
1998 struct bgp_pbr_match_entry_remain bpmer
;
1999 struct bgp_pbr_rule_remain bprr
;
2000 struct bgp_pbr_range_port
*src_port
;
2001 struct bgp_pbr_range_port
*dst_port
;
2002 struct bgp_pbr_range_port
*pkt_len
;
2003 struct bgp_pbr_rule pbr_rule
;
2004 struct bgp_pbr_rule
*bpr
;
2005 bool bpr_found
= false;
2006 bool bpme_found
= false;
2010 src_port
= bpf
->src_port
;
2011 dst_port
= bpf
->dst_port
;
2012 pkt_len
= bpf
->pkt_len
;
2014 if (BGP_DEBUG(zebra
, ZEBRA
))
2015 bgp_pbr_dump_entry(bpf
, true);
2017 /* look for bpa first */
2018 memset(&temp3
, 0, sizeof(temp3
));
2022 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2023 temp3
.vrf_id
= bpf
->vrf_id
;
2024 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2025 bgp_pbr_action_alloc_intern
);
2027 if (bpa
->fwmark
== 0) {
2028 /* drop is handled by iptable */
2029 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2031 bpa
->installed
= true;
2033 bpa
->fwmark
= bgp_zebra_tm_get_id();
2034 bpa
->table_id
= bpa
->fwmark
;
2035 bpa
->installed
= false;
2038 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2039 /* 0 value is forbidden */
2040 bpa
->install_in_progress
= false;
2042 if (bpf
->type
== BGP_PBR_IPRULE
) {
2043 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2044 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2045 pbr_rule
.priority
= 20;
2047 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2048 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2051 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2052 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2054 pbr_rule
.action
= bpa
;
2055 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2056 bgp_pbr_rule_alloc_intern
);
2057 if (bpr
&& bpr
->unique
== 0) {
2058 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2059 bpr
->installed
= false;
2060 bpr
->install_in_progress
= false;
2061 /* link bgp info to bpr */
2062 bpr
->path
= (void *)path
;
2065 /* already installed */
2066 if (bpr_found
&& bpr
) {
2067 struct bgp_path_info_extra
*extra
=
2068 bgp_path_info_extra_get(path
);
2071 listnode_lookup_nocheck(extra
->bgp_fs_iprule
,
2073 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2074 zlog_err("%s: entry %p/%p already "
2075 "installed in bgp pbr iprule",
2076 __func__
, path
, bpr
);
2080 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2081 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2082 bgp_zebra_announce_default(bgp
, nh
,
2083 AFI_IP
, bpa
->table_id
, true);
2086 if (bpr
&& !bpr
->installed
)
2087 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2089 /* A previous entry may already exist
2090 * flush previous entry if necessary
2092 bprr
.bpr_to_match
= bpr
;
2093 bprr
.bpr_found
= NULL
;
2094 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2095 if (bprr
.bpr_found
) {
2096 static struct bgp_pbr_rule
*local_bpr
;
2097 static struct bgp_pbr_action
*local_bpa
;
2099 local_bpr
= bprr
.bpr_found
;
2100 local_bpa
= local_bpr
->action
;
2101 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2106 /* then look for bpm */
2107 memset(&temp
, 0, sizeof(temp
));
2108 temp
.vrf_id
= bpf
->vrf_id
;
2110 temp
.flags
|= MATCH_IP_SRC_SET
;
2112 temp
.flags
|= MATCH_IP_DST_SET
;
2114 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2115 if (bpf
->protocol
== IPPROTO_ICMP
)
2116 temp
.flags
|= MATCH_ICMP_SET
;
2117 temp
.flags
|= MATCH_PORT_SRC_SET
;
2119 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2120 if (bpf
->protocol
== IPPROTO_ICMP
)
2121 temp
.flags
|= MATCH_ICMP_SET
;
2122 temp
.flags
|= MATCH_PORT_DST_SET
;
2124 if (src_port
&& src_port
->max_port
)
2125 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2126 if (dst_port
&& dst_port
->max_port
)
2127 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2129 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2130 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2131 temp
.type
= IPSET_NET_PORT
;
2133 temp
.type
= IPSET_NET
;
2135 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2136 temp
.type
= IPSET_NET_PORT_NET
;
2138 temp
.type
= IPSET_NET_NET
;
2141 temp
.pkt_len_min
= pkt_len
->min_port
;
2142 if (pkt_len
->max_port
)
2143 temp
.pkt_len_max
= pkt_len
->max_port
;
2144 } else if (bpf
->pkt_len_val
) {
2145 if (bpf
->pkt_len_val
->mask
)
2146 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2147 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2149 if (bpf
->tcp_flags
) {
2150 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2151 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2154 if (bpf
->dscp
->mask
)
2155 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2157 temp
.flags
|= MATCH_DSCP_SET
;
2158 temp
.dscp_value
= bpf
->dscp
->val
;
2160 if (bpf
->fragment
) {
2161 if (bpf
->fragment
->mask
)
2162 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2163 temp
.fragment
= bpf
->fragment
->val
;
2166 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2167 bgp_pbr_match_alloc_intern
);
2169 /* new, then self allocate ipset_name and unique */
2170 if (bpm
->unique
== 0) {
2171 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2172 /* 0 value is forbidden */
2173 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2174 bpm
->entry_hash
= hash_create_size(8,
2175 bgp_pbr_match_entry_hash_key
,
2176 bgp_pbr_match_entry_hash_equal
,
2177 "Match Entry Hash");
2178 bpm
->installed
= false;
2180 /* unique2 should be updated too */
2181 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2182 bpm
->installed_in_iptable
= false;
2183 bpm
->install_in_progress
= false;
2184 bpm
->install_iptable_in_progress
= false;
2187 memset(&temp2
, 0, sizeof(temp2
));
2189 prefix_copy(&temp2
.src
, bpf
->src
);
2191 temp2
.src
.family
= AF_INET
;
2193 prefix_copy(&temp2
.dst
, bpf
->dst
);
2195 temp2
.dst
.family
= AF_INET
;
2196 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2197 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2198 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2199 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2200 temp2
.proto
= bpf
->protocol
;
2201 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2202 bgp_pbr_match_entry_alloc_intern
);
2203 if (bpme
->unique
== 0) {
2204 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2205 /* 0 value is forbidden */
2206 bpme
->backpointer
= bpm
;
2207 bpme
->installed
= false;
2208 bpme
->install_in_progress
= false;
2209 /* link bgp info to bpme */
2210 bpme
->path
= (void *)path
;
2214 /* already installed */
2216 struct bgp_path_info_extra
*extra
=
2217 bgp_path_info_extra_get(path
);
2220 listnode_lookup_nocheck(extra
->bgp_fs_pbr
, bpme
)) {
2221 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2223 "%s: entry %p/%p already installed in bgp pbr",
2224 __func__
, path
, bpme
);
2228 /* BGP FS: append entry to zebra
2229 * - policies are not routing entries and as such
2230 * route replace semantics don't necessarily follow
2231 * through to policy entries
2232 * - because of that, not all policing information will be stored
2233 * into zebra. and non selected policies will be suppressed from zebra
2234 * - as consequence, in order to bring consistency
2235 * a policy will be added, then ifan ecmp policy exists,
2236 * it will be suppressed subsequently
2239 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2240 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2241 bgp_zebra_announce_default(bgp
, nh
,
2242 AFI_IP
, bpa
->table_id
, true);
2246 if (!bpm
->installed
)
2247 bgp_send_pbr_ipset_match(bpm
, true);
2249 if (!bpme
->installed
)
2250 bgp_send_pbr_ipset_entry_match(bpme
, true);
2253 if (!bpm
->installed_in_iptable
)
2254 bgp_send_pbr_iptable(bpa
, bpm
, true);
2256 /* A previous entry may already exist
2257 * flush previous entry if necessary
2259 bpmer
.bpme_to_match
= bpme
;
2260 bpmer
.bpme_found
= NULL
;
2261 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2262 if (bpmer
.bpme_found
) {
2263 static struct bgp_pbr_match
*local_bpm
;
2264 static struct bgp_pbr_action
*local_bpa
;
2266 local_bpm
= bpmer
.bpme_found
->backpointer
;
2267 local_bpa
= local_bpm
->action
;
2268 bgp_pbr_flush_entry(bgp
, local_bpa
,
2269 local_bpm
, bpmer
.bpme_found
);
2275 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2276 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2277 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2280 struct listnode
*node
, *nnode
;
2281 struct bgp_pbr_val_mask
*valmask
;
2282 uint8_t next_type_entry
;
2283 struct list
*orig_list
;
2284 struct bgp_pbr_val_mask
**target_val
;
2286 if (type_entry
== 0) {
2287 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2290 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2291 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2292 orig_list
= bpof
->tcpflags
;
2293 target_val
= &bpf
->tcp_flags
;
2294 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2295 orig_list
= bpof
->dscp
;
2296 target_val
= &bpf
->dscp
;
2297 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2298 orig_list
= bpof
->pkt_len
;
2299 target_val
= &bpf
->pkt_len_val
;
2300 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2301 orig_list
= bpof
->fragment
;
2302 target_val
= &bpf
->fragment
;
2303 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2304 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2305 /* enumerate list for icmp - must be last one */
2306 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2309 bgp_pbr_policyroute_add_to_zebra_recursive(
2310 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2313 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2314 *target_val
= valmask
;
2315 bgp_pbr_policyroute_add_to_zebra_recursive(
2316 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2320 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2321 struct bgp_path_info
*path
,
2322 struct bgp_pbr_filter
*bpf
,
2323 struct bgp_pbr_or_filter
*bpof
,
2324 struct nexthop
*nh
, float *rate
)
2327 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2331 bgp_pbr_policyroute_add_to_zebra_recursive(
2332 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2333 else if (bpof
->dscp
)
2334 bgp_pbr_policyroute_add_to_zebra_recursive(
2335 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2336 else if (bpof
->pkt_len
)
2337 bgp_pbr_policyroute_add_to_zebra_recursive(
2338 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2339 else if (bpof
->fragment
)
2340 bgp_pbr_policyroute_add_to_zebra_recursive(
2341 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2342 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2343 bgp_pbr_policyroute_add_to_zebra_recursive(
2344 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2346 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2349 list_delete_all_node(bpof
->tcpflags
);
2351 list_delete_all_node(bpof
->dscp
);
2353 list_delete_all_node(bpof
->pkt_len
);
2355 list_delete_all_node(bpof
->fragment
);
2356 if (bpof
->icmp_type
)
2357 list_delete_all_node(bpof
->icmp_type
);
2358 if (bpof
->icmp_code
)
2359 list_delete_all_node(bpof
->icmp_code
);
2362 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2363 struct bgp_pbr_entry_main
*api
, bool add
)
2367 int continue_loop
= 1;
2369 struct prefix
*src
= NULL
, *dst
= NULL
;
2371 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2372 struct bgp_pbr_range_port range
, range_icmp_code
;
2373 struct bgp_pbr_range_port pkt_len
;
2374 struct bgp_pbr_filter bpf
;
2376 struct bgp_pbr_or_filter bpof
;
2377 struct bgp_pbr_val_mask bpvm
;
2379 memset(&nh
, 0, sizeof(struct nexthop
));
2380 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2381 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2382 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2383 (api
->type
== BGP_PBR_IPRULE
&&
2384 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2385 src
= &api
->src_prefix
;
2386 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2387 (api
->type
== BGP_PBR_IPRULE
&&
2388 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2389 dst
= &api
->dst_prefix
;
2390 if (api
->type
== BGP_PBR_IPRULE
)
2391 bpf
.type
= api
->type
;
2392 memset(&nh
, 0, sizeof(struct nexthop
));
2393 nh
.vrf_id
= VRF_UNKNOWN
;
2394 if (api
->match_protocol_num
)
2395 proto
= (uint8_t)api
->protocol
[0].value
;
2396 /* if match_port is selected, then either src or dst port will be parsed
2397 * but not both at the same time
2399 if (api
->match_port_num
>= 1) {
2400 bgp_pbr_extract(api
->port
,
2401 api
->match_port_num
,
2403 srcp
= dstp
= &range
;
2404 } else if (api
->match_src_port_num
>= 1) {
2405 bgp_pbr_extract(api
->src_port
,
2406 api
->match_src_port_num
,
2410 } else if (api
->match_dst_port_num
>= 1) {
2411 bgp_pbr_extract(api
->dst_port
,
2412 api
->match_dst_port_num
,
2417 if (api
->match_icmp_type_num
>= 1) {
2418 proto
= IPPROTO_ICMP
;
2419 if (bgp_pbr_extract(api
->icmp_type
,
2420 api
->match_icmp_type_num
,
2424 bpof
.icmp_type
= list_new();
2425 bgp_pbr_extract_enumerate(api
->icmp_type
,
2426 api
->match_icmp_type_num
,
2429 FLOWSPEC_ICMP_TYPE
);
2432 if (api
->match_icmp_code_num
>= 1) {
2433 proto
= IPPROTO_ICMP
;
2434 if (bgp_pbr_extract(api
->icmp_code
,
2435 api
->match_icmp_code_num
,
2437 dstp
= &range_icmp_code
;
2439 bpof
.icmp_code
= list_new();
2440 bgp_pbr_extract_enumerate(api
->icmp_code
,
2441 api
->match_icmp_code_num
,
2444 FLOWSPEC_ICMP_CODE
);
2448 if (api
->match_tcpflags_num
) {
2449 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2450 api
->match_tcpflags_num
);
2451 if (kind_enum
== OPERATOR_UNARY_AND
) {
2452 bpf
.tcp_flags
= &bpvm
;
2453 bgp_pbr_extract_enumerate(api
->tcpflags
,
2454 api
->match_tcpflags_num
,
2457 FLOWSPEC_TCP_FLAGS
);
2458 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2459 bpof
.tcpflags
= list_new();
2460 bgp_pbr_extract_enumerate(api
->tcpflags
,
2461 api
->match_tcpflags_num
,
2464 FLOWSPEC_TCP_FLAGS
);
2467 if (api
->match_packet_length_num
) {
2470 ret
= bgp_pbr_extract(api
->packet_length
,
2471 api
->match_packet_length_num
,
2474 bpf
.pkt_len
= &pkt_len
;
2476 bpof
.pkt_len
= list_new();
2477 bgp_pbr_extract_enumerate(api
->packet_length
,
2478 api
->match_packet_length_num
,
2484 if (api
->match_dscp_num
>= 1) {
2485 bpof
.dscp
= list_new();
2486 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2488 bpof
.dscp
, FLOWSPEC_DSCP
);
2490 if (api
->match_fragment_num
) {
2491 bpof
.fragment
= list_new();
2492 bgp_pbr_extract_enumerate(api
->fragment
,
2493 api
->match_fragment_num
,
2498 bpf
.vrf_id
= api
->vrf_id
;
2501 bpf
.protocol
= proto
;
2502 bpf
.src_port
= srcp
;
2503 bpf
.dst_port
= dstp
;
2505 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2508 /* no action for add = true */
2509 for (i
= 0; i
< api
->action_num
; i
++) {
2510 switch (api
->actions
[i
].action
) {
2511 case ACTION_TRAFFICRATE
:
2513 if (api
->actions
[i
].u
.r
.rate
== 0) {
2514 nh
.vrf_id
= api
->vrf_id
;
2515 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2516 bgp_pbr_policyroute_add_to_zebra(
2517 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2519 /* update rate. can be reentrant */
2520 rate
= api
->actions
[i
].u
.r
.rate
;
2521 if (BGP_DEBUG(pbr
, PBR
)) {
2522 bgp_pbr_print_policy_route(api
);
2523 zlog_warn("PBR: ignoring Set action rate %f",
2524 api
->actions
[i
].u
.r
.rate
);
2528 case ACTION_TRAFFIC_ACTION
:
2529 if (api
->actions
[i
].u
.za
.filter
2530 & TRAFFIC_ACTION_SAMPLE
) {
2531 if (BGP_DEBUG(pbr
, PBR
)) {
2532 bgp_pbr_print_policy_route(api
);
2533 zlog_warn("PBR: Sample action Ignored");
2537 if (api
->actions
[i
].u
.za
.filter
2538 & TRAFFIC_ACTION_DISTRIBUTE
) {
2539 if (BGP_DEBUG(pbr
, PBR
)) {
2540 bgp_pbr_print_policy_route(api
);
2541 zlog_warn("PBR: Distribute action Applies");
2544 /* continue forwarding entry as before
2548 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2549 /* terminate action: run other filters
2552 case ACTION_REDIRECT_IP
:
2553 nh
.type
= NEXTHOP_TYPE_IPV4
;
2554 nh
.gate
.ipv4
.s_addr
=
2555 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2556 nh
.vrf_id
= api
->vrf_id
;
2557 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2559 /* XXX combination with REDIRECT_VRF
2560 * + REDIRECT_NH_IP not done
2564 case ACTION_REDIRECT
:
2565 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2566 nh
.type
= NEXTHOP_TYPE_IPV4
;
2567 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2571 case ACTION_MARKING
:
2572 if (BGP_DEBUG(pbr
, PBR
)) {
2573 bgp_pbr_print_policy_route(api
);
2574 zlog_warn("PBR: Set DSCP %u Ignored",
2575 api
->actions
[i
].u
.marking_dscp
);
2581 if (continue_loop
== 0)
2586 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2587 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2590 struct bgp_pbr_entry_main api
;
2593 return; /* IPv6 not supported */
2594 if (safi
!= SAFI_FLOWSPEC
)
2595 return; /* not supported */
2596 /* Make Zebra API structure. */
2597 memset(&api
, 0, sizeof(api
));
2598 api
.vrf_id
= bgp
->vrf_id
;
2601 if (!bgp_zebra_tm_chunk_obtained()) {
2602 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2603 flog_err(EC_BGP_TABLE_CHUNK
,
2604 "%s: table chunk not obtained yet", __func__
);
2608 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2609 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2610 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2611 "%s: cancel updating entry %p in bgp pbr",
2615 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2618 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2619 const struct bgp_pbr_interface
*b
)
2621 return strcmp(a
->name
, b
->name
);
2624 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2625 struct bgp_pbr_interface_head
*head
)
2627 struct bgp_pbr_interface pbr_if
;
2629 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2630 return (RB_FIND(bgp_pbr_interface_head
,
2634 /* this function resets to the default policy routing
2635 * go back to default status
2637 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2639 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2640 struct bgp_pbr_interface_head
*head
;
2641 struct bgp_pbr_interface
*pbr_if
;
2643 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2645 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2647 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2648 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2649 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2650 XFREE(MTYPE_TMP
, pbr_if
);