]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_pbr.c
bgpd: initialise nexthop structure, before filling in some attributes
[mirror_frr.git] / bgpd / bgp_pbr.c
1 /*
2 * BGP pbr
3 * Copyright (C) 6WIND
4 *
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
8 * later version.
9 *
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.
14 *
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
18 */
19
20 #include "zebra.h"
21 #include "prefix.h"
22 #include "zclient.h"
23 #include "jhash.h"
24
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"
34
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")
39
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);
44
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;
49
50 struct bgp_pbr_match_iptable_unique {
51 uint32_t unique;
52 struct bgp_pbr_match *bpm_found;
53 };
54
55 struct bgp_pbr_match_entry_unique {
56 uint32_t unique;
57 struct bgp_pbr_match_entry *bpme_found;
58 };
59
60 struct bgp_pbr_action_unique {
61 uint32_t unique;
62 struct bgp_pbr_action *bpa_found;
63 };
64
65 static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg)
66 {
67 struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)backet->data;
68 struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *)
69 arg;
70 uint32_t unique = bpau->unique;
71
72 if (bpa->unique == unique) {
73 bpau->bpa_found = bpa;
74 return HASHWALK_ABORT;
75 }
76 return HASHWALK_CONTINUE;
77 }
78
79 static int bgp_pbr_match_entry_walkcb(struct hash_backet *backet, void *arg)
80 {
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;
86
87 if (bpme->unique == unique) {
88 bpmeu->bpme_found = bpme;
89 return HASHWALK_ABORT;
90 }
91 return HASHWALK_CONTINUE;
92 }
93
94 struct bgp_pbr_match_ipsetname {
95 char *ipsetname;
96 struct bgp_pbr_match *bpm_found;
97 };
98
99 static int bgp_pbr_match_pername_walkcb(struct hash_backet *backet, void *arg)
100 {
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;
105
106 if (!strncmp(ipset_name, bpm->ipset_name,
107 ZEBRA_IPSET_NAME_SIZE)) {
108 bpmi->bpm_found = bpm;
109 return HASHWALK_ABORT;
110 }
111 return HASHWALK_CONTINUE;
112 }
113
114 static int bgp_pbr_match_iptable_walkcb(struct hash_backet *backet, void *arg)
115 {
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;
120
121 if (bpm->unique2 == unique) {
122 bpmiu->bpm_found = bpm;
123 return HASHWALK_ABORT;
124 }
125 return HASHWALK_CONTINUE;
126 }
127
128 struct bgp_pbr_match_unique {
129 uint32_t unique;
130 struct bgp_pbr_match *bpm_found;
131 };
132
133 static int bgp_pbr_match_walkcb(struct hash_backet *backet, void *arg)
134 {
135 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data;
136 struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *)
137 arg;
138 uint32_t unique = bpmu->unique;
139
140 if (bpm->unique == unique) {
141 bpmu->bpm_found = bpm;
142 return HASHWALK_ABORT;
143 }
144 return HASHWALK_CONTINUE;
145 }
146
147 static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
148 const char *prepend)
149 {
150 char *ptr = str;
151
152 if (prepend)
153 ptr += sprintf(ptr, "%s", prepend);
154 else {
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 ");
159 }
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);
170 }
171
172 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
173 if (_cnt) \
174 (_ptr) += sprintf((_ptr), "; "); \
175 _cnt++; \
176 } while (0)
177
178 struct bgp_pbr_range_port {
179 uint16_t min_port;
180 uint16_t max_port;
181 };
182
183 /* return true if extraction ok
184 */
185 static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
186 int num,
187 struct bgp_pbr_range_port *range)
188 {
189 int i = 0;
190 bool exact_match = false;
191
192 if (range)
193 memset(range, 0, sizeof(struct bgp_pbr_range_port));
194
195 if (num > 2)
196 return false;
197 for (i = 0; i < num; i++) {
198 if (i != 0 && (list[i].compare_operator ==
199 OPERATOR_COMPARE_EQUAL_TO))
200 return false;
201 if (i == 0 && (list[i].compare_operator ==
202 OPERATOR_COMPARE_EQUAL_TO)) {
203 if (range)
204 range->min_port = list[i].value;
205 exact_match = true;
206 }
207 if (exact_match == true && i > 0)
208 return false;
209 if (list[i].compare_operator ==
210 (OPERATOR_COMPARE_GREATER_THAN +
211 OPERATOR_COMPARE_EQUAL_TO)) {
212 if (range)
213 range->min_port = list[i].value;
214 } else if (list[i].compare_operator ==
215 (OPERATOR_COMPARE_LESS_THAN +
216 OPERATOR_COMPARE_EQUAL_TO)) {
217 if (range)
218 range->max_port = list[i].value;
219 } else if (list[i].compare_operator ==
220 OPERATOR_COMPARE_LESS_THAN) {
221 if (range)
222 range->max_port = list[i].value - 1;
223 } else if (list[i].compare_operator ==
224 OPERATOR_COMPARE_GREATER_THAN) {
225 if (range)
226 range->min_port = list[i].value + 1;
227 }
228 }
229 return true;
230 }
231
232 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
233 {
234 /* because bgp pbr entry may contain unsupported
235 * combinations, a message will be displayed here if
236 * not supported.
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
242 */
243 if (api->match_icmp_type_num || api->match_icmp_type_num
244 || api->match_packet_length_num || api->match_dscp_num
245 || api->match_tcpflags_num) {
246 if (BGP_DEBUG(pbr, PBR)) {
247 bgp_pbr_print_policy_route(api);
248 zlog_debug("BGP: some SET actions not supported by Zebra. ignoring.");
249 zlog_debug("BGP: case icmp or length or dscp or tcp flags");
250 }
251 return 0;
252 }
253
254 if (api->match_protocol_num > 1) {
255 if (BGP_DEBUG(pbr, PBR))
256 zlog_debug("BGP: match protocol operations:"
257 "multiple protocols ( %d). ignoring.",
258 api->match_protocol_num);
259 return 0;
260 }
261 if (api->match_protocol_num == 1 &&
262 api->protocol[0].value != PROTOCOL_UDP &&
263 api->protocol[0].value != PROTOCOL_TCP) {
264 if (BGP_DEBUG(pbr, PBR))
265 zlog_debug("BGP: match protocol operations:"
266 "protocol (%d) not supported. ignoring",
267 api->match_protocol_num);
268 return 0;
269 }
270 if (!bgp_pbr_extract(api->src_port, api->match_src_port_num, NULL)) {
271 if (BGP_DEBUG(pbr, PBR))
272 zlog_debug("BGP: match src port operations:"
273 "too complex. ignoring.");
274 return 0;
275 }
276 if (!bgp_pbr_extract(api->dst_port, api->match_dst_port_num, NULL)) {
277 if (BGP_DEBUG(pbr, PBR))
278 zlog_debug("BGP: match dst port operations:"
279 "too complex. ignoring.");
280 return 0;
281 }
282 if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
283 if (BGP_DEBUG(pbr, PBR))
284 zlog_debug("BGP: match port operations:"
285 "too complex. ignoring.");
286 return 0;
287 }
288 /* no combinations with both src_port and dst_port
289 * or port with src_port and dst_port
290 */
291 if (api->match_src_port_num + api->match_dst_port_num +
292 api->match_port_num > 3) {
293 if (BGP_DEBUG(pbr, PBR))
294 zlog_debug("BGP: match multiple port operations:"
295 " too complex. ignoring.");
296 return 0;
297 }
298 if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
299 !(api->match_bitmask & PREFIX_DST_PRESENT)) {
300 if (BGP_DEBUG(pbr, PBR)) {
301 bgp_pbr_print_policy_route(api);
302 zlog_debug("BGP: match actions without src"
303 " or dst address can not operate."
304 " ignoring.");
305 }
306 return 0;
307 }
308 return 1;
309 }
310
311 /* return -1 if build or validation failed */
312 static int bgp_pbr_build_and_validate_entry(struct prefix *p,
313 struct bgp_info *info,
314 struct bgp_pbr_entry_main *api)
315 {
316 int ret;
317 int i, action_count = 0;
318 struct ecommunity *ecom;
319 struct ecommunity_val *ecom_eval;
320 struct bgp_pbr_entry_action *api_action;
321 struct prefix *src = NULL, *dst = NULL;
322 int valid_prefix = 0;
323 afi_t afi = AFI_IP;
324
325 /* extract match from flowspec entries */
326 ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr,
327 p->u.prefix_flowspec.prefixlen, api);
328 if (ret < 0)
329 return -1;
330 /* extract actiosn from flowspec ecom list */
331 if (info && info->attr && info->attr->ecommunity) {
332 ecom = info->attr->ecommunity;
333 for (i = 0; i < ecom->size; i++) {
334 ecom_eval = (struct ecommunity_val *)
335 (ecom->val + (i * ECOMMUNITY_SIZE));
336 action_count++;
337 if (action_count > ACTIONS_MAX_NUM) {
338 if (BGP_DEBUG(pbr, PBR_ERROR))
339 zlog_err("%s: flowspec actions exceeds limit (max %u)",
340 __func__, action_count);
341 break;
342 }
343 api_action = &api->actions[action_count - 1];
344
345 if ((ecom_eval->val[1] ==
346 (char)ECOMMUNITY_REDIRECT_VRF) &&
347 (ecom_eval->val[0] ==
348 (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
349 ecom_eval->val[0] ==
350 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
351 ecom_eval->val[0] ==
352 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
353 struct ecommunity *eckey = ecommunity_new();
354 struct ecommunity_val ecom_copy;
355
356 memcpy(&ecom_copy, ecom_eval,
357 sizeof(struct ecommunity_val));
358 ecom_copy.val[0] &=
359 ~ECOMMUNITY_ENCODE_TRANS_EXP;
360 ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
361 ecommunity_add_val(eckey, &ecom_copy);
362
363 api_action->action = ACTION_REDIRECT;
364 api_action->u.redirect_vrf =
365 get_first_vrf_for_redirect_with_rt(
366 eckey);
367 ecommunity_free(&eckey);
368 } else if ((ecom_eval->val[0] ==
369 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
370 (ecom_eval->val[1] ==
371 (char)ECOMMUNITY_REDIRECT_IP_NH)) {
372 api_action->action = ACTION_REDIRECT_IP;
373 api_action->u.zr.redirect_ip_v4.s_addr =
374 info->attr->nexthop.s_addr;
375 api_action->u.zr.duplicate = ecom_eval->val[7];
376 } else {
377 if (ecom_eval->val[0] !=
378 (char)ECOMMUNITY_ENCODE_TRANS_EXP)
379 continue;
380 ret = ecommunity_fill_pbr_action(ecom_eval,
381 api_action);
382 if (ret != 0)
383 continue;
384 }
385 api->action_num++;
386 }
387 }
388
389 /* validate if incoming matc/action is compatible
390 * with our policy routing engine
391 */
392 if (!bgp_pbr_validate_policy_route(api))
393 return -1;
394
395 /* check inconsistency in the match rule */
396 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
397 src = &api->src_prefix;
398 afi = family2afi(src->family);
399 valid_prefix = 1;
400 }
401 if (api->match_bitmask & PREFIX_DST_PRESENT) {
402 dst = &api->dst_prefix;
403 if (valid_prefix && afi != family2afi(dst->family)) {
404 if (BGP_DEBUG(pbr, PBR)) {
405 bgp_pbr_print_policy_route(api);
406 zlog_debug("%s: inconsistency:"
407 " no match for afi src and dst (%u/%u)",
408 __func__, afi, family2afi(dst->family));
409 }
410 return -1;
411 }
412 }
413 return 0;
414 }
415
416 static void bgp_pbr_match_entry_free(void *arg)
417 {
418 struct bgp_pbr_match_entry *bpme;
419
420 bpme = (struct bgp_pbr_match_entry *)arg;
421
422 if (bpme->installed) {
423 bgp_send_pbr_ipset_entry_match(bpme, false);
424 bpme->installed = false;
425 bpme->backpointer = NULL;
426 }
427 XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
428 }
429
430 static void bgp_pbr_match_free(void *arg)
431 {
432 struct bgp_pbr_match *bpm;
433
434 bpm = (struct bgp_pbr_match *)arg;
435
436 hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
437
438 if (hashcount(bpm->entry_hash) == 0) {
439 /* delete iptable entry first */
440 /* then delete ipset match */
441 if (bpm->installed) {
442 if (bpm->installed_in_iptable) {
443 bgp_send_pbr_iptable(bpm->action,
444 bpm, false);
445 bpm->installed_in_iptable = false;
446 bpm->action->refcnt--;
447 }
448 bgp_send_pbr_ipset_match(bpm, false);
449 bpm->installed = false;
450 bpm->action = NULL;
451 }
452 }
453 hash_free(bpm->entry_hash);
454
455 XFREE(MTYPE_PBR_MATCH, bpm);
456 }
457
458 static void *bgp_pbr_match_alloc_intern(void *arg)
459 {
460 struct bgp_pbr_match *bpm, *new;
461
462 bpm = (struct bgp_pbr_match *)arg;
463
464 new = XCALLOC(MTYPE_PBR_MATCH, sizeof(*new));
465 memcpy(new, bpm, sizeof(*bpm));
466
467 return new;
468 }
469
470 static void bgp_pbr_action_free(void *arg)
471 {
472 struct bgp_pbr_action *bpa;
473
474 bpa = (struct bgp_pbr_action *)arg;
475
476 if (bpa->refcnt == 0) {
477 if (bpa->installed && bpa->table_id != 0) {
478 bgp_send_pbr_rule_action(bpa, false);
479 bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
480 AFI_IP,
481 bpa->table_id,
482 false);
483 }
484 }
485 XFREE(MTYPE_PBR_ACTION, bpa);
486 }
487
488 static void *bgp_pbr_action_alloc_intern(void *arg)
489 {
490 struct bgp_pbr_action *bpa, *new;
491
492 bpa = (struct bgp_pbr_action *)arg;
493
494 new = XCALLOC(MTYPE_PBR_ACTION, sizeof(*new));
495
496 memcpy(new, bpa, sizeof(*bpa));
497
498 return new;
499 }
500
501 static void *bgp_pbr_match_entry_alloc_intern(void *arg)
502 {
503 struct bgp_pbr_match_entry *bpme, *new;
504
505 bpme = (struct bgp_pbr_match_entry *)arg;
506
507 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY, sizeof(*new));
508
509 memcpy(new, bpme, sizeof(*bpme));
510
511 return new;
512 }
513
514 uint32_t bgp_pbr_match_hash_key(void *arg)
515 {
516 struct bgp_pbr_match *pbm = (struct bgp_pbr_match *)arg;
517 uint32_t key;
518
519 key = jhash_1word(pbm->vrf_id, 0x4312abde);
520 key = jhash_1word(pbm->flags, key);
521 return jhash_1word(pbm->type, key);
522 }
523
524 int bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
525 {
526 const struct bgp_pbr_match *r1, *r2;
527
528 r1 = (const struct bgp_pbr_match *)arg1;
529 r2 = (const struct bgp_pbr_match *)arg2;
530
531 if (r1->vrf_id != r2->vrf_id)
532 return 0;
533
534 if (r1->type != r2->type)
535 return 0;
536
537 if (r1->flags != r2->flags)
538 return 0;
539
540 if (r1->action != r2->action)
541 return 0;
542
543 return 1;
544 }
545
546 uint32_t bgp_pbr_match_entry_hash_key(void *arg)
547 {
548 struct bgp_pbr_match_entry *pbme;
549 uint32_t key;
550
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);
559
560 return key;
561 }
562
563 int bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
564 {
565 const struct bgp_pbr_match_entry *r1, *r2;
566
567 r1 = (const struct bgp_pbr_match_entry *)arg1;
568 r2 = (const struct bgp_pbr_match_entry *)arg2;
569
570 /* on updates, comparing
571 * backpointer is not necessary
572 */
573
574 /* unique value is self calculated
575 */
576
577 /* rate is ignored for now
578 */
579
580 if (!prefix_same(&r1->src, &r2->src))
581 return 0;
582
583 if (!prefix_same(&r1->dst, &r2->dst))
584 return 0;
585
586 if (r1->src_port_min != r2->src_port_min)
587 return 0;
588
589 if (r1->dst_port_min != r2->dst_port_min)
590 return 0;
591
592 if (r1->src_port_max != r2->src_port_max)
593 return 0;
594
595 if (r1->dst_port_max != r2->dst_port_max)
596 return 0;
597
598 if (r1->proto != r2->proto)
599 return 0;
600
601 return 1;
602 }
603
604 uint32_t bgp_pbr_action_hash_key(void *arg)
605 {
606 struct bgp_pbr_action *pbra;
607 uint32_t key;
608
609 pbra = (struct bgp_pbr_action *)arg;
610 key = jhash_1word(pbra->table_id, 0x4312abde);
611 key = jhash_1word(pbra->fwmark, key);
612 return key;
613 }
614
615 int bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
616 {
617 const struct bgp_pbr_action *r1, *r2;
618
619 r1 = (const struct bgp_pbr_action *)arg1;
620 r2 = (const struct bgp_pbr_action *)arg2;
621
622 /* unique value is self calculated
623 * table and fwmark is self calculated
624 * rate is ignored
625 */
626 if (r1->vrf_id != r2->vrf_id)
627 return 0;
628
629 if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop)))
630 return 0;
631 return 1;
632 }
633
634 struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
635 uint32_t unique)
636 {
637 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
638 struct bgp_pbr_action_unique bpau;
639
640 if (!bgp || unique == 0)
641 return NULL;
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;
646 }
647
648 struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
649 uint32_t unique)
650 {
651 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
652 struct bgp_pbr_match_unique bpmu;
653
654 if (!bgp || unique == 0)
655 return NULL;
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;
660 }
661
662 struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id,
663 char *ipset_name,
664 uint32_t unique)
665 {
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;
669
670 if (!bgp || unique == 0)
671 return NULL;
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);
677 if (!bpmi.bpm_found)
678 return NULL;
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;
684 }
685
686 struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
687 uint32_t unique)
688 {
689 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
690 struct bgp_pbr_match_iptable_unique bpmiu;
691
692 if (!bgp || unique == 0)
693 return NULL;
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;
698 }
699
700 void bgp_pbr_cleanup(struct bgp *bgp)
701 {
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;
706 }
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;
711 }
712 if (bgp->bgp_pbr_cfg == NULL)
713 return;
714 bgp_pbr_reset(bgp, AFI_IP);
715 XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
716 bgp->bgp_pbr_cfg = NULL;
717 }
718
719 void bgp_pbr_init(struct bgp *bgp)
720 {
721 bgp->pbr_match_hash =
722 hash_create_size(8, bgp_pbr_match_hash_key,
723 bgp_pbr_match_hash_equal,
724 "Match Hash");
725 bgp->pbr_action_hash =
726 hash_create_size(8, bgp_pbr_action_hash_key,
727 bgp_pbr_action_hash_equal,
728 "Match Hash Entry");
729
730 bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
731 bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
732 }
733
734 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
735 {
736 int i = 0;
737 char return_string[512];
738 char *ptr = return_string;
739 char buff[64];
740 int nb_items = 0;
741
742 ptr += sprintf(ptr, "MATCH : ");
743 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
744 struct prefix *p = &(api->src_prefix);
745
746 ptr += sprintf(ptr, "@src %s", prefix2str(p, buff, 64));
747 INCREMENT_DISPLAY(ptr, nb_items);
748 }
749 if (api->match_bitmask & PREFIX_DST_PRESENT) {
750 struct prefix *p = &(api->dst_prefix);
751
752 INCREMENT_DISPLAY(ptr, nb_items);
753 ptr += sprintf(ptr, "@dst %s", prefix2str(p, buff, 64));
754 }
755
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 ");
761
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 ");
767
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 ");
773
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 ");
779
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 ");
785
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 ");
791
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 ");
797
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 ");
803
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 ");
809
810 if (api->match_bitmask & FRAGMENT_PRESENT) {
811 INCREMENT_DISPLAY(ptr, nb_items);
812 ptr += sprintf(ptr, "@fragment %u", api->fragment.bitmask);
813 }
814 if (!nb_items)
815 ptr = return_string;
816 else
817 ptr += sprintf(ptr, "; ");
818 if (api->action_num)
819 ptr += sprintf(ptr, "SET : ");
820 nb_items = 0;
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);
827 break;
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)
833 ptr += sprintf(ptr,
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");
841 break;
842 case ACTION_REDIRECT_IP:
843 INCREMENT_DISPLAY(ptr, nb_items);
844 char local_buff[INET_ADDRSTRLEN];
845
846 if (inet_ntop(AF_INET,
847 &api->actions[i].u.zr.redirect_ip_v4,
848 local_buff, INET_ADDRSTRLEN) != NULL)
849 ptr += sprintf(ptr,
850 "@redirect ip nh %s", local_buff);
851 break;
852 case ACTION_REDIRECT:
853 INCREMENT_DISPLAY(ptr, nb_items);
854 ptr += sprintf(ptr, "@redirect vrf %u",
855 api->actions[i].u.redirect_vrf);
856 break;
857 case ACTION_MARKING:
858 INCREMENT_DISPLAY(ptr, nb_items);
859 ptr += sprintf(ptr, "@set dscp %u",
860 api->actions[i].u.marking_dscp);
861 break;
862 default:
863 break;
864 }
865 }
866 zlog_info("%s", return_string);
867 }
868
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)
872 {
873 /* if bpme is null, bpm is also null
874 */
875 if (bpme == NULL)
876 return;
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;
885
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;
891 }
892 }
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,
900 bpm, false);
901 bpm->installed_in_iptable = false;
902 bpm->action->refcnt--;
903 }
904 bgp_send_pbr_ipset_match(bpm, false);
905 bpm->installed = false;
906 bpm->action = NULL;
907 }
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
911 */
912 }
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),
917 AFI_IP,
918 bpa->table_id,
919 false);
920 }
921 }
922 }
923
924 struct bgp_pbr_match_entry_remain {
925 struct bgp_pbr_match_entry *bpme_to_match;
926 struct bgp_pbr_match_entry *bpme_found;
927 };
928
929 static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
930 {
931 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data;
932 struct bgp_pbr_match_entry_remain *bpmer =
933 (struct bgp_pbr_match_entry_remain *)arg;
934 struct bgp_pbr_match *bpm_temp;
935 struct bgp_pbr_match_entry *bpme = bpmer->bpme_to_match;
936
937 if (!bpme->backpointer ||
938 bpm == bpme->backpointer ||
939 bpme->backpointer->action == bpm->action)
940 return HASHWALK_CONTINUE;
941 /* ensure bpm other characteristics are equal */
942 bpm_temp = bpme->backpointer;
943 if (bpm_temp->vrf_id != bpm->vrf_id ||
944 bpm_temp->type != bpm->type ||
945 bpm_temp->flags != bpm->flags)
946 return HASHWALK_CONTINUE;
947
948 /* look for remaining bpme */
949 bpmer->bpme_found = hash_lookup(bpm->entry_hash, bpme);
950 if (!bpmer->bpme_found)
951 return HASHWALK_CONTINUE;
952 return HASHWALK_ABORT;
953 }
954
955 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
956 struct bgp_info *binfo,
957 vrf_id_t vrf_id,
958 struct prefix *src,
959 struct prefix *dst,
960 uint8_t protocol,
961 struct bgp_pbr_range_port *src_port,
962 struct bgp_pbr_range_port *dst_port)
963 {
964 struct bgp_pbr_match temp;
965 struct bgp_pbr_match_entry temp2;
966 struct bgp_pbr_match *bpm;
967 struct bgp_pbr_match_entry *bpme;
968 struct bgp_pbr_match_entry_remain bpmer;
969
970 /* as we don't know information from EC
971 * look for bpm that have the bpm
972 * with vrf_id characteristics
973 */
974 memset(&temp2, 0, sizeof(temp2));
975 memset(&temp, 0, sizeof(temp));
976 if (src) {
977 temp.flags |= MATCH_IP_SRC_SET;
978 prefix_copy(&temp2.src, src);
979 } else
980 temp2.src.family = AF_INET;
981 if (dst) {
982 temp.flags |= MATCH_IP_DST_SET;
983 prefix_copy(&temp2.dst, dst);
984 } else
985 temp2.dst.family = AF_INET;
986 if (src_port) {
987 temp.flags |= MATCH_PORT_SRC_SET;
988 temp2.src_port_min = src_port->min_port;
989 if (src_port->max_port) {
990 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
991 temp2.src_port_max = src_port->max_port;
992 }
993 }
994 if (dst_port) {
995 temp.flags |= MATCH_PORT_DST_SET;
996 temp2.dst_port_min = dst_port->min_port;
997 if (dst_port->max_port) {
998 temp.flags |= MATCH_PORT_DST_RANGE_SET;
999 temp2.dst_port_max = dst_port->max_port;
1000 }
1001 }
1002 temp2.proto = protocol;
1003
1004 if (src == NULL || dst == NULL) {
1005 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1006 temp.type = IPSET_NET_PORT;
1007 else
1008 temp.type = IPSET_NET;
1009 } else {
1010 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1011 temp.type = IPSET_NET_PORT_NET;
1012 else
1013 temp.type = IPSET_NET_NET;
1014 }
1015 if (vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
1016 temp.vrf_id = 0;
1017 else
1018 temp.vrf_id = vrf_id;
1019 bpme = &temp2;
1020 bpm = &temp;
1021 bpme->backpointer = bpm;
1022 /* right now, a previous entry may already exist
1023 * flush previous entry if necessary
1024 */
1025 bpmer.bpme_to_match = bpme;
1026 bpmer.bpme_found = NULL;
1027 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1028 if (bpmer.bpme_found) {
1029 static struct bgp_pbr_match *local_bpm;
1030 static struct bgp_pbr_action *local_bpa;
1031
1032 local_bpm = bpmer.bpme_found->backpointer;
1033 local_bpa = local_bpm->action;
1034 bgp_pbr_flush_entry(bgp, local_bpa,
1035 local_bpm, bpmer.bpme_found);
1036 }
1037 }
1038
1039 static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
1040 struct bgp_info *binfo,
1041 vrf_id_t vrf_id,
1042 struct prefix *src,
1043 struct prefix *dst,
1044 struct nexthop *nh,
1045 float *rate,
1046 uint8_t protocol,
1047 struct bgp_pbr_range_port *src_port,
1048 struct bgp_pbr_range_port *dst_port)
1049 {
1050 struct bgp_pbr_match temp;
1051 struct bgp_pbr_match_entry temp2;
1052 struct bgp_pbr_match *bpm;
1053 struct bgp_pbr_match_entry *bpme = NULL;
1054 struct bgp_pbr_action temp3;
1055 struct bgp_pbr_action *bpa = NULL;
1056 struct bgp_pbr_match_entry_remain bpmer;
1057
1058 /* look for bpa first */
1059 memset(&temp3, 0, sizeof(temp3));
1060 if (rate)
1061 temp3.rate = *rate;
1062 if (nh)
1063 memcpy(&temp3.nh, nh, sizeof(struct nexthop));
1064 temp3.vrf_id = vrf_id;
1065 bpa = hash_get(bgp->pbr_action_hash, &temp3,
1066 bgp_pbr_action_alloc_intern);
1067
1068 if (bpa->fwmark == 0) {
1069 /* drop is handled by iptable */
1070 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
1071 bpa->table_id = 0;
1072 bpa->installed = true;
1073 } else {
1074 bpa->fwmark = bgp_zebra_tm_get_id();
1075 bpa->table_id = bpa->fwmark;
1076 bpa->installed = false;
1077 }
1078 bpa->bgp = bgp;
1079 bpa->unique = ++bgp_pbr_action_counter_unique;
1080 /* 0 value is forbidden */
1081 bpa->install_in_progress = false;
1082 }
1083
1084 /* then look for bpm */
1085 memset(&temp, 0, sizeof(temp));
1086 if (src == NULL || dst == NULL) {
1087 if ((src_port && src_port->min_port) ||
1088 (dst_port && dst_port->min_port))
1089 temp.type = IPSET_NET_PORT;
1090 else
1091 temp.type = IPSET_NET;
1092 } else {
1093 if ((src_port && src_port->min_port) ||
1094 (dst_port && dst_port->min_port))
1095 temp.type = IPSET_NET_PORT_NET;
1096 else
1097 temp.type = IPSET_NET_NET;
1098 }
1099 temp.vrf_id = vrf_id;
1100 if (src)
1101 temp.flags |= MATCH_IP_SRC_SET;
1102 if (dst)
1103 temp.flags |= MATCH_IP_DST_SET;
1104
1105 if (src_port && src_port->min_port)
1106 temp.flags |= MATCH_PORT_SRC_SET;
1107 if (dst_port && dst_port->min_port)
1108 temp.flags |= MATCH_PORT_DST_SET;
1109 if (src_port && src_port->max_port)
1110 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1111 if (dst_port && dst_port->max_port)
1112 temp.flags |= MATCH_PORT_DST_RANGE_SET;
1113 temp.action = bpa;
1114 bpm = hash_get(bgp->pbr_match_hash, &temp,
1115 bgp_pbr_match_alloc_intern);
1116
1117 /* new, then self allocate ipset_name and unique */
1118 if (bpm && bpm->unique == 0) {
1119 bpm->unique = ++bgp_pbr_match_counter_unique;
1120 /* 0 value is forbidden */
1121 sprintf(bpm->ipset_name, "match%p", bpm);
1122 bpm->entry_hash = hash_create_size(8,
1123 bgp_pbr_match_entry_hash_key,
1124 bgp_pbr_match_entry_hash_equal,
1125 "Match Entry Hash");
1126 bpm->installed = false;
1127
1128 /* unique2 should be updated too */
1129 bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
1130 bpm->installed_in_iptable = false;
1131 bpm->install_in_progress = false;
1132 bpm->install_iptable_in_progress = false;
1133 }
1134
1135 memset(&temp2, 0, sizeof(temp2));
1136 if (src)
1137 prefix_copy(&temp2.src, src);
1138 else
1139 temp2.src.family = AF_INET;
1140 if (dst)
1141 prefix_copy(&temp2.dst, dst);
1142 else
1143 temp2.dst.family = AF_INET;
1144 temp2.src_port_min = src_port ? src_port->min_port : 0;
1145 temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
1146 temp2.src_port_max = src_port ? src_port->max_port : 0;
1147 temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
1148 temp2.proto = protocol;
1149 if (bpm)
1150 bpme = hash_get(bpm->entry_hash, &temp2,
1151 bgp_pbr_match_entry_alloc_intern);
1152 if (bpme && bpme->unique == 0) {
1153 bpme->unique = ++bgp_pbr_match_entry_counter_unique;
1154 /* 0 value is forbidden */
1155 bpme->backpointer = bpm;
1156 bpme->installed = false;
1157 bpme->install_in_progress = false;
1158 /* link bgp info to bpme */
1159 bpme->bgp_info = (void *)binfo;
1160 }
1161
1162 /* BGP FS: append entry to zebra
1163 * - policies are not routing entries and as such
1164 * route replace semantics don't necessarily follow
1165 * through to policy entries
1166 * - because of that, not all policing information will be stored
1167 * into zebra. and non selected policies will be suppressed from zebra
1168 * - as consequence, in order to bring consistency
1169 * a policy will be added, then ifan ecmp policy exists,
1170 * it will be suppressed subsequently
1171 */
1172 /* ip rule add */
1173 if (!bpa->installed) {
1174 bgp_send_pbr_rule_action(bpa, true);
1175 bgp_zebra_announce_default(bgp, nh,
1176 AFI_IP, bpa->table_id, true);
1177 }
1178
1179 /* ipset create */
1180 if (bpm && !bpm->installed)
1181 bgp_send_pbr_ipset_match(bpm, true);
1182 /* ipset add */
1183 if (bpme && !bpme->installed)
1184 bgp_send_pbr_ipset_entry_match(bpme, true);
1185
1186 /* iptables */
1187 if (bpm && !bpm->installed_in_iptable)
1188 bgp_send_pbr_iptable(bpa, bpm, true);
1189
1190 /* A previous entry may already exist
1191 * flush previous entry if necessary
1192 */
1193 bpmer.bpme_to_match = bpme;
1194 bpmer.bpme_found = NULL;
1195 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1196 if (bpmer.bpme_found) {
1197 static struct bgp_pbr_match *local_bpm;
1198 static struct bgp_pbr_action *local_bpa;
1199
1200 local_bpm = bpmer.bpme_found->backpointer;
1201 local_bpa = local_bpm->action;
1202 bgp_pbr_flush_entry(bgp, local_bpa,
1203 local_bpm, bpmer.bpme_found);
1204 }
1205
1206
1207 }
1208
1209 static void bgp_pbr_handle_entry(struct bgp *bgp,
1210 struct bgp_info *binfo,
1211 struct bgp_pbr_entry_main *api,
1212 bool add)
1213 {
1214 struct nexthop nh;
1215 int i = 0;
1216 int continue_loop = 1;
1217 float rate = 0;
1218 struct prefix *src = NULL, *dst = NULL;
1219 uint8_t proto = 0;
1220 struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
1221 struct bgp_pbr_range_port range;
1222
1223 memset(&nh, 0, sizeof(struct nexthop));
1224 if (api->match_bitmask & PREFIX_SRC_PRESENT)
1225 src = &api->src_prefix;
1226 if (api->match_bitmask & PREFIX_DST_PRESENT)
1227 dst = &api->dst_prefix;
1228 memset(&nh, 0, sizeof(struct nexthop));
1229 nh.vrf_id = VRF_UNKNOWN;
1230 if (api->match_protocol_num)
1231 proto = (uint8_t)api->protocol[0].value;
1232 /* if match_port is selected, then either src or dst port will be parsed
1233 * but not both at the same time
1234 */
1235 if (api->match_port_num >= 1) {
1236 bgp_pbr_extract(api->port,
1237 api->match_port_num,
1238 &range);
1239 srcp = dstp = &range;
1240 } else if (api->match_src_port_num >= 1) {
1241 bgp_pbr_extract(api->src_port,
1242 api->match_src_port_num,
1243 &range);
1244 srcp = &range;
1245 dstp = NULL;
1246 } else if (api->match_dst_port_num >= 1) {
1247 bgp_pbr_extract(api->dst_port,
1248 api->match_dst_port_num,
1249 &range);
1250 dstp = &range;
1251 srcp = NULL;
1252 }
1253 if (!add)
1254 return bgp_pbr_policyroute_remove_from_zebra(bgp, binfo,
1255 api->vrf_id, src, dst,
1256 proto, srcp, dstp);
1257 /* no action for add = true */
1258 for (i = 0; i < api->action_num; i++) {
1259 switch (api->actions[i].action) {
1260 case ACTION_TRAFFICRATE:
1261 /* drop packet */
1262 if (api->actions[i].u.r.rate == 0) {
1263 nh.vrf_id = api->vrf_id;
1264 nh.type = NEXTHOP_TYPE_BLACKHOLE;
1265 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1266 api->vrf_id, src, dst,
1267 &nh, &rate, proto,
1268 srcp, dstp);
1269 } else {
1270 /* update rate. can be reentrant */
1271 rate = api->actions[i].u.r.rate;
1272 if (BGP_DEBUG(pbr, PBR)) {
1273 bgp_pbr_print_policy_route(api);
1274 zlog_warn("PBR: ignoring Set action rate %f",
1275 api->actions[i].u.r.rate);
1276 }
1277 }
1278 break;
1279 case ACTION_TRAFFIC_ACTION:
1280 if (api->actions[i].u.za.filter
1281 & TRAFFIC_ACTION_SAMPLE) {
1282 if (BGP_DEBUG(pbr, PBR)) {
1283 bgp_pbr_print_policy_route(api);
1284 zlog_warn("PBR: Sample action Ignored");
1285 }
1286 }
1287 #if 0
1288 if (api->actions[i].u.za.filter
1289 & TRAFFIC_ACTION_DISTRIBUTE) {
1290 if (BGP_DEBUG(pbr, PBR)) {
1291 bgp_pbr_print_policy_route(api);
1292 zlog_warn("PBR: Distribute action Applies");
1293 }
1294 continue_loop = 0;
1295 /* continue forwarding entry as before
1296 * no action
1297 */
1298 }
1299 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
1300 /* terminate action: run other filters
1301 */
1302 break;
1303 case ACTION_REDIRECT_IP:
1304 nh.type = NEXTHOP_TYPE_IPV4;
1305 nh.gate.ipv4.s_addr =
1306 api->actions[i].u.zr.redirect_ip_v4.s_addr;
1307 nh.vrf_id = api->vrf_id;
1308 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1309 api->vrf_id,
1310 src, dst,
1311 &nh, &rate, proto,
1312 srcp, dstp);
1313 /* XXX combination with REDIRECT_VRF
1314 * + REDIRECT_NH_IP not done
1315 */
1316 continue_loop = 0;
1317 break;
1318 case ACTION_REDIRECT:
1319 nh.vrf_id = api->actions[i].u.redirect_vrf;
1320 nh.type = NEXTHOP_TYPE_IPV4;
1321 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1322 api->vrf_id,
1323 src, dst,
1324 &nh, &rate, proto,
1325 srcp, dstp);
1326 continue_loop = 0;
1327 break;
1328 case ACTION_MARKING:
1329 if (BGP_DEBUG(pbr, PBR)) {
1330 bgp_pbr_print_policy_route(api);
1331 zlog_warn("PBR: Set DSCP %u Ignored",
1332 api->actions[i].u.marking_dscp);
1333 }
1334 break;
1335 default:
1336 break;
1337 }
1338 if (continue_loop == 0)
1339 break;
1340 }
1341 }
1342
1343 void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
1344 struct bgp_info *info, afi_t afi, safi_t safi,
1345 bool nlri_update)
1346 {
1347 struct bgp_pbr_entry_main api;
1348
1349 if (afi == AFI_IP6)
1350 return; /* IPv6 not supported */
1351 if (safi != SAFI_FLOWSPEC)
1352 return; /* not supported */
1353 /* Make Zebra API structure. */
1354 memset(&api, 0, sizeof(api));
1355 api.vrf_id = bgp->vrf_id;
1356 api.afi = afi;
1357
1358 if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
1359 if (BGP_DEBUG(pbr, PBR_ERROR))
1360 zlog_err("%s: cancel updating entry in bgp pbr",
1361 __func__);
1362 return;
1363 }
1364 bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
1365 }
1366
1367 int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
1368 const struct bgp_pbr_interface *b)
1369 {
1370 return strcmp(a->name, b->name);
1371 }
1372
1373 struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
1374 struct bgp_pbr_interface_head *head)
1375 {
1376 struct bgp_pbr_interface pbr_if;
1377
1378 strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
1379 return (RB_FIND(bgp_pbr_interface_head,
1380 head, &pbr_if));
1381 }
1382
1383 /* this function resets to the default policy routing
1384 * go back to default status
1385 */
1386 void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
1387 {
1388 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
1389 struct bgp_pbr_interface_head *head;
1390 struct bgp_pbr_interface *pbr_if;
1391
1392 if (!bgp_pbr_cfg || afi != AFI_IP)
1393 return;
1394 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
1395
1396 while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
1397 pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
1398 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
1399 XFREE(MTYPE_TMP, pbr_if);
1400 }
1401 }