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 bool bgp_pbr_extract_enumerate_unary_opposite(
235 uint8_t unary_operator
,
236 struct bgp_pbr_val_mask
*and_valmask
,
237 struct list
*or_valmask
, uint32_t value
,
240 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
241 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
243 TCP_HEADER_ALL_FLAGS
&
245 } else if (type_entry
== FLOWSPEC_DSCP
||
246 type_entry
== FLOWSPEC_PKT_LEN
||
247 type_entry
== FLOWSPEC_FRAGMENT
) {
248 and_valmask
->val
= value
;
249 and_valmask
->mask
= 1; /* inverse */
251 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
252 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
253 sizeof(struct bgp_pbr_val_mask
));
254 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
255 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
257 TCP_HEADER_ALL_FLAGS
&
259 } else if (type_entry
== FLOWSPEC_DSCP
||
260 type_entry
== FLOWSPEC_FRAGMENT
||
261 type_entry
== FLOWSPEC_PKT_LEN
) {
262 and_valmask
->val
= value
;
263 and_valmask
->mask
= 1; /* inverse */
265 listnode_add(or_valmask
, and_valmask
);
266 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
267 type_entry
== FLOWSPEC_ICMP_TYPE
)
272 /* TCP : FIN and SYN -> val = ALL; mask = 3
273 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
274 * other variables type: dscp, pkt len, fragment
275 * - value is copied in bgp_pbr_val_mask->val value
276 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
278 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
279 int num
, uint8_t unary_operator
,
280 void *valmask
, uint8_t type_entry
)
283 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
284 struct list
*or_valmask
= NULL
;
288 if (unary_operator
== OPERATOR_UNARY_AND
) {
289 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
290 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
291 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
292 or_valmask
= (struct list
*)valmask
;
295 for (i
= 0; i
< num
; i
++) {
296 if (i
!= 0 && list
[i
].unary_operator
!=
299 if (!(list
[i
].compare_operator
&
300 OPERATOR_COMPARE_EQUAL_TO
) &&
301 !(list
[i
].compare_operator
&
302 OPERATOR_COMPARE_EXACT_MATCH
)) {
303 if ((list
[i
].compare_operator
&
304 OPERATOR_COMPARE_LESS_THAN
) &&
305 (list
[i
].compare_operator
&
306 OPERATOR_COMPARE_GREATER_THAN
)) {
307 ret
= bgp_pbr_extract_enumerate_unary_opposite(
308 unary_operator
, and_valmask
,
309 or_valmask
, list
[i
].value
,
317 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
318 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
320 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
321 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
322 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
323 sizeof(struct bgp_pbr_val_mask
));
324 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
325 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
327 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
328 } else if (type_entry
== FLOWSPEC_DSCP
||
329 type_entry
== FLOWSPEC_ICMP_TYPE
||
330 type_entry
== FLOWSPEC_ICMP_CODE
||
331 type_entry
== FLOWSPEC_FRAGMENT
||
332 type_entry
== FLOWSPEC_PKT_LEN
)
333 and_valmask
->val
= list
[i
].value
;
334 listnode_add(or_valmask
, and_valmask
);
337 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
338 && type_entry
== FLOWSPEC_TCP_FLAGS
)
339 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
343 /* if unary operator can either be UNARY_OR/AND/OR-AND.
344 * in the latter case, combinationf of both is not handled
346 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
347 int num
, uint8_t unary_operator
,
348 void *valmask
, uint8_t type_entry
)
351 uint8_t unary_operator_val
;
352 bool double_check
= false;
354 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
355 (unary_operator
& OPERATOR_UNARY_AND
)) {
356 unary_operator_val
= OPERATOR_UNARY_AND
;
359 unary_operator_val
= unary_operator
;
360 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
361 valmask
, type_entry
);
362 if (!ret
&& double_check
)
363 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
370 /* returns the unary operator that is in the list
371 * return 0 if both operators are used
373 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
378 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
380 for (i
= 0; i
< num
; i
++) {
383 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
384 unary_operator
= OPERATOR_UNARY_OR
;
385 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
386 && unary_operator
== OPERATOR_UNARY_OR
) ||
387 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
388 && unary_operator
== OPERATOR_UNARY_AND
))
391 return unary_operator
;
395 /* return true if extraction ok
397 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
399 struct bgp_pbr_range_port
*range
)
402 bool exact_match
= false;
405 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
409 for (i
= 0; i
< num
; i
++) {
410 if (i
!= 0 && (list
[i
].compare_operator
==
411 OPERATOR_COMPARE_EQUAL_TO
))
413 if (i
== 0 && (list
[i
].compare_operator
==
414 OPERATOR_COMPARE_EQUAL_TO
)) {
416 range
->min_port
= list
[i
].value
;
419 if (exact_match
== true && i
> 0)
421 if (list
[i
].compare_operator
==
422 (OPERATOR_COMPARE_GREATER_THAN
+
423 OPERATOR_COMPARE_EQUAL_TO
)) {
425 range
->min_port
= list
[i
].value
;
426 } else if (list
[i
].compare_operator
==
427 (OPERATOR_COMPARE_LESS_THAN
+
428 OPERATOR_COMPARE_EQUAL_TO
)) {
430 range
->max_port
= list
[i
].value
;
431 } else if (list
[i
].compare_operator
==
432 OPERATOR_COMPARE_LESS_THAN
) {
434 range
->max_port
= list
[i
].value
- 1;
435 } else if (list
[i
].compare_operator
==
436 OPERATOR_COMPARE_GREATER_THAN
) {
438 range
->min_port
= list
[i
].value
+ 1;
444 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
446 bool enumerate_icmp
= false;
448 /* because bgp pbr entry may contain unsupported
449 * combinations, a message will be displayed here if
451 * for now, only match/set supported is
452 * - combination src/dst => redirect nexthop [ + rate]
453 * - combination src/dst => redirect VRF [ + rate]
454 * - combination src/dst => drop
455 * - combination srcport + @IP
457 if (api
->match_protocol_num
> 1) {
458 if (BGP_DEBUG(pbr
, PBR
))
459 zlog_debug("BGP: match protocol operations:"
460 "multiple protocols ( %d). ignoring.",
461 api
->match_protocol_num
);
464 if (api
->match_protocol_num
== 1 &&
465 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
466 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
467 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
468 if (BGP_DEBUG(pbr
, PBR
))
469 zlog_debug("BGP: match protocol operations:"
470 "protocol (%d) not supported. ignoring",
471 api
->match_protocol_num
);
474 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
475 if (BGP_DEBUG(pbr
, PBR
))
476 zlog_debug("BGP: match src port operations:"
477 "too complex. ignoring.");
480 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
481 if (BGP_DEBUG(pbr
, PBR
))
482 zlog_debug("BGP: match dst port operations:"
483 "too complex. ignoring.");
486 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
487 api
->match_tcpflags_num
,
489 OPERATOR_UNARY_OR
, NULL
,
490 FLOWSPEC_TCP_FLAGS
)) {
491 if (BGP_DEBUG(pbr
, PBR
))
492 zlog_debug("BGP: match tcp flags:"
493 "too complex. ignoring.");
496 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
497 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
498 api
->match_icmp_type_num
,
499 OPERATOR_UNARY_OR
, NULL
,
500 FLOWSPEC_ICMP_TYPE
)) {
501 if (BGP_DEBUG(pbr
, PBR
))
502 zlog_debug("BGP: match icmp type operations:"
503 "too complex. ignoring.");
506 enumerate_icmp
= true;
508 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
509 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
510 api
->match_icmp_code_num
,
511 OPERATOR_UNARY_OR
, NULL
,
512 FLOWSPEC_ICMP_CODE
)) {
513 if (BGP_DEBUG(pbr
, PBR
))
514 zlog_debug("BGP: match icmp code operations:"
515 "too complex. ignoring.");
517 } else if (api
->match_icmp_type_num
> 1 &&
518 enumerate_icmp
== false) {
519 if (BGP_DEBUG(pbr
, PBR
))
520 zlog_debug("BGP: match icmp code is enumerate"
521 ", and icmp type is not."
522 " too complex. ignoring.");
526 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
527 if (BGP_DEBUG(pbr
, PBR
))
528 zlog_debug("BGP: match port operations:"
529 "too complex. ignoring.");
532 if (api
->match_packet_length_num
) {
535 ret
= bgp_pbr_extract(api
->packet_length
,
536 api
->match_packet_length_num
, NULL
);
538 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
539 api
->match_packet_length_num
,
541 | OPERATOR_UNARY_AND
,
542 NULL
, FLOWSPEC_PKT_LEN
);
544 if (BGP_DEBUG(pbr
, PBR
))
545 zlog_debug("BGP: match packet length operations:"
546 "too complex. ignoring.");
550 if (api
->match_dscp_num
) {
551 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
552 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
553 NULL
, FLOWSPEC_DSCP
)) {
554 if (BGP_DEBUG(pbr
, PBR
))
555 zlog_debug("BGP: match DSCP operations:"
556 "too complex. ignoring.");
560 if (api
->match_fragment_num
) {
564 success
= bgp_pbr_extract_enumerate(api
->fragment
,
565 api
->match_fragment_num
,
567 | OPERATOR_UNARY_AND
,
568 NULL
, FLOWSPEC_FRAGMENT
);
572 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
573 if (api
->fragment
[i
].value
!= 1 &&
574 api
->fragment
[i
].value
!= 2 &&
575 api
->fragment
[i
].value
!= 4 &&
576 api
->fragment
[i
].value
!= 8) {
579 "Value not valid (%d) for this implementation",
580 api
->fragment
[i
].value
);
584 sprintf(fail_str
, "too complex. ignoring");
586 if (BGP_DEBUG(pbr
, PBR
))
587 zlog_debug("BGP: match fragment operation (%d) %s",
588 api
->match_fragment_num
,
594 /* no combinations with both src_port and dst_port
595 * or port with src_port and dst_port
597 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
598 api
->match_port_num
> 3) {
599 if (BGP_DEBUG(pbr
, PBR
))
600 zlog_debug("BGP: match multiple port operations:"
601 " too complex. ignoring.");
604 if ((api
->match_src_port_num
|| api
->match_dst_port_num
605 || api
->match_port_num
) && (api
->match_icmp_type_num
606 || api
->match_icmp_code_num
)) {
607 if (BGP_DEBUG(pbr
, PBR
))
608 zlog_debug("BGP: match multiple port/imcp operations:"
609 " too complex. ignoring.");
612 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
613 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
614 if (BGP_DEBUG(pbr
, PBR
)) {
615 bgp_pbr_print_policy_route(api
);
616 zlog_debug("BGP: match actions without src"
617 " or dst address can not operate."
625 /* return -1 if build or validation failed */
626 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
627 struct bgp_info
*info
,
628 struct bgp_pbr_entry_main
*api
)
631 int i
, action_count
= 0;
632 struct ecommunity
*ecom
;
633 struct ecommunity_val
*ecom_eval
;
634 struct bgp_pbr_entry_action
*api_action
;
635 struct prefix
*src
= NULL
, *dst
= NULL
;
636 int valid_prefix
= 0;
639 /* extract match from flowspec entries */
640 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
641 p
->u
.prefix_flowspec
.prefixlen
, api
);
644 /* extract actiosn from flowspec ecom list */
645 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
646 ecom
= info
->attr
->ecommunity
;
647 for (i
= 0; i
< ecom
->size
; i
++) {
648 ecom_eval
= (struct ecommunity_val
*)
649 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
651 if (action_count
> ACTIONS_MAX_NUM
) {
652 if (BGP_DEBUG(pbr
, PBR_ERROR
))
653 zlog_err("%s: flowspec actions exceeds limit (max %u)",
654 __func__
, action_count
);
657 api_action
= &api
->actions
[action_count
- 1];
659 if ((ecom_eval
->val
[1] ==
660 (char)ECOMMUNITY_REDIRECT_VRF
) &&
661 (ecom_eval
->val
[0] ==
662 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
664 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
666 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
667 struct ecommunity
*eckey
= ecommunity_new();
668 struct ecommunity_val ecom_copy
;
670 memcpy(&ecom_copy
, ecom_eval
,
671 sizeof(struct ecommunity_val
));
673 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
674 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
675 ecommunity_add_val(eckey
, &ecom_copy
);
677 api_action
->action
= ACTION_REDIRECT
;
678 api_action
->u
.redirect_vrf
=
679 get_first_vrf_for_redirect_with_rt(
681 ecommunity_free(&eckey
);
682 } else if ((ecom_eval
->val
[0] ==
683 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
684 (ecom_eval
->val
[1] ==
685 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
686 api_action
->action
= ACTION_REDIRECT_IP
;
687 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
688 info
->attr
->nexthop
.s_addr
;
689 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
691 if (ecom_eval
->val
[0] !=
692 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
694 ret
= ecommunity_fill_pbr_action(ecom_eval
,
703 /* validate if incoming matc/action is compatible
704 * with our policy routing engine
706 if (!bgp_pbr_validate_policy_route(api
))
709 /* check inconsistency in the match rule */
710 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
711 src
= &api
->src_prefix
;
712 afi
= family2afi(src
->family
);
715 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
716 dst
= &api
->dst_prefix
;
717 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
718 if (BGP_DEBUG(pbr
, PBR
)) {
719 bgp_pbr_print_policy_route(api
);
720 zlog_debug("%s: inconsistency:"
721 " no match for afi src and dst (%u/%u)",
722 __func__
, afi
, family2afi(dst
->family
));
730 static void bgp_pbr_match_entry_free(void *arg
)
732 struct bgp_pbr_match_entry
*bpme
;
734 bpme
= (struct bgp_pbr_match_entry
*)arg
;
736 if (bpme
->installed
) {
737 bgp_send_pbr_ipset_entry_match(bpme
, false);
738 bpme
->installed
= false;
739 bpme
->backpointer
= NULL
;
741 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
744 static void bgp_pbr_match_free(void *arg
)
746 struct bgp_pbr_match
*bpm
;
748 bpm
= (struct bgp_pbr_match
*)arg
;
750 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
752 if (hashcount(bpm
->entry_hash
) == 0) {
753 /* delete iptable entry first */
754 /* then delete ipset match */
755 if (bpm
->installed
) {
756 if (bpm
->installed_in_iptable
) {
757 bgp_send_pbr_iptable(bpm
->action
,
759 bpm
->installed_in_iptable
= false;
760 bpm
->action
->refcnt
--;
762 bgp_send_pbr_ipset_match(bpm
, false);
763 bpm
->installed
= false;
767 hash_free(bpm
->entry_hash
);
769 XFREE(MTYPE_PBR_MATCH
, bpm
);
772 static void *bgp_pbr_match_alloc_intern(void *arg
)
774 struct bgp_pbr_match
*bpm
, *new;
776 bpm
= (struct bgp_pbr_match
*)arg
;
778 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
779 memcpy(new, bpm
, sizeof(*bpm
));
784 static void bgp_pbr_action_free(void *arg
)
786 struct bgp_pbr_action
*bpa
;
788 bpa
= (struct bgp_pbr_action
*)arg
;
790 if (bpa
->refcnt
== 0) {
791 if (bpa
->installed
&& bpa
->table_id
!= 0) {
792 bgp_send_pbr_rule_action(bpa
, false);
793 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
797 bpa
->installed
= false;
800 XFREE(MTYPE_PBR_ACTION
, bpa
);
803 static void *bgp_pbr_action_alloc_intern(void *arg
)
805 struct bgp_pbr_action
*bpa
, *new;
807 bpa
= (struct bgp_pbr_action
*)arg
;
809 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
811 memcpy(new, bpa
, sizeof(*bpa
));
816 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
818 struct bgp_pbr_match_entry
*bpme
, *new;
820 bpme
= (struct bgp_pbr_match_entry
*)arg
;
822 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
824 memcpy(new, bpme
, sizeof(*bpme
));
829 uint32_t bgp_pbr_match_hash_key(void *arg
)
831 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
834 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
835 key
= jhash_1word(pbm
->flags
, key
);
836 key
= jhash_1word(pbm
->pkt_len_min
, key
);
837 key
= jhash_1word(pbm
->pkt_len_max
, key
);
838 key
= jhash_1word(pbm
->tcp_flags
, key
);
839 key
= jhash_1word(pbm
->tcp_mask_flags
, key
);
840 key
= jhash_1word(pbm
->dscp_value
, key
);
841 key
= jhash_1word(pbm
->fragment
, key
);
842 return jhash_1word(pbm
->type
, key
);
845 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
847 const struct bgp_pbr_match
*r1
, *r2
;
849 r1
= (const struct bgp_pbr_match
*)arg1
;
850 r2
= (const struct bgp_pbr_match
*)arg2
;
852 if (r1
->vrf_id
!= r2
->vrf_id
)
855 if (r1
->type
!= r2
->type
)
858 if (r1
->flags
!= r2
->flags
)
861 if (r1
->action
!= r2
->action
)
864 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
867 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
870 if (r1
->tcp_flags
!= r2
->tcp_flags
)
873 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
876 if (r1
->dscp_value
!= r2
->dscp_value
)
879 if (r1
->fragment
!= r2
->fragment
)
884 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
886 struct bgp_pbr_match_entry
*pbme
;
889 pbme
= (struct bgp_pbr_match_entry
*)arg
;
890 key
= prefix_hash_key(&pbme
->src
);
891 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
892 key
= jhash(&pbme
->dst_port_min
, 2, key
);
893 key
= jhash(&pbme
->src_port_min
, 2, key
);
894 key
= jhash(&pbme
->dst_port_max
, 2, key
);
895 key
= jhash(&pbme
->src_port_max
, 2, key
);
896 key
= jhash(&pbme
->proto
, 1, key
);
901 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
903 const struct bgp_pbr_match_entry
*r1
, *r2
;
905 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
906 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
908 /* on updates, comparing
909 * backpointer is not necessary
912 /* unique value is self calculated
915 /* rate is ignored for now
918 if (!prefix_same(&r1
->src
, &r2
->src
))
921 if (!prefix_same(&r1
->dst
, &r2
->dst
))
924 if (r1
->src_port_min
!= r2
->src_port_min
)
927 if (r1
->dst_port_min
!= r2
->dst_port_min
)
930 if (r1
->src_port_max
!= r2
->src_port_max
)
933 if (r1
->dst_port_max
!= r2
->dst_port_max
)
936 if (r1
->proto
!= r2
->proto
)
942 uint32_t bgp_pbr_action_hash_key(void *arg
)
944 struct bgp_pbr_action
*pbra
;
947 pbra
= (struct bgp_pbr_action
*)arg
;
948 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
949 key
= jhash_1word(pbra
->fwmark
, key
);
953 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
955 const struct bgp_pbr_action
*r1
, *r2
;
957 r1
= (const struct bgp_pbr_action
*)arg1
;
958 r2
= (const struct bgp_pbr_action
*)arg2
;
960 /* unique value is self calculated
961 * table and fwmark is self calculated
964 if (r1
->vrf_id
!= r2
->vrf_id
)
967 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
972 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
975 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
976 struct bgp_pbr_action_unique bpau
;
978 if (!bgp
|| unique
== 0)
980 bpau
.unique
= unique
;
981 bpau
.bpa_found
= NULL
;
982 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
983 return bpau
.bpa_found
;
986 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
989 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
990 struct bgp_pbr_match_unique bpmu
;
992 if (!bgp
|| unique
== 0)
994 bpmu
.unique
= unique
;
995 bpmu
.bpm_found
= NULL
;
996 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
997 return bpmu
.bpm_found
;
1000 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
1004 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1005 struct bgp_pbr_match_entry_unique bpmeu
;
1006 struct bgp_pbr_match_ipsetname bpmi
;
1008 if (!bgp
|| unique
== 0)
1010 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
1011 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
1012 bpmi
.bpm_found
= NULL
;
1013 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
1014 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1015 if (!bpmi
.bpm_found
)
1017 bpmeu
.bpme_found
= NULL
;
1018 bpmeu
.unique
= unique
;
1019 hash_walk(bpmi
.bpm_found
->entry_hash
,
1020 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1021 return bpmeu
.bpme_found
;
1024 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1027 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1028 struct bgp_pbr_match_iptable_unique bpmiu
;
1030 if (!bgp
|| unique
== 0)
1032 bpmiu
.unique
= unique
;
1033 bpmiu
.bpm_found
= NULL
;
1034 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1035 return bpmiu
.bpm_found
;
1038 void bgp_pbr_cleanup(struct bgp
*bgp
)
1040 if (bgp
->pbr_match_hash
) {
1041 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1042 hash_free(bgp
->pbr_match_hash
);
1043 bgp
->pbr_match_hash
= NULL
;
1045 if (bgp
->pbr_action_hash
) {
1046 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1047 hash_free(bgp
->pbr_action_hash
);
1048 bgp
->pbr_action_hash
= NULL
;
1050 if (bgp
->bgp_pbr_cfg
== NULL
)
1052 bgp_pbr_reset(bgp
, AFI_IP
);
1053 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1054 bgp
->bgp_pbr_cfg
= NULL
;
1057 void bgp_pbr_init(struct bgp
*bgp
)
1059 bgp
->pbr_match_hash
=
1060 hash_create_size(8, bgp_pbr_match_hash_key
,
1061 bgp_pbr_match_hash_equal
,
1063 bgp
->pbr_action_hash
=
1064 hash_create_size(8, bgp_pbr_action_hash_key
,
1065 bgp_pbr_action_hash_equal
,
1066 "Match Hash Entry");
1068 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1069 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1072 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1075 char return_string
[512];
1076 char *ptr
= return_string
;
1080 ptr
+= sprintf(ptr
, "MATCH : ");
1081 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1082 struct prefix
*p
= &(api
->src_prefix
);
1084 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1085 INCREMENT_DISPLAY(ptr
, nb_items
);
1087 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1088 struct prefix
*p
= &(api
->dst_prefix
);
1090 INCREMENT_DISPLAY(ptr
, nb_items
);
1091 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1094 if (api
->match_protocol_num
)
1095 INCREMENT_DISPLAY(ptr
, nb_items
);
1096 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1097 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1098 i
> 0 ? NULL
: "@proto ");
1100 if (api
->match_src_port_num
)
1101 INCREMENT_DISPLAY(ptr
, nb_items
);
1102 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1103 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1104 i
> 0 ? NULL
: "@srcport ");
1106 if (api
->match_dst_port_num
)
1107 INCREMENT_DISPLAY(ptr
, nb_items
);
1108 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1109 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1110 i
> 0 ? NULL
: "@dstport ");
1112 if (api
->match_port_num
)
1113 INCREMENT_DISPLAY(ptr
, nb_items
);
1114 for (i
= 0; i
< api
->match_port_num
; i
++)
1115 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1116 i
> 0 ? NULL
: "@port ");
1118 if (api
->match_icmp_type_num
)
1119 INCREMENT_DISPLAY(ptr
, nb_items
);
1120 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1121 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1122 i
> 0 ? NULL
: "@icmptype ");
1124 if (api
->match_icmp_code_num
)
1125 INCREMENT_DISPLAY(ptr
, nb_items
);
1126 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1127 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1128 i
> 0 ? NULL
: "@icmpcode ");
1130 if (api
->match_packet_length_num
)
1131 INCREMENT_DISPLAY(ptr
, nb_items
);
1132 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1133 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1134 i
> 0 ? NULL
: "@plen ");
1136 if (api
->match_dscp_num
)
1137 INCREMENT_DISPLAY(ptr
, nb_items
);
1138 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1139 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1140 i
> 0 ? NULL
: "@dscp ");
1142 if (api
->match_tcpflags_num
)
1143 INCREMENT_DISPLAY(ptr
, nb_items
);
1144 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1145 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1146 i
> 0 ? NULL
: "@tcpflags ");
1148 if (api
->match_fragment_num
)
1149 INCREMENT_DISPLAY(ptr
, nb_items
);
1150 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1151 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1152 i
> 0 ? NULL
: "@fragment ");
1154 ptr
= return_string
;
1156 ptr
+= sprintf(ptr
, "; ");
1157 if (api
->action_num
)
1158 ptr
+= sprintf(ptr
, "SET : ");
1160 for (i
= 0; i
< api
->action_num
; i
++) {
1161 switch (api
->actions
[i
].action
) {
1162 case ACTION_TRAFFICRATE
:
1163 INCREMENT_DISPLAY(ptr
, nb_items
);
1164 ptr
+= sprintf(ptr
, "@set rate %f",
1165 api
->actions
[i
].u
.r
.rate
);
1167 case ACTION_TRAFFIC_ACTION
:
1168 INCREMENT_DISPLAY(ptr
, nb_items
);
1169 ptr
+= sprintf(ptr
, "@action ");
1170 if (api
->actions
[i
].u
.za
.filter
1171 & TRAFFIC_ACTION_TERMINATE
)
1173 " terminate (apply filter(s))");
1174 if (api
->actions
[i
].u
.za
.filter
1175 & TRAFFIC_ACTION_DISTRIBUTE
)
1176 ptr
+= sprintf(ptr
, " distribute");
1177 if (api
->actions
[i
].u
.za
.filter
1178 & TRAFFIC_ACTION_SAMPLE
)
1179 ptr
+= sprintf(ptr
, " sample");
1181 case ACTION_REDIRECT_IP
:
1182 INCREMENT_DISPLAY(ptr
, nb_items
);
1183 char local_buff
[INET_ADDRSTRLEN
];
1185 if (inet_ntop(AF_INET
,
1186 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1187 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1189 "@redirect ip nh %s", local_buff
);
1191 case ACTION_REDIRECT
:
1192 INCREMENT_DISPLAY(ptr
, nb_items
);
1193 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1194 api
->actions
[i
].u
.redirect_vrf
);
1196 case ACTION_MARKING
:
1197 INCREMENT_DISPLAY(ptr
, nb_items
);
1198 ptr
+= sprintf(ptr
, "@set dscp %u",
1199 api
->actions
[i
].u
.marking_dscp
);
1205 zlog_info("%s", return_string
);
1208 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1209 struct bgp_pbr_match
*bpm
,
1210 struct bgp_pbr_match_entry
*bpme
)
1212 /* if bpme is null, bpm is also null
1216 /* ipset del entry */
1217 if (bpme
->installed
) {
1218 bgp_send_pbr_ipset_entry_match(bpme
, false);
1219 bpme
->installed
= false;
1220 bpme
->backpointer
= NULL
;
1221 if (bpme
->bgp_info
) {
1222 struct bgp_info
*bgp_info
;
1223 struct bgp_info_extra
*extra
;
1225 /* unlink bgp_info to bpme */
1226 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
1227 extra
= bgp_info_extra_get(bgp_info
);
1228 extra
->bgp_fs_pbr
= NULL
;
1229 bpme
->bgp_info
= NULL
;
1232 hash_release(bpm
->entry_hash
, bpme
);
1233 if (hashcount(bpm
->entry_hash
) == 0) {
1234 /* delete iptable entry first */
1235 /* then delete ipset match */
1236 if (bpm
->installed
) {
1237 if (bpm
->installed_in_iptable
) {
1238 bgp_send_pbr_iptable(bpm
->action
,
1240 bpm
->installed_in_iptable
= false;
1241 bpm
->action
->refcnt
--;
1243 bgp_send_pbr_ipset_match(bpm
, false);
1244 bpm
->installed
= false;
1247 hash_release(bgp
->pbr_match_hash
, bpm
);
1248 /* XXX release pbr_match_action if not used
1249 * note that drop does not need to call send_pbr_action
1252 if (bpa
->refcnt
== 0) {
1253 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1254 bgp_send_pbr_rule_action(bpa
, false);
1255 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1259 bpa
->installed
= false;
1264 struct bgp_pbr_match_entry_remain
{
1265 struct bgp_pbr_match_entry
*bpme_to_match
;
1266 struct bgp_pbr_match_entry
*bpme_found
;
1269 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1271 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1272 struct bgp_pbr_match_entry_remain
*bpmer
=
1273 (struct bgp_pbr_match_entry_remain
*)arg
;
1274 struct bgp_pbr_match
*bpm_temp
;
1275 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1277 if (!bpme
->backpointer
||
1278 bpm
== bpme
->backpointer
||
1279 bpme
->backpointer
->action
== bpm
->action
)
1280 return HASHWALK_CONTINUE
;
1281 /* ensure bpm other characteristics are equal */
1282 bpm_temp
= bpme
->backpointer
;
1283 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1284 bpm_temp
->type
!= bpm
->type
||
1285 bpm_temp
->flags
!= bpm
->flags
)
1286 return HASHWALK_CONTINUE
;
1288 /* look for remaining bpme */
1289 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1290 if (!bpmer
->bpme_found
)
1291 return HASHWALK_CONTINUE
;
1292 return HASHWALK_ABORT
;
1295 static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp
*bgp
,
1296 struct bgp_info
*binfo
,
1297 struct bgp_pbr_filter
*bpf
)
1299 struct bgp_pbr_match temp
;
1300 struct bgp_pbr_match_entry temp2
;
1301 struct bgp_pbr_match
*bpm
;
1302 struct bgp_pbr_match_entry
*bpme
;
1303 struct bgp_pbr_match_entry_remain bpmer
;
1304 struct bgp_pbr_range_port
*src_port
;
1305 struct bgp_pbr_range_port
*dst_port
;
1306 struct bgp_pbr_range_port
*pkt_len
;
1310 src_port
= bpf
->src_port
;
1311 dst_port
= bpf
->dst_port
;
1312 pkt_len
= bpf
->pkt_len
;
1314 /* as we don't know information from EC
1315 * look for bpm that have the bpm
1316 * with vrf_id characteristics
1318 memset(&temp2
, 0, sizeof(temp2
));
1319 memset(&temp
, 0, sizeof(temp
));
1321 temp
.flags
|= MATCH_IP_SRC_SET
;
1322 prefix_copy(&temp2
.src
, bpf
->src
);
1324 temp2
.src
.family
= AF_INET
;
1326 temp
.flags
|= MATCH_IP_DST_SET
;
1327 prefix_copy(&temp2
.dst
, bpf
->dst
);
1329 temp2
.dst
.family
= AF_INET
;
1330 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1331 if (bpf
->protocol
== IPPROTO_ICMP
)
1332 temp
.flags
|= MATCH_ICMP_SET
;
1333 temp
.flags
|= MATCH_PORT_SRC_SET
;
1334 temp2
.src_port_min
= src_port
->min_port
;
1335 if (src_port
->max_port
) {
1336 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1337 temp2
.src_port_max
= src_port
->max_port
;
1340 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1341 if (bpf
->protocol
== IPPROTO_ICMP
)
1342 temp
.flags
|= MATCH_ICMP_SET
;
1343 temp
.flags
|= MATCH_PORT_DST_SET
;
1344 temp2
.dst_port_min
= dst_port
->min_port
;
1345 if (dst_port
->max_port
) {
1346 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1347 temp2
.dst_port_max
= dst_port
->max_port
;
1350 temp2
.proto
= bpf
->protocol
;
1353 temp
.pkt_len_min
= pkt_len
->min_port
;
1354 if (pkt_len
->max_port
)
1355 temp
.pkt_len_max
= pkt_len
->max_port
;
1356 } else if (bpf
->pkt_len_val
) {
1357 if (bpf
->pkt_len_val
->mask
)
1358 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1359 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1361 if (bpf
->tcp_flags
) {
1362 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1363 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1366 if (bpf
->dscp
->mask
)
1367 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1369 temp
.flags
|= MATCH_DSCP_SET
;
1370 temp
.dscp_value
= bpf
->dscp
->val
;
1372 if (bpf
->fragment
) {
1373 if (bpf
->fragment
->mask
)
1374 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1375 temp
.fragment
= bpf
->fragment
->val
;
1378 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1379 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1380 temp
.type
= IPSET_NET_PORT
;
1382 temp
.type
= IPSET_NET
;
1384 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1385 temp
.type
= IPSET_NET_PORT_NET
;
1387 temp
.type
= IPSET_NET_NET
;
1389 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1392 temp
.vrf_id
= bpf
->vrf_id
;
1395 bpme
->backpointer
= bpm
;
1396 /* right now, a previous entry may already exist
1397 * flush previous entry if necessary
1399 bpmer
.bpme_to_match
= bpme
;
1400 bpmer
.bpme_found
= NULL
;
1401 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1402 if (bpmer
.bpme_found
) {
1403 static struct bgp_pbr_match
*local_bpm
;
1404 static struct bgp_pbr_action
*local_bpa
;
1406 local_bpm
= bpmer
.bpme_found
->backpointer
;
1407 local_bpa
= local_bpm
->action
;
1408 bgp_pbr_flush_entry(bgp
, local_bpa
,
1409 local_bpm
, bpmer
.bpme_found
);
1413 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1415 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1416 return FLOWSPEC_DSCP
;
1417 if (type_entry
== FLOWSPEC_DSCP
)
1418 return FLOWSPEC_PKT_LEN
;
1419 if (type_entry
== FLOWSPEC_PKT_LEN
)
1420 return FLOWSPEC_FRAGMENT
;
1421 if (type_entry
== FLOWSPEC_FRAGMENT
)
1422 return FLOWSPEC_ICMP_TYPE
;
1426 static void bgp_pbr_icmp_action(struct bgp
*bgp
,
1427 struct bgp_info
*binfo
,
1428 struct bgp_pbr_filter
*bpf
,
1429 struct bgp_pbr_or_filter
*bpof
,
1434 struct bgp_pbr_range_port srcp
, dstp
;
1435 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1436 struct listnode
*tnode
, *cnode
;
1440 if (bpf
->protocol
!= IPPROTO_ICMP
)
1442 bpf
->src_port
= &srcp
;
1443 bpf
->dst_port
= &dstp
;
1444 /* parse icmp type and lookup appropriate icmp code
1445 * if no icmp code found, create as many entryes as
1446 * there are listed icmp codes for that icmp type
1448 if (!bpof
->icmp_type
) {
1450 srcp
.max_port
= 255;
1451 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1452 dstp
.min_port
= icmp_code
->val
;
1454 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1457 bgp_pbr_policyroute_remove_from_zebra_unit(
1462 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1463 srcp
.min_port
= icmp_type
->val
;
1466 /* only icmp type. create an entry only with icmp type */
1467 if (!bpof
->icmp_code
) {
1468 /* icmp type is not one of the above
1469 * forge an entry only based on the icmp type
1472 dstp
.max_port
= 255;
1474 bgp_pbr_policyroute_add_to_zebra_unit(
1478 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1482 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1483 dstp
.min_port
= icmp_code
->val
;
1485 bgp_pbr_policyroute_add_to_zebra_unit(
1489 bgp_pbr_policyroute_remove_from_zebra_unit(
1495 static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp
*bgp
,
1496 struct bgp_info
*binfo
,
1497 struct bgp_pbr_filter
*bpf
,
1498 struct bgp_pbr_or_filter
*bpof
,
1501 struct listnode
*node
, *nnode
;
1502 struct bgp_pbr_val_mask
*valmask
;
1503 uint8_t next_type_entry
;
1504 struct list
*orig_list
;
1505 struct bgp_pbr_val_mask
**target_val
;
1507 if (type_entry
== 0)
1508 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1510 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1511 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1512 orig_list
= bpof
->tcpflags
;
1513 target_val
= &bpf
->tcp_flags
;
1514 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1515 orig_list
= bpof
->dscp
;
1516 target_val
= &bpf
->dscp
;
1517 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1518 orig_list
= bpof
->pkt_len
;
1519 target_val
= &bpf
->pkt_len_val
;
1520 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1521 orig_list
= bpof
->fragment
;
1522 target_val
= &bpf
->fragment
;
1523 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1524 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1525 /* enumerate list for icmp - must be last one */
1526 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, false, NULL
, NULL
);
1529 return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
,
1534 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1535 *target_val
= valmask
;
1536 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1542 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
1543 struct bgp_info
*binfo
,
1544 struct bgp_pbr_filter
*bpf
,
1545 struct bgp_pbr_or_filter
*bpof
)
1548 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1552 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1554 FLOWSPEC_TCP_FLAGS
);
1555 else if (bpof
->dscp
)
1556 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1559 else if (bpof
->pkt_len
)
1560 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1563 else if (bpof
->fragment
)
1564 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1567 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1568 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1570 FLOWSPEC_ICMP_TYPE
);
1572 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, binfo
, bpf
);
1575 list_delete_all_node(bpof
->tcpflags
);
1577 list_delete_all_node(bpof
->dscp
);
1579 list_delete_all_node(bpof
->pkt_len
);
1581 list_delete_all_node(bpof
->fragment
);
1584 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1585 struct bgp_info
*binfo
,
1586 struct bgp_pbr_filter
*bpf
,
1590 struct bgp_pbr_match temp
;
1591 struct bgp_pbr_match_entry temp2
;
1592 struct bgp_pbr_match
*bpm
;
1593 struct bgp_pbr_match_entry
*bpme
= NULL
;
1594 struct bgp_pbr_action temp3
;
1595 struct bgp_pbr_action
*bpa
= NULL
;
1596 struct bgp_pbr_match_entry_remain bpmer
;
1597 struct bgp_pbr_range_port
*src_port
;
1598 struct bgp_pbr_range_port
*dst_port
;
1599 struct bgp_pbr_range_port
*pkt_len
;
1603 src_port
= bpf
->src_port
;
1604 dst_port
= bpf
->dst_port
;
1605 pkt_len
= bpf
->pkt_len
;
1607 if (BGP_DEBUG(zebra
, ZEBRA
)) {
1608 char bufsrc
[64], bufdst
[64];
1610 int remaining_len
= 0;
1611 char protocol_str
[16];
1613 protocol_str
[0] = '\0';
1614 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1615 bpf
->protocol
= IPPROTO_TCP
;
1617 snprintf(protocol_str
, sizeof(protocol_str
),
1618 "proto %d", bpf
->protocol
);
1620 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1621 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1623 src_port
->min_port
, 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: adding FS PBR from %s to %s, %s %s",
1682 bpf
->src
== NULL
? "<all>" :
1683 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1684 bpf
->dst
== NULL
? "<all>" :
1685 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1686 protocol_str
, buffer
);
1688 /* look for bpa first */
1689 memset(&temp3
, 0, sizeof(temp3
));
1693 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1694 temp3
.vrf_id
= bpf
->vrf_id
;
1695 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1696 bgp_pbr_action_alloc_intern
);
1698 if (bpa
->fwmark
== 0) {
1699 /* drop is handled by iptable */
1700 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1702 bpa
->installed
= true;
1704 bpa
->fwmark
= bgp_zebra_tm_get_id();
1705 bpa
->table_id
= bpa
->fwmark
;
1706 bpa
->installed
= false;
1709 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1710 /* 0 value is forbidden */
1711 bpa
->install_in_progress
= false;
1714 /* then look for bpm */
1715 memset(&temp
, 0, sizeof(temp
));
1716 temp
.vrf_id
= bpf
->vrf_id
;
1718 temp
.flags
|= MATCH_IP_SRC_SET
;
1720 temp
.flags
|= MATCH_IP_DST_SET
;
1722 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1723 if (bpf
->protocol
== IPPROTO_ICMP
)
1724 temp
.flags
|= MATCH_ICMP_SET
;
1725 temp
.flags
|= MATCH_PORT_SRC_SET
;
1727 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1728 if (bpf
->protocol
== IPPROTO_ICMP
)
1729 temp
.flags
|= MATCH_ICMP_SET
;
1730 temp
.flags
|= MATCH_PORT_DST_SET
;
1732 if (src_port
&& src_port
->max_port
)
1733 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1734 if (dst_port
&& dst_port
->max_port
)
1735 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1737 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1738 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1739 temp
.type
= IPSET_NET_PORT
;
1741 temp
.type
= IPSET_NET
;
1743 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1744 temp
.type
= IPSET_NET_PORT_NET
;
1746 temp
.type
= IPSET_NET_NET
;
1749 temp
.pkt_len_min
= pkt_len
->min_port
;
1750 if (pkt_len
->max_port
)
1751 temp
.pkt_len_max
= pkt_len
->max_port
;
1752 } else if (bpf
->pkt_len_val
) {
1753 if (bpf
->pkt_len_val
->mask
)
1754 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1755 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1757 if (bpf
->tcp_flags
) {
1758 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1759 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1762 if (bpf
->dscp
->mask
)
1763 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1765 temp
.flags
|= MATCH_DSCP_SET
;
1766 temp
.dscp_value
= bpf
->dscp
->val
;
1768 if (bpf
->fragment
) {
1769 if (bpf
->fragment
->mask
)
1770 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1771 temp
.fragment
= bpf
->fragment
->val
;
1774 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1775 bgp_pbr_match_alloc_intern
);
1777 /* new, then self allocate ipset_name and unique */
1778 if (bpm
&& bpm
->unique
== 0) {
1779 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1780 /* 0 value is forbidden */
1781 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1782 bpm
->entry_hash
= hash_create_size(8,
1783 bgp_pbr_match_entry_hash_key
,
1784 bgp_pbr_match_entry_hash_equal
,
1785 "Match Entry Hash");
1786 bpm
->installed
= false;
1788 /* unique2 should be updated too */
1789 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1790 bpm
->installed_in_iptable
= false;
1791 bpm
->install_in_progress
= false;
1792 bpm
->install_iptable_in_progress
= false;
1795 memset(&temp2
, 0, sizeof(temp2
));
1797 prefix_copy(&temp2
.src
, bpf
->src
);
1799 temp2
.src
.family
= AF_INET
;
1801 prefix_copy(&temp2
.dst
, bpf
->dst
);
1803 temp2
.dst
.family
= AF_INET
;
1804 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1805 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1806 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1807 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1808 temp2
.proto
= bpf
->protocol
;
1810 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1811 bgp_pbr_match_entry_alloc_intern
);
1812 if (bpme
&& bpme
->unique
== 0) {
1813 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1814 /* 0 value is forbidden */
1815 bpme
->backpointer
= bpm
;
1816 bpme
->installed
= false;
1817 bpme
->install_in_progress
= false;
1818 /* link bgp info to bpme */
1819 bpme
->bgp_info
= (void *)binfo
;
1822 /* BGP FS: append entry to zebra
1823 * - policies are not routing entries and as such
1824 * route replace semantics don't necessarily follow
1825 * through to policy entries
1826 * - because of that, not all policing information will be stored
1827 * into zebra. and non selected policies will be suppressed from zebra
1828 * - as consequence, in order to bring consistency
1829 * a policy will be added, then ifan ecmp policy exists,
1830 * it will be suppressed subsequently
1833 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1834 bgp_send_pbr_rule_action(bpa
, true);
1835 bgp_zebra_announce_default(bgp
, nh
,
1836 AFI_IP
, bpa
->table_id
, true);
1840 if (bpm
&& !bpm
->installed
)
1841 bgp_send_pbr_ipset_match(bpm
, true);
1843 if (bpme
&& !bpme
->installed
)
1844 bgp_send_pbr_ipset_entry_match(bpme
, true);
1847 if (bpm
&& !bpm
->installed_in_iptable
)
1848 bgp_send_pbr_iptable(bpa
, bpm
, true);
1850 /* A previous entry may already exist
1851 * flush previous entry if necessary
1853 bpmer
.bpme_to_match
= bpme
;
1854 bpmer
.bpme_found
= NULL
;
1855 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1856 if (bpmer
.bpme_found
) {
1857 static struct bgp_pbr_match
*local_bpm
;
1858 static struct bgp_pbr_action
*local_bpa
;
1860 local_bpm
= bpmer
.bpme_found
->backpointer
;
1861 local_bpa
= local_bpm
->action
;
1862 bgp_pbr_flush_entry(bgp
, local_bpa
,
1863 local_bpm
, bpmer
.bpme_found
);
1869 static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp
*bgp
,
1870 struct bgp_info
*binfo
,
1871 struct bgp_pbr_filter
*bpf
,
1872 struct bgp_pbr_or_filter
*bpof
,
1877 struct listnode
*node
, *nnode
;
1878 struct bgp_pbr_val_mask
*valmask
;
1879 uint8_t next_type_entry
;
1880 struct list
*orig_list
;
1881 struct bgp_pbr_val_mask
**target_val
;
1883 if (type_entry
== 0)
1884 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1886 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1887 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1888 orig_list
= bpof
->tcpflags
;
1889 target_val
= &bpf
->tcp_flags
;
1890 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1891 orig_list
= bpof
->dscp
;
1892 target_val
= &bpf
->dscp
;
1893 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1894 orig_list
= bpof
->pkt_len
;
1895 target_val
= &bpf
->pkt_len_val
;
1896 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1897 orig_list
= bpof
->fragment
;
1898 target_val
= &bpf
->fragment
;
1899 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1900 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1901 /* enumerate list for icmp - must be last one */
1902 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, true, nh
, rate
);
1905 return bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1906 bpf
, bpof
, nh
, rate
,
1909 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1910 *target_val
= valmask
;
1911 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1918 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1919 struct bgp_info
*binfo
,
1920 struct bgp_pbr_filter
*bpf
,
1921 struct bgp_pbr_or_filter
*bpof
,
1926 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1929 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1932 FLOWSPEC_TCP_FLAGS
);
1933 else if (bpof
->dscp
)
1934 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1938 else if (bpof
->pkt_len
)
1939 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1943 else if (bpof
->fragment
)
1944 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1948 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1949 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1950 bpf
, bpof
, nh
, rate
,
1951 FLOWSPEC_ICMP_TYPE
);
1953 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1957 list_delete_all_node(bpof
->tcpflags
);
1959 list_delete_all_node(bpof
->dscp
);
1961 list_delete_all_node(bpof
->pkt_len
);
1963 list_delete_all_node(bpof
->fragment
);
1964 if (bpof
->icmp_type
)
1965 list_delete_all_node(bpof
->icmp_type
);
1966 if (bpof
->icmp_code
)
1967 list_delete_all_node(bpof
->icmp_code
);
1970 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
1971 struct bgp_info
*binfo
,
1972 struct bgp_pbr_entry_main
*api
,
1977 int continue_loop
= 1;
1979 struct prefix
*src
= NULL
, *dst
= NULL
;
1981 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
1982 struct bgp_pbr_range_port range
, range_icmp_code
;
1983 struct bgp_pbr_range_port pkt_len
;
1984 struct bgp_pbr_filter bpf
;
1986 struct bgp_pbr_or_filter bpof
;
1987 struct bgp_pbr_val_mask bpvm
;
1989 memset(&nh
, 0, sizeof(struct nexthop
));
1990 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
1991 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
1992 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
1993 src
= &api
->src_prefix
;
1994 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
1995 dst
= &api
->dst_prefix
;
1996 memset(&nh
, 0, sizeof(struct nexthop
));
1997 nh
.vrf_id
= VRF_UNKNOWN
;
1998 if (api
->match_protocol_num
)
1999 proto
= (uint8_t)api
->protocol
[0].value
;
2000 /* if match_port is selected, then either src or dst port will be parsed
2001 * but not both at the same time
2003 if (api
->match_port_num
>= 1) {
2004 bgp_pbr_extract(api
->port
,
2005 api
->match_port_num
,
2007 srcp
= dstp
= &range
;
2008 } else if (api
->match_src_port_num
>= 1) {
2009 bgp_pbr_extract(api
->src_port
,
2010 api
->match_src_port_num
,
2014 } else if (api
->match_dst_port_num
>= 1) {
2015 bgp_pbr_extract(api
->dst_port
,
2016 api
->match_dst_port_num
,
2021 if (api
->match_icmp_type_num
>= 1) {
2022 proto
= IPPROTO_ICMP
;
2023 if (bgp_pbr_extract(api
->icmp_type
,
2024 api
->match_icmp_type_num
,
2028 bpof
.icmp_type
= list_new();
2029 bgp_pbr_extract_enumerate(api
->icmp_type
,
2030 api
->match_icmp_type_num
,
2033 FLOWSPEC_ICMP_TYPE
);
2036 if (api
->match_icmp_code_num
>= 1) {
2037 proto
= IPPROTO_ICMP
;
2038 if (bgp_pbr_extract(api
->icmp_code
,
2039 api
->match_icmp_code_num
,
2041 dstp
= &range_icmp_code
;
2043 bpof
.icmp_code
= list_new();
2044 bgp_pbr_extract_enumerate(api
->icmp_code
,
2045 api
->match_icmp_code_num
,
2048 FLOWSPEC_ICMP_CODE
);
2052 if (api
->match_tcpflags_num
) {
2053 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2054 api
->match_tcpflags_num
);
2055 if (kind_enum
== OPERATOR_UNARY_AND
) {
2056 bpf
.tcp_flags
= &bpvm
;
2057 bgp_pbr_extract_enumerate(api
->tcpflags
,
2058 api
->match_tcpflags_num
,
2061 FLOWSPEC_TCP_FLAGS
);
2062 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2063 bpof
.tcpflags
= list_new();
2064 bgp_pbr_extract_enumerate(api
->tcpflags
,
2065 api
->match_tcpflags_num
,
2068 FLOWSPEC_TCP_FLAGS
);
2071 if (api
->match_packet_length_num
) {
2074 ret
= bgp_pbr_extract(api
->packet_length
,
2075 api
->match_packet_length_num
,
2078 bpf
.pkt_len
= &pkt_len
;
2080 bpof
.pkt_len
= list_new();
2081 bgp_pbr_extract_enumerate(api
->packet_length
,
2082 api
->match_packet_length_num
,
2088 if (api
->match_dscp_num
>= 1) {
2089 bpof
.dscp
= list_new();
2090 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2092 bpof
.dscp
, FLOWSPEC_DSCP
);
2094 if (api
->match_fragment_num
) {
2095 bpof
.fragment
= list_new();
2096 bgp_pbr_extract_enumerate(api
->fragment
,
2097 api
->match_fragment_num
,
2102 bpf
.vrf_id
= api
->vrf_id
;
2105 bpf
.protocol
= proto
;
2106 bpf
.src_port
= srcp
;
2107 bpf
.dst_port
= dstp
;
2109 return bgp_pbr_policyroute_remove_from_zebra(bgp
,
2112 /* no action for add = true */
2113 for (i
= 0; i
< api
->action_num
; i
++) {
2114 switch (api
->actions
[i
].action
) {
2115 case ACTION_TRAFFICRATE
:
2117 if (api
->actions
[i
].u
.r
.rate
== 0) {
2118 nh
.vrf_id
= api
->vrf_id
;
2119 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2120 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2124 /* update rate. can be reentrant */
2125 rate
= api
->actions
[i
].u
.r
.rate
;
2126 if (BGP_DEBUG(pbr
, PBR
)) {
2127 bgp_pbr_print_policy_route(api
);
2128 zlog_warn("PBR: ignoring Set action rate %f",
2129 api
->actions
[i
].u
.r
.rate
);
2133 case ACTION_TRAFFIC_ACTION
:
2134 if (api
->actions
[i
].u
.za
.filter
2135 & TRAFFIC_ACTION_SAMPLE
) {
2136 if (BGP_DEBUG(pbr
, PBR
)) {
2137 bgp_pbr_print_policy_route(api
);
2138 zlog_warn("PBR: Sample action Ignored");
2142 if (api
->actions
[i
].u
.za
.filter
2143 & TRAFFIC_ACTION_DISTRIBUTE
) {
2144 if (BGP_DEBUG(pbr
, PBR
)) {
2145 bgp_pbr_print_policy_route(api
);
2146 zlog_warn("PBR: Distribute action Applies");
2149 /* continue forwarding entry as before
2153 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2154 /* terminate action: run other filters
2157 case ACTION_REDIRECT_IP
:
2158 nh
.type
= NEXTHOP_TYPE_IPV4
;
2159 nh
.gate
.ipv4
.s_addr
=
2160 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2161 nh
.vrf_id
= api
->vrf_id
;
2162 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2165 /* XXX combination with REDIRECT_VRF
2166 * + REDIRECT_NH_IP not done
2170 case ACTION_REDIRECT
:
2171 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2172 nh
.type
= NEXTHOP_TYPE_IPV4
;
2173 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2178 case ACTION_MARKING
:
2179 if (BGP_DEBUG(pbr
, PBR
)) {
2180 bgp_pbr_print_policy_route(api
);
2181 zlog_warn("PBR: Set DSCP %u Ignored",
2182 api
->actions
[i
].u
.marking_dscp
);
2188 if (continue_loop
== 0)
2193 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2194 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
2197 struct bgp_pbr_entry_main api
;
2198 struct bgp_info_extra
*extra
= bgp_info_extra_get(info
);
2201 return; /* IPv6 not supported */
2202 if (safi
!= SAFI_FLOWSPEC
)
2203 return; /* not supported */
2204 /* Make Zebra API structure. */
2205 memset(&api
, 0, sizeof(api
));
2206 api
.vrf_id
= bgp
->vrf_id
;
2209 if (!bgp_zebra_tm_chunk_obtained()) {
2210 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2211 zlog_err("%s: table chunk not obtained yet",
2215 /* already installed */
2216 if (nlri_update
&& extra
->bgp_fs_pbr
) {
2217 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2218 zlog_err("%s: entry %p already installed in bgp pbr",
2223 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2224 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2225 zlog_err("%s: cancel updating entry %p in bgp pbr",
2229 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2232 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2233 const struct bgp_pbr_interface
*b
)
2235 return strcmp(a
->name
, b
->name
);
2238 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2239 struct bgp_pbr_interface_head
*head
)
2241 struct bgp_pbr_interface pbr_if
;
2243 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2244 return (RB_FIND(bgp_pbr_interface_head
,
2248 /* this function resets to the default policy routing
2249 * go back to default status
2251 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2253 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2254 struct bgp_pbr_interface_head
*head
;
2255 struct bgp_pbr_interface
*pbr_if
;
2257 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2259 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2261 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2262 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2263 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2264 XFREE(MTYPE_TMP
, pbr_if
);