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
25 #include "bgpd/bgpd.h"
26 #include "bgpd/bgp_pbr.h"
27 #include "bgpd/bgp_debug.h"
28 #include "bgpd/bgp_flowspec_util.h"
29 #include "bgpd/bgp_ecommunity.h"
30 #include "bgpd/bgp_route.h"
31 #include "bgpd/bgp_attr.h"
32 #include "bgpd/bgp_zebra.h"
33 #include "bgpd/bgp_mplsvpn.h"
35 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH_ENTRY
, "PBR match entry")
36 DEFINE_MTYPE_STATIC(BGPD
, PBR_MATCH
, "PBR match")
37 DEFINE_MTYPE_STATIC(BGPD
, PBR_ACTION
, "PBR action")
38 DEFINE_MTYPE_STATIC(BGPD
, PBR
, "BGP PBR Context")
40 RB_GENERATE(bgp_pbr_interface_head
, bgp_pbr_interface
,
41 id_entry
, bgp_pbr_interface_compare
);
42 struct bgp_pbr_interface_head ifaces_by_name_ipv4
=
43 RB_INITIALIZER(&ifaces_by_name_ipv4
);
45 static int bgp_pbr_match_counter_unique
;
46 static int bgp_pbr_match_entry_counter_unique
;
47 static int bgp_pbr_action_counter_unique
;
48 static int bgp_pbr_match_iptable_counter_unique
;
50 struct bgp_pbr_match_iptable_unique
{
52 struct bgp_pbr_match
*bpm_found
;
55 struct bgp_pbr_match_entry_unique
{
57 struct bgp_pbr_match_entry
*bpme_found
;
60 struct bgp_pbr_action_unique
{
62 struct bgp_pbr_action
*bpa_found
;
65 static int bgp_pbr_action_walkcb(struct hash_backet
*backet
, void *arg
)
67 struct bgp_pbr_action
*bpa
= (struct bgp_pbr_action
*)backet
->data
;
68 struct bgp_pbr_action_unique
*bpau
= (struct bgp_pbr_action_unique
*)
70 uint32_t unique
= bpau
->unique
;
72 if (bpa
->unique
== unique
) {
73 bpau
->bpa_found
= bpa
;
74 return HASHWALK_ABORT
;
76 return HASHWALK_CONTINUE
;
79 static int bgp_pbr_match_entry_walkcb(struct hash_backet
*backet
, void *arg
)
81 struct bgp_pbr_match_entry
*bpme
=
82 (struct bgp_pbr_match_entry
*)backet
->data
;
83 struct bgp_pbr_match_entry_unique
*bpmeu
=
84 (struct bgp_pbr_match_entry_unique
*)arg
;
85 uint32_t unique
= bpmeu
->unique
;
87 if (bpme
->unique
== unique
) {
88 bpmeu
->bpme_found
= bpme
;
89 return HASHWALK_ABORT
;
91 return HASHWALK_CONTINUE
;
94 struct bgp_pbr_match_ipsetname
{
96 struct bgp_pbr_match
*bpm_found
;
99 static int bgp_pbr_match_pername_walkcb(struct hash_backet
*backet
, void *arg
)
101 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
102 struct bgp_pbr_match_ipsetname
*bpmi
=
103 (struct bgp_pbr_match_ipsetname
*)arg
;
104 char *ipset_name
= bpmi
->ipsetname
;
106 if (!strncmp(ipset_name
, bpm
->ipset_name
,
107 ZEBRA_IPSET_NAME_SIZE
)) {
108 bpmi
->bpm_found
= bpm
;
109 return HASHWALK_ABORT
;
111 return HASHWALK_CONTINUE
;
114 static int bgp_pbr_match_iptable_walkcb(struct hash_backet
*backet
, void *arg
)
116 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
117 struct bgp_pbr_match_iptable_unique
*bpmiu
=
118 (struct bgp_pbr_match_iptable_unique
*)arg
;
119 uint32_t unique
= bpmiu
->unique
;
121 if (bpm
->unique2
== unique
) {
122 bpmiu
->bpm_found
= bpm
;
123 return HASHWALK_ABORT
;
125 return HASHWALK_CONTINUE
;
128 struct bgp_pbr_match_unique
{
130 struct bgp_pbr_match
*bpm_found
;
133 static int bgp_pbr_match_walkcb(struct hash_backet
*backet
, void *arg
)
135 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
136 struct bgp_pbr_match_unique
*bpmu
= (struct bgp_pbr_match_unique
*)
138 uint32_t unique
= bpmu
->unique
;
140 if (bpm
->unique
== unique
) {
141 bpmu
->bpm_found
= bpm
;
142 return HASHWALK_ABORT
;
144 return HASHWALK_CONTINUE
;
147 static int sprintf_bgp_pbr_match_val(char *str
, struct bgp_pbr_match_val
*mval
,
153 ptr
+= sprintf(ptr
, "%s", prepend
);
155 if (mval
->unary_operator
& OPERATOR_UNARY_OR
)
156 ptr
+= sprintf(ptr
, ", or ");
157 if (mval
->unary_operator
& OPERATOR_UNARY_AND
)
158 ptr
+= sprintf(ptr
, ", and ");
160 if (mval
->compare_operator
& OPERATOR_COMPARE_LESS_THAN
)
161 ptr
+= sprintf(ptr
, "<");
162 if (mval
->compare_operator
& OPERATOR_COMPARE_GREATER_THAN
)
163 ptr
+= sprintf(ptr
, ">");
164 if (mval
->compare_operator
& OPERATOR_COMPARE_EQUAL_TO
)
165 ptr
+= sprintf(ptr
, "=");
166 if (mval
->compare_operator
& OPERATOR_COMPARE_EXACT_MATCH
)
167 ptr
+= sprintf(ptr
, "match");
168 ptr
+= sprintf(ptr
, " %u", mval
->value
);
169 return (int)(ptr
- str
);
172 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
174 (_ptr) += sprintf((_ptr), "; "); \
178 struct bgp_pbr_range_port
{
183 /* return true if extraction ok
185 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
187 struct bgp_pbr_range_port
*range
)
190 bool exact_match
= false;
193 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
197 for (i
= 0; i
< num
; i
++) {
198 if (i
!= 0 && (list
[i
].compare_operator
==
199 OPERATOR_COMPARE_EQUAL_TO
))
201 if (i
== 0 && (list
[i
].compare_operator
==
202 OPERATOR_COMPARE_EQUAL_TO
)) {
204 range
->min_port
= list
[i
].value
;
207 if (exact_match
== true && i
> 0)
209 if (list
[i
].compare_operator
==
210 (OPERATOR_COMPARE_GREATER_THAN
+
211 OPERATOR_COMPARE_EQUAL_TO
)) {
213 range
->min_port
= list
[i
].value
;
214 } else if (list
[i
].compare_operator
==
215 (OPERATOR_COMPARE_LESS_THAN
+
216 OPERATOR_COMPARE_EQUAL_TO
)) {
218 range
->max_port
= list
[i
].value
;
219 } else if (list
[i
].compare_operator
==
220 OPERATOR_COMPARE_LESS_THAN
) {
222 range
->max_port
= list
[i
].value
- 1;
223 } else if (list
[i
].compare_operator
==
224 OPERATOR_COMPARE_GREATER_THAN
) {
226 range
->min_port
= list
[i
].value
+ 1;
232 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
234 /* because bgp pbr entry may contain unsupported
235 * combinations, a message will be displayed here if
237 * for now, only match/set supported is
238 * - combination src/dst => redirect nexthop [ + rate]
239 * - combination src/dst => redirect VRF [ + rate]
240 * - combination src/dst => drop
241 * - combination srcport + @IP
243 if (api
->match_icmp_type_num
|| api
->match_packet_length_num
244 || api
->match_dscp_num
|| api
->match_tcpflags_num
) {
245 if (BGP_DEBUG(pbr
, PBR
)) {
246 bgp_pbr_print_policy_route(api
);
247 zlog_debug("BGP: some SET actions not supported by Zebra. ignoring.");
248 zlog_debug("BGP: case icmp or length or dscp or tcp flags");
253 if (api
->match_protocol_num
> 1) {
254 if (BGP_DEBUG(pbr
, PBR
))
255 zlog_debug("BGP: match protocol operations:"
256 "multiple protocols ( %d). ignoring.",
257 api
->match_protocol_num
);
260 if (api
->match_protocol_num
== 1 &&
261 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
262 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
263 if (BGP_DEBUG(pbr
, PBR
))
264 zlog_debug("BGP: match protocol operations:"
265 "protocol (%d) not supported. ignoring",
266 api
->match_protocol_num
);
269 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
270 if (BGP_DEBUG(pbr
, PBR
))
271 zlog_debug("BGP: match src port operations:"
272 "too complex. ignoring.");
275 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
276 if (BGP_DEBUG(pbr
, PBR
))
277 zlog_debug("BGP: match dst port operations:"
278 "too complex. ignoring.");
281 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
282 if (BGP_DEBUG(pbr
, PBR
))
283 zlog_debug("BGP: match port operations:"
284 "too complex. ignoring.");
287 /* no combinations with both src_port and dst_port
288 * or port with src_port and dst_port
290 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
291 api
->match_port_num
> 3) {
292 if (BGP_DEBUG(pbr
, PBR
))
293 zlog_debug("BGP: match multiple port operations:"
294 " too complex. ignoring.");
297 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
298 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
299 if (BGP_DEBUG(pbr
, PBR
)) {
300 bgp_pbr_print_policy_route(api
);
301 zlog_debug("BGP: match actions without src"
302 " or dst address can not operate."
310 /* return -1 if build or validation failed */
311 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
312 struct bgp_info
*info
,
313 struct bgp_pbr_entry_main
*api
)
316 int i
, action_count
= 0;
317 struct ecommunity
*ecom
;
318 struct ecommunity_val
*ecom_eval
;
319 struct bgp_pbr_entry_action
*api_action
;
320 struct prefix
*src
= NULL
, *dst
= NULL
;
321 int valid_prefix
= 0;
324 /* extract match from flowspec entries */
325 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
326 p
->u
.prefix_flowspec
.prefixlen
, api
);
329 /* extract actiosn from flowspec ecom list */
330 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
331 ecom
= info
->attr
->ecommunity
;
332 for (i
= 0; i
< ecom
->size
; i
++) {
333 ecom_eval
= (struct ecommunity_val
*)
334 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
336 if (action_count
> ACTIONS_MAX_NUM
) {
337 if (BGP_DEBUG(pbr
, PBR_ERROR
))
338 zlog_err("%s: flowspec actions exceeds limit (max %u)",
339 __func__
, action_count
);
342 api_action
= &api
->actions
[action_count
- 1];
344 if ((ecom_eval
->val
[1] ==
345 (char)ECOMMUNITY_REDIRECT_VRF
) &&
346 (ecom_eval
->val
[0] ==
347 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
349 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
351 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
352 struct ecommunity
*eckey
= ecommunity_new();
353 struct ecommunity_val ecom_copy
;
355 memcpy(&ecom_copy
, ecom_eval
,
356 sizeof(struct ecommunity_val
));
358 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
359 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
360 ecommunity_add_val(eckey
, &ecom_copy
);
362 api_action
->action
= ACTION_REDIRECT
;
363 api_action
->u
.redirect_vrf
=
364 get_first_vrf_for_redirect_with_rt(
366 ecommunity_free(&eckey
);
367 } else if ((ecom_eval
->val
[0] ==
368 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
369 (ecom_eval
->val
[1] ==
370 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
371 api_action
->action
= ACTION_REDIRECT_IP
;
372 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
373 info
->attr
->nexthop
.s_addr
;
374 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
376 if (ecom_eval
->val
[0] !=
377 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
379 ret
= ecommunity_fill_pbr_action(ecom_eval
,
388 /* validate if incoming matc/action is compatible
389 * with our policy routing engine
391 if (!bgp_pbr_validate_policy_route(api
))
394 /* check inconsistency in the match rule */
395 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
396 src
= &api
->src_prefix
;
397 afi
= family2afi(src
->family
);
400 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
401 dst
= &api
->dst_prefix
;
402 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
403 if (BGP_DEBUG(pbr
, PBR
)) {
404 bgp_pbr_print_policy_route(api
);
405 zlog_debug("%s: inconsistency:"
406 " no match for afi src and dst (%u/%u)",
407 __func__
, afi
, family2afi(dst
->family
));
415 static void bgp_pbr_match_entry_free(void *arg
)
417 struct bgp_pbr_match_entry
*bpme
;
419 bpme
= (struct bgp_pbr_match_entry
*)arg
;
421 if (bpme
->installed
) {
422 bgp_send_pbr_ipset_entry_match(bpme
, false);
423 bpme
->installed
= false;
424 bpme
->backpointer
= NULL
;
426 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
429 static void bgp_pbr_match_free(void *arg
)
431 struct bgp_pbr_match
*bpm
;
433 bpm
= (struct bgp_pbr_match
*)arg
;
435 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
437 if (hashcount(bpm
->entry_hash
) == 0) {
438 /* delete iptable entry first */
439 /* then delete ipset match */
440 if (bpm
->installed
) {
441 if (bpm
->installed_in_iptable
) {
442 bgp_send_pbr_iptable(bpm
->action
,
444 bpm
->installed_in_iptable
= false;
445 bpm
->action
->refcnt
--;
447 bgp_send_pbr_ipset_match(bpm
, false);
448 bpm
->installed
= false;
452 hash_free(bpm
->entry_hash
);
454 XFREE(MTYPE_PBR_MATCH
, bpm
);
457 static void *bgp_pbr_match_alloc_intern(void *arg
)
459 struct bgp_pbr_match
*bpm
, *new;
461 bpm
= (struct bgp_pbr_match
*)arg
;
463 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
464 memcpy(new, bpm
, sizeof(*bpm
));
469 static void bgp_pbr_action_free(void *arg
)
471 struct bgp_pbr_action
*bpa
;
473 bpa
= (struct bgp_pbr_action
*)arg
;
475 if (bpa
->refcnt
== 0) {
476 if (bpa
->installed
&& bpa
->table_id
!= 0) {
477 bgp_send_pbr_rule_action(bpa
, false);
478 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
482 bpa
->installed
= false;
485 XFREE(MTYPE_PBR_ACTION
, bpa
);
488 static void *bgp_pbr_action_alloc_intern(void *arg
)
490 struct bgp_pbr_action
*bpa
, *new;
492 bpa
= (struct bgp_pbr_action
*)arg
;
494 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
496 memcpy(new, bpa
, sizeof(*bpa
));
501 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
503 struct bgp_pbr_match_entry
*bpme
, *new;
505 bpme
= (struct bgp_pbr_match_entry
*)arg
;
507 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
509 memcpy(new, bpme
, sizeof(*bpme
));
514 uint32_t bgp_pbr_match_hash_key(void *arg
)
516 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
519 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
520 key
= jhash_1word(pbm
->flags
, key
);
521 return jhash_1word(pbm
->type
, key
);
524 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
526 const struct bgp_pbr_match
*r1
, *r2
;
528 r1
= (const struct bgp_pbr_match
*)arg1
;
529 r2
= (const struct bgp_pbr_match
*)arg2
;
531 if (r1
->vrf_id
!= r2
->vrf_id
)
534 if (r1
->type
!= r2
->type
)
537 if (r1
->flags
!= r2
->flags
)
540 if (r1
->action
!= r2
->action
)
546 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
548 struct bgp_pbr_match_entry
*pbme
;
551 pbme
= (struct bgp_pbr_match_entry
*)arg
;
552 key
= prefix_hash_key(&pbme
->src
);
553 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
554 key
= jhash(&pbme
->dst_port_min
, 2, key
);
555 key
= jhash(&pbme
->src_port_min
, 2, key
);
556 key
= jhash(&pbme
->dst_port_max
, 2, key
);
557 key
= jhash(&pbme
->src_port_max
, 2, key
);
558 key
= jhash(&pbme
->proto
, 1, key
);
563 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
565 const struct bgp_pbr_match_entry
*r1
, *r2
;
567 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
568 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
570 /* on updates, comparing
571 * backpointer is not necessary
574 /* unique value is self calculated
577 /* rate is ignored for now
580 if (!prefix_same(&r1
->src
, &r2
->src
))
583 if (!prefix_same(&r1
->dst
, &r2
->dst
))
586 if (r1
->src_port_min
!= r2
->src_port_min
)
589 if (r1
->dst_port_min
!= r2
->dst_port_min
)
592 if (r1
->src_port_max
!= r2
->src_port_max
)
595 if (r1
->dst_port_max
!= r2
->dst_port_max
)
598 if (r1
->proto
!= r2
->proto
)
604 uint32_t bgp_pbr_action_hash_key(void *arg
)
606 struct bgp_pbr_action
*pbra
;
609 pbra
= (struct bgp_pbr_action
*)arg
;
610 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
611 key
= jhash_1word(pbra
->fwmark
, key
);
615 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
617 const struct bgp_pbr_action
*r1
, *r2
;
619 r1
= (const struct bgp_pbr_action
*)arg1
;
620 r2
= (const struct bgp_pbr_action
*)arg2
;
622 /* unique value is self calculated
623 * table and fwmark is self calculated
626 if (r1
->vrf_id
!= r2
->vrf_id
)
629 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
634 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
637 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
638 struct bgp_pbr_action_unique bpau
;
640 if (!bgp
|| unique
== 0)
642 bpau
.unique
= unique
;
643 bpau
.bpa_found
= NULL
;
644 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
645 return bpau
.bpa_found
;
648 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
651 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
652 struct bgp_pbr_match_unique bpmu
;
654 if (!bgp
|| unique
== 0)
656 bpmu
.unique
= unique
;
657 bpmu
.bpm_found
= NULL
;
658 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
659 return bpmu
.bpm_found
;
662 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
666 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
667 struct bgp_pbr_match_entry_unique bpmeu
;
668 struct bgp_pbr_match_ipsetname bpmi
;
670 if (!bgp
|| unique
== 0)
672 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
673 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
674 bpmi
.bpm_found
= NULL
;
675 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
676 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
679 bpmeu
.bpme_found
= NULL
;
680 bpmeu
.unique
= unique
;
681 hash_walk(bpmi
.bpm_found
->entry_hash
,
682 bgp_pbr_match_entry_walkcb
, &bpmeu
);
683 return bpmeu
.bpme_found
;
686 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
689 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
690 struct bgp_pbr_match_iptable_unique bpmiu
;
692 if (!bgp
|| unique
== 0)
694 bpmiu
.unique
= unique
;
695 bpmiu
.bpm_found
= NULL
;
696 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
697 return bpmiu
.bpm_found
;
700 void bgp_pbr_cleanup(struct bgp
*bgp
)
702 if (bgp
->pbr_match_hash
) {
703 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
704 hash_free(bgp
->pbr_match_hash
);
705 bgp
->pbr_match_hash
= NULL
;
707 if (bgp
->pbr_action_hash
) {
708 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
709 hash_free(bgp
->pbr_action_hash
);
710 bgp
->pbr_action_hash
= NULL
;
712 if (bgp
->bgp_pbr_cfg
== NULL
)
714 bgp_pbr_reset(bgp
, AFI_IP
);
715 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
716 bgp
->bgp_pbr_cfg
= NULL
;
719 void bgp_pbr_init(struct bgp
*bgp
)
721 bgp
->pbr_match_hash
=
722 hash_create_size(8, bgp_pbr_match_hash_key
,
723 bgp_pbr_match_hash_equal
,
725 bgp
->pbr_action_hash
=
726 hash_create_size(8, bgp_pbr_action_hash_key
,
727 bgp_pbr_action_hash_equal
,
730 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
731 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
734 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
737 char return_string
[512];
738 char *ptr
= return_string
;
742 ptr
+= sprintf(ptr
, "MATCH : ");
743 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
744 struct prefix
*p
= &(api
->src_prefix
);
746 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
747 INCREMENT_DISPLAY(ptr
, nb_items
);
749 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
750 struct prefix
*p
= &(api
->dst_prefix
);
752 INCREMENT_DISPLAY(ptr
, nb_items
);
753 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
756 if (api
->match_protocol_num
)
757 INCREMENT_DISPLAY(ptr
, nb_items
);
758 for (i
= 0; i
< api
->match_protocol_num
; i
++)
759 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
760 i
> 0 ? NULL
: "@proto ");
762 if (api
->match_src_port_num
)
763 INCREMENT_DISPLAY(ptr
, nb_items
);
764 for (i
= 0; i
< api
->match_src_port_num
; i
++)
765 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
766 i
> 0 ? NULL
: "@srcport ");
768 if (api
->match_dst_port_num
)
769 INCREMENT_DISPLAY(ptr
, nb_items
);
770 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
771 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
772 i
> 0 ? NULL
: "@dstport ");
774 if (api
->match_port_num
)
775 INCREMENT_DISPLAY(ptr
, nb_items
);
776 for (i
= 0; i
< api
->match_port_num
; i
++)
777 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
778 i
> 0 ? NULL
: "@port ");
780 if (api
->match_icmp_type_num
)
781 INCREMENT_DISPLAY(ptr
, nb_items
);
782 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
783 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
784 i
> 0 ? NULL
: "@icmptype ");
786 if (api
->match_icmp_code_num
)
787 INCREMENT_DISPLAY(ptr
, nb_items
);
788 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
789 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
790 i
> 0 ? NULL
: "@icmpcode ");
792 if (api
->match_packet_length_num
)
793 INCREMENT_DISPLAY(ptr
, nb_items
);
794 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
795 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
796 i
> 0 ? NULL
: "@plen ");
798 if (api
->match_dscp_num
)
799 INCREMENT_DISPLAY(ptr
, nb_items
);
800 for (i
= 0; i
< api
->match_dscp_num
; i
++)
801 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
802 i
> 0 ? NULL
: "@dscp ");
804 if (api
->match_tcpflags_num
)
805 INCREMENT_DISPLAY(ptr
, nb_items
);
806 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
807 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
808 i
> 0 ? NULL
: "@tcpflags ");
810 if (api
->match_bitmask
& FRAGMENT_PRESENT
) {
811 INCREMENT_DISPLAY(ptr
, nb_items
);
812 ptr
+= sprintf(ptr
, "@fragment %u", api
->fragment
.bitmask
);
817 ptr
+= sprintf(ptr
, "; ");
819 ptr
+= sprintf(ptr
, "SET : ");
821 for (i
= 0; i
< api
->action_num
; i
++) {
822 switch (api
->actions
[i
].action
) {
823 case ACTION_TRAFFICRATE
:
824 INCREMENT_DISPLAY(ptr
, nb_items
);
825 ptr
+= sprintf(ptr
, "@set rate %f",
826 api
->actions
[i
].u
.r
.rate
);
828 case ACTION_TRAFFIC_ACTION
:
829 INCREMENT_DISPLAY(ptr
, nb_items
);
830 ptr
+= sprintf(ptr
, "@action ");
831 if (api
->actions
[i
].u
.za
.filter
832 & TRAFFIC_ACTION_TERMINATE
)
834 " terminate (apply filter(s))");
835 if (api
->actions
[i
].u
.za
.filter
836 & TRAFFIC_ACTION_DISTRIBUTE
)
837 ptr
+= sprintf(ptr
, " distribute");
838 if (api
->actions
[i
].u
.za
.filter
839 & TRAFFIC_ACTION_SAMPLE
)
840 ptr
+= sprintf(ptr
, " sample");
842 case ACTION_REDIRECT_IP
:
843 INCREMENT_DISPLAY(ptr
, nb_items
);
844 char local_buff
[INET_ADDRSTRLEN
];
846 if (inet_ntop(AF_INET
,
847 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
848 local_buff
, INET_ADDRSTRLEN
) != NULL
)
850 "@redirect ip nh %s", local_buff
);
852 case ACTION_REDIRECT
:
853 INCREMENT_DISPLAY(ptr
, nb_items
);
854 ptr
+= sprintf(ptr
, "@redirect vrf %u",
855 api
->actions
[i
].u
.redirect_vrf
);
858 INCREMENT_DISPLAY(ptr
, nb_items
);
859 ptr
+= sprintf(ptr
, "@set dscp %u",
860 api
->actions
[i
].u
.marking_dscp
);
866 zlog_info("%s", return_string
);
869 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
870 struct bgp_pbr_match
*bpm
,
871 struct bgp_pbr_match_entry
*bpme
)
873 /* if bpme is null, bpm is also null
877 /* ipset del entry */
878 if (bpme
->installed
) {
879 bgp_send_pbr_ipset_entry_match(bpme
, false);
880 bpme
->installed
= false;
881 bpme
->backpointer
= NULL
;
882 if (bpme
->bgp_info
) {
883 struct bgp_info
*bgp_info
;
884 struct bgp_info_extra
*extra
;
886 /* unlink bgp_info to bpme */
887 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
888 extra
= bgp_info_extra_get(bgp_info
);
889 extra
->bgp_fs_pbr
= NULL
;
890 bpme
->bgp_info
= NULL
;
893 hash_release(bpm
->entry_hash
, bpme
);
894 if (hashcount(bpm
->entry_hash
) == 0) {
895 /* delete iptable entry first */
896 /* then delete ipset match */
897 if (bpm
->installed
) {
898 if (bpm
->installed_in_iptable
) {
899 bgp_send_pbr_iptable(bpm
->action
,
901 bpm
->installed_in_iptable
= false;
902 bpm
->action
->refcnt
--;
904 bgp_send_pbr_ipset_match(bpm
, false);
905 bpm
->installed
= false;
908 hash_release(bgp
->pbr_match_hash
, bpm
);
909 /* XXX release pbr_match_action if not used
910 * note that drop does not need to call send_pbr_action
913 if (bpa
->refcnt
== 0) {
914 if (bpa
->installed
&& bpa
->table_id
!= 0) {
915 bgp_send_pbr_rule_action(bpa
, false);
916 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
920 bpa
->installed
= false;
925 struct bgp_pbr_match_entry_remain
{
926 struct bgp_pbr_match_entry
*bpme_to_match
;
927 struct bgp_pbr_match_entry
*bpme_found
;
930 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
932 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
933 struct bgp_pbr_match_entry_remain
*bpmer
=
934 (struct bgp_pbr_match_entry_remain
*)arg
;
935 struct bgp_pbr_match
*bpm_temp
;
936 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
938 if (!bpme
->backpointer
||
939 bpm
== bpme
->backpointer
||
940 bpme
->backpointer
->action
== bpm
->action
)
941 return HASHWALK_CONTINUE
;
942 /* ensure bpm other characteristics are equal */
943 bpm_temp
= bpme
->backpointer
;
944 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
945 bpm_temp
->type
!= bpm
->type
||
946 bpm_temp
->flags
!= bpm
->flags
)
947 return HASHWALK_CONTINUE
;
949 /* look for remaining bpme */
950 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
951 if (!bpmer
->bpme_found
)
952 return HASHWALK_CONTINUE
;
953 return HASHWALK_ABORT
;
956 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
957 struct bgp_info
*binfo
,
962 struct bgp_pbr_range_port
*src_port
,
963 struct bgp_pbr_range_port
*dst_port
)
965 struct bgp_pbr_match temp
;
966 struct bgp_pbr_match_entry temp2
;
967 struct bgp_pbr_match
*bpm
;
968 struct bgp_pbr_match_entry
*bpme
;
969 struct bgp_pbr_match_entry_remain bpmer
;
971 /* as we don't know information from EC
972 * look for bpm that have the bpm
973 * with vrf_id characteristics
975 memset(&temp2
, 0, sizeof(temp2
));
976 memset(&temp
, 0, sizeof(temp
));
978 temp
.flags
|= MATCH_IP_SRC_SET
;
979 prefix_copy(&temp2
.src
, src
);
981 temp2
.src
.family
= AF_INET
;
983 temp
.flags
|= MATCH_IP_DST_SET
;
984 prefix_copy(&temp2
.dst
, dst
);
986 temp2
.dst
.family
= AF_INET
;
988 temp
.flags
|= MATCH_PORT_SRC_SET
;
989 temp2
.src_port_min
= src_port
->min_port
;
990 if (src_port
->max_port
) {
991 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
992 temp2
.src_port_max
= src_port
->max_port
;
996 temp
.flags
|= MATCH_PORT_DST_SET
;
997 temp2
.dst_port_min
= dst_port
->min_port
;
998 if (dst_port
->max_port
) {
999 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1000 temp2
.dst_port_max
= dst_port
->max_port
;
1003 temp2
.proto
= protocol
;
1005 if (src
== NULL
|| dst
== NULL
) {
1006 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1007 temp
.type
= IPSET_NET_PORT
;
1009 temp
.type
= IPSET_NET
;
1011 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1012 temp
.type
= IPSET_NET_PORT_NET
;
1014 temp
.type
= IPSET_NET_NET
;
1016 if (vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1019 temp
.vrf_id
= vrf_id
;
1022 bpme
->backpointer
= bpm
;
1023 /* right now, a previous entry may already exist
1024 * flush previous entry if necessary
1026 bpmer
.bpme_to_match
= bpme
;
1027 bpmer
.bpme_found
= NULL
;
1028 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1029 if (bpmer
.bpme_found
) {
1030 static struct bgp_pbr_match
*local_bpm
;
1031 static struct bgp_pbr_action
*local_bpa
;
1033 local_bpm
= bpmer
.bpme_found
->backpointer
;
1034 local_bpa
= local_bpm
->action
;
1035 bgp_pbr_flush_entry(bgp
, local_bpa
,
1036 local_bpm
, bpmer
.bpme_found
);
1040 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1041 struct bgp_info
*binfo
,
1048 struct bgp_pbr_range_port
*src_port
,
1049 struct bgp_pbr_range_port
*dst_port
)
1051 struct bgp_pbr_match temp
;
1052 struct bgp_pbr_match_entry temp2
;
1053 struct bgp_pbr_match
*bpm
;
1054 struct bgp_pbr_match_entry
*bpme
= NULL
;
1055 struct bgp_pbr_action temp3
;
1056 struct bgp_pbr_action
*bpa
= NULL
;
1057 struct bgp_pbr_match_entry_remain bpmer
;
1059 /* look for bpa first */
1060 memset(&temp3
, 0, sizeof(temp3
));
1064 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1065 temp3
.vrf_id
= vrf_id
;
1066 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1067 bgp_pbr_action_alloc_intern
);
1069 if (bpa
->fwmark
== 0) {
1070 /* drop is handled by iptable */
1071 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1073 bpa
->installed
= true;
1075 bpa
->fwmark
= bgp_zebra_tm_get_id();
1076 bpa
->table_id
= bpa
->fwmark
;
1077 bpa
->installed
= false;
1080 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1081 /* 0 value is forbidden */
1082 bpa
->install_in_progress
= false;
1085 /* then look for bpm */
1086 memset(&temp
, 0, sizeof(temp
));
1087 if (src
== NULL
|| dst
== NULL
) {
1088 if ((src_port
&& src_port
->min_port
) ||
1089 (dst_port
&& dst_port
->min_port
))
1090 temp
.type
= IPSET_NET_PORT
;
1092 temp
.type
= IPSET_NET
;
1094 if ((src_port
&& src_port
->min_port
) ||
1095 (dst_port
&& dst_port
->min_port
))
1096 temp
.type
= IPSET_NET_PORT_NET
;
1098 temp
.type
= IPSET_NET_NET
;
1100 temp
.vrf_id
= vrf_id
;
1102 temp
.flags
|= MATCH_IP_SRC_SET
;
1104 temp
.flags
|= MATCH_IP_DST_SET
;
1106 if (src_port
&& src_port
->min_port
)
1107 temp
.flags
|= MATCH_PORT_SRC_SET
;
1108 if (dst_port
&& dst_port
->min_port
)
1109 temp
.flags
|= MATCH_PORT_DST_SET
;
1110 if (src_port
&& src_port
->max_port
)
1111 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1112 if (dst_port
&& dst_port
->max_port
)
1113 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1115 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1116 bgp_pbr_match_alloc_intern
);
1118 /* new, then self allocate ipset_name and unique */
1119 if (bpm
&& bpm
->unique
== 0) {
1120 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1121 /* 0 value is forbidden */
1122 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1123 bpm
->entry_hash
= hash_create_size(8,
1124 bgp_pbr_match_entry_hash_key
,
1125 bgp_pbr_match_entry_hash_equal
,
1126 "Match Entry Hash");
1127 bpm
->installed
= false;
1129 /* unique2 should be updated too */
1130 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1131 bpm
->installed_in_iptable
= false;
1132 bpm
->install_in_progress
= false;
1133 bpm
->install_iptable_in_progress
= false;
1136 memset(&temp2
, 0, sizeof(temp2
));
1138 prefix_copy(&temp2
.src
, src
);
1140 temp2
.src
.family
= AF_INET
;
1142 prefix_copy(&temp2
.dst
, dst
);
1144 temp2
.dst
.family
= AF_INET
;
1145 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1146 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1147 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1148 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1149 temp2
.proto
= protocol
;
1151 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1152 bgp_pbr_match_entry_alloc_intern
);
1153 if (bpme
&& bpme
->unique
== 0) {
1154 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1155 /* 0 value is forbidden */
1156 bpme
->backpointer
= bpm
;
1157 bpme
->installed
= false;
1158 bpme
->install_in_progress
= false;
1159 /* link bgp info to bpme */
1160 bpme
->bgp_info
= (void *)binfo
;
1163 /* BGP FS: append entry to zebra
1164 * - policies are not routing entries and as such
1165 * route replace semantics don't necessarily follow
1166 * through to policy entries
1167 * - because of that, not all policing information will be stored
1168 * into zebra. and non selected policies will be suppressed from zebra
1169 * - as consequence, in order to bring consistency
1170 * a policy will be added, then ifan ecmp policy exists,
1171 * it will be suppressed subsequently
1174 if (!bpa
->installed
) {
1175 bgp_send_pbr_rule_action(bpa
, true);
1176 bgp_zebra_announce_default(bgp
, nh
,
1177 AFI_IP
, bpa
->table_id
, true);
1181 if (bpm
&& !bpm
->installed
)
1182 bgp_send_pbr_ipset_match(bpm
, true);
1184 if (bpme
&& !bpme
->installed
)
1185 bgp_send_pbr_ipset_entry_match(bpme
, true);
1188 if (bpm
&& !bpm
->installed_in_iptable
)
1189 bgp_send_pbr_iptable(bpa
, bpm
, true);
1191 /* A previous entry may already exist
1192 * flush previous entry if necessary
1194 bpmer
.bpme_to_match
= bpme
;
1195 bpmer
.bpme_found
= NULL
;
1196 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1197 if (bpmer
.bpme_found
) {
1198 static struct bgp_pbr_match
*local_bpm
;
1199 static struct bgp_pbr_action
*local_bpa
;
1201 local_bpm
= bpmer
.bpme_found
->backpointer
;
1202 local_bpa
= local_bpm
->action
;
1203 bgp_pbr_flush_entry(bgp
, local_bpa
,
1204 local_bpm
, bpmer
.bpme_found
);
1210 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
1211 struct bgp_info
*binfo
,
1212 struct bgp_pbr_entry_main
*api
,
1217 int continue_loop
= 1;
1219 struct prefix
*src
= NULL
, *dst
= NULL
;
1221 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
1222 struct bgp_pbr_range_port range
;
1224 memset(&nh
, 0, sizeof(struct nexthop
));
1225 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
1226 src
= &api
->src_prefix
;
1227 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
1228 dst
= &api
->dst_prefix
;
1229 memset(&nh
, 0, sizeof(struct nexthop
));
1230 nh
.vrf_id
= VRF_UNKNOWN
;
1231 if (api
->match_protocol_num
)
1232 proto
= (uint8_t)api
->protocol
[0].value
;
1233 /* if match_port is selected, then either src or dst port will be parsed
1234 * but not both at the same time
1236 if (api
->match_port_num
>= 1) {
1237 bgp_pbr_extract(api
->port
,
1238 api
->match_port_num
,
1240 srcp
= dstp
= &range
;
1241 } else if (api
->match_src_port_num
>= 1) {
1242 bgp_pbr_extract(api
->src_port
,
1243 api
->match_src_port_num
,
1247 } else if (api
->match_dst_port_num
>= 1) {
1248 bgp_pbr_extract(api
->dst_port
,
1249 api
->match_dst_port_num
,
1255 return bgp_pbr_policyroute_remove_from_zebra(bgp
, binfo
,
1256 api
->vrf_id
, src
, dst
,
1258 /* no action for add = true */
1259 for (i
= 0; i
< api
->action_num
; i
++) {
1260 switch (api
->actions
[i
].action
) {
1261 case ACTION_TRAFFICRATE
:
1263 if (api
->actions
[i
].u
.r
.rate
== 0) {
1264 nh
.vrf_id
= api
->vrf_id
;
1265 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
1266 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1267 api
->vrf_id
, src
, dst
,
1271 /* update rate. can be reentrant */
1272 rate
= api
->actions
[i
].u
.r
.rate
;
1273 if (BGP_DEBUG(pbr
, PBR
)) {
1274 bgp_pbr_print_policy_route(api
);
1275 zlog_warn("PBR: ignoring Set action rate %f",
1276 api
->actions
[i
].u
.r
.rate
);
1280 case ACTION_TRAFFIC_ACTION
:
1281 if (api
->actions
[i
].u
.za
.filter
1282 & TRAFFIC_ACTION_SAMPLE
) {
1283 if (BGP_DEBUG(pbr
, PBR
)) {
1284 bgp_pbr_print_policy_route(api
);
1285 zlog_warn("PBR: Sample action Ignored");
1289 if (api
->actions
[i
].u
.za
.filter
1290 & TRAFFIC_ACTION_DISTRIBUTE
) {
1291 if (BGP_DEBUG(pbr
, PBR
)) {
1292 bgp_pbr_print_policy_route(api
);
1293 zlog_warn("PBR: Distribute action Applies");
1296 /* continue forwarding entry as before
1300 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
1301 /* terminate action: run other filters
1304 case ACTION_REDIRECT_IP
:
1305 nh
.type
= NEXTHOP_TYPE_IPV4
;
1306 nh
.gate
.ipv4
.s_addr
=
1307 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
1308 nh
.vrf_id
= api
->vrf_id
;
1309 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1314 /* XXX combination with REDIRECT_VRF
1315 * + REDIRECT_NH_IP not done
1319 case ACTION_REDIRECT
:
1320 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
1321 nh
.type
= NEXTHOP_TYPE_IPV4
;
1322 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1329 case ACTION_MARKING
:
1330 if (BGP_DEBUG(pbr
, PBR
)) {
1331 bgp_pbr_print_policy_route(api
);
1332 zlog_warn("PBR: Set DSCP %u Ignored",
1333 api
->actions
[i
].u
.marking_dscp
);
1339 if (continue_loop
== 0)
1344 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
1345 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
1348 struct bgp_pbr_entry_main api
;
1349 struct bgp_info_extra
*extra
= bgp_info_extra_get(info
);
1352 return; /* IPv6 not supported */
1353 if (safi
!= SAFI_FLOWSPEC
)
1354 return; /* not supported */
1355 /* Make Zebra API structure. */
1356 memset(&api
, 0, sizeof(api
));
1357 api
.vrf_id
= bgp
->vrf_id
;
1360 if (!bgp_zebra_tm_chunk_obtained()) {
1361 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1362 zlog_err("%s: table chunk not obtained yet",
1366 /* already installed */
1367 if (nlri_update
&& extra
->bgp_fs_pbr
) {
1368 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1369 zlog_err("%s: entry %p already installed in bgp pbr",
1374 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
1375 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1376 zlog_err("%s: cancel updating entry %p in bgp pbr",
1380 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
1383 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
1384 const struct bgp_pbr_interface
*b
)
1386 return strcmp(a
->name
, b
->name
);
1389 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
1390 struct bgp_pbr_interface_head
*head
)
1392 struct bgp_pbr_interface pbr_if
;
1394 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
1395 return (RB_FIND(bgp_pbr_interface_head
,
1399 /* this function resets to the default policy routing
1400 * go back to default status
1402 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
1404 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
1405 struct bgp_pbr_interface_head
*head
;
1406 struct bgp_pbr_interface
*pbr_if
;
1408 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
1410 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
1412 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
1413 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
1414 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
1415 XFREE(MTYPE_TMP
, pbr_if
);