1 // SPDX-License-Identifier: GPL-2.0-or-later
13 #include "lib/printfrr.h"
15 #include "bgpd/bgpd.h"
16 #include "bgpd/bgp_pbr.h"
17 #include "bgpd/bgp_debug.h"
18 #include "bgpd/bgp_flowspec_util.h"
19 #include "bgpd/bgp_ecommunity.h"
20 #include "bgpd/bgp_route.h"
21 #include "bgpd/bgp_attr.h"
22 #include "bgpd/bgp_zebra.h"
23 #include "bgpd/bgp_mplsvpn.h"
24 #include "bgpd/bgp_flowspec_private.h"
25 #include "bgpd/bgp_errors.h"
27 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry");
28 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match");
29 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action");
30 DEFINE_MTYPE_STATIC(BGPD
, PBR_RULE
, "PBR rule");
31 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context");
32 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value");
34 /* chain strings too long to fit in one line */
35 #define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
36 #define IPV6_FRAGMENT_INVALID "fragment not valid for IPv6 for this implementation"
38 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
39 id_entry
, bgp_pbr_interface_compare
);
40 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
41 RB_INITIALIZER(&ifaces_by_name_ipv4
);
43 static int bgp_pbr_match_counter_unique
;
44 static int bgp_pbr_match_entry_counter_unique
;
45 static int bgp_pbr_action_counter_unique
;
46 static int bgp_pbr_match_iptable_counter_unique
;
48 struct bgp_pbr_match_iptable_unique
{
50 struct bgp_pbr_match
*bpm_found
;
53 struct bgp_pbr_match_entry_unique
{
55 struct bgp_pbr_match_entry
*bpme_found
;
58 struct bgp_pbr_action_unique
{
60 struct bgp_pbr_action
*bpa_found
;
63 struct bgp_pbr_rule_unique
{
65 struct bgp_pbr_rule
*bpr_found
;
68 static int bgp_pbr_rule_walkcb(struct hash_bucket
*bucket
, void *arg
)
70 struct bgp_pbr_rule
*bpr
= (struct bgp_pbr_rule
*)bucket
->data
;
71 struct bgp_pbr_rule_unique
*bpru
= (struct bgp_pbr_rule_unique
*)
73 uint32_t unique
= bpru
->unique
;
75 if (bpr
->unique
== unique
) {
76 bpru
->bpr_found
= bpr
;
77 return HASHWALK_ABORT
;
79 return HASHWALK_CONTINUE
;
82 static int bgp_pbr_action_walkcb(struct hash_bucket
*bucket
, void *arg
)
84 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)bucket
->data
;
85 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
87 uint32_t unique
= bpau
->unique
;
89 if (bpa
->unique
== unique
) {
90 bpau
->bpa_found
= bpa
;
91 return HASHWALK_ABORT
;
93 return HASHWALK_CONTINUE
;
96 static int bgp_pbr_match_entry_walkcb(struct hash_bucket
*bucket
, void *arg
)
98 struct bgp_pbr_match_entry
*bpme
=
99 (struct bgp_pbr_match_entry
*)bucket
->data
;
100 struct bgp_pbr_match_entry_unique
*bpmeu
=
101 (struct bgp_pbr_match_entry_unique
*)arg
;
102 uint32_t unique
= bpmeu
->unique
;
104 if (bpme
->unique
== unique
) {
105 bpmeu
->bpme_found
= bpme
;
106 return HASHWALK_ABORT
;
108 return HASHWALK_CONTINUE
;
111 struct bgp_pbr_match_ipsetname
{
113 struct bgp_pbr_match
*bpm_found
;
116 static int bgp_pbr_match_pername_walkcb(struct hash_bucket
*bucket
, void *arg
)
118 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
119 struct bgp_pbr_match_ipsetname
*bpmi
=
120 (struct bgp_pbr_match_ipsetname
*)arg
;
121 char *ipset_name
= bpmi
->ipsetname
;
123 if (!strncmp(ipset_name
, bpm
->ipset_name
,
124 ZEBRA_IPSET_NAME_SIZE
)) {
125 bpmi
->bpm_found
= bpm
;
126 return HASHWALK_ABORT
;
128 return HASHWALK_CONTINUE
;
131 static int bgp_pbr_match_iptable_walkcb(struct hash_bucket
*bucket
, void *arg
)
133 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
134 struct bgp_pbr_match_iptable_unique
*bpmiu
=
135 (struct bgp_pbr_match_iptable_unique
*)arg
;
136 uint32_t unique
= bpmiu
->unique
;
138 if (bpm
->unique2
== unique
) {
139 bpmiu
->bpm_found
= bpm
;
140 return HASHWALK_ABORT
;
142 return HASHWALK_CONTINUE
;
145 struct bgp_pbr_match_unique
{
147 struct bgp_pbr_match
*bpm_found
;
150 static int bgp_pbr_match_walkcb(struct hash_bucket
*bucket
, void *arg
)
152 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
153 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
155 uint32_t unique
= bpmu
->unique
;
157 if (bpm
->unique
== unique
) {
158 bpmu
->bpm_found
= bpm
;
159 return HASHWALK_ABORT
;
161 return HASHWALK_CONTINUE
;
164 static int snprintf_bgp_pbr_match_val(char *str
, int len
,
165 struct bgp_pbr_match_val
*mval
,
172 delta
= snprintf(ptr
, len
, "%s", prepend
);
176 if (mval
->unary_operator
& OPERATOR_UNARY_OR
) {
177 delta
= snprintf(ptr
, len
, ", or ");
181 if (mval
->unary_operator
& OPERATOR_UNARY_AND
) {
182 delta
= snprintf(ptr
, len
, ", and ");
187 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
) {
188 delta
= snprintf(ptr
, len
, "<");
192 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
) {
193 delta
= snprintf(ptr
, len
, ">");
197 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
) {
198 delta
= snprintf(ptr
, len
, "=");
202 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
) {
203 delta
= snprintf(ptr
, len
, "match");
207 ptr
+= snprintf(ptr
, len
, " %u", mval
->value
);
208 return (int)(ptr
- str
);
211 #define INCREMENT_DISPLAY(_ptr, _cnt, _len) do { \
215 sn_delta = snprintf((_ptr), (_len), "; ");\
216 (_len) -= sn_delta; \
217 (_ptr) += sn_delta; \
222 /* this structure can be used for port range,
223 * but also for other values range like packet length range
225 struct bgp_pbr_range_port
{
230 /* this structure can be used to filter with a mask
231 * for instance it supports not instructions like for
234 struct bgp_pbr_val_mask
{
239 /* this structure is used to pass instructs
240 * so that BGP can create pbr instructions to ZEBRA
242 struct bgp_pbr_filter
{
248 uint8_t bitmask_iprule
;
250 struct bgp_pbr_range_port
*pkt_len
;
251 struct bgp_pbr_range_port
*src_port
;
252 struct bgp_pbr_range_port
*dst_port
;
253 struct bgp_pbr_val_mask
*tcp_flags
;
254 struct bgp_pbr_val_mask
*dscp
;
255 struct bgp_pbr_val_mask
*flow_label
;
256 struct bgp_pbr_val_mask
*pkt_len_val
;
257 struct bgp_pbr_val_mask
*fragment
;
260 /* this structure is used to contain OR instructions
261 * so that BGP can create multiple pbr instructions
264 struct bgp_pbr_or_filter
{
265 struct list
*tcpflags
;
267 struct list
*flowlabel
;
268 struct list
*pkt_len
;
269 struct list
*fragment
;
270 struct list
*icmp_type
;
271 struct list
*icmp_code
;
274 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
275 struct bgp_path_info
*path
,
276 struct bgp_pbr_filter
*bpf
,
280 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
282 static bool bgp_pbr_extract_enumerate_unary_opposite(
283 uint8_t unary_operator
,
284 struct bgp_pbr_val_mask
*and_valmask
,
285 struct list
*or_valmask
, uint32_t value
,
288 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
289 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
291 TCP_HEADER_ALL_FLAGS
&
293 } else if (type_entry
== FLOWSPEC_DSCP
||
294 type_entry
== FLOWSPEC_FLOW_LABEL
||
295 type_entry
== FLOWSPEC_PKT_LEN
||
296 type_entry
== FLOWSPEC_FRAGMENT
) {
297 and_valmask
->val
= value
;
298 and_valmask
->mask
= 1; /* inverse */
300 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
301 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
302 sizeof(struct bgp_pbr_val_mask
));
303 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
304 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
306 TCP_HEADER_ALL_FLAGS
&
308 } else if (type_entry
== FLOWSPEC_DSCP
||
309 type_entry
== FLOWSPEC_FLOW_LABEL
||
310 type_entry
== FLOWSPEC_FRAGMENT
||
311 type_entry
== FLOWSPEC_PKT_LEN
) {
312 and_valmask
->val
= value
;
313 and_valmask
->mask
= 1; /* inverse */
315 listnode_add(or_valmask
, and_valmask
);
316 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
317 type_entry
== FLOWSPEC_ICMP_TYPE
)
322 /* TCP : FIN and SYN -> val = ALL; mask = 3
323 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
324 * other variables type: dscp, pkt len, fragment, flow label
325 * - value is copied in bgp_pbr_val_mask->val value
326 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
328 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
329 int num
, uint8_t unary_operator
,
330 void *valmask
, uint8_t type_entry
)
333 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
334 struct list
*or_valmask
= NULL
;
338 if (unary_operator
== OPERATOR_UNARY_AND
) {
339 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
340 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
341 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
342 or_valmask
= (struct list
*)valmask
;
345 for (i
= 0; i
< num
; i
++) {
346 if (i
!= 0 && list
[i
].unary_operator
!=
349 if (!(list
[i
].compare_operator
&
350 OPERATOR_COMPARE_EQUAL_TO
) &&
351 !(list
[i
].compare_operator
&
352 OPERATOR_COMPARE_EXACT_MATCH
)) {
353 if ((list
[i
].compare_operator
&
354 OPERATOR_COMPARE_LESS_THAN
) &&
355 (list
[i
].compare_operator
&
356 OPERATOR_COMPARE_GREATER_THAN
)) {
357 ret
= bgp_pbr_extract_enumerate_unary_opposite(
358 unary_operator
, and_valmask
,
359 or_valmask
, list
[i
].value
,
367 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
368 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
370 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
371 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
372 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
373 sizeof(struct bgp_pbr_val_mask
));
374 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
375 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
377 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
378 } else if (type_entry
== FLOWSPEC_DSCP
||
379 type_entry
== FLOWSPEC_FLOW_LABEL
||
380 type_entry
== FLOWSPEC_ICMP_TYPE
||
381 type_entry
== FLOWSPEC_ICMP_CODE
||
382 type_entry
== FLOWSPEC_FRAGMENT
||
383 type_entry
== FLOWSPEC_PKT_LEN
)
384 and_valmask
->val
= list
[i
].value
;
385 listnode_add(or_valmask
, and_valmask
);
388 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
389 && type_entry
== FLOWSPEC_TCP_FLAGS
)
390 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
394 /* if unary operator can either be UNARY_OR/AND/OR-AND.
395 * in the latter case, combinationf of both is not handled
397 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
398 int num
, uint8_t unary_operator
,
399 void *valmask
, uint8_t type_entry
)
402 uint8_t unary_operator_val
;
403 bool double_check
= false;
405 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
406 (unary_operator
& OPERATOR_UNARY_AND
)) {
407 unary_operator_val
= OPERATOR_UNARY_AND
;
410 unary_operator_val
= unary_operator
;
411 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
412 valmask
, type_entry
);
413 if (!ret
&& double_check
)
414 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
421 /* returns the unary operator that is in the list
422 * return 0 if both operators are used
424 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
429 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
431 for (i
= 0; i
< num
; i
++) {
434 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
435 unary_operator
= OPERATOR_UNARY_OR
;
436 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
437 && unary_operator
== OPERATOR_UNARY_OR
) ||
438 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
439 && unary_operator
== OPERATOR_UNARY_AND
))
442 return unary_operator
;
446 /* return true if extraction ok
448 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
450 struct bgp_pbr_range_port
*range
)
453 bool exact_match
= false;
456 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
460 for (i
= 0; i
< num
; i
++) {
461 if (i
!= 0 && (list
[i
].compare_operator
==
462 OPERATOR_COMPARE_EQUAL_TO
))
464 if (i
== 0 && (list
[i
].compare_operator
==
465 OPERATOR_COMPARE_EQUAL_TO
)) {
467 range
->min_port
= list
[i
].value
;
470 if (exact_match
&& i
> 0)
472 if (list
[i
].compare_operator
==
473 (OPERATOR_COMPARE_GREATER_THAN
+
474 OPERATOR_COMPARE_EQUAL_TO
)) {
476 range
->min_port
= list
[i
].value
;
477 } else if (list
[i
].compare_operator
==
478 (OPERATOR_COMPARE_LESS_THAN
+
479 OPERATOR_COMPARE_EQUAL_TO
)) {
481 range
->max_port
= list
[i
].value
;
482 } else if (list
[i
].compare_operator
==
483 OPERATOR_COMPARE_LESS_THAN
) {
485 range
->max_port
= list
[i
].value
- 1;
486 } else if (list
[i
].compare_operator
==
487 OPERATOR_COMPARE_GREATER_THAN
) {
489 range
->min_port
= list
[i
].value
+ 1;
495 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
497 bool enumerate_icmp
= false;
499 if (api
->type
== BGP_PBR_UNDEFINED
) {
500 if (BGP_DEBUG(pbr
, PBR
))
501 zlog_debug("BGP: pbr entry undefined. cancel.");
504 /* because bgp pbr entry may contain unsupported
505 * combinations, a message will be displayed here if
507 * for now, only match/set supported is
508 * - combination src/dst => redirect nexthop [ + rate]
509 * - combination src/dst => redirect VRF [ + rate]
510 * - combination src/dst => drop
511 * - combination srcport + @IP
513 if (api
->match_protocol_num
> 1) {
514 if (BGP_DEBUG(pbr
, PBR
))
515 zlog_debug("BGP: match protocol operations:multiple protocols ( %d). ignoring.",
516 api
->match_protocol_num
);
519 if (api
->src_prefix_offset
> 0 ||
520 api
->dst_prefix_offset
> 0) {
521 if (BGP_DEBUG(pbr
, PBR
))
522 zlog_debug("BGP: match prefix offset:"
523 "implementation does not support it.");
526 if (api
->match_protocol_num
== 1 &&
527 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
528 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
529 api
->protocol
[0].value
!= PROTOCOL_ICMPV6
&&
530 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
531 if (BGP_DEBUG(pbr
, PBR
))
532 zlog_debug("BGP: match protocol operations:protocol (%d) not supported. ignoring",
533 api
->match_protocol_num
);
536 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
537 if (BGP_DEBUG(pbr
, PBR
))
538 zlog_debug("BGP: match src port operations:too complex. ignoring.");
541 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
542 if (BGP_DEBUG(pbr
, PBR
))
543 zlog_debug("BGP: match dst port operations:too complex. ignoring.");
546 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
547 api
->match_tcpflags_num
,
549 OPERATOR_UNARY_OR
, NULL
,
550 FLOWSPEC_TCP_FLAGS
)) {
551 if (BGP_DEBUG(pbr
, PBR
))
552 zlog_debug("BGP: match tcp flags:too complex. ignoring.");
555 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
556 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
557 api
->match_icmp_type_num
,
558 OPERATOR_UNARY_OR
, NULL
,
559 FLOWSPEC_ICMP_TYPE
)) {
560 if (BGP_DEBUG(pbr
, PBR
))
561 zlog_debug("BGP: match icmp type operations:too complex. ignoring.");
564 enumerate_icmp
= true;
566 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
567 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
568 api
->match_icmp_code_num
,
569 OPERATOR_UNARY_OR
, NULL
,
570 FLOWSPEC_ICMP_CODE
)) {
571 if (BGP_DEBUG(pbr
, PBR
))
572 zlog_debug("BGP: match icmp code operations:too complex. ignoring.");
574 } else if (api
->match_icmp_type_num
> 1 &&
576 if (BGP_DEBUG(pbr
, PBR
))
577 zlog_debug("BGP: match icmp code is enumerate, and icmp type is not. too complex. ignoring.");
581 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
582 if (BGP_DEBUG(pbr
, PBR
))
583 zlog_debug("BGP: match port operations:too complex. ignoring.");
586 if (api
->match_packet_length_num
) {
589 ret
= bgp_pbr_extract(api
->packet_length
,
590 api
->match_packet_length_num
, NULL
);
592 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
593 api
->match_packet_length_num
,
595 | OPERATOR_UNARY_AND
,
596 NULL
, FLOWSPEC_PKT_LEN
);
598 if (BGP_DEBUG(pbr
, PBR
))
599 zlog_debug("BGP: match packet length operations:too complex. ignoring.");
603 if (api
->match_dscp_num
) {
604 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
605 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
606 NULL
, FLOWSPEC_DSCP
)) {
607 if (BGP_DEBUG(pbr
, PBR
))
608 zlog_debug("BGP: match DSCP operations:too complex. ignoring.");
612 if (api
->match_flowlabel_num
) {
613 if (api
->afi
== AFI_IP
) {
614 if (BGP_DEBUG(pbr
, PBR
))
615 zlog_debug("BGP: match Flow Label operations:"
619 if (!bgp_pbr_extract_enumerate(api
->flow_label
,
620 api
->match_flowlabel_num
,
621 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
622 NULL
, FLOWSPEC_FLOW_LABEL
)) {
623 if (BGP_DEBUG(pbr
, PBR
))
624 zlog_debug("BGP: match FlowLabel operations:"
625 "too complex. ignoring.");
628 if (BGP_DEBUG(pbr
, PBR
))
629 zlog_debug("BGP: match FlowLabel operations "
630 "not supported. ignoring.");
633 if (api
->match_fragment_num
) {
637 success
= bgp_pbr_extract_enumerate(api
->fragment
,
638 api
->match_fragment_num
,
640 | OPERATOR_UNARY_AND
,
641 NULL
, FLOWSPEC_FRAGMENT
);
645 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
646 if (api
->fragment
[i
].value
!= 1 &&
647 api
->fragment
[i
].value
!= 2 &&
648 api
->fragment
[i
].value
!= 4 &&
649 api
->fragment
[i
].value
!= 8) {
652 fail_str
, sizeof(fail_str
),
653 "Value not valid (%d) for this implementation",
654 api
->fragment
[i
].value
);
656 if (api
->afi
== AFI_IP6
&&
657 api
->fragment
[i
].value
== 1) {
659 snprintf(fail_str
, sizeof(fail_str
),
660 "IPv6 dont fragment match invalid (%d)",
661 api
->fragment
[i
].value
);
664 if (api
->afi
== AFI_IP6
) {
666 snprintf(fail_str
, sizeof(fail_str
),
667 "%s", IPV6_FRAGMENT_INVALID
);
670 snprintf(fail_str
, sizeof(fail_str
),
671 "too complex. ignoring");
673 if (BGP_DEBUG(pbr
, PBR
))
674 zlog_debug("BGP: match fragment operation (%d) %s",
675 api
->match_fragment_num
,
681 /* no combinations with both src_port and dst_port
682 * or port with src_port and dst_port
684 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
685 api
->match_port_num
> 3) {
686 if (BGP_DEBUG(pbr
, PBR
))
687 zlog_debug("BGP: match multiple port operations: too complex. ignoring.");
690 if ((api
->match_src_port_num
|| api
->match_dst_port_num
691 || api
->match_port_num
) && (api
->match_icmp_type_num
692 || api
->match_icmp_code_num
)) {
693 if (BGP_DEBUG(pbr
, PBR
))
694 zlog_debug("BGP: match multiple port/imcp operations: too complex. ignoring.");
697 /* iprule only supports redirect IP */
698 if (api
->type
== BGP_PBR_IPRULE
) {
701 for (i
= 0; i
< api
->action_num
; i
++) {
702 if (api
->actions
[i
].action
== ACTION_TRAFFICRATE
&&
703 api
->actions
[i
].u
.r
.rate
== 0) {
704 if (BGP_DEBUG(pbr
, PBR
)) {
705 bgp_pbr_print_policy_route(api
);
706 zlog_debug("BGP: iprule match actions drop not supported");
710 if (api
->actions
[i
].action
== ACTION_MARKING
) {
711 if (BGP_DEBUG(pbr
, PBR
)) {
712 bgp_pbr_print_policy_route(api
);
713 zlog_warn("PBR: iprule set DSCP/Flow Label %u not supported",
714 api
->actions
[i
].u
.marking_dscp
);
717 if (api
->actions
[i
].action
== ACTION_REDIRECT
) {
718 if (BGP_DEBUG(pbr
, PBR
)) {
719 bgp_pbr_print_policy_route(api
);
720 zlog_warn("PBR: iprule redirect VRF %u not supported",
721 api
->actions
[i
].u
.redirect_vrf
);
726 } else if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
727 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
728 if (BGP_DEBUG(pbr
, PBR
)) {
729 bgp_pbr_print_policy_route(api
);
730 zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
737 /* return -1 if build or validation failed */
739 int bgp_pbr_build_and_validate_entry(const struct prefix
*p
,
740 struct bgp_path_info
*path
,
741 struct bgp_pbr_entry_main
*api
)
744 uint32_t i
, action_count
= 0;
745 struct ecommunity
*ecom
;
746 struct ecommunity_val
*ecom_eval
;
747 struct bgp_pbr_entry_action
*api_action
;
748 struct prefix
*src
= NULL
, *dst
= NULL
;
749 int valid_prefix
= 0;
750 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
751 bool discard_action_found
= false;
752 afi_t afi
= family2afi(p
->u
.prefix_flowspec
.family
);
754 /* extract match from flowspec entries */
755 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
756 p
->u
.prefix_flowspec
.prefixlen
, api
, afi
);
759 /* extract actiosn from flowspec ecom list */
760 if (path
&& bgp_attr_get_ecommunity(path
->attr
)) {
761 ecom
= bgp_attr_get_ecommunity(path
->attr
);
762 for (i
= 0; i
< ecom
->size
; i
++) {
763 ecom_eval
= (struct ecommunity_val
*)
764 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
766 if (action_count
> ACTIONS_MAX_NUM
) {
767 if (BGP_DEBUG(pbr
, PBR_ERROR
))
769 EC_BGP_FLOWSPEC_PACKET
,
772 FSPEC_ACTION_EXCEED_LIMIT
,
776 api_action
= &api
->actions
[action_count
- 1];
778 if ((ecom_eval
->val
[1] ==
779 (char)ECOMMUNITY_REDIRECT_VRF
) &&
780 (ecom_eval
->val
[0] ==
781 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
783 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
785 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
786 struct ecommunity
*eckey
= ecommunity_new();
787 struct ecommunity_val ecom_copy
;
789 memcpy(&ecom_copy
, ecom_eval
,
790 sizeof(struct ecommunity_val
));
792 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
793 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
794 ecommunity_add_val(eckey
, &ecom_copy
,
797 api_action
->action
= ACTION_REDIRECT
;
798 api_action
->u
.redirect_vrf
=
799 get_first_vrf_for_redirect_with_rt(
801 ecommunity_free(&eckey
);
802 } else if ((ecom_eval
->val
[0] ==
803 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
804 (ecom_eval
->val
[1] ==
805 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
806 /* in case the 2 ecom present,
808 * draft-ietf-idr-flowspec-redirect
810 if (api_action_redirect_ip
&&
811 p
->u
.prefix_flowspec
.family
== AF_INET
) {
812 if (api_action_redirect_ip
->u
813 .zr
.redirect_ip_v4
.s_addr
816 if (path
->attr
->nexthop
.s_addr
819 api_action_redirect_ip
->u
.zr
820 .redirect_ip_v4
.s_addr
=
821 path
->attr
->nexthop
.s_addr
;
822 api_action_redirect_ip
->u
.zr
.duplicate
825 } else if (api_action_redirect_ip
&&
826 p
->u
.prefix_flowspec
.family
== AF_INET6
) {
827 if (memcmp(&api_action_redirect_ip
->u
830 sizeof(struct in6_addr
)))
832 if (path
->attr
->mp_nexthop_len
== 0 ||
833 path
->attr
->mp_nexthop_len
==
834 BGP_ATTR_NHLEN_IPV4
||
835 path
->attr
->mp_nexthop_len
==
836 BGP_ATTR_NHLEN_VPNV4
)
838 memcpy(&api_action_redirect_ip
->u
840 &path
->attr
->mp_nexthop_global
,
841 sizeof(struct in6_addr
));
842 api_action_redirect_ip
->u
.zr
.duplicate
845 } else if (p
->u
.prefix_flowspec
.family
==
847 api_action
->action
= ACTION_REDIRECT_IP
;
848 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
849 path
->attr
->nexthop
.s_addr
;
850 api_action
->u
.zr
.duplicate
=
852 api_action_redirect_ip
= api_action
;
853 } else if (p
->u
.prefix_flowspec
.family
==
855 api_action
->action
= ACTION_REDIRECT_IP
;
856 memcpy(&api_action
->u
858 &path
->attr
->mp_nexthop_global
,
859 sizeof(struct in6_addr
));
860 api_action
->u
.zr
.duplicate
862 api_action_redirect_ip
= api_action
;
864 } else if ((ecom_eval
->val
[0] ==
865 (char)ECOMMUNITY_ENCODE_IP
) &&
866 (ecom_eval
->val
[1] ==
867 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
868 /* in case the 2 ecom present,
869 * overwrite simpson draft
870 * update redirect ip fields
872 if (api_action_redirect_ip
) {
873 memcpy(&(api_action_redirect_ip
->u
874 .zr
.redirect_ip_v4
.s_addr
),
875 (ecom_eval
->val
+2), 4);
876 api_action_redirect_ip
->u
881 api_action
->action
= ACTION_REDIRECT_IP
;
882 memcpy(&(api_action
->u
883 .zr
.redirect_ip_v4
.s_addr
),
884 (ecom_eval
->val
+2), 4);
885 api_action
->u
.zr
.duplicate
=
887 api_action_redirect_ip
= api_action
;
890 if (ecom_eval
->val
[0] !=
891 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
893 ret
= ecommunity_fill_pbr_action(ecom_eval
,
898 if ((api_action
->action
== ACTION_TRAFFICRATE
)
899 && api
->actions
[i
].u
.r
.rate
== 0)
900 discard_action_found
= true;
905 if (path
&& path
->attr
&& bgp_attr_get_ipv6_ecommunity(path
->attr
)) {
906 struct ecommunity_val_ipv6
*ipv6_ecom_eval
;
908 ecom
= bgp_attr_get_ipv6_ecommunity(path
->attr
);
909 for (i
= 0; i
< ecom
->size
; i
++) {
910 ipv6_ecom_eval
= (struct ecommunity_val_ipv6
*)
911 (ecom
->val
+ (i
* ecom
->unit_size
));
913 if (action_count
> ACTIONS_MAX_NUM
) {
914 if (BGP_DEBUG(pbr
, PBR_ERROR
))
916 EC_BGP_FLOWSPEC_PACKET
,
917 "%s: flowspec actions exceeds limit (max %u)",
918 __func__
, action_count
);
921 api_action
= &api
->actions
[action_count
- 1];
922 if ((ipv6_ecom_eval
->val
[1] ==
923 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) &&
924 (ipv6_ecom_eval
->val
[0] ==
925 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)) {
926 struct ecommunity
*eckey
= ecommunity_new();
927 struct ecommunity_val_ipv6 ecom_copy
;
929 eckey
->unit_size
= IPV6_ECOMMUNITY_SIZE
;
930 memcpy(&ecom_copy
, ipv6_ecom_eval
,
931 sizeof(struct ecommunity_val_ipv6
));
932 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
933 ecommunity_add_val_ipv6(eckey
, &ecom_copy
,
935 api_action
->action
= ACTION_REDIRECT
;
936 api_action
->u
.redirect_vrf
=
937 get_first_vrf_for_redirect_with_rt(
939 ecommunity_free(&eckey
);
944 /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
945 * then reduce the API action list to that action
947 if (api
->action_num
> 1 && discard_action_found
) {
949 memset(&api
->actions
[0], 0,
950 sizeof(struct bgp_pbr_entry_action
));
951 api
->actions
[0].action
= ACTION_TRAFFICRATE
;
954 /* validate if incoming matc/action is compatible
955 * with our policy routing engine
957 if (!bgp_pbr_validate_policy_route(api
))
960 /* check inconsistency in the match rule */
961 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
962 src
= &api
->src_prefix
;
963 afi
= family2afi(src
->family
);
966 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
967 dst
= &api
->dst_prefix
;
968 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
969 if (BGP_DEBUG(pbr
, PBR
)) {
970 bgp_pbr_print_policy_route(api
);
971 zlog_debug("%s: inconsistency: no match for afi src and dst (%u/%u)",
972 __func__
, afi
, family2afi(dst
->family
));
980 static void bgp_pbr_match_entry_free(void *arg
)
982 struct bgp_pbr_match_entry
*bpme
;
984 bpme
= (struct bgp_pbr_match_entry
*)arg
;
986 if (bpme
->installed
) {
987 bgp_send_pbr_ipset_entry_match(bpme
, false);
988 bpme
->installed
= false;
989 bpme
->backpointer
= NULL
;
991 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
994 static void bgp_pbr_match_free(void *arg
)
996 struct bgp_pbr_match
*bpm
;
998 bpm
= (struct bgp_pbr_match
*)arg
;
1000 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
1002 if (hashcount(bpm
->entry_hash
) == 0) {
1003 /* delete iptable entry first */
1004 /* then delete ipset match */
1005 if (bpm
->installed
) {
1006 if (bpm
->installed_in_iptable
) {
1007 bgp_send_pbr_iptable(bpm
->action
,
1009 bpm
->installed_in_iptable
= false;
1010 bpm
->action
->refcnt
--;
1012 bgp_send_pbr_ipset_match(bpm
, false);
1013 bpm
->installed
= false;
1017 hash_free(bpm
->entry_hash
);
1019 XFREE(MTYPE_PBR_MATCH
, bpm
);
1022 static void *bgp_pbr_match_alloc_intern(void *arg
)
1024 struct bgp_pbr_match
*bpm
, *new;
1026 bpm
= (struct bgp_pbr_match
*)arg
;
1028 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
1029 memcpy(new, bpm
, sizeof(*bpm
));
1034 static void bgp_pbr_rule_free(void *arg
)
1036 struct bgp_pbr_rule
*bpr
;
1038 bpr
= (struct bgp_pbr_rule
*)arg
;
1041 if (bpr
->installed
) {
1042 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
1043 bpr
->installed
= false;
1044 bpr
->action
->refcnt
--;
1047 XFREE(MTYPE_PBR_RULE
, bpr
);
1050 static void *bgp_pbr_rule_alloc_intern(void *arg
)
1052 struct bgp_pbr_rule
*bpr
, *new;
1054 bpr
= (struct bgp_pbr_rule
*)arg
;
1056 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
1057 memcpy(new, bpr
, sizeof(*bpr
));
1062 static void bgp_pbr_bpa_remove(struct bgp_pbr_action
*bpa
)
1064 if ((bpa
->refcnt
== 0) && bpa
->installed
&& bpa
->table_id
!= 0) {
1065 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1066 bgp_zebra_announce_default(bpa
->bgp
, &bpa
->nh
, bpa
->afi
,
1067 bpa
->table_id
, false);
1068 bpa
->installed
= false;
1072 static void bgp_pbr_bpa_add(struct bgp_pbr_action
*bpa
)
1074 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1075 bgp_send_pbr_rule_action(bpa
, NULL
, true);
1076 bgp_zebra_announce_default(bpa
->bgp
, &bpa
->nh
, bpa
->afi
,
1077 bpa
->table_id
, true);
1081 static void bgp_pbr_action_free(void *arg
)
1083 struct bgp_pbr_action
*bpa
= arg
;
1085 bgp_pbr_bpa_remove(bpa
);
1087 XFREE(MTYPE_PBR_ACTION
, bpa
);
1090 static void *bgp_pbr_action_alloc_intern(void *arg
)
1092 struct bgp_pbr_action
*bpa
, *new;
1094 bpa
= (struct bgp_pbr_action
*)arg
;
1096 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
1098 memcpy(new, bpa
, sizeof(*bpa
));
1103 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
1105 struct bgp_pbr_match_entry
*bpme
, *new;
1107 bpme
= (struct bgp_pbr_match_entry
*)arg
;
1109 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
1111 memcpy(new, bpme
, sizeof(*bpme
));
1116 uint32_t bgp_pbr_match_hash_key(const void *arg
)
1118 const struct bgp_pbr_match
*pbm
= arg
;
1121 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
1122 key
= jhash_1word(pbm
->flags
, key
);
1123 key
= jhash_1word(pbm
->family
, key
);
1124 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
1125 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
1126 key
= jhash(&pbm
->tcp_flags
, 2, key
);
1127 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
1128 key
= jhash(&pbm
->dscp_value
, 1, key
);
1129 key
= jhash(&pbm
->flow_label
, 2, key
);
1130 key
= jhash(&pbm
->fragment
, 1, key
);
1131 key
= jhash(&pbm
->protocol
, 1, key
);
1132 return jhash_1word(pbm
->type
, key
);
1135 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
1137 const struct bgp_pbr_match
*r1
, *r2
;
1139 r1
= (const struct bgp_pbr_match
*)arg1
;
1140 r2
= (const struct bgp_pbr_match
*)arg2
;
1142 if (r1
->vrf_id
!= r2
->vrf_id
)
1145 if (r1
->family
!= r2
->family
)
1148 if (r1
->type
!= r2
->type
)
1151 if (r1
->flags
!= r2
->flags
)
1154 if (r1
->action
!= r2
->action
)
1157 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1160 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1163 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1166 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1169 if (r1
->dscp_value
!= r2
->dscp_value
)
1172 if (r1
->flow_label
!= r2
->flow_label
)
1175 if (r1
->fragment
!= r2
->fragment
)
1178 if (r1
->protocol
!= r2
->protocol
)
1183 uint32_t bgp_pbr_rule_hash_key(const void *arg
)
1185 const struct bgp_pbr_rule
*pbr
= arg
;
1188 key
= prefix_hash_key(&pbr
->src
);
1189 key
= jhash_1word(pbr
->vrf_id
, key
);
1190 key
= jhash_1word(pbr
->flags
, key
);
1191 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1194 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1196 const struct bgp_pbr_rule
*r1
, *r2
;
1198 r1
= (const struct bgp_pbr_rule
*)arg1
;
1199 r2
= (const struct bgp_pbr_rule
*)arg2
;
1201 if (r1
->vrf_id
!= r2
->vrf_id
)
1204 if (r1
->flags
!= r2
->flags
)
1207 if (r1
->action
!= r2
->action
)
1210 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1211 !prefix_same(&r1
->src
, &r2
->src
))
1214 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1215 !prefix_same(&r1
->dst
, &r2
->dst
))
1221 uint32_t bgp_pbr_match_entry_hash_key(const void *arg
)
1223 const struct bgp_pbr_match_entry
*pbme
;
1227 key
= prefix_hash_key(&pbme
->src
);
1228 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1229 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1230 key
= jhash(&pbme
->src_port_min
, 2, key
);
1231 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1232 key
= jhash(&pbme
->src_port_max
, 2, key
);
1233 key
= jhash(&pbme
->proto
, 1, key
);
1238 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1240 const struct bgp_pbr_match_entry
*r1
, *r2
;
1242 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1243 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1246 * on updates, comparing backpointer is not necessary
1247 * unique value is self calculated
1248 * rate is ignored for now
1251 if (!prefix_same(&r1
->src
, &r2
->src
))
1254 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1257 if (r1
->src_port_min
!= r2
->src_port_min
)
1260 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1263 if (r1
->src_port_max
!= r2
->src_port_max
)
1266 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1269 if (r1
->proto
!= r2
->proto
)
1275 uint32_t bgp_pbr_action_hash_key(const void *arg
)
1277 const struct bgp_pbr_action
*pbra
;
1281 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1282 key
= jhash_1word(pbra
->fwmark
, key
);
1283 key
= jhash_1word(pbra
->afi
, key
);
1287 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1289 const struct bgp_pbr_action
*r1
, *r2
;
1291 r1
= (const struct bgp_pbr_action
*)arg1
;
1292 r2
= (const struct bgp_pbr_action
*)arg2
;
1294 /* unique value is self calculated
1295 * table and fwmark is self calculated
1298 if (r1
->vrf_id
!= r2
->vrf_id
)
1301 if (r1
->afi
!= r2
->afi
)
1304 return nexthop_same(&r1
->nh
, &r2
->nh
);
1307 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1310 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1311 struct bgp_pbr_rule_unique bpru
;
1313 if (!bgp
|| unique
== 0)
1315 bpru
.unique
= unique
;
1316 bpru
.bpr_found
= NULL
;
1317 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1318 return bpru
.bpr_found
;
1321 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1324 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1325 struct bgp_pbr_action_unique bpau
;
1327 if (!bgp
|| unique
== 0)
1329 bpau
.unique
= unique
;
1330 bpau
.bpa_found
= NULL
;
1331 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1332 return bpau
.bpa_found
;
1335 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1338 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1339 struct bgp_pbr_match_unique bpmu
;
1341 if (!bgp
|| unique
== 0)
1343 bpmu
.unique
= unique
;
1344 bpmu
.bpm_found
= NULL
;
1345 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1346 return bpmu
.bpm_found
;
1349 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1353 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1354 struct bgp_pbr_match_entry_unique bpmeu
;
1355 struct bgp_pbr_match_ipsetname bpmi
;
1357 if (!bgp
|| unique
== 0)
1359 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1360 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1361 bpmi
.bpm_found
= NULL
;
1362 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1363 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1364 if (!bpmi
.bpm_found
)
1366 bpmeu
.bpme_found
= NULL
;
1367 bpmeu
.unique
= unique
;
1368 hash_walk(bpmi
.bpm_found
->entry_hash
,
1369 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1370 return bpmeu
.bpme_found
;
1373 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1376 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1377 struct bgp_pbr_match_iptable_unique bpmiu
;
1379 if (!bgp
|| unique
== 0)
1381 bpmiu
.unique
= unique
;
1382 bpmiu
.bpm_found
= NULL
;
1383 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1384 return bpmiu
.bpm_found
;
1387 void bgp_pbr_cleanup(struct bgp
*bgp
)
1389 if (bgp
->pbr_match_hash
) {
1390 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1391 hash_free(bgp
->pbr_match_hash
);
1392 bgp
->pbr_match_hash
= NULL
;
1394 if (bgp
->pbr_rule_hash
) {
1395 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1396 hash_free(bgp
->pbr_rule_hash
);
1397 bgp
->pbr_rule_hash
= NULL
;
1399 if (bgp
->pbr_action_hash
) {
1400 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1401 hash_free(bgp
->pbr_action_hash
);
1402 bgp
->pbr_action_hash
= NULL
;
1404 if (bgp
->bgp_pbr_cfg
== NULL
)
1406 bgp_pbr_reset(bgp
, AFI_IP
);
1407 bgp_pbr_reset(bgp
, AFI_IP6
);
1408 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1411 void bgp_pbr_init(struct bgp
*bgp
)
1413 bgp
->pbr_match_hash
=
1414 hash_create_size(8, bgp_pbr_match_hash_key
,
1415 bgp_pbr_match_hash_equal
,
1417 bgp
->pbr_action_hash
=
1418 hash_create_size(8, bgp_pbr_action_hash_key
,
1419 bgp_pbr_action_hash_equal
,
1420 "Match Hash Entry");
1422 bgp
->pbr_rule_hash
=
1423 hash_create_size(8, bgp_pbr_rule_hash_key
,
1424 bgp_pbr_rule_hash_equal
,
1427 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1428 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1431 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1434 char return_string
[512];
1435 char *ptr
= return_string
;
1437 int delta
, len
= sizeof(return_string
);
1439 delta
= snprintf(ptr
, sizeof(return_string
), "MATCH : ");
1442 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1443 struct prefix
*p
= &(api
->src_prefix
);
1445 if (api
->src_prefix_offset
)
1446 delta
= snprintfrr(ptr
, len
, "@src %pFX/off%u", p
,
1447 api
->src_prefix_offset
);
1449 delta
= snprintfrr(ptr
, len
, "@src %pFX", p
);
1452 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1454 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1455 struct prefix
*p
= &(api
->dst_prefix
);
1457 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1458 if (api
->dst_prefix_offset
)
1459 delta
= snprintfrr(ptr
, len
, "@dst %pFX/off%u", p
,
1460 api
->dst_prefix_offset
);
1462 delta
= snprintfrr(ptr
, len
, "@dst %pFX", p
);
1467 if (api
->match_protocol_num
)
1468 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1469 for (i
= 0; i
< api
->match_protocol_num
; i
++) {
1470 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->protocol
[i
],
1471 i
> 0 ? NULL
: "@proto ");
1476 if (api
->match_src_port_num
)
1477 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1478 for (i
= 0; i
< api
->match_src_port_num
; i
++) {
1479 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->src_port
[i
],
1480 i
> 0 ? NULL
: "@srcport ");
1485 if (api
->match_dst_port_num
)
1486 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1487 for (i
= 0; i
< api
->match_dst_port_num
; i
++) {
1488 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->dst_port
[i
],
1489 i
> 0 ? NULL
: "@dstport ");
1494 if (api
->match_port_num
)
1495 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1496 for (i
= 0; i
< api
->match_port_num
; i
++) {
1497 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->port
[i
],
1498 i
> 0 ? NULL
: "@port ");
1503 if (api
->match_icmp_type_num
)
1504 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1505 for (i
= 0; i
< api
->match_icmp_type_num
; i
++) {
1506 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->icmp_type
[i
],
1507 i
> 0 ? NULL
: "@icmptype ");
1512 if (api
->match_icmp_code_num
)
1513 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1514 for (i
= 0; i
< api
->match_icmp_code_num
; i
++) {
1515 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->icmp_code
[i
],
1516 i
> 0 ? NULL
: "@icmpcode ");
1521 if (api
->match_packet_length_num
)
1522 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1523 for (i
= 0; i
< api
->match_packet_length_num
; i
++) {
1524 delta
= snprintf_bgp_pbr_match_val(ptr
, len
,
1525 &api
->packet_length
[i
],
1526 i
> 0 ? NULL
: "@plen ");
1531 if (api
->match_dscp_num
)
1532 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1533 for (i
= 0; i
< api
->match_dscp_num
; i
++) {
1534 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->dscp
[i
],
1535 i
> 0 ? NULL
: "@dscp ");
1540 if (api
->match_flowlabel_num
)
1541 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1542 for (i
= 0; i
< api
->match_flowlabel_num
; i
++) {
1543 delta
= snprintf_bgp_pbr_match_val(ptr
, len
,
1544 &api
->flow_label
[i
],
1545 i
> 0 ? NULL
: "@flowlabel ");
1550 if (api
->match_tcpflags_num
)
1551 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1552 for (i
= 0; i
< api
->match_tcpflags_num
; i
++) {
1553 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->tcpflags
[i
],
1554 i
> 0 ? NULL
: "@tcpflags ");
1559 if (api
->match_fragment_num
)
1560 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1561 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
1562 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->fragment
[i
],
1563 i
> 0 ? NULL
: "@fragment ");
1568 len
= sizeof(return_string
);
1570 ptr
= return_string
;
1572 len
-= (ptr
- return_string
);
1573 delta
= snprintf(ptr
, len
, "; ");
1577 if (api
->action_num
) {
1578 delta
= snprintf(ptr
, len
, "SET : ");
1583 for (i
= 0; i
< api
->action_num
; i
++) {
1584 switch (api
->actions
[i
].action
) {
1585 case ACTION_TRAFFICRATE
:
1586 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1587 delta
= snprintf(ptr
, len
, "@set rate %f",
1588 api
->actions
[i
].u
.r
.rate
);
1592 case ACTION_TRAFFIC_ACTION
:
1593 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1594 delta
= snprintf(ptr
, len
, "@action ");
1597 if (api
->actions
[i
].u
.za
.filter
1598 & TRAFFIC_ACTION_TERMINATE
) {
1599 delta
= snprintf(ptr
, len
,
1600 " terminate (apply filter(s))");
1604 if (api
->actions
[i
].u
.za
.filter
1605 & TRAFFIC_ACTION_DISTRIBUTE
) {
1606 delta
= snprintf(ptr
, len
, " distribute");
1610 if (api
->actions
[i
].u
.za
.filter
1611 & TRAFFIC_ACTION_SAMPLE
) {
1612 delta
= snprintf(ptr
, len
, " sample");
1617 case ACTION_REDIRECT_IP
: {
1618 char local_buff
[INET6_ADDRSTRLEN
];
1621 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1622 if (api
->afi
== AF_INET
)
1623 ptr_ip
= &api
->actions
[i
].u
.zr
.redirect_ip_v4
;
1625 ptr_ip
= &api
->actions
[i
].u
.zr
.redirect_ip_v6
;
1626 if (inet_ntop(afi2family(api
->afi
), ptr_ip
, local_buff
,
1627 sizeof(local_buff
)) != NULL
) {
1628 delta
= snprintf(ptr
, len
,
1629 "@redirect ip nh %s", local_buff
);
1635 case ACTION_REDIRECT
: {
1638 vrf
= vrf_lookup_by_id(api
->actions
[i
].u
.redirect_vrf
);
1639 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1640 delta
= snprintf(ptr
, len
, "@redirect vrf %s(%u)",
1642 api
->actions
[i
].u
.redirect_vrf
);
1647 case ACTION_MARKING
:
1648 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1649 delta
= snprintf(ptr
, len
, "@set dscp/flowlabel %u",
1650 api
->actions
[i
].u
.marking_dscp
);
1658 zlog_info("%s", return_string
);
1661 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1662 struct bgp_pbr_rule
*bpr
)
1664 /* if bpr is null, do nothing
1668 if (bpr
->installed
) {
1669 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1670 bpr
->installed
= false;
1671 bpr
->action
->refcnt
--;
1674 struct bgp_path_info
*path
;
1675 struct bgp_path_info_extra
*extra
;
1677 /* unlink path to bpme */
1678 path
= (struct bgp_path_info
*)bpr
->path
;
1679 extra
= bgp_path_info_extra_get(path
);
1680 if (extra
->bgp_fs_iprule
)
1681 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1685 hash_release(bgp
->pbr_rule_hash
, bpr
);
1686 bgp_pbr_bpa_remove(bpa
);
1689 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1690 struct bgp_pbr_match
*bpm
,
1691 struct bgp_pbr_match_entry
*bpme
)
1693 /* if bpme is null, bpm is also null
1697 /* ipset del entry */
1698 if (bpme
->installed
) {
1699 bgp_send_pbr_ipset_entry_match(bpme
, false);
1700 bpme
->installed
= false;
1701 bpme
->backpointer
= NULL
;
1703 struct bgp_path_info
*path
;
1704 struct bgp_path_info_extra
*extra
;
1706 /* unlink path to bpme */
1707 path
= (struct bgp_path_info
*)bpme
->path
;
1708 extra
= bgp_path_info_extra_get(path
);
1709 if (extra
->bgp_fs_pbr
)
1710 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1714 hash_release(bpm
->entry_hash
, bpme
);
1715 if (hashcount(bpm
->entry_hash
) == 0) {
1716 /* delete iptable entry first */
1717 /* then delete ipset match */
1718 if (bpm
->installed
) {
1719 if (bpm
->installed_in_iptable
) {
1720 bgp_send_pbr_iptable(bpm
->action
,
1722 bpm
->installed_in_iptable
= false;
1723 bpm
->action
->refcnt
--;
1725 bgp_send_pbr_ipset_match(bpm
, false);
1726 bpm
->installed
= false;
1729 hash_release(bgp
->pbr_match_hash
, bpm
);
1730 /* XXX release pbr_match_action if not used
1731 * note that drop does not need to call send_pbr_action
1734 bgp_pbr_bpa_remove(bpa
);
1737 struct bgp_pbr_match_entry_remain
{
1738 struct bgp_pbr_match_entry
*bpme_to_match
;
1739 struct bgp_pbr_match_entry
*bpme_found
;
1742 struct bgp_pbr_rule_remain
{
1743 struct bgp_pbr_rule
*bpr_to_match
;
1744 struct bgp_pbr_rule
*bpr_found
;
1747 static int bgp_pbr_get_same_rule(struct hash_bucket
*bucket
, void *arg
)
1749 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)bucket
->data
;
1750 struct bgp_pbr_rule_remain
*ctxt
=
1751 (struct bgp_pbr_rule_remain
*)arg
;
1752 struct bgp_pbr_rule
*r2
;
1754 r2
= ctxt
->bpr_to_match
;
1756 if (r1
->vrf_id
!= r2
->vrf_id
)
1757 return HASHWALK_CONTINUE
;
1759 if (r1
->flags
!= r2
->flags
)
1760 return HASHWALK_CONTINUE
;
1762 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1763 !prefix_same(&r1
->src
, &r2
->src
))
1764 return HASHWALK_CONTINUE
;
1766 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1767 !prefix_same(&r1
->dst
, &r2
->dst
))
1768 return HASHWALK_CONTINUE
;
1770 /* this function is used for two cases:
1771 * - remove an entry upon withdraw request
1772 * (case r2->action is null)
1773 * - replace an old iprule with different action
1774 * (case r2->action is != null)
1775 * the old one is removed after the new one
1776 * this is to avoid disruption in traffic
1778 if (r2
->action
== NULL
||
1779 r1
->action
!= r2
->action
) {
1780 ctxt
->bpr_found
= r1
;
1781 return HASHWALK_ABORT
;
1783 return HASHWALK_CONTINUE
;
1786 static int bgp_pbr_get_remaining_entry(struct hash_bucket
*bucket
, void *arg
)
1788 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
1789 struct bgp_pbr_match_entry_remain
*bpmer
=
1790 (struct bgp_pbr_match_entry_remain
*)arg
;
1791 struct bgp_pbr_match
*bpm_temp
;
1792 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1794 if (!bpme
->backpointer
||
1795 bpm
== bpme
->backpointer
||
1796 bpme
->backpointer
->action
== bpm
->action
)
1797 return HASHWALK_CONTINUE
;
1798 /* ensure bpm other characteristics are equal */
1799 bpm_temp
= bpme
->backpointer
;
1800 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1801 bpm_temp
->type
!= bpm
->type
||
1802 bpm_temp
->flags
!= bpm
->flags
||
1803 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1804 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1805 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1806 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1807 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1808 bpm_temp
->flow_label
!= bpm
->flow_label
||
1809 bpm_temp
->family
!= bpm
->family
||
1810 bpm_temp
->fragment
!= bpm
->fragment
)
1811 return HASHWALK_CONTINUE
;
1813 /* look for remaining bpme */
1814 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1815 if (!bpmer
->bpme_found
)
1816 return HASHWALK_CONTINUE
;
1817 return HASHWALK_ABORT
;
1820 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1821 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1823 struct bgp_pbr_match temp
;
1824 struct bgp_pbr_match_entry temp2
;
1825 struct bgp_pbr_rule pbr_rule
;
1826 struct bgp_pbr_rule
*bpr
;
1827 struct bgp_pbr_match
*bpm
;
1828 struct bgp_pbr_match_entry
*bpme
;
1829 struct bgp_pbr_match_entry_remain bpmer
;
1830 struct bgp_pbr_range_port
*src_port
;
1831 struct bgp_pbr_range_port
*dst_port
;
1832 struct bgp_pbr_range_port
*pkt_len
;
1833 struct bgp_pbr_rule_remain bprr
;
1837 src_port
= bpf
->src_port
;
1838 dst_port
= bpf
->dst_port
;
1839 pkt_len
= bpf
->pkt_len
;
1841 if (BGP_DEBUG(zebra
, ZEBRA
))
1842 bgp_pbr_dump_entry(bpf
, false);
1844 /* as we don't know information from EC
1845 * look for bpm that have the bpm
1846 * with vrf_id characteristics
1848 memset(&temp2
, 0, sizeof(temp2
));
1849 memset(&temp
, 0, sizeof(temp
));
1851 if (bpf
->type
== BGP_PBR_IPRULE
) {
1852 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1853 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1855 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1856 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1859 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1860 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1863 /* A previous entry may already exist
1864 * flush previous entry if necessary
1866 bprr
.bpr_to_match
= bpr
;
1867 bprr
.bpr_found
= NULL
;
1868 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1869 if (bprr
.bpr_found
) {
1870 static struct bgp_pbr_rule
*local_bpr
;
1871 static struct bgp_pbr_action
*local_bpa
;
1873 local_bpr
= bprr
.bpr_found
;
1874 local_bpa
= local_bpr
->action
;
1875 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1881 temp
.family
= bpf
->family
;
1883 temp
.flags
|= MATCH_IP_SRC_SET
;
1884 prefix_copy(&temp2
.src
, bpf
->src
);
1886 temp2
.src
.family
= bpf
->family
;
1888 temp
.flags
|= MATCH_IP_DST_SET
;
1889 prefix_copy(&temp2
.dst
, bpf
->dst
);
1891 temp2
.dst
.family
= bpf
->family
;
1892 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1893 if (bpf
->protocol
== IPPROTO_ICMP
)
1894 temp
.flags
|= MATCH_ICMP_SET
;
1895 temp
.flags
|= MATCH_PORT_SRC_SET
;
1896 temp2
.src_port_min
= src_port
->min_port
;
1897 if (src_port
->max_port
) {
1898 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1899 temp2
.src_port_max
= src_port
->max_port
;
1902 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1903 if (bpf
->protocol
== IPPROTO_ICMP
)
1904 temp
.flags
|= MATCH_ICMP_SET
;
1905 temp
.flags
|= MATCH_PORT_DST_SET
;
1906 temp2
.dst_port_min
= dst_port
->min_port
;
1907 if (dst_port
->max_port
) {
1908 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1909 temp2
.dst_port_max
= dst_port
->max_port
;
1912 temp2
.proto
= bpf
->protocol
;
1915 temp
.pkt_len_min
= pkt_len
->min_port
;
1916 if (pkt_len
->max_port
)
1917 temp
.pkt_len_max
= pkt_len
->max_port
;
1918 } else if (bpf
->pkt_len_val
) {
1919 if (bpf
->pkt_len_val
->mask
)
1920 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1921 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1923 if (bpf
->tcp_flags
) {
1924 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1925 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1928 if (bpf
->dscp
->mask
)
1929 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1931 temp
.flags
|= MATCH_DSCP_SET
;
1932 temp
.dscp_value
= bpf
->dscp
->val
;
1934 if (bpf
->flow_label
) {
1935 if (bpf
->flow_label
->mask
)
1936 temp
.flags
|= MATCH_FLOW_LABEL_INVERSE_SET
;
1938 temp
.flags
|= MATCH_FLOW_LABEL_SET
;
1939 temp
.flow_label
= bpf
->flow_label
->val
;
1942 if (bpf
->fragment
) {
1943 if (bpf
->fragment
->mask
)
1944 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1945 temp
.fragment
= bpf
->fragment
->val
;
1948 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1949 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1950 temp
.type
= IPSET_NET_PORT
;
1952 temp
.type
= IPSET_NET
;
1954 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1955 temp
.type
= IPSET_NET_PORT_NET
;
1957 temp
.type
= IPSET_NET_NET
;
1959 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1960 temp
.vrf_id
= VRF_DEFAULT
;
1962 temp
.vrf_id
= bpf
->vrf_id
;
1965 bpme
->backpointer
= bpm
;
1966 /* right now, a previous entry may already exist
1967 * flush previous entry if necessary
1969 bpmer
.bpme_to_match
= bpme
;
1970 bpmer
.bpme_found
= NULL
;
1971 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1972 if (bpmer
.bpme_found
) {
1973 static struct bgp_pbr_match
*local_bpm
;
1974 static struct bgp_pbr_action
*local_bpa
;
1976 local_bpm
= bpmer
.bpme_found
->backpointer
;
1977 local_bpa
= local_bpm
->action
;
1978 bgp_pbr_flush_entry(bgp
, local_bpa
,
1979 local_bpm
, bpmer
.bpme_found
);
1983 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1985 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1986 return FLOWSPEC_DSCP
;
1987 if (type_entry
== FLOWSPEC_DSCP
)
1988 return FLOWSPEC_FLOW_LABEL
;
1989 if (type_entry
== FLOWSPEC_FLOW_LABEL
)
1990 return FLOWSPEC_PKT_LEN
;
1991 if (type_entry
== FLOWSPEC_PKT_LEN
)
1992 return FLOWSPEC_FRAGMENT
;
1993 if (type_entry
== FLOWSPEC_FRAGMENT
)
1994 return FLOWSPEC_ICMP_TYPE
;
1998 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1999 struct bgp_pbr_filter
*bpf
,
2000 struct bgp_pbr_or_filter
*bpof
, bool add
,
2001 struct nexthop
*nh
, float *rate
)
2003 struct bgp_pbr_range_port srcp
, dstp
;
2004 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
2005 struct listnode
*tnode
, *cnode
;
2009 if (bpf
->protocol
!= IPPROTO_ICMP
)
2012 memset(&srcp
, 0, sizeof(srcp
));
2013 memset(&dstp
, 0, sizeof(dstp
));
2014 bpf
->src_port
= &srcp
;
2015 bpf
->dst_port
= &dstp
;
2016 /* parse icmp type and lookup appropriate icmp code
2017 * if no icmp code found, create as many entryes as
2018 * there are listed icmp codes for that icmp type
2020 if (!bpof
->icmp_type
) {
2022 srcp
.max_port
= 255;
2023 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
2024 dstp
.min_port
= icmp_code
->val
;
2026 bgp_pbr_policyroute_add_to_zebra_unit(
2027 bgp
, path
, bpf
, nh
, rate
);
2029 bgp_pbr_policyroute_remove_from_zebra_unit(
2034 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
2035 srcp
.min_port
= icmp_type
->val
;
2038 /* only icmp type. create an entry only with icmp type */
2039 if (!bpof
->icmp_code
) {
2040 /* icmp type is not one of the above
2041 * forge an entry only based on the icmp type
2044 dstp
.max_port
= 255;
2046 bgp_pbr_policyroute_add_to_zebra_unit(
2047 bgp
, path
, bpf
, nh
, rate
);
2049 bgp_pbr_policyroute_remove_from_zebra_unit(
2053 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
2054 dstp
.min_port
= icmp_code
->val
;
2056 bgp_pbr_policyroute_add_to_zebra_unit(
2057 bgp
, path
, bpf
, nh
, rate
);
2059 bgp_pbr_policyroute_remove_from_zebra_unit(
2064 bpf
->src_port
= NULL
;
2065 bpf
->dst_port
= NULL
;
2068 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
2069 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2070 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
2072 struct listnode
*node
, *nnode
;
2073 struct bgp_pbr_val_mask
*valmask
;
2074 uint8_t next_type_entry
;
2075 struct list
*orig_list
;
2076 struct bgp_pbr_val_mask
**target_val
;
2078 if (type_entry
== 0) {
2079 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2082 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2083 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2084 orig_list
= bpof
->tcpflags
;
2085 target_val
= &bpf
->tcp_flags
;
2086 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2087 orig_list
= bpof
->dscp
;
2088 target_val
= &bpf
->dscp
;
2089 } else if (type_entry
== FLOWSPEC_FLOW_LABEL
&& bpof
->flowlabel
) {
2090 orig_list
= bpof
->flowlabel
;
2091 target_val
= &bpf
->flow_label
;
2092 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2093 orig_list
= bpof
->pkt_len
;
2094 target_val
= &bpf
->pkt_len_val
;
2095 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2096 orig_list
= bpof
->fragment
;
2097 target_val
= &bpf
->fragment
;
2098 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2099 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2100 /* enumerate list for icmp - must be last one */
2101 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
2104 bgp_pbr_policyroute_remove_from_zebra_recursive(
2105 bgp
, path
, bpf
, bpof
, next_type_entry
);
2108 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2109 *target_val
= valmask
;
2110 bgp_pbr_policyroute_remove_from_zebra_recursive(
2111 bgp
, path
, bpf
, bpof
, next_type_entry
);
2115 static void bgp_pbr_policyroute_remove_from_zebra(
2116 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2117 struct bgp_pbr_or_filter
*bpof
)
2120 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2124 bgp_pbr_policyroute_remove_from_zebra_recursive(
2125 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
2126 else if (bpof
->dscp
)
2127 bgp_pbr_policyroute_remove_from_zebra_recursive(
2128 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
2129 else if (bpof
->flowlabel
)
2130 bgp_pbr_policyroute_remove_from_zebra_recursive(
2131 bgp
, path
, bpf
, bpof
, FLOWSPEC_FLOW_LABEL
);
2132 else if (bpof
->pkt_len
)
2133 bgp_pbr_policyroute_remove_from_zebra_recursive(
2134 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
2135 else if (bpof
->fragment
)
2136 bgp_pbr_policyroute_remove_from_zebra_recursive(
2137 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
2138 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2139 bgp_pbr_policyroute_remove_from_zebra_recursive(
2140 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
2142 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2145 list_delete_all_node(bpof
->tcpflags
);
2147 list_delete_all_node(bpof
->dscp
);
2148 if (bpof
->flowlabel
)
2149 list_delete_all_node(bpof
->flowlabel
);
2151 list_delete_all_node(bpof
->pkt_len
);
2153 list_delete_all_node(bpof
->fragment
);
2156 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
2158 struct bgp_pbr_range_port
*src_port
;
2159 struct bgp_pbr_range_port
*dst_port
;
2160 struct bgp_pbr_range_port
*pkt_len
;
2161 char bufsrc
[64], bufdst
[64];
2163 int remaining_len
= 0;
2164 char protocol_str
[16];
2168 src_port
= bpf
->src_port
;
2169 dst_port
= bpf
->dst_port
;
2170 pkt_len
= bpf
->pkt_len
;
2172 protocol_str
[0] = '\0';
2173 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
2174 bpf
->protocol
= IPPROTO_TCP
;
2176 snprintf(protocol_str
, sizeof(protocol_str
),
2177 "proto %d", bpf
->protocol
);
2179 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
2180 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
2183 dst_port
->min_port
);
2184 else if (bpf
->protocol
== IPPROTO_UDP
||
2185 bpf
->protocol
== IPPROTO_TCP
) {
2187 if (src_port
&& src_port
->min_port
)
2188 remaining_len
+= snprintf(buffer
,
2192 src_port
->max_port
?
2193 src_port
->max_port
:
2194 src_port
->min_port
);
2195 if (dst_port
&& dst_port
->min_port
)
2196 remaining_len
+= snprintf(buffer
+
2202 dst_port
->max_port
?
2203 dst_port
->max_port
:
2204 dst_port
->min_port
);
2206 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
2207 remaining_len
+= snprintf(buffer
+ remaining_len
,
2215 } else if (bpf
->pkt_len_val
) {
2216 remaining_len
+= snprintf(buffer
+ remaining_len
,
2220 bpf
->pkt_len_val
->mask
2222 bpf
->pkt_len_val
->val
);
2224 if (bpf
->tcp_flags
) {
2225 remaining_len
+= snprintf(buffer
+ remaining_len
,
2229 bpf
->tcp_flags
->val
,
2230 bpf
->tcp_flags
->mask
);
2233 snprintf(buffer
+ remaining_len
,
2241 if (bpf
->flow_label
) {
2242 snprintf(buffer
+ remaining_len
,
2246 bpf
->flow_label
->mask
2248 bpf
->flow_label
->val
);
2250 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
2251 add
? "adding" : "removing",
2252 bpf
->src
== NULL
? "<all>" :
2253 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
2254 bpf
->dst
== NULL
? "<all>" :
2255 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
2256 protocol_str
, buffer
);
2260 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
2261 struct bgp_path_info
*path
,
2262 struct bgp_pbr_filter
*bpf
,
2266 struct bgp_pbr_match temp
;
2267 struct bgp_pbr_match_entry temp2
;
2268 struct bgp_pbr_match
*bpm
;
2269 struct bgp_pbr_match_entry
*bpme
= NULL
;
2270 struct bgp_pbr_action temp3
;
2271 struct bgp_pbr_action
*bpa
= NULL
;
2272 struct bgp_pbr_match_entry_remain bpmer
;
2273 struct bgp_pbr_rule_remain bprr
;
2274 struct bgp_pbr_range_port
*src_port
;
2275 struct bgp_pbr_range_port
*dst_port
;
2276 struct bgp_pbr_range_port
*pkt_len
;
2277 struct bgp_pbr_rule pbr_rule
;
2278 struct bgp_pbr_rule
*bpr
;
2279 bool bpr_found
= false;
2280 bool bpme_found
= false;
2281 struct vrf
*vrf
= NULL
;
2285 src_port
= bpf
->src_port
;
2286 dst_port
= bpf
->dst_port
;
2287 pkt_len
= bpf
->pkt_len
;
2289 if (BGP_DEBUG(zebra
, ZEBRA
))
2290 bgp_pbr_dump_entry(bpf
, true);
2292 /* look for bpa first */
2293 memset(&temp3
, 0, sizeof(temp3
));
2297 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2298 temp3
.vrf_id
= bpf
->vrf_id
;
2299 temp3
.afi
= family2afi(bpf
->family
);
2300 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2301 bgp_pbr_action_alloc_intern
);
2304 vrf
= vrf_lookup_by_id(nh
->vrf_id
);
2305 if (bpa
->fwmark
== 0) {
2306 /* drop is handled by iptable */
2307 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2309 bpa
->installed
= true;
2311 bpa
->fwmark
= bgp_zebra_tm_get_id();
2312 /* if action is redirect-vrf, then
2313 * use directly table_id of vrf
2315 if (nh
&& vrf
&& !vrf_is_backend_netns()
2316 && bpf
->vrf_id
!= vrf
->vrf_id
)
2317 bpa
->table_id
= vrf
->data
.l
.table_id
;
2319 bpa
->table_id
= bpa
->fwmark
;
2320 bpa
->installed
= false;
2323 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2324 /* 0 value is forbidden */
2325 bpa
->install_in_progress
= false;
2327 if (bpf
->type
== BGP_PBR_IPRULE
) {
2328 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2329 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2330 pbr_rule
.priority
= 20;
2332 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2333 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2336 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2337 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2339 pbr_rule
.action
= bpa
;
2340 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2341 bgp_pbr_rule_alloc_intern
);
2342 if (bpr
->unique
== 0) {
2343 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2344 bpr
->installed
= false;
2345 bpr
->install_in_progress
= false;
2346 /* link bgp info to bpr */
2347 bpr
->path
= (void *)path
;
2350 /* already installed */
2352 struct bgp_path_info_extra
*extra
=
2353 bgp_path_info_extra_get(path
);
2356 listnode_lookup_nocheck(extra
->bgp_fs_iprule
,
2358 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2359 zlog_err("%s: entry %p/%p already installed in bgp pbr iprule",
2360 __func__
, path
, bpr
);
2365 bgp_pbr_bpa_add(bpa
);
2368 if (!bpr
->installed
)
2369 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2371 /* A previous entry may already exist
2372 * flush previous entry if necessary
2374 bprr
.bpr_to_match
= bpr
;
2375 bprr
.bpr_found
= NULL
;
2376 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2377 if (bprr
.bpr_found
) {
2378 static struct bgp_pbr_rule
*local_bpr
;
2379 static struct bgp_pbr_action
*local_bpa
;
2381 local_bpr
= bprr
.bpr_found
;
2382 local_bpa
= local_bpr
->action
;
2383 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2388 /* then look for bpm */
2389 memset(&temp
, 0, sizeof(temp
));
2390 temp
.vrf_id
= bpf
->vrf_id
;
2391 temp
.family
= bpf
->family
;
2393 temp
.flags
|= MATCH_IP_SRC_SET
;
2395 temp
.flags
|= MATCH_IP_DST_SET
;
2397 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2398 if (bpf
->protocol
== IPPROTO_ICMP
)
2399 temp
.flags
|= MATCH_ICMP_SET
;
2400 temp
.flags
|= MATCH_PORT_SRC_SET
;
2402 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2403 if (bpf
->protocol
== IPPROTO_ICMP
)
2404 temp
.flags
|= MATCH_ICMP_SET
;
2405 temp
.flags
|= MATCH_PORT_DST_SET
;
2407 if (src_port
&& src_port
->max_port
)
2408 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2409 if (dst_port
&& dst_port
->max_port
)
2410 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2412 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2413 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2414 temp
.type
= IPSET_NET_PORT
;
2416 temp
.type
= IPSET_NET
;
2418 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2419 temp
.type
= IPSET_NET_PORT_NET
;
2421 temp
.type
= IPSET_NET_NET
;
2424 temp
.pkt_len_min
= pkt_len
->min_port
;
2425 if (pkt_len
->max_port
)
2426 temp
.pkt_len_max
= pkt_len
->max_port
;
2427 } else if (bpf
->pkt_len_val
) {
2428 if (bpf
->pkt_len_val
->mask
)
2429 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2430 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2432 if (bpf
->tcp_flags
) {
2433 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2434 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2437 if (bpf
->dscp
->mask
)
2438 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2440 temp
.flags
|= MATCH_DSCP_SET
;
2441 temp
.dscp_value
= bpf
->dscp
->val
;
2443 if (bpf
->flow_label
) {
2444 if (bpf
->flow_label
->mask
)
2445 temp
.flags
|= MATCH_FLOW_LABEL_INVERSE_SET
;
2447 temp
.flags
|= MATCH_FLOW_LABEL_SET
;
2448 temp
.flow_label
= bpf
->flow_label
->val
;
2450 if (bpf
->fragment
) {
2451 if (bpf
->fragment
->mask
)
2452 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2453 temp
.fragment
= bpf
->fragment
->val
;
2455 if (bpf
->protocol
) {
2456 temp
.protocol
= bpf
->protocol
;
2457 temp
.flags
|= MATCH_PROTOCOL_SET
;
2460 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2461 bgp_pbr_match_alloc_intern
);
2463 /* new, then self allocate ipset_name and unique */
2464 if (bpm
->unique
== 0) {
2465 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2466 /* 0 value is forbidden */
2467 snprintf(bpm
->ipset_name
, sizeof(bpm
->ipset_name
),
2469 bpm
->entry_hash
= hash_create_size(8,
2470 bgp_pbr_match_entry_hash_key
,
2471 bgp_pbr_match_entry_hash_equal
,
2472 "Match Entry Hash");
2473 bpm
->installed
= false;
2475 /* unique2 should be updated too */
2476 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2477 bpm
->installed_in_iptable
= false;
2478 bpm
->install_in_progress
= false;
2479 bpm
->install_iptable_in_progress
= false;
2482 memset(&temp2
, 0, sizeof(temp2
));
2484 prefix_copy(&temp2
.src
, bpf
->src
);
2486 temp2
.src
.family
= bpf
->family
;
2488 prefix_copy(&temp2
.dst
, bpf
->dst
);
2490 temp2
.dst
.family
= bpf
->family
;
2491 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2492 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2493 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2494 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2495 temp2
.proto
= bpf
->protocol
;
2496 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2497 bgp_pbr_match_entry_alloc_intern
);
2498 if (bpme
->unique
== 0) {
2499 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2500 /* 0 value is forbidden */
2501 bpme
->backpointer
= bpm
;
2502 bpme
->installed
= false;
2503 bpme
->install_in_progress
= false;
2504 /* link bgp info to bpme */
2505 bpme
->path
= (void *)path
;
2509 /* already installed */
2511 struct bgp_path_info_extra
*extra
=
2512 bgp_path_info_extra_get(path
);
2515 listnode_lookup_nocheck(extra
->bgp_fs_pbr
, bpme
)) {
2516 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2518 "%s: entry %p/%p already installed in bgp pbr",
2519 __func__
, path
, bpme
);
2523 /* BGP FS: append entry to zebra
2524 * - policies are not routing entries and as such
2525 * route replace semantics don't necessarily follow
2526 * through to policy entries
2527 * - because of that, not all policing information will be stored
2528 * into zebra. and non selected policies will be suppressed from zebra
2529 * - as consequence, in order to bring consistency
2530 * a policy will be added, then ifan ecmp policy exists,
2531 * it will be suppressed subsequently
2534 bgp_pbr_bpa_add(bpa
);
2537 if (!bpm
->installed
)
2538 bgp_send_pbr_ipset_match(bpm
, true);
2540 if (!bpme
->installed
)
2541 bgp_send_pbr_ipset_entry_match(bpme
, true);
2544 if (!bpm
->installed_in_iptable
)
2545 bgp_send_pbr_iptable(bpa
, bpm
, true);
2547 /* A previous entry may already exist
2548 * flush previous entry if necessary
2550 bpmer
.bpme_to_match
= bpme
;
2551 bpmer
.bpme_found
= NULL
;
2552 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2553 if (bpmer
.bpme_found
) {
2554 static struct bgp_pbr_match
*local_bpm
;
2555 static struct bgp_pbr_action
*local_bpa
;
2557 local_bpm
= bpmer
.bpme_found
->backpointer
;
2558 local_bpa
= local_bpm
->action
;
2559 bgp_pbr_flush_entry(bgp
, local_bpa
,
2560 local_bpm
, bpmer
.bpme_found
);
2566 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2567 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2568 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2571 struct listnode
*node
, *nnode
;
2572 struct bgp_pbr_val_mask
*valmask
;
2573 uint8_t next_type_entry
;
2574 struct list
*orig_list
;
2575 struct bgp_pbr_val_mask
**target_val
;
2577 if (type_entry
== 0) {
2578 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2581 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2582 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2583 orig_list
= bpof
->tcpflags
;
2584 target_val
= &bpf
->tcp_flags
;
2585 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2586 orig_list
= bpof
->dscp
;
2587 target_val
= &bpf
->dscp
;
2588 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2589 orig_list
= bpof
->pkt_len
;
2590 target_val
= &bpf
->pkt_len_val
;
2591 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2592 orig_list
= bpof
->fragment
;
2593 target_val
= &bpf
->fragment
;
2594 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2595 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2596 /* enumerate list for icmp - must be last one */
2597 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2600 bgp_pbr_policyroute_add_to_zebra_recursive(
2601 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2604 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2605 *target_val
= valmask
;
2606 bgp_pbr_policyroute_add_to_zebra_recursive(
2607 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2611 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2612 struct bgp_path_info
*path
,
2613 struct bgp_pbr_filter
*bpf
,
2614 struct bgp_pbr_or_filter
*bpof
,
2615 struct nexthop
*nh
, float *rate
)
2618 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2622 bgp_pbr_policyroute_add_to_zebra_recursive(
2623 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2624 else if (bpof
->dscp
)
2625 bgp_pbr_policyroute_add_to_zebra_recursive(
2626 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2627 else if (bpof
->pkt_len
)
2628 bgp_pbr_policyroute_add_to_zebra_recursive(
2629 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2630 else if (bpof
->fragment
)
2631 bgp_pbr_policyroute_add_to_zebra_recursive(
2632 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2633 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2634 bgp_pbr_policyroute_add_to_zebra_recursive(
2635 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2637 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2640 list_delete_all_node(bpof
->tcpflags
);
2642 list_delete_all_node(bpof
->dscp
);
2644 list_delete_all_node(bpof
->pkt_len
);
2646 list_delete_all_node(bpof
->fragment
);
2647 if (bpof
->icmp_type
)
2648 list_delete_all_node(bpof
->icmp_type
);
2649 if (bpof
->icmp_code
)
2650 list_delete_all_node(bpof
->icmp_code
);
2653 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2654 struct bgp_pbr_entry_main
*api
, bool add
)
2658 int continue_loop
= 1;
2660 struct prefix
*src
= NULL
, *dst
= NULL
;
2662 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2663 struct bgp_pbr_range_port range
, range_icmp_code
;
2664 struct bgp_pbr_range_port pkt_len
;
2665 struct bgp_pbr_filter bpf
;
2667 struct bgp_pbr_or_filter bpof
;
2668 struct bgp_pbr_val_mask bpvm
;
2670 memset(&range
, 0, sizeof(range
));
2671 memset(&nh
, 0, sizeof(nh
));
2672 memset(&bpf
, 0, sizeof(bpf
));
2673 memset(&bpof
, 0, sizeof(bpof
));
2674 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2675 (api
->type
== BGP_PBR_IPRULE
&&
2676 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2677 src
= &api
->src_prefix
;
2678 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2679 (api
->type
== BGP_PBR_IPRULE
&&
2680 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2681 dst
= &api
->dst_prefix
;
2682 if (api
->type
== BGP_PBR_IPRULE
)
2683 bpf
.type
= api
->type
;
2684 memset(&nh
, 0, sizeof(nh
));
2685 nh
.vrf_id
= VRF_UNKNOWN
;
2686 if (api
->match_protocol_num
) {
2687 proto
= (uint8_t)api
->protocol
[0].value
;
2688 if (api
->afi
== AF_INET6
&& proto
== IPPROTO_ICMPV6
)
2689 proto
= IPPROTO_ICMP
;
2691 /* if match_port is selected, then either src or dst port will be parsed
2692 * but not both at the same time
2694 if (api
->match_port_num
>= 1) {
2695 bgp_pbr_extract(api
->port
,
2696 api
->match_port_num
,
2698 srcp
= dstp
= &range
;
2699 } else if (api
->match_src_port_num
>= 1) {
2700 bgp_pbr_extract(api
->src_port
,
2701 api
->match_src_port_num
,
2705 } else if (api
->match_dst_port_num
>= 1) {
2706 bgp_pbr_extract(api
->dst_port
,
2707 api
->match_dst_port_num
,
2712 if (api
->match_icmp_type_num
>= 1) {
2713 proto
= IPPROTO_ICMP
;
2714 if (bgp_pbr_extract(api
->icmp_type
,
2715 api
->match_icmp_type_num
,
2719 bpof
.icmp_type
= list_new();
2720 bgp_pbr_extract_enumerate(api
->icmp_type
,
2721 api
->match_icmp_type_num
,
2724 FLOWSPEC_ICMP_TYPE
);
2727 if (api
->match_icmp_code_num
>= 1) {
2728 proto
= IPPROTO_ICMP
;
2729 if (bgp_pbr_extract(api
->icmp_code
,
2730 api
->match_icmp_code_num
,
2732 dstp
= &range_icmp_code
;
2734 bpof
.icmp_code
= list_new();
2735 bgp_pbr_extract_enumerate(api
->icmp_code
,
2736 api
->match_icmp_code_num
,
2739 FLOWSPEC_ICMP_CODE
);
2743 if (api
->match_tcpflags_num
) {
2744 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2745 api
->match_tcpflags_num
);
2746 if (kind_enum
== OPERATOR_UNARY_AND
) {
2747 bpf
.tcp_flags
= &bpvm
;
2748 bgp_pbr_extract_enumerate(api
->tcpflags
,
2749 api
->match_tcpflags_num
,
2752 FLOWSPEC_TCP_FLAGS
);
2753 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2754 bpof
.tcpflags
= list_new();
2755 bgp_pbr_extract_enumerate(api
->tcpflags
,
2756 api
->match_tcpflags_num
,
2759 FLOWSPEC_TCP_FLAGS
);
2762 if (api
->match_packet_length_num
) {
2765 ret
= bgp_pbr_extract(api
->packet_length
,
2766 api
->match_packet_length_num
,
2769 bpf
.pkt_len
= &pkt_len
;
2771 bpof
.pkt_len
= list_new();
2772 bgp_pbr_extract_enumerate(api
->packet_length
,
2773 api
->match_packet_length_num
,
2779 if (api
->match_dscp_num
>= 1) {
2780 bpof
.dscp
= list_new();
2781 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2783 bpof
.dscp
, FLOWSPEC_DSCP
);
2785 if (api
->match_fragment_num
) {
2786 bpof
.fragment
= list_new();
2787 bgp_pbr_extract_enumerate(api
->fragment
,
2788 api
->match_fragment_num
,
2793 bpf
.vrf_id
= api
->vrf_id
;
2796 bpf
.protocol
= proto
;
2797 bpf
.src_port
= srcp
;
2798 bpf
.dst_port
= dstp
;
2799 bpf
.family
= afi2family(api
->afi
);
2801 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2804 /* no action for add = true */
2805 for (i
= 0; i
< api
->action_num
; i
++) {
2806 switch (api
->actions
[i
].action
) {
2807 case ACTION_TRAFFICRATE
:
2809 if (api
->actions
[i
].u
.r
.rate
== 0) {
2810 nh
.vrf_id
= api
->vrf_id
;
2811 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2812 bgp_pbr_policyroute_add_to_zebra(
2813 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2815 /* update rate. can be reentrant */
2816 rate
= api
->actions
[i
].u
.r
.rate
;
2817 if (BGP_DEBUG(pbr
, PBR
)) {
2818 bgp_pbr_print_policy_route(api
);
2819 zlog_warn("PBR: ignoring Set action rate %f",
2820 api
->actions
[i
].u
.r
.rate
);
2824 case ACTION_TRAFFIC_ACTION
:
2825 if (api
->actions
[i
].u
.za
.filter
2826 & TRAFFIC_ACTION_SAMPLE
) {
2827 if (BGP_DEBUG(pbr
, PBR
)) {
2828 bgp_pbr_print_policy_route(api
);
2829 zlog_warn("PBR: Sample action Ignored");
2832 /* terminate action: run other filters
2835 case ACTION_REDIRECT_IP
:
2836 nh
.vrf_id
= api
->vrf_id
;
2837 if (api
->afi
== AFI_IP
) {
2838 nh
.type
= NEXTHOP_TYPE_IPV4
;
2839 nh
.gate
.ipv4
.s_addr
=
2840 api
->actions
[i
].u
.zr
.
2841 redirect_ip_v4
.s_addr
;
2843 nh
.type
= NEXTHOP_TYPE_IPV6
;
2844 memcpy(&nh
.gate
.ipv6
,
2845 &api
->actions
[i
].u
.zr
.redirect_ip_v6
,
2846 sizeof(struct in6_addr
));
2848 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2850 /* XXX combination with REDIRECT_VRF
2851 * + REDIRECT_NH_IP not done
2855 case ACTION_REDIRECT
:
2856 if (api
->afi
== AFI_IP
)
2857 nh
.type
= NEXTHOP_TYPE_IPV4
;
2859 nh
.type
= NEXTHOP_TYPE_IPV6
;
2860 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2861 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2865 case ACTION_MARKING
:
2866 if (BGP_DEBUG(pbr
, PBR
)) {
2867 bgp_pbr_print_policy_route(api
);
2868 zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
2869 api
->actions
[i
].u
.marking_dscp
);
2875 if (continue_loop
== 0)
2880 void bgp_pbr_update_entry(struct bgp
*bgp
, const struct prefix
*p
,
2881 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2884 struct bgp_pbr_entry_main api
;
2886 if (safi
!= SAFI_FLOWSPEC
)
2887 return; /* not supported */
2888 /* Make Zebra API structure. */
2889 memset(&api
, 0, sizeof(api
));
2890 api
.vrf_id
= bgp
->vrf_id
;
2893 if (!bgp_zebra_tm_chunk_obtained()) {
2894 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2895 flog_err(EC_BGP_TABLE_CHUNK
,
2896 "%s: table chunk not obtained yet", __func__
);
2900 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2901 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2902 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2903 "%s: cancel updating entry %p in bgp pbr",
2907 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2910 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2911 const struct bgp_pbr_interface
*b
)
2913 return strcmp(a
->name
, b
->name
);
2916 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2917 struct bgp_pbr_interface_head
*head
)
2919 struct bgp_pbr_interface pbr_if
;
2921 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2922 return (RB_FIND(bgp_pbr_interface_head
,
2926 /* this function resets to the default policy routing
2927 * go back to default status
2929 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2931 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2932 struct bgp_pbr_interface_head
*head
;
2933 struct bgp_pbr_interface
*pbr_if
;
2938 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2940 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv6
);
2941 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2942 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2943 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2944 XFREE(MTYPE_TMP
, pbr_if
);