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 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list
[],
188 for (i
= 0; i
< num
; i
++) {
189 if (list
[i
].compare_operator
!=
190 OPERATOR_COMPARE_EQUAL_TO
)
196 /* return true if extraction ok
198 static bool bgp_pbr_extract(struct bgp_pbr_match_val list
[],
200 struct bgp_pbr_range_port
*range
)
203 bool exact_match
= false;
206 memset(range
, 0, sizeof(struct bgp_pbr_range_port
));
210 for (i
= 0; i
< num
; i
++) {
211 if (i
!= 0 && (list
[i
].compare_operator
==
212 OPERATOR_COMPARE_EQUAL_TO
))
214 if (i
== 0 && (list
[i
].compare_operator
==
215 OPERATOR_COMPARE_EQUAL_TO
)) {
217 range
->min_port
= list
[i
].value
;
220 if (exact_match
== true && i
> 0)
222 if (list
[i
].compare_operator
==
223 (OPERATOR_COMPARE_GREATER_THAN
+
224 OPERATOR_COMPARE_EQUAL_TO
)) {
226 range
->min_port
= list
[i
].value
;
227 } else if (list
[i
].compare_operator
==
228 (OPERATOR_COMPARE_LESS_THAN
+
229 OPERATOR_COMPARE_EQUAL_TO
)) {
231 range
->max_port
= list
[i
].value
;
232 } else if (list
[i
].compare_operator
==
233 OPERATOR_COMPARE_LESS_THAN
) {
235 range
->max_port
= list
[i
].value
- 1;
236 } else if (list
[i
].compare_operator
==
237 OPERATOR_COMPARE_GREATER_THAN
) {
239 range
->min_port
= list
[i
].value
+ 1;
245 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main
*api
)
247 bool enumerate_icmp
= false;
249 /* because bgp pbr entry may contain unsupported
250 * combinations, a message will be displayed here if
252 * for now, only match/set supported is
253 * - combination src/dst => redirect nexthop [ + rate]
254 * - combination src/dst => redirect VRF [ + rate]
255 * - combination src/dst => drop
256 * - combination srcport + @IP
258 if (api
->match_dscp_num
|| api
->match_tcpflags_num
) {
259 if (BGP_DEBUG(pbr
, PBR
)) {
260 bgp_pbr_print_policy_route(api
);
261 zlog_debug("BGP: some SET actions not supported by Zebra. ignoring.");
262 zlog_debug("BGP: case icmp or length or dscp or tcp flags");
267 if (api
->match_protocol_num
> 1) {
268 if (BGP_DEBUG(pbr
, PBR
))
269 zlog_debug("BGP: match protocol operations:"
270 "multiple protocols ( %d). ignoring.",
271 api
->match_protocol_num
);
274 if (api
->match_protocol_num
== 1 &&
275 api
->protocol
[0].value
!= PROTOCOL_UDP
&&
276 api
->protocol
[0].value
!= PROTOCOL_ICMP
&&
277 api
->protocol
[0].value
!= PROTOCOL_TCP
) {
278 if (BGP_DEBUG(pbr
, PBR
))
279 zlog_debug("BGP: match protocol operations:"
280 "protocol (%d) not supported. ignoring",
281 api
->match_protocol_num
);
284 if (!bgp_pbr_extract(api
->src_port
, api
->match_src_port_num
, NULL
)) {
285 if (BGP_DEBUG(pbr
, PBR
))
286 zlog_debug("BGP: match src port operations:"
287 "too complex. ignoring.");
290 if (!bgp_pbr_extract(api
->dst_port
, api
->match_dst_port_num
, NULL
)) {
291 if (BGP_DEBUG(pbr
, PBR
))
292 zlog_debug("BGP: match dst port operations:"
293 "too complex. ignoring.");
296 if (!bgp_pbr_extract(api
->icmp_type
, api
->match_icmp_type_num
, NULL
)) {
297 if (!bgp_pbr_extract_enumerate(api
->icmp_type
,
298 api
->match_icmp_type_num
)) {
299 if (BGP_DEBUG(pbr
, PBR
))
300 zlog_debug("BGP: match icmp type operations:"
301 "too complex. ignoring.");
304 enumerate_icmp
= true;
306 if (!bgp_pbr_extract(api
->icmp_code
, api
->match_icmp_code_num
, NULL
)) {
307 if (!bgp_pbr_extract_enumerate(api
->icmp_code
,
308 api
->match_icmp_code_num
)) {
309 if (BGP_DEBUG(pbr
, PBR
))
310 zlog_debug("BGP: match icmp code operations:"
311 "too complex. ignoring.");
313 } else if (api
->match_icmp_type_num
> 1 &&
314 enumerate_icmp
== false) {
315 if (BGP_DEBUG(pbr
, PBR
))
316 zlog_debug("BGP: match icmp code is enumerate"
317 ", and icmp type is not."
318 " too complex. ignoring.");
322 if (!bgp_pbr_extract(api
->port
, api
->match_port_num
, NULL
)) {
323 if (BGP_DEBUG(pbr
, PBR
))
324 zlog_debug("BGP: match port operations:"
325 "too complex. ignoring.");
328 if (!bgp_pbr_extract(api
->packet_length
, api
->match_packet_length_num
, NULL
)) {
329 if (BGP_DEBUG(pbr
, PBR
))
330 zlog_debug("BGP: match packet length operations:"
331 "too complex. ignoring.");
334 /* no combinations with both src_port and dst_port
335 * or port with src_port and dst_port
337 if (api
->match_src_port_num
+ api
->match_dst_port_num
+
338 api
->match_port_num
> 3) {
339 if (BGP_DEBUG(pbr
, PBR
))
340 zlog_debug("BGP: match multiple port operations:"
341 " too complex. ignoring.");
344 if ((api
->match_src_port_num
|| api
->match_dst_port_num
345 || api
->match_port_num
) && (api
->match_icmp_type_num
346 || api
->match_icmp_code_num
)) {
347 if (BGP_DEBUG(pbr
, PBR
))
348 zlog_debug("BGP: match multiple port/imcp operations:"
349 " too complex. ignoring.");
352 if (!(api
->match_bitmask
& PREFIX_SRC_PRESENT
) &&
353 !(api
->match_bitmask
& PREFIX_DST_PRESENT
)) {
354 if (BGP_DEBUG(pbr
, PBR
)) {
355 bgp_pbr_print_policy_route(api
);
356 zlog_debug("BGP: match actions without src"
357 " or dst address can not operate."
365 /* return -1 if build or validation failed */
366 static int bgp_pbr_build_and_validate_entry(struct prefix
*p
,
367 struct bgp_info
*info
,
368 struct bgp_pbr_entry_main
*api
)
371 int i
, action_count
= 0;
372 struct ecommunity
*ecom
;
373 struct ecommunity_val
*ecom_eval
;
374 struct bgp_pbr_entry_action
*api_action
;
375 struct prefix
*src
= NULL
, *dst
= NULL
;
376 int valid_prefix
= 0;
379 /* extract match from flowspec entries */
380 ret
= bgp_flowspec_match_rules_fill((uint8_t *)p
->u
.prefix_flowspec
.ptr
,
381 p
->u
.prefix_flowspec
.prefixlen
, api
);
384 /* extract actiosn from flowspec ecom list */
385 if (info
&& info
->attr
&& info
->attr
->ecommunity
) {
386 ecom
= info
->attr
->ecommunity
;
387 for (i
= 0; i
< ecom
->size
; i
++) {
388 ecom_eval
= (struct ecommunity_val
*)
389 (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
391 if (action_count
> ACTIONS_MAX_NUM
) {
392 if (BGP_DEBUG(pbr
, PBR_ERROR
))
393 zlog_err("%s: flowspec actions exceeds limit (max %u)",
394 __func__
, action_count
);
397 api_action
= &api
->actions
[action_count
- 1];
399 if ((ecom_eval
->val
[1] ==
400 (char)ECOMMUNITY_REDIRECT_VRF
) &&
401 (ecom_eval
->val
[0] ==
402 (char)ECOMMUNITY_ENCODE_TRANS_EXP
||
404 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
406 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
)) {
407 struct ecommunity
*eckey
= ecommunity_new();
408 struct ecommunity_val ecom_copy
;
410 memcpy(&ecom_copy
, ecom_eval
,
411 sizeof(struct ecommunity_val
));
413 ~ECOMMUNITY_ENCODE_TRANS_EXP
;
414 ecom_copy
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
415 ecommunity_add_val(eckey
, &ecom_copy
);
417 api_action
->action
= ACTION_REDIRECT
;
418 api_action
->u
.redirect_vrf
=
419 get_first_vrf_for_redirect_with_rt(
421 ecommunity_free(&eckey
);
422 } else if ((ecom_eval
->val
[0] ==
423 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) &&
424 (ecom_eval
->val
[1] ==
425 (char)ECOMMUNITY_REDIRECT_IP_NH
)) {
426 api_action
->action
= ACTION_REDIRECT_IP
;
427 api_action
->u
.zr
.redirect_ip_v4
.s_addr
=
428 info
->attr
->nexthop
.s_addr
;
429 api_action
->u
.zr
.duplicate
= ecom_eval
->val
[7];
431 if (ecom_eval
->val
[0] !=
432 (char)ECOMMUNITY_ENCODE_TRANS_EXP
)
434 ret
= ecommunity_fill_pbr_action(ecom_eval
,
443 /* validate if incoming matc/action is compatible
444 * with our policy routing engine
446 if (!bgp_pbr_validate_policy_route(api
))
449 /* check inconsistency in the match rule */
450 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
451 src
= &api
->src_prefix
;
452 afi
= family2afi(src
->family
);
455 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
456 dst
= &api
->dst_prefix
;
457 if (valid_prefix
&& afi
!= family2afi(dst
->family
)) {
458 if (BGP_DEBUG(pbr
, PBR
)) {
459 bgp_pbr_print_policy_route(api
);
460 zlog_debug("%s: inconsistency:"
461 " no match for afi src and dst (%u/%u)",
462 __func__
, afi
, family2afi(dst
->family
));
470 static void bgp_pbr_match_entry_free(void *arg
)
472 struct bgp_pbr_match_entry
*bpme
;
474 bpme
= (struct bgp_pbr_match_entry
*)arg
;
476 if (bpme
->installed
) {
477 bgp_send_pbr_ipset_entry_match(bpme
, false);
478 bpme
->installed
= false;
479 bpme
->backpointer
= NULL
;
481 XFREE(MTYPE_PBR_MATCH_ENTRY
, bpme
);
484 static void bgp_pbr_match_free(void *arg
)
486 struct bgp_pbr_match
*bpm
;
488 bpm
= (struct bgp_pbr_match
*)arg
;
490 hash_clean(bpm
->entry_hash
, bgp_pbr_match_entry_free
);
492 if (hashcount(bpm
->entry_hash
) == 0) {
493 /* delete iptable entry first */
494 /* then delete ipset match */
495 if (bpm
->installed
) {
496 if (bpm
->installed_in_iptable
) {
497 bgp_send_pbr_iptable(bpm
->action
,
499 bpm
->installed_in_iptable
= false;
500 bpm
->action
->refcnt
--;
502 bgp_send_pbr_ipset_match(bpm
, false);
503 bpm
->installed
= false;
507 hash_free(bpm
->entry_hash
);
509 XFREE(MTYPE_PBR_MATCH
, bpm
);
512 static void *bgp_pbr_match_alloc_intern(void *arg
)
514 struct bgp_pbr_match
*bpm
, *new;
516 bpm
= (struct bgp_pbr_match
*)arg
;
518 new = XCALLOC(MTYPE_PBR_MATCH
, sizeof(*new));
519 memcpy(new, bpm
, sizeof(*bpm
));
524 static void bgp_pbr_action_free(void *arg
)
526 struct bgp_pbr_action
*bpa
;
528 bpa
= (struct bgp_pbr_action
*)arg
;
530 if (bpa
->refcnt
== 0) {
531 if (bpa
->installed
&& bpa
->table_id
!= 0) {
532 bgp_send_pbr_rule_action(bpa
, false);
533 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
537 bpa
->installed
= false;
540 XFREE(MTYPE_PBR_ACTION
, bpa
);
543 static void *bgp_pbr_action_alloc_intern(void *arg
)
545 struct bgp_pbr_action
*bpa
, *new;
547 bpa
= (struct bgp_pbr_action
*)arg
;
549 new = XCALLOC(MTYPE_PBR_ACTION
, sizeof(*new));
551 memcpy(new, bpa
, sizeof(*bpa
));
556 static void *bgp_pbr_match_entry_alloc_intern(void *arg
)
558 struct bgp_pbr_match_entry
*bpme
, *new;
560 bpme
= (struct bgp_pbr_match_entry
*)arg
;
562 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY
, sizeof(*new));
564 memcpy(new, bpme
, sizeof(*bpme
));
569 uint32_t bgp_pbr_match_hash_key(void *arg
)
571 struct bgp_pbr_match
*pbm
= (struct bgp_pbr_match
*)arg
;
574 key
= jhash_1word(pbm
->vrf_id
, 0x4312abde);
575 key
= jhash_1word(pbm
->flags
, key
);
576 key
= jhash_1word(pbm
->pkt_len_min
, key
);
577 key
= jhash_1word(pbm
->pkt_len_max
, key
);
578 return jhash_1word(pbm
->type
, key
);
581 int bgp_pbr_match_hash_equal(const void *arg1
, const void *arg2
)
583 const struct bgp_pbr_match
*r1
, *r2
;
585 r1
= (const struct bgp_pbr_match
*)arg1
;
586 r2
= (const struct bgp_pbr_match
*)arg2
;
588 if (r1
->vrf_id
!= r2
->vrf_id
)
591 if (r1
->type
!= r2
->type
)
594 if (r1
->flags
!= r2
->flags
)
597 if (r1
->action
!= r2
->action
)
600 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
603 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
609 uint32_t bgp_pbr_match_entry_hash_key(void *arg
)
611 struct bgp_pbr_match_entry
*pbme
;
614 pbme
= (struct bgp_pbr_match_entry
*)arg
;
615 key
= prefix_hash_key(&pbme
->src
);
616 key
= jhash_1word(prefix_hash_key(&pbme
->dst
), key
);
617 key
= jhash(&pbme
->dst_port_min
, 2, key
);
618 key
= jhash(&pbme
->src_port_min
, 2, key
);
619 key
= jhash(&pbme
->dst_port_max
, 2, key
);
620 key
= jhash(&pbme
->src_port_max
, 2, key
);
621 key
= jhash(&pbme
->proto
, 1, key
);
626 int bgp_pbr_match_entry_hash_equal(const void *arg1
, const void *arg2
)
628 const struct bgp_pbr_match_entry
*r1
, *r2
;
630 r1
= (const struct bgp_pbr_match_entry
*)arg1
;
631 r2
= (const struct bgp_pbr_match_entry
*)arg2
;
633 /* on updates, comparing
634 * backpointer is not necessary
637 /* unique value is self calculated
640 /* rate is ignored for now
643 if (!prefix_same(&r1
->src
, &r2
->src
))
646 if (!prefix_same(&r1
->dst
, &r2
->dst
))
649 if (r1
->src_port_min
!= r2
->src_port_min
)
652 if (r1
->dst_port_min
!= r2
->dst_port_min
)
655 if (r1
->src_port_max
!= r2
->src_port_max
)
658 if (r1
->dst_port_max
!= r2
->dst_port_max
)
661 if (r1
->proto
!= r2
->proto
)
667 uint32_t bgp_pbr_action_hash_key(void *arg
)
669 struct bgp_pbr_action
*pbra
;
672 pbra
= (struct bgp_pbr_action
*)arg
;
673 key
= jhash_1word(pbra
->table_id
, 0x4312abde);
674 key
= jhash_1word(pbra
->fwmark
, key
);
678 int bgp_pbr_action_hash_equal(const void *arg1
, const void *arg2
)
680 const struct bgp_pbr_action
*r1
, *r2
;
682 r1
= (const struct bgp_pbr_action
*)arg1
;
683 r2
= (const struct bgp_pbr_action
*)arg2
;
685 /* unique value is self calculated
686 * table and fwmark is self calculated
689 if (r1
->vrf_id
!= r2
->vrf_id
)
692 if (memcmp(&r1
->nh
, &r2
->nh
, sizeof(struct nexthop
)))
697 struct bgp_pbr_action
*bgp_pbr_action_rule_lookup(vrf_id_t vrf_id
,
700 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
701 struct bgp_pbr_action_unique bpau
;
703 if (!bgp
|| unique
== 0)
705 bpau
.unique
= unique
;
706 bpau
.bpa_found
= NULL
;
707 hash_walk(bgp
->pbr_action_hash
, bgp_pbr_action_walkcb
, &bpau
);
708 return bpau
.bpa_found
;
711 struct bgp_pbr_match
*bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id
,
714 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
715 struct bgp_pbr_match_unique bpmu
;
717 if (!bgp
|| unique
== 0)
719 bpmu
.unique
= unique
;
720 bpmu
.bpm_found
= NULL
;
721 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_walkcb
, &bpmu
);
722 return bpmu
.bpm_found
;
725 struct bgp_pbr_match_entry
*bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id
,
729 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
730 struct bgp_pbr_match_entry_unique bpmeu
;
731 struct bgp_pbr_match_ipsetname bpmi
;
733 if (!bgp
|| unique
== 0)
735 bpmi
.ipsetname
= XCALLOC(MTYPE_TMP
, ZEBRA_IPSET_NAME_SIZE
);
736 snprintf(bpmi
.ipsetname
, ZEBRA_IPSET_NAME_SIZE
, "%s", ipset_name
);
737 bpmi
.bpm_found
= NULL
;
738 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_pername_walkcb
, &bpmi
);
739 XFREE(MTYPE_TMP
, bpmi
.ipsetname
);
742 bpmeu
.bpme_found
= NULL
;
743 bpmeu
.unique
= unique
;
744 hash_walk(bpmi
.bpm_found
->entry_hash
,
745 bgp_pbr_match_entry_walkcb
, &bpmeu
);
746 return bpmeu
.bpme_found
;
749 struct bgp_pbr_match
*bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id
,
752 struct bgp
*bgp
= bgp_lookup_by_vrf_id(vrf_id
);
753 struct bgp_pbr_match_iptable_unique bpmiu
;
755 if (!bgp
|| unique
== 0)
757 bpmiu
.unique
= unique
;
758 bpmiu
.bpm_found
= NULL
;
759 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_match_iptable_walkcb
, &bpmiu
);
760 return bpmiu
.bpm_found
;
763 void bgp_pbr_cleanup(struct bgp
*bgp
)
765 if (bgp
->pbr_match_hash
) {
766 hash_clean(bgp
->pbr_match_hash
, bgp_pbr_match_free
);
767 hash_free(bgp
->pbr_match_hash
);
768 bgp
->pbr_match_hash
= NULL
;
770 if (bgp
->pbr_action_hash
) {
771 hash_clean(bgp
->pbr_action_hash
, bgp_pbr_action_free
);
772 hash_free(bgp
->pbr_action_hash
);
773 bgp
->pbr_action_hash
= NULL
;
775 if (bgp
->bgp_pbr_cfg
== NULL
)
777 bgp_pbr_reset(bgp
, AFI_IP
);
778 XFREE(MTYPE_PBR
, bgp
->bgp_pbr_cfg
);
779 bgp
->bgp_pbr_cfg
= NULL
;
782 void bgp_pbr_init(struct bgp
*bgp
)
784 bgp
->pbr_match_hash
=
785 hash_create_size(8, bgp_pbr_match_hash_key
,
786 bgp_pbr_match_hash_equal
,
788 bgp
->pbr_action_hash
=
789 hash_create_size(8, bgp_pbr_action_hash_key
,
790 bgp_pbr_action_hash_equal
,
793 bgp
->bgp_pbr_cfg
= XCALLOC(MTYPE_PBR
, sizeof(struct bgp_pbr_config
));
794 bgp
->bgp_pbr_cfg
->pbr_interface_any_ipv4
= true;
797 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main
*api
)
800 char return_string
[512];
801 char *ptr
= return_string
;
805 ptr
+= sprintf(ptr
, "MATCH : ");
806 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
) {
807 struct prefix
*p
= &(api
->src_prefix
);
809 ptr
+= sprintf(ptr
, "@src %s", prefix2str(p
, buff
, 64));
810 INCREMENT_DISPLAY(ptr
, nb_items
);
812 if (api
->match_bitmask
& PREFIX_DST_PRESENT
) {
813 struct prefix
*p
= &(api
->dst_prefix
);
815 INCREMENT_DISPLAY(ptr
, nb_items
);
816 ptr
+= sprintf(ptr
, "@dst %s", prefix2str(p
, buff
, 64));
819 if (api
->match_protocol_num
)
820 INCREMENT_DISPLAY(ptr
, nb_items
);
821 for (i
= 0; i
< api
->match_protocol_num
; i
++)
822 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->protocol
[i
],
823 i
> 0 ? NULL
: "@proto ");
825 if (api
->match_src_port_num
)
826 INCREMENT_DISPLAY(ptr
, nb_items
);
827 for (i
= 0; i
< api
->match_src_port_num
; i
++)
828 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->src_port
[i
],
829 i
> 0 ? NULL
: "@srcport ");
831 if (api
->match_dst_port_num
)
832 INCREMENT_DISPLAY(ptr
, nb_items
);
833 for (i
= 0; i
< api
->match_dst_port_num
; i
++)
834 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dst_port
[i
],
835 i
> 0 ? NULL
: "@dstport ");
837 if (api
->match_port_num
)
838 INCREMENT_DISPLAY(ptr
, nb_items
);
839 for (i
= 0; i
< api
->match_port_num
; i
++)
840 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->port
[i
],
841 i
> 0 ? NULL
: "@port ");
843 if (api
->match_icmp_type_num
)
844 INCREMENT_DISPLAY(ptr
, nb_items
);
845 for (i
= 0; i
< api
->match_icmp_type_num
; i
++)
846 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_type
[i
],
847 i
> 0 ? NULL
: "@icmptype ");
849 if (api
->match_icmp_code_num
)
850 INCREMENT_DISPLAY(ptr
, nb_items
);
851 for (i
= 0; i
< api
->match_icmp_code_num
; i
++)
852 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->icmp_code
[i
],
853 i
> 0 ? NULL
: "@icmpcode ");
855 if (api
->match_packet_length_num
)
856 INCREMENT_DISPLAY(ptr
, nb_items
);
857 for (i
= 0; i
< api
->match_packet_length_num
; i
++)
858 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->packet_length
[i
],
859 i
> 0 ? NULL
: "@plen ");
861 if (api
->match_dscp_num
)
862 INCREMENT_DISPLAY(ptr
, nb_items
);
863 for (i
= 0; i
< api
->match_dscp_num
; i
++)
864 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->dscp
[i
],
865 i
> 0 ? NULL
: "@dscp ");
867 if (api
->match_tcpflags_num
)
868 INCREMENT_DISPLAY(ptr
, nb_items
);
869 for (i
= 0; i
< api
->match_tcpflags_num
; i
++)
870 ptr
+= sprintf_bgp_pbr_match_val(ptr
, &api
->tcpflags
[i
],
871 i
> 0 ? NULL
: "@tcpflags ");
873 if (api
->match_bitmask
& FRAGMENT_PRESENT
) {
874 INCREMENT_DISPLAY(ptr
, nb_items
);
875 ptr
+= sprintf(ptr
, "@fragment %u", api
->fragment
.bitmask
);
880 ptr
+= sprintf(ptr
, "; ");
882 ptr
+= sprintf(ptr
, "SET : ");
884 for (i
= 0; i
< api
->action_num
; i
++) {
885 switch (api
->actions
[i
].action
) {
886 case ACTION_TRAFFICRATE
:
887 INCREMENT_DISPLAY(ptr
, nb_items
);
888 ptr
+= sprintf(ptr
, "@set rate %f",
889 api
->actions
[i
].u
.r
.rate
);
891 case ACTION_TRAFFIC_ACTION
:
892 INCREMENT_DISPLAY(ptr
, nb_items
);
893 ptr
+= sprintf(ptr
, "@action ");
894 if (api
->actions
[i
].u
.za
.filter
895 & TRAFFIC_ACTION_TERMINATE
)
897 " terminate (apply filter(s))");
898 if (api
->actions
[i
].u
.za
.filter
899 & TRAFFIC_ACTION_DISTRIBUTE
)
900 ptr
+= sprintf(ptr
, " distribute");
901 if (api
->actions
[i
].u
.za
.filter
902 & TRAFFIC_ACTION_SAMPLE
)
903 ptr
+= sprintf(ptr
, " sample");
905 case ACTION_REDIRECT_IP
:
906 INCREMENT_DISPLAY(ptr
, nb_items
);
907 char local_buff
[INET_ADDRSTRLEN
];
909 if (inet_ntop(AF_INET
,
910 &api
->actions
[i
].u
.zr
.redirect_ip_v4
,
911 local_buff
, INET_ADDRSTRLEN
) != NULL
)
913 "@redirect ip nh %s", local_buff
);
915 case ACTION_REDIRECT
:
916 INCREMENT_DISPLAY(ptr
, nb_items
);
917 ptr
+= sprintf(ptr
, "@redirect vrf %u",
918 api
->actions
[i
].u
.redirect_vrf
);
921 INCREMENT_DISPLAY(ptr
, nb_items
);
922 ptr
+= sprintf(ptr
, "@set dscp %u",
923 api
->actions
[i
].u
.marking_dscp
);
929 zlog_info("%s", return_string
);
932 static void bgp_pbr_flush_entry(struct bgp
*bgp
, struct bgp_pbr_action
*bpa
,
933 struct bgp_pbr_match
*bpm
,
934 struct bgp_pbr_match_entry
*bpme
)
936 /* if bpme is null, bpm is also null
940 /* ipset del entry */
941 if (bpme
->installed
) {
942 bgp_send_pbr_ipset_entry_match(bpme
, false);
943 bpme
->installed
= false;
944 bpme
->backpointer
= NULL
;
945 if (bpme
->bgp_info
) {
946 struct bgp_info
*bgp_info
;
947 struct bgp_info_extra
*extra
;
949 /* unlink bgp_info to bpme */
950 bgp_info
= (struct bgp_info
*)bpme
->bgp_info
;
951 extra
= bgp_info_extra_get(bgp_info
);
952 extra
->bgp_fs_pbr
= NULL
;
953 bpme
->bgp_info
= NULL
;
956 hash_release(bpm
->entry_hash
, bpme
);
957 if (hashcount(bpm
->entry_hash
) == 0) {
958 /* delete iptable entry first */
959 /* then delete ipset match */
960 if (bpm
->installed
) {
961 if (bpm
->installed_in_iptable
) {
962 bgp_send_pbr_iptable(bpm
->action
,
964 bpm
->installed_in_iptable
= false;
965 bpm
->action
->refcnt
--;
967 bgp_send_pbr_ipset_match(bpm
, false);
968 bpm
->installed
= false;
971 hash_release(bgp
->pbr_match_hash
, bpm
);
972 /* XXX release pbr_match_action if not used
973 * note that drop does not need to call send_pbr_action
976 if (bpa
->refcnt
== 0) {
977 if (bpa
->installed
&& bpa
->table_id
!= 0) {
978 bgp_send_pbr_rule_action(bpa
, false);
979 bgp_zebra_announce_default(bpa
->bgp
, &(bpa
->nh
),
983 bpa
->installed
= false;
988 struct bgp_pbr_match_entry_remain
{
989 struct bgp_pbr_match_entry
*bpme_to_match
;
990 struct bgp_pbr_match_entry
*bpme_found
;
993 static int bgp_pbr_get_remaining_entry(struct hash_backet
*backet
, void *arg
)
995 struct bgp_pbr_match
*bpm
= (struct bgp_pbr_match
*)backet
->data
;
996 struct bgp_pbr_match_entry_remain
*bpmer
=
997 (struct bgp_pbr_match_entry_remain
*)arg
;
998 struct bgp_pbr_match
*bpm_temp
;
999 struct bgp_pbr_match_entry
*bpme
= bpmer
->bpme_to_match
;
1001 if (!bpme
->backpointer
||
1002 bpm
== bpme
->backpointer
||
1003 bpme
->backpointer
->action
== bpm
->action
)
1004 return HASHWALK_CONTINUE
;
1005 /* ensure bpm other characteristics are equal */
1006 bpm_temp
= bpme
->backpointer
;
1007 if (bpm_temp
->vrf_id
!= bpm
->vrf_id
||
1008 bpm_temp
->type
!= bpm
->type
||
1009 bpm_temp
->flags
!= bpm
->flags
)
1010 return HASHWALK_CONTINUE
;
1012 /* look for remaining bpme */
1013 bpmer
->bpme_found
= hash_lookup(bpm
->entry_hash
, bpme
);
1014 if (!bpmer
->bpme_found
)
1015 return HASHWALK_CONTINUE
;
1016 return HASHWALK_ABORT
;
1019 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp
*bgp
,
1020 struct bgp_info
*binfo
,
1025 struct bgp_pbr_range_port
*pkt_len
,
1026 struct bgp_pbr_range_port
*src_port
,
1027 struct bgp_pbr_range_port
*dst_port
)
1029 struct bgp_pbr_match temp
;
1030 struct bgp_pbr_match_entry temp2
;
1031 struct bgp_pbr_match
*bpm
;
1032 struct bgp_pbr_match_entry
*bpme
;
1033 struct bgp_pbr_match_entry_remain bpmer
;
1035 /* as we don't know information from EC
1036 * look for bpm that have the bpm
1037 * with vrf_id characteristics
1039 memset(&temp2
, 0, sizeof(temp2
));
1040 memset(&temp
, 0, sizeof(temp
));
1042 temp
.flags
|= MATCH_IP_SRC_SET
;
1043 prefix_copy(&temp2
.src
, src
);
1045 temp2
.src
.family
= AF_INET
;
1047 temp
.flags
|= MATCH_IP_DST_SET
;
1048 prefix_copy(&temp2
.dst
, dst
);
1050 temp2
.dst
.family
= AF_INET
;
1051 if (src_port
&& src_port
->min_port
) {
1052 temp
.flags
|= MATCH_PORT_SRC_SET
;
1053 temp2
.src_port_min
= src_port
->min_port
;
1054 if (src_port
->max_port
) {
1055 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1056 temp2
.src_port_max
= src_port
->max_port
;
1059 if (dst_port
&& dst_port
->min_port
) {
1060 temp
.flags
|= MATCH_PORT_DST_SET
;
1061 temp2
.dst_port_min
= dst_port
->min_port
;
1062 if (dst_port
->max_port
) {
1063 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1064 temp2
.dst_port_max
= dst_port
->max_port
;
1067 temp2
.proto
= protocol
;
1070 temp
.pkt_len_min
= pkt_len
->min_port
;
1071 if (pkt_len
&& pkt_len
->max_port
)
1072 temp
.pkt_len_max
= pkt_len
->max_port
;
1074 if (src
== NULL
|| dst
== NULL
) {
1075 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1076 temp
.type
= IPSET_NET_PORT
;
1078 temp
.type
= IPSET_NET
;
1080 if (temp
.flags
& (MATCH_PORT_DST_SET
| MATCH_PORT_SRC_SET
))
1081 temp
.type
= IPSET_NET_PORT_NET
;
1083 temp
.type
= IPSET_NET_NET
;
1085 if (vrf_id
== VRF_UNKNOWN
) /* XXX case BGP destroy */
1088 temp
.vrf_id
= vrf_id
;
1091 bpme
->backpointer
= bpm
;
1092 /* right now, a previous entry may already exist
1093 * flush previous entry if necessary
1095 bpmer
.bpme_to_match
= bpme
;
1096 bpmer
.bpme_found
= NULL
;
1097 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1098 if (bpmer
.bpme_found
) {
1099 static struct bgp_pbr_match
*local_bpm
;
1100 static struct bgp_pbr_action
*local_bpa
;
1102 local_bpm
= bpmer
.bpme_found
->backpointer
;
1103 local_bpa
= local_bpm
->action
;
1104 bgp_pbr_flush_entry(bgp
, local_bpa
,
1105 local_bpm
, bpmer
.bpme_found
);
1109 static void bgp_pbr_policyroute_add_to_zebra(struct bgp
*bgp
,
1110 struct bgp_info
*binfo
,
1117 struct bgp_pbr_range_port
*pkt_len
,
1118 struct bgp_pbr_range_port
*src_port
,
1119 struct bgp_pbr_range_port
*dst_port
)
1121 struct bgp_pbr_match temp
;
1122 struct bgp_pbr_match_entry temp2
;
1123 struct bgp_pbr_match
*bpm
;
1124 struct bgp_pbr_match_entry
*bpme
= NULL
;
1125 struct bgp_pbr_action temp3
;
1126 struct bgp_pbr_action
*bpa
= NULL
;
1127 struct bgp_pbr_match_entry_remain bpmer
;
1129 /* look for bpa first */
1130 memset(&temp3
, 0, sizeof(temp3
));
1134 memcpy(&temp3
.nh
, nh
, sizeof(struct nexthop
));
1135 temp3
.vrf_id
= vrf_id
;
1136 bpa
= hash_get(bgp
->pbr_action_hash
, &temp3
,
1137 bgp_pbr_action_alloc_intern
);
1139 if (bpa
->fwmark
== 0) {
1140 /* drop is handled by iptable */
1141 if (nh
&& nh
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
1143 bpa
->installed
= true;
1145 bpa
->fwmark
= bgp_zebra_tm_get_id();
1146 bpa
->table_id
= bpa
->fwmark
;
1147 bpa
->installed
= false;
1150 bpa
->unique
= ++bgp_pbr_action_counter_unique
;
1151 /* 0 value is forbidden */
1152 bpa
->install_in_progress
= false;
1155 /* then look for bpm */
1156 memset(&temp
, 0, sizeof(temp
));
1157 if (src
== NULL
|| dst
== NULL
) {
1158 if ((src_port
&& src_port
->min_port
) ||
1159 (dst_port
&& dst_port
->min_port
))
1160 temp
.type
= IPSET_NET_PORT
;
1162 temp
.type
= IPSET_NET
;
1164 if ((src_port
&& src_port
->min_port
) ||
1165 (dst_port
&& dst_port
->min_port
))
1166 temp
.type
= IPSET_NET_PORT_NET
;
1168 temp
.type
= IPSET_NET_NET
;
1170 temp
.vrf_id
= vrf_id
;
1172 temp
.flags
|= MATCH_IP_SRC_SET
;
1174 temp
.flags
|= MATCH_IP_DST_SET
;
1176 if (src_port
&& src_port
->min_port
)
1177 temp
.flags
|= MATCH_PORT_SRC_SET
;
1178 if (dst_port
&& dst_port
->min_port
)
1179 temp
.flags
|= MATCH_PORT_DST_SET
;
1180 if (src_port
&& src_port
->max_port
)
1181 temp
.flags
|= MATCH_PORT_SRC_RANGE_SET
;
1182 if (dst_port
&& dst_port
->max_port
)
1183 temp
.flags
|= MATCH_PORT_DST_RANGE_SET
;
1185 temp
.pkt_len_min
= pkt_len
->min_port
;
1186 if (pkt_len
&& pkt_len
->max_port
)
1187 temp
.pkt_len_max
= pkt_len
->max_port
;
1190 bpm
= hash_get(bgp
->pbr_match_hash
, &temp
,
1191 bgp_pbr_match_alloc_intern
);
1193 /* new, then self allocate ipset_name and unique */
1194 if (bpm
&& bpm
->unique
== 0) {
1195 bpm
->unique
= ++bgp_pbr_match_counter_unique
;
1196 /* 0 value is forbidden */
1197 sprintf(bpm
->ipset_name
, "match%p", bpm
);
1198 bpm
->entry_hash
= hash_create_size(8,
1199 bgp_pbr_match_entry_hash_key
,
1200 bgp_pbr_match_entry_hash_equal
,
1201 "Match Entry Hash");
1202 bpm
->installed
= false;
1204 /* unique2 should be updated too */
1205 bpm
->unique2
= ++bgp_pbr_match_iptable_counter_unique
;
1206 bpm
->installed_in_iptable
= false;
1207 bpm
->install_in_progress
= false;
1208 bpm
->install_iptable_in_progress
= false;
1211 memset(&temp2
, 0, sizeof(temp2
));
1213 prefix_copy(&temp2
.src
, src
);
1215 temp2
.src
.family
= AF_INET
;
1217 prefix_copy(&temp2
.dst
, dst
);
1219 temp2
.dst
.family
= AF_INET
;
1220 temp2
.src_port_min
= src_port
? src_port
->min_port
: 0;
1221 temp2
.dst_port_min
= dst_port
? dst_port
->min_port
: 0;
1222 temp2
.src_port_max
= src_port
? src_port
->max_port
: 0;
1223 temp2
.dst_port_max
= dst_port
? dst_port
->max_port
: 0;
1224 temp2
.proto
= protocol
;
1226 bpme
= hash_get(bpm
->entry_hash
, &temp2
,
1227 bgp_pbr_match_entry_alloc_intern
);
1228 if (bpme
&& bpme
->unique
== 0) {
1229 bpme
->unique
= ++bgp_pbr_match_entry_counter_unique
;
1230 /* 0 value is forbidden */
1231 bpme
->backpointer
= bpm
;
1232 bpme
->installed
= false;
1233 bpme
->install_in_progress
= false;
1234 /* link bgp info to bpme */
1235 bpme
->bgp_info
= (void *)binfo
;
1238 /* BGP FS: append entry to zebra
1239 * - policies are not routing entries and as such
1240 * route replace semantics don't necessarily follow
1241 * through to policy entries
1242 * - because of that, not all policing information will be stored
1243 * into zebra. and non selected policies will be suppressed from zebra
1244 * - as consequence, in order to bring consistency
1245 * a policy will be added, then ifan ecmp policy exists,
1246 * it will be suppressed subsequently
1249 if (!bpa
->installed
) {
1250 bgp_send_pbr_rule_action(bpa
, true);
1251 bgp_zebra_announce_default(bgp
, nh
,
1252 AFI_IP
, bpa
->table_id
, true);
1256 if (bpm
&& !bpm
->installed
)
1257 bgp_send_pbr_ipset_match(bpm
, true);
1259 if (bpme
&& !bpme
->installed
)
1260 bgp_send_pbr_ipset_entry_match(bpme
, true);
1263 if (bpm
&& !bpm
->installed_in_iptable
)
1264 bgp_send_pbr_iptable(bpa
, bpm
, true);
1266 /* A previous entry may already exist
1267 * flush previous entry if necessary
1269 bpmer
.bpme_to_match
= bpme
;
1270 bpmer
.bpme_found
= NULL
;
1271 hash_walk(bgp
->pbr_match_hash
, bgp_pbr_get_remaining_entry
, &bpmer
);
1272 if (bpmer
.bpme_found
) {
1273 static struct bgp_pbr_match
*local_bpm
;
1274 static struct bgp_pbr_action
*local_bpa
;
1276 local_bpm
= bpmer
.bpme_found
->backpointer
;
1277 local_bpa
= local_bpm
->action
;
1278 bgp_pbr_flush_entry(bgp
, local_bpa
,
1279 local_bpm
, bpmer
.bpme_found
);
1285 static const struct message icmp_code_unreach_str
[] = {
1286 { 9, "communication-prohibited-by-filtering"},
1287 { 10, "destination-host-prohibited"},
1288 { 7, "destination-host-unknown"},
1289 { 6, "destination-network-unknown"},
1290 { 4, "fragmentation-needed"},
1291 { 14, "host-precedence-violation"},
1292 { 0, "network-unreachable"},
1293 { 12, "network-unreachable-for-tos"},
1294 { 3, "port-unreachable"},
1295 { 8, "source-host-isolated"},
1296 { 5, "source-route-failed"},
1300 static const struct message icmp_code_redirect_str
[] = {
1301 { 1, "redirect-for-host"},
1302 { 0, "redirect-for-network"},
1303 { 3, "redirect-for-tos-and-host"},
1304 { 2, "redirect-for-tos-and-net"},
1308 static const struct message icmp_code_exceed_str
[] = {
1309 { 1, "ttl-eq-zero-during-reassembly"},
1310 { 0, "ttl-eq-zero-during-transit"},
1314 static const struct message icmp_code_problem_str
[] = {
1315 { 1, "required-option-missing"},
1316 { 2, "ip-header-bad"},
1319 static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src
[],
1321 struct bgp_pbr_match_val dst
[],
1323 struct prefix
*src_address
,
1324 struct prefix
*dst_address
,
1326 struct bgp_pbr_range_port
*pkt_len
,
1328 struct bgp_info
*binfo
,
1335 struct bgp_pbr_range_port srcp
, dstp
;
1337 if (proto
!= IPPROTO_ICMP
)
1339 /* combinatory forced. ignore icmp type / code combinatory */
1340 if (src_num
== 1 && dst_num
== 1) {
1343 srcp
.min_port
= src
[0].value
;
1344 dstp
.min_port
= dst
[0].value
;
1346 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1347 vrf_id
, src_address
,
1350 pkt_len
, &srcp
, &dstp
);
1352 bgp_pbr_policyroute_remove_from_zebra(
1362 /* parse icmp type and lookup appropriate icmp code
1363 * if no icmp code found, create as many entryes as
1364 * there are listed icmp codes for that icmp type
1366 for (i
= 0; i
< src_num
; i
++) {
1367 const struct message
*pnt
;
1368 const struct message
*pnt_code
= NULL
;
1369 static struct message nt
= {0};
1370 bool icmp_typecode_configured
= false;
1372 srcp
.min_port
= src
[i
].value
;
1375 if (src
[i
].value
== 3)
1376 pnt_code
= icmp_code_unreach_str
;
1377 else if (src
[i
].value
== 5)
1378 pnt_code
= icmp_code_redirect_str
;
1379 else if (src
[i
].value
== 11)
1380 pnt_code
= icmp_code_exceed_str
;
1381 else if (src
[i
].value
== 12)
1382 pnt_code
= icmp_code_problem_str
;
1383 switch (src
[i
].value
) {
1388 for (j
= 0; j
< dst_num
; j
++) {
1389 for (pnt
= pnt_code
;
1390 pnt
&& memcmp(pnt
, &nt
, sizeof(struct message
));
1392 if (dst
[i
].value
!= pnt
->key
)
1394 dstp
.min_port
= dst
[i
].value
;
1395 icmp_typecode_configured
= true;
1397 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1398 vrf_id
, src_address
,
1401 pkt_len
, &srcp
, &dstp
);
1403 bgp_pbr_policyroute_remove_from_zebra(
1414 /* create a list of ICMP type/code combinatories */
1415 if (!icmp_typecode_configured
) {
1416 for (pnt
= pnt_code
;
1417 pnt
&& memcmp(pnt
, &nt
, sizeof(struct message
));
1419 dstp
.min_port
= pnt
->key
;
1421 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1422 vrf_id
, src_address
,
1428 bgp_pbr_policyroute_remove_from_zebra(
1441 /* icmp type is not one of the above
1442 * forge an entry only based on the icmp type
1446 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1447 vrf_id
, src_address
,
1450 pkt_len
, &srcp
, &dstp
);
1452 bgp_pbr_policyroute_remove_from_zebra(
1465 static void bgp_pbr_handle_entry(struct bgp
*bgp
,
1466 struct bgp_info
*binfo
,
1467 struct bgp_pbr_entry_main
*api
,
1472 int continue_loop
= 1;
1474 struct prefix
*src
= NULL
, *dst
= NULL
;
1476 struct bgp_pbr_range_port
*srcp
= NULL
, *dstp
= NULL
;
1477 struct bgp_pbr_range_port range
, range_icmp_code
;
1478 struct bgp_pbr_range_port pkt_len
;
1479 bool enum_icmp
= false;
1481 memset(&nh
, 0, sizeof(struct nexthop
));
1482 if (api
->match_bitmask
& PREFIX_SRC_PRESENT
)
1483 src
= &api
->src_prefix
;
1484 if (api
->match_bitmask
& PREFIX_DST_PRESENT
)
1485 dst
= &api
->dst_prefix
;
1486 memset(&nh
, 0, sizeof(struct nexthop
));
1487 nh
.vrf_id
= VRF_UNKNOWN
;
1488 if (api
->match_protocol_num
)
1489 proto
= (uint8_t)api
->protocol
[0].value
;
1490 /* if match_port is selected, then either src or dst port will be parsed
1491 * but not both at the same time
1493 if (api
->match_port_num
>= 1) {
1494 bgp_pbr_extract(api
->port
,
1495 api
->match_port_num
,
1497 srcp
= dstp
= &range
;
1498 } else if (api
->match_src_port_num
>= 1) {
1499 bgp_pbr_extract(api
->src_port
,
1500 api
->match_src_port_num
,
1504 } else if (api
->match_dst_port_num
>= 1) {
1505 bgp_pbr_extract(api
->dst_port
,
1506 api
->match_dst_port_num
,
1511 if (api
->match_icmp_type_num
>= 1) {
1512 proto
= IPPROTO_ICMP
;
1513 if (bgp_pbr_extract_enumerate(api
->icmp_type
,
1514 api
->match_icmp_type_num
))
1517 bgp_pbr_extract(api
->icmp_type
,
1518 api
->match_icmp_type_num
,
1523 if (api
->match_icmp_code_num
>= 1) {
1524 proto
= IPPROTO_ICMP
;
1525 if (bgp_pbr_extract_enumerate(api
->icmp_code
,
1526 api
->match_icmp_code_num
))
1529 bgp_pbr_extract(api
->icmp_code
,
1530 api
->match_icmp_code_num
,
1532 dstp
= &range_icmp_code
;
1535 if (api
->match_packet_length_num
>= 1)
1536 bgp_pbr_extract(api
->packet_length
,
1537 api
->match_packet_length_num
,
1541 return bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
1542 api
->match_icmp_type_num
,
1544 api
->match_icmp_code_num
,
1545 src
, dst
, proto
, &pkt_len
,
1547 api
->vrf_id
, NULL
, NULL
);
1549 return bgp_pbr_policyroute_remove_from_zebra(bgp
,
1556 /* no action for add = true */
1557 for (i
= 0; i
< api
->action_num
; i
++) {
1558 switch (api
->actions
[i
].action
) {
1559 case ACTION_TRAFFICRATE
:
1561 if (api
->actions
[i
].u
.r
.rate
== 0) {
1562 nh
.vrf_id
= api
->vrf_id
;
1563 nh
.type
= NEXTHOP_TYPE_BLACKHOLE
;
1565 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
1566 api
->match_icmp_type_num
,
1568 api
->match_icmp_code_num
,
1569 src
, dst
, proto
, &pkt_len
,
1571 api
->vrf_id
, &nh
, &rate
);
1573 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1574 api
->vrf_id
, src
, dst
,
1576 &pkt_len
, srcp
, dstp
);
1578 /* update rate. can be reentrant */
1579 rate
= api
->actions
[i
].u
.r
.rate
;
1580 if (BGP_DEBUG(pbr
, PBR
)) {
1581 bgp_pbr_print_policy_route(api
);
1582 zlog_warn("PBR: ignoring Set action rate %f",
1583 api
->actions
[i
].u
.r
.rate
);
1587 case ACTION_TRAFFIC_ACTION
:
1588 if (api
->actions
[i
].u
.za
.filter
1589 & TRAFFIC_ACTION_SAMPLE
) {
1590 if (BGP_DEBUG(pbr
, PBR
)) {
1591 bgp_pbr_print_policy_route(api
);
1592 zlog_warn("PBR: Sample action Ignored");
1596 if (api
->actions
[i
].u
.za
.filter
1597 & TRAFFIC_ACTION_DISTRIBUTE
) {
1598 if (BGP_DEBUG(pbr
, PBR
)) {
1599 bgp_pbr_print_policy_route(api
);
1600 zlog_warn("PBR: Distribute action Applies");
1603 /* continue forwarding entry as before
1607 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
1608 /* terminate action: run other filters
1611 case ACTION_REDIRECT_IP
:
1612 nh
.type
= NEXTHOP_TYPE_IPV4
;
1613 nh
.gate
.ipv4
.s_addr
=
1614 api
->actions
[i
].u
.zr
.redirect_ip_v4
.s_addr
;
1615 nh
.vrf_id
= api
->vrf_id
;
1617 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
1618 api
->match_icmp_type_num
,
1620 api
->match_icmp_code_num
,
1621 src
, dst
, proto
, &pkt_len
,
1623 api
->vrf_id
, &nh
, &rate
);
1625 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1629 &pkt_len
, srcp
, dstp
);
1630 /* XXX combination with REDIRECT_VRF
1631 * + REDIRECT_NH_IP not done
1635 case ACTION_REDIRECT
:
1636 nh
.vrf_id
= api
->actions
[i
].u
.redirect_vrf
;
1637 nh
.type
= NEXTHOP_TYPE_IPV4
;
1639 bgp_pbr_enumerate_action_src_dst(api
->icmp_type
,
1640 api
->match_icmp_type_num
,
1642 api
->match_icmp_code_num
,
1643 src
, dst
, proto
, &pkt_len
,
1645 api
->vrf_id
, &nh
, &rate
);
1647 bgp_pbr_policyroute_add_to_zebra(bgp
, binfo
,
1651 &pkt_len
, srcp
, dstp
);
1654 case ACTION_MARKING
:
1655 if (BGP_DEBUG(pbr
, PBR
)) {
1656 bgp_pbr_print_policy_route(api
);
1657 zlog_warn("PBR: Set DSCP %u Ignored",
1658 api
->actions
[i
].u
.marking_dscp
);
1664 if (continue_loop
== 0)
1669 void bgp_pbr_update_entry(struct bgp
*bgp
, struct prefix
*p
,
1670 struct bgp_info
*info
, afi_t afi
, safi_t safi
,
1673 struct bgp_pbr_entry_main api
;
1674 struct bgp_info_extra
*extra
= bgp_info_extra_get(info
);
1677 return; /* IPv6 not supported */
1678 if (safi
!= SAFI_FLOWSPEC
)
1679 return; /* not supported */
1680 /* Make Zebra API structure. */
1681 memset(&api
, 0, sizeof(api
));
1682 api
.vrf_id
= bgp
->vrf_id
;
1685 if (!bgp_zebra_tm_chunk_obtained()) {
1686 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1687 zlog_err("%s: table chunk not obtained yet",
1691 /* already installed */
1692 if (nlri_update
&& extra
->bgp_fs_pbr
) {
1693 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1694 zlog_err("%s: entry %p already installed in bgp pbr",
1699 if (bgp_pbr_build_and_validate_entry(p
, info
, &api
) < 0) {
1700 if (BGP_DEBUG(pbr
, PBR_ERROR
))
1701 zlog_err("%s: cancel updating entry %p in bgp pbr",
1705 bgp_pbr_handle_entry(bgp
, info
, &api
, nlri_update
);
1708 int bgp_pbr_interface_compare(const struct bgp_pbr_interface
*a
,
1709 const struct bgp_pbr_interface
*b
)
1711 return strcmp(a
->name
, b
->name
);
1714 struct bgp_pbr_interface
*bgp_pbr_interface_lookup(const char *name
,
1715 struct bgp_pbr_interface_head
*head
)
1717 struct bgp_pbr_interface pbr_if
;
1719 strlcpy(pbr_if
.name
, name
, sizeof(pbr_if
.name
));
1720 return (RB_FIND(bgp_pbr_interface_head
,
1724 /* this function resets to the default policy routing
1725 * go back to default status
1727 void bgp_pbr_reset(struct bgp
*bgp
, afi_t afi
)
1729 struct bgp_pbr_config
*bgp_pbr_cfg
= bgp
->bgp_pbr_cfg
;
1730 struct bgp_pbr_interface_head
*head
;
1731 struct bgp_pbr_interface
*pbr_if
;
1733 if (!bgp_pbr_cfg
|| afi
!= AFI_IP
)
1735 head
= &(bgp_pbr_cfg
->ifaces_by_name_ipv4
);
1737 while (!RB_EMPTY(bgp_pbr_interface_head
, head
)) {
1738 pbr_if
= RB_ROOT(bgp_pbr_interface_head
, head
);
1739 RB_REMOVE(bgp_pbr_interface_head
, head
, pbr_if
);
1740 XFREE(MTYPE_TMP
, pbr_if
);