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"
37 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry")
38 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match")
39 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action")
40 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context")
41 DEFINE_MTYPE_STATIC(BGPD
, PBR_VALMASK
, "BGP PBR Val Mask Value")
43 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
44 id_entry
, bgp_pbr_interface_compare
);
45 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
46 RB_INITIALIZER(&ifaces_by_name_ipv4
);
48 static int bgp_pbr_match_counter_unique
;
49 static int bgp_pbr_match_entry_counter_unique
;
50 static int bgp_pbr_action_counter_unique
;
51 static int bgp_pbr_match_iptable_counter_unique
;
53 struct bgp_pbr_match_iptable_unique
{
55 struct bgp_pbr_match
*bpm_found
;
58 struct bgp_pbr_match_entry_unique
{
60 struct bgp_pbr_match_entry
*bpme_found
;
63 struct bgp_pbr_action_unique
{
65 struct bgp_pbr_action
*bpa_found
;
68 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
70 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
71 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
73 uint32_t unique
= bpau
->unique
;
75 if (bpa
->unique
== unique
) {
76 bpau
->bpa_found
= bpa
;
77 return HASHWALK_ABORT
;
79 return HASHWALK_CONTINUE
;
82 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
84 struct bgp_pbr_match_entry
*bpme
=
85 (struct bgp_pbr_match_entry
*)backet
->data
;
86 struct bgp_pbr_match_entry_unique
*bpmeu
=
87 (struct bgp_pbr_match_entry_unique
*)arg
;
88 uint32_t unique
= bpmeu
->unique
;
90 if (bpme
->unique
== unique
) {
91 bpmeu
->bpme_found
= bpme
;
92 return HASHWALK_ABORT
;
94 return HASHWALK_CONTINUE
;
97 struct bgp_pbr_match_ipsetname
{
99 struct bgp_pbr_match
*bpm_found
;
102 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
104 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
105 struct bgp_pbr_match_ipsetname
*bpmi
=
106 (struct bgp_pbr_match_ipsetname
*)arg
;
107 char *ipset_name
= bpmi
->ipsetname
;
109 if (!strncmp(ipset_name
, bpm
->ipset_name
,
110 ZEBRA_IPSET_NAME_SIZE
)) {
111 bpmi
->bpm_found
= bpm
;
112 return HASHWALK_ABORT
;
114 return HASHWALK_CONTINUE
;
117 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
119 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
120 struct bgp_pbr_match_iptable_unique
*bpmiu
=
121 (struct bgp_pbr_match_iptable_unique
*)arg
;
122 uint32_t unique
= bpmiu
->unique
;
124 if (bpm
->unique2
== unique
) {
125 bpmiu
->bpm_found
= bpm
;
126 return HASHWALK_ABORT
;
128 return HASHWALK_CONTINUE
;
131 struct bgp_pbr_match_unique
{
133 struct bgp_pbr_match
*bpm_found
;
136 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
138 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
139 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
141 uint32_t unique
= bpmu
->unique
;
143 if (bpm
->unique
== unique
) {
144 bpmu
->bpm_found
= bpm
;
145 return HASHWALK_ABORT
;
147 return HASHWALK_CONTINUE
;
150 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
156 ptr
+= sprintf(ptr
, "%s", prepend
);
158 if (mval
->unary_operator
& OPERATOR_UNARY_OR
)
159 ptr
+= sprintf(ptr
, ", or ");
160 if (mval
->unary_operator
& OPERATOR_UNARY_AND
)
161 ptr
+= sprintf(ptr
, ", and ");
163 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
)
164 ptr
+= sprintf(ptr
, "<");
165 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
)
166 ptr
+= sprintf(ptr
, ">");
167 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
)
168 ptr
+= sprintf(ptr
, "=");
169 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
)
170 ptr
+= sprintf(ptr
, "match");
171 ptr
+= sprintf(ptr
, " %u", mval
->value
);
172 return (int)(ptr
- str
);
175 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
177 (_ptr) += sprintf((_ptr), "; "); \
181 /* this structure can be used for port range,
182 * but also for other values range like packet length range
184 struct bgp_pbr_range_port
{
189 /* this structure can be used to filter with a mask
190 * for instance it supports not instructions like for
193 struct bgp_pbr_val_mask
{
198 /* this structure is used to pass instructs
199 * so that BGP can create pbr instructions to ZEBRA
201 struct bgp_pbr_filter
{
206 struct bgp_pbr_range_port
*pkt_len
;
207 struct bgp_pbr_range_port
*src_port
;
208 struct bgp_pbr_range_port
*dst_port
;
209 struct bgp_pbr_val_mask
*tcp_flags
;
210 struct bgp_pbr_val_mask
*dscp
;
211 struct bgp_pbr_val_mask
*pkt_len_val
;
212 struct bgp_pbr_val_mask
*fragment
;
215 /* this structure is used to contain OR instructions
216 * so that BGP can create multiple pbr instructions
219 struct bgp_pbr_or_filter
{
220 struct list
*tcpflags
;
222 struct list
*pkt_len
;
223 struct list
*fragment
;
224 struct list
*icmp_type
;
225 struct list
*icmp_code
;
228 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
229 struct bgp_info
*binfo
,
230 struct bgp_pbr_filter
*bpf
,
234 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
);
236 static bool bgp_pbr_extract_enumerate_unary_opposite(
237 uint8_t unary_operator
,
238 struct bgp_pbr_val_mask
*and_valmask
,
239 struct list
*or_valmask
, uint32_t value
,
242 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
243 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
245 TCP_HEADER_ALL_FLAGS
&
247 } else if (type_entry
== FLOWSPEC_DSCP
||
248 type_entry
== FLOWSPEC_PKT_LEN
||
249 type_entry
== FLOWSPEC_FRAGMENT
) {
250 and_valmask
->val
= value
;
251 and_valmask
->mask
= 1; /* inverse */
253 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
254 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
255 sizeof(struct bgp_pbr_val_mask
));
256 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
257 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
259 TCP_HEADER_ALL_FLAGS
&
261 } else if (type_entry
== FLOWSPEC_DSCP
||
262 type_entry
== FLOWSPEC_FRAGMENT
||
263 type_entry
== FLOWSPEC_PKT_LEN
) {
264 and_valmask
->val
= value
;
265 and_valmask
->mask
= 1; /* inverse */
267 listnode_add(or_valmask
, and_valmask
);
268 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
269 type_entry
== FLOWSPEC_ICMP_TYPE
)
274 /* TCP : FIN and SYN -> val = ALL; mask = 3
275 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
276 * other variables type: dscp, pkt len, fragment
277 * - value is copied in bgp_pbr_val_mask->val value
278 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
280 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
281 int num
, uint8_t unary_operator
,
282 void *valmask
, uint8_t type_entry
)
285 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
286 struct list
*or_valmask
= NULL
;
290 if (unary_operator
== OPERATOR_UNARY_AND
) {
291 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
292 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
293 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
294 or_valmask
= (struct list
*)valmask
;
297 for (i
= 0; i
< num
; i
++) {
298 if (i
!= 0 && list
[i
].unary_operator
!=
301 if (!(list
[i
].compare_operator
&
302 OPERATOR_COMPARE_EQUAL_TO
) &&
303 !(list
[i
].compare_operator
&
304 OPERATOR_COMPARE_EXACT_MATCH
)) {
305 if ((list
[i
].compare_operator
&
306 OPERATOR_COMPARE_LESS_THAN
) &&
307 (list
[i
].compare_operator
&
308 OPERATOR_COMPARE_GREATER_THAN
)) {
309 ret
= bgp_pbr_extract_enumerate_unary_opposite(
310 unary_operator
, and_valmask
,
311 or_valmask
, list
[i
].value
,
319 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
320 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
322 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
323 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
324 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
325 sizeof(struct bgp_pbr_val_mask
));
326 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
327 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
329 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
330 } else if (type_entry
== FLOWSPEC_DSCP
||
331 type_entry
== FLOWSPEC_ICMP_TYPE
||
332 type_entry
== FLOWSPEC_ICMP_CODE
||
333 type_entry
== FLOWSPEC_FRAGMENT
||
334 type_entry
== FLOWSPEC_PKT_LEN
)
335 and_valmask
->val
= list
[i
].value
;
336 listnode_add(or_valmask
, and_valmask
);
339 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
340 && type_entry
== FLOWSPEC_TCP_FLAGS
)
341 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
345 /* if unary operator can either be UNARY_OR/AND/OR-AND.
346 * in the latter case, combinationf of both is not handled
348 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
349 int num
, uint8_t unary_operator
,
350 void *valmask
, uint8_t type_entry
)
353 uint8_t unary_operator_val
;
354 bool double_check
= false;
356 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
357 (unary_operator
& OPERATOR_UNARY_AND
)) {
358 unary_operator_val
= OPERATOR_UNARY_AND
;
361 unary_operator_val
= unary_operator
;
362 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
363 valmask
, type_entry
);
364 if (!ret
&& double_check
)
365 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
372 /* returns the unary operator that is in the list
373 * return 0 if both operators are used
375 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
380 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
382 for (i
= 0; i
< num
; i
++) {
385 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
386 unary_operator
= OPERATOR_UNARY_OR
;
387 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
388 && unary_operator
== OPERATOR_UNARY_OR
) ||
389 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
390 && unary_operator
== OPERATOR_UNARY_AND
))
393 return unary_operator
;
397 /* return true if extraction ok
399 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
401 struct bgp_pbr_range_port
*range
)
404 bool exact_match
= false;
407 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
411 for (i
= 0; i
< num
; i
++) {
412 if (i
!= 0 && (list
[i
].compare_operator
==
413 OPERATOR_COMPARE_EQUAL_TO
))
415 if (i
== 0 && (list
[i
].compare_operator
==
416 OPERATOR_COMPARE_EQUAL_TO
)) {
418 range
->min_port
= list
[i
].value
;
421 if (exact_match
== true && i
> 0)
423 if (list
[i
].compare_operator
==
424 (OPERATOR_COMPARE_GREATER_THAN
+
425 OPERATOR_COMPARE_EQUAL_TO
)) {
427 range
->min_port
= list
[i
].value
;
428 } else if (list
[i
].compare_operator
==
429 (OPERATOR_COMPARE_LESS_THAN
+
430 OPERATOR_COMPARE_EQUAL_TO
)) {
432 range
->max_port
= list
[i
].value
;
433 } else if (list
[i
].compare_operator
==
434 OPERATOR_COMPARE_LESS_THAN
) {
436 range
->max_port
= list
[i
].value
- 1;
437 } else if (list
[i
].compare_operator
==
438 OPERATOR_COMPARE_GREATER_THAN
) {
440 range
->min_port
= list
[i
].value
+ 1;
446 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
448 bool enumerate_icmp
= false;
450 /* because bgp pbr entry may contain unsupported
451 * combinations, a message will be displayed here if
453 * for now, only match/set supported is
454 * - combination src/dst => redirect nexthop [ + rate]
455 * - combination src/dst => redirect VRF [ + rate]
456 * - combination src/dst => drop
457 * - combination srcport + @IP
459 if (api
->match_protocol_num
> 1) {
460 if (BGP_DEBUG(pbr
, PBR
))
461 zlog_debug("BGP: match protocol operations:"
462 "multiple protocols ( %d). ignoring.",
463 api
->match_protocol_num
);
466 if (api
->match_protocol_num
== 1 &&
467 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
468 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
469 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
470 if (BGP_DEBUG(pbr
, PBR
))
471 zlog_debug("BGP: match protocol operations:"
472 "protocol (%d) not supported. ignoring",
473 api
->match_protocol_num
);
476 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
477 if (BGP_DEBUG(pbr
, PBR
))
478 zlog_debug("BGP: match src port operations:"
479 "too complex. ignoring.");
482 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
483 if (BGP_DEBUG(pbr
, PBR
))
484 zlog_debug("BGP: match dst port operations:"
485 "too complex. ignoring.");
488 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
489 api
->match_tcpflags_num
,
491 OPERATOR_UNARY_OR
, NULL
,
492 FLOWSPEC_TCP_FLAGS
)) {
493 if (BGP_DEBUG(pbr
, PBR
))
494 zlog_debug("BGP: match tcp flags:"
495 "too complex. ignoring.");
498 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
499 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
500 api
->match_icmp_type_num
,
501 OPERATOR_UNARY_OR
, NULL
,
502 FLOWSPEC_ICMP_TYPE
)) {
503 if (BGP_DEBUG(pbr
, PBR
))
504 zlog_debug("BGP: match icmp type operations:"
505 "too complex. ignoring.");
508 enumerate_icmp
= true;
510 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
511 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
512 api
->match_icmp_code_num
,
513 OPERATOR_UNARY_OR
, NULL
,
514 FLOWSPEC_ICMP_CODE
)) {
515 if (BGP_DEBUG(pbr
, PBR
))
516 zlog_debug("BGP: match icmp code operations:"
517 "too complex. ignoring.");
519 } else if (api
->match_icmp_type_num
> 1 &&
520 enumerate_icmp
== false) {
521 if (BGP_DEBUG(pbr
, PBR
))
522 zlog_debug("BGP: match icmp code is enumerate"
523 ", and icmp type is not."
524 " too complex. ignoring.");
528 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
529 if (BGP_DEBUG(pbr
, PBR
))
530 zlog_debug("BGP: match port operations:"
531 "too complex. ignoring.");
534 if (api
->match_packet_length_num
) {
537 ret
= bgp_pbr_extract(api
->packet_length
,
538 api
->match_packet_length_num
, NULL
);
540 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
541 api
->match_packet_length_num
,
543 | OPERATOR_UNARY_AND
,
544 NULL
, FLOWSPEC_PKT_LEN
);
546 if (BGP_DEBUG(pbr
, PBR
))
547 zlog_debug("BGP: match packet length operations:"
548 "too complex. ignoring.");
552 if (api
->match_dscp_num
) {
553 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
554 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
555 NULL
, FLOWSPEC_DSCP
)) {
556 if (BGP_DEBUG(pbr
, PBR
))
557 zlog_debug("BGP: match DSCP operations:"
558 "too complex. ignoring.");
562 if (api
->match_fragment_num
) {
566 success
= bgp_pbr_extract_enumerate(api
->fragment
,
567 api
->match_fragment_num
,
569 | OPERATOR_UNARY_AND
,
570 NULL
, FLOWSPEC_FRAGMENT
);
574 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
575 if (api
->fragment
[i
].value
!= 1 &&
576 api
->fragment
[i
].value
!= 2 &&
577 api
->fragment
[i
].value
!= 4 &&
578 api
->fragment
[i
].value
!= 8) {
581 "Value not valid (%d) for this implementation",
582 api
->fragment
[i
].value
);
586 sprintf(fail_str
, "too complex. ignoring");
588 if (BGP_DEBUG(pbr
, PBR
))
589 zlog_debug("BGP: match fragment operation (%d) %s",
590 api
->match_fragment_num
,
596 /* no combinations with both src_port and dst_port
597 * or port with src_port and dst_port
599 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
600 api
->match_port_num
> 3) {
601 if (BGP_DEBUG(pbr
, PBR
))
602 zlog_debug("BGP: match multiple port operations:"
603 " too complex. ignoring.");
606 if ((api
->match_src_port_num
|| api
->match_dst_port_num
607 || api
->match_port_num
) && (api
->match_icmp_type_num
608 || api
->match_icmp_code_num
)) {
609 if (BGP_DEBUG(pbr
, PBR
))
610 zlog_debug("BGP: match multiple port/imcp operations:"
611 " too complex. ignoring.");
614 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
615 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
616 if (BGP_DEBUG(pbr
, PBR
)) {
617 bgp_pbr_print_policy_route(api
);
618 zlog_debug("BGP: match actions without src"
619 " or dst address can not operate."
627 /* return -1 if build or validation failed */
628 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
629 struct bgp_info
*info
,
630 struct bgp_pbr_entry_main
*api
)
633 int i
, action_count
= 0;
634 struct ecommunity
*ecom
;
635 struct ecommunity_val
*ecom_eval
;
636 struct bgp_pbr_entry_action
*api_action
;
637 struct prefix
*src
= NULL
, *dst
= NULL
;
638 int valid_prefix
= 0;
641 /* extract match from flowspec entries */
642 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
643 p
->u
.prefix_flowspec
.prefixlen
, api
);
646 /* extract actiosn from flowspec ecom list */
647 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
648 ecom
= info
->attr
->ecommunity
;
649 for (i
= 0; i
< ecom
->size
; i
++) {
650 ecom_eval
= (struct ecommunity_val
*)
651 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
653 if (action_count
> ACTIONS_MAX_NUM
) {
654 if (BGP_DEBUG(pbr
, PBR_ERROR
))
655 zlog_err("%s: flowspec actions exceeds limit (max %u)",
656 __func__
, action_count
);
659 api_action
= &api
->actions
[action_count
- 1];
661 if ((ecom_eval
->val
[1] ==
662 (char)ECOMMUNITY_REDIRECT_VRF
) &&
663 (ecom_eval
->val
[0] ==
664 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
666 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
668 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
669 struct ecommunity
*eckey
= ecommunity_new();
670 struct ecommunity_val ecom_copy
;
672 memcpy(&ecom_copy
, ecom_eval
,
673 sizeof(struct ecommunity_val
));
675 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
676 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
677 ecommunity_add_val(eckey
, &ecom_copy
);
679 api_action
->action
= ACTION_REDIRECT
;
680 api_action
->u
.redirect_vrf
=
681 get_first_vrf_for_redirect_with_rt(
683 ecommunity_free(&eckey
);
684 } else if ((ecom_eval
->val
[0] ==
685 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
686 (ecom_eval
->val
[1] ==
687 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
688 api_action
->action
= ACTION_REDIRECT_IP
;
689 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
690 info
->attr
->nexthop
.s_addr
;
691 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
693 if (ecom_eval
->val
[0] !=
694 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
696 ret
= ecommunity_fill_pbr_action(ecom_eval
,
705 /* validate if incoming matc/action is compatible
706 * with our policy routing engine
708 if (!bgp_pbr_validate_policy_route(api
))
711 /* check inconsistency in the match rule */
712 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
713 src
= &api
->src_prefix
;
714 afi
= family2afi(src
->family
);
717 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
718 dst
= &api
->dst_prefix
;
719 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
720 if (BGP_DEBUG(pbr
, PBR
)) {
721 bgp_pbr_print_policy_route(api
);
722 zlog_debug("%s: inconsistency:"
723 " no match for afi src and dst (%u/%u)",
724 __func__
, afi
, family2afi(dst
->family
));
732 static void bgp_pbr_match_entry_free(void *arg
)
734 struct bgp_pbr_match_entry
*bpme
;
736 bpme
= (struct bgp_pbr_match_entry
*)arg
;
738 if (bpme
->installed
) {
739 bgp_send_pbr_ipset_entry_match(bpme
, false);
740 bpme
->installed
= false;
741 bpme
->backpointer
= NULL
;
743 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
746 static void bgp_pbr_match_free(void *arg
)
748 struct bgp_pbr_match
*bpm
;
750 bpm
= (struct bgp_pbr_match
*)arg
;
752 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
754 if (hashcount(bpm
->entry_hash
) == 0) {
755 /* delete iptable entry first */
756 /* then delete ipset match */
757 if (bpm
->installed
) {
758 if (bpm
->installed_in_iptable
) {
759 bgp_send_pbr_iptable(bpm
->action
,
761 bpm
->installed_in_iptable
= false;
762 bpm
->action
->refcnt
--;
764 bgp_send_pbr_ipset_match(bpm
, false);
765 bpm
->installed
= false;
769 hash_free(bpm
->entry_hash
);
771 XFREE(MTYPE_PBR_MATCH
, bpm
);
774 static void *bgp_pbr_match_alloc_intern(void *arg
)
776 struct bgp_pbr_match
*bpm
, *new;
778 bpm
= (struct bgp_pbr_match
*)arg
;
780 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
781 memcpy(new, bpm
, sizeof(*bpm
));
786 static void bgp_pbr_action_free(void *arg
)
788 struct bgp_pbr_action
*bpa
;
790 bpa
= (struct bgp_pbr_action
*)arg
;
792 if (bpa
->refcnt
== 0) {
793 if (bpa
->installed
&& bpa
->table_id
!= 0) {
794 bgp_send_pbr_rule_action(bpa
, false);
795 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
799 bpa
->installed
= false;
802 XFREE(MTYPE_PBR_ACTION
, bpa
);
805 static void *bgp_pbr_action_alloc_intern(void *arg
)
807 struct bgp_pbr_action
*bpa
, *new;
809 bpa
= (struct bgp_pbr_action
*)arg
;
811 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
813 memcpy(new, bpa
, sizeof(*bpa
));
818 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
820 struct bgp_pbr_match_entry
*bpme
, *new;
822 bpme
= (struct bgp_pbr_match_entry
*)arg
;
824 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
826 memcpy(new, bpme
, sizeof(*bpme
));
831 uint32_t bgp_pbr_match_hash_key(void *arg
)
833 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
836 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
837 key
= jhash_1word(pbm
->flags
, key
);
838 key
= jhash(&pbm
->pkt_len_min
, 2, key
);
839 key
= jhash(&pbm
->pkt_len_max
, 2, key
);
840 key
= jhash(&pbm
->tcp_flags
, 2, key
);
841 key
= jhash(&pbm
->tcp_mask_flags
, 2, key
);
842 key
= jhash(&pbm
->dscp_value
, 1, key
);
843 key
= jhash(&pbm
->fragment
, 1, key
);
844 return jhash_1word(pbm
->type
, key
);
847 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
849 const struct bgp_pbr_match
*r1
, *r2
;
851 r1
= (const struct bgp_pbr_match
*)arg1
;
852 r2
= (const struct bgp_pbr_match
*)arg2
;
854 if (r1
->vrf_id
!= r2
->vrf_id
)
857 if (r1
->type
!= r2
->type
)
860 if (r1
->flags
!= r2
->flags
)
863 if (r1
->action
!= r2
->action
)
866 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
869 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
872 if (r1
->tcp_flags
!= r2
->tcp_flags
)
875 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
878 if (r1
->dscp_value
!= r2
->dscp_value
)
881 if (r1
->fragment
!= r2
->fragment
)
886 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
888 struct bgp_pbr_match_entry
*pbme
;
891 pbme
= (struct bgp_pbr_match_entry
*)arg
;
892 key
= prefix_hash_key(&pbme
->src
);
893 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
894 key
= jhash(&pbme
->dst_port_min
, 2, key
);
895 key
= jhash(&pbme
->src_port_min
, 2, key
);
896 key
= jhash(&pbme
->dst_port_max
, 2, key
);
897 key
= jhash(&pbme
->src_port_max
, 2, key
);
898 key
= jhash(&pbme
->proto
, 1, key
);
903 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
905 const struct bgp_pbr_match_entry
*r1
, *r2
;
907 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
908 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
910 /* on updates, comparing
911 * backpointer is not necessary
914 /* unique value is self calculated
917 /* rate is ignored for now
920 if (!prefix_same(&r1
->src
, &r2
->src
))
923 if (!prefix_same(&r1
->dst
, &r2
->dst
))
926 if (r1
->src_port_min
!= r2
->src_port_min
)
929 if (r1
->dst_port_min
!= r2
->dst_port_min
)
932 if (r1
->src_port_max
!= r2
->src_port_max
)
935 if (r1
->dst_port_max
!= r2
->dst_port_max
)
938 if (r1
->proto
!= r2
->proto
)
944 uint32_t bgp_pbr_action_hash_key(void *arg
)
946 struct bgp_pbr_action
*pbra
;
949 pbra
= (struct bgp_pbr_action
*)arg
;
950 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
951 key
= jhash_1word(pbra
->fwmark
, key
);
955 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
957 const struct bgp_pbr_action
*r1
, *r2
;
959 r1
= (const struct bgp_pbr_action
*)arg1
;
960 r2
= (const struct bgp_pbr_action
*)arg2
;
962 /* unique value is self calculated
963 * table and fwmark is self calculated
966 if (r1
->vrf_id
!= r2
->vrf_id
)
969 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
974 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
977 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
978 struct bgp_pbr_action_unique bpau
;
980 if (!bgp
|| unique
== 0)
982 bpau
.unique
= unique
;
983 bpau
.bpa_found
= NULL
;
984 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
985 return bpau
.bpa_found
;
988 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
991 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
992 struct bgp_pbr_match_unique bpmu
;
994 if (!bgp
|| unique
== 0)
996 bpmu
.unique
= unique
;
997 bpmu
.bpm_found
= NULL
;
998 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
999 return bpmu
.bpm_found
;
1002 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1006 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1007 struct bgp_pbr_match_entry_unique bpmeu
;
1008 struct bgp_pbr_match_ipsetname bpmi
;
1010 if (!bgp
|| unique
== 0)
1012 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1013 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1014 bpmi
.bpm_found
= NULL
;
1015 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1016 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1017 if (!bpmi
.bpm_found
)
1019 bpmeu
.bpme_found
= NULL
;
1020 bpmeu
.unique
= unique
;
1021 hash_walk(bpmi
.bpm_found
->entry_hash
,
1022 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1023 return bpmeu
.bpme_found
;
1026 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1029 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1030 struct bgp_pbr_match_iptable_unique bpmiu
;
1032 if (!bgp
|| unique
== 0)
1034 bpmiu
.unique
= unique
;
1035 bpmiu
.bpm_found
= NULL
;
1036 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1037 return bpmiu
.bpm_found
;
1040 void bgp_pbr_cleanup(struct bgp
*bgp
)
1042 if (bgp
->pbr_match_hash
) {
1043 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1044 hash_free(bgp
->pbr_match_hash
);
1045 bgp
->pbr_match_hash
= NULL
;
1047 if (bgp
->pbr_action_hash
) {
1048 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1049 hash_free(bgp
->pbr_action_hash
);
1050 bgp
->pbr_action_hash
= NULL
;
1052 if (bgp
->bgp_pbr_cfg
== NULL
)
1054 bgp_pbr_reset(bgp
, AFI_IP
);
1055 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1056 bgp
->bgp_pbr_cfg
= NULL
;
1059 void bgp_pbr_init(struct bgp
*bgp
)
1061 bgp
->pbr_match_hash
=
1062 hash_create_size(8, bgp_pbr_match_hash_key
,
1063 bgp_pbr_match_hash_equal
,
1065 bgp
->pbr_action_hash
=
1066 hash_create_size(8, bgp_pbr_action_hash_key
,
1067 bgp_pbr_action_hash_equal
,
1068 "Match Hash Entry");
1070 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1071 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1074 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1077 char return_string
[512];
1078 char *ptr
= return_string
;
1082 ptr
+= sprintf(ptr
, "MATCH : ");
1083 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1084 struct prefix
*p
= &(api
->src_prefix
);
1086 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1087 INCREMENT_DISPLAY(ptr
, nb_items
);
1089 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1090 struct prefix
*p
= &(api
->dst_prefix
);
1092 INCREMENT_DISPLAY(ptr
, nb_items
);
1093 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1096 if (api
->match_protocol_num
)
1097 INCREMENT_DISPLAY(ptr
, nb_items
);
1098 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1099 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1100 i
> 0 ? NULL
: "@proto ");
1102 if (api
->match_src_port_num
)
1103 INCREMENT_DISPLAY(ptr
, nb_items
);
1104 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1105 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1106 i
> 0 ? NULL
: "@srcport ");
1108 if (api
->match_dst_port_num
)
1109 INCREMENT_DISPLAY(ptr
, nb_items
);
1110 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1111 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1112 i
> 0 ? NULL
: "@dstport ");
1114 if (api
->match_port_num
)
1115 INCREMENT_DISPLAY(ptr
, nb_items
);
1116 for (i
= 0; i
< api
->match_port_num
; i
++)
1117 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1118 i
> 0 ? NULL
: "@port ");
1120 if (api
->match_icmp_type_num
)
1121 INCREMENT_DISPLAY(ptr
, nb_items
);
1122 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1123 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1124 i
> 0 ? NULL
: "@icmptype ");
1126 if (api
->match_icmp_code_num
)
1127 INCREMENT_DISPLAY(ptr
, nb_items
);
1128 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1129 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1130 i
> 0 ? NULL
: "@icmpcode ");
1132 if (api
->match_packet_length_num
)
1133 INCREMENT_DISPLAY(ptr
, nb_items
);
1134 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1135 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1136 i
> 0 ? NULL
: "@plen ");
1138 if (api
->match_dscp_num
)
1139 INCREMENT_DISPLAY(ptr
, nb_items
);
1140 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1141 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1142 i
> 0 ? NULL
: "@dscp ");
1144 if (api
->match_tcpflags_num
)
1145 INCREMENT_DISPLAY(ptr
, nb_items
);
1146 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1147 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1148 i
> 0 ? NULL
: "@tcpflags ");
1150 if (api
->match_fragment_num
)
1151 INCREMENT_DISPLAY(ptr
, nb_items
);
1152 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1153 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1154 i
> 0 ? NULL
: "@fragment ");
1156 ptr
= return_string
;
1158 ptr
+= sprintf(ptr
, "; ");
1159 if (api
->action_num
)
1160 ptr
+= sprintf(ptr
, "SET : ");
1162 for (i
= 0; i
< api
->action_num
; i
++) {
1163 switch (api
->actions
[i
].action
) {
1164 case ACTION_TRAFFICRATE
:
1165 INCREMENT_DISPLAY(ptr
, nb_items
);
1166 ptr
+= sprintf(ptr
, "@set rate %f",
1167 api
->actions
[i
].u
.r
.rate
);
1169 case ACTION_TRAFFIC_ACTION
:
1170 INCREMENT_DISPLAY(ptr
, nb_items
);
1171 ptr
+= sprintf(ptr
, "@action ");
1172 if (api
->actions
[i
].u
.za
.filter
1173 & TRAFFIC_ACTION_TERMINATE
)
1175 " terminate (apply filter(s))");
1176 if (api
->actions
[i
].u
.za
.filter
1177 & TRAFFIC_ACTION_DISTRIBUTE
)
1178 ptr
+= sprintf(ptr
, " distribute");
1179 if (api
->actions
[i
].u
.za
.filter
1180 & TRAFFIC_ACTION_SAMPLE
)
1181 ptr
+= sprintf(ptr
, " sample");
1183 case ACTION_REDIRECT_IP
:
1184 INCREMENT_DISPLAY(ptr
, nb_items
);
1185 char local_buff
[INET_ADDRSTRLEN
];
1187 if (inet_ntop(AF_INET
,
1188 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1189 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1191 "@redirect ip nh %s", local_buff
);
1193 case ACTION_REDIRECT
:
1194 INCREMENT_DISPLAY(ptr
, nb_items
);
1195 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1196 api
->actions
[i
].u
.redirect_vrf
);
1198 case ACTION_MARKING
:
1199 INCREMENT_DISPLAY(ptr
, nb_items
);
1200 ptr
+= sprintf(ptr
, "@set dscp %u",
1201 api
->actions
[i
].u
.marking_dscp
);
1207 zlog_info("%s", return_string
);
1210 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1211 struct bgp_pbr_match
*bpm
,
1212 struct bgp_pbr_match_entry
*bpme
)
1214 /* if bpme is null, bpm is also null
1218 /* ipset del entry */
1219 if (bpme
->installed
) {
1220 bgp_send_pbr_ipset_entry_match(bpme
, false);
1221 bpme
->installed
= false;
1222 bpme
->backpointer
= NULL
;
1223 if (bpme
->bgp_info
) {
1224 struct bgp_info
*bgp_info
;
1225 struct bgp_info_extra
*extra
;
1227 /* unlink bgp_info to bpme */
1228 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
1229 extra
= bgp_info_extra_get(bgp_info
);
1230 if (extra
->bgp_fs_pbr
)
1231 listnode_delete(extra
->bgp_fs_pbr
, bpme
);
1232 bpme
->bgp_info
= NULL
;
1235 hash_release(bpm
->entry_hash
, bpme
);
1236 if (hashcount(bpm
->entry_hash
) == 0) {
1237 /* delete iptable entry first */
1238 /* then delete ipset match */
1239 if (bpm
->installed
) {
1240 if (bpm
->installed_in_iptable
) {
1241 bgp_send_pbr_iptable(bpm
->action
,
1243 bpm
->installed_in_iptable
= false;
1244 bpm
->action
->refcnt
--;
1246 bgp_send_pbr_ipset_match(bpm
, false);
1247 bpm
->installed
= false;
1250 hash_release(bgp
->pbr_match_hash
, bpm
);
1251 /* XXX release pbr_match_action if not used
1252 * note that drop does not need to call send_pbr_action
1255 if (bpa
->refcnt
== 0) {
1256 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1257 bgp_send_pbr_rule_action(bpa
, false);
1258 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1262 bpa
->installed
= false;
1267 struct bgp_pbr_match_entry_remain
{
1268 struct bgp_pbr_match_entry
*bpme_to_match
;
1269 struct bgp_pbr_match_entry
*bpme_found
;
1272 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1274 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1275 struct bgp_pbr_match_entry_remain
*bpmer
=
1276 (struct bgp_pbr_match_entry_remain
*)arg
;
1277 struct bgp_pbr_match
*bpm_temp
;
1278 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1280 if (!bpme
->backpointer
||
1281 bpm
== bpme
->backpointer
||
1282 bpme
->backpointer
->action
== bpm
->action
)
1283 return HASHWALK_CONTINUE
;
1284 /* ensure bpm other characteristics are equal */
1285 bpm_temp
= bpme
->backpointer
;
1286 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1287 bpm_temp
->type
!= bpm
->type
||
1288 bpm_temp
->flags
!= bpm
->flags
||
1289 bpm_temp
->tcp_flags
!= bpm
->tcp_flags
||
1290 bpm_temp
->tcp_mask_flags
!= bpm
->tcp_mask_flags
||
1291 bpm_temp
->pkt_len_min
!= bpm
->pkt_len_min
||
1292 bpm_temp
->pkt_len_max
!= bpm
->pkt_len_max
||
1293 bpm_temp
->dscp_value
!= bpm
->dscp_value
||
1294 bpm_temp
->fragment
!= bpm
->fragment
)
1295 return HASHWALK_CONTINUE
;
1297 /* look for remaining bpme */
1298 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1299 if (!bpmer
->bpme_found
)
1300 return HASHWALK_CONTINUE
;
1301 return HASHWALK_ABORT
;
1304 static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp
*bgp
,
1305 struct bgp_info
*binfo
,
1306 struct bgp_pbr_filter
*bpf
)
1308 struct bgp_pbr_match temp
;
1309 struct bgp_pbr_match_entry temp2
;
1310 struct bgp_pbr_match
*bpm
;
1311 struct bgp_pbr_match_entry
*bpme
;
1312 struct bgp_pbr_match_entry_remain bpmer
;
1313 struct bgp_pbr_range_port
*src_port
;
1314 struct bgp_pbr_range_port
*dst_port
;
1315 struct bgp_pbr_range_port
*pkt_len
;
1319 src_port
= bpf
->src_port
;
1320 dst_port
= bpf
->dst_port
;
1321 pkt_len
= bpf
->pkt_len
;
1323 if (BGP_DEBUG(zebra
, ZEBRA
))
1324 bgp_pbr_dump_entry(bpf
, false);
1326 /* as we don't know information from EC
1327 * look for bpm that have the bpm
1328 * with vrf_id characteristics
1330 memset(&temp2
, 0, sizeof(temp2
));
1331 memset(&temp
, 0, sizeof(temp
));
1333 temp
.flags
|= MATCH_IP_SRC_SET
;
1334 prefix_copy(&temp2
.src
, bpf
->src
);
1336 temp2
.src
.family
= AF_INET
;
1338 temp
.flags
|= MATCH_IP_DST_SET
;
1339 prefix_copy(&temp2
.dst
, bpf
->dst
);
1341 temp2
.dst
.family
= AF_INET
;
1342 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1343 if (bpf
->protocol
== IPPROTO_ICMP
)
1344 temp
.flags
|= MATCH_ICMP_SET
;
1345 temp
.flags
|= MATCH_PORT_SRC_SET
;
1346 temp2
.src_port_min
= src_port
->min_port
;
1347 if (src_port
->max_port
) {
1348 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1349 temp2
.src_port_max
= src_port
->max_port
;
1352 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1353 if (bpf
->protocol
== IPPROTO_ICMP
)
1354 temp
.flags
|= MATCH_ICMP_SET
;
1355 temp
.flags
|= MATCH_PORT_DST_SET
;
1356 temp2
.dst_port_min
= dst_port
->min_port
;
1357 if (dst_port
->max_port
) {
1358 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1359 temp2
.dst_port_max
= dst_port
->max_port
;
1362 temp2
.proto
= bpf
->protocol
;
1365 temp
.pkt_len_min
= pkt_len
->min_port
;
1366 if (pkt_len
->max_port
)
1367 temp
.pkt_len_max
= pkt_len
->max_port
;
1368 } else if (bpf
->pkt_len_val
) {
1369 if (bpf
->pkt_len_val
->mask
)
1370 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1371 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1373 if (bpf
->tcp_flags
) {
1374 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1375 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1378 if (bpf
->dscp
->mask
)
1379 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1381 temp
.flags
|= MATCH_DSCP_SET
;
1382 temp
.dscp_value
= bpf
->dscp
->val
;
1384 if (bpf
->fragment
) {
1385 if (bpf
->fragment
->mask
)
1386 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1387 temp
.fragment
= bpf
->fragment
->val
;
1390 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1391 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1392 temp
.type
= IPSET_NET_PORT
;
1394 temp
.type
= IPSET_NET
;
1396 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1397 temp
.type
= IPSET_NET_PORT_NET
;
1399 temp
.type
= IPSET_NET_NET
;
1401 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1404 temp
.vrf_id
= bpf
->vrf_id
;
1407 bpme
->backpointer
= bpm
;
1408 /* right now, a previous entry may already exist
1409 * flush previous entry if necessary
1411 bpmer
.bpme_to_match
= bpme
;
1412 bpmer
.bpme_found
= NULL
;
1413 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1414 if (bpmer
.bpme_found
) {
1415 static struct bgp_pbr_match
*local_bpm
;
1416 static struct bgp_pbr_action
*local_bpa
;
1418 local_bpm
= bpmer
.bpme_found
->backpointer
;
1419 local_bpa
= local_bpm
->action
;
1420 bgp_pbr_flush_entry(bgp
, local_bpa
,
1421 local_bpm
, bpmer
.bpme_found
);
1425 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1427 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1428 return FLOWSPEC_DSCP
;
1429 if (type_entry
== FLOWSPEC_DSCP
)
1430 return FLOWSPEC_PKT_LEN
;
1431 if (type_entry
== FLOWSPEC_PKT_LEN
)
1432 return FLOWSPEC_FRAGMENT
;
1433 if (type_entry
== FLOWSPEC_FRAGMENT
)
1434 return FLOWSPEC_ICMP_TYPE
;
1438 static void bgp_pbr_icmp_action(struct bgp
*bgp
,
1439 struct bgp_info
*binfo
,
1440 struct bgp_pbr_filter
*bpf
,
1441 struct bgp_pbr_or_filter
*bpof
,
1446 struct bgp_pbr_range_port srcp
, dstp
;
1447 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1448 struct listnode
*tnode
, *cnode
;
1452 if (bpf
->protocol
!= IPPROTO_ICMP
)
1454 bpf
->src_port
= &srcp
;
1455 bpf
->dst_port
= &dstp
;
1456 /* parse icmp type and lookup appropriate icmp code
1457 * if no icmp code found, create as many entryes as
1458 * there are listed icmp codes for that icmp type
1460 if (!bpof
->icmp_type
) {
1462 srcp
.max_port
= 255;
1463 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1464 dstp
.min_port
= icmp_code
->val
;
1466 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1469 bgp_pbr_policyroute_remove_from_zebra_unit(
1474 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1475 srcp
.min_port
= icmp_type
->val
;
1478 /* only icmp type. create an entry only with icmp type */
1479 if (!bpof
->icmp_code
) {
1480 /* icmp type is not one of the above
1481 * forge an entry only based on the icmp type
1484 dstp
.max_port
= 255;
1486 bgp_pbr_policyroute_add_to_zebra_unit(
1490 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1494 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1495 dstp
.min_port
= icmp_code
->val
;
1497 bgp_pbr_policyroute_add_to_zebra_unit(
1501 bgp_pbr_policyroute_remove_from_zebra_unit(
1507 static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp
*bgp
,
1508 struct bgp_info
*binfo
,
1509 struct bgp_pbr_filter
*bpf
,
1510 struct bgp_pbr_or_filter
*bpof
,
1513 struct listnode
*node
, *nnode
;
1514 struct bgp_pbr_val_mask
*valmask
;
1515 uint8_t next_type_entry
;
1516 struct list
*orig_list
;
1517 struct bgp_pbr_val_mask
**target_val
;
1519 if (type_entry
== 0)
1520 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1522 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1523 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1524 orig_list
= bpof
->tcpflags
;
1525 target_val
= &bpf
->tcp_flags
;
1526 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1527 orig_list
= bpof
->dscp
;
1528 target_val
= &bpf
->dscp
;
1529 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1530 orig_list
= bpof
->pkt_len
;
1531 target_val
= &bpf
->pkt_len_val
;
1532 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1533 orig_list
= bpof
->fragment
;
1534 target_val
= &bpf
->fragment
;
1535 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1536 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1537 /* enumerate list for icmp - must be last one */
1538 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, false, NULL
, NULL
);
1541 return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
,
1546 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1547 *target_val
= valmask
;
1548 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1554 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
1555 struct bgp_info
*binfo
,
1556 struct bgp_pbr_filter
*bpf
,
1557 struct bgp_pbr_or_filter
*bpof
)
1560 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1564 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1566 FLOWSPEC_TCP_FLAGS
);
1567 else if (bpof
->dscp
)
1568 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1571 else if (bpof
->pkt_len
)
1572 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1575 else if (bpof
->fragment
)
1576 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1579 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1580 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1582 FLOWSPEC_ICMP_TYPE
);
1584 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, binfo
, bpf
);
1587 list_delete_all_node(bpof
->tcpflags
);
1589 list_delete_all_node(bpof
->dscp
);
1591 list_delete_all_node(bpof
->pkt_len
);
1593 list_delete_all_node(bpof
->fragment
);
1596 static void bgp_pbr_dump_entry(struct bgp_pbr_filter
*bpf
, bool add
)
1598 struct bgp_pbr_range_port
*src_port
;
1599 struct bgp_pbr_range_port
*dst_port
;
1600 struct bgp_pbr_range_port
*pkt_len
;
1601 char bufsrc
[64], bufdst
[64];
1603 int remaining_len
= 0;
1604 char protocol_str
[16];
1608 src_port
= bpf
->src_port
;
1609 dst_port
= bpf
->dst_port
;
1610 pkt_len
= bpf
->pkt_len
;
1612 protocol_str
[0] = '\0';
1613 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1614 bpf
->protocol
= IPPROTO_TCP
;
1616 snprintf(protocol_str
, sizeof(protocol_str
),
1617 "proto %d", bpf
->protocol
);
1619 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1620 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1623 dst_port
->min_port
);
1624 else if (bpf
->protocol
== IPPROTO_UDP
||
1625 bpf
->protocol
== IPPROTO_TCP
) {
1627 if (src_port
&& src_port
->min_port
)
1628 remaining_len
+= snprintf(buffer
,
1632 src_port
->max_port
?
1633 src_port
->max_port
:
1634 src_port
->min_port
);
1635 if (dst_port
&& dst_port
->min_port
)
1636 remaining_len
+= snprintf(buffer
+
1642 dst_port
->max_port
?
1643 dst_port
->max_port
:
1644 dst_port
->min_port
);
1646 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1647 remaining_len
+= snprintf(buffer
+ remaining_len
,
1655 } else if (bpf
->pkt_len_val
) {
1656 remaining_len
+= snprintf(buffer
+ remaining_len
,
1660 bpf
->pkt_len_val
->mask
1662 bpf
->pkt_len_val
->val
);
1664 if (bpf
->tcp_flags
) {
1665 remaining_len
+= snprintf(buffer
+ remaining_len
,
1669 bpf
->tcp_flags
->val
,
1670 bpf
->tcp_flags
->mask
);
1673 snprintf(buffer
+ remaining_len
,
1681 zlog_info("BGP: %s FS PBR from %s to %s, %s %s",
1682 add
? "adding" : "removing",
1683 bpf
->src
== NULL
? "<all>" :
1684 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1685 bpf
->dst
== NULL
? "<all>" :
1686 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1687 protocol_str
, buffer
);
1691 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1692 struct bgp_info
*binfo
,
1693 struct bgp_pbr_filter
*bpf
,
1697 struct bgp_pbr_match temp
;
1698 struct bgp_pbr_match_entry temp2
;
1699 struct bgp_pbr_match
*bpm
;
1700 struct bgp_pbr_match_entry
*bpme
= NULL
;
1701 struct bgp_pbr_action temp3
;
1702 struct bgp_pbr_action
*bpa
= NULL
;
1703 struct bgp_pbr_match_entry_remain bpmer
;
1704 struct bgp_pbr_range_port
*src_port
;
1705 struct bgp_pbr_range_port
*dst_port
;
1706 struct bgp_pbr_range_port
*pkt_len
;
1707 bool bpme_found
= false;
1711 src_port
= bpf
->src_port
;
1712 dst_port
= bpf
->dst_port
;
1713 pkt_len
= bpf
->pkt_len
;
1715 if (BGP_DEBUG(zebra
, ZEBRA
))
1716 bgp_pbr_dump_entry(bpf
, true);
1718 /* look for bpa first */
1719 memset(&temp3
, 0, sizeof(temp3
));
1723 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1724 temp3
.vrf_id
= bpf
->vrf_id
;
1725 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1726 bgp_pbr_action_alloc_intern
);
1728 if (bpa
->fwmark
== 0) {
1729 /* drop is handled by iptable */
1730 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1732 bpa
->installed
= true;
1734 bpa
->fwmark
= bgp_zebra_tm_get_id();
1735 bpa
->table_id
= bpa
->fwmark
;
1736 bpa
->installed
= false;
1739 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1740 /* 0 value is forbidden */
1741 bpa
->install_in_progress
= false;
1744 /* then look for bpm */
1745 memset(&temp
, 0, sizeof(temp
));
1746 temp
.vrf_id
= bpf
->vrf_id
;
1748 temp
.flags
|= MATCH_IP_SRC_SET
;
1750 temp
.flags
|= MATCH_IP_DST_SET
;
1752 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1753 if (bpf
->protocol
== IPPROTO_ICMP
)
1754 temp
.flags
|= MATCH_ICMP_SET
;
1755 temp
.flags
|= MATCH_PORT_SRC_SET
;
1757 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1758 if (bpf
->protocol
== IPPROTO_ICMP
)
1759 temp
.flags
|= MATCH_ICMP_SET
;
1760 temp
.flags
|= MATCH_PORT_DST_SET
;
1762 if (src_port
&& src_port
->max_port
)
1763 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1764 if (dst_port
&& dst_port
->max_port
)
1765 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1767 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1768 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1769 temp
.type
= IPSET_NET_PORT
;
1771 temp
.type
= IPSET_NET
;
1773 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1774 temp
.type
= IPSET_NET_PORT_NET
;
1776 temp
.type
= IPSET_NET_NET
;
1779 temp
.pkt_len_min
= pkt_len
->min_port
;
1780 if (pkt_len
->max_port
)
1781 temp
.pkt_len_max
= pkt_len
->max_port
;
1782 } else if (bpf
->pkt_len_val
) {
1783 if (bpf
->pkt_len_val
->mask
)
1784 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1785 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1787 if (bpf
->tcp_flags
) {
1788 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1789 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1792 if (bpf
->dscp
->mask
)
1793 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1795 temp
.flags
|= MATCH_DSCP_SET
;
1796 temp
.dscp_value
= bpf
->dscp
->val
;
1798 if (bpf
->fragment
) {
1799 if (bpf
->fragment
->mask
)
1800 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1801 temp
.fragment
= bpf
->fragment
->val
;
1804 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1805 bgp_pbr_match_alloc_intern
);
1807 /* new, then self allocate ipset_name and unique */
1808 if (bpm
&& bpm
->unique
== 0) {
1809 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1810 /* 0 value is forbidden */
1811 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1812 bpm
->entry_hash
= hash_create_size(8,
1813 bgp_pbr_match_entry_hash_key
,
1814 bgp_pbr_match_entry_hash_equal
,
1815 "Match Entry Hash");
1816 bpm
->installed
= false;
1818 /* unique2 should be updated too */
1819 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1820 bpm
->installed_in_iptable
= false;
1821 bpm
->install_in_progress
= false;
1822 bpm
->install_iptable_in_progress
= false;
1825 memset(&temp2
, 0, sizeof(temp2
));
1827 prefix_copy(&temp2
.src
, bpf
->src
);
1829 temp2
.src
.family
= AF_INET
;
1831 prefix_copy(&temp2
.dst
, bpf
->dst
);
1833 temp2
.dst
.family
= AF_INET
;
1834 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1835 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1836 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1837 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1838 temp2
.proto
= bpf
->protocol
;
1840 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1841 bgp_pbr_match_entry_alloc_intern
);
1842 if (bpme
&& bpme
->unique
== 0) {
1843 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1844 /* 0 value is forbidden */
1845 bpme
->backpointer
= bpm
;
1846 bpme
->installed
= false;
1847 bpme
->install_in_progress
= false;
1848 /* link bgp info to bpme */
1849 bpme
->bgp_info
= (void *)binfo
;
1853 /* already installed */
1854 if (bpme_found
&& bpme
) {
1855 struct bgp_info_extra
*extra
= bgp_info_extra_get(binfo
);
1857 if (extra
&& extra
->bgp_fs_pbr
&&
1858 listnode_lookup(extra
->bgp_fs_pbr
, bpme
)) {
1859 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1860 zlog_err("%s: entry %p/%p already installed in bgp pbr",
1861 __func__
, binfo
, bpme
);
1865 /* BGP FS: append entry to zebra
1866 * - policies are not routing entries and as such
1867 * route replace semantics don't necessarily follow
1868 * through to policy entries
1869 * - because of that, not all policing information will be stored
1870 * into zebra. and non selected policies will be suppressed from zebra
1871 * - as consequence, in order to bring consistency
1872 * a policy will be added, then ifan ecmp policy exists,
1873 * it will be suppressed subsequently
1876 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1877 bgp_send_pbr_rule_action(bpa
, true);
1878 bgp_zebra_announce_default(bgp
, nh
,
1879 AFI_IP
, bpa
->table_id
, true);
1883 if (bpm
&& !bpm
->installed
)
1884 bgp_send_pbr_ipset_match(bpm
, true);
1886 if (bpme
&& !bpme
->installed
)
1887 bgp_send_pbr_ipset_entry_match(bpme
, true);
1890 if (bpm
&& !bpm
->installed_in_iptable
)
1891 bgp_send_pbr_iptable(bpa
, bpm
, true);
1893 /* A previous entry may already exist
1894 * flush previous entry if necessary
1896 bpmer
.bpme_to_match
= bpme
;
1897 bpmer
.bpme_found
= NULL
;
1898 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1899 if (bpmer
.bpme_found
) {
1900 static struct bgp_pbr_match
*local_bpm
;
1901 static struct bgp_pbr_action
*local_bpa
;
1903 local_bpm
= bpmer
.bpme_found
->backpointer
;
1904 local_bpa
= local_bpm
->action
;
1905 bgp_pbr_flush_entry(bgp
, local_bpa
,
1906 local_bpm
, bpmer
.bpme_found
);
1912 static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp
*bgp
,
1913 struct bgp_info
*binfo
,
1914 struct bgp_pbr_filter
*bpf
,
1915 struct bgp_pbr_or_filter
*bpof
,
1920 struct listnode
*node
, *nnode
;
1921 struct bgp_pbr_val_mask
*valmask
;
1922 uint8_t next_type_entry
;
1923 struct list
*orig_list
;
1924 struct bgp_pbr_val_mask
**target_val
;
1926 if (type_entry
== 0)
1927 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1929 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1930 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1931 orig_list
= bpof
->tcpflags
;
1932 target_val
= &bpf
->tcp_flags
;
1933 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1934 orig_list
= bpof
->dscp
;
1935 target_val
= &bpf
->dscp
;
1936 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1937 orig_list
= bpof
->pkt_len
;
1938 target_val
= &bpf
->pkt_len_val
;
1939 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1940 orig_list
= bpof
->fragment
;
1941 target_val
= &bpf
->fragment
;
1942 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1943 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1944 /* enumerate list for icmp - must be last one */
1945 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, true, nh
, rate
);
1948 return bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1949 bpf
, bpof
, nh
, rate
,
1952 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1953 *target_val
= valmask
;
1954 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1961 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1962 struct bgp_info
*binfo
,
1963 struct bgp_pbr_filter
*bpf
,
1964 struct bgp_pbr_or_filter
*bpof
,
1969 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1972 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1975 FLOWSPEC_TCP_FLAGS
);
1976 else if (bpof
->dscp
)
1977 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1981 else if (bpof
->pkt_len
)
1982 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1986 else if (bpof
->fragment
)
1987 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1991 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1992 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1993 bpf
, bpof
, nh
, rate
,
1994 FLOWSPEC_ICMP_TYPE
);
1996 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
2000 list_delete_all_node(bpof
->tcpflags
);
2002 list_delete_all_node(bpof
->dscp
);
2004 list_delete_all_node(bpof
->pkt_len
);
2006 list_delete_all_node(bpof
->fragment
);
2007 if (bpof
->icmp_type
)
2008 list_delete_all_node(bpof
->icmp_type
);
2009 if (bpof
->icmp_code
)
2010 list_delete_all_node(bpof
->icmp_code
);
2013 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
2014 struct bgp_info
*binfo
,
2015 struct bgp_pbr_entry_main
*api
,
2020 int continue_loop
= 1;
2022 struct prefix
*src
= NULL
, *dst
= NULL
;
2024 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
2025 struct bgp_pbr_range_port range
, range_icmp_code
;
2026 struct bgp_pbr_range_port pkt_len
;
2027 struct bgp_pbr_filter bpf
;
2029 struct bgp_pbr_or_filter bpof
;
2030 struct bgp_pbr_val_mask bpvm
;
2032 memset(&nh
, 0, sizeof(struct nexthop
));
2033 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2034 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2035 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
2036 src
= &api
->src_prefix
;
2037 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
2038 dst
= &api
->dst_prefix
;
2039 memset(&nh
, 0, sizeof(struct nexthop
));
2040 nh
.vrf_id
= VRF_UNKNOWN
;
2041 if (api
->match_protocol_num
)
2042 proto
= (uint8_t)api
->protocol
[0].value
;
2043 /* if match_port is selected, then either src or dst port will be parsed
2044 * but not both at the same time
2046 if (api
->match_port_num
>= 1) {
2047 bgp_pbr_extract(api
->port
,
2048 api
->match_port_num
,
2050 srcp
= dstp
= &range
;
2051 } else if (api
->match_src_port_num
>= 1) {
2052 bgp_pbr_extract(api
->src_port
,
2053 api
->match_src_port_num
,
2057 } else if (api
->match_dst_port_num
>= 1) {
2058 bgp_pbr_extract(api
->dst_port
,
2059 api
->match_dst_port_num
,
2064 if (api
->match_icmp_type_num
>= 1) {
2065 proto
= IPPROTO_ICMP
;
2066 if (bgp_pbr_extract(api
->icmp_type
,
2067 api
->match_icmp_type_num
,
2071 bpof
.icmp_type
= list_new();
2072 bgp_pbr_extract_enumerate(api
->icmp_type
,
2073 api
->match_icmp_type_num
,
2076 FLOWSPEC_ICMP_TYPE
);
2079 if (api
->match_icmp_code_num
>= 1) {
2080 proto
= IPPROTO_ICMP
;
2081 if (bgp_pbr_extract(api
->icmp_code
,
2082 api
->match_icmp_code_num
,
2084 dstp
= &range_icmp_code
;
2086 bpof
.icmp_code
= list_new();
2087 bgp_pbr_extract_enumerate(api
->icmp_code
,
2088 api
->match_icmp_code_num
,
2091 FLOWSPEC_ICMP_CODE
);
2095 if (api
->match_tcpflags_num
) {
2096 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2097 api
->match_tcpflags_num
);
2098 if (kind_enum
== OPERATOR_UNARY_AND
) {
2099 bpf
.tcp_flags
= &bpvm
;
2100 bgp_pbr_extract_enumerate(api
->tcpflags
,
2101 api
->match_tcpflags_num
,
2104 FLOWSPEC_TCP_FLAGS
);
2105 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2106 bpof
.tcpflags
= list_new();
2107 bgp_pbr_extract_enumerate(api
->tcpflags
,
2108 api
->match_tcpflags_num
,
2111 FLOWSPEC_TCP_FLAGS
);
2114 if (api
->match_packet_length_num
) {
2117 ret
= bgp_pbr_extract(api
->packet_length
,
2118 api
->match_packet_length_num
,
2121 bpf
.pkt_len
= &pkt_len
;
2123 bpof
.pkt_len
= list_new();
2124 bgp_pbr_extract_enumerate(api
->packet_length
,
2125 api
->match_packet_length_num
,
2131 if (api
->match_dscp_num
>= 1) {
2132 bpof
.dscp
= list_new();
2133 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2135 bpof
.dscp
, FLOWSPEC_DSCP
);
2137 if (api
->match_fragment_num
) {
2138 bpof
.fragment
= list_new();
2139 bgp_pbr_extract_enumerate(api
->fragment
,
2140 api
->match_fragment_num
,
2145 bpf
.vrf_id
= api
->vrf_id
;
2148 bpf
.protocol
= proto
;
2149 bpf
.src_port
= srcp
;
2150 bpf
.dst_port
= dstp
;
2152 return bgp_pbr_policyroute_remove_from_zebra(bgp
,
2155 /* no action for add = true */
2156 for (i
= 0; i
< api
->action_num
; i
++) {
2157 switch (api
->actions
[i
].action
) {
2158 case ACTION_TRAFFICRATE
:
2160 if (api
->actions
[i
].u
.r
.rate
== 0) {
2161 nh
.vrf_id
= api
->vrf_id
;
2162 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2163 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2167 /* update rate. can be reentrant */
2168 rate
= api
->actions
[i
].u
.r
.rate
;
2169 if (BGP_DEBUG(pbr
, PBR
)) {
2170 bgp_pbr_print_policy_route(api
);
2171 zlog_warn("PBR: ignoring Set action rate %f",
2172 api
->actions
[i
].u
.r
.rate
);
2176 case ACTION_TRAFFIC_ACTION
:
2177 if (api
->actions
[i
].u
.za
.filter
2178 & TRAFFIC_ACTION_SAMPLE
) {
2179 if (BGP_DEBUG(pbr
, PBR
)) {
2180 bgp_pbr_print_policy_route(api
);
2181 zlog_warn("PBR: Sample action Ignored");
2185 if (api
->actions
[i
].u
.za
.filter
2186 & TRAFFIC_ACTION_DISTRIBUTE
) {
2187 if (BGP_DEBUG(pbr
, PBR
)) {
2188 bgp_pbr_print_policy_route(api
);
2189 zlog_warn("PBR: Distribute action Applies");
2192 /* continue forwarding entry as before
2196 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2197 /* terminate action: run other filters
2200 case ACTION_REDIRECT_IP
:
2201 nh
.type
= NEXTHOP_TYPE_IPV4
;
2202 nh
.gate
.ipv4
.s_addr
=
2203 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2204 nh
.vrf_id
= api
->vrf_id
;
2205 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2208 /* XXX combination with REDIRECT_VRF
2209 * + REDIRECT_NH_IP not done
2213 case ACTION_REDIRECT
:
2214 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2215 nh
.type
= NEXTHOP_TYPE_IPV4
;
2216 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2221 case ACTION_MARKING
:
2222 if (BGP_DEBUG(pbr
, PBR
)) {
2223 bgp_pbr_print_policy_route(api
);
2224 zlog_warn("PBR: Set DSCP %u Ignored",
2225 api
->actions
[i
].u
.marking_dscp
);
2231 if (continue_loop
== 0)
2236 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2237 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
2240 struct bgp_pbr_entry_main api
;
2243 return; /* IPv6 not supported */
2244 if (safi
!= SAFI_FLOWSPEC
)
2245 return; /* not supported */
2246 /* Make Zebra API structure. */
2247 memset(&api
, 0, sizeof(api
));
2248 api
.vrf_id
= bgp
->vrf_id
;
2251 if (!bgp_zebra_tm_chunk_obtained()) {
2252 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2253 zlog_err("%s: table chunk not obtained yet",
2258 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2259 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2260 zlog_err("%s: cancel updating entry %p in bgp pbr",
2264 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2267 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2268 const struct bgp_pbr_interface
*b
)
2270 return strcmp(a
->name
, b
->name
);
2273 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2274 struct bgp_pbr_interface_head
*head
)
2276 struct bgp_pbr_interface pbr_if
;
2278 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2279 return (RB_FIND(bgp_pbr_interface_head
,
2283 /* this function resets to the default policy routing
2284 * go back to default status
2286 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2288 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2289 struct bgp_pbr_interface_head
*head
;
2290 struct bgp_pbr_interface
*pbr_if
;
2292 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2294 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2296 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2297 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2298 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2299 XFREE(MTYPE_TMP
, pbr_if
);