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 "lib/printfrr.h"
28 #include "bgpd/bgpd.h"
29 #include "bgpd/bgp_pbr.h"
30 #include "bgpd/bgp_debug.h"
31 #include "bgpd/bgp_flowspec_util.h"
32 #include "bgpd/bgp_ecommunity.h"
33 #include "bgpd/bgp_route.h"
34 #include "bgpd/bgp_attr.h"
35 #include "bgpd/bgp_zebra.h"
36 #include "bgpd/bgp_mplsvpn.h"
37 #include "bgpd/bgp_flowspec_private.h"
38 #include "bgpd/bgp_errors.h"
40 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry")
41 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match")
42 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action")
43 DEFINE_MTYPE_STATIC(BGPD
, PBR_RULE
, "PBR rule")
44 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context")
45 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value")
47 /* chain strings too long to fit in one line */
48 #define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
49 #define IPV6_FRAGMENT_INVALID "fragment not valid for IPv6 for this implementation"
51 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
52 id_entry
, bgp_pbr_interface_compare
);
53 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
54 RB_INITIALIZER(&ifaces_by_name_ipv4
);
56 static int bgp_pbr_match_counter_unique
;
57 static int bgp_pbr_match_entry_counter_unique
;
58 static int bgp_pbr_action_counter_unique
;
59 static int bgp_pbr_match_iptable_counter_unique
;
61 struct bgp_pbr_match_iptable_unique
{
63 struct bgp_pbr_match
*bpm_found
;
66 struct bgp_pbr_match_entry_unique
{
68 struct bgp_pbr_match_entry
*bpme_found
;
71 struct bgp_pbr_action_unique
{
73 struct bgp_pbr_action
*bpa_found
;
76 struct bgp_pbr_rule_unique
{
78 struct bgp_pbr_rule
*bpr_found
;
81 static int bgp_pbr_rule_walkcb(struct hash_bucket
*bucket
, void *arg
)
83 struct bgp_pbr_rule
*bpr
= (struct bgp_pbr_rule
*)bucket
->data
;
84 struct bgp_pbr_rule_unique
*bpru
= (struct bgp_pbr_rule_unique
*)
86 uint32_t unique
= bpru
->unique
;
88 if (bpr
->unique
== unique
) {
89 bpru
->bpr_found
= bpr
;
90 return HASHWALK_ABORT
;
92 return HASHWALK_CONTINUE
;
95 static int bgp_pbr_action_walkcb(struct hash_bucket
*bucket
, void *arg
)
97 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)bucket
->data
;
98 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
100 uint32_t unique
= bpau
->unique
;
102 if (bpa
->unique
== unique
) {
103 bpau
->bpa_found
= bpa
;
104 return HASHWALK_ABORT
;
106 return HASHWALK_CONTINUE
;
109 static int bgp_pbr_match_entry_walkcb(struct hash_bucket
*bucket
, void *arg
)
111 struct bgp_pbr_match_entry
*bpme
=
112 (struct bgp_pbr_match_entry
*)bucket
->data
;
113 struct bgp_pbr_match_entry_unique
*bpmeu
=
114 (struct bgp_pbr_match_entry_unique
*)arg
;
115 uint32_t unique
= bpmeu
->unique
;
117 if (bpme
->unique
== unique
) {
118 bpmeu
->bpme_found
= bpme
;
119 return HASHWALK_ABORT
;
121 return HASHWALK_CONTINUE
;
124 struct bgp_pbr_match_ipsetname
{
126 struct bgp_pbr_match
*bpm_found
;
129 static int bgp_pbr_match_pername_walkcb(struct hash_bucket
*bucket
, void *arg
)
131 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
132 struct bgp_pbr_match_ipsetname
*bpmi
=
133 (struct bgp_pbr_match_ipsetname
*)arg
;
134 char *ipset_name
= bpmi
->ipsetname
;
136 if (!strncmp(ipset_name
, bpm
->ipset_name
,
137 ZEBRA_IPSET_NAME_SIZE
)) {
138 bpmi
->bpm_found
= bpm
;
139 return HASHWALK_ABORT
;
141 return HASHWALK_CONTINUE
;
144 static int bgp_pbr_match_iptable_walkcb(struct hash_bucket
*bucket
, void *arg
)
146 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
147 struct bgp_pbr_match_iptable_unique
*bpmiu
=
148 (struct bgp_pbr_match_iptable_unique
*)arg
;
149 uint32_t unique
= bpmiu
->unique
;
151 if (bpm
->unique2
== unique
) {
152 bpmiu
->bpm_found
= bpm
;
153 return HASHWALK_ABORT
;
155 return HASHWALK_CONTINUE
;
158 struct bgp_pbr_match_unique
{
160 struct bgp_pbr_match
*bpm_found
;
163 static int bgp_pbr_match_walkcb(struct hash_bucket
*bucket
, void *arg
)
165 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
166 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
168 uint32_t unique
= bpmu
->unique
;
170 if (bpm
->unique
== unique
) {
171 bpmu
->bpm_found
= bpm
;
172 return HASHWALK_ABORT
;
174 return HASHWALK_CONTINUE
;
177 static int snprintf_bgp_pbr_match_val(char *str
, int len
,
178 struct bgp_pbr_match_val
*mval
,
185 delta
= snprintf(ptr
, len
, "%s", prepend
);
189 if (mval
->unary_operator
& OPERATOR_UNARY_OR
) {
190 delta
= snprintf(ptr
, len
, ", or ");
194 if (mval
->unary_operator
& OPERATOR_UNARY_AND
) {
195 delta
= snprintf(ptr
, len
, ", and ");
200 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
) {
201 delta
= snprintf(ptr
, len
, "<");
205 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
) {
206 delta
= snprintf(ptr
, len
, ">");
210 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
) {
211 delta
= snprintf(ptr
, len
, "=");
215 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
) {
216 delta
= snprintf(ptr
, len
, "match");
220 ptr
+= snprintf(ptr
, len
, " %u", mval
->value
);
221 return (int)(ptr
- str
);
224 #define INCREMENT_DISPLAY(_ptr, _cnt, _len) do { \
228 sn_delta = snprintf((_ptr), (_len), "; ");\
229 (_len) -= sn_delta; \
230 (_ptr) += sn_delta; \
235 /* this structure can be used for port range,
236 * but also for other values range like packet length range
238 struct bgp_pbr_range_port
{
243 /* this structure can be used to filter with a mask
244 * for instance it supports not instructions like for
247 struct bgp_pbr_val_mask
{
252 /* this structure is used to pass instructs
253 * so that BGP can create pbr instructions to ZEBRA
255 struct bgp_pbr_filter
{
261 uint8_t bitmask_iprule
;
263 struct bgp_pbr_range_port
*pkt_len
;
264 struct bgp_pbr_range_port
*src_port
;
265 struct bgp_pbr_range_port
*dst_port
;
266 struct bgp_pbr_val_mask
*tcp_flags
;
267 struct bgp_pbr_val_mask
*dscp
;
268 struct bgp_pbr_val_mask
*flow_label
;
269 struct bgp_pbr_val_mask
*pkt_len_val
;
270 struct bgp_pbr_val_mask
*fragment
;
273 /* this structure is used to contain OR instructions
274 * so that BGP can create multiple pbr instructions
277 struct bgp_pbr_or_filter
{
278 struct list
*tcpflags
;
280 struct list
*flowlabel
;
281 struct list
*pkt_len
;
282 struct list
*fragment
;
283 struct list
*icmp_type
;
284 struct list
*icmp_code
;
287 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
288 struct bgp_path_info
*path
,
289 struct bgp_pbr_filter
*bpf
,
293 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
295 static bool bgp_pbr_extract_enumerate_unary_opposite(
296 uint8_t unary_operator
,
297 struct bgp_pbr_val_mask
*and_valmask
,
298 struct list
*or_valmask
, uint32_t value
,
301 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
302 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
304 TCP_HEADER_ALL_FLAGS
&
306 } else if (type_entry
== FLOWSPEC_DSCP
||
307 type_entry
== FLOWSPEC_FLOW_LABEL
||
308 type_entry
== FLOWSPEC_PKT_LEN
||
309 type_entry
== FLOWSPEC_FRAGMENT
) {
310 and_valmask
->val
= value
;
311 and_valmask
->mask
= 1; /* inverse */
313 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
314 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
315 sizeof(struct bgp_pbr_val_mask
));
316 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
317 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
319 TCP_HEADER_ALL_FLAGS
&
321 } else if (type_entry
== FLOWSPEC_DSCP
||
322 type_entry
== FLOWSPEC_FLOW_LABEL
||
323 type_entry
== FLOWSPEC_FRAGMENT
||
324 type_entry
== FLOWSPEC_PKT_LEN
) {
325 and_valmask
->val
= value
;
326 and_valmask
->mask
= 1; /* inverse */
328 listnode_add(or_valmask
, and_valmask
);
329 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
330 type_entry
== FLOWSPEC_ICMP_TYPE
)
335 /* TCP : FIN and SYN -> val = ALL; mask = 3
336 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
337 * other variables type: dscp, pkt len, fragment, flow label
338 * - value is copied in bgp_pbr_val_mask->val value
339 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
341 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
342 int num
, uint8_t unary_operator
,
343 void *valmask
, uint8_t type_entry
)
346 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
347 struct list
*or_valmask
= NULL
;
351 if (unary_operator
== OPERATOR_UNARY_AND
) {
352 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
353 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
354 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
355 or_valmask
= (struct list
*)valmask
;
358 for (i
= 0; i
< num
; i
++) {
359 if (i
!= 0 && list
[i
].unary_operator
!=
362 if (!(list
[i
].compare_operator
&
363 OPERATOR_COMPARE_EQUAL_TO
) &&
364 !(list
[i
].compare_operator
&
365 OPERATOR_COMPARE_EXACT_MATCH
)) {
366 if ((list
[i
].compare_operator
&
367 OPERATOR_COMPARE_LESS_THAN
) &&
368 (list
[i
].compare_operator
&
369 OPERATOR_COMPARE_GREATER_THAN
)) {
370 ret
= bgp_pbr_extract_enumerate_unary_opposite(
371 unary_operator
, and_valmask
,
372 or_valmask
, list
[i
].value
,
380 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
381 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
383 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
384 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
385 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
386 sizeof(struct bgp_pbr_val_mask
));
387 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
388 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
390 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
391 } else if (type_entry
== FLOWSPEC_DSCP
||
392 type_entry
== FLOWSPEC_FLOW_LABEL
||
393 type_entry
== FLOWSPEC_ICMP_TYPE
||
394 type_entry
== FLOWSPEC_ICMP_CODE
||
395 type_entry
== FLOWSPEC_FRAGMENT
||
396 type_entry
== FLOWSPEC_PKT_LEN
)
397 and_valmask
->val
= list
[i
].value
;
398 listnode_add(or_valmask
, and_valmask
);
401 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
402 && type_entry
== FLOWSPEC_TCP_FLAGS
)
403 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
407 /* if unary operator can either be UNARY_OR/AND/OR-AND.
408 * in the latter case, combinationf of both is not handled
410 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
411 int num
, uint8_t unary_operator
,
412 void *valmask
, uint8_t type_entry
)
415 uint8_t unary_operator_val
;
416 bool double_check
= false;
418 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
419 (unary_operator
& OPERATOR_UNARY_AND
)) {
420 unary_operator_val
= OPERATOR_UNARY_AND
;
423 unary_operator_val
= unary_operator
;
424 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
425 valmask
, type_entry
);
426 if (!ret
&& double_check
)
427 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
434 /* returns the unary operator that is in the list
435 * return 0 if both operators are used
437 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
442 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
444 for (i
= 0; i
< num
; i
++) {
447 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
448 unary_operator
= OPERATOR_UNARY_OR
;
449 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
450 && unary_operator
== OPERATOR_UNARY_OR
) ||
451 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
452 && unary_operator
== OPERATOR_UNARY_AND
))
455 return unary_operator
;
459 /* return true if extraction ok
461 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
463 struct bgp_pbr_range_port
*range
)
466 bool exact_match
= false;
469 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
473 for (i
= 0; i
< num
; i
++) {
474 if (i
!= 0 && (list
[i
].compare_operator
==
475 OPERATOR_COMPARE_EQUAL_TO
))
477 if (i
== 0 && (list
[i
].compare_operator
==
478 OPERATOR_COMPARE_EQUAL_TO
)) {
480 range
->min_port
= list
[i
].value
;
483 if (exact_match
&& i
> 0)
485 if (list
[i
].compare_operator
==
486 (OPERATOR_COMPARE_GREATER_THAN
+
487 OPERATOR_COMPARE_EQUAL_TO
)) {
489 range
->min_port
= list
[i
].value
;
490 } else if (list
[i
].compare_operator
==
491 (OPERATOR_COMPARE_LESS_THAN
+
492 OPERATOR_COMPARE_EQUAL_TO
)) {
494 range
->max_port
= list
[i
].value
;
495 } else if (list
[i
].compare_operator
==
496 OPERATOR_COMPARE_LESS_THAN
) {
498 range
->max_port
= list
[i
].value
- 1;
499 } else if (list
[i
].compare_operator
==
500 OPERATOR_COMPARE_GREATER_THAN
) {
502 range
->min_port
= list
[i
].value
+ 1;
508 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
510 bool enumerate_icmp
= false;
512 if (api
->type
== BGP_PBR_UNDEFINED
) {
513 if (BGP_DEBUG(pbr
, PBR
))
514 zlog_debug("BGP: pbr entry undefined. cancel.");
517 /* because bgp pbr entry may contain unsupported
518 * combinations, a message will be displayed here if
520 * for now, only match/set supported is
521 * - combination src/dst => redirect nexthop [ + rate]
522 * - combination src/dst => redirect VRF [ + rate]
523 * - combination src/dst => drop
524 * - combination srcport + @IP
526 if (api
->match_protocol_num
> 1) {
527 if (BGP_DEBUG(pbr
, PBR
))
528 zlog_debug("BGP: match protocol operations:multiple protocols ( %d). ignoring.",
529 api
->match_protocol_num
);
532 if (api
->src_prefix_offset
> 0 ||
533 api
->dst_prefix_offset
> 0) {
534 if (BGP_DEBUG(pbr
, PBR
))
535 zlog_debug("BGP: match prefix offset:"
536 "implementation does not support it.");
539 if (api
->match_protocol_num
== 1 &&
540 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
541 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
542 api
->protocol
[0].value
!= PROTOCOL_ICMPV6
&&
543 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
544 if (BGP_DEBUG(pbr
, PBR
))
545 zlog_debug("BGP: match protocol operations:protocol (%d) not supported. ignoring",
546 api
->match_protocol_num
);
549 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
550 if (BGP_DEBUG(pbr
, PBR
))
551 zlog_debug("BGP: match src port operations:too complex. ignoring.");
554 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
555 if (BGP_DEBUG(pbr
, PBR
))
556 zlog_debug("BGP: match dst port operations:too complex. ignoring.");
559 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
560 api
->match_tcpflags_num
,
562 OPERATOR_UNARY_OR
, NULL
,
563 FLOWSPEC_TCP_FLAGS
)) {
564 if (BGP_DEBUG(pbr
, PBR
))
565 zlog_debug("BGP: match tcp flags:too complex. ignoring.");
568 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
569 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
570 api
->match_icmp_type_num
,
571 OPERATOR_UNARY_OR
, NULL
,
572 FLOWSPEC_ICMP_TYPE
)) {
573 if (BGP_DEBUG(pbr
, PBR
))
574 zlog_debug("BGP: match icmp type operations:too complex. ignoring.");
577 enumerate_icmp
= true;
579 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
580 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
581 api
->match_icmp_code_num
,
582 OPERATOR_UNARY_OR
, NULL
,
583 FLOWSPEC_ICMP_CODE
)) {
584 if (BGP_DEBUG(pbr
, PBR
))
585 zlog_debug("BGP: match icmp code operations:too complex. ignoring.");
587 } else if (api
->match_icmp_type_num
> 1 &&
589 if (BGP_DEBUG(pbr
, PBR
))
590 zlog_debug("BGP: match icmp code is enumerate, and icmp type is not. too complex. ignoring.");
594 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
595 if (BGP_DEBUG(pbr
, PBR
))
596 zlog_debug("BGP: match port operations:too complex. ignoring.");
599 if (api
->match_packet_length_num
) {
602 ret
= bgp_pbr_extract(api
->packet_length
,
603 api
->match_packet_length_num
, NULL
);
605 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
606 api
->match_packet_length_num
,
608 | OPERATOR_UNARY_AND
,
609 NULL
, FLOWSPEC_PKT_LEN
);
611 if (BGP_DEBUG(pbr
, PBR
))
612 zlog_debug("BGP: match packet length operations:too complex. ignoring.");
616 if (api
->match_dscp_num
) {
617 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
618 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
619 NULL
, FLOWSPEC_DSCP
)) {
620 if (BGP_DEBUG(pbr
, PBR
))
621 zlog_debug("BGP: match DSCP operations:too complex. ignoring.");
625 if (api
->match_flowlabel_num
) {
626 if (api
->afi
== AFI_IP
) {
627 if (BGP_DEBUG(pbr
, PBR
))
628 zlog_debug("BGP: match Flow Label operations:"
632 if (!bgp_pbr_extract_enumerate(api
->flow_label
,
633 api
->match_flowlabel_num
,
634 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
635 NULL
, FLOWSPEC_FLOW_LABEL
)) {
636 if (BGP_DEBUG(pbr
, PBR
))
637 zlog_debug("BGP: match FlowLabel operations:"
638 "too complex. ignoring.");
641 if (BGP_DEBUG(pbr
, PBR
))
642 zlog_debug("BGP: match FlowLabel operations "
643 "not supported. ignoring.");
646 if (api
->match_fragment_num
) {
650 success
= bgp_pbr_extract_enumerate(api
->fragment
,
651 api
->match_fragment_num
,
653 | OPERATOR_UNARY_AND
,
654 NULL
, FLOWSPEC_FRAGMENT
);
658 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
659 if (api
->fragment
[i
].value
!= 1 &&
660 api
->fragment
[i
].value
!= 2 &&
661 api
->fragment
[i
].value
!= 4 &&
662 api
->fragment
[i
].value
!= 8) {
665 fail_str
, sizeof(fail_str
),
666 "Value not valid (%d) for this implementation",
667 api
->fragment
[i
].value
);
669 if (api
->afi
== AFI_IP6
&&
670 api
->fragment
[i
].value
== 1) {
672 snprintf(fail_str
, sizeof(fail_str
),
673 "IPv6 dont fragment match invalid (%d)",
674 api
->fragment
[i
].value
);
677 if (api
->afi
== AFI_IP6
) {
679 snprintf(fail_str
, sizeof(fail_str
),
680 "%s", IPV6_FRAGMENT_INVALID
);
683 snprintf(fail_str
, sizeof(fail_str
),
684 "too complex. ignoring");
686 if (BGP_DEBUG(pbr
, PBR
))
687 zlog_debug("BGP: match fragment operation (%d) %s",
688 api
->match_fragment_num
,
694 /* no combinations with both src_port and dst_port
695 * or port with src_port and dst_port
697 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
698 api
->match_port_num
> 3) {
699 if (BGP_DEBUG(pbr
, PBR
))
700 zlog_debug("BGP: match multiple port operations: too complex. ignoring.");
703 if ((api
->match_src_port_num
|| api
->match_dst_port_num
704 || api
->match_port_num
) && (api
->match_icmp_type_num
705 || api
->match_icmp_code_num
)) {
706 if (BGP_DEBUG(pbr
, PBR
))
707 zlog_debug("BGP: match multiple port/imcp operations: too complex. ignoring.");
710 /* iprule only supports redirect IP */
711 if (api
->type
== BGP_PBR_IPRULE
) {
714 for (i
= 0; i
< api
->action_num
; i
++) {
715 if (api
->actions
[i
].action
== ACTION_TRAFFICRATE
&&
716 api
->actions
[i
].u
.r
.rate
== 0) {
717 if (BGP_DEBUG(pbr
, PBR
)) {
718 bgp_pbr_print_policy_route(api
);
719 zlog_debug("BGP: iprule match actions drop not supported");
723 if (api
->actions
[i
].action
== ACTION_MARKING
) {
724 if (BGP_DEBUG(pbr
, PBR
)) {
725 bgp_pbr_print_policy_route(api
);
726 zlog_warn("PBR: iprule set DSCP/Flow Label %u not supported",
727 api
->actions
[i
].u
.marking_dscp
);
730 if (api
->actions
[i
].action
== ACTION_REDIRECT
) {
731 if (BGP_DEBUG(pbr
, PBR
)) {
732 bgp_pbr_print_policy_route(api
);
733 zlog_warn("PBR: iprule redirect VRF %u not supported",
734 api
->actions
[i
].u
.redirect_vrf
);
739 } else if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
740 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
741 if (BGP_DEBUG(pbr
, PBR
)) {
742 bgp_pbr_print_policy_route(api
);
743 zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
750 /* return -1 if build or validation failed */
752 int bgp_pbr_build_and_validate_entry(const struct prefix
*p
,
753 struct bgp_path_info
*path
,
754 struct bgp_pbr_entry_main
*api
)
757 int i
, action_count
= 0;
758 struct ecommunity
*ecom
;
759 struct ecommunity_val
*ecom_eval
;
760 struct bgp_pbr_entry_action
*api_action
;
761 struct prefix
*src
= NULL
, *dst
= NULL
;
762 int valid_prefix
= 0;
763 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
764 bool discard_action_found
= false;
765 afi_t afi
= family2afi(p
->u
.prefix_flowspec
.family
);
767 /* extract match from flowspec entries */
768 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
769 p
->u
.prefix_flowspec
.prefixlen
, api
, afi
);
772 /* extract actiosn from flowspec ecom list */
773 if (path
&& path
->attr
->ecommunity
) {
774 ecom
= path
->attr
->ecommunity
;
775 for (i
= 0; i
< ecom
->size
; i
++) {
776 ecom_eval
= (struct ecommunity_val
*)
777 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
779 if (action_count
> ACTIONS_MAX_NUM
) {
780 if (BGP_DEBUG(pbr
, PBR_ERROR
))
782 EC_BGP_FLOWSPEC_PACKET
,
785 FSPEC_ACTION_EXCEED_LIMIT
,
789 api_action
= &api
->actions
[action_count
- 1];
791 if ((ecom_eval
->val
[1] ==
792 (char)ECOMMUNITY_REDIRECT_VRF
) &&
793 (ecom_eval
->val
[0] ==
794 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
796 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
798 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
799 struct ecommunity
*eckey
= ecommunity_new();
800 struct ecommunity_val ecom_copy
;
802 memcpy(&ecom_copy
, ecom_eval
,
803 sizeof(struct ecommunity_val
));
805 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
806 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
807 ecommunity_add_val(eckey
, &ecom_copy
,
810 api_action
->action
= ACTION_REDIRECT
;
811 api_action
->u
.redirect_vrf
=
812 get_first_vrf_for_redirect_with_rt(
814 ecommunity_free(&eckey
);
815 } else if ((ecom_eval
->val
[0] ==
816 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
817 (ecom_eval
->val
[1] ==
818 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
819 /* in case the 2 ecom present,
821 * draft-ietf-idr-flowspec-redirect
823 if (api_action_redirect_ip
&&
824 p
->u
.prefix_flowspec
.family
== AF_INET
) {
825 if (api_action_redirect_ip
->u
826 .zr
.redirect_ip_v4
.s_addr
829 if (path
->attr
->nexthop
.s_addr
832 api_action_redirect_ip
->u
.zr
833 .redirect_ip_v4
.s_addr
=
834 path
->attr
->nexthop
.s_addr
;
835 api_action_redirect_ip
->u
.zr
.duplicate
838 } else if (api_action_redirect_ip
&&
839 p
->u
.prefix_flowspec
.family
== AF_INET6
) {
840 if (memcmp(&api_action_redirect_ip
->u
843 sizeof(struct in6_addr
)))
845 if (path
->attr
->mp_nexthop_len
== 0 ||
846 path
->attr
->mp_nexthop_len
==
847 BGP_ATTR_NHLEN_IPV4
||
848 path
->attr
->mp_nexthop_len
==
849 BGP_ATTR_NHLEN_VPNV4
)
851 memcpy(&api_action_redirect_ip
->u
853 &path
->attr
->mp_nexthop_global
,
854 sizeof(struct in6_addr
));
855 api_action_redirect_ip
->u
.zr
.duplicate
858 } else if (p
->u
.prefix_flowspec
.family
==
860 api_action
->action
= ACTION_REDIRECT_IP
;
861 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
862 path
->attr
->nexthop
.s_addr
;
863 api_action
->u
.zr
.duplicate
=
865 api_action_redirect_ip
= api_action
;
866 } else if (p
->u
.prefix_flowspec
.family
==
868 api_action
->action
= ACTION_REDIRECT_IP
;
869 memcpy(&api_action
->u
871 &path
->attr
->mp_nexthop_global
,
872 sizeof(struct in6_addr
));
873 api_action
->u
.zr
.duplicate
875 api_action_redirect_ip
= api_action
;
877 } else if ((ecom_eval
->val
[0] ==
878 (char)ECOMMUNITY_ENCODE_IP
) &&
879 (ecom_eval
->val
[1] ==
880 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
881 /* in case the 2 ecom present,
882 * overwrite simpson draft
883 * update redirect ip fields
885 if (api_action_redirect_ip
) {
886 memcpy(&(api_action_redirect_ip
->u
887 .zr
.redirect_ip_v4
.s_addr
),
888 (ecom_eval
->val
+2), 4);
889 api_action_redirect_ip
->u
894 api_action
->action
= ACTION_REDIRECT_IP
;
895 memcpy(&(api_action
->u
896 .zr
.redirect_ip_v4
.s_addr
),
897 (ecom_eval
->val
+2), 4);
898 api_action
->u
.zr
.duplicate
=
900 api_action_redirect_ip
= api_action
;
903 if (ecom_eval
->val
[0] !=
904 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
906 ret
= ecommunity_fill_pbr_action(ecom_eval
,
911 if ((api_action
->action
== ACTION_TRAFFICRATE
)
912 && api
->actions
[i
].u
.r
.rate
== 0)
913 discard_action_found
= true;
918 if (path
&& path
->attr
&& path
->attr
->ipv6_ecommunity
) {
919 struct ecommunity_val_ipv6
*ipv6_ecom_eval
;
921 ecom
= path
->attr
->ipv6_ecommunity
;
922 for (i
= 0; i
< ecom
->size
; i
++) {
923 ipv6_ecom_eval
= (struct ecommunity_val_ipv6
*)
924 (ecom
->val
+ (i
* ecom
->unit_size
));
926 if (action_count
> ACTIONS_MAX_NUM
) {
927 if (BGP_DEBUG(pbr
, PBR_ERROR
))
929 EC_BGP_FLOWSPEC_PACKET
,
930 "%s: flowspec actions exceeds limit (max %u)",
931 __func__
, action_count
);
934 api_action
= &api
->actions
[action_count
- 1];
935 if ((ipv6_ecom_eval
->val
[1] ==
936 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) &&
937 (ipv6_ecom_eval
->val
[0] ==
938 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)) {
939 struct ecommunity
*eckey
= ecommunity_new();
940 struct ecommunity_val_ipv6 ecom_copy
;
942 eckey
->unit_size
= IPV6_ECOMMUNITY_SIZE
;
943 memcpy(&ecom_copy
, ipv6_ecom_eval
,
944 sizeof(struct ecommunity_val_ipv6
));
945 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
946 ecommunity_add_val_ipv6(eckey
, &ecom_copy
,
948 api_action
->action
= ACTION_REDIRECT
;
949 api_action
->u
.redirect_vrf
=
950 get_first_vrf_for_redirect_with_rt(
952 ecommunity_free(&eckey
);
957 /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
958 * then reduce the API action list to that action
960 if (api
->action_num
> 1 && discard_action_found
) {
962 memset(&api
->actions
[0], 0,
963 sizeof(struct bgp_pbr_entry_action
));
964 api
->actions
[0].action
= ACTION_TRAFFICRATE
;
967 /* validate if incoming matc/action is compatible
968 * with our policy routing engine
970 if (!bgp_pbr_validate_policy_route(api
))
973 /* check inconsistency in the match rule */
974 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
975 src
= &api
->src_prefix
;
976 afi
= family2afi(src
->family
);
979 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
980 dst
= &api
->dst_prefix
;
981 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
982 if (BGP_DEBUG(pbr
, PBR
)) {
983 bgp_pbr_print_policy_route(api
);
984 zlog_debug("%s: inconsistency: no match for afi src and dst (%u/%u)",
985 __func__
, afi
, family2afi(dst
->family
));
993 static void bgp_pbr_match_entry_free(void *arg
)
995 struct bgp_pbr_match_entry
*bpme
;
997 bpme
= (struct bgp_pbr_match_entry
*)arg
;
999 if (bpme
->installed
) {
1000 bgp_send_pbr_ipset_entry_match(bpme
, false);
1001 bpme
->installed
= false;
1002 bpme
->backpointer
= NULL
;
1004 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
1007 static void bgp_pbr_match_free(void *arg
)
1009 struct bgp_pbr_match
*bpm
;
1011 bpm
= (struct bgp_pbr_match
*)arg
;
1013 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
1015 if (hashcount(bpm
->entry_hash
) == 0) {
1016 /* delete iptable entry first */
1017 /* then delete ipset match */
1018 if (bpm
->installed
) {
1019 if (bpm
->installed_in_iptable
) {
1020 bgp_send_pbr_iptable(bpm
->action
,
1022 bpm
->installed_in_iptable
= false;
1023 bpm
->action
->refcnt
--;
1025 bgp_send_pbr_ipset_match(bpm
, false);
1026 bpm
->installed
= false;
1030 hash_free(bpm
->entry_hash
);
1032 XFREE(MTYPE_PBR_MATCH
, bpm
);
1035 static void *bgp_pbr_match_alloc_intern(void *arg
)
1037 struct bgp_pbr_match
*bpm
, *new;
1039 bpm
= (struct bgp_pbr_match
*)arg
;
1041 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
1042 memcpy(new, bpm
, sizeof(*bpm
));
1047 static void bgp_pbr_rule_free(void *arg
)
1049 struct bgp_pbr_rule
*bpr
;
1051 bpr
= (struct bgp_pbr_rule
*)arg
;
1054 if (bpr
->installed
) {
1055 bgp_send_pbr_rule_action(bpr
->action
, bpr
, false);
1056 bpr
->installed
= false;
1057 bpr
->action
->refcnt
--;
1060 XFREE(MTYPE_PBR_RULE
, bpr
);
1063 static void *bgp_pbr_rule_alloc_intern(void *arg
)
1065 struct bgp_pbr_rule
*bpr
, *new;
1067 bpr
= (struct bgp_pbr_rule
*)arg
;
1069 new = XCALLOC(MTYPE_PBR_RULE
, sizeof(*new));
1070 memcpy(new, bpr
, sizeof(*bpr
));
1075 static void bgp_pbr_action_free(void *arg
)
1077 struct bgp_pbr_action
*bpa
;
1079 bpa
= (struct bgp_pbr_action
*)arg
;
1081 if (bpa
->refcnt
== 0) {
1082 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1083 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1084 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1088 bpa
->installed
= false;
1091 XFREE(MTYPE_PBR_ACTION
, bpa
);
1094 static void *bgp_pbr_action_alloc_intern(void *arg
)
1096 struct bgp_pbr_action
*bpa
, *new;
1098 bpa
= (struct bgp_pbr_action
*)arg
;
1100 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
1102 memcpy(new, bpa
, sizeof(*bpa
));
1107 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
1109 struct bgp_pbr_match_entry
*bpme
, *new;
1111 bpme
= (struct bgp_pbr_match_entry
*)arg
;
1113 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
1115 memcpy(new, bpme
, sizeof(*bpme
));
1120 uint32_t bgp_pbr_match_hash_key(const void *arg
)
1122 const struct bgp_pbr_match
*pbm
= arg
;
1125 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
1126 key
= jhash_1word(pbm
->flags
, key
);
1127 key
= jhash_1word(pbm
->family
, key
);
1128 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
1129 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
1130 key
= jhash(&pbm
->tcp_flags
, 2, key
);
1131 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
1132 key
= jhash(&pbm
->dscp_value
, 1, key
);
1133 key
= jhash(&pbm
->flow_label
, 2, key
);
1134 key
= jhash(&pbm
->fragment
, 1, key
);
1135 key
= jhash(&pbm
->protocol
, 1, key
);
1136 return jhash_1word(pbm
->type
, key
);
1139 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
1141 const struct bgp_pbr_match
*r1
, *r2
;
1143 r1
= (const struct bgp_pbr_match
*)arg1
;
1144 r2
= (const struct bgp_pbr_match
*)arg2
;
1146 if (r1
->vrf_id
!= r2
->vrf_id
)
1149 if (r1
->family
!= r2
->family
)
1152 if (r1
->type
!= r2
->type
)
1155 if (r1
->flags
!= r2
->flags
)
1158 if (r1
->action
!= r2
->action
)
1161 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
1164 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
1167 if (r1
->tcp_flags
!= r2
->tcp_flags
)
1170 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
1173 if (r1
->dscp_value
!= r2
->dscp_value
)
1176 if (r1
->flow_label
!= r2
->flow_label
)
1179 if (r1
->fragment
!= r2
->fragment
)
1182 if (r1
->protocol
!= r2
->protocol
)
1187 uint32_t bgp_pbr_rule_hash_key(const void *arg
)
1189 const struct bgp_pbr_rule
*pbr
= arg
;
1192 key
= prefix_hash_key(&pbr
->src
);
1193 key
= jhash_1word(pbr
->vrf_id
, key
);
1194 key
= jhash_1word(pbr
->flags
, key
);
1195 return jhash_1word(prefix_hash_key(&pbr
->dst
), key
);
1198 bool bgp_pbr_rule_hash_equal(const void *arg1
, const void *arg2
)
1200 const struct bgp_pbr_rule
*r1
, *r2
;
1202 r1
= (const struct bgp_pbr_rule
*)arg1
;
1203 r2
= (const struct bgp_pbr_rule
*)arg2
;
1205 if (r1
->vrf_id
!= r2
->vrf_id
)
1208 if (r1
->flags
!= r2
->flags
)
1211 if (r1
->action
!= r2
->action
)
1214 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1215 !prefix_same(&r1
->src
, &r2
->src
))
1218 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1219 !prefix_same(&r1
->dst
, &r2
->dst
))
1225 uint32_t bgp_pbr_match_entry_hash_key(const void *arg
)
1227 const struct bgp_pbr_match_entry
*pbme
;
1231 key
= prefix_hash_key(&pbme
->src
);
1232 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
1233 key
= jhash(&pbme
->dst_port_min
, 2, key
);
1234 key
= jhash(&pbme
->src_port_min
, 2, key
);
1235 key
= jhash(&pbme
->dst_port_max
, 2, key
);
1236 key
= jhash(&pbme
->src_port_max
, 2, key
);
1237 key
= jhash(&pbme
->proto
, 1, key
);
1242 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
1244 const struct bgp_pbr_match_entry
*r1
, *r2
;
1246 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
1247 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
1250 * on updates, comparing backpointer is not necessary
1251 * unique value is self calculated
1252 * rate is ignored for now
1255 if (!prefix_same(&r1
->src
, &r2
->src
))
1258 if (!prefix_same(&r1
->dst
, &r2
->dst
))
1261 if (r1
->src_port_min
!= r2
->src_port_min
)
1264 if (r1
->dst_port_min
!= r2
->dst_port_min
)
1267 if (r1
->src_port_max
!= r2
->src_port_max
)
1270 if (r1
->dst_port_max
!= r2
->dst_port_max
)
1273 if (r1
->proto
!= r2
->proto
)
1279 uint32_t bgp_pbr_action_hash_key(const void *arg
)
1281 const struct bgp_pbr_action
*pbra
;
1285 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
1286 key
= jhash_1word(pbra
->fwmark
, key
);
1287 key
= jhash_1word(pbra
->afi
, key
);
1291 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1293 const struct bgp_pbr_action
*r1
, *r2
;
1295 r1
= (const struct bgp_pbr_action
*)arg1
;
1296 r2
= (const struct bgp_pbr_action
*)arg2
;
1298 /* unique value is self calculated
1299 * table and fwmark is self calculated
1302 if (r1
->vrf_id
!= r2
->vrf_id
)
1305 if (r1
->afi
!= r2
->afi
)
1308 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1314 struct bgp_pbr_rule
*bgp_pbr_rule_lookup(vrf_id_t vrf_id
,
1317 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1318 struct bgp_pbr_rule_unique bpru
;
1320 if (!bgp
|| unique
== 0)
1322 bpru
.unique
= unique
;
1323 bpru
.bpr_found
= NULL
;
1324 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_rule_walkcb
, &bpru
);
1325 return bpru
.bpr_found
;
1328 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1331 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1332 struct bgp_pbr_action_unique bpau
;
1334 if (!bgp
|| unique
== 0)
1336 bpau
.unique
= unique
;
1337 bpau
.bpa_found
= NULL
;
1338 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1339 return bpau
.bpa_found
;
1342 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1345 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1346 struct bgp_pbr_match_unique bpmu
;
1348 if (!bgp
|| unique
== 0)
1350 bpmu
.unique
= unique
;
1351 bpmu
.bpm_found
= NULL
;
1352 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1353 return bpmu
.bpm_found
;
1356 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1360 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1361 struct bgp_pbr_match_entry_unique bpmeu
;
1362 struct bgp_pbr_match_ipsetname bpmi
;
1364 if (!bgp
|| unique
== 0)
1366 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1367 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1368 bpmi
.bpm_found
= NULL
;
1369 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1370 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1371 if (!bpmi
.bpm_found
)
1373 bpmeu
.bpme_found
= NULL
;
1374 bpmeu
.unique
= unique
;
1375 hash_walk(bpmi
.bpm_found
->entry_hash
,
1376 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1377 return bpmeu
.bpme_found
;
1380 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1383 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1384 struct bgp_pbr_match_iptable_unique bpmiu
;
1386 if (!bgp
|| unique
== 0)
1388 bpmiu
.unique
= unique
;
1389 bpmiu
.bpm_found
= NULL
;
1390 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1391 return bpmiu
.bpm_found
;
1394 void bgp_pbr_cleanup(struct bgp
*bgp
)
1396 if (bgp
->pbr_match_hash
) {
1397 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1398 hash_free(bgp
->pbr_match_hash
);
1399 bgp
->pbr_match_hash
= NULL
;
1401 if (bgp
->pbr_rule_hash
) {
1402 hash_clean(bgp
->pbr_rule_hash
, bgp_pbr_rule_free
);
1403 hash_free(bgp
->pbr_rule_hash
);
1404 bgp
->pbr_rule_hash
= NULL
;
1406 if (bgp
->pbr_action_hash
) {
1407 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1408 hash_free(bgp
->pbr_action_hash
);
1409 bgp
->pbr_action_hash
= NULL
;
1411 if (bgp
->bgp_pbr_cfg
== NULL
)
1413 bgp_pbr_reset(bgp
, AFI_IP
);
1414 bgp_pbr_reset(bgp
, AFI_IP6
);
1415 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1418 void bgp_pbr_init(struct bgp
*bgp
)
1420 bgp
->pbr_match_hash
=
1421 hash_create_size(8, bgp_pbr_match_hash_key
,
1422 bgp_pbr_match_hash_equal
,
1424 bgp
->pbr_action_hash
=
1425 hash_create_size(8, bgp_pbr_action_hash_key
,
1426 bgp_pbr_action_hash_equal
,
1427 "Match Hash Entry");
1429 bgp
->pbr_rule_hash
=
1430 hash_create_size(8, bgp_pbr_rule_hash_key
,
1431 bgp_pbr_rule_hash_equal
,
1434 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1435 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1438 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1441 char return_string
[512];
1442 char *ptr
= return_string
;
1444 int delta
, len
= sizeof(return_string
);
1446 delta
= snprintf(ptr
, sizeof(return_string
), "MATCH : ");
1449 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1450 struct prefix
*p
= &(api
->src_prefix
);
1452 if (api
->src_prefix_offset
)
1453 delta
= snprintfrr(ptr
, len
, "@src %pFX/off%u", p
,
1454 api
->src_prefix_offset
);
1456 delta
= snprintfrr(ptr
, len
, "@src %pFX", p
);
1459 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1461 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1462 struct prefix
*p
= &(api
->dst_prefix
);
1464 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1465 if (api
->dst_prefix_offset
)
1466 delta
= snprintfrr(ptr
, len
, "@dst %pFX/off%u", p
,
1467 api
->dst_prefix_offset
);
1469 delta
= snprintfrr(ptr
, len
, "@dst %pFX", p
);
1474 if (api
->match_protocol_num
)
1475 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1476 for (i
= 0; i
< api
->match_protocol_num
; i
++) {
1477 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->protocol
[i
],
1478 i
> 0 ? NULL
: "@proto ");
1483 if (api
->match_src_port_num
)
1484 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1485 for (i
= 0; i
< api
->match_src_port_num
; i
++) {
1486 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->src_port
[i
],
1487 i
> 0 ? NULL
: "@srcport ");
1492 if (api
->match_dst_port_num
)
1493 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1494 for (i
= 0; i
< api
->match_dst_port_num
; i
++) {
1495 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->dst_port
[i
],
1496 i
> 0 ? NULL
: "@dstport ");
1501 if (api
->match_port_num
)
1502 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1503 for (i
= 0; i
< api
->match_port_num
; i
++) {
1504 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->port
[i
],
1505 i
> 0 ? NULL
: "@port ");
1510 if (api
->match_icmp_type_num
)
1511 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1512 for (i
= 0; i
< api
->match_icmp_type_num
; i
++) {
1513 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->icmp_type
[i
],
1514 i
> 0 ? NULL
: "@icmptype ");
1519 if (api
->match_icmp_code_num
)
1520 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1521 for (i
= 0; i
< api
->match_icmp_code_num
; i
++) {
1522 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->icmp_code
[i
],
1523 i
> 0 ? NULL
: "@icmpcode ");
1528 if (api
->match_packet_length_num
)
1529 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1530 for (i
= 0; i
< api
->match_packet_length_num
; i
++) {
1531 delta
= snprintf_bgp_pbr_match_val(ptr
, len
,
1532 &api
->packet_length
[i
],
1533 i
> 0 ? NULL
: "@plen ");
1538 if (api
->match_dscp_num
)
1539 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1540 for (i
= 0; i
< api
->match_dscp_num
; i
++) {
1541 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->dscp
[i
],
1542 i
> 0 ? NULL
: "@dscp ");
1547 if (api
->match_flowlabel_num
)
1548 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1549 for (i
= 0; i
< api
->match_flowlabel_num
; i
++) {
1550 delta
= snprintf_bgp_pbr_match_val(ptr
, len
,
1551 &api
->flow_label
[i
],
1552 i
> 0 ? NULL
: "@flowlabel ");
1557 if (api
->match_tcpflags_num
)
1558 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1559 for (i
= 0; i
< api
->match_tcpflags_num
; i
++) {
1560 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->tcpflags
[i
],
1561 i
> 0 ? NULL
: "@tcpflags ");
1566 if (api
->match_fragment_num
)
1567 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1568 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
1569 delta
= snprintf_bgp_pbr_match_val(ptr
, len
, &api
->fragment
[i
],
1570 i
> 0 ? NULL
: "@fragment ");
1575 len
= sizeof(return_string
);
1577 ptr
= return_string
;
1579 len
-= (ptr
- return_string
);
1580 delta
= snprintf(ptr
, len
, "; ");
1584 if (api
->action_num
) {
1585 delta
= snprintf(ptr
, len
, "SET : ");
1590 for (i
= 0; i
< api
->action_num
; i
++) {
1591 switch (api
->actions
[i
].action
) {
1592 case ACTION_TRAFFICRATE
:
1593 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1594 delta
= snprintf(ptr
, len
, "@set rate %f",
1595 api
->actions
[i
].u
.r
.rate
);
1599 case ACTION_TRAFFIC_ACTION
:
1600 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1601 delta
= snprintf(ptr
, len
, "@action ");
1604 if (api
->actions
[i
].u
.za
.filter
1605 & TRAFFIC_ACTION_TERMINATE
) {
1606 delta
= snprintf(ptr
, len
,
1607 " terminate (apply filter(s))");
1611 if (api
->actions
[i
].u
.za
.filter
1612 & TRAFFIC_ACTION_DISTRIBUTE
) {
1613 delta
= snprintf(ptr
, len
, " distribute");
1617 if (api
->actions
[i
].u
.za
.filter
1618 & TRAFFIC_ACTION_SAMPLE
) {
1619 delta
= snprintf(ptr
, len
, " sample");
1624 case ACTION_REDIRECT_IP
: {
1625 char local_buff
[INET6_ADDRSTRLEN
];
1628 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1629 if (api
->afi
== AF_INET
)
1630 ptr_ip
= &api
->actions
[i
].u
.zr
.redirect_ip_v4
;
1632 ptr_ip
= &api
->actions
[i
].u
.zr
.redirect_ip_v6
;
1633 if (inet_ntop(afi2family(api
->afi
),
1635 INET6_ADDRSTRLEN
) != NULL
) {
1636 delta
= snprintf(ptr
, len
,
1637 "@redirect ip nh %s", local_buff
);
1643 case ACTION_REDIRECT
: {
1646 vrf
= vrf_lookup_by_id(api
->actions
[i
].u
.redirect_vrf
);
1647 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1648 delta
= snprintf(ptr
, len
, "@redirect vrf %s(%u)",
1650 api
->actions
[i
].u
.redirect_vrf
);
1655 case ACTION_MARKING
:
1656 INCREMENT_DISPLAY(ptr
, nb_items
, len
);
1657 delta
= snprintf(ptr
, len
, "@set dscp/flowlabel %u",
1658 api
->actions
[i
].u
.marking_dscp
);
1666 zlog_info("%s", return_string
);
1669 static void bgp_pbr_flush_iprule(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1670 struct bgp_pbr_rule
*bpr
)
1672 /* if bpr is null, do nothing
1676 if (bpr
->installed
) {
1677 bgp_send_pbr_rule_action(bpa
, bpr
, false);
1678 bpr
->installed
= false;
1679 bpr
->action
->refcnt
--;
1682 struct bgp_path_info
*path
;
1683 struct bgp_path_info_extra
*extra
;
1685 /* unlink path to bpme */
1686 path
= (struct bgp_path_info
*)bpr
->path
;
1687 extra
= bgp_path_info_extra_get(path
);
1688 if (extra
->bgp_fs_iprule
)
1689 listnode_delete(extra
->bgp_fs_iprule
, bpr
);
1693 hash_release(bgp
->pbr_rule_hash
, bpr
);
1694 if (bpa
->refcnt
== 0) {
1695 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1696 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1697 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1701 bpa
->installed
= false;
1706 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1707 struct bgp_pbr_match
*bpm
,
1708 struct bgp_pbr_match_entry
*bpme
)
1710 /* if bpme is null, bpm is also null
1714 /* ipset del entry */
1715 if (bpme
->installed
) {
1716 bgp_send_pbr_ipset_entry_match(bpme
, false);
1717 bpme
->installed
= false;
1718 bpme
->backpointer
= NULL
;
1720 struct bgp_path_info
*path
;
1721 struct bgp_path_info_extra
*extra
;
1723 /* unlink path to bpme */
1724 path
= (struct bgp_path_info
*)bpme
->path
;
1725 extra
= bgp_path_info_extra_get(path
);
1726 if (extra
->bgp_fs_pbr
)
1727 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1731 hash_release(bpm
->entry_hash
, bpme
);
1732 if (hashcount(bpm
->entry_hash
) == 0) {
1733 /* delete iptable entry first */
1734 /* then delete ipset match */
1735 if (bpm
->installed
) {
1736 if (bpm
->installed_in_iptable
) {
1737 bgp_send_pbr_iptable(bpm
->action
,
1739 bpm
->installed_in_iptable
= false;
1740 bpm
->action
->refcnt
--;
1742 bgp_send_pbr_ipset_match(bpm
, false);
1743 bpm
->installed
= false;
1746 hash_release(bgp
->pbr_match_hash
, bpm
);
1747 /* XXX release pbr_match_action if not used
1748 * note that drop does not need to call send_pbr_action
1751 if (bpa
->refcnt
== 0) {
1752 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1753 bgp_send_pbr_rule_action(bpa
, NULL
, false);
1754 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1758 bpa
->installed
= false;
1763 struct bgp_pbr_match_entry_remain
{
1764 struct bgp_pbr_match_entry
*bpme_to_match
;
1765 struct bgp_pbr_match_entry
*bpme_found
;
1768 struct bgp_pbr_rule_remain
{
1769 struct bgp_pbr_rule
*bpr_to_match
;
1770 struct bgp_pbr_rule
*bpr_found
;
1773 static int bgp_pbr_get_same_rule(struct hash_bucket
*bucket
, void *arg
)
1775 struct bgp_pbr_rule
*r1
= (struct bgp_pbr_rule
*)bucket
->data
;
1776 struct bgp_pbr_rule_remain
*ctxt
=
1777 (struct bgp_pbr_rule_remain
*)arg
;
1778 struct bgp_pbr_rule
*r2
;
1780 r2
= ctxt
->bpr_to_match
;
1782 if (r1
->vrf_id
!= r2
->vrf_id
)
1783 return HASHWALK_CONTINUE
;
1785 if (r1
->flags
!= r2
->flags
)
1786 return HASHWALK_CONTINUE
;
1788 if ((r1
->flags
& MATCH_IP_SRC_SET
) &&
1789 !prefix_same(&r1
->src
, &r2
->src
))
1790 return HASHWALK_CONTINUE
;
1792 if ((r1
->flags
& MATCH_IP_DST_SET
) &&
1793 !prefix_same(&r1
->dst
, &r2
->dst
))
1794 return HASHWALK_CONTINUE
;
1796 /* this function is used for two cases:
1797 * - remove an entry upon withdraw request
1798 * (case r2->action is null)
1799 * - replace an old iprule with different action
1800 * (case r2->action is != null)
1801 * the old one is removed after the new one
1802 * this is to avoid disruption in traffic
1804 if (r2
->action
== NULL
||
1805 r1
->action
!= r2
->action
) {
1806 ctxt
->bpr_found
= r1
;
1807 return HASHWALK_ABORT
;
1809 return HASHWALK_CONTINUE
;
1812 static int bgp_pbr_get_remaining_entry(struct hash_bucket
*bucket
, void *arg
)
1814 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)bucket
->data
;
1815 struct bgp_pbr_match_entry_remain
*bpmer
=
1816 (struct bgp_pbr_match_entry_remain
*)arg
;
1817 struct bgp_pbr_match
*bpm_temp
;
1818 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1820 if (!bpme
->backpointer
||
1821 bpm
== bpme
->backpointer
||
1822 bpme
->backpointer
->action
== bpm
->action
)
1823 return HASHWALK_CONTINUE
;
1824 /* ensure bpm other characteristics are equal */
1825 bpm_temp
= bpme
->backpointer
;
1826 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1827 bpm_temp
->type
!= bpm
->type
||
1828 bpm_temp
->flags
!= bpm
->flags
||
1829 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1830 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1831 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1832 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1833 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1834 bpm_temp
->flow_label
!= bpm
->flow_label
||
1835 bpm_temp
->family
!= bpm
->family
||
1836 bpm_temp
->fragment
!= bpm
->fragment
)
1837 return HASHWALK_CONTINUE
;
1839 /* look for remaining bpme */
1840 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1841 if (!bpmer
->bpme_found
)
1842 return HASHWALK_CONTINUE
;
1843 return HASHWALK_ABORT
;
1846 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1847 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1849 struct bgp_pbr_match temp
;
1850 struct bgp_pbr_match_entry temp2
;
1851 struct bgp_pbr_rule pbr_rule
;
1852 struct bgp_pbr_rule
*bpr
;
1853 struct bgp_pbr_match
*bpm
;
1854 struct bgp_pbr_match_entry
*bpme
;
1855 struct bgp_pbr_match_entry_remain bpmer
;
1856 struct bgp_pbr_range_port
*src_port
;
1857 struct bgp_pbr_range_port
*dst_port
;
1858 struct bgp_pbr_range_port
*pkt_len
;
1859 struct bgp_pbr_rule_remain bprr
;
1863 src_port
= bpf
->src_port
;
1864 dst_port
= bpf
->dst_port
;
1865 pkt_len
= bpf
->pkt_len
;
1867 if (BGP_DEBUG(zebra
, ZEBRA
))
1868 bgp_pbr_dump_entry(bpf
, false);
1870 /* as we don't know information from EC
1871 * look for bpm that have the bpm
1872 * with vrf_id characteristics
1874 memset(&temp2
, 0, sizeof(temp2
));
1875 memset(&temp
, 0, sizeof(temp
));
1877 if (bpf
->type
== BGP_PBR_IPRULE
) {
1878 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
1879 pbr_rule
.vrf_id
= bpf
->vrf_id
;
1881 prefix_copy(&pbr_rule
.src
, bpf
->src
);
1882 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
1885 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
1886 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
1889 /* A previous entry may already exist
1890 * flush previous entry if necessary
1892 bprr
.bpr_to_match
= bpr
;
1893 bprr
.bpr_found
= NULL
;
1894 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
1895 if (bprr
.bpr_found
) {
1896 static struct bgp_pbr_rule
*local_bpr
;
1897 static struct bgp_pbr_action
*local_bpa
;
1899 local_bpr
= bprr
.bpr_found
;
1900 local_bpa
= local_bpr
->action
;
1901 bgp_pbr_flush_iprule(bgp
, local_bpa
,
1907 temp
.family
= bpf
->family
;
1909 temp
.flags
|= MATCH_IP_SRC_SET
;
1910 prefix_copy(&temp2
.src
, bpf
->src
);
1912 temp2
.src
.family
= bpf
->family
;
1914 temp
.flags
|= MATCH_IP_DST_SET
;
1915 prefix_copy(&temp2
.dst
, bpf
->dst
);
1917 temp2
.dst
.family
= bpf
->family
;
1918 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1919 if (bpf
->protocol
== IPPROTO_ICMP
)
1920 temp
.flags
|= MATCH_ICMP_SET
;
1921 temp
.flags
|= MATCH_PORT_SRC_SET
;
1922 temp2
.src_port_min
= src_port
->min_port
;
1923 if (src_port
->max_port
) {
1924 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1925 temp2
.src_port_max
= src_port
->max_port
;
1928 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1929 if (bpf
->protocol
== IPPROTO_ICMP
)
1930 temp
.flags
|= MATCH_ICMP_SET
;
1931 temp
.flags
|= MATCH_PORT_DST_SET
;
1932 temp2
.dst_port_min
= dst_port
->min_port
;
1933 if (dst_port
->max_port
) {
1934 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1935 temp2
.dst_port_max
= dst_port
->max_port
;
1938 temp2
.proto
= bpf
->protocol
;
1941 temp
.pkt_len_min
= pkt_len
->min_port
;
1942 if (pkt_len
->max_port
)
1943 temp
.pkt_len_max
= pkt_len
->max_port
;
1944 } else if (bpf
->pkt_len_val
) {
1945 if (bpf
->pkt_len_val
->mask
)
1946 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1947 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1949 if (bpf
->tcp_flags
) {
1950 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1951 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1954 if (bpf
->dscp
->mask
)
1955 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1957 temp
.flags
|= MATCH_DSCP_SET
;
1958 temp
.dscp_value
= bpf
->dscp
->val
;
1960 if (bpf
->flow_label
) {
1961 if (bpf
->flow_label
->mask
)
1962 temp
.flags
|= MATCH_FLOW_LABEL_INVERSE_SET
;
1964 temp
.flags
|= MATCH_FLOW_LABEL_SET
;
1965 temp
.flow_label
= bpf
->flow_label
->val
;
1968 if (bpf
->fragment
) {
1969 if (bpf
->fragment
->mask
)
1970 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1971 temp
.fragment
= bpf
->fragment
->val
;
1974 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1975 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1976 temp
.type
= IPSET_NET_PORT
;
1978 temp
.type
= IPSET_NET
;
1980 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1981 temp
.type
= IPSET_NET_PORT_NET
;
1983 temp
.type
= IPSET_NET_NET
;
1985 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1986 temp
.vrf_id
= VRF_DEFAULT
;
1988 temp
.vrf_id
= bpf
->vrf_id
;
1991 bpme
->backpointer
= bpm
;
1992 /* right now, a previous entry may already exist
1993 * flush previous entry if necessary
1995 bpmer
.bpme_to_match
= bpme
;
1996 bpmer
.bpme_found
= NULL
;
1997 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1998 if (bpmer
.bpme_found
) {
1999 static struct bgp_pbr_match
*local_bpm
;
2000 static struct bgp_pbr_action
*local_bpa
;
2002 local_bpm
= bpmer
.bpme_found
->backpointer
;
2003 local_bpa
= local_bpm
->action
;
2004 bgp_pbr_flush_entry(bgp
, local_bpa
,
2005 local_bpm
, bpmer
.bpme_found
);
2009 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
2011 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
2012 return FLOWSPEC_DSCP
;
2013 if (type_entry
== FLOWSPEC_DSCP
)
2014 return FLOWSPEC_FLOW_LABEL
;
2015 if (type_entry
== FLOWSPEC_FLOW_LABEL
)
2016 return FLOWSPEC_PKT_LEN
;
2017 if (type_entry
== FLOWSPEC_PKT_LEN
)
2018 return FLOWSPEC_FRAGMENT
;
2019 if (type_entry
== FLOWSPEC_FRAGMENT
)
2020 return FLOWSPEC_ICMP_TYPE
;
2024 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
2025 struct bgp_pbr_filter
*bpf
,
2026 struct bgp_pbr_or_filter
*bpof
, bool add
,
2027 struct nexthop
*nh
, float *rate
)
2029 struct bgp_pbr_range_port srcp
, dstp
;
2030 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
2031 struct listnode
*tnode
, *cnode
;
2035 if (bpf
->protocol
!= IPPROTO_ICMP
)
2037 bpf
->src_port
= &srcp
;
2038 bpf
->dst_port
= &dstp
;
2039 /* parse icmp type and lookup appropriate icmp code
2040 * if no icmp code found, create as many entryes as
2041 * there are listed icmp codes for that icmp type
2043 if (!bpof
->icmp_type
) {
2045 srcp
.max_port
= 255;
2046 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
2047 dstp
.min_port
= icmp_code
->val
;
2049 bgp_pbr_policyroute_add_to_zebra_unit(
2050 bgp
, path
, bpf
, nh
, rate
);
2052 bgp_pbr_policyroute_remove_from_zebra_unit(
2057 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
2058 srcp
.min_port
= icmp_type
->val
;
2061 /* only icmp type. create an entry only with icmp type */
2062 if (!bpof
->icmp_code
) {
2063 /* icmp type is not one of the above
2064 * forge an entry only based on the icmp type
2067 dstp
.max_port
= 255;
2069 bgp_pbr_policyroute_add_to_zebra_unit(
2070 bgp
, path
, bpf
, nh
, rate
);
2072 bgp_pbr_policyroute_remove_from_zebra_unit(
2076 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
2077 dstp
.min_port
= icmp_code
->val
;
2079 bgp_pbr_policyroute_add_to_zebra_unit(
2080 bgp
, path
, bpf
, nh
, rate
);
2082 bgp_pbr_policyroute_remove_from_zebra_unit(
2088 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
2089 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2090 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
2092 struct listnode
*node
, *nnode
;
2093 struct bgp_pbr_val_mask
*valmask
;
2094 uint8_t next_type_entry
;
2095 struct list
*orig_list
;
2096 struct bgp_pbr_val_mask
**target_val
;
2098 if (type_entry
== 0) {
2099 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2102 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2103 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2104 orig_list
= bpof
->tcpflags
;
2105 target_val
= &bpf
->tcp_flags
;
2106 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2107 orig_list
= bpof
->dscp
;
2108 target_val
= &bpf
->dscp
;
2109 } else if (type_entry
== FLOWSPEC_FLOW_LABEL
&& bpof
->flowlabel
) {
2110 orig_list
= bpof
->flowlabel
;
2111 target_val
= &bpf
->flow_label
;
2112 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2113 orig_list
= bpof
->pkt_len
;
2114 target_val
= &bpf
->pkt_len_val
;
2115 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2116 orig_list
= bpof
->fragment
;
2117 target_val
= &bpf
->fragment
;
2118 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2119 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2120 /* enumerate list for icmp - must be last one */
2121 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
2124 bgp_pbr_policyroute_remove_from_zebra_recursive(
2125 bgp
, path
, bpf
, bpof
, next_type_entry
);
2128 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2129 *target_val
= valmask
;
2130 bgp_pbr_policyroute_remove_from_zebra_recursive(
2131 bgp
, path
, bpf
, bpof
, next_type_entry
);
2135 static void bgp_pbr_policyroute_remove_from_zebra(
2136 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2137 struct bgp_pbr_or_filter
*bpof
)
2140 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2144 bgp_pbr_policyroute_remove_from_zebra_recursive(
2145 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
2146 else if (bpof
->dscp
)
2147 bgp_pbr_policyroute_remove_from_zebra_recursive(
2148 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
2149 else if (bpof
->flowlabel
)
2150 bgp_pbr_policyroute_remove_from_zebra_recursive(
2151 bgp
, path
, bpf
, bpof
, FLOWSPEC_FLOW_LABEL
);
2152 else if (bpof
->pkt_len
)
2153 bgp_pbr_policyroute_remove_from_zebra_recursive(
2154 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
2155 else if (bpof
->fragment
)
2156 bgp_pbr_policyroute_remove_from_zebra_recursive(
2157 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
2158 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2159 bgp_pbr_policyroute_remove_from_zebra_recursive(
2160 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
2162 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
2165 list_delete_all_node(bpof
->tcpflags
);
2167 list_delete_all_node(bpof
->dscp
);
2168 if (bpof
->flowlabel
)
2169 list_delete_all_node(bpof
->flowlabel
);
2171 list_delete_all_node(bpof
->pkt_len
);
2173 list_delete_all_node(bpof
->fragment
);
2176 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
2178 struct bgp_pbr_range_port
*src_port
;
2179 struct bgp_pbr_range_port
*dst_port
;
2180 struct bgp_pbr_range_port
*pkt_len
;
2181 char bufsrc
[64], bufdst
[64];
2183 int remaining_len
= 0;
2184 char protocol_str
[16];
2188 src_port
= bpf
->src_port
;
2189 dst_port
= bpf
->dst_port
;
2190 pkt_len
= bpf
->pkt_len
;
2192 protocol_str
[0] = '\0';
2193 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
2194 bpf
->protocol
= IPPROTO_TCP
;
2196 snprintf(protocol_str
, sizeof(protocol_str
),
2197 "proto %d", bpf
->protocol
);
2199 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
2200 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
2203 dst_port
->min_port
);
2204 else if (bpf
->protocol
== IPPROTO_UDP
||
2205 bpf
->protocol
== IPPROTO_TCP
) {
2207 if (src_port
&& src_port
->min_port
)
2208 remaining_len
+= snprintf(buffer
,
2212 src_port
->max_port
?
2213 src_port
->max_port
:
2214 src_port
->min_port
);
2215 if (dst_port
&& dst_port
->min_port
)
2216 remaining_len
+= snprintf(buffer
+
2222 dst_port
->max_port
?
2223 dst_port
->max_port
:
2224 dst_port
->min_port
);
2226 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
2227 remaining_len
+= snprintf(buffer
+ remaining_len
,
2235 } else if (bpf
->pkt_len_val
) {
2236 remaining_len
+= snprintf(buffer
+ remaining_len
,
2240 bpf
->pkt_len_val
->mask
2242 bpf
->pkt_len_val
->val
);
2244 if (bpf
->tcp_flags
) {
2245 remaining_len
+= snprintf(buffer
+ remaining_len
,
2249 bpf
->tcp_flags
->val
,
2250 bpf
->tcp_flags
->mask
);
2253 snprintf(buffer
+ remaining_len
,
2261 if (bpf
->flow_label
) {
2262 snprintf(buffer
+ remaining_len
,
2266 bpf
->flow_label
->mask
2268 bpf
->flow_label
->val
);
2270 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
2271 add
? "adding" : "removing",
2272 bpf
->src
== NULL
? "<all>" :
2273 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
2274 bpf
->dst
== NULL
? "<all>" :
2275 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
2276 protocol_str
, buffer
);
2280 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
2281 struct bgp_path_info
*path
,
2282 struct bgp_pbr_filter
*bpf
,
2286 struct bgp_pbr_match temp
;
2287 struct bgp_pbr_match_entry temp2
;
2288 struct bgp_pbr_match
*bpm
;
2289 struct bgp_pbr_match_entry
*bpme
= NULL
;
2290 struct bgp_pbr_action temp3
;
2291 struct bgp_pbr_action
*bpa
= NULL
;
2292 struct bgp_pbr_match_entry_remain bpmer
;
2293 struct bgp_pbr_rule_remain bprr
;
2294 struct bgp_pbr_range_port
*src_port
;
2295 struct bgp_pbr_range_port
*dst_port
;
2296 struct bgp_pbr_range_port
*pkt_len
;
2297 struct bgp_pbr_rule pbr_rule
;
2298 struct bgp_pbr_rule
*bpr
;
2299 bool bpr_found
= false;
2300 bool bpme_found
= false;
2304 src_port
= bpf
->src_port
;
2305 dst_port
= bpf
->dst_port
;
2306 pkt_len
= bpf
->pkt_len
;
2308 if (BGP_DEBUG(zebra
, ZEBRA
))
2309 bgp_pbr_dump_entry(bpf
, true);
2311 /* look for bpa first */
2312 memset(&temp3
, 0, sizeof(temp3
));
2316 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
2317 temp3
.vrf_id
= bpf
->vrf_id
;
2318 temp3
.afi
= family2afi(bpf
->family
);
2319 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
2320 bgp_pbr_action_alloc_intern
);
2322 if (bpa
->fwmark
== 0) {
2323 /* drop is handled by iptable */
2324 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
2326 bpa
->installed
= true;
2328 bpa
->fwmark
= bgp_zebra_tm_get_id();
2329 bpa
->table_id
= bpa
->fwmark
;
2330 bpa
->installed
= false;
2333 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
2334 /* 0 value is forbidden */
2335 bpa
->install_in_progress
= false;
2337 if (bpf
->type
== BGP_PBR_IPRULE
) {
2338 memset(&pbr_rule
, 0, sizeof(pbr_rule
));
2339 pbr_rule
.vrf_id
= bpf
->vrf_id
;
2340 pbr_rule
.priority
= 20;
2342 pbr_rule
.flags
|= MATCH_IP_SRC_SET
;
2343 prefix_copy(&pbr_rule
.src
, bpf
->src
);
2346 pbr_rule
.flags
|= MATCH_IP_DST_SET
;
2347 prefix_copy(&pbr_rule
.dst
, bpf
->dst
);
2349 pbr_rule
.action
= bpa
;
2350 bpr
= hash_get(bgp
->pbr_rule_hash
, &pbr_rule
,
2351 bgp_pbr_rule_alloc_intern
);
2352 if (bpr
&& bpr
->unique
== 0) {
2353 bpr
->unique
= ++bgp_pbr_action_counter_unique
;
2354 bpr
->installed
= false;
2355 bpr
->install_in_progress
= false;
2356 /* link bgp info to bpr */
2357 bpr
->path
= (void *)path
;
2360 /* already installed */
2361 if (bpr_found
&& bpr
) {
2362 struct bgp_path_info_extra
*extra
=
2363 bgp_path_info_extra_get(path
);
2366 listnode_lookup_nocheck(extra
->bgp_fs_iprule
,
2368 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2369 zlog_err("%s: entry %p/%p already installed in bgp pbr iprule",
2370 __func__
, path
, bpr
);
2374 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2375 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2376 bgp_zebra_announce_default(bgp
, nh
,
2378 bpa
->table_id
, true);
2381 if (bpr
&& !bpr
->installed
)
2382 bgp_send_pbr_rule_action(bpa
, bpr
, true);
2384 /* A previous entry may already exist
2385 * flush previous entry if necessary
2387 bprr
.bpr_to_match
= bpr
;
2388 bprr
.bpr_found
= NULL
;
2389 hash_walk(bgp
->pbr_rule_hash
, bgp_pbr_get_same_rule
, &bprr
);
2390 if (bprr
.bpr_found
) {
2391 static struct bgp_pbr_rule
*local_bpr
;
2392 static struct bgp_pbr_action
*local_bpa
;
2394 local_bpr
= bprr
.bpr_found
;
2395 local_bpa
= local_bpr
->action
;
2396 bgp_pbr_flush_iprule(bgp
, local_bpa
,
2401 /* then look for bpm */
2402 memset(&temp
, 0, sizeof(temp
));
2403 temp
.vrf_id
= bpf
->vrf_id
;
2404 temp
.family
= bpf
->family
;
2406 temp
.flags
|= MATCH_IP_SRC_SET
;
2408 temp
.flags
|= MATCH_IP_DST_SET
;
2410 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2411 if (bpf
->protocol
== IPPROTO_ICMP
)
2412 temp
.flags
|= MATCH_ICMP_SET
;
2413 temp
.flags
|= MATCH_PORT_SRC_SET
;
2415 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
2416 if (bpf
->protocol
== IPPROTO_ICMP
)
2417 temp
.flags
|= MATCH_ICMP_SET
;
2418 temp
.flags
|= MATCH_PORT_DST_SET
;
2420 if (src_port
&& src_port
->max_port
)
2421 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
2422 if (dst_port
&& dst_port
->max_port
)
2423 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
2425 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
2426 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2427 temp
.type
= IPSET_NET_PORT
;
2429 temp
.type
= IPSET_NET
;
2431 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
2432 temp
.type
= IPSET_NET_PORT_NET
;
2434 temp
.type
= IPSET_NET_NET
;
2437 temp
.pkt_len_min
= pkt_len
->min_port
;
2438 if (pkt_len
->max_port
)
2439 temp
.pkt_len_max
= pkt_len
->max_port
;
2440 } else if (bpf
->pkt_len_val
) {
2441 if (bpf
->pkt_len_val
->mask
)
2442 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
2443 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
2445 if (bpf
->tcp_flags
) {
2446 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
2447 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
2450 if (bpf
->dscp
->mask
)
2451 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
2453 temp
.flags
|= MATCH_DSCP_SET
;
2454 temp
.dscp_value
= bpf
->dscp
->val
;
2456 if (bpf
->flow_label
) {
2457 if (bpf
->flow_label
->mask
)
2458 temp
.flags
|= MATCH_FLOW_LABEL_INVERSE_SET
;
2460 temp
.flags
|= MATCH_FLOW_LABEL_SET
;
2461 temp
.flow_label
= bpf
->flow_label
->val
;
2463 if (bpf
->fragment
) {
2464 if (bpf
->fragment
->mask
)
2465 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
2466 temp
.fragment
= bpf
->fragment
->val
;
2468 if (bpf
->protocol
) {
2469 temp
.protocol
= bpf
->protocol
;
2470 temp
.flags
|= MATCH_PROTOCOL_SET
;
2473 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
2474 bgp_pbr_match_alloc_intern
);
2476 /* new, then self allocate ipset_name and unique */
2477 if (bpm
->unique
== 0) {
2478 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
2479 /* 0 value is forbidden */
2480 snprintf(bpm
->ipset_name
, sizeof(bpm
->ipset_name
),
2482 bpm
->entry_hash
= hash_create_size(8,
2483 bgp_pbr_match_entry_hash_key
,
2484 bgp_pbr_match_entry_hash_equal
,
2485 "Match Entry Hash");
2486 bpm
->installed
= false;
2488 /* unique2 should be updated too */
2489 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
2490 bpm
->installed_in_iptable
= false;
2491 bpm
->install_in_progress
= false;
2492 bpm
->install_iptable_in_progress
= false;
2495 memset(&temp2
, 0, sizeof(temp2
));
2497 prefix_copy(&temp2
.src
, bpf
->src
);
2499 temp2
.src
.family
= bpf
->family
;
2501 prefix_copy(&temp2
.dst
, bpf
->dst
);
2503 temp2
.dst
.family
= bpf
->family
;
2504 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
2505 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
2506 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
2507 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
2508 temp2
.proto
= bpf
->protocol
;
2509 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
2510 bgp_pbr_match_entry_alloc_intern
);
2511 if (bpme
->unique
== 0) {
2512 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
2513 /* 0 value is forbidden */
2514 bpme
->backpointer
= bpm
;
2515 bpme
->installed
= false;
2516 bpme
->install_in_progress
= false;
2517 /* link bgp info to bpme */
2518 bpme
->path
= (void *)path
;
2522 /* already installed */
2524 struct bgp_path_info_extra
*extra
=
2525 bgp_path_info_extra_get(path
);
2528 listnode_lookup_nocheck(extra
->bgp_fs_pbr
, bpme
)) {
2529 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2531 "%s: entry %p/%p already installed in bgp pbr",
2532 __func__
, path
, bpme
);
2536 /* BGP FS: append entry to zebra
2537 * - policies are not routing entries and as such
2538 * route replace semantics don't necessarily follow
2539 * through to policy entries
2540 * - because of that, not all policing information will be stored
2541 * into zebra. and non selected policies will be suppressed from zebra
2542 * - as consequence, in order to bring consistency
2543 * a policy will be added, then ifan ecmp policy exists,
2544 * it will be suppressed subsequently
2547 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
2548 bgp_send_pbr_rule_action(bpa
, NULL
, true);
2549 bgp_zebra_announce_default(bgp
, nh
,
2550 bpa
->afi
, bpa
->table_id
, true);
2554 if (!bpm
->installed
)
2555 bgp_send_pbr_ipset_match(bpm
, true);
2557 if (!bpme
->installed
)
2558 bgp_send_pbr_ipset_entry_match(bpme
, true);
2561 if (!bpm
->installed_in_iptable
)
2562 bgp_send_pbr_iptable(bpa
, bpm
, true);
2564 /* A previous entry may already exist
2565 * flush previous entry if necessary
2567 bpmer
.bpme_to_match
= bpme
;
2568 bpmer
.bpme_found
= NULL
;
2569 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
2570 if (bpmer
.bpme_found
) {
2571 static struct bgp_pbr_match
*local_bpm
;
2572 static struct bgp_pbr_action
*local_bpa
;
2574 local_bpm
= bpmer
.bpme_found
->backpointer
;
2575 local_bpa
= local_bpm
->action
;
2576 bgp_pbr_flush_entry(bgp
, local_bpa
,
2577 local_bpm
, bpmer
.bpme_found
);
2583 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2584 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
2585 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
2588 struct listnode
*node
, *nnode
;
2589 struct bgp_pbr_val_mask
*valmask
;
2590 uint8_t next_type_entry
;
2591 struct list
*orig_list
;
2592 struct bgp_pbr_val_mask
**target_val
;
2594 if (type_entry
== 0) {
2595 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2598 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
2599 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
2600 orig_list
= bpof
->tcpflags
;
2601 target_val
= &bpf
->tcp_flags
;
2602 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
2603 orig_list
= bpof
->dscp
;
2604 target_val
= &bpf
->dscp
;
2605 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
2606 orig_list
= bpof
->pkt_len
;
2607 target_val
= &bpf
->pkt_len_val
;
2608 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
2609 orig_list
= bpof
->fragment
;
2610 target_val
= &bpf
->fragment
;
2611 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
2612 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
2613 /* enumerate list for icmp - must be last one */
2614 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
2617 bgp_pbr_policyroute_add_to_zebra_recursive(
2618 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2621 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
2622 *target_val
= valmask
;
2623 bgp_pbr_policyroute_add_to_zebra_recursive(
2624 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
2628 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
2629 struct bgp_path_info
*path
,
2630 struct bgp_pbr_filter
*bpf
,
2631 struct bgp_pbr_or_filter
*bpof
,
2632 struct nexthop
*nh
, float *rate
)
2635 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2639 bgp_pbr_policyroute_add_to_zebra_recursive(
2640 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2641 else if (bpof
->dscp
)
2642 bgp_pbr_policyroute_add_to_zebra_recursive(
2643 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2644 else if (bpof
->pkt_len
)
2645 bgp_pbr_policyroute_add_to_zebra_recursive(
2646 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2647 else if (bpof
->fragment
)
2648 bgp_pbr_policyroute_add_to_zebra_recursive(
2649 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2650 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2651 bgp_pbr_policyroute_add_to_zebra_recursive(
2652 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2654 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2657 list_delete_all_node(bpof
->tcpflags
);
2659 list_delete_all_node(bpof
->dscp
);
2661 list_delete_all_node(bpof
->pkt_len
);
2663 list_delete_all_node(bpof
->fragment
);
2664 if (bpof
->icmp_type
)
2665 list_delete_all_node(bpof
->icmp_type
);
2666 if (bpof
->icmp_code
)
2667 list_delete_all_node(bpof
->icmp_code
);
2670 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2671 struct bgp_pbr_entry_main
*api
, bool add
)
2675 int continue_loop
= 1;
2677 struct prefix
*src
= NULL
, *dst
= NULL
;
2679 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2680 struct bgp_pbr_range_port range
, range_icmp_code
;
2681 struct bgp_pbr_range_port pkt_len
;
2682 struct bgp_pbr_filter bpf
;
2684 struct bgp_pbr_or_filter bpof
;
2685 struct bgp_pbr_val_mask bpvm
;
2687 memset(&nh
, 0, sizeof(struct nexthop
));
2688 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2689 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2690 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
||
2691 (api
->type
== BGP_PBR_IPRULE
&&
2692 api
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
))
2693 src
= &api
->src_prefix
;
2694 if (api
->match_bitmask
& PREFIX_DST_PRESENT
||
2695 (api
->type
== BGP_PBR_IPRULE
&&
2696 api
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
2697 dst
= &api
->dst_prefix
;
2698 if (api
->type
== BGP_PBR_IPRULE
)
2699 bpf
.type
= api
->type
;
2700 memset(&nh
, 0, sizeof(struct nexthop
));
2701 nh
.vrf_id
= VRF_UNKNOWN
;
2702 if (api
->match_protocol_num
) {
2703 proto
= (uint8_t)api
->protocol
[0].value
;
2704 if (api
->afi
== AF_INET6
&& proto
== IPPROTO_ICMPV6
)
2705 proto
= IPPROTO_ICMP
;
2707 /* if match_port is selected, then either src or dst port will be parsed
2708 * but not both at the same time
2710 if (api
->match_port_num
>= 1) {
2711 bgp_pbr_extract(api
->port
,
2712 api
->match_port_num
,
2714 srcp
= dstp
= &range
;
2715 } else if (api
->match_src_port_num
>= 1) {
2716 bgp_pbr_extract(api
->src_port
,
2717 api
->match_src_port_num
,
2721 } else if (api
->match_dst_port_num
>= 1) {
2722 bgp_pbr_extract(api
->dst_port
,
2723 api
->match_dst_port_num
,
2728 if (api
->match_icmp_type_num
>= 1) {
2729 proto
= IPPROTO_ICMP
;
2730 if (bgp_pbr_extract(api
->icmp_type
,
2731 api
->match_icmp_type_num
,
2735 bpof
.icmp_type
= list_new();
2736 bgp_pbr_extract_enumerate(api
->icmp_type
,
2737 api
->match_icmp_type_num
,
2740 FLOWSPEC_ICMP_TYPE
);
2743 if (api
->match_icmp_code_num
>= 1) {
2744 proto
= IPPROTO_ICMP
;
2745 if (bgp_pbr_extract(api
->icmp_code
,
2746 api
->match_icmp_code_num
,
2748 dstp
= &range_icmp_code
;
2750 bpof
.icmp_code
= list_new();
2751 bgp_pbr_extract_enumerate(api
->icmp_code
,
2752 api
->match_icmp_code_num
,
2755 FLOWSPEC_ICMP_CODE
);
2759 if (api
->match_tcpflags_num
) {
2760 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2761 api
->match_tcpflags_num
);
2762 if (kind_enum
== OPERATOR_UNARY_AND
) {
2763 bpf
.tcp_flags
= &bpvm
;
2764 bgp_pbr_extract_enumerate(api
->tcpflags
,
2765 api
->match_tcpflags_num
,
2768 FLOWSPEC_TCP_FLAGS
);
2769 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2770 bpof
.tcpflags
= list_new();
2771 bgp_pbr_extract_enumerate(api
->tcpflags
,
2772 api
->match_tcpflags_num
,
2775 FLOWSPEC_TCP_FLAGS
);
2778 if (api
->match_packet_length_num
) {
2781 ret
= bgp_pbr_extract(api
->packet_length
,
2782 api
->match_packet_length_num
,
2785 bpf
.pkt_len
= &pkt_len
;
2787 bpof
.pkt_len
= list_new();
2788 bgp_pbr_extract_enumerate(api
->packet_length
,
2789 api
->match_packet_length_num
,
2795 if (api
->match_dscp_num
>= 1) {
2796 bpof
.dscp
= list_new();
2797 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2799 bpof
.dscp
, FLOWSPEC_DSCP
);
2801 if (api
->match_fragment_num
) {
2802 bpof
.fragment
= list_new();
2803 bgp_pbr_extract_enumerate(api
->fragment
,
2804 api
->match_fragment_num
,
2809 bpf
.vrf_id
= api
->vrf_id
;
2812 bpf
.protocol
= proto
;
2813 bpf
.src_port
= srcp
;
2814 bpf
.dst_port
= dstp
;
2815 bpf
.family
= afi2family(api
->afi
);
2817 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2820 /* no action for add = true */
2821 for (i
= 0; i
< api
->action_num
; i
++) {
2822 switch (api
->actions
[i
].action
) {
2823 case ACTION_TRAFFICRATE
:
2825 if (api
->actions
[i
].u
.r
.rate
== 0) {
2826 nh
.vrf_id
= api
->vrf_id
;
2827 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2828 bgp_pbr_policyroute_add_to_zebra(
2829 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2831 /* update rate. can be reentrant */
2832 rate
= api
->actions
[i
].u
.r
.rate
;
2833 if (BGP_DEBUG(pbr
, PBR
)) {
2834 bgp_pbr_print_policy_route(api
);
2835 zlog_warn("PBR: ignoring Set action rate %f",
2836 api
->actions
[i
].u
.r
.rate
);
2840 case ACTION_TRAFFIC_ACTION
:
2841 if (api
->actions
[i
].u
.za
.filter
2842 & TRAFFIC_ACTION_SAMPLE
) {
2843 if (BGP_DEBUG(pbr
, PBR
)) {
2844 bgp_pbr_print_policy_route(api
);
2845 zlog_warn("PBR: Sample action Ignored");
2849 if (api
->actions
[i
].u
.za
.filter
2850 & TRAFFIC_ACTION_DISTRIBUTE
) {
2851 if (BGP_DEBUG(pbr
, PBR
)) {
2852 bgp_pbr_print_policy_route(api
);
2853 zlog_warn("PBR: Distribute action Applies");
2856 /* continue forwarding entry as before
2860 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2861 /* terminate action: run other filters
2864 case ACTION_REDIRECT_IP
:
2865 nh
.vrf_id
= api
->vrf_id
;
2866 if (api
->afi
== AFI_IP
) {
2867 nh
.type
= NEXTHOP_TYPE_IPV4
;
2868 nh
.gate
.ipv4
.s_addr
=
2869 api
->actions
[i
].u
.zr
.
2870 redirect_ip_v4
.s_addr
;
2872 nh
.type
= NEXTHOP_TYPE_IPV6
;
2873 memcpy(&nh
.gate
.ipv6
,
2874 &api
->actions
[i
].u
.zr
.redirect_ip_v6
,
2875 sizeof(struct in6_addr
));
2877 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2879 /* XXX combination with REDIRECT_VRF
2880 * + REDIRECT_NH_IP not done
2884 case ACTION_REDIRECT
:
2885 if (api
->afi
== AFI_IP
)
2886 nh
.type
= NEXTHOP_TYPE_IPV4
;
2888 nh
.type
= NEXTHOP_TYPE_IPV6
;
2889 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2890 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2894 case ACTION_MARKING
:
2895 if (BGP_DEBUG(pbr
, PBR
)) {
2896 bgp_pbr_print_policy_route(api
);
2897 zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
2898 api
->actions
[i
].u
.marking_dscp
);
2904 if (continue_loop
== 0)
2909 void bgp_pbr_update_entry(struct bgp
*bgp
, const struct prefix
*p
,
2910 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2913 struct bgp_pbr_entry_main api
;
2915 if (safi
!= SAFI_FLOWSPEC
)
2916 return; /* not supported */
2917 /* Make Zebra API structure. */
2918 memset(&api
, 0, sizeof(api
));
2919 api
.vrf_id
= bgp
->vrf_id
;
2922 if (!bgp_zebra_tm_chunk_obtained()) {
2923 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2924 flog_err(EC_BGP_TABLE_CHUNK
,
2925 "%s: table chunk not obtained yet", __func__
);
2929 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2930 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2931 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2932 "%s: cancel updating entry %p in bgp pbr",
2936 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2939 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2940 const struct bgp_pbr_interface
*b
)
2942 return strcmp(a
->name
, b
->name
);
2945 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2946 struct bgp_pbr_interface_head
*head
)
2948 struct bgp_pbr_interface pbr_if
;
2950 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2951 return (RB_FIND(bgp_pbr_interface_head
,
2955 /* this function resets to the default policy routing
2956 * go back to default status
2958 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2960 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2961 struct bgp_pbr_interface_head
*head
;
2962 struct bgp_pbr_interface
*pbr_if
;
2967 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2969 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv6
);
2970 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2971 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2972 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2973 XFREE(MTYPE_TMP
, pbr_if
);