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
;
226 /* TCP : FIN and SYN -> val = ALL; mask = 3
227 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
228 * other variables type: dscp, pkt len, fragment
229 * - value is copied in bgp_pbr_val_mask->val value
230 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
232 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
233 int num
, uint8_t unary_operator
,
234 void *valmask
, uint8_t type_entry
)
237 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
238 struct list
*or_valmask
= NULL
;
241 if (unary_operator
== OPERATOR_UNARY_AND
) {
242 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
243 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
244 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
245 or_valmask
= (struct list
*)valmask
;
248 for (i
= 0; i
< num
; i
++) {
249 if (i
!= 0 && list
[i
].unary_operator
!=
252 if (!(list
[i
].compare_operator
&
253 OPERATOR_COMPARE_EQUAL_TO
) &&
254 !(list
[i
].compare_operator
&
255 OPERATOR_COMPARE_EXACT_MATCH
)) {
256 if ((list
[i
].compare_operator
&
257 OPERATOR_COMPARE_LESS_THAN
) &&
258 (list
[i
].compare_operator
&
259 OPERATOR_COMPARE_GREATER_THAN
)) {
260 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
261 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
263 TCP_HEADER_ALL_FLAGS
&
265 } else if (type_entry
== FLOWSPEC_DSCP
||
266 type_entry
== FLOWSPEC_PKT_LEN
||
267 type_entry
== FLOWSPEC_FRAGMENT
) {
268 and_valmask
->val
= list
[i
].value
;
269 and_valmask
->mask
= 1; /* inverse */
271 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
272 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
273 sizeof(struct bgp_pbr_val_mask
));
274 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
275 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
277 TCP_HEADER_ALL_FLAGS
&
279 } else if (type_entry
== FLOWSPEC_DSCP
||
280 type_entry
== FLOWSPEC_FRAGMENT
||
281 type_entry
== FLOWSPEC_PKT_LEN
) {
282 and_valmask
->val
= list
[i
].value
;
283 and_valmask
->mask
= 1; /* inverse */
285 listnode_add (or_valmask
, and_valmask
);
291 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
292 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
294 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
295 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
296 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
297 sizeof(struct bgp_pbr_val_mask
));
298 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
299 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
301 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
302 } else if (type_entry
== FLOWSPEC_DSCP
||
303 type_entry
== FLOWSPEC_FRAGMENT
||
304 type_entry
== FLOWSPEC_PKT_LEN
)
305 and_valmask
->val
= list
[i
].value
;
306 listnode_add(or_valmask
, and_valmask
);
309 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
310 && type_entry
== FLOWSPEC_TCP_FLAGS
)
311 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
315 /* if unary operator can either be UNARY_OR/AND/OR-AND.
316 * in the latter case, combinationf of both is not handled
318 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
319 int num
, uint8_t unary_operator
,
320 void *valmask
, uint8_t type_entry
)
323 uint8_t unary_operator_val
= unary_operator
;
324 bool double_check
= false;
326 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
327 (unary_operator
& OPERATOR_UNARY_AND
)) {
328 unary_operator_val
= OPERATOR_UNARY_AND
;
331 unary_operator_val
= unary_operator
;
332 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
333 valmask
, type_entry
);
334 if (!ret
&& double_check
)
335 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
342 /* returns the unary operator that is in the list
343 * return 0 if both operators are used
345 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
350 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
352 for (i
= 0; i
< num
; i
++) {
355 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
356 unary_operator
= OPERATOR_UNARY_OR
;
357 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
358 && unary_operator
== OPERATOR_UNARY_OR
) ||
359 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
360 && unary_operator
== OPERATOR_UNARY_AND
))
363 return unary_operator
;
367 /* return true if extraction ok
369 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
371 struct bgp_pbr_range_port
*range
)
374 bool exact_match
= false;
377 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
381 for (i
= 0; i
< num
; i
++) {
382 if (i
!= 0 && (list
[i
].compare_operator
==
383 OPERATOR_COMPARE_EQUAL_TO
))
385 if (i
== 0 && (list
[i
].compare_operator
==
386 OPERATOR_COMPARE_EQUAL_TO
)) {
388 range
->min_port
= list
[i
].value
;
391 if (exact_match
== true && i
> 0)
393 if (list
[i
].compare_operator
==
394 (OPERATOR_COMPARE_GREATER_THAN
+
395 OPERATOR_COMPARE_EQUAL_TO
)) {
397 range
->min_port
= list
[i
].value
;
398 } else if (list
[i
].compare_operator
==
399 (OPERATOR_COMPARE_LESS_THAN
+
400 OPERATOR_COMPARE_EQUAL_TO
)) {
402 range
->max_port
= list
[i
].value
;
403 } else if (list
[i
].compare_operator
==
404 OPERATOR_COMPARE_LESS_THAN
) {
406 range
->max_port
= list
[i
].value
- 1;
407 } else if (list
[i
].compare_operator
==
408 OPERATOR_COMPARE_GREATER_THAN
) {
410 range
->min_port
= list
[i
].value
+ 1;
416 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
418 bool enumerate_icmp
= false;
420 /* because bgp pbr entry may contain unsupported
421 * combinations, a message will be displayed here if
423 * for now, only match/set supported is
424 * - combination src/dst => redirect nexthop [ + rate]
425 * - combination src/dst => redirect VRF [ + rate]
426 * - combination src/dst => drop
427 * - combination srcport + @IP
429 if (api
->match_protocol_num
> 1) {
430 if (BGP_DEBUG(pbr
, PBR
))
431 zlog_debug("BGP: match protocol operations:"
432 "multiple protocols ( %d). ignoring.",
433 api
->match_protocol_num
);
436 if (api
->match_protocol_num
== 1 &&
437 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
438 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
439 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
440 if (BGP_DEBUG(pbr
, PBR
))
441 zlog_debug("BGP: match protocol operations:"
442 "protocol (%d) not supported. ignoring",
443 api
->match_protocol_num
);
446 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
447 if (BGP_DEBUG(pbr
, PBR
))
448 zlog_debug("BGP: match src port operations:"
449 "too complex. ignoring.");
452 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
453 if (BGP_DEBUG(pbr
, PBR
))
454 zlog_debug("BGP: match dst port operations:"
455 "too complex. ignoring.");
458 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
459 api
->match_tcpflags_num
,
461 OPERATOR_UNARY_OR
, NULL
,
462 FLOWSPEC_TCP_FLAGS
)) {
463 if (BGP_DEBUG(pbr
, PBR
))
464 zlog_debug("BGP: match tcp flags:"
465 "too complex. ignoring.");
468 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
469 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
470 api
->match_icmp_type_num
,
471 OPERATOR_UNARY_OR
, NULL
,
472 FLOWSPEC_ICMP_TYPE
)) {
473 if (BGP_DEBUG(pbr
, PBR
))
474 zlog_debug("BGP: match icmp type operations:"
475 "too complex. ignoring.");
478 enumerate_icmp
= true;
480 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
481 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
482 api
->match_icmp_code_num
,
483 OPERATOR_UNARY_OR
, NULL
,
484 FLOWSPEC_ICMP_CODE
)) {
485 if (BGP_DEBUG(pbr
, PBR
))
486 zlog_debug("BGP: match icmp code operations:"
487 "too complex. ignoring.");
489 } else if (api
->match_icmp_type_num
> 1 &&
490 enumerate_icmp
== false) {
491 if (BGP_DEBUG(pbr
, PBR
))
492 zlog_debug("BGP: match icmp code is enumerate"
493 ", and icmp type is not."
494 " too complex. ignoring.");
498 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
499 if (BGP_DEBUG(pbr
, PBR
))
500 zlog_debug("BGP: match port operations:"
501 "too complex. ignoring.");
504 if (api
->match_packet_length_num
) {
507 ret
= bgp_pbr_extract(api
->packet_length
,
508 api
->match_packet_length_num
, NULL
);
510 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
511 api
->match_packet_length_num
,
513 | OPERATOR_UNARY_AND
,
514 NULL
, FLOWSPEC_PKT_LEN
);
516 if (BGP_DEBUG(pbr
, PBR
))
517 zlog_debug("BGP: match packet length operations:"
518 "too complex. ignoring.");
522 if (api
->match_dscp_num
) {
523 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
524 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
525 NULL
, FLOWSPEC_DSCP
)) {
526 if (BGP_DEBUG(pbr
, PBR
))
527 zlog_debug("BGP: match DSCP operations:"
528 "too complex. ignoring.");
532 if (api
->match_fragment_num
) {
536 success
= bgp_pbr_extract_enumerate(api
->fragment
,
537 api
->match_fragment_num
,
539 | OPERATOR_UNARY_AND
,
540 NULL
, FLOWSPEC_FRAGMENT
);
544 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
545 if (api
->fragment
[i
].value
!= 1 &&
546 api
->fragment
[i
].value
!= 2 &&
547 api
->fragment
[i
].value
!= 4 &&
548 api
->fragment
[i
].value
!= 8) {
551 "Value not valid (%d) for this implementation",
552 api
->fragment
[i
].value
);
556 sprintf(fail_str
, "too complex. ignoring");
558 if (BGP_DEBUG(pbr
, PBR
))
559 zlog_debug("BGP: match fragment operation (%d) %s",
560 api
->match_fragment_num
,
566 /* no combinations with both src_port and dst_port
567 * or port with src_port and dst_port
569 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
570 api
->match_port_num
> 3) {
571 if (BGP_DEBUG(pbr
, PBR
))
572 zlog_debug("BGP: match multiple port operations:"
573 " too complex. ignoring.");
576 if ((api
->match_src_port_num
|| api
->match_dst_port_num
577 || api
->match_port_num
) && (api
->match_icmp_type_num
578 || api
->match_icmp_code_num
)) {
579 if (BGP_DEBUG(pbr
, PBR
))
580 zlog_debug("BGP: match multiple port/imcp operations:"
581 " too complex. ignoring.");
584 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
585 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
586 if (BGP_DEBUG(pbr
, PBR
)) {
587 bgp_pbr_print_policy_route(api
);
588 zlog_debug("BGP: match actions without src"
589 " or dst address can not operate."
597 /* return -1 if build or validation failed */
598 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
599 struct bgp_info
*info
,
600 struct bgp_pbr_entry_main
*api
)
603 int i
, action_count
= 0;
604 struct ecommunity
*ecom
;
605 struct ecommunity_val
*ecom_eval
;
606 struct bgp_pbr_entry_action
*api_action
;
607 struct prefix
*src
= NULL
, *dst
= NULL
;
608 int valid_prefix
= 0;
611 /* extract match from flowspec entries */
612 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
613 p
->u
.prefix_flowspec
.prefixlen
, api
);
616 /* extract actiosn from flowspec ecom list */
617 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
618 ecom
= info
->attr
->ecommunity
;
619 for (i
= 0; i
< ecom
->size
; i
++) {
620 ecom_eval
= (struct ecommunity_val
*)
621 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
623 if (action_count
> ACTIONS_MAX_NUM
) {
624 if (BGP_DEBUG(pbr
, PBR_ERROR
))
625 zlog_err("%s: flowspec actions exceeds limit (max %u)",
626 __func__
, action_count
);
629 api_action
= &api
->actions
[action_count
- 1];
631 if ((ecom_eval
->val
[1] ==
632 (char)ECOMMUNITY_REDIRECT_VRF
) &&
633 (ecom_eval
->val
[0] ==
634 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
636 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
638 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
639 struct ecommunity
*eckey
= ecommunity_new();
640 struct ecommunity_val ecom_copy
;
642 memcpy(&ecom_copy
, ecom_eval
,
643 sizeof(struct ecommunity_val
));
645 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
646 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
647 ecommunity_add_val(eckey
, &ecom_copy
);
649 api_action
->action
= ACTION_REDIRECT
;
650 api_action
->u
.redirect_vrf
=
651 get_first_vrf_for_redirect_with_rt(
653 ecommunity_free(&eckey
);
654 } else if ((ecom_eval
->val
[0] ==
655 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
656 (ecom_eval
->val
[1] ==
657 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
658 api_action
->action
= ACTION_REDIRECT_IP
;
659 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
660 info
->attr
->nexthop
.s_addr
;
661 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
663 if (ecom_eval
->val
[0] !=
664 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
666 ret
= ecommunity_fill_pbr_action(ecom_eval
,
675 /* validate if incoming matc/action is compatible
676 * with our policy routing engine
678 if (!bgp_pbr_validate_policy_route(api
))
681 /* check inconsistency in the match rule */
682 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
683 src
= &api
->src_prefix
;
684 afi
= family2afi(src
->family
);
687 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
688 dst
= &api
->dst_prefix
;
689 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
690 if (BGP_DEBUG(pbr
, PBR
)) {
691 bgp_pbr_print_policy_route(api
);
692 zlog_debug("%s: inconsistency:"
693 " no match for afi src and dst (%u/%u)",
694 __func__
, afi
, family2afi(dst
->family
));
702 static void bgp_pbr_match_entry_free(void *arg
)
704 struct bgp_pbr_match_entry
*bpme
;
706 bpme
= (struct bgp_pbr_match_entry
*)arg
;
708 if (bpme
->installed
) {
709 bgp_send_pbr_ipset_entry_match(bpme
, false);
710 bpme
->installed
= false;
711 bpme
->backpointer
= NULL
;
713 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
716 static void bgp_pbr_match_free(void *arg
)
718 struct bgp_pbr_match
*bpm
;
720 bpm
= (struct bgp_pbr_match
*)arg
;
722 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
724 if (hashcount(bpm
->entry_hash
) == 0) {
725 /* delete iptable entry first */
726 /* then delete ipset match */
727 if (bpm
->installed
) {
728 if (bpm
->installed_in_iptable
) {
729 bgp_send_pbr_iptable(bpm
->action
,
731 bpm
->installed_in_iptable
= false;
732 bpm
->action
->refcnt
--;
734 bgp_send_pbr_ipset_match(bpm
, false);
735 bpm
->installed
= false;
739 hash_free(bpm
->entry_hash
);
741 XFREE(MTYPE_PBR_MATCH
, bpm
);
744 static void *bgp_pbr_match_alloc_intern(void *arg
)
746 struct bgp_pbr_match
*bpm
, *new;
748 bpm
= (struct bgp_pbr_match
*)arg
;
750 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
751 memcpy(new, bpm
, sizeof(*bpm
));
756 static void bgp_pbr_action_free(void *arg
)
758 struct bgp_pbr_action
*bpa
;
760 bpa
= (struct bgp_pbr_action
*)arg
;
762 if (bpa
->refcnt
== 0) {
763 if (bpa
->installed
&& bpa
->table_id
!= 0) {
764 bgp_send_pbr_rule_action(bpa
, false);
765 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
769 bpa
->installed
= false;
772 XFREE(MTYPE_PBR_ACTION
, bpa
);
775 static void *bgp_pbr_action_alloc_intern(void *arg
)
777 struct bgp_pbr_action
*bpa
, *new;
779 bpa
= (struct bgp_pbr_action
*)arg
;
781 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
783 memcpy(new, bpa
, sizeof(*bpa
));
788 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
790 struct bgp_pbr_match_entry
*bpme
, *new;
792 bpme
= (struct bgp_pbr_match_entry
*)arg
;
794 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
796 memcpy(new, bpme
, sizeof(*bpme
));
801 uint32_t bgp_pbr_match_hash_key(void *arg
)
803 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
806 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
807 key
= jhash_1word(pbm
->flags
, key
);
808 key
= jhash_1word(pbm
->pkt_len_min
, key
);
809 key
= jhash_1word(pbm
->pkt_len_max
, key
);
810 key
= jhash_1word(pbm
->tcp_flags
, key
);
811 key
= jhash_1word(pbm
->tcp_mask_flags
, key
);
812 key
= jhash_1word(pbm
->dscp_value
, key
);
813 key
= jhash_1word(pbm
->fragment
, key
);
814 return jhash_1word(pbm
->type
, key
);
817 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
819 const struct bgp_pbr_match
*r1
, *r2
;
821 r1
= (const struct bgp_pbr_match
*)arg1
;
822 r2
= (const struct bgp_pbr_match
*)arg2
;
824 if (r1
->vrf_id
!= r2
->vrf_id
)
827 if (r1
->type
!= r2
->type
)
830 if (r1
->flags
!= r2
->flags
)
833 if (r1
->action
!= r2
->action
)
836 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
839 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
842 if (r1
->tcp_flags
!= r2
->tcp_flags
)
845 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
848 if (r1
->dscp_value
!= r2
->dscp_value
)
851 if (r1
->fragment
!= r2
->fragment
)
856 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
858 struct bgp_pbr_match_entry
*pbme
;
861 pbme
= (struct bgp_pbr_match_entry
*)arg
;
862 key
= prefix_hash_key(&pbme
->src
);
863 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
864 key
= jhash(&pbme
->dst_port_min
, 2, key
);
865 key
= jhash(&pbme
->src_port_min
, 2, key
);
866 key
= jhash(&pbme
->dst_port_max
, 2, key
);
867 key
= jhash(&pbme
->src_port_max
, 2, key
);
868 key
= jhash(&pbme
->proto
, 1, key
);
873 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
875 const struct bgp_pbr_match_entry
*r1
, *r2
;
877 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
878 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
880 /* on updates, comparing
881 * backpointer is not necessary
884 /* unique value is self calculated
887 /* rate is ignored for now
890 if (!prefix_same(&r1
->src
, &r2
->src
))
893 if (!prefix_same(&r1
->dst
, &r2
->dst
))
896 if (r1
->src_port_min
!= r2
->src_port_min
)
899 if (r1
->dst_port_min
!= r2
->dst_port_min
)
902 if (r1
->src_port_max
!= r2
->src_port_max
)
905 if (r1
->dst_port_max
!= r2
->dst_port_max
)
908 if (r1
->proto
!= r2
->proto
)
914 uint32_t bgp_pbr_action_hash_key(void *arg
)
916 struct bgp_pbr_action
*pbra
;
919 pbra
= (struct bgp_pbr_action
*)arg
;
920 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
921 key
= jhash_1word(pbra
->fwmark
, key
);
925 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
927 const struct bgp_pbr_action
*r1
, *r2
;
929 r1
= (const struct bgp_pbr_action
*)arg1
;
930 r2
= (const struct bgp_pbr_action
*)arg2
;
932 /* unique value is self calculated
933 * table and fwmark is self calculated
936 if (r1
->vrf_id
!= r2
->vrf_id
)
939 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
944 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
947 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
948 struct bgp_pbr_action_unique bpau
;
950 if (!bgp
|| unique
== 0)
952 bpau
.unique
= unique
;
953 bpau
.bpa_found
= NULL
;
954 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
955 return bpau
.bpa_found
;
958 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
961 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
962 struct bgp_pbr_match_unique bpmu
;
964 if (!bgp
|| unique
== 0)
966 bpmu
.unique
= unique
;
967 bpmu
.bpm_found
= NULL
;
968 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
969 return bpmu
.bpm_found
;
972 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
976 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
977 struct bgp_pbr_match_entry_unique bpmeu
;
978 struct bgp_pbr_match_ipsetname bpmi
;
980 if (!bgp
|| unique
== 0)
982 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
983 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
984 bpmi
.bpm_found
= NULL
;
985 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
986 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
989 bpmeu
.bpme_found
= NULL
;
990 bpmeu
.unique
= unique
;
991 hash_walk(bpmi
.bpm_found
->entry_hash
,
992 bgp_pbr_match_entry_walkcb
, &bpmeu
);
993 return bpmeu
.bpme_found
;
996 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
999 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1000 struct bgp_pbr_match_iptable_unique bpmiu
;
1002 if (!bgp
|| unique
== 0)
1004 bpmiu
.unique
= unique
;
1005 bpmiu
.bpm_found
= NULL
;
1006 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1007 return bpmiu
.bpm_found
;
1010 void bgp_pbr_cleanup(struct bgp
*bgp
)
1012 if (bgp
->pbr_match_hash
) {
1013 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1014 hash_free(bgp
->pbr_match_hash
);
1015 bgp
->pbr_match_hash
= NULL
;
1017 if (bgp
->pbr_action_hash
) {
1018 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1019 hash_free(bgp
->pbr_action_hash
);
1020 bgp
->pbr_action_hash
= NULL
;
1022 if (bgp
->bgp_pbr_cfg
== NULL
)
1024 bgp_pbr_reset(bgp
, AFI_IP
);
1025 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1026 bgp
->bgp_pbr_cfg
= NULL
;
1029 void bgp_pbr_init(struct bgp
*bgp
)
1031 bgp
->pbr_match_hash
=
1032 hash_create_size(8, bgp_pbr_match_hash_key
,
1033 bgp_pbr_match_hash_equal
,
1035 bgp
->pbr_action_hash
=
1036 hash_create_size(8, bgp_pbr_action_hash_key
,
1037 bgp_pbr_action_hash_equal
,
1038 "Match Hash Entry");
1040 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1041 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1044 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1047 char return_string
[512];
1048 char *ptr
= return_string
;
1052 ptr
+= sprintf(ptr
, "MATCH : ");
1053 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1054 struct prefix
*p
= &(api
->src_prefix
);
1056 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1057 INCREMENT_DISPLAY(ptr
, nb_items
);
1059 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1060 struct prefix
*p
= &(api
->dst_prefix
);
1062 INCREMENT_DISPLAY(ptr
, nb_items
);
1063 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1066 if (api
->match_protocol_num
)
1067 INCREMENT_DISPLAY(ptr
, nb_items
);
1068 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1069 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1070 i
> 0 ? NULL
: "@proto ");
1072 if (api
->match_src_port_num
)
1073 INCREMENT_DISPLAY(ptr
, nb_items
);
1074 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1075 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1076 i
> 0 ? NULL
: "@srcport ");
1078 if (api
->match_dst_port_num
)
1079 INCREMENT_DISPLAY(ptr
, nb_items
);
1080 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1081 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1082 i
> 0 ? NULL
: "@dstport ");
1084 if (api
->match_port_num
)
1085 INCREMENT_DISPLAY(ptr
, nb_items
);
1086 for (i
= 0; i
< api
->match_port_num
; i
++)
1087 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1088 i
> 0 ? NULL
: "@port ");
1090 if (api
->match_icmp_type_num
)
1091 INCREMENT_DISPLAY(ptr
, nb_items
);
1092 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1093 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1094 i
> 0 ? NULL
: "@icmptype ");
1096 if (api
->match_icmp_code_num
)
1097 INCREMENT_DISPLAY(ptr
, nb_items
);
1098 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1099 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1100 i
> 0 ? NULL
: "@icmpcode ");
1102 if (api
->match_packet_length_num
)
1103 INCREMENT_DISPLAY(ptr
, nb_items
);
1104 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1105 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1106 i
> 0 ? NULL
: "@plen ");
1108 if (api
->match_dscp_num
)
1109 INCREMENT_DISPLAY(ptr
, nb_items
);
1110 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1111 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1112 i
> 0 ? NULL
: "@dscp ");
1114 if (api
->match_tcpflags_num
)
1115 INCREMENT_DISPLAY(ptr
, nb_items
);
1116 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1117 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1118 i
> 0 ? NULL
: "@tcpflags ");
1120 if (api
->match_fragment_num
)
1121 INCREMENT_DISPLAY(ptr
, nb_items
);
1122 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1123 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1124 i
> 0 ? NULL
: "@fragment ");
1126 ptr
= return_string
;
1128 ptr
+= sprintf(ptr
, "; ");
1129 if (api
->action_num
)
1130 ptr
+= sprintf(ptr
, "SET : ");
1132 for (i
= 0; i
< api
->action_num
; i
++) {
1133 switch (api
->actions
[i
].action
) {
1134 case ACTION_TRAFFICRATE
:
1135 INCREMENT_DISPLAY(ptr
, nb_items
);
1136 ptr
+= sprintf(ptr
, "@set rate %f",
1137 api
->actions
[i
].u
.r
.rate
);
1139 case ACTION_TRAFFIC_ACTION
:
1140 INCREMENT_DISPLAY(ptr
, nb_items
);
1141 ptr
+= sprintf(ptr
, "@action ");
1142 if (api
->actions
[i
].u
.za
.filter
1143 & TRAFFIC_ACTION_TERMINATE
)
1145 " terminate (apply filter(s))");
1146 if (api
->actions
[i
].u
.za
.filter
1147 & TRAFFIC_ACTION_DISTRIBUTE
)
1148 ptr
+= sprintf(ptr
, " distribute");
1149 if (api
->actions
[i
].u
.za
.filter
1150 & TRAFFIC_ACTION_SAMPLE
)
1151 ptr
+= sprintf(ptr
, " sample");
1153 case ACTION_REDIRECT_IP
:
1154 INCREMENT_DISPLAY(ptr
, nb_items
);
1155 char local_buff
[INET_ADDRSTRLEN
];
1157 if (inet_ntop(AF_INET
,
1158 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1159 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1161 "@redirect ip nh %s", local_buff
);
1163 case ACTION_REDIRECT
:
1164 INCREMENT_DISPLAY(ptr
, nb_items
);
1165 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1166 api
->actions
[i
].u
.redirect_vrf
);
1168 case ACTION_MARKING
:
1169 INCREMENT_DISPLAY(ptr
, nb_items
);
1170 ptr
+= sprintf(ptr
, "@set dscp %u",
1171 api
->actions
[i
].u
.marking_dscp
);
1177 zlog_info("%s", return_string
);
1180 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1181 struct bgp_pbr_match
*bpm
,
1182 struct bgp_pbr_match_entry
*bpme
)
1184 /* if bpme is null, bpm is also null
1188 /* ipset del entry */
1189 if (bpme
->installed
) {
1190 bgp_send_pbr_ipset_entry_match(bpme
, false);
1191 bpme
->installed
= false;
1192 bpme
->backpointer
= NULL
;
1193 if (bpme
->bgp_info
) {
1194 struct bgp_info
*bgp_info
;
1195 struct bgp_info_extra
*extra
;
1197 /* unlink bgp_info to bpme */
1198 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
1199 extra
= bgp_info_extra_get(bgp_info
);
1200 extra
->bgp_fs_pbr
= NULL
;
1201 bpme
->bgp_info
= NULL
;
1204 hash_release(bpm
->entry_hash
, bpme
);
1205 if (hashcount(bpm
->entry_hash
) == 0) {
1206 /* delete iptable entry first */
1207 /* then delete ipset match */
1208 if (bpm
->installed
) {
1209 if (bpm
->installed_in_iptable
) {
1210 bgp_send_pbr_iptable(bpm
->action
,
1212 bpm
->installed_in_iptable
= false;
1213 bpm
->action
->refcnt
--;
1215 bgp_send_pbr_ipset_match(bpm
, false);
1216 bpm
->installed
= false;
1219 hash_release(bgp
->pbr_match_hash
, bpm
);
1220 /* XXX release pbr_match_action if not used
1221 * note that drop does not need to call send_pbr_action
1224 if (bpa
->refcnt
== 0) {
1225 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1226 bgp_send_pbr_rule_action(bpa
, false);
1227 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1231 bpa
->installed
= false;
1236 struct bgp_pbr_match_entry_remain
{
1237 struct bgp_pbr_match_entry
*bpme_to_match
;
1238 struct bgp_pbr_match_entry
*bpme_found
;
1241 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1243 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1244 struct bgp_pbr_match_entry_remain
*bpmer
=
1245 (struct bgp_pbr_match_entry_remain
*)arg
;
1246 struct bgp_pbr_match
*bpm_temp
;
1247 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1249 if (!bpme
->backpointer
||
1250 bpm
== bpme
->backpointer
||
1251 bpme
->backpointer
->action
== bpm
->action
)
1252 return HASHWALK_CONTINUE
;
1253 /* ensure bpm other characteristics are equal */
1254 bpm_temp
= bpme
->backpointer
;
1255 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1256 bpm_temp
->type
!= bpm
->type
||
1257 bpm_temp
->flags
!= bpm
->flags
)
1258 return HASHWALK_CONTINUE
;
1260 /* look for remaining bpme */
1261 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1262 if (!bpmer
->bpme_found
)
1263 return HASHWALK_CONTINUE
;
1264 return HASHWALK_ABORT
;
1267 static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp
*bgp
,
1268 struct bgp_info
*binfo
,
1269 struct bgp_pbr_filter
*bpf
)
1271 struct bgp_pbr_match temp
;
1272 struct bgp_pbr_match_entry temp2
;
1273 struct bgp_pbr_match
*bpm
;
1274 struct bgp_pbr_match_entry
*bpme
;
1275 struct bgp_pbr_match_entry_remain bpmer
;
1276 struct bgp_pbr_range_port
*src_port
;
1277 struct bgp_pbr_range_port
*dst_port
;
1278 struct bgp_pbr_range_port
*pkt_len
;
1282 src_port
= bpf
->src_port
;
1283 dst_port
= bpf
->dst_port
;
1284 pkt_len
= bpf
->pkt_len
;
1286 /* as we don't know information from EC
1287 * look for bpm that have the bpm
1288 * with vrf_id characteristics
1290 memset(&temp2
, 0, sizeof(temp2
));
1291 memset(&temp
, 0, sizeof(temp
));
1293 temp
.flags
|= MATCH_IP_SRC_SET
;
1294 prefix_copy(&temp2
.src
, bpf
->src
);
1296 temp2
.src
.family
= AF_INET
;
1298 temp
.flags
|= MATCH_IP_DST_SET
;
1299 prefix_copy(&temp2
.dst
, bpf
->dst
);
1301 temp2
.dst
.family
= AF_INET
;
1302 if (src_port
&& src_port
->min_port
) {
1303 temp
.flags
|= MATCH_PORT_SRC_SET
;
1304 temp2
.src_port_min
= src_port
->min_port
;
1305 if (src_port
->max_port
) {
1306 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1307 temp2
.src_port_max
= src_port
->max_port
;
1310 if (dst_port
&& dst_port
->min_port
) {
1311 temp
.flags
|= MATCH_PORT_DST_SET
;
1312 temp2
.dst_port_min
= dst_port
->min_port
;
1313 if (dst_port
->max_port
) {
1314 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1315 temp2
.dst_port_max
= dst_port
->max_port
;
1318 temp2
.proto
= bpf
->protocol
;
1321 temp
.pkt_len_min
= pkt_len
->min_port
;
1322 if (pkt_len
->max_port
)
1323 temp
.pkt_len_max
= pkt_len
->max_port
;
1324 } else if (bpf
->pkt_len_val
) {
1325 if (bpf
->pkt_len_val
->mask
)
1326 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1327 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1329 if (bpf
->tcp_flags
) {
1330 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1331 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1334 if (bpf
->dscp
->mask
)
1335 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1337 temp
.flags
|= MATCH_DSCP_SET
;
1338 temp
.dscp_value
= bpf
->dscp
->val
;
1340 if (bpf
->fragment
) {
1341 if (bpf
->fragment
->mask
)
1342 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1343 temp
.fragment
= bpf
->fragment
->val
;
1346 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1347 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1348 temp
.type
= IPSET_NET_PORT
;
1350 temp
.type
= IPSET_NET
;
1352 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1353 temp
.type
= IPSET_NET_PORT_NET
;
1355 temp
.type
= IPSET_NET_NET
;
1357 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1360 temp
.vrf_id
= bpf
->vrf_id
;
1363 bpme
->backpointer
= bpm
;
1364 /* right now, a previous entry may already exist
1365 * flush previous entry if necessary
1367 bpmer
.bpme_to_match
= bpme
;
1368 bpmer
.bpme_found
= NULL
;
1369 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1370 if (bpmer
.bpme_found
) {
1371 static struct bgp_pbr_match
*local_bpm
;
1372 static struct bgp_pbr_action
*local_bpa
;
1374 local_bpm
= bpmer
.bpme_found
->backpointer
;
1375 local_bpa
= local_bpm
->action
;
1376 bgp_pbr_flush_entry(bgp
, local_bpa
,
1377 local_bpm
, bpmer
.bpme_found
);
1381 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1383 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1384 return FLOWSPEC_DSCP
;
1385 if (type_entry
== FLOWSPEC_DSCP
)
1386 return FLOWSPEC_PKT_LEN
;
1387 if (type_entry
== FLOWSPEC_PKT_LEN
)
1388 return FLOWSPEC_FRAGMENT
;
1392 static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp
*bgp
,
1393 struct bgp_info
*binfo
,
1394 struct bgp_pbr_filter
*bpf
,
1395 struct bgp_pbr_or_filter
*bpof
,
1398 struct listnode
*node
, *nnode
;
1399 struct bgp_pbr_val_mask
*valmask
;
1400 uint8_t next_type_entry
;
1401 struct list
*orig_list
;
1402 struct bgp_pbr_val_mask
**target_val
;
1404 if (type_entry
== 0)
1405 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1407 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1408 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1409 orig_list
= bpof
->tcpflags
;
1410 target_val
= &bpf
->tcp_flags
;
1411 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1412 orig_list
= bpof
->dscp
;
1413 target_val
= &bpf
->dscp
;
1414 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1415 orig_list
= bpof
->pkt_len
;
1416 target_val
= &bpf
->pkt_len_val
;
1417 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1418 orig_list
= bpof
->fragment
;
1419 target_val
= &bpf
->fragment
;
1421 return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
,
1426 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1427 *target_val
= valmask
;
1428 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1434 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
1435 struct bgp_info
*binfo
,
1436 struct bgp_pbr_filter
*bpf
,
1437 struct bgp_pbr_or_filter
*bpof
)
1440 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1444 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1446 FLOWSPEC_TCP_FLAGS
);
1447 else if (bpof
->dscp
)
1448 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1451 else if (bpof
->pkt_len
)
1452 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1455 else if (bpof
->fragment
)
1456 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1460 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, binfo
, bpf
);
1463 list_delete_all_node(bpof
->tcpflags
);
1465 list_delete_all_node(bpof
->dscp
);
1467 list_delete_all_node(bpof
->pkt_len
);
1469 list_delete_all_node(bpof
->fragment
);
1472 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1473 struct bgp_info
*binfo
,
1474 struct bgp_pbr_filter
*bpf
,
1478 struct bgp_pbr_match temp
;
1479 struct bgp_pbr_match_entry temp2
;
1480 struct bgp_pbr_match
*bpm
;
1481 struct bgp_pbr_match_entry
*bpme
= NULL
;
1482 struct bgp_pbr_action temp3
;
1483 struct bgp_pbr_action
*bpa
= NULL
;
1484 struct bgp_pbr_match_entry_remain bpmer
;
1485 struct bgp_pbr_range_port
*src_port
;
1486 struct bgp_pbr_range_port
*dst_port
;
1487 struct bgp_pbr_range_port
*pkt_len
;
1491 src_port
= bpf
->src_port
;
1492 dst_port
= bpf
->dst_port
;
1493 pkt_len
= bpf
->pkt_len
;
1495 if (BGP_DEBUG(zebra
, ZEBRA
)) {
1496 char bufsrc
[64], bufdst
[64];
1498 int remaining_len
= 0;
1499 char protocol_str
[16];
1501 protocol_str
[0] = '\0';
1502 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1503 bpf
->protocol
= IPPROTO_TCP
;
1505 snprintf(protocol_str
, sizeof(protocol_str
),
1506 "proto %d", bpf
->protocol
);
1508 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1509 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1511 src_port
->min_port
, dst_port
->min_port
);
1512 else if (bpf
->protocol
== IPPROTO_UDP
||
1513 bpf
->protocol
== IPPROTO_TCP
) {
1515 if (src_port
&& src_port
->min_port
)
1516 remaining_len
+= snprintf(buffer
,
1520 src_port
->max_port
?
1521 src_port
->max_port
:
1522 src_port
->min_port
);
1523 if (dst_port
&& dst_port
->min_port
)
1524 remaining_len
+= snprintf(buffer
+
1530 dst_port
->max_port
?
1531 dst_port
->max_port
:
1532 dst_port
->min_port
);
1534 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1535 remaining_len
+= snprintf(buffer
+ remaining_len
,
1543 } else if (bpf
->pkt_len_val
) {
1544 remaining_len
+= snprintf(buffer
+ remaining_len
,
1548 bpf
->pkt_len_val
->mask
1550 bpf
->pkt_len_val
->val
);
1552 if (bpf
->tcp_flags
) {
1553 remaining_len
+= snprintf(buffer
+ remaining_len
,
1557 bpf
->tcp_flags
->val
,
1558 bpf
->tcp_flags
->mask
);
1561 snprintf(buffer
+ remaining_len
,
1569 zlog_info("BGP: adding FS PBR from %s to %s, %s %s",
1570 bpf
->src
== NULL
? "<all>" :
1571 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1572 bpf
->dst
== NULL
? "<all>" :
1573 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1574 protocol_str
, buffer
);
1576 /* look for bpa first */
1577 memset(&temp3
, 0, sizeof(temp3
));
1581 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1582 temp3
.vrf_id
= bpf
->vrf_id
;
1583 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1584 bgp_pbr_action_alloc_intern
);
1586 if (bpa
->fwmark
== 0) {
1587 /* drop is handled by iptable */
1588 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1590 bpa
->installed
= true;
1592 bpa
->fwmark
= bgp_zebra_tm_get_id();
1593 bpa
->table_id
= bpa
->fwmark
;
1594 bpa
->installed
= false;
1597 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1598 /* 0 value is forbidden */
1599 bpa
->install_in_progress
= false;
1602 /* then look for bpm */
1603 memset(&temp
, 0, sizeof(temp
));
1604 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1605 if ((src_port
&& src_port
->min_port
) ||
1606 (dst_port
&& dst_port
->min_port
))
1607 temp
.type
= IPSET_NET_PORT
;
1609 temp
.type
= IPSET_NET
;
1611 if ((src_port
&& src_port
->min_port
) ||
1612 (dst_port
&& dst_port
->min_port
))
1613 temp
.type
= IPSET_NET_PORT_NET
;
1615 temp
.type
= IPSET_NET_NET
;
1617 temp
.vrf_id
= bpf
->vrf_id
;
1619 temp
.flags
|= MATCH_IP_SRC_SET
;
1621 temp
.flags
|= MATCH_IP_DST_SET
;
1623 if (src_port
&& src_port
->min_port
)
1624 temp
.flags
|= MATCH_PORT_SRC_SET
;
1625 if (dst_port
&& dst_port
->min_port
)
1626 temp
.flags
|= MATCH_PORT_DST_SET
;
1627 if (src_port
&& src_port
->max_port
)
1628 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1629 if (dst_port
&& dst_port
->max_port
)
1630 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1632 temp
.pkt_len_min
= pkt_len
->min_port
;
1633 if (pkt_len
->max_port
)
1634 temp
.pkt_len_max
= pkt_len
->max_port
;
1635 } else if (bpf
->pkt_len_val
) {
1636 if (bpf
->pkt_len_val
->mask
)
1637 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1638 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1640 if (bpf
->tcp_flags
) {
1641 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1642 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1645 if (bpf
->dscp
->mask
)
1646 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1648 temp
.flags
|= MATCH_DSCP_SET
;
1649 temp
.dscp_value
= bpf
->dscp
->val
;
1651 if (bpf
->fragment
) {
1652 if (bpf
->fragment
->mask
)
1653 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1654 temp
.fragment
= bpf
->fragment
->val
;
1657 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1658 bgp_pbr_match_alloc_intern
);
1660 /* new, then self allocate ipset_name and unique */
1661 if (bpm
&& bpm
->unique
== 0) {
1662 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1663 /* 0 value is forbidden */
1664 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1665 bpm
->entry_hash
= hash_create_size(8,
1666 bgp_pbr_match_entry_hash_key
,
1667 bgp_pbr_match_entry_hash_equal
,
1668 "Match Entry Hash");
1669 bpm
->installed
= false;
1671 /* unique2 should be updated too */
1672 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1673 bpm
->installed_in_iptable
= false;
1674 bpm
->install_in_progress
= false;
1675 bpm
->install_iptable_in_progress
= false;
1678 memset(&temp2
, 0, sizeof(temp2
));
1680 prefix_copy(&temp2
.src
, bpf
->src
);
1682 temp2
.src
.family
= AF_INET
;
1684 prefix_copy(&temp2
.dst
, bpf
->dst
);
1686 temp2
.dst
.family
= AF_INET
;
1687 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1688 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1689 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1690 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1691 temp2
.proto
= bpf
->protocol
;
1693 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1694 bgp_pbr_match_entry_alloc_intern
);
1695 if (bpme
&& bpme
->unique
== 0) {
1696 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1697 /* 0 value is forbidden */
1698 bpme
->backpointer
= bpm
;
1699 bpme
->installed
= false;
1700 bpme
->install_in_progress
= false;
1701 /* link bgp info to bpme */
1702 bpme
->bgp_info
= (void *)binfo
;
1705 /* BGP FS: append entry to zebra
1706 * - policies are not routing entries and as such
1707 * route replace semantics don't necessarily follow
1708 * through to policy entries
1709 * - because of that, not all policing information will be stored
1710 * into zebra. and non selected policies will be suppressed from zebra
1711 * - as consequence, in order to bring consistency
1712 * a policy will be added, then ifan ecmp policy exists,
1713 * it will be suppressed subsequently
1716 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1717 bgp_send_pbr_rule_action(bpa
, true);
1718 bgp_zebra_announce_default(bgp
, nh
,
1719 AFI_IP
, bpa
->table_id
, true);
1723 if (bpm
&& !bpm
->installed
)
1724 bgp_send_pbr_ipset_match(bpm
, true);
1726 if (bpme
&& !bpme
->installed
)
1727 bgp_send_pbr_ipset_entry_match(bpme
, true);
1730 if (bpm
&& !bpm
->installed_in_iptable
)
1731 bgp_send_pbr_iptable(bpa
, bpm
, true);
1733 /* A previous entry may already exist
1734 * flush previous entry if necessary
1736 bpmer
.bpme_to_match
= bpme
;
1737 bpmer
.bpme_found
= NULL
;
1738 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1739 if (bpmer
.bpme_found
) {
1740 static struct bgp_pbr_match
*local_bpm
;
1741 static struct bgp_pbr_action
*local_bpa
;
1743 local_bpm
= bpmer
.bpme_found
->backpointer
;
1744 local_bpa
= local_bpm
->action
;
1745 bgp_pbr_flush_entry(bgp
, local_bpa
,
1746 local_bpm
, bpmer
.bpme_found
);
1752 static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp
*bgp
,
1753 struct bgp_info
*binfo
,
1754 struct bgp_pbr_filter
*bpf
,
1755 struct bgp_pbr_or_filter
*bpof
,
1760 struct listnode
*node
, *nnode
;
1761 struct bgp_pbr_val_mask
*valmask
;
1762 uint8_t next_type_entry
;
1763 struct list
*orig_list
;
1764 struct bgp_pbr_val_mask
**target_val
;
1766 if (type_entry
== 0)
1767 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1769 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1770 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1771 orig_list
= bpof
->tcpflags
;
1772 target_val
= &bpf
->tcp_flags
;
1773 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1774 orig_list
= bpof
->dscp
;
1775 target_val
= &bpf
->dscp
;
1776 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1777 orig_list
= bpof
->pkt_len
;
1778 target_val
= &bpf
->pkt_len_val
;
1779 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1780 orig_list
= bpof
->fragment
;
1781 target_val
= &bpf
->fragment
;
1783 return bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1784 bpf
, bpof
, nh
, rate
,
1787 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1788 *target_val
= valmask
;
1789 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1796 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1797 struct bgp_info
*binfo
,
1798 struct bgp_pbr_filter
*bpf
,
1799 struct bgp_pbr_or_filter
*bpof
,
1804 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1807 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1810 FLOWSPEC_TCP_FLAGS
);
1811 else if (bpof
->dscp
)
1812 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1816 else if (bpof
->pkt_len
)
1817 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1821 else if (bpof
->fragment
)
1822 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1827 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1831 list_delete_all_node(bpof
->tcpflags
);
1833 list_delete_all_node(bpof
->dscp
);
1835 list_delete_all_node(bpof
->pkt_len
);
1837 list_delete_all_node(bpof
->fragment
);
1840 static const struct message icmp_code_unreach_str
[] = {
1841 { 9, "communication-prohibited-by-filtering"},
1842 { 10, "destination-host-prohibited"},
1843 { 7, "destination-host-unknown"},
1844 { 6, "destination-network-unknown"},
1845 { 4, "fragmentation-needed"},
1846 { 14, "host-precedence-violation"},
1847 { 0, "network-unreachable"},
1848 { 12, "network-unreachable-for-tos"},
1849 { 3, "port-unreachable"},
1850 { 8, "source-host-isolated"},
1851 { 5, "source-route-failed"},
1855 static const struct message icmp_code_redirect_str
[] = {
1856 { 1, "redirect-for-host"},
1857 { 0, "redirect-for-network"},
1858 { 3, "redirect-for-tos-and-host"},
1859 { 2, "redirect-for-tos-and-net"},
1863 static const struct message icmp_code_exceed_str
[] = {
1864 { 1, "ttl-eq-zero-during-reassembly"},
1865 { 0, "ttl-eq-zero-during-transit"},
1869 static const struct message icmp_code_problem_str
[] = {
1870 { 1, "required-option-missing"},
1871 { 2, "ip-header-bad"},
1874 static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src
[],
1876 struct bgp_pbr_match_val dst
[],
1878 struct bgp_pbr_filter
*bpf
,
1880 struct bgp_info
*binfo
,
1886 struct bgp_pbr_range_port srcp
, dstp
;
1890 if (bpf
->protocol
!= IPPROTO_ICMP
)
1892 bpf
->src_port
= &srcp
;
1893 bpf
->dst_port
= &dstp
;
1894 /* combinatory forced. ignore icmp type / code combinatory */
1895 if (src_num
== 1 && dst_num
== 1) {
1898 srcp
.min_port
= src
[0].value
;
1899 dstp
.min_port
= dst
[0].value
;
1901 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1902 bpf
, NULL
, nh
, rate
);
1904 bgp_pbr_policyroute_remove_from_zebra(bgp
,
1908 /* parse icmp type and lookup appropriate icmp code
1909 * if no icmp code found, create as many entryes as
1910 * there are listed icmp codes for that icmp type
1912 for (i
= 0; i
< src_num
; i
++) {
1913 const struct message
*pnt
;
1914 const struct message
*pnt_code
= NULL
;
1915 static struct message nt
= {0};
1916 bool icmp_typecode_configured
= false;
1918 srcp
.min_port
= src
[i
].value
;
1921 if (src
[i
].value
== 3)
1922 pnt_code
= icmp_code_unreach_str
;
1923 else if (src
[i
].value
== 5)
1924 pnt_code
= icmp_code_redirect_str
;
1925 else if (src
[i
].value
== 11)
1926 pnt_code
= icmp_code_exceed_str
;
1927 else if (src
[i
].value
== 12)
1928 pnt_code
= icmp_code_problem_str
;
1929 switch (src
[i
].value
) {
1934 for (j
= 0; j
< dst_num
; j
++) {
1935 for (pnt
= pnt_code
;
1936 pnt
&& memcmp(pnt
, &nt
, sizeof(struct message
));
1938 if (dst
[i
].value
!= pnt
->key
)
1940 dstp
.min_port
= dst
[i
].value
;
1941 icmp_typecode_configured
= true;
1943 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1947 bgp_pbr_policyroute_remove_from_zebra(
1948 bgp
, binfo
, bpf
, NULL
);
1951 /* create a list of ICMP type/code combinatories */
1952 if (!icmp_typecode_configured
) {
1953 for (pnt
= pnt_code
;
1954 pnt
&& memcmp(pnt
, &nt
, sizeof(struct message
));
1956 dstp
.min_port
= pnt
->key
;
1958 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1959 bpf
, NULL
, nh
, rate
);
1961 bgp_pbr_policyroute_remove_from_zebra(bgp
,
1968 /* icmp type is not one of the above
1969 * forge an entry only based on the icmp type
1973 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1974 bpf
, NULL
, nh
, rate
);
1976 bgp_pbr_policyroute_remove_from_zebra(bgp
,
1983 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
1984 struct bgp_info
*binfo
,
1985 struct bgp_pbr_entry_main
*api
,
1990 int continue_loop
= 1;
1992 struct prefix
*src
= NULL
, *dst
= NULL
;
1994 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
1995 struct bgp_pbr_range_port range
, range_icmp_code
;
1996 struct bgp_pbr_range_port pkt_len
;
1997 bool enum_icmp
= false;
1998 struct bgp_pbr_filter bpf
;
2000 struct bgp_pbr_or_filter bpof
;
2001 struct bgp_pbr_val_mask bpvm
;
2003 memset(&nh
, 0, sizeof(struct nexthop
));
2004 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
2005 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
2006 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
2007 src
= &api
->src_prefix
;
2008 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
2009 dst
= &api
->dst_prefix
;
2010 memset(&nh
, 0, sizeof(struct nexthop
));
2011 nh
.vrf_id
= VRF_UNKNOWN
;
2012 if (api
->match_protocol_num
)
2013 proto
= (uint8_t)api
->protocol
[0].value
;
2014 /* if match_port is selected, then either src or dst port will be parsed
2015 * but not both at the same time
2017 if (api
->match_port_num
>= 1) {
2018 bgp_pbr_extract(api
->port
,
2019 api
->match_port_num
,
2021 srcp
= dstp
= &range
;
2022 } else if (api
->match_src_port_num
>= 1) {
2023 bgp_pbr_extract(api
->src_port
,
2024 api
->match_src_port_num
,
2028 } else if (api
->match_dst_port_num
>= 1) {
2029 bgp_pbr_extract(api
->dst_port
,
2030 api
->match_dst_port_num
,
2035 if (api
->match_icmp_type_num
>= 1) {
2036 proto
= IPPROTO_ICMP
;
2037 if (bgp_pbr_extract_enumerate(api
->icmp_type
,
2038 api
->match_icmp_type_num
,
2039 OPERATOR_UNARY_OR
, NULL
,
2040 FLOWSPEC_ICMP_TYPE
))
2043 bgp_pbr_extract(api
->icmp_type
,
2044 api
->match_icmp_type_num
,
2049 if (api
->match_icmp_code_num
>= 1) {
2050 proto
= IPPROTO_ICMP
;
2051 if (bgp_pbr_extract_enumerate(api
->icmp_code
,
2052 api
->match_icmp_code_num
,
2053 OPERATOR_UNARY_OR
, NULL
,
2054 FLOWSPEC_ICMP_CODE
))
2057 bgp_pbr_extract(api
->icmp_code
,
2058 api
->match_icmp_code_num
,
2060 dstp
= &range_icmp_code
;
2064 if (api
->match_tcpflags_num
) {
2065 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2066 api
->match_tcpflags_num
);
2067 if (kind_enum
== OPERATOR_UNARY_AND
) {
2068 bpf
.tcp_flags
= &bpvm
;
2069 bgp_pbr_extract_enumerate(api
->tcpflags
,
2070 api
->match_tcpflags_num
,
2073 FLOWSPEC_TCP_FLAGS
);
2074 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2075 bpof
.tcpflags
= list_new();
2076 bgp_pbr_extract_enumerate(api
->tcpflags
,
2077 api
->match_tcpflags_num
,
2080 FLOWSPEC_TCP_FLAGS
);
2083 if (api
->match_packet_length_num
) {
2086 ret
= bgp_pbr_extract(api
->packet_length
,
2087 api
->match_packet_length_num
,
2090 bpf
.pkt_len
= &pkt_len
;
2092 bpof
.pkt_len
= list_new();
2093 bgp_pbr_extract_enumerate(api
->packet_length
,
2094 api
->match_packet_length_num
,
2100 if (api
->match_dscp_num
>= 1) {
2101 bpof
.dscp
= list_new();
2102 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2104 bpof
.dscp
, FLOWSPEC_DSCP
);
2106 if (api
->match_fragment_num
) {
2107 bpof
.fragment
= list_new();
2108 bgp_pbr_extract_enumerate(api
->fragment
,
2109 api
->match_fragment_num
,
2114 bpf
.vrf_id
= api
->vrf_id
;
2117 bpf
.protocol
= proto
;
2118 bpf
.src_port
= srcp
;
2119 bpf
.dst_port
= dstp
;
2122 return bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
2123 api
->match_icmp_type_num
,
2125 api
->match_icmp_code_num
,
2126 &bpf
, bgp
, binfo
, add
,
2129 return bgp_pbr_policyroute_remove_from_zebra(bgp
,
2133 /* no action for add = true */
2134 for (i
= 0; i
< api
->action_num
; i
++) {
2135 switch (api
->actions
[i
].action
) {
2136 case ACTION_TRAFFICRATE
:
2138 if (api
->actions
[i
].u
.r
.rate
== 0) {
2139 nh
.vrf_id
= api
->vrf_id
;
2140 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2142 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
2143 api
->match_icmp_type_num
,
2145 api
->match_icmp_code_num
,
2146 &bpf
, bgp
, binfo
, add
,
2149 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
, &bpf
,
2152 /* update rate. can be reentrant */
2153 rate
= api
->actions
[i
].u
.r
.rate
;
2154 if (BGP_DEBUG(pbr
, PBR
)) {
2155 bgp_pbr_print_policy_route(api
);
2156 zlog_warn("PBR: ignoring Set action rate %f",
2157 api
->actions
[i
].u
.r
.rate
);
2161 case ACTION_TRAFFIC_ACTION
:
2162 if (api
->actions
[i
].u
.za
.filter
2163 & TRAFFIC_ACTION_SAMPLE
) {
2164 if (BGP_DEBUG(pbr
, PBR
)) {
2165 bgp_pbr_print_policy_route(api
);
2166 zlog_warn("PBR: Sample action Ignored");
2170 if (api
->actions
[i
].u
.za
.filter
2171 & TRAFFIC_ACTION_DISTRIBUTE
) {
2172 if (BGP_DEBUG(pbr
, PBR
)) {
2173 bgp_pbr_print_policy_route(api
);
2174 zlog_warn("PBR: Distribute action Applies");
2177 /* continue forwarding entry as before
2181 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2182 /* terminate action: run other filters
2185 case ACTION_REDIRECT_IP
:
2186 nh
.type
= NEXTHOP_TYPE_IPV4
;
2187 nh
.gate
.ipv4
.s_addr
=
2188 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2189 nh
.vrf_id
= api
->vrf_id
;
2191 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
2192 api
->match_icmp_type_num
,
2194 api
->match_icmp_code_num
,
2195 &bpf
, bgp
, binfo
, add
,
2198 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
, &bpf
, &bpof
,
2200 /* XXX combination with REDIRECT_VRF
2201 * + REDIRECT_NH_IP not done
2205 case ACTION_REDIRECT
:
2206 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2207 nh
.type
= NEXTHOP_TYPE_IPV4
;
2209 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
2210 api
->match_icmp_type_num
,
2212 api
->match_icmp_code_num
,
2213 &bpf
, bgp
, binfo
, add
,
2216 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2217 &bpf
, &bpof
, &nh
, &rate
);
2220 case ACTION_MARKING
:
2221 if (BGP_DEBUG(pbr
, PBR
)) {
2222 bgp_pbr_print_policy_route(api
);
2223 zlog_warn("PBR: Set DSCP %u Ignored",
2224 api
->actions
[i
].u
.marking_dscp
);
2230 if (continue_loop
== 0)
2235 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2236 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
2239 struct bgp_pbr_entry_main api
;
2240 struct bgp_info_extra
*extra
= bgp_info_extra_get(info
);
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",
2257 /* already installed */
2258 if (nlri_update
&& extra
->bgp_fs_pbr
) {
2259 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2260 zlog_err("%s: entry %p already installed in bgp pbr",
2265 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2266 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2267 zlog_err("%s: cancel updating entry %p in bgp pbr",
2271 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2274 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2275 const struct bgp_pbr_interface
*b
)
2277 return strcmp(a
->name
, b
->name
);
2280 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2281 struct bgp_pbr_interface_head
*head
)
2283 struct bgp_pbr_interface pbr_if
;
2285 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2286 return (RB_FIND(bgp_pbr_interface_head
,
2290 /* this function resets to the default policy routing
2291 * go back to default status
2293 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2295 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2296 struct bgp_pbr_interface_head
*head
;
2297 struct bgp_pbr_interface
*pbr_if
;
2299 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2301 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2303 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2304 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2305 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2306 XFREE(MTYPE_TMP
, pbr_if
);