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
, "BGP PBR Context")
42 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value")
44 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
45 id_entry
, bgp_pbr_interface_compare
);
46 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
47 RB_INITIALIZER(&ifaces_by_name_ipv4
);
49 static int bgp_pbr_match_counter_unique
;
50 static int bgp_pbr_match_entry_counter_unique
;
51 static int bgp_pbr_action_counter_unique
;
52 static int bgp_pbr_match_iptable_counter_unique
;
54 struct bgp_pbr_match_iptable_unique
{
56 struct bgp_pbr_match
*bpm_found
;
59 struct bgp_pbr_match_entry_unique
{
61 struct bgp_pbr_match_entry
*bpme_found
;
64 struct bgp_pbr_action_unique
{
66 struct bgp_pbr_action
*bpa_found
;
69 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
71 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
72 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
74 uint32_t unique
= bpau
->unique
;
76 if (bpa
->unique
== unique
) {
77 bpau
->bpa_found
= bpa
;
78 return HASHWALK_ABORT
;
80 return HASHWALK_CONTINUE
;
83 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
85 struct bgp_pbr_match_entry
*bpme
=
86 (struct bgp_pbr_match_entry
*)backet
->data
;
87 struct bgp_pbr_match_entry_unique
*bpmeu
=
88 (struct bgp_pbr_match_entry_unique
*)arg
;
89 uint32_t unique
= bpmeu
->unique
;
91 if (bpme
->unique
== unique
) {
92 bpmeu
->bpme_found
= bpme
;
93 return HASHWALK_ABORT
;
95 return HASHWALK_CONTINUE
;
98 struct bgp_pbr_match_ipsetname
{
100 struct bgp_pbr_match
*bpm_found
;
103 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
105 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
106 struct bgp_pbr_match_ipsetname
*bpmi
=
107 (struct bgp_pbr_match_ipsetname
*)arg
;
108 char *ipset_name
= bpmi
->ipsetname
;
110 if (!strncmp(ipset_name
, bpm
->ipset_name
,
111 ZEBRA_IPSET_NAME_SIZE
)) {
112 bpmi
->bpm_found
= bpm
;
113 return HASHWALK_ABORT
;
115 return HASHWALK_CONTINUE
;
118 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
120 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
121 struct bgp_pbr_match_iptable_unique
*bpmiu
=
122 (struct bgp_pbr_match_iptable_unique
*)arg
;
123 uint32_t unique
= bpmiu
->unique
;
125 if (bpm
->unique2
== unique
) {
126 bpmiu
->bpm_found
= bpm
;
127 return HASHWALK_ABORT
;
129 return HASHWALK_CONTINUE
;
132 struct bgp_pbr_match_unique
{
134 struct bgp_pbr_match
*bpm_found
;
137 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
139 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
140 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
142 uint32_t unique
= bpmu
->unique
;
144 if (bpm
->unique
== unique
) {
145 bpmu
->bpm_found
= bpm
;
146 return HASHWALK_ABORT
;
148 return HASHWALK_CONTINUE
;
151 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
157 ptr
+= sprintf(ptr
, "%s", prepend
);
159 if (mval
->unary_operator
& OPERATOR_UNARY_OR
)
160 ptr
+= sprintf(ptr
, ", or ");
161 if (mval
->unary_operator
& OPERATOR_UNARY_AND
)
162 ptr
+= sprintf(ptr
, ", and ");
164 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
)
165 ptr
+= sprintf(ptr
, "<");
166 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
)
167 ptr
+= sprintf(ptr
, ">");
168 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
)
169 ptr
+= sprintf(ptr
, "=");
170 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
)
171 ptr
+= sprintf(ptr
, "match");
172 ptr
+= sprintf(ptr
, " %u", mval
->value
);
173 return (int)(ptr
- str
);
176 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
178 (_ptr) += sprintf((_ptr), "; "); \
182 /* this structure can be used for port range,
183 * but also for other values range like packet length range
185 struct bgp_pbr_range_port
{
190 /* this structure can be used to filter with a mask
191 * for instance it supports not instructions like for
194 struct bgp_pbr_val_mask
{
199 /* this structure is used to pass instructs
200 * so that BGP can create pbr instructions to ZEBRA
202 struct bgp_pbr_filter
{
207 struct bgp_pbr_range_port
*pkt_len
;
208 struct bgp_pbr_range_port
*src_port
;
209 struct bgp_pbr_range_port
*dst_port
;
210 struct bgp_pbr_val_mask
*tcp_flags
;
211 struct bgp_pbr_val_mask
*dscp
;
212 struct bgp_pbr_val_mask
*pkt_len_val
;
213 struct bgp_pbr_val_mask
*fragment
;
216 /* this structure is used to contain OR instructions
217 * so that BGP can create multiple pbr instructions
220 struct bgp_pbr_or_filter
{
221 struct list
*tcpflags
;
223 struct list
*pkt_len
;
224 struct list
*fragment
;
225 struct list
*icmp_type
;
226 struct list
*icmp_code
;
229 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
230 struct bgp_path_info
*path
,
231 struct bgp_pbr_filter
*bpf
,
235 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
237 static bool bgp_pbr_extract_enumerate_unary_opposite(
238 uint8_t unary_operator
,
239 struct bgp_pbr_val_mask
*and_valmask
,
240 struct list
*or_valmask
, uint32_t value
,
243 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
244 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
246 TCP_HEADER_ALL_FLAGS
&
248 } else if (type_entry
== FLOWSPEC_DSCP
||
249 type_entry
== FLOWSPEC_PKT_LEN
||
250 type_entry
== FLOWSPEC_FRAGMENT
) {
251 and_valmask
->val
= value
;
252 and_valmask
->mask
= 1; /* inverse */
254 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
255 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
256 sizeof(struct bgp_pbr_val_mask
));
257 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
258 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
260 TCP_HEADER_ALL_FLAGS
&
262 } else if (type_entry
== FLOWSPEC_DSCP
||
263 type_entry
== FLOWSPEC_FRAGMENT
||
264 type_entry
== FLOWSPEC_PKT_LEN
) {
265 and_valmask
->val
= value
;
266 and_valmask
->mask
= 1; /* inverse */
268 listnode_add(or_valmask
, and_valmask
);
269 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
270 type_entry
== FLOWSPEC_ICMP_TYPE
)
275 /* TCP : FIN and SYN -> val = ALL; mask = 3
276 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
277 * other variables type: dscp, pkt len, fragment
278 * - value is copied in bgp_pbr_val_mask->val value
279 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
281 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
282 int num
, uint8_t unary_operator
,
283 void *valmask
, uint8_t type_entry
)
286 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
287 struct list
*or_valmask
= NULL
;
291 if (unary_operator
== OPERATOR_UNARY_AND
) {
292 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
293 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
294 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
295 or_valmask
= (struct list
*)valmask
;
298 for (i
= 0; i
< num
; i
++) {
299 if (i
!= 0 && list
[i
].unary_operator
!=
302 if (!(list
[i
].compare_operator
&
303 OPERATOR_COMPARE_EQUAL_TO
) &&
304 !(list
[i
].compare_operator
&
305 OPERATOR_COMPARE_EXACT_MATCH
)) {
306 if ((list
[i
].compare_operator
&
307 OPERATOR_COMPARE_LESS_THAN
) &&
308 (list
[i
].compare_operator
&
309 OPERATOR_COMPARE_GREATER_THAN
)) {
310 ret
= bgp_pbr_extract_enumerate_unary_opposite(
311 unary_operator
, and_valmask
,
312 or_valmask
, list
[i
].value
,
320 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
321 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
323 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
324 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
325 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
326 sizeof(struct bgp_pbr_val_mask
));
327 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
328 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
330 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
331 } else if (type_entry
== FLOWSPEC_DSCP
||
332 type_entry
== FLOWSPEC_ICMP_TYPE
||
333 type_entry
== FLOWSPEC_ICMP_CODE
||
334 type_entry
== FLOWSPEC_FRAGMENT
||
335 type_entry
== FLOWSPEC_PKT_LEN
)
336 and_valmask
->val
= list
[i
].value
;
337 listnode_add(or_valmask
, and_valmask
);
340 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
341 && type_entry
== FLOWSPEC_TCP_FLAGS
)
342 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
346 /* if unary operator can either be UNARY_OR/AND/OR-AND.
347 * in the latter case, combinationf of both is not handled
349 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
350 int num
, uint8_t unary_operator
,
351 void *valmask
, uint8_t type_entry
)
354 uint8_t unary_operator_val
;
355 bool double_check
= false;
357 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
358 (unary_operator
& OPERATOR_UNARY_AND
)) {
359 unary_operator_val
= OPERATOR_UNARY_AND
;
362 unary_operator_val
= unary_operator
;
363 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
364 valmask
, type_entry
);
365 if (!ret
&& double_check
)
366 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
373 /* returns the unary operator that is in the list
374 * return 0 if both operators are used
376 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
381 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
383 for (i
= 0; i
< num
; i
++) {
386 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
387 unary_operator
= OPERATOR_UNARY_OR
;
388 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
389 && unary_operator
== OPERATOR_UNARY_OR
) ||
390 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
391 && unary_operator
== OPERATOR_UNARY_AND
))
394 return unary_operator
;
398 /* return true if extraction ok
400 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
402 struct bgp_pbr_range_port
*range
)
405 bool exact_match
= false;
408 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
412 for (i
= 0; i
< num
; i
++) {
413 if (i
!= 0 && (list
[i
].compare_operator
==
414 OPERATOR_COMPARE_EQUAL_TO
))
416 if (i
== 0 && (list
[i
].compare_operator
==
417 OPERATOR_COMPARE_EQUAL_TO
)) {
419 range
->min_port
= list
[i
].value
;
422 if (exact_match
== true && i
> 0)
424 if (list
[i
].compare_operator
==
425 (OPERATOR_COMPARE_GREATER_THAN
+
426 OPERATOR_COMPARE_EQUAL_TO
)) {
428 range
->min_port
= list
[i
].value
;
429 } else if (list
[i
].compare_operator
==
430 (OPERATOR_COMPARE_LESS_THAN
+
431 OPERATOR_COMPARE_EQUAL_TO
)) {
433 range
->max_port
= list
[i
].value
;
434 } else if (list
[i
].compare_operator
==
435 OPERATOR_COMPARE_LESS_THAN
) {
437 range
->max_port
= list
[i
].value
- 1;
438 } else if (list
[i
].compare_operator
==
439 OPERATOR_COMPARE_GREATER_THAN
) {
441 range
->min_port
= list
[i
].value
+ 1;
447 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
449 bool enumerate_icmp
= false;
451 /* because bgp pbr entry may contain unsupported
452 * combinations, a message will be displayed here if
454 * for now, only match/set supported is
455 * - combination src/dst => redirect nexthop [ + rate]
456 * - combination src/dst => redirect VRF [ + rate]
457 * - combination src/dst => drop
458 * - combination srcport + @IP
460 if (api
->match_protocol_num
> 1) {
461 if (BGP_DEBUG(pbr
, PBR
))
462 zlog_debug("BGP: match protocol operations:"
463 "multiple protocols ( %d). ignoring.",
464 api
->match_protocol_num
);
467 if (api
->match_protocol_num
== 1 &&
468 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
469 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
470 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
471 if (BGP_DEBUG(pbr
, PBR
))
472 zlog_debug("BGP: match protocol operations:"
473 "protocol (%d) not supported. ignoring",
474 api
->match_protocol_num
);
477 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
478 if (BGP_DEBUG(pbr
, PBR
))
479 zlog_debug("BGP: match src port operations:"
480 "too complex. ignoring.");
483 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
484 if (BGP_DEBUG(pbr
, PBR
))
485 zlog_debug("BGP: match dst port operations:"
486 "too complex. ignoring.");
489 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
490 api
->match_tcpflags_num
,
492 OPERATOR_UNARY_OR
, NULL
,
493 FLOWSPEC_TCP_FLAGS
)) {
494 if (BGP_DEBUG(pbr
, PBR
))
495 zlog_debug("BGP: match tcp flags:"
496 "too complex. ignoring.");
499 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
500 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
501 api
->match_icmp_type_num
,
502 OPERATOR_UNARY_OR
, NULL
,
503 FLOWSPEC_ICMP_TYPE
)) {
504 if (BGP_DEBUG(pbr
, PBR
))
505 zlog_debug("BGP: match icmp type operations:"
506 "too complex. ignoring.");
509 enumerate_icmp
= true;
511 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
512 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
513 api
->match_icmp_code_num
,
514 OPERATOR_UNARY_OR
, NULL
,
515 FLOWSPEC_ICMP_CODE
)) {
516 if (BGP_DEBUG(pbr
, PBR
))
517 zlog_debug("BGP: match icmp code operations:"
518 "too complex. ignoring.");
520 } else if (api
->match_icmp_type_num
> 1 &&
521 enumerate_icmp
== false) {
522 if (BGP_DEBUG(pbr
, PBR
))
523 zlog_debug("BGP: match icmp code is enumerate"
524 ", and icmp type is not."
525 " too complex. ignoring.");
529 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
530 if (BGP_DEBUG(pbr
, PBR
))
531 zlog_debug("BGP: match port operations:"
532 "too complex. ignoring.");
535 if (api
->match_packet_length_num
) {
538 ret
= bgp_pbr_extract(api
->packet_length
,
539 api
->match_packet_length_num
, NULL
);
541 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
542 api
->match_packet_length_num
,
544 | OPERATOR_UNARY_AND
,
545 NULL
, FLOWSPEC_PKT_LEN
);
547 if (BGP_DEBUG(pbr
, PBR
))
548 zlog_debug("BGP: match packet length operations:"
549 "too complex. ignoring.");
553 if (api
->match_dscp_num
) {
554 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
555 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
556 NULL
, FLOWSPEC_DSCP
)) {
557 if (BGP_DEBUG(pbr
, PBR
))
558 zlog_debug("BGP: match DSCP operations:"
559 "too complex. ignoring.");
563 if (api
->match_fragment_num
) {
567 success
= bgp_pbr_extract_enumerate(api
->fragment
,
568 api
->match_fragment_num
,
570 | OPERATOR_UNARY_AND
,
571 NULL
, FLOWSPEC_FRAGMENT
);
575 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
576 if (api
->fragment
[i
].value
!= 1 &&
577 api
->fragment
[i
].value
!= 2 &&
578 api
->fragment
[i
].value
!= 4 &&
579 api
->fragment
[i
].value
!= 8) {
582 "Value not valid (%d) for this implementation",
583 api
->fragment
[i
].value
);
587 sprintf(fail_str
, "too complex. ignoring");
589 if (BGP_DEBUG(pbr
, PBR
))
590 zlog_debug("BGP: match fragment operation (%d) %s",
591 api
->match_fragment_num
,
597 /* no combinations with both src_port and dst_port
598 * or port with src_port and dst_port
600 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
601 api
->match_port_num
> 3) {
602 if (BGP_DEBUG(pbr
, PBR
))
603 zlog_debug("BGP: match multiple port operations:"
604 " too complex. ignoring.");
607 if ((api
->match_src_port_num
|| api
->match_dst_port_num
608 || api
->match_port_num
) && (api
->match_icmp_type_num
609 || api
->match_icmp_code_num
)) {
610 if (BGP_DEBUG(pbr
, PBR
))
611 zlog_debug("BGP: match multiple port/imcp operations:"
612 " too complex. ignoring.");
615 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
616 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
617 if (BGP_DEBUG(pbr
, PBR
)) {
618 bgp_pbr_print_policy_route(api
);
619 zlog_debug("BGP: match actions without src"
620 " or dst address can not operate."
628 /* return -1 if build or validation failed */
629 int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
630 struct bgp_path_info
*path
,
631 struct bgp_pbr_entry_main
*api
)
634 int i
, action_count
= 0;
635 struct ecommunity
*ecom
;
636 struct ecommunity_val
*ecom_eval
;
637 struct bgp_pbr_entry_action
*api_action
;
638 struct prefix
*src
= NULL
, *dst
= NULL
;
639 int valid_prefix
= 0;
641 struct bgp_pbr_entry_action
*api_action_redirect_ip
= NULL
;
643 /* extract match from flowspec entries */
644 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
645 p
->u
.prefix_flowspec
.prefixlen
, api
);
648 /* extract actiosn from flowspec ecom list */
649 if (path
&& path
->attr
&& path
->attr
->ecommunity
) {
650 ecom
= path
->attr
->ecommunity
;
651 for (i
= 0; i
< ecom
->size
; i
++) {
652 ecom_eval
= (struct ecommunity_val
*)
653 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
655 if (action_count
> ACTIONS_MAX_NUM
) {
656 if (BGP_DEBUG(pbr
, PBR_ERROR
))
658 EC_BGP_FLOWSPEC_PACKET
,
659 "%s: flowspec actions exceeds limit (max %u)",
660 __func__
, action_count
);
663 api_action
= &api
->actions
[action_count
- 1];
665 if ((ecom_eval
->val
[1] ==
666 (char)ECOMMUNITY_REDIRECT_VRF
) &&
667 (ecom_eval
->val
[0] ==
668 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
670 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
672 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
673 struct ecommunity
*eckey
= ecommunity_new();
674 struct ecommunity_val ecom_copy
;
676 memcpy(&ecom_copy
, ecom_eval
,
677 sizeof(struct ecommunity_val
));
679 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
680 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
681 ecommunity_add_val(eckey
, &ecom_copy
);
683 api_action
->action
= ACTION_REDIRECT
;
684 api_action
->u
.redirect_vrf
=
685 get_first_vrf_for_redirect_with_rt(
687 ecommunity_free(&eckey
);
688 } else if ((ecom_eval
->val
[0] ==
689 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
690 (ecom_eval
->val
[1] ==
691 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
692 /* in case the 2 ecom present,
694 * draft-ietf-idr-flowspec-redirect
696 if (api_action_redirect_ip
) {
697 if (api_action_redirect_ip
->u
698 .zr
.redirect_ip_v4
.s_addr
)
700 if (!path
->attr
->nexthop
.s_addr
)
702 api_action_redirect_ip
->u
703 .zr
.redirect_ip_v4
.s_addr
=
704 path
->attr
->nexthop
.s_addr
;
705 api_action_redirect_ip
->u
.zr
.duplicate
709 api_action
->action
= ACTION_REDIRECT_IP
;
710 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
711 path
->attr
->nexthop
.s_addr
;
712 api_action
->u
.zr
.duplicate
=
714 api_action_redirect_ip
= api_action
;
716 } else if ((ecom_eval
->val
[0] ==
717 (char)ECOMMUNITY_ENCODE_IP
) &&
718 (ecom_eval
->val
[1] ==
719 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
)) {
720 /* in case the 2 ecom present,
721 * overwrite simpson draft
722 * update redirect ip fields
724 if (api_action_redirect_ip
) {
725 memcpy(&(api_action_redirect_ip
->u
726 .zr
.redirect_ip_v4
.s_addr
),
727 (ecom_eval
->val
+2), 4);
728 api_action_redirect_ip
->u
733 api_action
->action
= ACTION_REDIRECT_IP
;
734 memcpy(&(api_action
->u
735 .zr
.redirect_ip_v4
.s_addr
),
736 (ecom_eval
->val
+2), 4);
737 api_action
->u
.zr
.duplicate
=
739 api_action_redirect_ip
= api_action
;
742 if (ecom_eval
->val
[0] !=
743 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
745 ret
= ecommunity_fill_pbr_action(ecom_eval
,
754 /* validate if incoming matc/action is compatible
755 * with our policy routing engine
757 if (!bgp_pbr_validate_policy_route(api
))
760 /* check inconsistency in the match rule */
761 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
762 src
= &api
->src_prefix
;
763 afi
= family2afi(src
->family
);
766 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
767 dst
= &api
->dst_prefix
;
768 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
769 if (BGP_DEBUG(pbr
, PBR
)) {
770 bgp_pbr_print_policy_route(api
);
771 zlog_debug("%s: inconsistency:"
772 " no match for afi src and dst (%u/%u)",
773 __func__
, afi
, family2afi(dst
->family
));
781 static void bgp_pbr_match_entry_free(void *arg
)
783 struct bgp_pbr_match_entry
*bpme
;
785 bpme
= (struct bgp_pbr_match_entry
*)arg
;
787 if (bpme
->installed
) {
788 bgp_send_pbr_ipset_entry_match(bpme
, false);
789 bpme
->installed
= false;
790 bpme
->backpointer
= NULL
;
792 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
795 static void bgp_pbr_match_free(void *arg
)
797 struct bgp_pbr_match
*bpm
;
799 bpm
= (struct bgp_pbr_match
*)arg
;
801 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
803 if (hashcount(bpm
->entry_hash
) == 0) {
804 /* delete iptable entry first */
805 /* then delete ipset match */
806 if (bpm
->installed
) {
807 if (bpm
->installed_in_iptable
) {
808 bgp_send_pbr_iptable(bpm
->action
,
810 bpm
->installed_in_iptable
= false;
811 bpm
->action
->refcnt
--;
813 bgp_send_pbr_ipset_match(bpm
, false);
814 bpm
->installed
= false;
818 hash_free(bpm
->entry_hash
);
820 XFREE(MTYPE_PBR_MATCH
, bpm
);
823 static void *bgp_pbr_match_alloc_intern(void *arg
)
825 struct bgp_pbr_match
*bpm
, *new;
827 bpm
= (struct bgp_pbr_match
*)arg
;
829 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
830 memcpy(new, bpm
, sizeof(*bpm
));
835 static void bgp_pbr_action_free(void *arg
)
837 struct bgp_pbr_action
*bpa
;
839 bpa
= (struct bgp_pbr_action
*)arg
;
841 if (bpa
->refcnt
== 0) {
842 if (bpa
->installed
&& bpa
->table_id
!= 0) {
843 bgp_send_pbr_rule_action(bpa
, false);
844 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
848 bpa
->installed
= false;
851 XFREE(MTYPE_PBR_ACTION
, bpa
);
854 static void *bgp_pbr_action_alloc_intern(void *arg
)
856 struct bgp_pbr_action
*bpa
, *new;
858 bpa
= (struct bgp_pbr_action
*)arg
;
860 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
862 memcpy(new, bpa
, sizeof(*bpa
));
867 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
869 struct bgp_pbr_match_entry
*bpme
, *new;
871 bpme
= (struct bgp_pbr_match_entry
*)arg
;
873 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
875 memcpy(new, bpme
, sizeof(*bpme
));
880 uint32_t bgp_pbr_match_hash_key(void *arg
)
882 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
885 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
886 key
= jhash_1word(pbm
->flags
, key
);
887 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
888 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
889 key
= jhash(&pbm
->tcp_flags
, 2, key
);
890 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
891 key
= jhash(&pbm
->dscp_value
, 1, key
);
892 key
= jhash(&pbm
->fragment
, 1, key
);
893 return jhash_1word(pbm
->type
, key
);
896 bool bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
898 const struct bgp_pbr_match
*r1
, *r2
;
900 r1
= (const struct bgp_pbr_match
*)arg1
;
901 r2
= (const struct bgp_pbr_match
*)arg2
;
903 if (r1
->vrf_id
!= r2
->vrf_id
)
906 if (r1
->type
!= r2
->type
)
909 if (r1
->flags
!= r2
->flags
)
912 if (r1
->action
!= r2
->action
)
915 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
918 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
921 if (r1
->tcp_flags
!= r2
->tcp_flags
)
924 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
927 if (r1
->dscp_value
!= r2
->dscp_value
)
930 if (r1
->fragment
!= r2
->fragment
)
935 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
937 struct bgp_pbr_match_entry
*pbme
;
940 pbme
= (struct bgp_pbr_match_entry
*)arg
;
941 key
= prefix_hash_key(&pbme
->src
);
942 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
943 key
= jhash(&pbme
->dst_port_min
, 2, key
);
944 key
= jhash(&pbme
->src_port_min
, 2, key
);
945 key
= jhash(&pbme
->dst_port_max
, 2, key
);
946 key
= jhash(&pbme
->src_port_max
, 2, key
);
947 key
= jhash(&pbme
->proto
, 1, key
);
952 bool bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
954 const struct bgp_pbr_match_entry
*r1
, *r2
;
956 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
957 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
960 * on updates, comparing backpointer is not necessary
961 * unique value is self calculated
962 * rate is ignored for now
965 if (!prefix_same(&r1
->src
, &r2
->src
))
968 if (!prefix_same(&r1
->dst
, &r2
->dst
))
971 if (r1
->src_port_min
!= r2
->src_port_min
)
974 if (r1
->dst_port_min
!= r2
->dst_port_min
)
977 if (r1
->src_port_max
!= r2
->src_port_max
)
980 if (r1
->dst_port_max
!= r2
->dst_port_max
)
983 if (r1
->proto
!= r2
->proto
)
989 uint32_t bgp_pbr_action_hash_key(void *arg
)
991 struct bgp_pbr_action
*pbra
;
994 pbra
= (struct bgp_pbr_action
*)arg
;
995 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
996 key
= jhash_1word(pbra
->fwmark
, key
);
1000 bool bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
1002 const struct bgp_pbr_action
*r1
, *r2
;
1004 r1
= (const struct bgp_pbr_action
*)arg1
;
1005 r2
= (const struct bgp_pbr_action
*)arg2
;
1007 /* unique value is self calculated
1008 * table and fwmark is self calculated
1011 if (r1
->vrf_id
!= r2
->vrf_id
)
1014 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
1020 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
1023 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1024 struct bgp_pbr_action_unique bpau
;
1026 if (!bgp
|| unique
== 0)
1028 bpau
.unique
= unique
;
1029 bpau
.bpa_found
= NULL
;
1030 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
1031 return bpau
.bpa_found
;
1034 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
1037 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1038 struct bgp_pbr_match_unique bpmu
;
1040 if (!bgp
|| unique
== 0)
1042 bpmu
.unique
= unique
;
1043 bpmu
.bpm_found
= NULL
;
1044 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
1045 return bpmu
.bpm_found
;
1048 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1052 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1053 struct bgp_pbr_match_entry_unique bpmeu
;
1054 struct bgp_pbr_match_ipsetname bpmi
;
1056 if (!bgp
|| unique
== 0)
1058 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1059 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1060 bpmi
.bpm_found
= NULL
;
1061 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1062 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1063 if (!bpmi
.bpm_found
)
1065 bpmeu
.bpme_found
= NULL
;
1066 bpmeu
.unique
= unique
;
1067 hash_walk(bpmi
.bpm_found
->entry_hash
,
1068 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1069 return bpmeu
.bpme_found
;
1072 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1075 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1076 struct bgp_pbr_match_iptable_unique bpmiu
;
1078 if (!bgp
|| unique
== 0)
1080 bpmiu
.unique
= unique
;
1081 bpmiu
.bpm_found
= NULL
;
1082 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1083 return bpmiu
.bpm_found
;
1086 void bgp_pbr_cleanup(struct bgp
*bgp
)
1088 if (bgp
->pbr_match_hash
) {
1089 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1090 hash_free(bgp
->pbr_match_hash
);
1091 bgp
->pbr_match_hash
= NULL
;
1093 if (bgp
->pbr_action_hash
) {
1094 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1095 hash_free(bgp
->pbr_action_hash
);
1096 bgp
->pbr_action_hash
= NULL
;
1098 if (bgp
->bgp_pbr_cfg
== NULL
)
1100 bgp_pbr_reset(bgp
, AFI_IP
);
1101 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1102 bgp
->bgp_pbr_cfg
= NULL
;
1105 void bgp_pbr_init(struct bgp
*bgp
)
1107 bgp
->pbr_match_hash
=
1108 hash_create_size(8, bgp_pbr_match_hash_key
,
1109 bgp_pbr_match_hash_equal
,
1111 bgp
->pbr_action_hash
=
1112 hash_create_size(8, bgp_pbr_action_hash_key
,
1113 bgp_pbr_action_hash_equal
,
1114 "Match Hash Entry");
1116 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1117 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1120 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1123 char return_string
[512];
1124 char *ptr
= return_string
;
1128 ptr
+= sprintf(ptr
, "MATCH : ");
1129 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1130 struct prefix
*p
= &(api
->src_prefix
);
1132 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1133 INCREMENT_DISPLAY(ptr
, nb_items
);
1135 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1136 struct prefix
*p
= &(api
->dst_prefix
);
1138 INCREMENT_DISPLAY(ptr
, nb_items
);
1139 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1142 if (api
->match_protocol_num
)
1143 INCREMENT_DISPLAY(ptr
, nb_items
);
1144 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1145 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1146 i
> 0 ? NULL
: "@proto ");
1148 if (api
->match_src_port_num
)
1149 INCREMENT_DISPLAY(ptr
, nb_items
);
1150 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1151 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1152 i
> 0 ? NULL
: "@srcport ");
1154 if (api
->match_dst_port_num
)
1155 INCREMENT_DISPLAY(ptr
, nb_items
);
1156 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1157 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1158 i
> 0 ? NULL
: "@dstport ");
1160 if (api
->match_port_num
)
1161 INCREMENT_DISPLAY(ptr
, nb_items
);
1162 for (i
= 0; i
< api
->match_port_num
; i
++)
1163 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1164 i
> 0 ? NULL
: "@port ");
1166 if (api
->match_icmp_type_num
)
1167 INCREMENT_DISPLAY(ptr
, nb_items
);
1168 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1169 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1170 i
> 0 ? NULL
: "@icmptype ");
1172 if (api
->match_icmp_code_num
)
1173 INCREMENT_DISPLAY(ptr
, nb_items
);
1174 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1175 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1176 i
> 0 ? NULL
: "@icmpcode ");
1178 if (api
->match_packet_length_num
)
1179 INCREMENT_DISPLAY(ptr
, nb_items
);
1180 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1181 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1182 i
> 0 ? NULL
: "@plen ");
1184 if (api
->match_dscp_num
)
1185 INCREMENT_DISPLAY(ptr
, nb_items
);
1186 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1187 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1188 i
> 0 ? NULL
: "@dscp ");
1190 if (api
->match_tcpflags_num
)
1191 INCREMENT_DISPLAY(ptr
, nb_items
);
1192 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1193 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1194 i
> 0 ? NULL
: "@tcpflags ");
1196 if (api
->match_fragment_num
)
1197 INCREMENT_DISPLAY(ptr
, nb_items
);
1198 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1199 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1200 i
> 0 ? NULL
: "@fragment ");
1202 ptr
= return_string
;
1204 ptr
+= sprintf(ptr
, "; ");
1205 if (api
->action_num
)
1206 ptr
+= sprintf(ptr
, "SET : ");
1208 for (i
= 0; i
< api
->action_num
; i
++) {
1209 switch (api
->actions
[i
].action
) {
1210 case ACTION_TRAFFICRATE
:
1211 INCREMENT_DISPLAY(ptr
, nb_items
);
1212 ptr
+= sprintf(ptr
, "@set rate %f",
1213 api
->actions
[i
].u
.r
.rate
);
1215 case ACTION_TRAFFIC_ACTION
:
1216 INCREMENT_DISPLAY(ptr
, nb_items
);
1217 ptr
+= sprintf(ptr
, "@action ");
1218 if (api
->actions
[i
].u
.za
.filter
1219 & TRAFFIC_ACTION_TERMINATE
)
1221 " terminate (apply filter(s))");
1222 if (api
->actions
[i
].u
.za
.filter
1223 & TRAFFIC_ACTION_DISTRIBUTE
)
1224 ptr
+= sprintf(ptr
, " distribute");
1225 if (api
->actions
[i
].u
.za
.filter
1226 & TRAFFIC_ACTION_SAMPLE
)
1227 ptr
+= sprintf(ptr
, " sample");
1229 case ACTION_REDIRECT_IP
:
1230 INCREMENT_DISPLAY(ptr
, nb_items
);
1231 char local_buff
[INET_ADDRSTRLEN
];
1233 if (inet_ntop(AF_INET
,
1234 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1235 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1237 "@redirect ip nh %s", local_buff
);
1239 case ACTION_REDIRECT
:
1240 INCREMENT_DISPLAY(ptr
, nb_items
);
1241 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1242 api
->actions
[i
].u
.redirect_vrf
);
1244 case ACTION_MARKING
:
1245 INCREMENT_DISPLAY(ptr
, nb_items
);
1246 ptr
+= sprintf(ptr
, "@set dscp %u",
1247 api
->actions
[i
].u
.marking_dscp
);
1253 zlog_info("%s", return_string
);
1256 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1257 struct bgp_pbr_match
*bpm
,
1258 struct bgp_pbr_match_entry
*bpme
)
1260 /* if bpme is null, bpm is also null
1264 /* ipset del entry */
1265 if (bpme
->installed
) {
1266 bgp_send_pbr_ipset_entry_match(bpme
, false);
1267 bpme
->installed
= false;
1268 bpme
->backpointer
= NULL
;
1270 struct bgp_path_info
*path
;
1271 struct bgp_path_info_extra
*extra
;
1273 /* unlink bgp_path_info to bpme */
1274 path
= (struct bgp_path_info
*)bpme
->path
;
1275 extra
= bgp_path_info_extra_get(path
);
1276 if (extra
->bgp_fs_pbr
)
1277 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1281 hash_release(bpm
->entry_hash
, bpme
);
1282 if (hashcount(bpm
->entry_hash
) == 0) {
1283 /* delete iptable entry first */
1284 /* then delete ipset match */
1285 if (bpm
->installed
) {
1286 if (bpm
->installed_in_iptable
) {
1287 bgp_send_pbr_iptable(bpm
->action
,
1289 bpm
->installed_in_iptable
= false;
1290 bpm
->action
->refcnt
--;
1292 bgp_send_pbr_ipset_match(bpm
, false);
1293 bpm
->installed
= false;
1296 hash_release(bgp
->pbr_match_hash
, bpm
);
1297 /* XXX release pbr_match_action if not used
1298 * note that drop does not need to call send_pbr_action
1301 if (bpa
->refcnt
== 0) {
1302 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1303 bgp_send_pbr_rule_action(bpa
, false);
1304 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1308 bpa
->installed
= false;
1313 struct bgp_pbr_match_entry_remain
{
1314 struct bgp_pbr_match_entry
*bpme_to_match
;
1315 struct bgp_pbr_match_entry
*bpme_found
;
1318 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1320 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1321 struct bgp_pbr_match_entry_remain
*bpmer
=
1322 (struct bgp_pbr_match_entry_remain
*)arg
;
1323 struct bgp_pbr_match
*bpm_temp
;
1324 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1326 if (!bpme
->backpointer
||
1327 bpm
== bpme
->backpointer
||
1328 bpme
->backpointer
->action
== bpm
->action
)
1329 return HASHWALK_CONTINUE
;
1330 /* ensure bpm other characteristics are equal */
1331 bpm_temp
= bpme
->backpointer
;
1332 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1333 bpm_temp
->type
!= bpm
->type
||
1334 bpm_temp
->flags
!= bpm
->flags
||
1335 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1336 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1337 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1338 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1339 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1340 bpm_temp
->fragment
!= bpm
->fragment
)
1341 return HASHWALK_CONTINUE
;
1343 /* look for remaining bpme */
1344 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1345 if (!bpmer
->bpme_found
)
1346 return HASHWALK_CONTINUE
;
1347 return HASHWALK_ABORT
;
1350 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1351 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
)
1353 struct bgp_pbr_match temp
;
1354 struct bgp_pbr_match_entry temp2
;
1355 struct bgp_pbr_match
*bpm
;
1356 struct bgp_pbr_match_entry
*bpme
;
1357 struct bgp_pbr_match_entry_remain bpmer
;
1358 struct bgp_pbr_range_port
*src_port
;
1359 struct bgp_pbr_range_port
*dst_port
;
1360 struct bgp_pbr_range_port
*pkt_len
;
1364 src_port
= bpf
->src_port
;
1365 dst_port
= bpf
->dst_port
;
1366 pkt_len
= bpf
->pkt_len
;
1368 if (BGP_DEBUG(zebra
, ZEBRA
))
1369 bgp_pbr_dump_entry(bpf
, false);
1371 /* as we don't know information from EC
1372 * look for bpm that have the bpm
1373 * with vrf_id characteristics
1375 memset(&temp2
, 0, sizeof(temp2
));
1376 memset(&temp
, 0, sizeof(temp
));
1378 temp
.flags
|= MATCH_IP_SRC_SET
;
1379 prefix_copy(&temp2
.src
, bpf
->src
);
1381 temp2
.src
.family
= AF_INET
;
1383 temp
.flags
|= MATCH_IP_DST_SET
;
1384 prefix_copy(&temp2
.dst
, bpf
->dst
);
1386 temp2
.dst
.family
= AF_INET
;
1387 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1388 if (bpf
->protocol
== IPPROTO_ICMP
)
1389 temp
.flags
|= MATCH_ICMP_SET
;
1390 temp
.flags
|= MATCH_PORT_SRC_SET
;
1391 temp2
.src_port_min
= src_port
->min_port
;
1392 if (src_port
->max_port
) {
1393 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1394 temp2
.src_port_max
= src_port
->max_port
;
1397 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1398 if (bpf
->protocol
== IPPROTO_ICMP
)
1399 temp
.flags
|= MATCH_ICMP_SET
;
1400 temp
.flags
|= MATCH_PORT_DST_SET
;
1401 temp2
.dst_port_min
= dst_port
->min_port
;
1402 if (dst_port
->max_port
) {
1403 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1404 temp2
.dst_port_max
= dst_port
->max_port
;
1407 temp2
.proto
= bpf
->protocol
;
1410 temp
.pkt_len_min
= pkt_len
->min_port
;
1411 if (pkt_len
->max_port
)
1412 temp
.pkt_len_max
= pkt_len
->max_port
;
1413 } else if (bpf
->pkt_len_val
) {
1414 if (bpf
->pkt_len_val
->mask
)
1415 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1416 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1418 if (bpf
->tcp_flags
) {
1419 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1420 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1423 if (bpf
->dscp
->mask
)
1424 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1426 temp
.flags
|= MATCH_DSCP_SET
;
1427 temp
.dscp_value
= bpf
->dscp
->val
;
1429 if (bpf
->fragment
) {
1430 if (bpf
->fragment
->mask
)
1431 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1432 temp
.fragment
= bpf
->fragment
->val
;
1435 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1436 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1437 temp
.type
= IPSET_NET_PORT
;
1439 temp
.type
= IPSET_NET
;
1441 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1442 temp
.type
= IPSET_NET_PORT_NET
;
1444 temp
.type
= IPSET_NET_NET
;
1446 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1449 temp
.vrf_id
= bpf
->vrf_id
;
1452 bpme
->backpointer
= bpm
;
1453 /* right now, a previous entry may already exist
1454 * flush previous entry if necessary
1456 bpmer
.bpme_to_match
= bpme
;
1457 bpmer
.bpme_found
= NULL
;
1458 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1459 if (bpmer
.bpme_found
) {
1460 static struct bgp_pbr_match
*local_bpm
;
1461 static struct bgp_pbr_action
*local_bpa
;
1463 local_bpm
= bpmer
.bpme_found
->backpointer
;
1464 local_bpa
= local_bpm
->action
;
1465 bgp_pbr_flush_entry(bgp
, local_bpa
,
1466 local_bpm
, bpmer
.bpme_found
);
1470 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1472 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1473 return FLOWSPEC_DSCP
;
1474 if (type_entry
== FLOWSPEC_DSCP
)
1475 return FLOWSPEC_PKT_LEN
;
1476 if (type_entry
== FLOWSPEC_PKT_LEN
)
1477 return FLOWSPEC_FRAGMENT
;
1478 if (type_entry
== FLOWSPEC_FRAGMENT
)
1479 return FLOWSPEC_ICMP_TYPE
;
1483 static void bgp_pbr_icmp_action(struct bgp
*bgp
, struct bgp_path_info
*path
,
1484 struct bgp_pbr_filter
*bpf
,
1485 struct bgp_pbr_or_filter
*bpof
, bool add
,
1486 struct nexthop
*nh
, float *rate
)
1488 struct bgp_pbr_range_port srcp
, dstp
;
1489 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1490 struct listnode
*tnode
, *cnode
;
1494 if (bpf
->protocol
!= IPPROTO_ICMP
)
1496 bpf
->src_port
= &srcp
;
1497 bpf
->dst_port
= &dstp
;
1498 /* parse icmp type and lookup appropriate icmp code
1499 * if no icmp code found, create as many entryes as
1500 * there are listed icmp codes for that icmp type
1502 if (!bpof
->icmp_type
) {
1504 srcp
.max_port
= 255;
1505 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1506 dstp
.min_port
= icmp_code
->val
;
1508 bgp_pbr_policyroute_add_to_zebra_unit(
1509 bgp
, path
, bpf
, nh
, rate
);
1511 bgp_pbr_policyroute_remove_from_zebra_unit(
1516 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1517 srcp
.min_port
= icmp_type
->val
;
1520 /* only icmp type. create an entry only with icmp type */
1521 if (!bpof
->icmp_code
) {
1522 /* icmp type is not one of the above
1523 * forge an entry only based on the icmp type
1526 dstp
.max_port
= 255;
1528 bgp_pbr_policyroute_add_to_zebra_unit(
1529 bgp
, path
, bpf
, nh
, rate
);
1531 bgp_pbr_policyroute_remove_from_zebra_unit(
1535 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1536 dstp
.min_port
= icmp_code
->val
;
1538 bgp_pbr_policyroute_add_to_zebra_unit(
1539 bgp
, path
, bpf
, nh
, rate
);
1541 bgp_pbr_policyroute_remove_from_zebra_unit(
1547 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1548 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1549 struct bgp_pbr_or_filter
*bpof
, uint8_t type_entry
)
1551 struct listnode
*node
, *nnode
;
1552 struct bgp_pbr_val_mask
*valmask
;
1553 uint8_t next_type_entry
;
1554 struct list
*orig_list
;
1555 struct bgp_pbr_val_mask
**target_val
;
1557 if (type_entry
== 0) {
1558 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1561 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1562 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1563 orig_list
= bpof
->tcpflags
;
1564 target_val
= &bpf
->tcp_flags
;
1565 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1566 orig_list
= bpof
->dscp
;
1567 target_val
= &bpf
->dscp
;
1568 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1569 orig_list
= bpof
->pkt_len
;
1570 target_val
= &bpf
->pkt_len_val
;
1571 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1572 orig_list
= bpof
->fragment
;
1573 target_val
= &bpf
->fragment
;
1574 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1575 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1576 /* enumerate list for icmp - must be last one */
1577 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, false, NULL
, NULL
);
1580 bgp_pbr_policyroute_remove_from_zebra_recursive(
1581 bgp
, path
, bpf
, bpof
, next_type_entry
);
1584 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1585 *target_val
= valmask
;
1586 bgp_pbr_policyroute_remove_from_zebra_recursive(
1587 bgp
, path
, bpf
, bpof
, next_type_entry
);
1591 static void bgp_pbr_policyroute_remove_from_zebra(
1592 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1593 struct bgp_pbr_or_filter
*bpof
)
1596 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1600 bgp_pbr_policyroute_remove_from_zebra_recursive(
1601 bgp
, path
, bpf
, bpof
, FLOWSPEC_TCP_FLAGS
);
1602 else if (bpof
->dscp
)
1603 bgp_pbr_policyroute_remove_from_zebra_recursive(
1604 bgp
, path
, bpf
, bpof
, FLOWSPEC_DSCP
);
1605 else if (bpof
->pkt_len
)
1606 bgp_pbr_policyroute_remove_from_zebra_recursive(
1607 bgp
, path
, bpf
, bpof
, FLOWSPEC_PKT_LEN
);
1608 else if (bpof
->fragment
)
1609 bgp_pbr_policyroute_remove_from_zebra_recursive(
1610 bgp
, path
, bpf
, bpof
, FLOWSPEC_FRAGMENT
);
1611 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1612 bgp_pbr_policyroute_remove_from_zebra_recursive(
1613 bgp
, path
, bpf
, bpof
, FLOWSPEC_ICMP_TYPE
);
1615 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, path
, bpf
);
1618 list_delete_all_node(bpof
->tcpflags
);
1620 list_delete_all_node(bpof
->dscp
);
1622 list_delete_all_node(bpof
->pkt_len
);
1624 list_delete_all_node(bpof
->fragment
);
1627 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1629 struct bgp_pbr_range_port
*src_port
;
1630 struct bgp_pbr_range_port
*dst_port
;
1631 struct bgp_pbr_range_port
*pkt_len
;
1632 char bufsrc
[64], bufdst
[64];
1634 int remaining_len
= 0;
1635 char protocol_str
[16];
1639 src_port
= bpf
->src_port
;
1640 dst_port
= bpf
->dst_port
;
1641 pkt_len
= bpf
->pkt_len
;
1643 protocol_str
[0] = '\0';
1644 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1645 bpf
->protocol
= IPPROTO_TCP
;
1647 snprintf(protocol_str
, sizeof(protocol_str
),
1648 "proto %d", bpf
->protocol
);
1650 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1651 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1654 dst_port
->min_port
);
1655 else if (bpf
->protocol
== IPPROTO_UDP
||
1656 bpf
->protocol
== IPPROTO_TCP
) {
1658 if (src_port
&& src_port
->min_port
)
1659 remaining_len
+= snprintf(buffer
,
1663 src_port
->max_port
?
1664 src_port
->max_port
:
1665 src_port
->min_port
);
1666 if (dst_port
&& dst_port
->min_port
)
1667 remaining_len
+= snprintf(buffer
+
1673 dst_port
->max_port
?
1674 dst_port
->max_port
:
1675 dst_port
->min_port
);
1677 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1678 remaining_len
+= snprintf(buffer
+ remaining_len
,
1686 } else if (bpf
->pkt_len_val
) {
1687 remaining_len
+= snprintf(buffer
+ remaining_len
,
1691 bpf
->pkt_len_val
->mask
1693 bpf
->pkt_len_val
->val
);
1695 if (bpf
->tcp_flags
) {
1696 remaining_len
+= snprintf(buffer
+ remaining_len
,
1700 bpf
->tcp_flags
->val
,
1701 bpf
->tcp_flags
->mask
);
1704 snprintf(buffer
+ remaining_len
,
1712 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1713 add
? "adding" : "removing",
1714 bpf
->src
== NULL
? "<all>" :
1715 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1716 bpf
->dst
== NULL
? "<all>" :
1717 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1718 protocol_str
, buffer
);
1722 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1723 struct bgp_path_info
*path
,
1724 struct bgp_pbr_filter
*bpf
,
1728 struct bgp_pbr_match temp
;
1729 struct bgp_pbr_match_entry temp2
;
1730 struct bgp_pbr_match
*bpm
;
1731 struct bgp_pbr_match_entry
*bpme
= NULL
;
1732 struct bgp_pbr_action temp3
;
1733 struct bgp_pbr_action
*bpa
= NULL
;
1734 struct bgp_pbr_match_entry_remain bpmer
;
1735 struct bgp_pbr_range_port
*src_port
;
1736 struct bgp_pbr_range_port
*dst_port
;
1737 struct bgp_pbr_range_port
*pkt_len
;
1738 bool bpme_found
= false;
1742 src_port
= bpf
->src_port
;
1743 dst_port
= bpf
->dst_port
;
1744 pkt_len
= bpf
->pkt_len
;
1746 if (BGP_DEBUG(zebra
, ZEBRA
))
1747 bgp_pbr_dump_entry(bpf
, true);
1749 /* look for bpa first */
1750 memset(&temp3
, 0, sizeof(temp3
));
1754 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1755 temp3
.vrf_id
= bpf
->vrf_id
;
1756 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1757 bgp_pbr_action_alloc_intern
);
1759 if (bpa
->fwmark
== 0) {
1760 /* drop is handled by iptable */
1761 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1763 bpa
->installed
= true;
1765 bpa
->fwmark
= bgp_zebra_tm_get_id();
1766 bpa
->table_id
= bpa
->fwmark
;
1767 bpa
->installed
= false;
1770 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1771 /* 0 value is forbidden */
1772 bpa
->install_in_progress
= false;
1775 /* then look for bpm */
1776 memset(&temp
, 0, sizeof(temp
));
1777 temp
.vrf_id
= bpf
->vrf_id
;
1779 temp
.flags
|= MATCH_IP_SRC_SET
;
1781 temp
.flags
|= MATCH_IP_DST_SET
;
1783 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1784 if (bpf
->protocol
== IPPROTO_ICMP
)
1785 temp
.flags
|= MATCH_ICMP_SET
;
1786 temp
.flags
|= MATCH_PORT_SRC_SET
;
1788 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1789 if (bpf
->protocol
== IPPROTO_ICMP
)
1790 temp
.flags
|= MATCH_ICMP_SET
;
1791 temp
.flags
|= MATCH_PORT_DST_SET
;
1793 if (src_port
&& src_port
->max_port
)
1794 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1795 if (dst_port
&& dst_port
->max_port
)
1796 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1798 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1799 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1800 temp
.type
= IPSET_NET_PORT
;
1802 temp
.type
= IPSET_NET
;
1804 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1805 temp
.type
= IPSET_NET_PORT_NET
;
1807 temp
.type
= IPSET_NET_NET
;
1810 temp
.pkt_len_min
= pkt_len
->min_port
;
1811 if (pkt_len
->max_port
)
1812 temp
.pkt_len_max
= pkt_len
->max_port
;
1813 } else if (bpf
->pkt_len_val
) {
1814 if (bpf
->pkt_len_val
->mask
)
1815 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1816 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1818 if (bpf
->tcp_flags
) {
1819 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1820 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1823 if (bpf
->dscp
->mask
)
1824 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1826 temp
.flags
|= MATCH_DSCP_SET
;
1827 temp
.dscp_value
= bpf
->dscp
->val
;
1829 if (bpf
->fragment
) {
1830 if (bpf
->fragment
->mask
)
1831 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1832 temp
.fragment
= bpf
->fragment
->val
;
1835 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1836 bgp_pbr_match_alloc_intern
);
1838 /* new, then self allocate ipset_name and unique */
1839 if (bpm
->unique
== 0) {
1840 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1841 /* 0 value is forbidden */
1842 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1843 bpm
->entry_hash
= hash_create_size(8,
1844 bgp_pbr_match_entry_hash_key
,
1845 bgp_pbr_match_entry_hash_equal
,
1846 "Match Entry Hash");
1847 bpm
->installed
= false;
1849 /* unique2 should be updated too */
1850 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1851 bpm
->installed_in_iptable
= false;
1852 bpm
->install_in_progress
= false;
1853 bpm
->install_iptable_in_progress
= false;
1856 memset(&temp2
, 0, sizeof(temp2
));
1858 prefix_copy(&temp2
.src
, bpf
->src
);
1860 temp2
.src
.family
= AF_INET
;
1862 prefix_copy(&temp2
.dst
, bpf
->dst
);
1864 temp2
.dst
.family
= AF_INET
;
1865 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1866 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1867 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1868 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1869 temp2
.proto
= bpf
->protocol
;
1870 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1871 bgp_pbr_match_entry_alloc_intern
);
1872 if (bpme
->unique
== 0) {
1873 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1874 /* 0 value is forbidden */
1875 bpme
->backpointer
= bpm
;
1876 bpme
->installed
= false;
1877 bpme
->install_in_progress
= false;
1878 /* link bgp info to bpme */
1879 bpme
->path
= (void *)path
;
1883 /* already installed */
1885 struct bgp_path_info_extra
*extra
=
1886 bgp_path_info_extra_get(path
);
1888 if (extra
&& extra
->bgp_fs_pbr
&&
1889 listnode_lookup(extra
->bgp_fs_pbr
, bpme
)) {
1890 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1892 "%s: entry %p/%p already installed in bgp pbr",
1893 __func__
, path
, bpme
);
1897 /* BGP FS: append entry to zebra
1898 * - policies are not routing entries and as such
1899 * route replace semantics don't necessarily follow
1900 * through to policy entries
1901 * - because of that, not all policing information will be stored
1902 * into zebra. and non selected policies will be suppressed from zebra
1903 * - as consequence, in order to bring consistency
1904 * a policy will be added, then ifan ecmp policy exists,
1905 * it will be suppressed subsequently
1908 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1909 bgp_send_pbr_rule_action(bpa
, true);
1910 bgp_zebra_announce_default(bgp
, nh
,
1911 AFI_IP
, bpa
->table_id
, true);
1915 if (!bpm
->installed
)
1916 bgp_send_pbr_ipset_match(bpm
, true);
1918 if (!bpme
->installed
)
1919 bgp_send_pbr_ipset_entry_match(bpme
, true);
1922 if (!bpm
->installed_in_iptable
)
1923 bgp_send_pbr_iptable(bpa
, bpm
, true);
1925 /* A previous entry may already exist
1926 * flush previous entry if necessary
1928 bpmer
.bpme_to_match
= bpme
;
1929 bpmer
.bpme_found
= NULL
;
1930 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1931 if (bpmer
.bpme_found
) {
1932 static struct bgp_pbr_match
*local_bpm
;
1933 static struct bgp_pbr_action
*local_bpa
;
1935 local_bpm
= bpmer
.bpme_found
->backpointer
;
1936 local_bpa
= local_bpm
->action
;
1937 bgp_pbr_flush_entry(bgp
, local_bpa
,
1938 local_bpm
, bpmer
.bpme_found
);
1944 static void bgp_pbr_policyroute_add_to_zebra_recursive(
1945 struct bgp
*bgp
, struct bgp_path_info
*path
, struct bgp_pbr_filter
*bpf
,
1946 struct bgp_pbr_or_filter
*bpof
, struct nexthop
*nh
, float *rate
,
1949 struct listnode
*node
, *nnode
;
1950 struct bgp_pbr_val_mask
*valmask
;
1951 uint8_t next_type_entry
;
1952 struct list
*orig_list
;
1953 struct bgp_pbr_val_mask
**target_val
;
1955 if (type_entry
== 0) {
1956 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
1959 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1960 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1961 orig_list
= bpof
->tcpflags
;
1962 target_val
= &bpf
->tcp_flags
;
1963 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1964 orig_list
= bpof
->dscp
;
1965 target_val
= &bpf
->dscp
;
1966 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1967 orig_list
= bpof
->pkt_len
;
1968 target_val
= &bpf
->pkt_len_val
;
1969 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1970 orig_list
= bpof
->fragment
;
1971 target_val
= &bpf
->fragment
;
1972 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1973 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1974 /* enumerate list for icmp - must be last one */
1975 bgp_pbr_icmp_action(bgp
, path
, bpf
, bpof
, true, nh
, rate
);
1978 bgp_pbr_policyroute_add_to_zebra_recursive(
1979 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
1982 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1983 *target_val
= valmask
;
1984 bgp_pbr_policyroute_add_to_zebra_recursive(
1985 bgp
, path
, bpf
, bpof
, nh
, rate
, next_type_entry
);
1989 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1990 struct bgp_path_info
*path
,
1991 struct bgp_pbr_filter
*bpf
,
1992 struct bgp_pbr_or_filter
*bpof
,
1993 struct nexthop
*nh
, float *rate
)
1996 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2000 bgp_pbr_policyroute_add_to_zebra_recursive(
2001 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_TCP_FLAGS
);
2002 else if (bpof
->dscp
)
2003 bgp_pbr_policyroute_add_to_zebra_recursive(
2004 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_DSCP
);
2005 else if (bpof
->pkt_len
)
2006 bgp_pbr_policyroute_add_to_zebra_recursive(
2007 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_PKT_LEN
);
2008 else if (bpof
->fragment
)
2009 bgp_pbr_policyroute_add_to_zebra_recursive(
2010 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_FRAGMENT
);
2011 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
2012 bgp_pbr_policyroute_add_to_zebra_recursive(
2013 bgp
, path
, bpf
, bpof
, nh
, rate
, FLOWSPEC_ICMP_TYPE
);
2015 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, path
, bpf
, nh
, rate
);
2018 list_delete_all_node(bpof
->tcpflags
);
2020 list_delete_all_node(bpof
->dscp
);
2022 list_delete_all_node(bpof
->pkt_len
);
2024 list_delete_all_node(bpof
->fragment
);
2025 if (bpof
->icmp_type
)
2026 list_delete_all_node(bpof
->icmp_type
);
2027 if (bpof
->icmp_code
)
2028 list_delete_all_node(bpof
->icmp_code
);
2031 static void bgp_pbr_handle_entry(struct bgp
*bgp
, struct bgp_path_info
*path
,
2032 struct bgp_pbr_entry_main
*api
, bool add
)
2036 int continue_loop
= 1;
2038 struct prefix
*src
= NULL
, *dst
= NULL
;
2040 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2041 struct bgp_pbr_range_port range
, range_icmp_code
;
2042 struct bgp_pbr_range_port pkt_len
;
2043 struct bgp_pbr_filter bpf
;
2045 struct bgp_pbr_or_filter bpof
;
2046 struct bgp_pbr_val_mask bpvm
;
2048 memset(&nh
, 0, sizeof(struct nexthop
));
2049 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2050 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2051 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
2052 src
= &api
->src_prefix
;
2053 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
2054 dst
= &api
->dst_prefix
;
2055 memset(&nh
, 0, sizeof(struct nexthop
));
2056 nh
.vrf_id
= VRF_UNKNOWN
;
2057 if (api
->match_protocol_num
)
2058 proto
= (uint8_t)api
->protocol
[0].value
;
2059 /* if match_port is selected, then either src or dst port will be parsed
2060 * but not both at the same time
2062 if (api
->match_port_num
>= 1) {
2063 bgp_pbr_extract(api
->port
,
2064 api
->match_port_num
,
2066 srcp
= dstp
= &range
;
2067 } else if (api
->match_src_port_num
>= 1) {
2068 bgp_pbr_extract(api
->src_port
,
2069 api
->match_src_port_num
,
2073 } else if (api
->match_dst_port_num
>= 1) {
2074 bgp_pbr_extract(api
->dst_port
,
2075 api
->match_dst_port_num
,
2080 if (api
->match_icmp_type_num
>= 1) {
2081 proto
= IPPROTO_ICMP
;
2082 if (bgp_pbr_extract(api
->icmp_type
,
2083 api
->match_icmp_type_num
,
2087 bpof
.icmp_type
= list_new();
2088 bgp_pbr_extract_enumerate(api
->icmp_type
,
2089 api
->match_icmp_type_num
,
2092 FLOWSPEC_ICMP_TYPE
);
2095 if (api
->match_icmp_code_num
>= 1) {
2096 proto
= IPPROTO_ICMP
;
2097 if (bgp_pbr_extract(api
->icmp_code
,
2098 api
->match_icmp_code_num
,
2100 dstp
= &range_icmp_code
;
2102 bpof
.icmp_code
= list_new();
2103 bgp_pbr_extract_enumerate(api
->icmp_code
,
2104 api
->match_icmp_code_num
,
2107 FLOWSPEC_ICMP_CODE
);
2111 if (api
->match_tcpflags_num
) {
2112 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2113 api
->match_tcpflags_num
);
2114 if (kind_enum
== OPERATOR_UNARY_AND
) {
2115 bpf
.tcp_flags
= &bpvm
;
2116 bgp_pbr_extract_enumerate(api
->tcpflags
,
2117 api
->match_tcpflags_num
,
2120 FLOWSPEC_TCP_FLAGS
);
2121 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2122 bpof
.tcpflags
= list_new();
2123 bgp_pbr_extract_enumerate(api
->tcpflags
,
2124 api
->match_tcpflags_num
,
2127 FLOWSPEC_TCP_FLAGS
);
2130 if (api
->match_packet_length_num
) {
2133 ret
= bgp_pbr_extract(api
->packet_length
,
2134 api
->match_packet_length_num
,
2137 bpf
.pkt_len
= &pkt_len
;
2139 bpof
.pkt_len
= list_new();
2140 bgp_pbr_extract_enumerate(api
->packet_length
,
2141 api
->match_packet_length_num
,
2147 if (api
->match_dscp_num
>= 1) {
2148 bpof
.dscp
= list_new();
2149 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2151 bpof
.dscp
, FLOWSPEC_DSCP
);
2153 if (api
->match_fragment_num
) {
2154 bpof
.fragment
= list_new();
2155 bgp_pbr_extract_enumerate(api
->fragment
,
2156 api
->match_fragment_num
,
2161 bpf
.vrf_id
= api
->vrf_id
;
2164 bpf
.protocol
= proto
;
2165 bpf
.src_port
= srcp
;
2166 bpf
.dst_port
= dstp
;
2168 bgp_pbr_policyroute_remove_from_zebra(bgp
, path
, &bpf
, &bpof
);
2171 /* no action for add = true */
2172 for (i
= 0; i
< api
->action_num
; i
++) {
2173 switch (api
->actions
[i
].action
) {
2174 case ACTION_TRAFFICRATE
:
2176 if (api
->actions
[i
].u
.r
.rate
== 0) {
2177 nh
.vrf_id
= api
->vrf_id
;
2178 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2179 bgp_pbr_policyroute_add_to_zebra(
2180 bgp
, path
, &bpf
, &bpof
, &nh
, &rate
);
2182 /* update rate. can be reentrant */
2183 rate
= api
->actions
[i
].u
.r
.rate
;
2184 if (BGP_DEBUG(pbr
, PBR
)) {
2185 bgp_pbr_print_policy_route(api
);
2186 zlog_warn("PBR: ignoring Set action rate %f",
2187 api
->actions
[i
].u
.r
.rate
);
2191 case ACTION_TRAFFIC_ACTION
:
2192 if (api
->actions
[i
].u
.za
.filter
2193 & TRAFFIC_ACTION_SAMPLE
) {
2194 if (BGP_DEBUG(pbr
, PBR
)) {
2195 bgp_pbr_print_policy_route(api
);
2196 zlog_warn("PBR: Sample action Ignored");
2200 if (api
->actions
[i
].u
.za
.filter
2201 & TRAFFIC_ACTION_DISTRIBUTE
) {
2202 if (BGP_DEBUG(pbr
, PBR
)) {
2203 bgp_pbr_print_policy_route(api
);
2204 zlog_warn("PBR: Distribute action Applies");
2207 /* continue forwarding entry as before
2211 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2212 /* terminate action: run other filters
2215 case ACTION_REDIRECT_IP
:
2216 nh
.type
= NEXTHOP_TYPE_IPV4
;
2217 nh
.gate
.ipv4
.s_addr
=
2218 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2219 nh
.vrf_id
= api
->vrf_id
;
2220 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2222 /* XXX combination with REDIRECT_VRF
2223 * + REDIRECT_NH_IP not done
2227 case ACTION_REDIRECT
:
2228 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2229 nh
.type
= NEXTHOP_TYPE_IPV4
;
2230 bgp_pbr_policyroute_add_to_zebra(bgp
, path
, &bpf
, &bpof
,
2234 case ACTION_MARKING
:
2235 if (BGP_DEBUG(pbr
, PBR
)) {
2236 bgp_pbr_print_policy_route(api
);
2237 zlog_warn("PBR: Set DSCP %u Ignored",
2238 api
->actions
[i
].u
.marking_dscp
);
2244 if (continue_loop
== 0)
2249 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2250 struct bgp_path_info
*info
, afi_t afi
, safi_t safi
,
2253 struct bgp_pbr_entry_main api
;
2256 return; /* IPv6 not supported */
2257 if (safi
!= SAFI_FLOWSPEC
)
2258 return; /* not supported */
2259 /* Make Zebra API structure. */
2260 memset(&api
, 0, sizeof(api
));
2261 api
.vrf_id
= bgp
->vrf_id
;
2264 if (!bgp_zebra_tm_chunk_obtained()) {
2265 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2266 flog_err(EC_BGP_TABLE_CHUNK
,
2267 "%s: table chunk not obtained yet", __func__
);
2271 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2272 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2273 flog_err(EC_BGP_FLOWSPEC_INSTALLATION
,
2274 "%s: cancel updating entry %p in bgp pbr",
2278 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2281 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2282 const struct bgp_pbr_interface
*b
)
2284 return strcmp(a
->name
, b
->name
);
2287 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2288 struct bgp_pbr_interface_head
*head
)
2290 struct bgp_pbr_interface pbr_if
;
2292 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2293 return (RB_FIND(bgp_pbr_interface_head
,
2297 /* this function resets to the default policy routing
2298 * go back to default status
2300 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2302 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2303 struct bgp_pbr_interface_head
*head
;
2304 struct bgp_pbr_interface
*pbr_if
;
2306 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2308 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2310 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2311 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2312 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2313 XFREE(MTYPE_TMP
, pbr_if
);