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
,
233 /* TCP : FIN and SYN -> val = ALL; mask = 3
234 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
235 * other variables type: dscp, pkt len, fragment
236 * - value is copied in bgp_pbr_val_mask->val value
237 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
239 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list
[],
240 int num
, uint8_t unary_operator
,
241 void *valmask
, uint8_t type_entry
)
244 struct bgp_pbr_val_mask
*and_valmask
= NULL
;
245 struct list
*or_valmask
= NULL
;
248 if (unary_operator
== OPERATOR_UNARY_AND
) {
249 and_valmask
= (struct bgp_pbr_val_mask
*)valmask
;
250 memset(and_valmask
, 0, sizeof(struct bgp_pbr_val_mask
));
251 } else if (unary_operator
== OPERATOR_UNARY_OR
) {
252 or_valmask
= (struct list
*)valmask
;
255 for (i
= 0; i
< num
; i
++) {
256 if (i
!= 0 && list
[i
].unary_operator
!=
259 if (!(list
[i
].compare_operator
&
260 OPERATOR_COMPARE_EQUAL_TO
) &&
261 !(list
[i
].compare_operator
&
262 OPERATOR_COMPARE_EXACT_MATCH
)) {
263 if ((list
[i
].compare_operator
&
264 OPERATOR_COMPARE_LESS_THAN
) &&
265 (list
[i
].compare_operator
&
266 OPERATOR_COMPARE_GREATER_THAN
)) {
267 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
268 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
270 TCP_HEADER_ALL_FLAGS
&
272 } else if (type_entry
== FLOWSPEC_DSCP
||
273 type_entry
== FLOWSPEC_PKT_LEN
||
274 type_entry
== FLOWSPEC_FRAGMENT
) {
275 and_valmask
->val
= list
[i
].value
;
276 and_valmask
->mask
= 1; /* inverse */
278 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
279 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
280 sizeof(struct bgp_pbr_val_mask
));
281 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
282 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
284 TCP_HEADER_ALL_FLAGS
&
286 } else if (type_entry
== FLOWSPEC_DSCP
||
287 type_entry
== FLOWSPEC_FRAGMENT
||
288 type_entry
== FLOWSPEC_PKT_LEN
) {
289 and_valmask
->val
= list
[i
].value
;
290 and_valmask
->mask
= 1; /* inverse */
292 listnode_add (or_valmask
, and_valmask
);
293 } else if (type_entry
== FLOWSPEC_ICMP_CODE
||
294 type_entry
== FLOWSPEC_ICMP_TYPE
)
300 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
) {
301 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
303 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
304 } else if (unary_operator
== OPERATOR_UNARY_OR
&& or_valmask
) {
305 and_valmask
= XCALLOC(MTYPE_PBR_VALMASK
,
306 sizeof(struct bgp_pbr_val_mask
));
307 if (type_entry
== FLOWSPEC_TCP_FLAGS
) {
308 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
310 TCP_HEADER_ALL_FLAGS
& list
[i
].value
;
311 } else if (type_entry
== FLOWSPEC_DSCP
||
312 type_entry
== FLOWSPEC_ICMP_TYPE
||
313 type_entry
== FLOWSPEC_ICMP_CODE
||
314 type_entry
== FLOWSPEC_FRAGMENT
||
315 type_entry
== FLOWSPEC_PKT_LEN
)
316 and_valmask
->val
= list
[i
].value
;
317 listnode_add(or_valmask
, and_valmask
);
320 if (unary_operator
== OPERATOR_UNARY_AND
&& and_valmask
321 && type_entry
== FLOWSPEC_TCP_FLAGS
)
322 and_valmask
->val
= TCP_HEADER_ALL_FLAGS
;
326 /* if unary operator can either be UNARY_OR/AND/OR-AND.
327 * in the latter case, combinationf of both is not handled
329 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
330 int num
, uint8_t unary_operator
,
331 void *valmask
, uint8_t type_entry
)
334 uint8_t unary_operator_val
= unary_operator
;
335 bool double_check
= false;
337 if ((unary_operator
& OPERATOR_UNARY_OR
) &&
338 (unary_operator
& OPERATOR_UNARY_AND
)) {
339 unary_operator_val
= OPERATOR_UNARY_AND
;
342 unary_operator_val
= unary_operator
;
343 ret
= bgp_pbr_extract_enumerate_unary(list
, num
, unary_operator_val
,
344 valmask
, type_entry
);
345 if (!ret
&& double_check
)
346 ret
= bgp_pbr_extract_enumerate_unary(list
, num
,
353 /* returns the unary operator that is in the list
354 * return 0 if both operators are used
356 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list
[],
361 uint8_t unary_operator
= OPERATOR_UNARY_AND
;
363 for (i
= 0; i
< num
; i
++) {
366 if (list
[i
].unary_operator
& OPERATOR_UNARY_OR
)
367 unary_operator
= OPERATOR_UNARY_OR
;
368 if ((list
[i
].unary_operator
& OPERATOR_UNARY_AND
369 && unary_operator
== OPERATOR_UNARY_OR
) ||
370 (list
[i
].unary_operator
& OPERATOR_UNARY_OR
371 && unary_operator
== OPERATOR_UNARY_AND
))
374 return unary_operator
;
378 /* return true if extraction ok
380 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
382 struct bgp_pbr_range_port
*range
)
385 bool exact_match
= false;
388 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
392 for (i
= 0; i
< num
; i
++) {
393 if (i
!= 0 && (list
[i
].compare_operator
==
394 OPERATOR_COMPARE_EQUAL_TO
))
396 if (i
== 0 && (list
[i
].compare_operator
==
397 OPERATOR_COMPARE_EQUAL_TO
)) {
399 range
->min_port
= list
[i
].value
;
402 if (exact_match
== true && i
> 0)
404 if (list
[i
].compare_operator
==
405 (OPERATOR_COMPARE_GREATER_THAN
+
406 OPERATOR_COMPARE_EQUAL_TO
)) {
408 range
->min_port
= list
[i
].value
;
409 } else if (list
[i
].compare_operator
==
410 (OPERATOR_COMPARE_LESS_THAN
+
411 OPERATOR_COMPARE_EQUAL_TO
)) {
413 range
->max_port
= list
[i
].value
;
414 } else if (list
[i
].compare_operator
==
415 OPERATOR_COMPARE_LESS_THAN
) {
417 range
->max_port
= list
[i
].value
- 1;
418 } else if (list
[i
].compare_operator
==
419 OPERATOR_COMPARE_GREATER_THAN
) {
421 range
->min_port
= list
[i
].value
+ 1;
427 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
429 bool enumerate_icmp
= false;
431 /* because bgp pbr entry may contain unsupported
432 * combinations, a message will be displayed here if
434 * for now, only match/set supported is
435 * - combination src/dst => redirect nexthop [ + rate]
436 * - combination src/dst => redirect VRF [ + rate]
437 * - combination src/dst => drop
438 * - combination srcport + @IP
440 if (api
->match_protocol_num
> 1) {
441 if (BGP_DEBUG(pbr
, PBR
))
442 zlog_debug("BGP: match protocol operations:"
443 "multiple protocols ( %d). ignoring.",
444 api
->match_protocol_num
);
447 if (api
->match_protocol_num
== 1 &&
448 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
449 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
450 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
451 if (BGP_DEBUG(pbr
, PBR
))
452 zlog_debug("BGP: match protocol operations:"
453 "protocol (%d) not supported. ignoring",
454 api
->match_protocol_num
);
457 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
458 if (BGP_DEBUG(pbr
, PBR
))
459 zlog_debug("BGP: match src port operations:"
460 "too complex. ignoring.");
463 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
464 if (BGP_DEBUG(pbr
, PBR
))
465 zlog_debug("BGP: match dst port operations:"
466 "too complex. ignoring.");
469 if (!bgp_pbr_extract_enumerate(api
->tcpflags
,
470 api
->match_tcpflags_num
,
472 OPERATOR_UNARY_OR
, NULL
,
473 FLOWSPEC_TCP_FLAGS
)) {
474 if (BGP_DEBUG(pbr
, PBR
))
475 zlog_debug("BGP: match tcp flags:"
476 "too complex. ignoring.");
479 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
480 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
481 api
->match_icmp_type_num
,
482 OPERATOR_UNARY_OR
, NULL
,
483 FLOWSPEC_ICMP_TYPE
)) {
484 if (BGP_DEBUG(pbr
, PBR
))
485 zlog_debug("BGP: match icmp type operations:"
486 "too complex. ignoring.");
489 enumerate_icmp
= true;
491 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
492 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
493 api
->match_icmp_code_num
,
494 OPERATOR_UNARY_OR
, NULL
,
495 FLOWSPEC_ICMP_CODE
)) {
496 if (BGP_DEBUG(pbr
, PBR
))
497 zlog_debug("BGP: match icmp code operations:"
498 "too complex. ignoring.");
500 } else if (api
->match_icmp_type_num
> 1 &&
501 enumerate_icmp
== false) {
502 if (BGP_DEBUG(pbr
, PBR
))
503 zlog_debug("BGP: match icmp code is enumerate"
504 ", and icmp type is not."
505 " too complex. ignoring.");
509 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
510 if (BGP_DEBUG(pbr
, PBR
))
511 zlog_debug("BGP: match port operations:"
512 "too complex. ignoring.");
515 if (api
->match_packet_length_num
) {
518 ret
= bgp_pbr_extract(api
->packet_length
,
519 api
->match_packet_length_num
, NULL
);
521 ret
= bgp_pbr_extract_enumerate(api
->packet_length
,
522 api
->match_packet_length_num
,
524 | OPERATOR_UNARY_AND
,
525 NULL
, FLOWSPEC_PKT_LEN
);
527 if (BGP_DEBUG(pbr
, PBR
))
528 zlog_debug("BGP: match packet length operations:"
529 "too complex. ignoring.");
533 if (api
->match_dscp_num
) {
534 if (!bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
535 OPERATOR_UNARY_OR
| OPERATOR_UNARY_AND
,
536 NULL
, FLOWSPEC_DSCP
)) {
537 if (BGP_DEBUG(pbr
, PBR
))
538 zlog_debug("BGP: match DSCP operations:"
539 "too complex. ignoring.");
543 if (api
->match_fragment_num
) {
547 success
= bgp_pbr_extract_enumerate(api
->fragment
,
548 api
->match_fragment_num
,
550 | OPERATOR_UNARY_AND
,
551 NULL
, FLOWSPEC_FRAGMENT
);
555 for (i
= 0; i
< api
->match_fragment_num
; i
++) {
556 if (api
->fragment
[i
].value
!= 1 &&
557 api
->fragment
[i
].value
!= 2 &&
558 api
->fragment
[i
].value
!= 4 &&
559 api
->fragment
[i
].value
!= 8) {
562 "Value not valid (%d) for this implementation",
563 api
->fragment
[i
].value
);
567 sprintf(fail_str
, "too complex. ignoring");
569 if (BGP_DEBUG(pbr
, PBR
))
570 zlog_debug("BGP: match fragment operation (%d) %s",
571 api
->match_fragment_num
,
577 /* no combinations with both src_port and dst_port
578 * or port with src_port and dst_port
580 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
581 api
->match_port_num
> 3) {
582 if (BGP_DEBUG(pbr
, PBR
))
583 zlog_debug("BGP: match multiple port operations:"
584 " too complex. ignoring.");
587 if ((api
->match_src_port_num
|| api
->match_dst_port_num
588 || api
->match_port_num
) && (api
->match_icmp_type_num
589 || api
->match_icmp_code_num
)) {
590 if (BGP_DEBUG(pbr
, PBR
))
591 zlog_debug("BGP: match multiple port/imcp operations:"
592 " too complex. ignoring.");
595 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
596 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
597 if (BGP_DEBUG(pbr
, PBR
)) {
598 bgp_pbr_print_policy_route(api
);
599 zlog_debug("BGP: match actions without src"
600 " or dst address can not operate."
608 /* return -1 if build or validation failed */
609 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
610 struct bgp_info
*info
,
611 struct bgp_pbr_entry_main
*api
)
614 int i
, action_count
= 0;
615 struct ecommunity
*ecom
;
616 struct ecommunity_val
*ecom_eval
;
617 struct bgp_pbr_entry_action
*api_action
;
618 struct prefix
*src
= NULL
, *dst
= NULL
;
619 int valid_prefix
= 0;
622 /* extract match from flowspec entries */
623 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
624 p
->u
.prefix_flowspec
.prefixlen
, api
);
627 /* extract actiosn from flowspec ecom list */
628 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
629 ecom
= info
->attr
->ecommunity
;
630 for (i
= 0; i
< ecom
->size
; i
++) {
631 ecom_eval
= (struct ecommunity_val
*)
632 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
634 if (action_count
> ACTIONS_MAX_NUM
) {
635 if (BGP_DEBUG(pbr
, PBR_ERROR
))
636 zlog_err("%s: flowspec actions exceeds limit (max %u)",
637 __func__
, action_count
);
640 api_action
= &api
->actions
[action_count
- 1];
642 if ((ecom_eval
->val
[1] ==
643 (char)ECOMMUNITY_REDIRECT_VRF
) &&
644 (ecom_eval
->val
[0] ==
645 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
647 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
649 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
650 struct ecommunity
*eckey
= ecommunity_new();
651 struct ecommunity_val ecom_copy
;
653 memcpy(&ecom_copy
, ecom_eval
,
654 sizeof(struct ecommunity_val
));
656 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
657 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
658 ecommunity_add_val(eckey
, &ecom_copy
);
660 api_action
->action
= ACTION_REDIRECT
;
661 api_action
->u
.redirect_vrf
=
662 get_first_vrf_for_redirect_with_rt(
664 ecommunity_free(&eckey
);
665 } else if ((ecom_eval
->val
[0] ==
666 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
667 (ecom_eval
->val
[1] ==
668 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
669 api_action
->action
= ACTION_REDIRECT_IP
;
670 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
671 info
->attr
->nexthop
.s_addr
;
672 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
674 if (ecom_eval
->val
[0] !=
675 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
677 ret
= ecommunity_fill_pbr_action(ecom_eval
,
686 /* validate if incoming matc/action is compatible
687 * with our policy routing engine
689 if (!bgp_pbr_validate_policy_route(api
))
692 /* check inconsistency in the match rule */
693 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
694 src
= &api
->src_prefix
;
695 afi
= family2afi(src
->family
);
698 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
699 dst
= &api
->dst_prefix
;
700 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
701 if (BGP_DEBUG(pbr
, PBR
)) {
702 bgp_pbr_print_policy_route(api
);
703 zlog_debug("%s: inconsistency:"
704 " no match for afi src and dst (%u/%u)",
705 __func__
, afi
, family2afi(dst
->family
));
713 static void bgp_pbr_match_entry_free(void *arg
)
715 struct bgp_pbr_match_entry
*bpme
;
717 bpme
= (struct bgp_pbr_match_entry
*)arg
;
719 if (bpme
->installed
) {
720 bgp_send_pbr_ipset_entry_match(bpme
, false);
721 bpme
->installed
= false;
722 bpme
->backpointer
= NULL
;
724 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
727 static void bgp_pbr_match_free(void *arg
)
729 struct bgp_pbr_match
*bpm
;
731 bpm
= (struct bgp_pbr_match
*)arg
;
733 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
735 if (hashcount(bpm
->entry_hash
) == 0) {
736 /* delete iptable entry first */
737 /* then delete ipset match */
738 if (bpm
->installed
) {
739 if (bpm
->installed_in_iptable
) {
740 bgp_send_pbr_iptable(bpm
->action
,
742 bpm
->installed_in_iptable
= false;
743 bpm
->action
->refcnt
--;
745 bgp_send_pbr_ipset_match(bpm
, false);
746 bpm
->installed
= false;
750 hash_free(bpm
->entry_hash
);
752 XFREE(MTYPE_PBR_MATCH
, bpm
);
755 static void *bgp_pbr_match_alloc_intern(void *arg
)
757 struct bgp_pbr_match
*bpm
, *new;
759 bpm
= (struct bgp_pbr_match
*)arg
;
761 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
762 memcpy(new, bpm
, sizeof(*bpm
));
767 static void bgp_pbr_action_free(void *arg
)
769 struct bgp_pbr_action
*bpa
;
771 bpa
= (struct bgp_pbr_action
*)arg
;
773 if (bpa
->refcnt
== 0) {
774 if (bpa
->installed
&& bpa
->table_id
!= 0) {
775 bgp_send_pbr_rule_action(bpa
, false);
776 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
780 bpa
->installed
= false;
783 XFREE(MTYPE_PBR_ACTION
, bpa
);
786 static void *bgp_pbr_action_alloc_intern(void *arg
)
788 struct bgp_pbr_action
*bpa
, *new;
790 bpa
= (struct bgp_pbr_action
*)arg
;
792 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
794 memcpy(new, bpa
, sizeof(*bpa
));
799 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
801 struct bgp_pbr_match_entry
*bpme
, *new;
803 bpme
= (struct bgp_pbr_match_entry
*)arg
;
805 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
807 memcpy(new, bpme
, sizeof(*bpme
));
812 uint32_t bgp_pbr_match_hash_key(void *arg
)
814 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
817 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
818 key
= jhash_1word(pbm
->flags
, key
);
819 key
= jhash_1word(pbm
->pkt_len_min
, key
);
820 key
= jhash_1word(pbm
->pkt_len_max
, key
);
821 key
= jhash_1word(pbm
->tcp_flags
, key
);
822 key
= jhash_1word(pbm
->tcp_mask_flags
, key
);
823 key
= jhash_1word(pbm
->dscp_value
, key
);
824 key
= jhash_1word(pbm
->fragment
, key
);
825 return jhash_1word(pbm
->type
, key
);
828 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
830 const struct bgp_pbr_match
*r1
, *r2
;
832 r1
= (const struct bgp_pbr_match
*)arg1
;
833 r2
= (const struct bgp_pbr_match
*)arg2
;
835 if (r1
->vrf_id
!= r2
->vrf_id
)
838 if (r1
->type
!= r2
->type
)
841 if (r1
->flags
!= r2
->flags
)
844 if (r1
->action
!= r2
->action
)
847 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
850 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
853 if (r1
->tcp_flags
!= r2
->tcp_flags
)
856 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
859 if (r1
->dscp_value
!= r2
->dscp_value
)
862 if (r1
->fragment
!= r2
->fragment
)
867 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
869 struct bgp_pbr_match_entry
*pbme
;
872 pbme
= (struct bgp_pbr_match_entry
*)arg
;
873 key
= prefix_hash_key(&pbme
->src
);
874 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
875 key
= jhash(&pbme
->dst_port_min
, 2, key
);
876 key
= jhash(&pbme
->src_port_min
, 2, key
);
877 key
= jhash(&pbme
->dst_port_max
, 2, key
);
878 key
= jhash(&pbme
->src_port_max
, 2, key
);
879 key
= jhash(&pbme
->proto
, 1, key
);
884 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
886 const struct bgp_pbr_match_entry
*r1
, *r2
;
888 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
889 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
891 /* on updates, comparing
892 * backpointer is not necessary
895 /* unique value is self calculated
898 /* rate is ignored for now
901 if (!prefix_same(&r1
->src
, &r2
->src
))
904 if (!prefix_same(&r1
->dst
, &r2
->dst
))
907 if (r1
->src_port_min
!= r2
->src_port_min
)
910 if (r1
->dst_port_min
!= r2
->dst_port_min
)
913 if (r1
->src_port_max
!= r2
->src_port_max
)
916 if (r1
->dst_port_max
!= r2
->dst_port_max
)
919 if (r1
->proto
!= r2
->proto
)
925 uint32_t bgp_pbr_action_hash_key(void *arg
)
927 struct bgp_pbr_action
*pbra
;
930 pbra
= (struct bgp_pbr_action
*)arg
;
931 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
932 key
= jhash_1word(pbra
->fwmark
, key
);
936 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
938 const struct bgp_pbr_action
*r1
, *r2
;
940 r1
= (const struct bgp_pbr_action
*)arg1
;
941 r2
= (const struct bgp_pbr_action
*)arg2
;
943 /* unique value is self calculated
944 * table and fwmark is self calculated
947 if (r1
->vrf_id
!= r2
->vrf_id
)
950 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
955 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
958 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
959 struct bgp_pbr_action_unique bpau
;
961 if (!bgp
|| unique
== 0)
963 bpau
.unique
= unique
;
964 bpau
.bpa_found
= NULL
;
965 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
966 return bpau
.bpa_found
;
969 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
972 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
973 struct bgp_pbr_match_unique bpmu
;
975 if (!bgp
|| unique
== 0)
977 bpmu
.unique
= unique
;
978 bpmu
.bpm_found
= NULL
;
979 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
980 return bpmu
.bpm_found
;
983 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
987 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
988 struct bgp_pbr_match_entry_unique bpmeu
;
989 struct bgp_pbr_match_ipsetname bpmi
;
991 if (!bgp
|| unique
== 0)
993 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
994 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
995 bpmi
.bpm_found
= NULL
;
996 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
997 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
1000 bpmeu
.bpme_found
= NULL
;
1001 bpmeu
.unique
= unique
;
1002 hash_walk(bpmi
.bpm_found
->entry_hash
,
1003 bgp_pbr_match_entry_walkcb
, &bpmeu
);
1004 return bpmeu
.bpme_found
;
1007 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
1010 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
1011 struct bgp_pbr_match_iptable_unique bpmiu
;
1013 if (!bgp
|| unique
== 0)
1015 bpmiu
.unique
= unique
;
1016 bpmiu
.bpm_found
= NULL
;
1017 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
1018 return bpmiu
.bpm_found
;
1021 void bgp_pbr_cleanup(struct bgp
*bgp
)
1023 if (bgp
->pbr_match_hash
) {
1024 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
1025 hash_free(bgp
->pbr_match_hash
);
1026 bgp
->pbr_match_hash
= NULL
;
1028 if (bgp
->pbr_action_hash
) {
1029 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
1030 hash_free(bgp
->pbr_action_hash
);
1031 bgp
->pbr_action_hash
= NULL
;
1033 if (bgp
->bgp_pbr_cfg
== NULL
)
1035 bgp_pbr_reset(bgp
, AFI_IP
);
1036 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
1037 bgp
->bgp_pbr_cfg
= NULL
;
1040 void bgp_pbr_init(struct bgp
*bgp
)
1042 bgp
->pbr_match_hash
=
1043 hash_create_size(8, bgp_pbr_match_hash_key
,
1044 bgp_pbr_match_hash_equal
,
1046 bgp
->pbr_action_hash
=
1047 hash_create_size(8, bgp_pbr_action_hash_key
,
1048 bgp_pbr_action_hash_equal
,
1049 "Match Hash Entry");
1051 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
1052 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
1055 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
1058 char return_string
[512];
1059 char *ptr
= return_string
;
1063 ptr
+= sprintf(ptr
, "MATCH : ");
1064 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
1065 struct prefix
*p
= &(api
->src_prefix
);
1067 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
1068 INCREMENT_DISPLAY(ptr
, nb_items
);
1070 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
1071 struct prefix
*p
= &(api
->dst_prefix
);
1073 INCREMENT_DISPLAY(ptr
, nb_items
);
1074 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
1077 if (api
->match_protocol_num
)
1078 INCREMENT_DISPLAY(ptr
, nb_items
);
1079 for (i
= 0; i
< api
->match_protocol_num
; i
++)
1080 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
1081 i
> 0 ? NULL
: "@proto ");
1083 if (api
->match_src_port_num
)
1084 INCREMENT_DISPLAY(ptr
, nb_items
);
1085 for (i
= 0; i
< api
->match_src_port_num
; i
++)
1086 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
1087 i
> 0 ? NULL
: "@srcport ");
1089 if (api
->match_dst_port_num
)
1090 INCREMENT_DISPLAY(ptr
, nb_items
);
1091 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
1092 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
1093 i
> 0 ? NULL
: "@dstport ");
1095 if (api
->match_port_num
)
1096 INCREMENT_DISPLAY(ptr
, nb_items
);
1097 for (i
= 0; i
< api
->match_port_num
; i
++)
1098 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
1099 i
> 0 ? NULL
: "@port ");
1101 if (api
->match_icmp_type_num
)
1102 INCREMENT_DISPLAY(ptr
, nb_items
);
1103 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
1104 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
1105 i
> 0 ? NULL
: "@icmptype ");
1107 if (api
->match_icmp_code_num
)
1108 INCREMENT_DISPLAY(ptr
, nb_items
);
1109 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
1110 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
1111 i
> 0 ? NULL
: "@icmpcode ");
1113 if (api
->match_packet_length_num
)
1114 INCREMENT_DISPLAY(ptr
, nb_items
);
1115 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
1116 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
1117 i
> 0 ? NULL
: "@plen ");
1119 if (api
->match_dscp_num
)
1120 INCREMENT_DISPLAY(ptr
, nb_items
);
1121 for (i
= 0; i
< api
->match_dscp_num
; i
++)
1122 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
1123 i
> 0 ? NULL
: "@dscp ");
1125 if (api
->match_tcpflags_num
)
1126 INCREMENT_DISPLAY(ptr
, nb_items
);
1127 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
1128 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
1129 i
> 0 ? NULL
: "@tcpflags ");
1131 if (api
->match_fragment_num
)
1132 INCREMENT_DISPLAY(ptr
, nb_items
);
1133 for (i
= 0; i
< api
->match_fragment_num
; i
++)
1134 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->fragment
[i
],
1135 i
> 0 ? NULL
: "@fragment ");
1137 ptr
= return_string
;
1139 ptr
+= sprintf(ptr
, "; ");
1140 if (api
->action_num
)
1141 ptr
+= sprintf(ptr
, "SET : ");
1143 for (i
= 0; i
< api
->action_num
; i
++) {
1144 switch (api
->actions
[i
].action
) {
1145 case ACTION_TRAFFICRATE
:
1146 INCREMENT_DISPLAY(ptr
, nb_items
);
1147 ptr
+= sprintf(ptr
, "@set rate %f",
1148 api
->actions
[i
].u
.r
.rate
);
1150 case ACTION_TRAFFIC_ACTION
:
1151 INCREMENT_DISPLAY(ptr
, nb_items
);
1152 ptr
+= sprintf(ptr
, "@action ");
1153 if (api
->actions
[i
].u
.za
.filter
1154 & TRAFFIC_ACTION_TERMINATE
)
1156 " terminate (apply filter(s))");
1157 if (api
->actions
[i
].u
.za
.filter
1158 & TRAFFIC_ACTION_DISTRIBUTE
)
1159 ptr
+= sprintf(ptr
, " distribute");
1160 if (api
->actions
[i
].u
.za
.filter
1161 & TRAFFIC_ACTION_SAMPLE
)
1162 ptr
+= sprintf(ptr
, " sample");
1164 case ACTION_REDIRECT_IP
:
1165 INCREMENT_DISPLAY(ptr
, nb_items
);
1166 char local_buff
[INET_ADDRSTRLEN
];
1168 if (inet_ntop(AF_INET
,
1169 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
1170 local_buff
, INET_ADDRSTRLEN
) != NULL
)
1172 "@redirect ip nh %s", local_buff
);
1174 case ACTION_REDIRECT
:
1175 INCREMENT_DISPLAY(ptr
, nb_items
);
1176 ptr
+= sprintf(ptr
, "@redirect vrf %u",
1177 api
->actions
[i
].u
.redirect_vrf
);
1179 case ACTION_MARKING
:
1180 INCREMENT_DISPLAY(ptr
, nb_items
);
1181 ptr
+= sprintf(ptr
, "@set dscp %u",
1182 api
->actions
[i
].u
.marking_dscp
);
1188 zlog_info("%s", return_string
);
1191 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
1192 struct bgp_pbr_match
*bpm
,
1193 struct bgp_pbr_match_entry
*bpme
)
1195 /* if bpme is null, bpm is also null
1199 /* ipset del entry */
1200 if (bpme
->installed
) {
1201 bgp_send_pbr_ipset_entry_match(bpme
, false);
1202 bpme
->installed
= false;
1203 bpme
->backpointer
= NULL
;
1204 if (bpme
->bgp_info
) {
1205 struct bgp_info
*bgp_info
;
1206 struct bgp_info_extra
*extra
;
1208 /* unlink bgp_info to bpme */
1209 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
1210 extra
= bgp_info_extra_get(bgp_info
);
1211 extra
->bgp_fs_pbr
= NULL
;
1212 bpme
->bgp_info
= NULL
;
1215 hash_release(bpm
->entry_hash
, bpme
);
1216 if (hashcount(bpm
->entry_hash
) == 0) {
1217 /* delete iptable entry first */
1218 /* then delete ipset match */
1219 if (bpm
->installed
) {
1220 if (bpm
->installed_in_iptable
) {
1221 bgp_send_pbr_iptable(bpm
->action
,
1223 bpm
->installed_in_iptable
= false;
1224 bpm
->action
->refcnt
--;
1226 bgp_send_pbr_ipset_match(bpm
, false);
1227 bpm
->installed
= false;
1230 hash_release(bgp
->pbr_match_hash
, bpm
);
1231 /* XXX release pbr_match_action if not used
1232 * note that drop does not need to call send_pbr_action
1235 if (bpa
->refcnt
== 0) {
1236 if (bpa
->installed
&& bpa
->table_id
!= 0) {
1237 bgp_send_pbr_rule_action(bpa
, false);
1238 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
1242 bpa
->installed
= false;
1247 struct bgp_pbr_match_entry_remain
{
1248 struct bgp_pbr_match_entry
*bpme_to_match
;
1249 struct bgp_pbr_match_entry
*bpme_found
;
1252 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
1254 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
1255 struct bgp_pbr_match_entry_remain
*bpmer
=
1256 (struct bgp_pbr_match_entry_remain
*)arg
;
1257 struct bgp_pbr_match
*bpm_temp
;
1258 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1260 if (!bpme
->backpointer
||
1261 bpm
== bpme
->backpointer
||
1262 bpme
->backpointer
->action
== bpm
->action
)
1263 return HASHWALK_CONTINUE
;
1264 /* ensure bpm other characteristics are equal */
1265 bpm_temp
= bpme
->backpointer
;
1266 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1267 bpm_temp
->type
!= bpm
->type
||
1268 bpm_temp
->flags
!= bpm
->flags
)
1269 return HASHWALK_CONTINUE
;
1271 /* look for remaining bpme */
1272 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1273 if (!bpmer
->bpme_found
)
1274 return HASHWALK_CONTINUE
;
1275 return HASHWALK_ABORT
;
1278 static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp
*bgp
,
1279 struct bgp_info
*binfo
,
1280 struct bgp_pbr_filter
*bpf
)
1282 struct bgp_pbr_match temp
;
1283 struct bgp_pbr_match_entry temp2
;
1284 struct bgp_pbr_match
*bpm
;
1285 struct bgp_pbr_match_entry
*bpme
;
1286 struct bgp_pbr_match_entry_remain bpmer
;
1287 struct bgp_pbr_range_port
*src_port
;
1288 struct bgp_pbr_range_port
*dst_port
;
1289 struct bgp_pbr_range_port
*pkt_len
;
1293 src_port
= bpf
->src_port
;
1294 dst_port
= bpf
->dst_port
;
1295 pkt_len
= bpf
->pkt_len
;
1297 /* as we don't know information from EC
1298 * look for bpm that have the bpm
1299 * with vrf_id characteristics
1301 memset(&temp2
, 0, sizeof(temp2
));
1302 memset(&temp
, 0, sizeof(temp
));
1304 temp
.flags
|= MATCH_IP_SRC_SET
;
1305 prefix_copy(&temp2
.src
, bpf
->src
);
1307 temp2
.src
.family
= AF_INET
;
1309 temp
.flags
|= MATCH_IP_DST_SET
;
1310 prefix_copy(&temp2
.dst
, bpf
->dst
);
1312 temp2
.dst
.family
= AF_INET
;
1313 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1314 if (bpf
->protocol
== IPPROTO_ICMP
)
1315 temp
.flags
|= MATCH_ICMP_SET
;
1316 temp
.flags
|= MATCH_PORT_SRC_SET
;
1317 temp2
.src_port_min
= src_port
->min_port
;
1318 if (src_port
->max_port
) {
1319 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1320 temp2
.src_port_max
= src_port
->max_port
;
1323 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1324 if (bpf
->protocol
== IPPROTO_ICMP
)
1325 temp
.flags
|= MATCH_ICMP_SET
;
1326 temp
.flags
|= MATCH_PORT_DST_SET
;
1327 temp2
.dst_port_min
= dst_port
->min_port
;
1328 if (dst_port
->max_port
) {
1329 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1330 temp2
.dst_port_max
= dst_port
->max_port
;
1333 temp2
.proto
= bpf
->protocol
;
1336 temp
.pkt_len_min
= pkt_len
->min_port
;
1337 if (pkt_len
->max_port
)
1338 temp
.pkt_len_max
= pkt_len
->max_port
;
1339 } else if (bpf
->pkt_len_val
) {
1340 if (bpf
->pkt_len_val
->mask
)
1341 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1342 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1344 if (bpf
->tcp_flags
) {
1345 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1346 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1349 if (bpf
->dscp
->mask
)
1350 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1352 temp
.flags
|= MATCH_DSCP_SET
;
1353 temp
.dscp_value
= bpf
->dscp
->val
;
1355 if (bpf
->fragment
) {
1356 if (bpf
->fragment
->mask
)
1357 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1358 temp
.fragment
= bpf
->fragment
->val
;
1361 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1362 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1363 temp
.type
= IPSET_NET_PORT
;
1365 temp
.type
= IPSET_NET
;
1367 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1368 temp
.type
= IPSET_NET_PORT_NET
;
1370 temp
.type
= IPSET_NET_NET
;
1372 if (bpf
->vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1375 temp
.vrf_id
= bpf
->vrf_id
;
1378 bpme
->backpointer
= bpm
;
1379 /* right now, a previous entry may already exist
1380 * flush previous entry if necessary
1382 bpmer
.bpme_to_match
= bpme
;
1383 bpmer
.bpme_found
= NULL
;
1384 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1385 if (bpmer
.bpme_found
) {
1386 static struct bgp_pbr_match
*local_bpm
;
1387 static struct bgp_pbr_action
*local_bpa
;
1389 local_bpm
= bpmer
.bpme_found
->backpointer
;
1390 local_bpa
= local_bpm
->action
;
1391 bgp_pbr_flush_entry(bgp
, local_bpa
,
1392 local_bpm
, bpmer
.bpme_found
);
1396 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry
)
1398 if (type_entry
== FLOWSPEC_TCP_FLAGS
)
1399 return FLOWSPEC_DSCP
;
1400 if (type_entry
== FLOWSPEC_DSCP
)
1401 return FLOWSPEC_PKT_LEN
;
1402 if (type_entry
== FLOWSPEC_PKT_LEN
)
1403 return FLOWSPEC_FRAGMENT
;
1404 if (type_entry
== FLOWSPEC_FRAGMENT
)
1405 return FLOWSPEC_ICMP_TYPE
;
1409 static void bgp_pbr_icmp_action(struct bgp
*bgp
,
1410 struct bgp_info
*binfo
,
1411 struct bgp_pbr_filter
*bpf
,
1412 struct bgp_pbr_or_filter
*bpof
,
1417 struct bgp_pbr_range_port srcp
, dstp
;
1418 struct bgp_pbr_val_mask
*icmp_type
, *icmp_code
;
1419 struct listnode
*tnode
, *cnode
;
1423 if (bpf
->protocol
!= IPPROTO_ICMP
)
1425 bpf
->src_port
= &srcp
;
1426 bpf
->dst_port
= &dstp
;
1427 /* parse icmp type and lookup appropriate icmp code
1428 * if no icmp code found, create as many entryes as
1429 * there are listed icmp codes for that icmp type
1431 if (!bpof
->icmp_type
) {
1433 srcp
.max_port
= 255;
1434 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1435 dstp
.min_port
= icmp_code
->val
;
1437 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1440 bgp_pbr_policyroute_remove_from_zebra_unit(
1445 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_type
, tnode
, icmp_type
)) {
1446 srcp
.min_port
= icmp_type
->val
;
1449 /* only icmp type. create an entry only with icmp type */
1450 if (!bpof
->icmp_code
) {
1451 /* icmp type is not one of the above
1452 * forge an entry only based on the icmp type
1455 dstp
.max_port
= 255;
1457 bgp_pbr_policyroute_add_to_zebra_unit(
1461 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1465 for (ALL_LIST_ELEMENTS_RO(bpof
->icmp_code
, cnode
, icmp_code
)) {
1466 dstp
.min_port
= icmp_code
->val
;
1468 bgp_pbr_policyroute_add_to_zebra_unit(
1472 bgp_pbr_policyroute_remove_from_zebra_unit(
1478 static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp
*bgp
,
1479 struct bgp_info
*binfo
,
1480 struct bgp_pbr_filter
*bpf
,
1481 struct bgp_pbr_or_filter
*bpof
,
1484 struct listnode
*node
, *nnode
;
1485 struct bgp_pbr_val_mask
*valmask
;
1486 uint8_t next_type_entry
;
1487 struct list
*orig_list
;
1488 struct bgp_pbr_val_mask
**target_val
;
1490 if (type_entry
== 0)
1491 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1493 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1494 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1495 orig_list
= bpof
->tcpflags
;
1496 target_val
= &bpf
->tcp_flags
;
1497 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1498 orig_list
= bpof
->dscp
;
1499 target_val
= &bpf
->dscp
;
1500 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1501 orig_list
= bpof
->pkt_len
;
1502 target_val
= &bpf
->pkt_len_val
;
1503 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1504 orig_list
= bpof
->fragment
;
1505 target_val
= &bpf
->fragment
;
1506 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1507 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1508 /* enumerate list for icmp - must be last one */
1509 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, false, NULL
, NULL
);
1512 return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
,
1517 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1518 *target_val
= valmask
;
1519 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1525 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
1526 struct bgp_info
*binfo
,
1527 struct bgp_pbr_filter
*bpf
,
1528 struct bgp_pbr_or_filter
*bpof
)
1531 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp
,
1535 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1537 FLOWSPEC_TCP_FLAGS
);
1538 else if (bpof
->dscp
)
1539 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1542 else if (bpof
->pkt_len
)
1543 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1546 else if (bpof
->fragment
)
1547 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1550 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1551 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp
, binfo
,
1553 FLOWSPEC_ICMP_TYPE
);
1555 bgp_pbr_policyroute_remove_from_zebra_unit(bgp
, binfo
, bpf
);
1558 list_delete_all_node(bpof
->tcpflags
);
1560 list_delete_all_node(bpof
->dscp
);
1562 list_delete_all_node(bpof
->pkt_len
);
1564 list_delete_all_node(bpof
->fragment
);
1567 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp
*bgp
,
1568 struct bgp_info
*binfo
,
1569 struct bgp_pbr_filter
*bpf
,
1573 struct bgp_pbr_match temp
;
1574 struct bgp_pbr_match_entry temp2
;
1575 struct bgp_pbr_match
*bpm
;
1576 struct bgp_pbr_match_entry
*bpme
= NULL
;
1577 struct bgp_pbr_action temp3
;
1578 struct bgp_pbr_action
*bpa
= NULL
;
1579 struct bgp_pbr_match_entry_remain bpmer
;
1580 struct bgp_pbr_range_port
*src_port
;
1581 struct bgp_pbr_range_port
*dst_port
;
1582 struct bgp_pbr_range_port
*pkt_len
;
1586 src_port
= bpf
->src_port
;
1587 dst_port
= bpf
->dst_port
;
1588 pkt_len
= bpf
->pkt_len
;
1590 if (BGP_DEBUG(zebra
, ZEBRA
)) {
1591 char bufsrc
[64], bufdst
[64];
1593 int remaining_len
= 0;
1594 char protocol_str
[16];
1596 protocol_str
[0] = '\0';
1597 if (bpf
->tcp_flags
&& bpf
->tcp_flags
->mask
)
1598 bpf
->protocol
= IPPROTO_TCP
;
1600 snprintf(protocol_str
, sizeof(protocol_str
),
1601 "proto %d", bpf
->protocol
);
1603 if (bpf
->protocol
== IPPROTO_ICMP
&& src_port
&& dst_port
)
1604 remaining_len
+= snprintf(buffer
, sizeof(buffer
),
1606 src_port
->min_port
, dst_port
->min_port
);
1607 else if (bpf
->protocol
== IPPROTO_UDP
||
1608 bpf
->protocol
== IPPROTO_TCP
) {
1610 if (src_port
&& src_port
->min_port
)
1611 remaining_len
+= snprintf(buffer
,
1615 src_port
->max_port
?
1616 src_port
->max_port
:
1617 src_port
->min_port
);
1618 if (dst_port
&& dst_port
->min_port
)
1619 remaining_len
+= snprintf(buffer
+
1625 dst_port
->max_port
?
1626 dst_port
->max_port
:
1627 dst_port
->min_port
);
1629 if (pkt_len
&& (pkt_len
->min_port
|| pkt_len
->max_port
)) {
1630 remaining_len
+= snprintf(buffer
+ remaining_len
,
1638 } else if (bpf
->pkt_len_val
) {
1639 remaining_len
+= snprintf(buffer
+ remaining_len
,
1643 bpf
->pkt_len_val
->mask
1645 bpf
->pkt_len_val
->val
);
1647 if (bpf
->tcp_flags
) {
1648 remaining_len
+= snprintf(buffer
+ remaining_len
,
1652 bpf
->tcp_flags
->val
,
1653 bpf
->tcp_flags
->mask
);
1656 snprintf(buffer
+ remaining_len
,
1664 zlog_info("BGP: adding FS PBR from %s to %s, %s %s",
1665 bpf
->src
== NULL
? "<all>" :
1666 prefix2str(bpf
->src
, bufsrc
, sizeof(bufsrc
)),
1667 bpf
->dst
== NULL
? "<all>" :
1668 prefix2str(bpf
->dst
, bufdst
, sizeof(bufdst
)),
1669 protocol_str
, buffer
);
1671 /* look for bpa first */
1672 memset(&temp3
, 0, sizeof(temp3
));
1676 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1677 temp3
.vrf_id
= bpf
->vrf_id
;
1678 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1679 bgp_pbr_action_alloc_intern
);
1681 if (bpa
->fwmark
== 0) {
1682 /* drop is handled by iptable */
1683 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1685 bpa
->installed
= true;
1687 bpa
->fwmark
= bgp_zebra_tm_get_id();
1688 bpa
->table_id
= bpa
->fwmark
;
1689 bpa
->installed
= false;
1692 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1693 /* 0 value is forbidden */
1694 bpa
->install_in_progress
= false;
1697 /* then look for bpm */
1698 memset(&temp
, 0, sizeof(temp
));
1699 temp
.vrf_id
= bpf
->vrf_id
;
1701 temp
.flags
|= MATCH_IP_SRC_SET
;
1703 temp
.flags
|= MATCH_IP_DST_SET
;
1705 if (src_port
&& (src_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1706 if (bpf
->protocol
== IPPROTO_ICMP
)
1707 temp
.flags
|= MATCH_ICMP_SET
;
1708 temp
.flags
|= MATCH_PORT_SRC_SET
;
1710 if (dst_port
&& (dst_port
->min_port
|| bpf
->protocol
== IPPROTO_ICMP
)) {
1711 if (bpf
->protocol
== IPPROTO_ICMP
)
1712 temp
.flags
|= MATCH_ICMP_SET
;
1713 temp
.flags
|= MATCH_PORT_DST_SET
;
1715 if (src_port
&& src_port
->max_port
)
1716 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1717 if (dst_port
&& dst_port
->max_port
)
1718 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1720 if (bpf
->src
== NULL
|| bpf
->dst
== NULL
) {
1721 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1722 temp
.type
= IPSET_NET_PORT
;
1724 temp
.type
= IPSET_NET
;
1726 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1727 temp
.type
= IPSET_NET_PORT_NET
;
1729 temp
.type
= IPSET_NET_NET
;
1732 temp
.pkt_len_min
= pkt_len
->min_port
;
1733 if (pkt_len
->max_port
)
1734 temp
.pkt_len_max
= pkt_len
->max_port
;
1735 } else if (bpf
->pkt_len_val
) {
1736 if (bpf
->pkt_len_val
->mask
)
1737 temp
.flags
|= MATCH_PKT_LEN_INVERSE_SET
;
1738 temp
.pkt_len_min
= bpf
->pkt_len_val
->val
;
1740 if (bpf
->tcp_flags
) {
1741 temp
.tcp_flags
= bpf
->tcp_flags
->val
;
1742 temp
.tcp_mask_flags
= bpf
->tcp_flags
->mask
;
1745 if (bpf
->dscp
->mask
)
1746 temp
.flags
|= MATCH_DSCP_INVERSE_SET
;
1748 temp
.flags
|= MATCH_DSCP_SET
;
1749 temp
.dscp_value
= bpf
->dscp
->val
;
1751 if (bpf
->fragment
) {
1752 if (bpf
->fragment
->mask
)
1753 temp
.flags
|= MATCH_FRAGMENT_INVERSE_SET
;
1754 temp
.fragment
= bpf
->fragment
->val
;
1757 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1758 bgp_pbr_match_alloc_intern
);
1760 /* new, then self allocate ipset_name and unique */
1761 if (bpm
&& bpm
->unique
== 0) {
1762 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1763 /* 0 value is forbidden */
1764 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1765 bpm
->entry_hash
= hash_create_size(8,
1766 bgp_pbr_match_entry_hash_key
,
1767 bgp_pbr_match_entry_hash_equal
,
1768 "Match Entry Hash");
1769 bpm
->installed
= false;
1771 /* unique2 should be updated too */
1772 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1773 bpm
->installed_in_iptable
= false;
1774 bpm
->install_in_progress
= false;
1775 bpm
->install_iptable_in_progress
= false;
1778 memset(&temp2
, 0, sizeof(temp2
));
1780 prefix_copy(&temp2
.src
, bpf
->src
);
1782 temp2
.src
.family
= AF_INET
;
1784 prefix_copy(&temp2
.dst
, bpf
->dst
);
1786 temp2
.dst
.family
= AF_INET
;
1787 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1788 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1789 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1790 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1791 temp2
.proto
= bpf
->protocol
;
1793 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1794 bgp_pbr_match_entry_alloc_intern
);
1795 if (bpme
&& bpme
->unique
== 0) {
1796 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1797 /* 0 value is forbidden */
1798 bpme
->backpointer
= bpm
;
1799 bpme
->installed
= false;
1800 bpme
->install_in_progress
= false;
1801 /* link bgp info to bpme */
1802 bpme
->bgp_info
= (void *)binfo
;
1805 /* BGP FS: append entry to zebra
1806 * - policies are not routing entries and as such
1807 * route replace semantics don't necessarily follow
1808 * through to policy entries
1809 * - because of that, not all policing information will be stored
1810 * into zebra. and non selected policies will be suppressed from zebra
1811 * - as consequence, in order to bring consistency
1812 * a policy will be added, then ifan ecmp policy exists,
1813 * it will be suppressed subsequently
1816 if (!bpa
->installed
&& !bpa
->install_in_progress
) {
1817 bgp_send_pbr_rule_action(bpa
, true);
1818 bgp_zebra_announce_default(bgp
, nh
,
1819 AFI_IP
, bpa
->table_id
, true);
1823 if (bpm
&& !bpm
->installed
)
1824 bgp_send_pbr_ipset_match(bpm
, true);
1826 if (bpme
&& !bpme
->installed
)
1827 bgp_send_pbr_ipset_entry_match(bpme
, true);
1830 if (bpm
&& !bpm
->installed_in_iptable
)
1831 bgp_send_pbr_iptable(bpa
, bpm
, true);
1833 /* A previous entry may already exist
1834 * flush previous entry if necessary
1836 bpmer
.bpme_to_match
= bpme
;
1837 bpmer
.bpme_found
= NULL
;
1838 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1839 if (bpmer
.bpme_found
) {
1840 static struct bgp_pbr_match
*local_bpm
;
1841 static struct bgp_pbr_action
*local_bpa
;
1843 local_bpm
= bpmer
.bpme_found
->backpointer
;
1844 local_bpa
= local_bpm
->action
;
1845 bgp_pbr_flush_entry(bgp
, local_bpa
,
1846 local_bpm
, bpmer
.bpme_found
);
1852 static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp
*bgp
,
1853 struct bgp_info
*binfo
,
1854 struct bgp_pbr_filter
*bpf
,
1855 struct bgp_pbr_or_filter
*bpof
,
1860 struct listnode
*node
, *nnode
;
1861 struct bgp_pbr_val_mask
*valmask
;
1862 uint8_t next_type_entry
;
1863 struct list
*orig_list
;
1864 struct bgp_pbr_val_mask
**target_val
;
1866 if (type_entry
== 0)
1867 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1869 next_type_entry
= bgp_pbr_next_type_entry(type_entry
);
1870 if (type_entry
== FLOWSPEC_TCP_FLAGS
&& bpof
->tcpflags
) {
1871 orig_list
= bpof
->tcpflags
;
1872 target_val
= &bpf
->tcp_flags
;
1873 } else if (type_entry
== FLOWSPEC_DSCP
&& bpof
->dscp
) {
1874 orig_list
= bpof
->dscp
;
1875 target_val
= &bpf
->dscp
;
1876 } else if (type_entry
== FLOWSPEC_PKT_LEN
&& bpof
->pkt_len
) {
1877 orig_list
= bpof
->pkt_len
;
1878 target_val
= &bpf
->pkt_len_val
;
1879 } else if (type_entry
== FLOWSPEC_FRAGMENT
&& bpof
->fragment
) {
1880 orig_list
= bpof
->fragment
;
1881 target_val
= &bpf
->fragment
;
1882 } else if (type_entry
== FLOWSPEC_ICMP_TYPE
&&
1883 (bpof
->icmp_type
|| bpof
->icmp_code
)) {
1884 /* enumerate list for icmp - must be last one */
1885 bgp_pbr_icmp_action(bgp
, binfo
, bpf
, bpof
, true, nh
, rate
);
1888 return bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1889 bpf
, bpof
, nh
, rate
,
1892 for (ALL_LIST_ELEMENTS(orig_list
, node
, nnode
, valmask
)) {
1893 *target_val
= valmask
;
1894 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1901 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1902 struct bgp_info
*binfo
,
1903 struct bgp_pbr_filter
*bpf
,
1904 struct bgp_pbr_or_filter
*bpof
,
1909 return bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
,
1912 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1915 FLOWSPEC_TCP_FLAGS
);
1916 else if (bpof
->dscp
)
1917 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1921 else if (bpof
->pkt_len
)
1922 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1926 else if (bpof
->fragment
)
1927 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1931 else if (bpof
->icmp_type
|| bpof
->icmp_code
)
1932 bgp_pbr_policyroute_add_to_zebra_recursive(bgp
, binfo
,
1933 bpf
, bpof
, nh
, rate
,
1934 FLOWSPEC_ICMP_TYPE
);
1936 bgp_pbr_policyroute_add_to_zebra_unit(bgp
, binfo
, bpf
,
1940 list_delete_all_node(bpof
->tcpflags
);
1942 list_delete_all_node(bpof
->dscp
);
1944 list_delete_all_node(bpof
->pkt_len
);
1946 list_delete_all_node(bpof
->fragment
);
1947 if (bpof
->icmp_type
)
1948 list_delete_all_node(bpof
->icmp_type
);
1949 if (bpof
->icmp_code
)
1950 list_delete_all_node(bpof
->icmp_code
);
1953 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
1954 struct bgp_info
*binfo
,
1955 struct bgp_pbr_entry_main
*api
,
1960 int continue_loop
= 1;
1962 struct prefix
*src
= NULL
, *dst
= NULL
;
1964 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
1965 struct bgp_pbr_range_port range
, range_icmp_code
;
1966 struct bgp_pbr_range_port pkt_len
;
1967 struct bgp_pbr_filter bpf
;
1969 struct bgp_pbr_or_filter bpof
;
1970 struct bgp_pbr_val_mask bpvm
;
1972 memset(&nh
, 0, sizeof(struct nexthop
));
1973 memset(&bpf
, 0, sizeof(struct bgp_pbr_filter
));
1974 memset(&bpof
, 0, sizeof(struct bgp_pbr_or_filter
));
1975 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
1976 src
= &api
->src_prefix
;
1977 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
1978 dst
= &api
->dst_prefix
;
1979 memset(&nh
, 0, sizeof(struct nexthop
));
1980 nh
.vrf_id
= VRF_UNKNOWN
;
1981 if (api
->match_protocol_num
)
1982 proto
= (uint8_t)api
->protocol
[0].value
;
1983 /* if match_port is selected, then either src or dst port will be parsed
1984 * but not both at the same time
1986 if (api
->match_port_num
>= 1) {
1987 bgp_pbr_extract(api
->port
,
1988 api
->match_port_num
,
1990 srcp
= dstp
= &range
;
1991 } else if (api
->match_src_port_num
>= 1) {
1992 bgp_pbr_extract(api
->src_port
,
1993 api
->match_src_port_num
,
1997 } else if (api
->match_dst_port_num
>= 1) {
1998 bgp_pbr_extract(api
->dst_port
,
1999 api
->match_dst_port_num
,
2004 if (api
->match_icmp_type_num
>= 1) {
2005 proto
= IPPROTO_ICMP
;
2006 if (bgp_pbr_extract(api
->icmp_type
,
2007 api
->match_icmp_type_num
,
2011 bpof
.icmp_type
= list_new();
2012 bgp_pbr_extract_enumerate(api
->icmp_type
,
2013 api
->match_icmp_type_num
,
2016 FLOWSPEC_ICMP_TYPE
);
2019 if (api
->match_icmp_code_num
>= 1) {
2020 proto
= IPPROTO_ICMP
;
2021 if (bgp_pbr_extract(api
->icmp_code
,
2022 api
->match_icmp_code_num
,
2024 dstp
= &range_icmp_code
;
2026 bpof
.icmp_code
= list_new();
2027 bgp_pbr_extract_enumerate(api
->icmp_code
,
2028 api
->match_icmp_code_num
,
2031 FLOWSPEC_ICMP_CODE
);
2035 if (api
->match_tcpflags_num
) {
2036 kind_enum
= bgp_pbr_match_val_get_operator(api
->tcpflags
,
2037 api
->match_tcpflags_num
);
2038 if (kind_enum
== OPERATOR_UNARY_AND
) {
2039 bpf
.tcp_flags
= &bpvm
;
2040 bgp_pbr_extract_enumerate(api
->tcpflags
,
2041 api
->match_tcpflags_num
,
2044 FLOWSPEC_TCP_FLAGS
);
2045 } else if (kind_enum
== OPERATOR_UNARY_OR
) {
2046 bpof
.tcpflags
= list_new();
2047 bgp_pbr_extract_enumerate(api
->tcpflags
,
2048 api
->match_tcpflags_num
,
2051 FLOWSPEC_TCP_FLAGS
);
2054 if (api
->match_packet_length_num
) {
2057 ret
= bgp_pbr_extract(api
->packet_length
,
2058 api
->match_packet_length_num
,
2061 bpf
.pkt_len
= &pkt_len
;
2063 bpof
.pkt_len
= list_new();
2064 bgp_pbr_extract_enumerate(api
->packet_length
,
2065 api
->match_packet_length_num
,
2071 if (api
->match_dscp_num
>= 1) {
2072 bpof
.dscp
= list_new();
2073 bgp_pbr_extract_enumerate(api
->dscp
, api
->match_dscp_num
,
2075 bpof
.dscp
, FLOWSPEC_DSCP
);
2077 if (api
->match_fragment_num
) {
2078 bpof
.fragment
= list_new();
2079 bgp_pbr_extract_enumerate(api
->fragment
,
2080 api
->match_fragment_num
,
2085 bpf
.vrf_id
= api
->vrf_id
;
2088 bpf
.protocol
= proto
;
2089 bpf
.src_port
= srcp
;
2090 bpf
.dst_port
= dstp
;
2092 return bgp_pbr_policyroute_remove_from_zebra(bgp
,
2095 /* no action for add = true */
2096 for (i
= 0; i
< api
->action_num
; i
++) {
2097 switch (api
->actions
[i
].action
) {
2098 case ACTION_TRAFFICRATE
:
2100 if (api
->actions
[i
].u
.r
.rate
== 0) {
2101 nh
.vrf_id
= api
->vrf_id
;
2102 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
2103 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2107 /* update rate. can be reentrant */
2108 rate
= api
->actions
[i
].u
.r
.rate
;
2109 if (BGP_DEBUG(pbr
, PBR
)) {
2110 bgp_pbr_print_policy_route(api
);
2111 zlog_warn("PBR: ignoring Set action rate %f",
2112 api
->actions
[i
].u
.r
.rate
);
2116 case ACTION_TRAFFIC_ACTION
:
2117 if (api
->actions
[i
].u
.za
.filter
2118 & TRAFFIC_ACTION_SAMPLE
) {
2119 if (BGP_DEBUG(pbr
, PBR
)) {
2120 bgp_pbr_print_policy_route(api
);
2121 zlog_warn("PBR: Sample action Ignored");
2125 if (api
->actions
[i
].u
.za
.filter
2126 & TRAFFIC_ACTION_DISTRIBUTE
) {
2127 if (BGP_DEBUG(pbr
, PBR
)) {
2128 bgp_pbr_print_policy_route(api
);
2129 zlog_warn("PBR: Distribute action Applies");
2132 /* continue forwarding entry as before
2136 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2137 /* terminate action: run other filters
2140 case ACTION_REDIRECT_IP
:
2141 nh
.type
= NEXTHOP_TYPE_IPV4
;
2142 nh
.gate
.ipv4
.s_addr
=
2143 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
2144 nh
.vrf_id
= api
->vrf_id
;
2145 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2148 /* XXX combination with REDIRECT_VRF
2149 * + REDIRECT_NH_IP not done
2153 case ACTION_REDIRECT
:
2154 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
2155 nh
.type
= NEXTHOP_TYPE_IPV4
;
2156 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
2161 case ACTION_MARKING
:
2162 if (BGP_DEBUG(pbr
, PBR
)) {
2163 bgp_pbr_print_policy_route(api
);
2164 zlog_warn("PBR: Set DSCP %u Ignored",
2165 api
->actions
[i
].u
.marking_dscp
);
2171 if (continue_loop
== 0)
2176 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
2177 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
2180 struct bgp_pbr_entry_main api
;
2181 struct bgp_info_extra
*extra
= bgp_info_extra_get(info
);
2184 return; /* IPv6 not supported */
2185 if (safi
!= SAFI_FLOWSPEC
)
2186 return; /* not supported */
2187 /* Make Zebra API structure. */
2188 memset(&api
, 0, sizeof(api
));
2189 api
.vrf_id
= bgp
->vrf_id
;
2192 if (!bgp_zebra_tm_chunk_obtained()) {
2193 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2194 zlog_err("%s: table chunk not obtained yet",
2198 /* already installed */
2199 if (nlri_update
&& extra
->bgp_fs_pbr
) {
2200 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2201 zlog_err("%s: entry %p already installed in bgp pbr",
2206 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
2207 if (BGP_DEBUG(pbr
, PBR_ERROR
))
2208 zlog_err("%s: cancel updating entry %p in bgp pbr",
2212 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
2215 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
2216 const struct bgp_pbr_interface
*b
)
2218 return strcmp(a
->name
, b
->name
);
2221 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
2222 struct bgp_pbr_interface_head
*head
)
2224 struct bgp_pbr_interface pbr_if
;
2226 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
2227 return (RB_FIND(bgp_pbr_interface_head
,
2231 /* this function resets to the default policy routing
2232 * go back to default status
2234 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
2236 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
2237 struct bgp_pbr_interface_head
*head
;
2238 struct bgp_pbr_interface
*pbr_if
;
2240 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
2242 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
2244 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
2245 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
2246 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
2247 XFREE(MTYPE_TMP
, pbr_if
);