5 * FRR is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
10 * FRR is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "bgpd/bgpd.h"
27 #include "bgpd/bgp_pbr.h"
28 #include "bgpd/bgp_debug.h"
29 #include "bgpd/bgp_flowspec_util.h"
30 #include "bgpd/bgp_ecommunity.h"
31 #include "bgpd/bgp_route.h"
32 #include "bgpd/bgp_attr.h"
33 #include "bgpd/bgp_zebra.h"
34 #include "bgpd/bgp_mplsvpn.h"
35 #include "bgpd/bgp_flowspec_private.h"
36 #include "bgpd/bgp_errors.h"
38 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry")
39 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match")
40 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action")
41 DEFINE_MTYPE_STATIC(BGPD
, PBR_RULE
, "PBR rule")
42 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context")
43 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value")
45 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
46 id_entry
, bgp_pbr_interface_compare
);
47 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
48 RB_INITIALIZER(&ifaces_by_name_ipv4
);
50 static int bgp_pbr_match_counter_unique
;
51 static int bgp_pbr_match_entry_counter_unique
;
52 static int bgp_pbr_action_counter_unique
;
53 static int bgp_pbr_match_iptable_counter_unique
;
55 struct bgp_pbr_match_iptable_unique
{
57 struct bgp_pbr_match
*bpm_found
;
60 struct bgp_pbr_match_entry_unique
{
62 struct bgp_pbr_match_entry
*bpme_found
;
65 struct bgp_pbr_action_unique
{
67 struct bgp_pbr_action
*bpa_found
;
70 struct bgp_pbr_rule_unique
{
72 struct bgp_pbr_rule
*bpr_found
;
75 static int bgp_pbr_rule_walkcb(struct hash_backet
*backet
, void *arg
)
77 struct bgp_pbr_rule
*bpr
= (struct bgp_pbr_rule
*)backet
->data
;
78 struct bgp_pbr_rule_unique
*bpru
= (struct bgp_pbr_rule_unique
*)
80 uint32_t unique
= bpru
->unique
;
82 if (bpr
->unique
== unique
) {
83 bpru
->bpr_found
= bpr
;
84 return HASHWALK_ABORT
;
86 return HASHWALK_CONTINUE
;
89 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
91 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
92 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
94 uint32_t unique
= bpau
->unique
;
96 if (bpa
->unique
== unique
) {
97 bpau
->bpa_found
= bpa
;
98 return HASHWALK_ABORT
;
100 return HASHWALK_CONTINUE
;
103 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
105 struct bgp_pbr_match_entry
*bpme
=
106 (struct bgp_pbr_match_entry
*)backet
->data
;
107 struct bgp_pbr_match_entry_unique
*bpmeu
=
108 (struct bgp_pbr_match_entry_unique
*)arg
;
109 uint32_t unique
= bpmeu
->unique
;
111 if (bpme
->unique
== unique
) {
112 bpmeu
->bpme_found
= bpme
;
113 return HASHWALK_ABORT
;
115 return HASHWALK_CONTINUE
;
118 struct bgp_pbr_match_ipsetname
{
120 struct bgp_pbr_match
*bpm_found
;
123 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
125 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
126 struct bgp_pbr_match_ipsetname
*bpmi
=
127 (struct bgp_pbr_match_ipsetname
*)arg
;
128 char *ipset_name
= bpmi
->ipsetname
;
130 if (!strncmp(ipset_name
, bpm
->ipset_name
,
131 ZEBRA_IPSET_NAME_SIZE
)) {
132 bpmi
->bpm_found
= bpm
;
133 return HASHWALK_ABORT
;
135 return HASHWALK_CONTINUE
;
138 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
140 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
141 struct bgp_pbr_match_iptable_unique
*bpmiu
=
142 (struct bgp_pbr_match_iptable_unique
*)arg
;
143 uint32_t unique
= bpmiu
->unique
;
145 if (bpm
->unique2
== unique
) {
146 bpmiu
->bpm_found
= bpm
;
147 return HASHWALK_ABORT
;
149 return HASHWALK_CONTINUE
;
152 struct bgp_pbr_match_unique
{
154 struct bgp_pbr_match
*bpm_found
;
157 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
159 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
160 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
162 uint32_t unique
= bpmu
->unique
;
164 if (bpm
->unique
== unique
) {
165 bpmu
->bpm_found
= bpm
;
166 return HASHWALK_ABORT
;
168 return HASHWALK_CONTINUE
;
171 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
177 ptr
+= sprintf(ptr
, "%s", prepend
);
179 if (mval
->unary_operator
& OPERATOR_UNARY_OR
)
180 ptr
+= sprintf(ptr
, ", or ");
181 if (mval
->unary_operator
& OPERATOR_UNARY_AND
)
182 ptr
+= sprintf(ptr
, ", and ");
184 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
)
185 ptr
+= sprintf(ptr
, "<");
186 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
)
187 ptr
+= sprintf(ptr
, ">");
188 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
)
189 ptr
+= sprintf(ptr
, "=");
190 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
)
191 ptr
+= sprintf(ptr
, "match");
192 ptr
+= sprintf(ptr
, " %u", mval
->value
);
193 return (int)(ptr
- str
);
196 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
198 (_ptr) += sprintf((_ptr), "; "); \
202 /* this structure can be used for port range,
203 * but also for other values range like packet length range
205 struct bgp_pbr_range_port
{
210 /* this structure can be used to filter with a mask
211 * for instance it supports not instructions like for
214 struct bgp_pbr_val_mask
{
219 /* this structure is used to pass instructs
220 * so that BGP can create pbr instructions to ZEBRA
222 struct bgp_pbr_filter
{
227 uint8_t bitmask_iprule
;
229 struct bgp_pbr_range_port
*pkt_len
;
230 struct bgp_pbr_range_port
*src_port
;
231 struct bgp_pbr_range_port
*dst_port
;
232 struct bgp_pbr_val_mask
*tcp_flags
;
233 struct bgp_pbr_val_mask
*dscp
;
234 struct bgp_pbr_val_mask
*pkt_len_val
;
235 struct bgp_pbr_val_mask
*fragment
;
238 /* this structure is used to contain OR instructions
239 * so that BGP can create multiple pbr instructions
242 struct bgp_pbr_or_filter
{
243 struct list
*tcpflags
;
245 struct list
*pkt_len
;
246 struct list
*fragment
;
247 struct list
*icmp_type
;
248 struct list
*icmp_code
;
251 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
252 struct bgp_path_info
*path
,
253 struct bgp_pbr_filter
*bpf
,
257 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
259 static bool bgp_pbr_extract_enumerate_unary_opposite(
260 uint8_t unary_operator
,
261 struct bgp_pbr_val_mask
*and_valmask
,
262 struct list
*or_valmask
, uint32_t value
,
265 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
266 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
268 TCP_HEADER_ALL_FLAGS
&
270 } else if (type_entry
== FLOWSPEC_DSCP
||
271 type_entry
== FLOWSPEC_PKT_LEN
||
272 type_entry
== FLOWSPEC_FRAGMENT
) {
273 and_valmask
->val
= value
;
274 and_valmask
->mask
= 1; /* inverse */
276 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
277 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
278 sizeof(struct bgp_pbr_val_mask
));
279 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
280 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
282 TCP_HEADER_ALL_FLAGS
&
284 } else if (type_entry
== FLOWSPEC_DSCP
||
285 type_entry
== FLOWSPEC_FRAGMENT
||
286 type_entry
== FLOWSPEC_PKT_LEN
) {
287 and_valmask
->val
= value
;
288 and_valmask
->mask
= 1; /* inverse */
290 listnode_add(or_valmask
, and_valmask
);
291 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
292 type_entry
== FLOWSPEC_ICMP_TYPE
)
297 /* TCP : FIN and SYN -> val = ALL; mask = 3
298 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
299 * other variables type: dscp, pkt len, fragment
300 * - value is copied in bgp_pbr_val_mask->val value
301 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
303 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
304 int num
, uint8_t unary_operator
,
305 void *valmask
, uint8_t type_entry
)
308 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
309 struct list
*or_valmask
= NULL
;
313 if (unary_operator
== OPERATOR_UNARY_AND
) {
314 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
315 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
316 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
317 or_valmask
= (struct list
*)valmask
;
320 for (i
= 0; i
< num
; i
++) {
321 if (i
!= 0 && list
[i
].unary_operator
!=
324 if (!(list
[i
].compare_operator
&
325 OPERATOR_COMPARE_EQUAL_TO
) &&
326 !(list
[i
].compare_operator
&
327 OPERATOR_COMPARE_EXACT_MATCH
)) {
328 if ((list
[i
].compare_operator
&
329 OPERATOR_COMPARE_LESS_THAN
) &&
330 (list
[i
].compare_operator
&
331 OPERATOR_COMPARE_GREATER_THAN
)) {
332 ret
= bgp_pbr_extract_enumerate_unary_opposite(
333 unary_operator
, and_valmask
,
334 or_valmask
, list
[i
].value
,
342 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
343 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
345 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
346 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
347 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
348 sizeof(struct bgp_pbr_val_mask
));
349 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
350 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
352 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
353 } else if (type_entry
== FLOWSPEC_DSCP
||
354 type_entry
== FLOWSPEC_ICMP_TYPE
||
355 type_entry
== FLOWSPEC_ICMP_CODE
||
356 type_entry
== FLOWSPEC_FRAGMENT
||
357 type_entry
== FLOWSPEC_PKT_LEN
)
358 and_valmask
->val
= list
[i
].value
;
359 listnode_add(or_valmask
, and_valmask
);
362 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
363 && type_entry
== FLOWSPEC_TCP_FLAGS
)
364 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
368 /* if unary operator can either be UNARY_OR/AND/OR-AND.
369 * in the latter case, combinationf of both is not handled
371 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
372 int num
, uint8_t unary_operator
,
373 void *valmask
, uint8_t type_entry
)
376 uint8_t unary_operator_val
;
377 bool double_check
= false;
379 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
380 (unary_operator
& OPERATOR_UNARY_AND
)) {
381 unary_operator_val
= OPERATOR_UNARY_AND
;
384 unary_operator_val
= unary_operator
;
385 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
386 valmask
, type_entry
);
387 if (!ret
&& double_check
)
388 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
395 /* returns the unary operator that is in the list
396 * return 0 if both operators are used
398 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
403 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
405 for (i
= 0; i
< num
; i
++) {
408 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
409 unary_operator
= OPERATOR_UNARY_OR
;
410 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
411 && unary_operator
== OPERATOR_UNARY_OR
) ||
412 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
413 && unary_operator
== OPERATOR_UNARY_AND
))
416 return unary_operator
;
420 /* return true if extraction ok
422 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
424 struct bgp_pbr_range_port
*range
)
427 bool exact_match
= false;
430 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
434 for (i
= 0; i
< num
; i
++) {
435 if (i
!= 0 && (list
[i
].compare_operator
==
436 OPERATOR_COMPARE_EQUAL_TO
))
438 if (i
== 0 && (list
[i
].compare_operator
==
439 OPERATOR_COMPARE_EQUAL_TO
)) {
441 range
->min_port
= list
[i
].value
;
444 if (exact_match
== true && i
> 0)
446 if (list
[i
].compare_operator
==
447 (OPERATOR_COMPARE_GREATER_THAN
+
448 OPERATOR_COMPARE_EQUAL_TO
)) {
450 range
->min_port
= list
[i
].value
;
451 } else if (list
[i
].compare_operator
==
452 (OPERATOR_COMPARE_LESS_THAN
+
453 OPERATOR_COMPARE_EQUAL_TO
)) {
455 range
->max_port
= list
[i
].value
;
456 } else if (list
[i
].compare_operator
==
457 OPERATOR_COMPARE_LESS_THAN
) {
459 range
->max_port
= list
[i
].value
- 1;
460 } else if (list
[i
].compare_operator
==
461 OPERATOR_COMPARE_GREATER_THAN
) {
463 range
->min_port
= list
[i
].value
+ 1;
469 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
471 bool enumerate_icmp
= false;
473 if (api
->type
== BGP_PBR_UNDEFINED
) {
474 if (BGP_DEBUG(pbr
, PBR
))
475 zlog_debug("BGP: pbr entry undefined. cancel.");
478 /* because bgp pbr entry may contain unsupported
479 * combinations, a message will be displayed here if
481 * for now, only match/set supported is
482 * - combination src/dst => redirect nexthop [ + rate]
483 * - combination src/dst => redirect VRF [ + rate]
484 * - combination src/dst => drop
485 * - combination srcport + @IP
487 if (api
->match_protocol_num
> 1) {
488 if (BGP_DEBUG(pbr
, PBR
))
489 zlog_debug("BGP: match protocol operations:"
490 "multiple protocols ( %d). ignoring.",
491 api
->match_protocol_num
);
494 if (api
->match_protocol_num
== 1 &&
495 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
496 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
497 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
498 if (BGP_DEBUG(pbr
, PBR
))
499 zlog_debug("BGP: match protocol operations:"
500 "protocol (%d) not supported. ignoring",
501 api
->match_protocol_num
);
504 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
505 if (BGP_DEBUG(pbr
, PBR
))
506 zlog_debug("BGP: match src port operations:"
507 "too complex. ignoring.");
510 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
511 if (BGP_DEBUG(pbr
, PBR
))
512 zlog_debug("BGP: match dst port operations:"
513 "too complex. ignoring.");
516 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
517 api
->match_tcpflags_num
,
519 OPERATOR_UNARY_OR
, NULL
,
520 FLOWSPEC_TCP_FLAGS
)) {
521 if (BGP_DEBUG(pbr
, PBR
))
522 zlog_debug("BGP: match tcp flags:"
523 "too complex. ignoring.");
526 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
527 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
528 api
->match_icmp_type_num
,
529 OPERATOR_UNARY_OR
, NULL
,
530 FLOWSPEC_ICMP_TYPE
)) {
531 if (BGP_DEBUG(pbr
, PBR
))
532 zlog_debug("BGP: match icmp type operations:"
533 "too complex. ignoring.");
536 enumerate_icmp
= true;
538 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
539 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
540 api
->match_icmp_code_num
,
541 OPERATOR_UNARY_OR
, NULL
,
542 FLOWSPEC_ICMP_CODE
)) {
543 if (BGP_DEBUG(pbr
, PBR
))
544 zlog_debug("BGP: match icmp code operations:"
545 "too complex. ignoring.");
547 } else if (api
->match_icmp_type_num
> 1 &&
548 enumerate_icmp
== false) {
549 if (BGP_DEBUG(pbr
, PBR
))
550 zlog_debug("BGP: match icmp code is enumerate"
551 ", and icmp type is not."
552 " too complex. ignoring.");
556 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
557 if (BGP_DEBUG(pbr
, PBR
))
558 zlog_debug("BGP: match port operations:"
559 "too complex. ignoring.");
562 if (api
->match_packet_length_num
) {
565 ret
= bgp_pbr_extract(api
->packet_length
,
566 api
->match_packet_length_num
, NULL
);
568 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
569 api
->match_packet_length_num
,
571 | OPERATOR_UNARY_AND
,
572 NULL
, FLOWSPEC_PKT_LEN
);
574 if (BGP_DEBUG(pbr
, PBR
))
575 zlog_debug("BGP: match packet length operations:"
576 "too complex. ignoring.");
580 if (api
->match_dscp_num
) {
581 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
582 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
583 NULL
, FLOWSPEC_DSCP
)) {
584 if (BGP_DEBUG(pbr
, PBR
))
585 zlog_debug("BGP: match DSCP operations:"
586 "too complex. ignoring.");
590 if (api
->match_fragment_num
) {
594 success
= bgp_pbr_extract_enumerate(api
->fragment
,
595 api
->match_fragment_num
,
597 | OPERATOR_UNARY_AND
,
598 NULL
, FLOWSPEC_FRAGMENT
);
602 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
603 if (api
->fragment
[i
].value
!= 1 &&
604 api
->fragment
[i
].value
!= 2 &&
605 api
->fragment
[i
].value
!= 4 &&
606 api
->fragment
[i
].value
!= 8) {
609 "Value not valid (%d) for this implementation",
610 api
->fragment
[i
].value
);
614 sprintf(fail_str
, "too complex. ignoring");
616 if (BGP_DEBUG(pbr
, PBR
))
617 zlog_debug("BGP: match fragment operation (%d) %s",
618 api
->match_fragment_num
,
624 /* no combinations with both src_port and dst_port
625 * or port with src_port and dst_port
627 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
628 api
->match_port_num
> 3) {
629 if (BGP_DEBUG(pbr
, PBR
))
630 zlog_debug("BGP: match multiple port operations:"
631 " too complex. ignoring.");
634 if ((api
->match_src_port_num
|| api
->match_dst_port_num
635 || api
->match_port_num
) && (api
->match_icmp_type_num
636 || api
->match_icmp_code_num
)) {
637 if (BGP_DEBUG(pbr
, PBR
))
638 zlog_debug("BGP: match multiple port/imcp operations:"
639 " too complex. ignoring.");
642 /* iprule only supports redirect IP */
643 if (api
->type
== BGP_PBR_IPRULE
) {
646 for (i
= 0; i
< api
->action_num
; i
++) {
647 if (api
->actions
[i
].action
== ACTION_TRAFFICRATE
&&
648 api
->actions
[i
].u
.r
.rate
== 0) {
649 if (BGP_DEBUG(pbr
, PBR
)) {
650 bgp_pbr_print_policy_route(api
);
651 zlog_debug("BGP: iprule match actions"
652 " drop not supported");
656 if (api
->actions
[i
].action
== ACTION_MARKING
) {
657 if (BGP_DEBUG(pbr
, PBR
)) {
658 bgp_pbr_print_policy_route(api
);
659 zlog_warn("PBR: iprule set DSCP %u"
661 api
->actions
[i
].u
.marking_dscp
);
664 if (api
->actions
[i
].action
== ACTION_REDIRECT
) {
665 if (BGP_DEBUG(pbr
, PBR
)) {
666 bgp_pbr_print_policy_route(api
);
667 zlog_warn("PBR: iprule redirect VRF %u"
669 api
->actions
[i
].u
.redirect_vrf
);
674 } else if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
675 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
676 if (BGP_DEBUG(pbr
, PBR
)) {
677 bgp_pbr_print_policy_route(api
);
678 zlog_debug("BGP: match actions without src"
679 " or dst address can not operate."
687 /* return -1 if build or validation failed */
688 int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
689 struct bgp_path_info
*path
,
690 struct bgp_pbr_entry_main
*api
)
693 int i
, action_count
= 0;
694 struct ecommunity
*ecom
;
695 struct ecommunity_val
*ecom_eval
;
696 struct bgp_pbr_entry_action
*api_action
;
697 struct prefix
*src
= NULL
, *dst
= NULL
;
698 int valid_prefix
= 0;
700 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
702 /* extract match from flowspec entries */
703 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
704 p
->u
.prefix_flowspec
.prefixlen
, api
);
707 /* extract actiosn from flowspec ecom list */
708 if (path
&& path
->attr
&& path
->attr
->ecommunity
) {
709 ecom
= path
->attr
->ecommunity
;
710 for (i
= 0; i
< ecom
->size
; i
++) {
711 ecom_eval
= (struct ecommunity_val
*)
712 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
714 if (action_count
> ACTIONS_MAX_NUM
) {
715 if (BGP_DEBUG(pbr
, PBR_ERROR
))
717 EC_BGP_FLOWSPEC_PACKET
,
718 "%s: flowspec actions exceeds limit (max %u)",
719 __func__
, action_count
);
722 api_action
= &api
->actions
[action_count
- 1];
724 if ((ecom_eval
->val
[1] ==
725 (char)ECOMMUNITY_REDIRECT_VRF
) &&
726 (ecom_eval
->val
[0] ==
727 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
729 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
731 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
732 struct ecommunity
*eckey
= ecommunity_new();
733 struct ecommunity_val ecom_copy
;
735 memcpy(&ecom_copy
, ecom_eval
,
736 sizeof(struct ecommunity_val
));
738 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
739 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
740 ecommunity_add_val(eckey
, &ecom_copy
);
742 api_action
->action
= ACTION_REDIRECT
;
743 api_action
->u
.redirect_vrf
=
744 get_first_vrf_for_redirect_with_rt(
746 ecommunity_free(&eckey
);
747 } else if ((ecom_eval
->val
[0] ==
748 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
749 (ecom_eval
->val
[1] ==
750 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
751 /* in case the 2 ecom present,
753 * draft-ietf-idr-flowspec-redirect
755 if (api_action_redirect_ip
) {
756 if (api_action_redirect_ip
->u
757 .zr
.redirect_ip_v4
.s_addr
)
759 if (!path
->attr
->nexthop
.s_addr
)
761 api_action_redirect_ip
->u
762 .zr
.redirect_ip_v4
.s_addr
=
763 path
->attr
->nexthop
.s_addr
;
764 api_action_redirect_ip
->u
.zr
.duplicate
768 api_action
->action
= ACTION_REDIRECT_IP
;
769 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
770 path
->attr
->nexthop
.s_addr
;
771 api_action
->u
.zr
.duplicate
=
773 api_action_redirect_ip
= api_action
;
775 } else if ((ecom_eval
->val
[0] ==
776 (char)ECOMMUNITY_ENCODE_IP
) &&
777 (ecom_eval
->val
[1] ==
778 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
779 /* in case the 2 ecom present,
780 * overwrite simpson draft
781 * update redirect ip fields
783 if (api_action_redirect_ip
) {
784 memcpy(&(api_action_redirect_ip
->u
785 .zr
.redirect_ip_v4
.s_addr
),
786 (ecom_eval
->val
+2), 4);
787 api_action_redirect_ip
->u
792 api_action
->action
= ACTION_REDIRECT_IP
;
793 memcpy(&(api_action
->u
794 .zr
.redirect_ip_v4
.s_addr
),
795 (ecom_eval
->val
+2), 4);
796 api_action
->u
.zr
.duplicate
=
798 api_action_redirect_ip
= api_action
;
801 if (ecom_eval
->val
[0] !=
802 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
804 ret
= ecommunity_fill_pbr_action(ecom_eval
,
813 /* validate if incoming matc/action is compatible
814 * with our policy routing engine
816 if (!bgp_pbr_validate_policy_route(api
))
819 /* check inconsistency in the match rule */
820 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
821 src
= &api
->src_prefix
;
822 afi
= family2afi(src
->family
);
825 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
826 dst
= &api
->dst_prefix
;
827 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
828 if (BGP_DEBUG(pbr
, PBR
)) {
829 bgp_pbr_print_policy_route(api
);
830 zlog_debug("%s: inconsistency:"
831 " no match for afi src and dst (%u/%u)",
832 __func__
, afi
, family2afi(dst
->family
));
840 static void bgp_pbr_match_entry_free(void *arg
)
842 struct bgp_pbr_match_entry
*bpme
;
844 bpme
= (struct bgp_pbr_match_entry
*)arg
;
846 if (bpme
->installed
) {
847 bgp_send_pbr_ipset_entry_match(bpme
, false);
848 bpme
->installed
= false;
849 bpme
->backpointer
= NULL
;
851 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
854 static void bgp_pbr_match_free(void *arg
)
856 struct bgp_pbr_match
*bpm
;
858 bpm
= (struct bgp_pbr_match
*)arg
;
860 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
862 if (hashcount(bpm
->entry_hash
) == 0) {
863 /* delete iptable entry first */
864 /* then delete ipset match */
865 if (bpm
->installed
) {
866 if (bpm
->installed_in_iptable
) {
867 bgp_send_pbr_iptable(bpm
->action
,
869 bpm
->installed_in_iptable
= false;
870 bpm
->action
->refcnt
--;
872 bgp_send_pbr_ipset_match(bpm
, false);
873 bpm
->installed
= false;
877 hash_free(bpm
->entry_hash
);
879 XFREE(MTYPE_PBR_MATCH
, bpm
);
882 static void *bgp_pbr_match_alloc_intern(void *arg
)
884 struct bgp_pbr_match
*bpm
, *new;
886 bpm
= (struct bgp_pbr_match
*)arg
;
888 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
889 memcpy(new, bpm
, sizeof(*bpm
));
894 static void bgp_pbr_rule_free(void *arg
)
896 struct bgp_pbr_rule
*bpr
;
898 bpr
= (struct bgp_pbr_rule
*)arg
;
901 if (bpr
->installed
) {
902 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
903 bpr
->installed
= false;
904 bpr
->action
->refcnt
--;
907 XFREE(MTYPE_PBR_RULE
, bpr
);
910 static void *bgp_pbr_rule_alloc_intern(void *arg
)
912 struct bgp_pbr_rule
*bpr
, *new;
914 bpr
= (struct bgp_pbr_rule
*)arg
;
916 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
917 memcpy(new, bpr
, sizeof(*bpr
));
922 static void bgp_pbr_action_free(void *arg
)
924 struct bgp_pbr_action
*bpa
;
926 bpa
= (struct bgp_pbr_action
*)arg
;
928 if (bpa
->refcnt
== 0) {
929 if (bpa
->installed
&& bpa
->table_id
!= 0) {
930 bgp_send_pbr_rule_action(bpa
, NULL
, false);
931 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
935 bpa
->installed
= false;
938 XFREE(MTYPE_PBR_ACTION
, bpa
);
941 static void *bgp_pbr_action_alloc_intern(void *arg
)
943 struct bgp_pbr_action
*bpa
, *new;
945 bpa
= (struct bgp_pbr_action
*)arg
;
947 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
949 memcpy(new, bpa
, sizeof(*bpa
));
954 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
956 struct bgp_pbr_match_entry
*bpme
, *new;
958 bpme
= (struct bgp_pbr_match_entry
*)arg
;
960 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
962 memcpy(new, bpme
, sizeof(*bpme
));
967 uint32_t bgp_pbr_match_hash_key(void *arg
)
969 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
972 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
973 key
= jhash_1word(pbm
->flags
, key
);
974 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
975 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
976 key
= jhash(&pbm
->tcp_flags
, 2, key
);
977 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
978 key
= jhash(&pbm
->dscp_value
, 1, key
);
979 key
= jhash(&pbm
->fragment
, 1, key
);
980 return jhash_1word(pbm
->type
, key
);
983 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
985 const struct bgp_pbr_match
*r1
, *r2
;
987 r1
= (const struct bgp_pbr_match
*)arg1
;
988 r2
= (const struct bgp_pbr_match
*)arg2
;
990 if (r1
->vrf_id
!= r2
->vrf_id
)
993 if (r1
->type
!= r2
->type
)
996 if (r1
->flags
!= r2
->flags
)
999 if (r1
->action
!= r2
->action
)
1002 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1005 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1008 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1011 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1014 if (r1
->dscp_value
!= r2
->dscp_value
)
1017 if (r1
->fragment
!= r2
->fragment
)
1022 uint32_t bgp_pbr_rule_hash_key(void *arg
)
1024 struct bgp_pbr_rule
*pbr
= (struct bgp_pbr_rule
*)arg
;
1027 key
= prefix_hash_key(&pbr
->src
);
1028 key
= jhash_1word(pbr
->vrf_id
, key
);
1029 key
= jhash_1word(pbr
->flags
, key
);
1030 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1033 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1035 const struct bgp_pbr_rule
*r1
, *r2
;
1037 r1
= (const struct bgp_pbr_rule
*)arg1
;
1038 r2
= (const struct bgp_pbr_rule
*)arg2
;
1040 if (r1
->vrf_id
!= r2
->vrf_id
)
1043 if (r1
->flags
!= r2
->flags
)
1046 if (r1
->action
!= r2
->action
)
1049 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1050 !prefix_same(&r1
->src
, &r2
->src
))
1053 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1054 !prefix_same(&r1
->dst
, &r2
->dst
))
1060 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
1062 struct bgp_pbr_match_entry
*pbme
;
1065 pbme
= (struct bgp_pbr_match_entry
*)arg
;
1066 key
= prefix_hash_key(&pbme
->src
);
1067 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1068 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1069 key
= jhash(&pbme
->src_port_min
, 2, key
);
1070 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1071 key
= jhash(&pbme
->src_port_max
, 2, key
);
1072 key
= jhash(&pbme
->proto
, 1, key
);
1077 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1079 const struct bgp_pbr_match_entry
*r1
, *r2
;
1081 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1082 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1085 * on updates, comparing backpointer is not necessary
1086 * unique value is self calculated
1087 * rate is ignored for now
1090 if (!prefix_same(&r1
->src
, &r2
->src
))
1093 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1096 if (r1
->src_port_min
!= r2
->src_port_min
)
1099 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1102 if (r1
->src_port_max
!= r2
->src_port_max
)
1105 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1108 if (r1
->proto
!= r2
->proto
)
1114 uint32_t bgp_pbr_action_hash_key(void *arg
)
1116 struct bgp_pbr_action
*pbra
;
1119 pbra
= (struct bgp_pbr_action
*)arg
;
1120 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1121 key
= jhash_1word(pbra
->fwmark
, key
);
1125 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1127 const struct bgp_pbr_action
*r1
, *r2
;
1129 r1
= (const struct bgp_pbr_action
*)arg1
;
1130 r2
= (const struct bgp_pbr_action
*)arg2
;
1132 /* unique value is self calculated
1133 * table and fwmark is self calculated
1136 if (r1
->vrf_id
!= r2
->vrf_id
)
1139 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1145 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1148 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1149 struct bgp_pbr_rule_unique bpru
;
1151 if (!bgp
|| unique
== 0)
1153 bpru
.unique
= unique
;
1154 bpru
.bpr_found
= NULL
;
1155 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1156 return bpru
.bpr_found
;
1159 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1162 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1163 struct bgp_pbr_action_unique bpau
;
1165 if (!bgp
|| unique
== 0)
1167 bpau
.unique
= unique
;
1168 bpau
.bpa_found
= NULL
;
1169 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1170 return bpau
.bpa_found
;
1173 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1176 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1177 struct bgp_pbr_match_unique bpmu
;
1179 if (!bgp
|| unique
== 0)
1181 bpmu
.unique
= unique
;
1182 bpmu
.bpm_found
= NULL
;
1183 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1184 return bpmu
.bpm_found
;
1187 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1191 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1192 struct bgp_pbr_match_entry_unique bpmeu
;
1193 struct bgp_pbr_match_ipsetname bpmi
;
1195 if (!bgp
|| unique
== 0)
1197 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1198 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1199 bpmi
.bpm_found
= NULL
;
1200 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1201 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1202 if (!bpmi
.bpm_found
)
1204 bpmeu
.bpme_found
= NULL
;
1205 bpmeu
.unique
= unique
;
1206 hash_walk(bpmi
.bpm_found
->entry_hash
,
1207 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1208 return bpmeu
.bpme_found
;
1211 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1214 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1215 struct bgp_pbr_match_iptable_unique bpmiu
;
1217 if (!bgp
|| unique
== 0)
1219 bpmiu
.unique
= unique
;
1220 bpmiu
.bpm_found
= NULL
;
1221 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1222 return bpmiu
.bpm_found
;
1225 void bgp_pbr_cleanup(struct bgp
*bgp
)
1227 if (bgp
->pbr_match_hash
) {
1228 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1229 hash_free(bgp
->pbr_match_hash
);
1230 bgp
->pbr_match_hash
= NULL
;
1232 if (bgp
->pbr_rule_hash
) {
1233 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1234 hash_free(bgp
->pbr_rule_hash
);
1235 bgp
->pbr_rule_hash
= NULL
;
1237 if (bgp
->pbr_action_hash
) {
1238 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1239 hash_free(bgp
->pbr_action_hash
);
1240 bgp
->pbr_action_hash
= NULL
;
1242 if (bgp
->bgp_pbr_cfg
== NULL
)
1244 bgp_pbr_reset(bgp
, AFI_IP
);
1245 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1246 bgp
->bgp_pbr_cfg
= NULL
;
1249 void bgp_pbr_init(struct bgp
*bgp
)
1251 bgp
->pbr_match_hash
=
1252 hash_create_size(8, bgp_pbr_match_hash_key
,
1253 bgp_pbr_match_hash_equal
,
1255 bgp
->pbr_action_hash
=
1256 hash_create_size(8, bgp_pbr_action_hash_key
,
1257 bgp_pbr_action_hash_equal
,
1258 "Match Hash Entry");
1260 bgp
->pbr_rule_hash
=
1261 hash_create_size(8, bgp_pbr_rule_hash_key
,
1262 bgp_pbr_rule_hash_equal
,
1265 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1266 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1269 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1272 char return_string
[512];
1273 char *ptr
= return_string
;
1277 ptr
+= sprintf(ptr
, "MATCH : ");
1278 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1279 struct prefix
*p
= &(api
->src_prefix
);
1281 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1282 INCREMENT_DISPLAY(ptr
, nb_items
);
1284 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1285 struct prefix
*p
= &(api
->dst_prefix
);
1287 INCREMENT_DISPLAY(ptr
, nb_items
);
1288 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1291 if (api
->match_protocol_num
)
1292 INCREMENT_DISPLAY(ptr
, nb_items
);
1293 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1294 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1295 i
> 0 ? NULL
: "@proto ");
1297 if (api
->match_src_port_num
)
1298 INCREMENT_DISPLAY(ptr
, nb_items
);
1299 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1300 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1301 i
> 0 ? NULL
: "@srcport ");
1303 if (api
->match_dst_port_num
)
1304 INCREMENT_DISPLAY(ptr
, nb_items
);
1305 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1306 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1307 i
> 0 ? NULL
: "@dstport ");
1309 if (api
->match_port_num
)
1310 INCREMENT_DISPLAY(ptr
, nb_items
);
1311 for (i
= 0; i
< api
->match_port_num
; i
++)
1312 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1313 i
> 0 ? NULL
: "@port ");
1315 if (api
->match_icmp_type_num
)
1316 INCREMENT_DISPLAY(ptr
, nb_items
);
1317 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1318 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1319 i
> 0 ? NULL
: "@icmptype ");
1321 if (api
->match_icmp_code_num
)
1322 INCREMENT_DISPLAY(ptr
, nb_items
);
1323 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1324 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1325 i
> 0 ? NULL
: "@icmpcode ");
1327 if (api
->match_packet_length_num
)
1328 INCREMENT_DISPLAY(ptr
, nb_items
);
1329 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1330 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1331 i
> 0 ? NULL
: "@plen ");
1333 if (api
->match_dscp_num
)
1334 INCREMENT_DISPLAY(ptr
, nb_items
);
1335 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1336 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1337 i
> 0 ? NULL
: "@dscp ");
1339 if (api
->match_tcpflags_num
)
1340 INCREMENT_DISPLAY(ptr
, nb_items
);
1341 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1342 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1343 i
> 0 ? NULL
: "@tcpflags ");
1345 if (api
->match_fragment_num
)
1346 INCREMENT_DISPLAY(ptr
, nb_items
);
1347 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1348 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1349 i
> 0 ? NULL
: "@fragment ");
1351 ptr
= return_string
;
1353 ptr
+= sprintf(ptr
, "; ");
1354 if (api
->action_num
)
1355 ptr
+= sprintf(ptr
, "SET : ");
1357 for (i
= 0; i
< api
->action_num
; i
++) {
1358 switch (api
->actions
[i
].action
) {
1359 case ACTION_TRAFFICRATE
:
1360 INCREMENT_DISPLAY(ptr
, nb_items
);
1361 ptr
+= sprintf(ptr
, "@set rate %f",
1362 api
->actions
[i
].u
.r
.rate
);
1364 case ACTION_TRAFFIC_ACTION
:
1365 INCREMENT_DISPLAY(ptr
, nb_items
);
1366 ptr
+= sprintf(ptr
, "@action ");
1367 if (api
->actions
[i
].u
.za
.filter
1368 & TRAFFIC_ACTION_TERMINATE
)
1370 " terminate (apply filter(s))");
1371 if (api
->actions
[i
].u
.za
.filter
1372 & TRAFFIC_ACTION_DISTRIBUTE
)
1373 ptr
+= sprintf(ptr
, " distribute");
1374 if (api
->actions
[i
].u
.za
.filter
1375 & TRAFFIC_ACTION_SAMPLE
)
1376 ptr
+= sprintf(ptr
, " sample");
1378 case ACTION_REDIRECT_IP
:
1379 INCREMENT_DISPLAY(ptr
, nb_items
);
1380 char local_buff
[INET_ADDRSTRLEN
];
1382 if (inet_ntop(AF_INET
,
1383 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1384 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1386 "@redirect ip nh %s", local_buff
);
1388 case ACTION_REDIRECT
:
1389 INCREMENT_DISPLAY(ptr
, nb_items
);
1390 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1391 api
->actions
[i
].u
.redirect_vrf
);
1393 case ACTION_MARKING
:
1394 INCREMENT_DISPLAY(ptr
, nb_items
);
1395 ptr
+= sprintf(ptr
, "@set dscp %u",
1396 api
->actions
[i
].u
.marking_dscp
);
1402 zlog_info("%s", return_string
);
1405 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1406 struct bgp_pbr_rule
*bpr
)
1408 /* if bpr is null, do nothing
1412 if (bpr
->installed
) {
1413 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1414 bpr
->installed
= false;
1415 bpr
->action
->refcnt
--;
1418 struct bgp_path_info
*path
;
1419 struct bgp_path_info_extra
*extra
;
1421 /* unlink path to bpme */
1422 path
= (struct bgp_path_info
*)bpr
->path
;
1423 extra
= bgp_path_info_extra_get(path
);
1424 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1428 hash_release(bgp
->pbr_rule_hash
, bpr
);
1429 if (bpa
->refcnt
== 0) {
1430 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1431 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1432 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1436 bpa
->installed
= false;
1441 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1442 struct bgp_pbr_match
*bpm
,
1443 struct bgp_pbr_match_entry
*bpme
)
1445 /* if bpme is null, bpm is also null
1449 /* ipset del entry */
1450 if (bpme
->installed
) {
1451 bgp_send_pbr_ipset_entry_match(bpme
, false);
1452 bpme
->installed
= false;
1453 bpme
->backpointer
= NULL
;
1455 struct bgp_path_info
*path
;
1456 struct bgp_path_info_extra
*extra
;
1458 /* unlink path to bpme */
1459 path
= (struct bgp_path_info
*)bpme
->path
;
1460 extra
= bgp_path_info_extra_get(path
);
1461 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1465 hash_release(bpm
->entry_hash
, bpme
);
1466 if (hashcount(bpm
->entry_hash
) == 0) {
1467 /* delete iptable entry first */
1468 /* then delete ipset match */
1469 if (bpm
->installed
) {
1470 if (bpm
->installed_in_iptable
) {
1471 bgp_send_pbr_iptable(bpm
->action
,
1473 bpm
->installed_in_iptable
= false;
1474 bpm
->action
->refcnt
--;
1476 bgp_send_pbr_ipset_match(bpm
, false);
1477 bpm
->installed
= false;
1480 hash_release(bgp
->pbr_match_hash
, bpm
);
1481 /* XXX release pbr_match_action if not used
1482 * note that drop does not need to call send_pbr_action
1485 if (bpa
->refcnt
== 0) {
1486 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1487 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1488 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1492 bpa
->installed
= false;
1497 struct bgp_pbr_match_entry_remain
{
1498 struct bgp_pbr_match_entry
*bpme_to_match
;
1499 struct bgp_pbr_match_entry
*bpme_found
;
1502 struct bgp_pbr_rule_remain
{
1503 struct bgp_pbr_rule
*bpr_to_match
;
1504 struct bgp_pbr_rule
*bpr_found
;
1507 static int bgp_pbr_get_same_rule(struct hash_backet
*backet
, void *arg
)
1509 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)backet
->data
;
1510 struct bgp_pbr_rule_remain
*ctxt
=
1511 (struct bgp_pbr_rule_remain
*)arg
;
1512 struct bgp_pbr_rule
*r2
;
1514 r2
= ctxt
->bpr_to_match
;
1516 if (r1
->vrf_id
!= r2
->vrf_id
)
1517 return HASHWALK_CONTINUE
;
1519 if (r1
->flags
!= r2
->flags
)
1520 return HASHWALK_CONTINUE
;
1522 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1523 !prefix_same(&r1
->src
, &r2
->src
))
1524 return HASHWALK_CONTINUE
;
1526 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1527 !prefix_same(&r1
->dst
, &r2
->dst
))
1528 return HASHWALK_CONTINUE
;
1530 /* this function is used for two cases:
1531 * - remove an entry upon withdraw request
1532 * (case r2->action is null)
1533 * - replace an old iprule with different action
1534 * (case r2->action is != null)
1535 * the old one is removed after the new one
1536 * this is to avoid disruption in traffic
1538 if (r2
->action
== NULL
||
1539 r1
->action
!= r2
->action
) {
1540 ctxt
->bpr_found
= r1
;
1541 return HASHWALK_ABORT
;
1543 return HASHWALK_CONTINUE
;
1546 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1548 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1549 struct bgp_pbr_match_entry_remain
*bpmer
=
1550 (struct bgp_pbr_match_entry_remain
*)arg
;
1551 struct bgp_pbr_match
*bpm_temp
;
1552 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1554 if (!bpme
->backpointer
||
1555 bpm
== bpme
->backpointer
||
1556 bpme
->backpointer
->action
== bpm
->action
)
1557 return HASHWALK_CONTINUE
;
1558 /* ensure bpm other characteristics are equal */
1559 bpm_temp
= bpme
->backpointer
;
1560 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1561 bpm_temp
->type
!= bpm
->type
||
1562 bpm_temp
->flags
!= bpm
->flags
||
1563 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1564 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1565 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1566 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1567 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1568 bpm_temp
->fragment
!= bpm
->fragment
)
1569 return HASHWALK_CONTINUE
;
1571 /* look for remaining bpme */
1572 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1573 if (!bpmer
->bpme_found
)
1574 return HASHWALK_CONTINUE
;
1575 return HASHWALK_ABORT
;
1578 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1579 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1581 struct bgp_pbr_match temp
;
1582 struct bgp_pbr_match_entry temp2
;
1583 struct bgp_pbr_rule pbr_rule
;
1584 struct bgp_pbr_rule
*bpr
;
1585 struct bgp_pbr_match
*bpm
;
1586 struct bgp_pbr_match_entry
*bpme
;
1587 struct bgp_pbr_match_entry_remain bpmer
;
1588 struct bgp_pbr_range_port
*src_port
;
1589 struct bgp_pbr_range_port
*dst_port
;
1590 struct bgp_pbr_range_port
*pkt_len
;
1591 struct bgp_pbr_rule_remain bprr
;
1595 src_port
= bpf
->src_port
;
1596 dst_port
= bpf
->dst_port
;
1597 pkt_len
= bpf
->pkt_len
;
1599 if (BGP_DEBUG(zebra
, ZEBRA
))
1600 bgp_pbr_dump_entry(bpf
, false);
1602 /* as we don't know information from EC
1603 * look for bpm that have the bpm
1604 * with vrf_id characteristics
1606 memset(&temp2
, 0, sizeof(temp2
));
1607 memset(&temp
, 0, sizeof(temp
));
1609 if (bpf
->type
== BGP_PBR_IPRULE
) {
1610 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1611 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1613 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1614 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1617 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1618 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1621 /* A previous entry may already exist
1622 * flush previous entry if necessary
1624 bprr
.bpr_to_match
= bpr
;
1625 bprr
.bpr_found
= NULL
;
1626 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1627 if (bprr
.bpr_found
) {
1628 static struct bgp_pbr_rule
*local_bpr
;
1629 static struct bgp_pbr_action
*local_bpa
;
1631 local_bpr
= bprr
.bpr_found
;
1632 local_bpa
= local_bpr
->action
;
1633 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1640 temp
.flags
|= MATCH_IP_SRC_SET
;
1641 prefix_copy(&temp2
.src
, bpf
->src
);
1643 temp2
.src
.family
= AF_INET
;
1645 temp
.flags
|= MATCH_IP_DST_SET
;
1646 prefix_copy(&temp2
.dst
, bpf
->dst
);
1648 temp2
.dst
.family
= AF_INET
;
1649 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1650 if (bpf
->protocol
== IPPROTO_ICMP
)
1651 temp
.flags
|= MATCH_ICMP_SET
;
1652 temp
.flags
|= MATCH_PORT_SRC_SET
;
1653 temp2
.src_port_min
= src_port
->min_port
;
1654 if (src_port
->max_port
) {
1655 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1656 temp2
.src_port_max
= src_port
->max_port
;
1659 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1660 if (bpf
->protocol
== IPPROTO_ICMP
)
1661 temp
.flags
|= MATCH_ICMP_SET
;
1662 temp
.flags
|= MATCH_PORT_DST_SET
;
1663 temp2
.dst_port_min
= dst_port
->min_port
;
1664 if (dst_port
->max_port
) {
1665 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1666 temp2
.dst_port_max
= dst_port
->max_port
;
1669 temp2
.proto
= bpf
->protocol
;
1672 temp
.pkt_len_min
= pkt_len
->min_port
;
1673 if (pkt_len
->max_port
)
1674 temp
.pkt_len_max
= pkt_len
->max_port
;
1675 } else if (bpf
->pkt_len_val
) {
1676 if (bpf
->pkt_len_val
->mask
)
1677 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1678 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1680 if (bpf
->tcp_flags
) {
1681 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1682 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1685 if (bpf
->dscp
->mask
)
1686 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1688 temp
.flags
|= MATCH_DSCP_SET
;
1689 temp
.dscp_value
= bpf
->dscp
->val
;
1691 if (bpf
->fragment
) {
1692 if (bpf
->fragment
->mask
)
1693 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1694 temp
.fragment
= bpf
->fragment
->val
;
1697 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1698 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1699 temp
.type
= IPSET_NET_PORT
;
1701 temp
.type
= IPSET_NET
;
1703 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1704 temp
.type
= IPSET_NET_PORT_NET
;
1706 temp
.type
= IPSET_NET_NET
;
1708 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1711 temp
.vrf_id
= bpf
->vrf_id
;
1714 bpme
->backpointer
= bpm
;
1715 /* right now, a previous entry may already exist
1716 * flush previous entry if necessary
1718 bpmer
.bpme_to_match
= bpme
;
1719 bpmer
.bpme_found
= NULL
;
1720 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1721 if (bpmer
.bpme_found
) {
1722 static struct bgp_pbr_match
*local_bpm
;
1723 static struct bgp_pbr_action
*local_bpa
;
1725 local_bpm
= bpmer
.bpme_found
->backpointer
;
1726 local_bpa
= local_bpm
->action
;
1727 bgp_pbr_flush_entry(bgp
, local_bpa
,
1728 local_bpm
, bpmer
.bpme_found
);
1732 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1734 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1735 return FLOWSPEC_DSCP
;
1736 if (type_entry
== FLOWSPEC_DSCP
)
1737 return FLOWSPEC_PKT_LEN
;
1738 if (type_entry
== FLOWSPEC_PKT_LEN
)
1739 return FLOWSPEC_FRAGMENT
;
1740 if (type_entry
== FLOWSPEC_FRAGMENT
)
1741 return FLOWSPEC_ICMP_TYPE
;
1745 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1746 struct bgp_pbr_filter
*bpf
,
1747 struct bgp_pbr_or_filter
*bpof
, bool add
,
1748 struct nexthop
*nh
, float *rate
)
1750 struct bgp_pbr_range_port srcp
, dstp
;
1751 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1752 struct listnode
*tnode
, *cnode
;
1756 if (bpf
->protocol
!= IPPROTO_ICMP
)
1758 bpf
->src_port
= &srcp
;
1759 bpf
->dst_port
= &dstp
;
1760 /* parse icmp type and lookup appropriate icmp code
1761 * if no icmp code found, create as many entryes as
1762 * there are listed icmp codes for that icmp type
1764 if (!bpof
->icmp_type
) {
1766 srcp
.max_port
= 255;
1767 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1768 dstp
.min_port
= icmp_code
->val
;
1770 bgp_pbr_policyroute_add_to_zebra_unit(
1771 bgp
, path
, bpf
, nh
, rate
);
1773 bgp_pbr_policyroute_remove_from_zebra_unit(
1778 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1779 srcp
.min_port
= icmp_type
->val
;
1782 /* only icmp type. create an entry only with icmp type */
1783 if (!bpof
->icmp_code
) {
1784 /* icmp type is not one of the above
1785 * forge an entry only based on the icmp type
1788 dstp
.max_port
= 255;
1790 bgp_pbr_policyroute_add_to_zebra_unit(
1791 bgp
, path
, bpf
, nh
, rate
);
1793 bgp_pbr_policyroute_remove_from_zebra_unit(
1797 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1798 dstp
.min_port
= icmp_code
->val
;
1800 bgp_pbr_policyroute_add_to_zebra_unit(
1801 bgp
, path
, bpf
, nh
, rate
);
1803 bgp_pbr_policyroute_remove_from_zebra_unit(
1809 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1810 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1811 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1813 struct listnode
*node
, *nnode
;
1814 struct bgp_pbr_val_mask
*valmask
;
1815 uint8_t next_type_entry
;
1816 struct list
*orig_list
;
1817 struct bgp_pbr_val_mask
**target_val
;
1819 if (type_entry
== 0) {
1820 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1823 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1824 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1825 orig_list
= bpof
->tcpflags
;
1826 target_val
= &bpf
->tcp_flags
;
1827 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1828 orig_list
= bpof
->dscp
;
1829 target_val
= &bpf
->dscp
;
1830 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1831 orig_list
= bpof
->pkt_len
;
1832 target_val
= &bpf
->pkt_len_val
;
1833 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1834 orig_list
= bpof
->fragment
;
1835 target_val
= &bpf
->fragment
;
1836 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1837 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1838 /* enumerate list for icmp - must be last one */
1839 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1842 bgp_pbr_policyroute_remove_from_zebra_recursive(
1843 bgp
, path
, bpf
, bpof
, next_type_entry
);
1846 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1847 *target_val
= valmask
;
1848 bgp_pbr_policyroute_remove_from_zebra_recursive(
1849 bgp
, path
, bpf
, bpof
, next_type_entry
);
1853 static void bgp_pbr_policyroute_remove_from_zebra(
1854 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1855 struct bgp_pbr_or_filter
*bpof
)
1858 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1862 bgp_pbr_policyroute_remove_from_zebra_recursive(
1863 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1864 else if (bpof
->dscp
)
1865 bgp_pbr_policyroute_remove_from_zebra_recursive(
1866 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1867 else if (bpof
->pkt_len
)
1868 bgp_pbr_policyroute_remove_from_zebra_recursive(
1869 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1870 else if (bpof
->fragment
)
1871 bgp_pbr_policyroute_remove_from_zebra_recursive(
1872 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1873 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1874 bgp_pbr_policyroute_remove_from_zebra_recursive(
1875 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1877 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1880 list_delete_all_node(bpof
->tcpflags
);
1882 list_delete_all_node(bpof
->dscp
);
1884 list_delete_all_node(bpof
->pkt_len
);
1886 list_delete_all_node(bpof
->fragment
);
1889 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1891 struct bgp_pbr_range_port
*src_port
;
1892 struct bgp_pbr_range_port
*dst_port
;
1893 struct bgp_pbr_range_port
*pkt_len
;
1894 char bufsrc
[64], bufdst
[64];
1896 int remaining_len
= 0;
1897 char protocol_str
[16];
1901 src_port
= bpf
->src_port
;
1902 dst_port
= bpf
->dst_port
;
1903 pkt_len
= bpf
->pkt_len
;
1905 protocol_str
[0] = '\0';
1906 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1907 bpf
->protocol
= IPPROTO_TCP
;
1909 snprintf(protocol_str
, sizeof(protocol_str
),
1910 "proto %d", bpf
->protocol
);
1912 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1913 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1916 dst_port
->min_port
);
1917 else if (bpf
->protocol
== IPPROTO_UDP
||
1918 bpf
->protocol
== IPPROTO_TCP
) {
1920 if (src_port
&& src_port
->min_port
)
1921 remaining_len
+= snprintf(buffer
,
1925 src_port
->max_port
?
1926 src_port
->max_port
:
1927 src_port
->min_port
);
1928 if (dst_port
&& dst_port
->min_port
)
1929 remaining_len
+= snprintf(buffer
+
1935 dst_port
->max_port
?
1936 dst_port
->max_port
:
1937 dst_port
->min_port
);
1939 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1940 remaining_len
+= snprintf(buffer
+ remaining_len
,
1948 } else if (bpf
->pkt_len_val
) {
1949 remaining_len
+= snprintf(buffer
+ remaining_len
,
1953 bpf
->pkt_len_val
->mask
1955 bpf
->pkt_len_val
->val
);
1957 if (bpf
->tcp_flags
) {
1958 remaining_len
+= snprintf(buffer
+ remaining_len
,
1962 bpf
->tcp_flags
->val
,
1963 bpf
->tcp_flags
->mask
);
1966 snprintf(buffer
+ remaining_len
,
1974 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1975 add
? "adding" : "removing",
1976 bpf
->src
== NULL
? "<all>" :
1977 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1978 bpf
->dst
== NULL
? "<all>" :
1979 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1980 protocol_str
, buffer
);
1984 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1985 struct bgp_path_info
*path
,
1986 struct bgp_pbr_filter
*bpf
,
1990 struct bgp_pbr_match temp
;
1991 struct bgp_pbr_match_entry temp2
;
1992 struct bgp_pbr_match
*bpm
;
1993 struct bgp_pbr_match_entry
*bpme
= NULL
;
1994 struct bgp_pbr_action temp3
;
1995 struct bgp_pbr_action
*bpa
= NULL
;
1996 struct bgp_pbr_match_entry_remain bpmer
;
1997 struct bgp_pbr_rule_remain bprr
;
1998 struct bgp_pbr_range_port
*src_port
;
1999 struct bgp_pbr_range_port
*dst_port
;
2000 struct bgp_pbr_range_port
*pkt_len
;
2001 struct bgp_pbr_rule pbr_rule
;
2002 struct bgp_pbr_rule
*bpr
;
2003 bool bpr_found
= false;
2004 bool bpme_found
= false;
2008 src_port
= bpf
->src_port
;
2009 dst_port
= bpf
->dst_port
;
2010 pkt_len
= bpf
->pkt_len
;
2012 if (BGP_DEBUG(zebra
, ZEBRA
))
2013 bgp_pbr_dump_entry(bpf
, true);
2015 /* look for bpa first */
2016 memset(&temp3
, 0, sizeof(temp3
));
2020 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2021 temp3
.vrf_id
= bpf
->vrf_id
;
2022 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2023 bgp_pbr_action_alloc_intern
);
2025 if (bpa
->fwmark
== 0) {
2026 /* drop is handled by iptable */
2027 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2029 bpa
->installed
= true;
2031 bpa
->fwmark
= bgp_zebra_tm_get_id();
2032 bpa
->table_id
= bpa
->fwmark
;
2033 bpa
->installed
= false;
2036 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2037 /* 0 value is forbidden */
2038 bpa
->install_in_progress
= false;
2040 if (bpf
->type
== BGP_PBR_IPRULE
) {
2041 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2042 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2043 pbr_rule
.priority
= 20;
2045 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2046 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2049 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2050 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2052 pbr_rule
.action
= bpa
;
2053 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2054 bgp_pbr_rule_alloc_intern
);
2055 if (bpr
&& bpr
->unique
== 0) {
2056 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2057 bpr
->installed
= false;
2058 bpr
->install_in_progress
= false;
2059 /* link bgp info to bpr */
2060 bpr
->path
= (void *)path
;
2063 /* already installed */
2064 if (bpr_found
&& bpr
) {
2065 struct bgp_path_info_extra
*extra
=
2066 bgp_path_info_extra_get(path
);
2068 if (extra
&& listnode_lookup(extra
->bgp_fs_iprule
,
2070 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2071 zlog_err("%s: entry %p/%p already "
2072 "installed in bgp pbr iprule",
2073 __func__
, path
, bpr
);
2077 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2078 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2079 bgp_zebra_announce_default(bgp
, nh
,
2080 AFI_IP
, bpa
->table_id
, true);
2083 if (bpr
&& !bpr
->installed
)
2084 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2086 /* A previous entry may already exist
2087 * flush previous entry if necessary
2089 bprr
.bpr_to_match
= bpr
;
2090 bprr
.bpr_found
= NULL
;
2091 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2092 if (bprr
.bpr_found
) {
2093 static struct bgp_pbr_rule
*local_bpr
;
2094 static struct bgp_pbr_action
*local_bpa
;
2096 local_bpr
= bprr
.bpr_found
;
2097 local_bpa
= local_bpr
->action
;
2098 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2103 /* then look for bpm */
2104 memset(&temp
, 0, sizeof(temp
));
2105 temp
.vrf_id
= bpf
->vrf_id
;
2107 temp
.flags
|= MATCH_IP_SRC_SET
;
2109 temp
.flags
|= MATCH_IP_DST_SET
;
2111 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2112 if (bpf
->protocol
== IPPROTO_ICMP
)
2113 temp
.flags
|= MATCH_ICMP_SET
;
2114 temp
.flags
|= MATCH_PORT_SRC_SET
;
2116 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2117 if (bpf
->protocol
== IPPROTO_ICMP
)
2118 temp
.flags
|= MATCH_ICMP_SET
;
2119 temp
.flags
|= MATCH_PORT_DST_SET
;
2121 if (src_port
&& src_port
->max_port
)
2122 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2123 if (dst_port
&& dst_port
->max_port
)
2124 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2126 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2127 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2128 temp
.type
= IPSET_NET_PORT
;
2130 temp
.type
= IPSET_NET
;
2132 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2133 temp
.type
= IPSET_NET_PORT_NET
;
2135 temp
.type
= IPSET_NET_NET
;
2138 temp
.pkt_len_min
= pkt_len
->min_port
;
2139 if (pkt_len
->max_port
)
2140 temp
.pkt_len_max
= pkt_len
->max_port
;
2141 } else if (bpf
->pkt_len_val
) {
2142 if (bpf
->pkt_len_val
->mask
)
2143 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2144 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2146 if (bpf
->tcp_flags
) {
2147 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2148 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2151 if (bpf
->dscp
->mask
)
2152 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2154 temp
.flags
|= MATCH_DSCP_SET
;
2155 temp
.dscp_value
= bpf
->dscp
->val
;
2157 if (bpf
->fragment
) {
2158 if (bpf
->fragment
->mask
)
2159 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2160 temp
.fragment
= bpf
->fragment
->val
;
2163 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2164 bgp_pbr_match_alloc_intern
);
2166 /* new, then self allocate ipset_name and unique */
2167 if (bpm
->unique
== 0) {
2168 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2169 /* 0 value is forbidden */
2170 sprintf(bpm
->ipset_name
, "match%p", bpm
);
2171 bpm
->entry_hash
= hash_create_size(8,
2172 bgp_pbr_match_entry_hash_key
,
2173 bgp_pbr_match_entry_hash_equal
,
2174 "Match Entry Hash");
2175 bpm
->installed
= false;
2177 /* unique2 should be updated too */
2178 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2179 bpm
->installed_in_iptable
= false;
2180 bpm
->install_in_progress
= false;
2181 bpm
->install_iptable_in_progress
= false;
2184 memset(&temp2
, 0, sizeof(temp2
));
2186 prefix_copy(&temp2
.src
, bpf
->src
);
2188 temp2
.src
.family
= AF_INET
;
2190 prefix_copy(&temp2
.dst
, bpf
->dst
);
2192 temp2
.dst
.family
= AF_INET
;
2193 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2194 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2195 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2196 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2197 temp2
.proto
= bpf
->protocol
;
2198 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2199 bgp_pbr_match_entry_alloc_intern
);
2200 if (bpme
->unique
== 0) {
2201 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2202 /* 0 value is forbidden */
2203 bpme
->backpointer
= bpm
;
2204 bpme
->installed
= false;
2205 bpme
->install_in_progress
= false;
2206 /* link bgp info to bpme */
2207 bpme
->path
= (void *)path
;
2211 /* already installed */
2213 struct bgp_path_info_extra
*extra
=
2214 bgp_path_info_extra_get(path
);
2216 if (extra
&& listnode_lookup(extra
->bgp_fs_pbr
, bpme
)) {
2217 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2219 "%s: entry %p/%p already installed in bgp pbr",
2220 __func__
, path
, bpme
);
2224 /* BGP FS: append entry to zebra
2225 * - policies are not routing entries and as such
2226 * route replace semantics don't necessarily follow
2227 * through to policy entries
2228 * - because of that, not all policing information will be stored
2229 * into zebra. and non selected policies will be suppressed from zebra
2230 * - as consequence, in order to bring consistency
2231 * a policy will be added, then ifan ecmp policy exists,
2232 * it will be suppressed subsequently
2235 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2236 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2237 bgp_zebra_announce_default(bgp
, nh
,
2238 AFI_IP
, bpa
->table_id
, true);
2242 if (!bpm
->installed
)
2243 bgp_send_pbr_ipset_match(bpm
, true);
2245 if (!bpme
->installed
)
2246 bgp_send_pbr_ipset_entry_match(bpme
, true);
2249 if (!bpm
->installed_in_iptable
)
2250 bgp_send_pbr_iptable(bpa
, bpm
, true);
2252 /* A previous entry may already exist
2253 * flush previous entry if necessary
2255 bpmer
.bpme_to_match
= bpme
;
2256 bpmer
.bpme_found
= NULL
;
2257 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2258 if (bpmer
.bpme_found
) {
2259 static struct bgp_pbr_match
*local_bpm
;
2260 static struct bgp_pbr_action
*local_bpa
;
2262 local_bpm
= bpmer
.bpme_found
->backpointer
;
2263 local_bpa
= local_bpm
->action
;
2264 bgp_pbr_flush_entry(bgp
, local_bpa
,
2265 local_bpm
, bpmer
.bpme_found
);
2271 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2272 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2273 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2276 struct listnode
*node
, *nnode
;
2277 struct bgp_pbr_val_mask
*valmask
;
2278 uint8_t next_type_entry
;
2279 struct list
*orig_list
;
2280 struct bgp_pbr_val_mask
**target_val
;
2282 if (type_entry
== 0) {
2283 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2286 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2287 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2288 orig_list
= bpof
->tcpflags
;
2289 target_val
= &bpf
->tcp_flags
;
2290 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2291 orig_list
= bpof
->dscp
;
2292 target_val
= &bpf
->dscp
;
2293 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2294 orig_list
= bpof
->pkt_len
;
2295 target_val
= &bpf
->pkt_len_val
;
2296 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2297 orig_list
= bpof
->fragment
;
2298 target_val
= &bpf
->fragment
;
2299 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2300 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2301 /* enumerate list for icmp - must be last one */
2302 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2305 bgp_pbr_policyroute_add_to_zebra_recursive(
2306 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2309 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2310 *target_val
= valmask
;
2311 bgp_pbr_policyroute_add_to_zebra_recursive(
2312 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2316 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2317 struct bgp_path_info
*path
,
2318 struct bgp_pbr_filter
*bpf
,
2319 struct bgp_pbr_or_filter
*bpof
,
2320 struct nexthop
*nh
, float *rate
)
2323 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2327 bgp_pbr_policyroute_add_to_zebra_recursive(
2328 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2329 else if (bpof
->dscp
)
2330 bgp_pbr_policyroute_add_to_zebra_recursive(
2331 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2332 else if (bpof
->pkt_len
)
2333 bgp_pbr_policyroute_add_to_zebra_recursive(
2334 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2335 else if (bpof
->fragment
)
2336 bgp_pbr_policyroute_add_to_zebra_recursive(
2337 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2338 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2339 bgp_pbr_policyroute_add_to_zebra_recursive(
2340 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2342 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2345 list_delete_all_node(bpof
->tcpflags
);
2347 list_delete_all_node(bpof
->dscp
);
2349 list_delete_all_node(bpof
->pkt_len
);
2351 list_delete_all_node(bpof
->fragment
);
2352 if (bpof
->icmp_type
)
2353 list_delete_all_node(bpof
->icmp_type
);
2354 if (bpof
->icmp_code
)
2355 list_delete_all_node(bpof
->icmp_code
);
2358 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2359 struct bgp_pbr_entry_main
*api
, bool add
)
2363 int continue_loop
= 1;
2365 struct prefix
*src
= NULL
, *dst
= NULL
;
2367 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2368 struct bgp_pbr_range_port range
, range_icmp_code
;
2369 struct bgp_pbr_range_port pkt_len
;
2370 struct bgp_pbr_filter bpf
;
2372 struct bgp_pbr_or_filter bpof
;
2373 struct bgp_pbr_val_mask bpvm
;
2375 memset(&nh
, 0, sizeof(struct nexthop
));
2376 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2377 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2378 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2379 (api
->type
== BGP_PBR_IPRULE
&&
2380 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2381 src
= &api
->src_prefix
;
2382 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2383 (api
->type
== BGP_PBR_IPRULE
&&
2384 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2385 dst
= &api
->dst_prefix
;
2386 if (api
->type
== BGP_PBR_IPRULE
)
2387 bpf
.type
= api
->type
;
2388 memset(&nh
, 0, sizeof(struct nexthop
));
2389 nh
.vrf_id
= VRF_UNKNOWN
;
2390 if (api
->match_protocol_num
)
2391 proto
= (uint8_t)api
->protocol
[0].value
;
2392 /* if match_port is selected, then either src or dst port will be parsed
2393 * but not both at the same time
2395 if (api
->match_port_num
>= 1) {
2396 bgp_pbr_extract(api
->port
,
2397 api
->match_port_num
,
2399 srcp
= dstp
= &range
;
2400 } else if (api
->match_src_port_num
>= 1) {
2401 bgp_pbr_extract(api
->src_port
,
2402 api
->match_src_port_num
,
2406 } else if (api
->match_dst_port_num
>= 1) {
2407 bgp_pbr_extract(api
->dst_port
,
2408 api
->match_dst_port_num
,
2413 if (api
->match_icmp_type_num
>= 1) {
2414 proto
= IPPROTO_ICMP
;
2415 if (bgp_pbr_extract(api
->icmp_type
,
2416 api
->match_icmp_type_num
,
2420 bpof
.icmp_type
= list_new();
2421 bgp_pbr_extract_enumerate(api
->icmp_type
,
2422 api
->match_icmp_type_num
,
2425 FLOWSPEC_ICMP_TYPE
);
2428 if (api
->match_icmp_code_num
>= 1) {
2429 proto
= IPPROTO_ICMP
;
2430 if (bgp_pbr_extract(api
->icmp_code
,
2431 api
->match_icmp_code_num
,
2433 dstp
= &range_icmp_code
;
2435 bpof
.icmp_code
= list_new();
2436 bgp_pbr_extract_enumerate(api
->icmp_code
,
2437 api
->match_icmp_code_num
,
2440 FLOWSPEC_ICMP_CODE
);
2444 if (api
->match_tcpflags_num
) {
2445 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2446 api
->match_tcpflags_num
);
2447 if (kind_enum
== OPERATOR_UNARY_AND
) {
2448 bpf
.tcp_flags
= &bpvm
;
2449 bgp_pbr_extract_enumerate(api
->tcpflags
,
2450 api
->match_tcpflags_num
,
2453 FLOWSPEC_TCP_FLAGS
);
2454 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2455 bpof
.tcpflags
= list_new();
2456 bgp_pbr_extract_enumerate(api
->tcpflags
,
2457 api
->match_tcpflags_num
,
2460 FLOWSPEC_TCP_FLAGS
);
2463 if (api
->match_packet_length_num
) {
2466 ret
= bgp_pbr_extract(api
->packet_length
,
2467 api
->match_packet_length_num
,
2470 bpf
.pkt_len
= &pkt_len
;
2472 bpof
.pkt_len
= list_new();
2473 bgp_pbr_extract_enumerate(api
->packet_length
,
2474 api
->match_packet_length_num
,
2480 if (api
->match_dscp_num
>= 1) {
2481 bpof
.dscp
= list_new();
2482 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2484 bpof
.dscp
, FLOWSPEC_DSCP
);
2486 if (api
->match_fragment_num
) {
2487 bpof
.fragment
= list_new();
2488 bgp_pbr_extract_enumerate(api
->fragment
,
2489 api
->match_fragment_num
,
2494 bpf
.vrf_id
= api
->vrf_id
;
2497 bpf
.protocol
= proto
;
2498 bpf
.src_port
= srcp
;
2499 bpf
.dst_port
= dstp
;
2501 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2504 /* no action for add = true */
2505 for (i
= 0; i
< api
->action_num
; i
++) {
2506 switch (api
->actions
[i
].action
) {
2507 case ACTION_TRAFFICRATE
:
2509 if (api
->actions
[i
].u
.r
.rate
== 0) {
2510 nh
.vrf_id
= api
->vrf_id
;
2511 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2512 bgp_pbr_policyroute_add_to_zebra(
2513 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2515 /* update rate. can be reentrant */
2516 rate
= api
->actions
[i
].u
.r
.rate
;
2517 if (BGP_DEBUG(pbr
, PBR
)) {
2518 bgp_pbr_print_policy_route(api
);
2519 zlog_warn("PBR: ignoring Set action rate %f",
2520 api
->actions
[i
].u
.r
.rate
);
2524 case ACTION_TRAFFIC_ACTION
:
2525 if (api
->actions
[i
].u
.za
.filter
2526 & TRAFFIC_ACTION_SAMPLE
) {
2527 if (BGP_DEBUG(pbr
, PBR
)) {
2528 bgp_pbr_print_policy_route(api
);
2529 zlog_warn("PBR: Sample action Ignored");
2533 if (api
->actions
[i
].u
.za
.filter
2534 & TRAFFIC_ACTION_DISTRIBUTE
) {
2535 if (BGP_DEBUG(pbr
, PBR
)) {
2536 bgp_pbr_print_policy_route(api
);
2537 zlog_warn("PBR: Distribute action Applies");
2540 /* continue forwarding entry as before
2544 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2545 /* terminate action: run other filters
2548 case ACTION_REDIRECT_IP
:
2549 nh
.type
= NEXTHOP_TYPE_IPV4
;
2550 nh
.gate
.ipv4
.s_addr
=
2551 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2552 nh
.vrf_id
= api
->vrf_id
;
2553 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2555 /* XXX combination with REDIRECT_VRF
2556 * + REDIRECT_NH_IP not done
2560 case ACTION_REDIRECT
:
2561 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2562 nh
.type
= NEXTHOP_TYPE_IPV4
;
2563 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2567 case ACTION_MARKING
:
2568 if (BGP_DEBUG(pbr
, PBR
)) {
2569 bgp_pbr_print_policy_route(api
);
2570 zlog_warn("PBR: Set DSCP %u Ignored",
2571 api
->actions
[i
].u
.marking_dscp
);
2577 if (continue_loop
== 0)
2582 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2583 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2586 struct bgp_pbr_entry_main api
;
2589 return; /* IPv6 not supported */
2590 if (safi
!= SAFI_FLOWSPEC
)
2591 return; /* not supported */
2592 /* Make Zebra API structure. */
2593 memset(&api
, 0, sizeof(api
));
2594 api
.vrf_id
= bgp
->vrf_id
;
2597 if (!bgp_zebra_tm_chunk_obtained()) {
2598 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2599 flog_err(EC_BGP_TABLE_CHUNK
,
2600 "%s: table chunk not obtained yet", __func__
);
2604 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2605 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2606 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2607 "%s: cancel updating entry %p in bgp pbr",
2611 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2614 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2615 const struct bgp_pbr_interface
*b
)
2617 return strcmp(a
->name
, b
->name
);
2620 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2621 struct bgp_pbr_interface_head
*head
)
2623 struct bgp_pbr_interface pbr_if
;
2625 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2626 return (RB_FIND(bgp_pbr_interface_head
,
2630 /* this function resets to the default policy routing
2631 * go back to default status
2633 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2635 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2636 struct bgp_pbr_interface_head
*head
;
2637 struct bgp_pbr_interface
*pbr_if
;
2639 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2641 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2643 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2644 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2645 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2646 XFREE(MTYPE_TMP
, pbr_if
);