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
758 .zr
.redirect_ip_v4
.s_addr
)
760 if (!path
->attr
->nexthop
.s_addr
)
762 api_action_redirect_ip
->u
763 .zr
.redirect_ip_v4
.s_addr
=
764 path
->attr
->nexthop
.s_addr
;
765 api_action_redirect_ip
->u
.zr
.duplicate
769 api_action
->action
= ACTION_REDIRECT_IP
;
770 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
771 path
->attr
->nexthop
.s_addr
;
772 api_action
->u
.zr
.duplicate
=
774 api_action_redirect_ip
= api_action
;
776 } else if ((ecom_eval
->val
[0] ==
777 (char)ECOMMUNITY_ENCODE_IP
) &&
778 (ecom_eval
->val
[1] ==
779 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
780 /* in case the 2 ecom present,
781 * overwrite simpson draft
782 * update redirect ip fields
784 if (api_action_redirect_ip
) {
785 memcpy(&(api_action_redirect_ip
->u
786 .zr
.redirect_ip_v4
.s_addr
),
787 (ecom_eval
->val
+2), 4);
788 api_action_redirect_ip
->u
793 api_action
->action
= ACTION_REDIRECT_IP
;
794 memcpy(&(api_action
->u
795 .zr
.redirect_ip_v4
.s_addr
),
796 (ecom_eval
->val
+2), 4);
797 api_action
->u
.zr
.duplicate
=
799 api_action_redirect_ip
= api_action
;
802 if (ecom_eval
->val
[0] !=
803 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
805 ret
= ecommunity_fill_pbr_action(ecom_eval
,
809 if ((api_action
->action
== ACTION_TRAFFICRATE
) &&
810 api
->actions
[i
].u
.r
.rate
== 0)
811 discard_action_found
= true;
816 /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
817 * then reduce the API action list to that action
819 if (api
->action_num
> 1 && discard_action_found
) {
821 memset(&api
->actions
[0], 0,
822 sizeof(struct bgp_pbr_entry_action
));
823 api
->actions
[0].action
= ACTION_TRAFFICRATE
;
826 /* validate if incoming matc/action is compatible
827 * with our policy routing engine
829 if (!bgp_pbr_validate_policy_route(api
))
832 /* check inconsistency in the match rule */
833 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
834 src
= &api
->src_prefix
;
835 afi
= family2afi(src
->family
);
838 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
839 dst
= &api
->dst_prefix
;
840 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
841 if (BGP_DEBUG(pbr
, PBR
)) {
842 bgp_pbr_print_policy_route(api
);
843 zlog_debug("%s: inconsistency:"
844 " no match for afi src and dst (%u/%u)",
845 __func__
, afi
, family2afi(dst
->family
));
853 static void bgp_pbr_match_entry_free(void *arg
)
855 struct bgp_pbr_match_entry
*bpme
;
857 bpme
= (struct bgp_pbr_match_entry
*)arg
;
859 if (bpme
->installed
) {
860 bgp_send_pbr_ipset_entry_match(bpme
, false);
861 bpme
->installed
= false;
862 bpme
->backpointer
= NULL
;
864 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
867 static void bgp_pbr_match_free(void *arg
)
869 struct bgp_pbr_match
*bpm
;
871 bpm
= (struct bgp_pbr_match
*)arg
;
873 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
875 if (hashcount(bpm
->entry_hash
) == 0) {
876 /* delete iptable entry first */
877 /* then delete ipset match */
878 if (bpm
->installed
) {
879 if (bpm
->installed_in_iptable
) {
880 bgp_send_pbr_iptable(bpm
->action
,
882 bpm
->installed_in_iptable
= false;
883 bpm
->action
->refcnt
--;
885 bgp_send_pbr_ipset_match(bpm
, false);
886 bpm
->installed
= false;
890 hash_free(bpm
->entry_hash
);
892 XFREE(MTYPE_PBR_MATCH
, bpm
);
895 static void *bgp_pbr_match_alloc_intern(void *arg
)
897 struct bgp_pbr_match
*bpm
, *new;
899 bpm
= (struct bgp_pbr_match
*)arg
;
901 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
902 memcpy(new, bpm
, sizeof(*bpm
));
907 static void bgp_pbr_rule_free(void *arg
)
909 struct bgp_pbr_rule
*bpr
;
911 bpr
= (struct bgp_pbr_rule
*)arg
;
914 if (bpr
->installed
) {
915 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
916 bpr
->installed
= false;
917 bpr
->action
->refcnt
--;
920 XFREE(MTYPE_PBR_RULE
, bpr
);
923 static void *bgp_pbr_rule_alloc_intern(void *arg
)
925 struct bgp_pbr_rule
*bpr
, *new;
927 bpr
= (struct bgp_pbr_rule
*)arg
;
929 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
930 memcpy(new, bpr
, sizeof(*bpr
));
935 static void bgp_pbr_action_free(void *arg
)
937 struct bgp_pbr_action
*bpa
;
939 bpa
= (struct bgp_pbr_action
*)arg
;
941 if (bpa
->refcnt
== 0) {
942 if (bpa
->installed
&& bpa
->table_id
!= 0) {
943 bgp_send_pbr_rule_action(bpa
, NULL
, false);
944 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
948 bpa
->installed
= false;
951 XFREE(MTYPE_PBR_ACTION
, bpa
);
954 static void *bgp_pbr_action_alloc_intern(void *arg
)
956 struct bgp_pbr_action
*bpa
, *new;
958 bpa
= (struct bgp_pbr_action
*)arg
;
960 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
962 memcpy(new, bpa
, sizeof(*bpa
));
967 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
969 struct bgp_pbr_match_entry
*bpme
, *new;
971 bpme
= (struct bgp_pbr_match_entry
*)arg
;
973 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
975 memcpy(new, bpme
, sizeof(*bpme
));
980 uint32_t bgp_pbr_match_hash_key(const void *arg
)
982 const struct bgp_pbr_match
*pbm
= arg
;
985 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
986 key
= jhash_1word(pbm
->flags
, key
);
987 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
988 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
989 key
= jhash(&pbm
->tcp_flags
, 2, key
);
990 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
991 key
= jhash(&pbm
->dscp_value
, 1, key
);
992 key
= jhash(&pbm
->fragment
, 1, key
);
993 key
= jhash(&pbm
->protocol
, 1, key
);
994 return jhash_1word(pbm
->type
, key
);
997 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
999 const struct bgp_pbr_match
*r1
, *r2
;
1001 r1
= (const struct bgp_pbr_match
*)arg1
;
1002 r2
= (const struct bgp_pbr_match
*)arg2
;
1004 if (r1
->vrf_id
!= r2
->vrf_id
)
1007 if (r1
->type
!= r2
->type
)
1010 if (r1
->flags
!= r2
->flags
)
1013 if (r1
->action
!= r2
->action
)
1016 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1019 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1022 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1025 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1028 if (r1
->dscp_value
!= r2
->dscp_value
)
1031 if (r1
->fragment
!= r2
->fragment
)
1034 if (r1
->protocol
!= r2
->protocol
)
1039 uint32_t bgp_pbr_rule_hash_key(const void *arg
)
1041 const struct bgp_pbr_rule
*pbr
= arg
;
1044 key
= prefix_hash_key(&pbr
->src
);
1045 key
= jhash_1word(pbr
->vrf_id
, key
);
1046 key
= jhash_1word(pbr
->flags
, key
);
1047 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1050 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1052 const struct bgp_pbr_rule
*r1
, *r2
;
1054 r1
= (const struct bgp_pbr_rule
*)arg1
;
1055 r2
= (const struct bgp_pbr_rule
*)arg2
;
1057 if (r1
->vrf_id
!= r2
->vrf_id
)
1060 if (r1
->flags
!= r2
->flags
)
1063 if (r1
->action
!= r2
->action
)
1066 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1067 !prefix_same(&r1
->src
, &r2
->src
))
1070 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1071 !prefix_same(&r1
->dst
, &r2
->dst
))
1077 uint32_t bgp_pbr_match_entry_hash_key(const void *arg
)
1079 const struct bgp_pbr_match_entry
*pbme
;
1083 key
= prefix_hash_key(&pbme
->src
);
1084 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1085 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1086 key
= jhash(&pbme
->src_port_min
, 2, key
);
1087 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1088 key
= jhash(&pbme
->src_port_max
, 2, key
);
1089 key
= jhash(&pbme
->proto
, 1, key
);
1094 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1096 const struct bgp_pbr_match_entry
*r1
, *r2
;
1098 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1099 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1102 * on updates, comparing backpointer is not necessary
1103 * unique value is self calculated
1104 * rate is ignored for now
1107 if (!prefix_same(&r1
->src
, &r2
->src
))
1110 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1113 if (r1
->src_port_min
!= r2
->src_port_min
)
1116 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1119 if (r1
->src_port_max
!= r2
->src_port_max
)
1122 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1125 if (r1
->proto
!= r2
->proto
)
1131 uint32_t bgp_pbr_action_hash_key(const void *arg
)
1133 const struct bgp_pbr_action
*pbra
;
1137 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1138 key
= jhash_1word(pbra
->fwmark
, key
);
1142 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1144 const struct bgp_pbr_action
*r1
, *r2
;
1146 r1
= (const struct bgp_pbr_action
*)arg1
;
1147 r2
= (const struct bgp_pbr_action
*)arg2
;
1149 /* unique value is self calculated
1150 * table and fwmark is self calculated
1153 if (r1
->vrf_id
!= r2
->vrf_id
)
1156 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1162 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1165 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1166 struct bgp_pbr_rule_unique bpru
;
1168 if (!bgp
|| unique
== 0)
1170 bpru
.unique
= unique
;
1171 bpru
.bpr_found
= NULL
;
1172 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1173 return bpru
.bpr_found
;
1176 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1179 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1180 struct bgp_pbr_action_unique bpau
;
1182 if (!bgp
|| unique
== 0)
1184 bpau
.unique
= unique
;
1185 bpau
.bpa_found
= NULL
;
1186 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1187 return bpau
.bpa_found
;
1190 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1193 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1194 struct bgp_pbr_match_unique bpmu
;
1196 if (!bgp
|| unique
== 0)
1198 bpmu
.unique
= unique
;
1199 bpmu
.bpm_found
= NULL
;
1200 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1201 return bpmu
.bpm_found
;
1204 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1208 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1209 struct bgp_pbr_match_entry_unique bpmeu
;
1210 struct bgp_pbr_match_ipsetname bpmi
;
1212 if (!bgp
|| unique
== 0)
1214 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1215 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1216 bpmi
.bpm_found
= NULL
;
1217 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1218 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1219 if (!bpmi
.bpm_found
)
1221 bpmeu
.bpme_found
= NULL
;
1222 bpmeu
.unique
= unique
;
1223 hash_walk(bpmi
.bpm_found
->entry_hash
,
1224 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1225 return bpmeu
.bpme_found
;
1228 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1231 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1232 struct bgp_pbr_match_iptable_unique bpmiu
;
1234 if (!bgp
|| unique
== 0)
1236 bpmiu
.unique
= unique
;
1237 bpmiu
.bpm_found
= NULL
;
1238 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1239 return bpmiu
.bpm_found
;
1242 void bgp_pbr_cleanup(struct bgp
*bgp
)
1244 if (bgp
->pbr_match_hash
) {
1245 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1246 hash_free(bgp
->pbr_match_hash
);
1247 bgp
->pbr_match_hash
= NULL
;
1249 if (bgp
->pbr_rule_hash
) {
1250 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1251 hash_free(bgp
->pbr_rule_hash
);
1252 bgp
->pbr_rule_hash
= NULL
;
1254 if (bgp
->pbr_action_hash
) {
1255 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1256 hash_free(bgp
->pbr_action_hash
);
1257 bgp
->pbr_action_hash
= NULL
;
1259 if (bgp
->bgp_pbr_cfg
== NULL
)
1261 bgp_pbr_reset(bgp
, AFI_IP
);
1262 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1263 bgp
->bgp_pbr_cfg
= NULL
;
1266 void bgp_pbr_init(struct bgp
*bgp
)
1268 bgp
->pbr_match_hash
=
1269 hash_create_size(8, bgp_pbr_match_hash_key
,
1270 bgp_pbr_match_hash_equal
,
1272 bgp
->pbr_action_hash
=
1273 hash_create_size(8, bgp_pbr_action_hash_key
,
1274 bgp_pbr_action_hash_equal
,
1275 "Match Hash Entry");
1277 bgp
->pbr_rule_hash
=
1278 hash_create_size(8, bgp_pbr_rule_hash_key
,
1279 bgp_pbr_rule_hash_equal
,
1282 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1283 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1286 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1289 char return_string
[512];
1290 char *ptr
= return_string
;
1294 ptr
+= sprintf(ptr
, "MATCH : ");
1295 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1296 struct prefix
*p
= &(api
->src_prefix
);
1298 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1299 INCREMENT_DISPLAY(ptr
, nb_items
);
1301 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1302 struct prefix
*p
= &(api
->dst_prefix
);
1304 INCREMENT_DISPLAY(ptr
, nb_items
);
1305 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1308 if (api
->match_protocol_num
)
1309 INCREMENT_DISPLAY(ptr
, nb_items
);
1310 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1311 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1312 i
> 0 ? NULL
: "@proto ");
1314 if (api
->match_src_port_num
)
1315 INCREMENT_DISPLAY(ptr
, nb_items
);
1316 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1317 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1318 i
> 0 ? NULL
: "@srcport ");
1320 if (api
->match_dst_port_num
)
1321 INCREMENT_DISPLAY(ptr
, nb_items
);
1322 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1323 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1324 i
> 0 ? NULL
: "@dstport ");
1326 if (api
->match_port_num
)
1327 INCREMENT_DISPLAY(ptr
, nb_items
);
1328 for (i
= 0; i
< api
->match_port_num
; i
++)
1329 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1330 i
> 0 ? NULL
: "@port ");
1332 if (api
->match_icmp_type_num
)
1333 INCREMENT_DISPLAY(ptr
, nb_items
);
1334 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1335 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1336 i
> 0 ? NULL
: "@icmptype ");
1338 if (api
->match_icmp_code_num
)
1339 INCREMENT_DISPLAY(ptr
, nb_items
);
1340 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1341 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1342 i
> 0 ? NULL
: "@icmpcode ");
1344 if (api
->match_packet_length_num
)
1345 INCREMENT_DISPLAY(ptr
, nb_items
);
1346 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1347 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1348 i
> 0 ? NULL
: "@plen ");
1350 if (api
->match_dscp_num
)
1351 INCREMENT_DISPLAY(ptr
, nb_items
);
1352 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1353 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1354 i
> 0 ? NULL
: "@dscp ");
1356 if (api
->match_tcpflags_num
)
1357 INCREMENT_DISPLAY(ptr
, nb_items
);
1358 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1359 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1360 i
> 0 ? NULL
: "@tcpflags ");
1362 if (api
->match_fragment_num
)
1363 INCREMENT_DISPLAY(ptr
, nb_items
);
1364 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1365 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1366 i
> 0 ? NULL
: "@fragment ");
1368 ptr
= return_string
;
1370 ptr
+= sprintf(ptr
, "; ");
1371 if (api
->action_num
)
1372 ptr
+= sprintf(ptr
, "SET : ");
1374 for (i
= 0; i
< api
->action_num
; i
++) {
1375 switch (api
->actions
[i
].action
) {
1376 case ACTION_TRAFFICRATE
:
1377 INCREMENT_DISPLAY(ptr
, nb_items
);
1378 ptr
+= sprintf(ptr
, "@set rate %f",
1379 api
->actions
[i
].u
.r
.rate
);
1381 case ACTION_TRAFFIC_ACTION
:
1382 INCREMENT_DISPLAY(ptr
, nb_items
);
1383 ptr
+= sprintf(ptr
, "@action ");
1384 if (api
->actions
[i
].u
.za
.filter
1385 & TRAFFIC_ACTION_TERMINATE
)
1387 " terminate (apply filter(s))");
1388 if (api
->actions
[i
].u
.za
.filter
1389 & TRAFFIC_ACTION_DISTRIBUTE
)
1390 ptr
+= sprintf(ptr
, " distribute");
1391 if (api
->actions
[i
].u
.za
.filter
1392 & TRAFFIC_ACTION_SAMPLE
)
1393 ptr
+= sprintf(ptr
, " sample");
1395 case ACTION_REDIRECT_IP
:
1396 INCREMENT_DISPLAY(ptr
, nb_items
);
1397 char local_buff
[INET_ADDRSTRLEN
];
1399 if (inet_ntop(AF_INET
,
1400 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1401 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1403 "@redirect ip nh %s", local_buff
);
1405 case ACTION_REDIRECT
:
1406 INCREMENT_DISPLAY(ptr
, nb_items
);
1407 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1408 api
->actions
[i
].u
.redirect_vrf
);
1410 case ACTION_MARKING
:
1411 INCREMENT_DISPLAY(ptr
, nb_items
);
1412 ptr
+= sprintf(ptr
, "@set dscp %u",
1413 api
->actions
[i
].u
.marking_dscp
);
1419 zlog_info("%s", return_string
);
1422 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1423 struct bgp_pbr_rule
*bpr
)
1425 /* if bpr is null, do nothing
1429 if (bpr
->installed
) {
1430 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1431 bpr
->installed
= false;
1432 bpr
->action
->refcnt
--;
1435 struct bgp_path_info
*path
;
1436 struct bgp_path_info_extra
*extra
;
1438 /* unlink path to bpme */
1439 path
= (struct bgp_path_info
*)bpr
->path
;
1440 extra
= bgp_path_info_extra_get(path
);
1441 if (extra
->bgp_fs_iprule
)
1442 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1446 hash_release(bgp
->pbr_rule_hash
, bpr
);
1447 if (bpa
->refcnt
== 0) {
1448 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1449 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1450 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1454 bpa
->installed
= false;
1459 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1460 struct bgp_pbr_match
*bpm
,
1461 struct bgp_pbr_match_entry
*bpme
)
1463 /* if bpme is null, bpm is also null
1467 /* ipset del entry */
1468 if (bpme
->installed
) {
1469 bgp_send_pbr_ipset_entry_match(bpme
, false);
1470 bpme
->installed
= false;
1471 bpme
->backpointer
= NULL
;
1473 struct bgp_path_info
*path
;
1474 struct bgp_path_info_extra
*extra
;
1476 /* unlink path to bpme */
1477 path
= (struct bgp_path_info
*)bpme
->path
;
1478 extra
= bgp_path_info_extra_get(path
);
1479 if (extra
->bgp_fs_pbr
)
1480 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1484 hash_release(bpm
->entry_hash
, bpme
);
1485 if (hashcount(bpm
->entry_hash
) == 0) {
1486 /* delete iptable entry first */
1487 /* then delete ipset match */
1488 if (bpm
->installed
) {
1489 if (bpm
->installed_in_iptable
) {
1490 bgp_send_pbr_iptable(bpm
->action
,
1492 bpm
->installed_in_iptable
= false;
1493 bpm
->action
->refcnt
--;
1495 bgp_send_pbr_ipset_match(bpm
, false);
1496 bpm
->installed
= false;
1499 hash_release(bgp
->pbr_match_hash
, bpm
);
1500 /* XXX release pbr_match_action if not used
1501 * note that drop does not need to call send_pbr_action
1504 if (bpa
->refcnt
== 0) {
1505 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1506 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1507 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1511 bpa
->installed
= false;
1516 struct bgp_pbr_match_entry_remain
{
1517 struct bgp_pbr_match_entry
*bpme_to_match
;
1518 struct bgp_pbr_match_entry
*bpme_found
;
1521 struct bgp_pbr_rule_remain
{
1522 struct bgp_pbr_rule
*bpr_to_match
;
1523 struct bgp_pbr_rule
*bpr_found
;
1526 static int bgp_pbr_get_same_rule(struct hash_bucket
*bucket
, void *arg
)
1528 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)bucket
->data
;
1529 struct bgp_pbr_rule_remain
*ctxt
=
1530 (struct bgp_pbr_rule_remain
*)arg
;
1531 struct bgp_pbr_rule
*r2
;
1533 r2
= ctxt
->bpr_to_match
;
1535 if (r1
->vrf_id
!= r2
->vrf_id
)
1536 return HASHWALK_CONTINUE
;
1538 if (r1
->flags
!= r2
->flags
)
1539 return HASHWALK_CONTINUE
;
1541 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1542 !prefix_same(&r1
->src
, &r2
->src
))
1543 return HASHWALK_CONTINUE
;
1545 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1546 !prefix_same(&r1
->dst
, &r2
->dst
))
1547 return HASHWALK_CONTINUE
;
1549 /* this function is used for two cases:
1550 * - remove an entry upon withdraw request
1551 * (case r2->action is null)
1552 * - replace an old iprule with different action
1553 * (case r2->action is != null)
1554 * the old one is removed after the new one
1555 * this is to avoid disruption in traffic
1557 if (r2
->action
== NULL
||
1558 r1
->action
!= r2
->action
) {
1559 ctxt
->bpr_found
= r1
;
1560 return HASHWALK_ABORT
;
1562 return HASHWALK_CONTINUE
;
1565 static int bgp_pbr_get_remaining_entry(struct hash_bucket
*bucket
, void *arg
)
1567 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
1568 struct bgp_pbr_match_entry_remain
*bpmer
=
1569 (struct bgp_pbr_match_entry_remain
*)arg
;
1570 struct bgp_pbr_match
*bpm_temp
;
1571 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1573 if (!bpme
->backpointer
||
1574 bpm
== bpme
->backpointer
||
1575 bpme
->backpointer
->action
== bpm
->action
)
1576 return HASHWALK_CONTINUE
;
1577 /* ensure bpm other characteristics are equal */
1578 bpm_temp
= bpme
->backpointer
;
1579 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1580 bpm_temp
->type
!= bpm
->type
||
1581 bpm_temp
->flags
!= bpm
->flags
||
1582 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1583 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1584 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1585 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1586 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1587 bpm_temp
->fragment
!= bpm
->fragment
)
1588 return HASHWALK_CONTINUE
;
1590 /* look for remaining bpme */
1591 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1592 if (!bpmer
->bpme_found
)
1593 return HASHWALK_CONTINUE
;
1594 return HASHWALK_ABORT
;
1597 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1598 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1600 struct bgp_pbr_match temp
;
1601 struct bgp_pbr_match_entry temp2
;
1602 struct bgp_pbr_rule pbr_rule
;
1603 struct bgp_pbr_rule
*bpr
;
1604 struct bgp_pbr_match
*bpm
;
1605 struct bgp_pbr_match_entry
*bpme
;
1606 struct bgp_pbr_match_entry_remain bpmer
;
1607 struct bgp_pbr_range_port
*src_port
;
1608 struct bgp_pbr_range_port
*dst_port
;
1609 struct bgp_pbr_range_port
*pkt_len
;
1610 struct bgp_pbr_rule_remain bprr
;
1614 src_port
= bpf
->src_port
;
1615 dst_port
= bpf
->dst_port
;
1616 pkt_len
= bpf
->pkt_len
;
1618 if (BGP_DEBUG(zebra
, ZEBRA
))
1619 bgp_pbr_dump_entry(bpf
, false);
1621 /* as we don't know information from EC
1622 * look for bpm that have the bpm
1623 * with vrf_id characteristics
1625 memset(&temp2
, 0, sizeof(temp2
));
1626 memset(&temp
, 0, sizeof(temp
));
1628 if (bpf
->type
== BGP_PBR_IPRULE
) {
1629 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1630 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1632 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1633 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1636 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1637 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1640 /* A previous entry may already exist
1641 * flush previous entry if necessary
1643 bprr
.bpr_to_match
= bpr
;
1644 bprr
.bpr_found
= NULL
;
1645 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1646 if (bprr
.bpr_found
) {
1647 static struct bgp_pbr_rule
*local_bpr
;
1648 static struct bgp_pbr_action
*local_bpa
;
1650 local_bpr
= bprr
.bpr_found
;
1651 local_bpa
= local_bpr
->action
;
1652 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1659 temp
.flags
|= MATCH_IP_SRC_SET
;
1660 prefix_copy(&temp2
.src
, bpf
->src
);
1662 temp2
.src
.family
= AF_INET
;
1664 temp
.flags
|= MATCH_IP_DST_SET
;
1665 prefix_copy(&temp2
.dst
, bpf
->dst
);
1667 temp2
.dst
.family
= AF_INET
;
1668 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1669 if (bpf
->protocol
== IPPROTO_ICMP
)
1670 temp
.flags
|= MATCH_ICMP_SET
;
1671 temp
.flags
|= MATCH_PORT_SRC_SET
;
1672 temp2
.src_port_min
= src_port
->min_port
;
1673 if (src_port
->max_port
) {
1674 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1675 temp2
.src_port_max
= src_port
->max_port
;
1678 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1679 if (bpf
->protocol
== IPPROTO_ICMP
)
1680 temp
.flags
|= MATCH_ICMP_SET
;
1681 temp
.flags
|= MATCH_PORT_DST_SET
;
1682 temp2
.dst_port_min
= dst_port
->min_port
;
1683 if (dst_port
->max_port
) {
1684 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1685 temp2
.dst_port_max
= dst_port
->max_port
;
1688 temp2
.proto
= bpf
->protocol
;
1691 temp
.pkt_len_min
= pkt_len
->min_port
;
1692 if (pkt_len
->max_port
)
1693 temp
.pkt_len_max
= pkt_len
->max_port
;
1694 } else if (bpf
->pkt_len_val
) {
1695 if (bpf
->pkt_len_val
->mask
)
1696 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1697 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1699 if (bpf
->tcp_flags
) {
1700 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1701 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1704 if (bpf
->dscp
->mask
)
1705 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1707 temp
.flags
|= MATCH_DSCP_SET
;
1708 temp
.dscp_value
= bpf
->dscp
->val
;
1710 if (bpf
->fragment
) {
1711 if (bpf
->fragment
->mask
)
1712 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1713 temp
.fragment
= bpf
->fragment
->val
;
1716 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1717 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1718 temp
.type
= IPSET_NET_PORT
;
1720 temp
.type
= IPSET_NET
;
1722 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1723 temp
.type
= IPSET_NET_PORT_NET
;
1725 temp
.type
= IPSET_NET_NET
;
1727 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1730 temp
.vrf_id
= bpf
->vrf_id
;
1733 bpme
->backpointer
= bpm
;
1734 /* right now, a previous entry may already exist
1735 * flush previous entry if necessary
1737 bpmer
.bpme_to_match
= bpme
;
1738 bpmer
.bpme_found
= NULL
;
1739 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1740 if (bpmer
.bpme_found
) {
1741 static struct bgp_pbr_match
*local_bpm
;
1742 static struct bgp_pbr_action
*local_bpa
;
1744 local_bpm
= bpmer
.bpme_found
->backpointer
;
1745 local_bpa
= local_bpm
->action
;
1746 bgp_pbr_flush_entry(bgp
, local_bpa
,
1747 local_bpm
, bpmer
.bpme_found
);
1751 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1753 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1754 return FLOWSPEC_DSCP
;
1755 if (type_entry
== FLOWSPEC_DSCP
)
1756 return FLOWSPEC_PKT_LEN
;
1757 if (type_entry
== FLOWSPEC_PKT_LEN
)
1758 return FLOWSPEC_FRAGMENT
;
1759 if (type_entry
== FLOWSPEC_FRAGMENT
)
1760 return FLOWSPEC_ICMP_TYPE
;
1764 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1765 struct bgp_pbr_filter
*bpf
,
1766 struct bgp_pbr_or_filter
*bpof
, bool add
,
1767 struct nexthop
*nh
, float *rate
)
1769 struct bgp_pbr_range_port srcp
, dstp
;
1770 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1771 struct listnode
*tnode
, *cnode
;
1775 if (bpf
->protocol
!= IPPROTO_ICMP
)
1777 bpf
->src_port
= &srcp
;
1778 bpf
->dst_port
= &dstp
;
1779 /* parse icmp type and lookup appropriate icmp code
1780 * if no icmp code found, create as many entryes as
1781 * there are listed icmp codes for that icmp type
1783 if (!bpof
->icmp_type
) {
1785 srcp
.max_port
= 255;
1786 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1787 dstp
.min_port
= icmp_code
->val
;
1789 bgp_pbr_policyroute_add_to_zebra_unit(
1790 bgp
, path
, bpf
, nh
, rate
);
1792 bgp_pbr_policyroute_remove_from_zebra_unit(
1797 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1798 srcp
.min_port
= icmp_type
->val
;
1801 /* only icmp type. create an entry only with icmp type */
1802 if (!bpof
->icmp_code
) {
1803 /* icmp type is not one of the above
1804 * forge an entry only based on the icmp type
1807 dstp
.max_port
= 255;
1809 bgp_pbr_policyroute_add_to_zebra_unit(
1810 bgp
, path
, bpf
, nh
, rate
);
1812 bgp_pbr_policyroute_remove_from_zebra_unit(
1816 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1817 dstp
.min_port
= icmp_code
->val
;
1819 bgp_pbr_policyroute_add_to_zebra_unit(
1820 bgp
, path
, bpf
, nh
, rate
);
1822 bgp_pbr_policyroute_remove_from_zebra_unit(
1828 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1829 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1830 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1832 struct listnode
*node
, *nnode
;
1833 struct bgp_pbr_val_mask
*valmask
;
1834 uint8_t next_type_entry
;
1835 struct list
*orig_list
;
1836 struct bgp_pbr_val_mask
**target_val
;
1838 if (type_entry
== 0) {
1839 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1842 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1843 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1844 orig_list
= bpof
->tcpflags
;
1845 target_val
= &bpf
->tcp_flags
;
1846 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1847 orig_list
= bpof
->dscp
;
1848 target_val
= &bpf
->dscp
;
1849 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1850 orig_list
= bpof
->pkt_len
;
1851 target_val
= &bpf
->pkt_len_val
;
1852 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1853 orig_list
= bpof
->fragment
;
1854 target_val
= &bpf
->fragment
;
1855 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1856 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1857 /* enumerate list for icmp - must be last one */
1858 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1861 bgp_pbr_policyroute_remove_from_zebra_recursive(
1862 bgp
, path
, bpf
, bpof
, next_type_entry
);
1865 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1866 *target_val
= valmask
;
1867 bgp_pbr_policyroute_remove_from_zebra_recursive(
1868 bgp
, path
, bpf
, bpof
, next_type_entry
);
1872 static void bgp_pbr_policyroute_remove_from_zebra(
1873 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1874 struct bgp_pbr_or_filter
*bpof
)
1877 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1881 bgp_pbr_policyroute_remove_from_zebra_recursive(
1882 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1883 else if (bpof
->dscp
)
1884 bgp_pbr_policyroute_remove_from_zebra_recursive(
1885 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1886 else if (bpof
->pkt_len
)
1887 bgp_pbr_policyroute_remove_from_zebra_recursive(
1888 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1889 else if (bpof
->fragment
)
1890 bgp_pbr_policyroute_remove_from_zebra_recursive(
1891 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1892 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1893 bgp_pbr_policyroute_remove_from_zebra_recursive(
1894 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1896 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1899 list_delete_all_node(bpof
->tcpflags
);
1901 list_delete_all_node(bpof
->dscp
);
1903 list_delete_all_node(bpof
->pkt_len
);
1905 list_delete_all_node(bpof
->fragment
);
1908 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1910 struct bgp_pbr_range_port
*src_port
;
1911 struct bgp_pbr_range_port
*dst_port
;
1912 struct bgp_pbr_range_port
*pkt_len
;
1913 char bufsrc
[64], bufdst
[64];
1915 int remaining_len
= 0;
1916 char protocol_str
[16];
1920 src_port
= bpf
->src_port
;
1921 dst_port
= bpf
->dst_port
;
1922 pkt_len
= bpf
->pkt_len
;
1924 protocol_str
[0] = '\0';
1925 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1926 bpf
->protocol
= IPPROTO_TCP
;
1928 snprintf(protocol_str
, sizeof(protocol_str
),
1929 "proto %d", bpf
->protocol
);
1931 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1932 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1935 dst_port
->min_port
);
1936 else if (bpf
->protocol
== IPPROTO_UDP
||
1937 bpf
->protocol
== IPPROTO_TCP
) {
1939 if (src_port
&& src_port
->min_port
)
1940 remaining_len
+= snprintf(buffer
,
1944 src_port
->max_port
?
1945 src_port
->max_port
:
1946 src_port
->min_port
);
1947 if (dst_port
&& dst_port
->min_port
)
1948 remaining_len
+= snprintf(buffer
+
1954 dst_port
->max_port
?
1955 dst_port
->max_port
:
1956 dst_port
->min_port
);
1958 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1959 remaining_len
+= snprintf(buffer
+ remaining_len
,
1967 } else if (bpf
->pkt_len_val
) {
1968 remaining_len
+= snprintf(buffer
+ remaining_len
,
1972 bpf
->pkt_len_val
->mask
1974 bpf
->pkt_len_val
->val
);
1976 if (bpf
->tcp_flags
) {
1977 remaining_len
+= snprintf(buffer
+ remaining_len
,
1981 bpf
->tcp_flags
->val
,
1982 bpf
->tcp_flags
->mask
);
1985 snprintf(buffer
+ remaining_len
,
1993 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1994 add
? "adding" : "removing",
1995 bpf
->src
== NULL
? "<all>" :
1996 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1997 bpf
->dst
== NULL
? "<all>" :
1998 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1999 protocol_str
, buffer
);
2003 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
2004 struct bgp_path_info
*path
,
2005 struct bgp_pbr_filter
*bpf
,
2009 struct bgp_pbr_match temp
;
2010 struct bgp_pbr_match_entry temp2
;
2011 struct bgp_pbr_match
*bpm
;
2012 struct bgp_pbr_match_entry
*bpme
= NULL
;
2013 struct bgp_pbr_action temp3
;
2014 struct bgp_pbr_action
*bpa
= NULL
;
2015 struct bgp_pbr_match_entry_remain bpmer
;
2016 struct bgp_pbr_rule_remain bprr
;
2017 struct bgp_pbr_range_port
*src_port
;
2018 struct bgp_pbr_range_port
*dst_port
;
2019 struct bgp_pbr_range_port
*pkt_len
;
2020 struct bgp_pbr_rule pbr_rule
;
2021 struct bgp_pbr_rule
*bpr
;
2022 bool bpr_found
= false;
2023 bool bpme_found
= false;
2027 src_port
= bpf
->src_port
;
2028 dst_port
= bpf
->dst_port
;
2029 pkt_len
= bpf
->pkt_len
;
2031 if (BGP_DEBUG(zebra
, ZEBRA
))
2032 bgp_pbr_dump_entry(bpf
, true);
2034 /* look for bpa first */
2035 memset(&temp3
, 0, sizeof(temp3
));
2039 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2040 temp3
.vrf_id
= bpf
->vrf_id
;
2041 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2042 bgp_pbr_action_alloc_intern
);
2044 if (bpa
->fwmark
== 0) {
2045 /* drop is handled by iptable */
2046 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2048 bpa
->installed
= true;
2050 bpa
->fwmark
= bgp_zebra_tm_get_id();
2051 bpa
->table_id
= bpa
->fwmark
;
2052 bpa
->installed
= false;
2055 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2056 /* 0 value is forbidden */
2057 bpa
->install_in_progress
= false;
2059 if (bpf
->type
== BGP_PBR_IPRULE
) {
2060 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2061 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2062 pbr_rule
.priority
= 20;
2064 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2065 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2068 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2069 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2071 pbr_rule
.action
= bpa
;
2072 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2073 bgp_pbr_rule_alloc_intern
);
2074 if (bpr
&& bpr
->unique
== 0) {
2075 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2076 bpr
->installed
= false;
2077 bpr
->install_in_progress
= false;
2078 /* link bgp info to bpr */
2079 bpr
->path
= (void *)path
;
2082 /* already installed */
2083 if (bpr_found
&& bpr
) {
2084 struct bgp_path_info_extra
*extra
=
2085 bgp_path_info_extra_get(path
);
2088 listnode_lookup_nocheck(extra
->bgp_fs_iprule
,
2090 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2091 zlog_err("%s: entry %p/%p already "
2092 "installed in bgp pbr iprule",
2093 __func__
, path
, bpr
);
2097 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2098 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2099 bgp_zebra_announce_default(bgp
, nh
,
2100 AFI_IP
, bpa
->table_id
, true);
2103 if (bpr
&& !bpr
->installed
)
2104 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2106 /* A previous entry may already exist
2107 * flush previous entry if necessary
2109 bprr
.bpr_to_match
= bpr
;
2110 bprr
.bpr_found
= NULL
;
2111 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2112 if (bprr
.bpr_found
) {
2113 static struct bgp_pbr_rule
*local_bpr
;
2114 static struct bgp_pbr_action
*local_bpa
;
2116 local_bpr
= bprr
.bpr_found
;
2117 local_bpa
= local_bpr
->action
;
2118 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2123 /* then look for bpm */
2124 memset(&temp
, 0, sizeof(temp
));
2125 temp
.vrf_id
= bpf
->vrf_id
;
2127 temp
.flags
|= MATCH_IP_SRC_SET
;
2129 temp
.flags
|= MATCH_IP_DST_SET
;
2131 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2132 if (bpf
->protocol
== IPPROTO_ICMP
)
2133 temp
.flags
|= MATCH_ICMP_SET
;
2134 temp
.flags
|= MATCH_PORT_SRC_SET
;
2136 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2137 if (bpf
->protocol
== IPPROTO_ICMP
)
2138 temp
.flags
|= MATCH_ICMP_SET
;
2139 temp
.flags
|= MATCH_PORT_DST_SET
;
2141 if (src_port
&& src_port
->max_port
)
2142 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2143 if (dst_port
&& dst_port
->max_port
)
2144 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2146 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2147 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2148 temp
.type
= IPSET_NET_PORT
;
2150 temp
.type
= IPSET_NET
;
2152 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2153 temp
.type
= IPSET_NET_PORT_NET
;
2155 temp
.type
= IPSET_NET_NET
;
2158 temp
.pkt_len_min
= pkt_len
->min_port
;
2159 if (pkt_len
->max_port
)
2160 temp
.pkt_len_max
= pkt_len
->max_port
;
2161 } else if (bpf
->pkt_len_val
) {
2162 if (bpf
->pkt_len_val
->mask
)
2163 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2164 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2166 if (bpf
->tcp_flags
) {
2167 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2168 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2171 if (bpf
->dscp
->mask
)
2172 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2174 temp
.flags
|= MATCH_DSCP_SET
;
2175 temp
.dscp_value
= bpf
->dscp
->val
;
2177 if (bpf
->fragment
) {
2178 if (bpf
->fragment
->mask
)
2179 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2180 temp
.fragment
= bpf
->fragment
->val
;
2182 if (bpf
->protocol
) {
2183 temp
.protocol
= bpf
->protocol
;
2184 temp
.flags
|= MATCH_PROTOCOL_SET
;
2187 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2188 bgp_pbr_match_alloc_intern
);
2190 /* new, then self allocate ipset_name and unique */
2191 if (bpm
->unique
== 0) {
2192 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2193 /* 0 value is forbidden */
2194 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2195 bpm
->entry_hash
= hash_create_size(8,
2196 bgp_pbr_match_entry_hash_key
,
2197 bgp_pbr_match_entry_hash_equal
,
2198 "Match Entry Hash");
2199 bpm
->installed
= false;
2201 /* unique2 should be updated too */
2202 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2203 bpm
->installed_in_iptable
= false;
2204 bpm
->install_in_progress
= false;
2205 bpm
->install_iptable_in_progress
= false;
2208 memset(&temp2
, 0, sizeof(temp2
));
2210 prefix_copy(&temp2
.src
, bpf
->src
);
2212 temp2
.src
.family
= AF_INET
;
2214 prefix_copy(&temp2
.dst
, bpf
->dst
);
2216 temp2
.dst
.family
= AF_INET
;
2217 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2218 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2219 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2220 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2221 temp2
.proto
= bpf
->protocol
;
2222 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2223 bgp_pbr_match_entry_alloc_intern
);
2224 if (bpme
->unique
== 0) {
2225 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2226 /* 0 value is forbidden */
2227 bpme
->backpointer
= bpm
;
2228 bpme
->installed
= false;
2229 bpme
->install_in_progress
= false;
2230 /* link bgp info to bpme */
2231 bpme
->path
= (void *)path
;
2235 /* already installed */
2237 struct bgp_path_info_extra
*extra
=
2238 bgp_path_info_extra_get(path
);
2241 listnode_lookup_nocheck(extra
->bgp_fs_pbr
, bpme
)) {
2242 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2244 "%s: entry %p/%p already installed in bgp pbr",
2245 __func__
, path
, bpme
);
2249 /* BGP FS: append entry to zebra
2250 * - policies are not routing entries and as such
2251 * route replace semantics don't necessarily follow
2252 * through to policy entries
2253 * - because of that, not all policing information will be stored
2254 * into zebra. and non selected policies will be suppressed from zebra
2255 * - as consequence, in order to bring consistency
2256 * a policy will be added, then ifan ecmp policy exists,
2257 * it will be suppressed subsequently
2260 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2261 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2262 bgp_zebra_announce_default(bgp
, nh
,
2263 AFI_IP
, bpa
->table_id
, true);
2267 if (!bpm
->installed
)
2268 bgp_send_pbr_ipset_match(bpm
, true);
2270 if (!bpme
->installed
)
2271 bgp_send_pbr_ipset_entry_match(bpme
, true);
2274 if (!bpm
->installed_in_iptable
)
2275 bgp_send_pbr_iptable(bpa
, bpm
, true);
2277 /* A previous entry may already exist
2278 * flush previous entry if necessary
2280 bpmer
.bpme_to_match
= bpme
;
2281 bpmer
.bpme_found
= NULL
;
2282 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2283 if (bpmer
.bpme_found
) {
2284 static struct bgp_pbr_match
*local_bpm
;
2285 static struct bgp_pbr_action
*local_bpa
;
2287 local_bpm
= bpmer
.bpme_found
->backpointer
;
2288 local_bpa
= local_bpm
->action
;
2289 bgp_pbr_flush_entry(bgp
, local_bpa
,
2290 local_bpm
, bpmer
.bpme_found
);
2296 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2297 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2298 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2301 struct listnode
*node
, *nnode
;
2302 struct bgp_pbr_val_mask
*valmask
;
2303 uint8_t next_type_entry
;
2304 struct list
*orig_list
;
2305 struct bgp_pbr_val_mask
**target_val
;
2307 if (type_entry
== 0) {
2308 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2311 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2312 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2313 orig_list
= bpof
->tcpflags
;
2314 target_val
= &bpf
->tcp_flags
;
2315 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2316 orig_list
= bpof
->dscp
;
2317 target_val
= &bpf
->dscp
;
2318 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2319 orig_list
= bpof
->pkt_len
;
2320 target_val
= &bpf
->pkt_len_val
;
2321 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2322 orig_list
= bpof
->fragment
;
2323 target_val
= &bpf
->fragment
;
2324 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2325 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2326 /* enumerate list for icmp - must be last one */
2327 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2330 bgp_pbr_policyroute_add_to_zebra_recursive(
2331 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2334 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2335 *target_val
= valmask
;
2336 bgp_pbr_policyroute_add_to_zebra_recursive(
2337 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2341 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2342 struct bgp_path_info
*path
,
2343 struct bgp_pbr_filter
*bpf
,
2344 struct bgp_pbr_or_filter
*bpof
,
2345 struct nexthop
*nh
, float *rate
)
2348 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2352 bgp_pbr_policyroute_add_to_zebra_recursive(
2353 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2354 else if (bpof
->dscp
)
2355 bgp_pbr_policyroute_add_to_zebra_recursive(
2356 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2357 else if (bpof
->pkt_len
)
2358 bgp_pbr_policyroute_add_to_zebra_recursive(
2359 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2360 else if (bpof
->fragment
)
2361 bgp_pbr_policyroute_add_to_zebra_recursive(
2362 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2363 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2364 bgp_pbr_policyroute_add_to_zebra_recursive(
2365 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2367 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2370 list_delete_all_node(bpof
->tcpflags
);
2372 list_delete_all_node(bpof
->dscp
);
2374 list_delete_all_node(bpof
->pkt_len
);
2376 list_delete_all_node(bpof
->fragment
);
2377 if (bpof
->icmp_type
)
2378 list_delete_all_node(bpof
->icmp_type
);
2379 if (bpof
->icmp_code
)
2380 list_delete_all_node(bpof
->icmp_code
);
2383 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2384 struct bgp_pbr_entry_main
*api
, bool add
)
2388 int continue_loop
= 1;
2390 struct prefix
*src
= NULL
, *dst
= NULL
;
2392 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2393 struct bgp_pbr_range_port range
, range_icmp_code
;
2394 struct bgp_pbr_range_port pkt_len
;
2395 struct bgp_pbr_filter bpf
;
2397 struct bgp_pbr_or_filter bpof
;
2398 struct bgp_pbr_val_mask bpvm
;
2400 memset(&nh
, 0, sizeof(struct nexthop
));
2401 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2402 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2403 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2404 (api
->type
== BGP_PBR_IPRULE
&&
2405 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2406 src
= &api
->src_prefix
;
2407 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2408 (api
->type
== BGP_PBR_IPRULE
&&
2409 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2410 dst
= &api
->dst_prefix
;
2411 if (api
->type
== BGP_PBR_IPRULE
)
2412 bpf
.type
= api
->type
;
2413 memset(&nh
, 0, sizeof(struct nexthop
));
2414 nh
.vrf_id
= VRF_UNKNOWN
;
2415 if (api
->match_protocol_num
)
2416 proto
= (uint8_t)api
->protocol
[0].value
;
2417 /* if match_port is selected, then either src or dst port will be parsed
2418 * but not both at the same time
2420 if (api
->match_port_num
>= 1) {
2421 bgp_pbr_extract(api
->port
,
2422 api
->match_port_num
,
2424 srcp
= dstp
= &range
;
2425 } else if (api
->match_src_port_num
>= 1) {
2426 bgp_pbr_extract(api
->src_port
,
2427 api
->match_src_port_num
,
2431 } else if (api
->match_dst_port_num
>= 1) {
2432 bgp_pbr_extract(api
->dst_port
,
2433 api
->match_dst_port_num
,
2438 if (api
->match_icmp_type_num
>= 1) {
2439 proto
= IPPROTO_ICMP
;
2440 if (bgp_pbr_extract(api
->icmp_type
,
2441 api
->match_icmp_type_num
,
2445 bpof
.icmp_type
= list_new();
2446 bgp_pbr_extract_enumerate(api
->icmp_type
,
2447 api
->match_icmp_type_num
,
2450 FLOWSPEC_ICMP_TYPE
);
2453 if (api
->match_icmp_code_num
>= 1) {
2454 proto
= IPPROTO_ICMP
;
2455 if (bgp_pbr_extract(api
->icmp_code
,
2456 api
->match_icmp_code_num
,
2458 dstp
= &range_icmp_code
;
2460 bpof
.icmp_code
= list_new();
2461 bgp_pbr_extract_enumerate(api
->icmp_code
,
2462 api
->match_icmp_code_num
,
2465 FLOWSPEC_ICMP_CODE
);
2469 if (api
->match_tcpflags_num
) {
2470 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2471 api
->match_tcpflags_num
);
2472 if (kind_enum
== OPERATOR_UNARY_AND
) {
2473 bpf
.tcp_flags
= &bpvm
;
2474 bgp_pbr_extract_enumerate(api
->tcpflags
,
2475 api
->match_tcpflags_num
,
2478 FLOWSPEC_TCP_FLAGS
);
2479 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2480 bpof
.tcpflags
= list_new();
2481 bgp_pbr_extract_enumerate(api
->tcpflags
,
2482 api
->match_tcpflags_num
,
2485 FLOWSPEC_TCP_FLAGS
);
2488 if (api
->match_packet_length_num
) {
2491 ret
= bgp_pbr_extract(api
->packet_length
,
2492 api
->match_packet_length_num
,
2495 bpf
.pkt_len
= &pkt_len
;
2497 bpof
.pkt_len
= list_new();
2498 bgp_pbr_extract_enumerate(api
->packet_length
,
2499 api
->match_packet_length_num
,
2505 if (api
->match_dscp_num
>= 1) {
2506 bpof
.dscp
= list_new();
2507 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2509 bpof
.dscp
, FLOWSPEC_DSCP
);
2511 if (api
->match_fragment_num
) {
2512 bpof
.fragment
= list_new();
2513 bgp_pbr_extract_enumerate(api
->fragment
,
2514 api
->match_fragment_num
,
2519 bpf
.vrf_id
= api
->vrf_id
;
2522 bpf
.protocol
= proto
;
2523 bpf
.src_port
= srcp
;
2524 bpf
.dst_port
= dstp
;
2526 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2529 /* no action for add = true */
2530 for (i
= 0; i
< api
->action_num
; i
++) {
2531 switch (api
->actions
[i
].action
) {
2532 case ACTION_TRAFFICRATE
:
2534 if (api
->actions
[i
].u
.r
.rate
== 0) {
2535 nh
.vrf_id
= api
->vrf_id
;
2536 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2537 bgp_pbr_policyroute_add_to_zebra(
2538 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2540 /* update rate. can be reentrant */
2541 rate
= api
->actions
[i
].u
.r
.rate
;
2542 if (BGP_DEBUG(pbr
, PBR
)) {
2543 bgp_pbr_print_policy_route(api
);
2544 zlog_warn("PBR: ignoring Set action rate %f",
2545 api
->actions
[i
].u
.r
.rate
);
2549 case ACTION_TRAFFIC_ACTION
:
2550 if (api
->actions
[i
].u
.za
.filter
2551 & TRAFFIC_ACTION_SAMPLE
) {
2552 if (BGP_DEBUG(pbr
, PBR
)) {
2553 bgp_pbr_print_policy_route(api
);
2554 zlog_warn("PBR: Sample action Ignored");
2558 if (api
->actions
[i
].u
.za
.filter
2559 & TRAFFIC_ACTION_DISTRIBUTE
) {
2560 if (BGP_DEBUG(pbr
, PBR
)) {
2561 bgp_pbr_print_policy_route(api
);
2562 zlog_warn("PBR: Distribute action Applies");
2565 /* continue forwarding entry as before
2569 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2570 /* terminate action: run other filters
2573 case ACTION_REDIRECT_IP
:
2574 nh
.type
= NEXTHOP_TYPE_IPV4
;
2575 nh
.gate
.ipv4
.s_addr
=
2576 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2577 nh
.vrf_id
= api
->vrf_id
;
2578 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2580 /* XXX combination with REDIRECT_VRF
2581 * + REDIRECT_NH_IP not done
2585 case ACTION_REDIRECT
:
2586 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2587 nh
.type
= NEXTHOP_TYPE_IPV4
;
2588 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2592 case ACTION_MARKING
:
2593 if (BGP_DEBUG(pbr
, PBR
)) {
2594 bgp_pbr_print_policy_route(api
);
2595 zlog_warn("PBR: Set DSCP %u Ignored",
2596 api
->actions
[i
].u
.marking_dscp
);
2602 if (continue_loop
== 0)
2607 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2608 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2611 struct bgp_pbr_entry_main api
;
2614 return; /* IPv6 not supported */
2615 if (safi
!= SAFI_FLOWSPEC
)
2616 return; /* not supported */
2617 /* Make Zebra API structure. */
2618 memset(&api
, 0, sizeof(api
));
2619 api
.vrf_id
= bgp
->vrf_id
;
2622 if (!bgp_zebra_tm_chunk_obtained()) {
2623 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2624 flog_err(EC_BGP_TABLE_CHUNK
,
2625 "%s: table chunk not obtained yet", __func__
);
2629 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2630 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2631 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2632 "%s: cancel updating entry %p in bgp pbr",
2636 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2639 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2640 const struct bgp_pbr_interface
*b
)
2642 return strcmp(a
->name
, b
->name
);
2645 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2646 struct bgp_pbr_interface_head
*head
)
2648 struct bgp_pbr_interface pbr_if
;
2650 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2651 return (RB_FIND(bgp_pbr_interface_head
,
2655 /* this function resets to the default policy routing
2656 * go back to default status
2658 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2660 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2661 struct bgp_pbr_interface_head
*head
;
2662 struct bgp_pbr_interface
*pbr_if
;
2664 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2666 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2668 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2669 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2670 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2671 XFREE(MTYPE_TMP
, pbr_if
);