]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_pbr.c
bgpd: add support of bgp flowspec filtering per packet length
[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 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
184 int num)
185 {
186 int i = 0;
187
188 for (i = 0; i < num; i++) {
189 if (list[i].compare_operator !=
190 OPERATOR_COMPARE_EQUAL_TO)
191 return false;
192 }
193 return true;
194 }
195
196 /* return true if extraction ok
197 */
198 static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
199 int num,
200 struct bgp_pbr_range_port *range)
201 {
202 int i = 0;
203 bool exact_match = false;
204
205 if (range)
206 memset(range, 0, sizeof(struct bgp_pbr_range_port));
207
208 if (num > 2)
209 return false;
210 for (i = 0; i < num; i++) {
211 if (i != 0 && (list[i].compare_operator ==
212 OPERATOR_COMPARE_EQUAL_TO))
213 return false;
214 if (i == 0 && (list[i].compare_operator ==
215 OPERATOR_COMPARE_EQUAL_TO)) {
216 if (range)
217 range->min_port = list[i].value;
218 exact_match = true;
219 }
220 if (exact_match == true && i > 0)
221 return false;
222 if (list[i].compare_operator ==
223 (OPERATOR_COMPARE_GREATER_THAN +
224 OPERATOR_COMPARE_EQUAL_TO)) {
225 if (range)
226 range->min_port = list[i].value;
227 } else if (list[i].compare_operator ==
228 (OPERATOR_COMPARE_LESS_THAN +
229 OPERATOR_COMPARE_EQUAL_TO)) {
230 if (range)
231 range->max_port = list[i].value;
232 } else if (list[i].compare_operator ==
233 OPERATOR_COMPARE_LESS_THAN) {
234 if (range)
235 range->max_port = list[i].value - 1;
236 } else if (list[i].compare_operator ==
237 OPERATOR_COMPARE_GREATER_THAN) {
238 if (range)
239 range->min_port = list[i].value + 1;
240 }
241 }
242 return true;
243 }
244
245 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
246 {
247 bool enumerate_icmp = false;
248
249 /* because bgp pbr entry may contain unsupported
250 * combinations, a message will be displayed here if
251 * not supported.
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
257 */
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");
263 }
264 return 0;
265 }
266
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);
272 return 0;
273 }
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);
282 return 0;
283 }
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.");
288 return 0;
289 }
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.");
294 return 0;
295 }
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.");
302 return 0;
303 }
304 enumerate_icmp = true;
305 }
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.");
312 return 0;
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.");
319 return 0;
320 }
321 }
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.");
326 return 0;
327 }
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.");
332 return 0;
333 }
334 /* no combinations with both src_port and dst_port
335 * or port with src_port and dst_port
336 */
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.");
342 return 0;
343 }
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.");
350 return 0;
351 }
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."
358 " ignoring.");
359 }
360 return 0;
361 }
362 return 1;
363 }
364
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)
369 {
370 int ret;
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;
377 afi_t afi = AFI_IP;
378
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);
382 if (ret < 0)
383 return -1;
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));
390 action_count++;
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);
395 break;
396 }
397 api_action = &api->actions[action_count - 1];
398
399 if ((ecom_eval->val[1] ==
400 (char)ECOMMUNITY_REDIRECT_VRF) &&
401 (ecom_eval->val[0] ==
402 (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
403 ecom_eval->val[0] ==
404 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
405 ecom_eval->val[0] ==
406 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
407 struct ecommunity *eckey = ecommunity_new();
408 struct ecommunity_val ecom_copy;
409
410 memcpy(&ecom_copy, ecom_eval,
411 sizeof(struct ecommunity_val));
412 ecom_copy.val[0] &=
413 ~ECOMMUNITY_ENCODE_TRANS_EXP;
414 ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
415 ecommunity_add_val(eckey, &ecom_copy);
416
417 api_action->action = ACTION_REDIRECT;
418 api_action->u.redirect_vrf =
419 get_first_vrf_for_redirect_with_rt(
420 eckey);
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];
430 } else {
431 if (ecom_eval->val[0] !=
432 (char)ECOMMUNITY_ENCODE_TRANS_EXP)
433 continue;
434 ret = ecommunity_fill_pbr_action(ecom_eval,
435 api_action);
436 if (ret != 0)
437 continue;
438 }
439 api->action_num++;
440 }
441 }
442
443 /* validate if incoming matc/action is compatible
444 * with our policy routing engine
445 */
446 if (!bgp_pbr_validate_policy_route(api))
447 return -1;
448
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);
453 valid_prefix = 1;
454 }
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));
463 }
464 return -1;
465 }
466 }
467 return 0;
468 }
469
470 static void bgp_pbr_match_entry_free(void *arg)
471 {
472 struct bgp_pbr_match_entry *bpme;
473
474 bpme = (struct bgp_pbr_match_entry *)arg;
475
476 if (bpme->installed) {
477 bgp_send_pbr_ipset_entry_match(bpme, false);
478 bpme->installed = false;
479 bpme->backpointer = NULL;
480 }
481 XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
482 }
483
484 static void bgp_pbr_match_free(void *arg)
485 {
486 struct bgp_pbr_match *bpm;
487
488 bpm = (struct bgp_pbr_match *)arg;
489
490 hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
491
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,
498 bpm, false);
499 bpm->installed_in_iptable = false;
500 bpm->action->refcnt--;
501 }
502 bgp_send_pbr_ipset_match(bpm, false);
503 bpm->installed = false;
504 bpm->action = NULL;
505 }
506 }
507 hash_free(bpm->entry_hash);
508
509 XFREE(MTYPE_PBR_MATCH, bpm);
510 }
511
512 static void *bgp_pbr_match_alloc_intern(void *arg)
513 {
514 struct bgp_pbr_match *bpm, *new;
515
516 bpm = (struct bgp_pbr_match *)arg;
517
518 new = XCALLOC(MTYPE_PBR_MATCH, sizeof(*new));
519 memcpy(new, bpm, sizeof(*bpm));
520
521 return new;
522 }
523
524 static void bgp_pbr_action_free(void *arg)
525 {
526 struct bgp_pbr_action *bpa;
527
528 bpa = (struct bgp_pbr_action *)arg;
529
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),
534 AFI_IP,
535 bpa->table_id,
536 false);
537 bpa->installed = false;
538 }
539 }
540 XFREE(MTYPE_PBR_ACTION, bpa);
541 }
542
543 static void *bgp_pbr_action_alloc_intern(void *arg)
544 {
545 struct bgp_pbr_action *bpa, *new;
546
547 bpa = (struct bgp_pbr_action *)arg;
548
549 new = XCALLOC(MTYPE_PBR_ACTION, sizeof(*new));
550
551 memcpy(new, bpa, sizeof(*bpa));
552
553 return new;
554 }
555
556 static void *bgp_pbr_match_entry_alloc_intern(void *arg)
557 {
558 struct bgp_pbr_match_entry *bpme, *new;
559
560 bpme = (struct bgp_pbr_match_entry *)arg;
561
562 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY, sizeof(*new));
563
564 memcpy(new, bpme, sizeof(*bpme));
565
566 return new;
567 }
568
569 uint32_t bgp_pbr_match_hash_key(void *arg)
570 {
571 struct bgp_pbr_match *pbm = (struct bgp_pbr_match *)arg;
572 uint32_t key;
573
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);
579 }
580
581 int bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
582 {
583 const struct bgp_pbr_match *r1, *r2;
584
585 r1 = (const struct bgp_pbr_match *)arg1;
586 r2 = (const struct bgp_pbr_match *)arg2;
587
588 if (r1->vrf_id != r2->vrf_id)
589 return 0;
590
591 if (r1->type != r2->type)
592 return 0;
593
594 if (r1->flags != r2->flags)
595 return 0;
596
597 if (r1->action != r2->action)
598 return 0;
599
600 if (r1->pkt_len_min != r2->pkt_len_min)
601 return 0;
602
603 if (r1->pkt_len_max != r2->pkt_len_max)
604 return 0;
605
606 return 1;
607 }
608
609 uint32_t bgp_pbr_match_entry_hash_key(void *arg)
610 {
611 struct bgp_pbr_match_entry *pbme;
612 uint32_t key;
613
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);
622
623 return key;
624 }
625
626 int bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
627 {
628 const struct bgp_pbr_match_entry *r1, *r2;
629
630 r1 = (const struct bgp_pbr_match_entry *)arg1;
631 r2 = (const struct bgp_pbr_match_entry *)arg2;
632
633 /* on updates, comparing
634 * backpointer is not necessary
635 */
636
637 /* unique value is self calculated
638 */
639
640 /* rate is ignored for now
641 */
642
643 if (!prefix_same(&r1->src, &r2->src))
644 return 0;
645
646 if (!prefix_same(&r1->dst, &r2->dst))
647 return 0;
648
649 if (r1->src_port_min != r2->src_port_min)
650 return 0;
651
652 if (r1->dst_port_min != r2->dst_port_min)
653 return 0;
654
655 if (r1->src_port_max != r2->src_port_max)
656 return 0;
657
658 if (r1->dst_port_max != r2->dst_port_max)
659 return 0;
660
661 if (r1->proto != r2->proto)
662 return 0;
663
664 return 1;
665 }
666
667 uint32_t bgp_pbr_action_hash_key(void *arg)
668 {
669 struct bgp_pbr_action *pbra;
670 uint32_t key;
671
672 pbra = (struct bgp_pbr_action *)arg;
673 key = jhash_1word(pbra->table_id, 0x4312abde);
674 key = jhash_1word(pbra->fwmark, key);
675 return key;
676 }
677
678 int bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
679 {
680 const struct bgp_pbr_action *r1, *r2;
681
682 r1 = (const struct bgp_pbr_action *)arg1;
683 r2 = (const struct bgp_pbr_action *)arg2;
684
685 /* unique value is self calculated
686 * table and fwmark is self calculated
687 * rate is ignored
688 */
689 if (r1->vrf_id != r2->vrf_id)
690 return 0;
691
692 if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop)))
693 return 0;
694 return 1;
695 }
696
697 struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
698 uint32_t unique)
699 {
700 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
701 struct bgp_pbr_action_unique bpau;
702
703 if (!bgp || unique == 0)
704 return NULL;
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;
709 }
710
711 struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
712 uint32_t unique)
713 {
714 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
715 struct bgp_pbr_match_unique bpmu;
716
717 if (!bgp || unique == 0)
718 return NULL;
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;
723 }
724
725 struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id,
726 char *ipset_name,
727 uint32_t unique)
728 {
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;
732
733 if (!bgp || unique == 0)
734 return NULL;
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);
740 if (!bpmi.bpm_found)
741 return NULL;
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;
747 }
748
749 struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
750 uint32_t unique)
751 {
752 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
753 struct bgp_pbr_match_iptable_unique bpmiu;
754
755 if (!bgp || unique == 0)
756 return NULL;
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;
761 }
762
763 void bgp_pbr_cleanup(struct bgp *bgp)
764 {
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;
769 }
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;
774 }
775 if (bgp->bgp_pbr_cfg == NULL)
776 return;
777 bgp_pbr_reset(bgp, AFI_IP);
778 XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
779 bgp->bgp_pbr_cfg = NULL;
780 }
781
782 void bgp_pbr_init(struct bgp *bgp)
783 {
784 bgp->pbr_match_hash =
785 hash_create_size(8, bgp_pbr_match_hash_key,
786 bgp_pbr_match_hash_equal,
787 "Match Hash");
788 bgp->pbr_action_hash =
789 hash_create_size(8, bgp_pbr_action_hash_key,
790 bgp_pbr_action_hash_equal,
791 "Match Hash Entry");
792
793 bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
794 bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
795 }
796
797 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
798 {
799 int i = 0;
800 char return_string[512];
801 char *ptr = return_string;
802 char buff[64];
803 int nb_items = 0;
804
805 ptr += sprintf(ptr, "MATCH : ");
806 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
807 struct prefix *p = &(api->src_prefix);
808
809 ptr += sprintf(ptr, "@src %s", prefix2str(p, buff, 64));
810 INCREMENT_DISPLAY(ptr, nb_items);
811 }
812 if (api->match_bitmask & PREFIX_DST_PRESENT) {
813 struct prefix *p = &(api->dst_prefix);
814
815 INCREMENT_DISPLAY(ptr, nb_items);
816 ptr += sprintf(ptr, "@dst %s", prefix2str(p, buff, 64));
817 }
818
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 ");
824
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 ");
830
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 ");
836
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 ");
842
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 ");
848
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 ");
854
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 ");
860
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 ");
866
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 ");
872
873 if (api->match_bitmask & FRAGMENT_PRESENT) {
874 INCREMENT_DISPLAY(ptr, nb_items);
875 ptr += sprintf(ptr, "@fragment %u", api->fragment.bitmask);
876 }
877 if (!nb_items)
878 ptr = return_string;
879 else
880 ptr += sprintf(ptr, "; ");
881 if (api->action_num)
882 ptr += sprintf(ptr, "SET : ");
883 nb_items = 0;
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);
890 break;
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)
896 ptr += sprintf(ptr,
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");
904 break;
905 case ACTION_REDIRECT_IP:
906 INCREMENT_DISPLAY(ptr, nb_items);
907 char local_buff[INET_ADDRSTRLEN];
908
909 if (inet_ntop(AF_INET,
910 &api->actions[i].u.zr.redirect_ip_v4,
911 local_buff, INET_ADDRSTRLEN) != NULL)
912 ptr += sprintf(ptr,
913 "@redirect ip nh %s", local_buff);
914 break;
915 case ACTION_REDIRECT:
916 INCREMENT_DISPLAY(ptr, nb_items);
917 ptr += sprintf(ptr, "@redirect vrf %u",
918 api->actions[i].u.redirect_vrf);
919 break;
920 case ACTION_MARKING:
921 INCREMENT_DISPLAY(ptr, nb_items);
922 ptr += sprintf(ptr, "@set dscp %u",
923 api->actions[i].u.marking_dscp);
924 break;
925 default:
926 break;
927 }
928 }
929 zlog_info("%s", return_string);
930 }
931
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)
935 {
936 /* if bpme is null, bpm is also null
937 */
938 if (bpme == NULL)
939 return;
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;
948
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;
954 }
955 }
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,
963 bpm, false);
964 bpm->installed_in_iptable = false;
965 bpm->action->refcnt--;
966 }
967 bgp_send_pbr_ipset_match(bpm, false);
968 bpm->installed = false;
969 bpm->action = NULL;
970 }
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
974 */
975 }
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),
980 AFI_IP,
981 bpa->table_id,
982 false);
983 bpa->installed = false;
984 }
985 }
986 }
987
988 struct bgp_pbr_match_entry_remain {
989 struct bgp_pbr_match_entry *bpme_to_match;
990 struct bgp_pbr_match_entry *bpme_found;
991 };
992
993 static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
994 {
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;
1000
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;
1011
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;
1017 }
1018
1019 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
1020 struct bgp_info *binfo,
1021 vrf_id_t vrf_id,
1022 struct prefix *src,
1023 struct prefix *dst,
1024 uint8_t protocol,
1025 struct bgp_pbr_range_port *pkt_len,
1026 struct bgp_pbr_range_port *src_port,
1027 struct bgp_pbr_range_port *dst_port)
1028 {
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;
1034
1035 /* as we don't know information from EC
1036 * look for bpm that have the bpm
1037 * with vrf_id characteristics
1038 */
1039 memset(&temp2, 0, sizeof(temp2));
1040 memset(&temp, 0, sizeof(temp));
1041 if (src) {
1042 temp.flags |= MATCH_IP_SRC_SET;
1043 prefix_copy(&temp2.src, src);
1044 } else
1045 temp2.src.family = AF_INET;
1046 if (dst) {
1047 temp.flags |= MATCH_IP_DST_SET;
1048 prefix_copy(&temp2.dst, dst);
1049 } else
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;
1057 }
1058 }
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;
1065 }
1066 }
1067 temp2.proto = protocol;
1068
1069 if (pkt_len)
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;
1073
1074 if (src == NULL || dst == NULL) {
1075 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1076 temp.type = IPSET_NET_PORT;
1077 else
1078 temp.type = IPSET_NET;
1079 } else {
1080 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1081 temp.type = IPSET_NET_PORT_NET;
1082 else
1083 temp.type = IPSET_NET_NET;
1084 }
1085 if (vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
1086 temp.vrf_id = 0;
1087 else
1088 temp.vrf_id = vrf_id;
1089 bpme = &temp2;
1090 bpm = &temp;
1091 bpme->backpointer = bpm;
1092 /* right now, a previous entry may already exist
1093 * flush previous entry if necessary
1094 */
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;
1101
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);
1106 }
1107 }
1108
1109 static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
1110 struct bgp_info *binfo,
1111 vrf_id_t vrf_id,
1112 struct prefix *src,
1113 struct prefix *dst,
1114 struct nexthop *nh,
1115 float *rate,
1116 uint8_t protocol,
1117 struct bgp_pbr_range_port *pkt_len,
1118 struct bgp_pbr_range_port *src_port,
1119 struct bgp_pbr_range_port *dst_port)
1120 {
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;
1128
1129 /* look for bpa first */
1130 memset(&temp3, 0, sizeof(temp3));
1131 if (rate)
1132 temp3.rate = *rate;
1133 if (nh)
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);
1138
1139 if (bpa->fwmark == 0) {
1140 /* drop is handled by iptable */
1141 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
1142 bpa->table_id = 0;
1143 bpa->installed = true;
1144 } else {
1145 bpa->fwmark = bgp_zebra_tm_get_id();
1146 bpa->table_id = bpa->fwmark;
1147 bpa->installed = false;
1148 }
1149 bpa->bgp = bgp;
1150 bpa->unique = ++bgp_pbr_action_counter_unique;
1151 /* 0 value is forbidden */
1152 bpa->install_in_progress = false;
1153 }
1154
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;
1161 else
1162 temp.type = IPSET_NET;
1163 } else {
1164 if ((src_port && src_port->min_port) ||
1165 (dst_port && dst_port->min_port))
1166 temp.type = IPSET_NET_PORT_NET;
1167 else
1168 temp.type = IPSET_NET_NET;
1169 }
1170 temp.vrf_id = vrf_id;
1171 if (src)
1172 temp.flags |= MATCH_IP_SRC_SET;
1173 if (dst)
1174 temp.flags |= MATCH_IP_DST_SET;
1175
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;
1184 if (pkt_len)
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;
1188
1189 temp.action = bpa;
1190 bpm = hash_get(bgp->pbr_match_hash, &temp,
1191 bgp_pbr_match_alloc_intern);
1192
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;
1203
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;
1209 }
1210
1211 memset(&temp2, 0, sizeof(temp2));
1212 if (src)
1213 prefix_copy(&temp2.src, src);
1214 else
1215 temp2.src.family = AF_INET;
1216 if (dst)
1217 prefix_copy(&temp2.dst, dst);
1218 else
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;
1225 if (bpm)
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;
1236 }
1237
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
1247 */
1248 /* ip rule add */
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);
1253 }
1254
1255 /* ipset create */
1256 if (bpm && !bpm->installed)
1257 bgp_send_pbr_ipset_match(bpm, true);
1258 /* ipset add */
1259 if (bpme && !bpme->installed)
1260 bgp_send_pbr_ipset_entry_match(bpme, true);
1261
1262 /* iptables */
1263 if (bpm && !bpm->installed_in_iptable)
1264 bgp_send_pbr_iptable(bpa, bpm, true);
1265
1266 /* A previous entry may already exist
1267 * flush previous entry if necessary
1268 */
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;
1275
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);
1280 }
1281
1282
1283 }
1284
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"},
1297 {0}
1298 };
1299
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"},
1305 {0}
1306 };
1307
1308 static const struct message icmp_code_exceed_str[] = {
1309 { 1, "ttl-eq-zero-during-reassembly"},
1310 { 0, "ttl-eq-zero-during-transit"},
1311 {0}
1312 };
1313
1314 static const struct message icmp_code_problem_str[] = {
1315 { 1, "required-option-missing"},
1316 { 2, "ip-header-bad"},
1317 {0}
1318 };
1319 static void bgp_pbr_enumerate_action_src_dst(struct bgp_pbr_match_val src[],
1320 int src_num,
1321 struct bgp_pbr_match_val dst[],
1322 int dst_num,
1323 struct prefix *src_address,
1324 struct prefix *dst_address,
1325 uint8_t proto,
1326 struct bgp_pbr_range_port *pkt_len,
1327 struct bgp *bgp,
1328 struct bgp_info *binfo,
1329 bool add,
1330 vrf_id_t vrf_id,
1331 struct nexthop *nh,
1332 float *rate)
1333 {
1334 int i = 0, j;
1335 struct bgp_pbr_range_port srcp, dstp;
1336
1337 if (proto != IPPROTO_ICMP)
1338 return;
1339 /* combinatory forced. ignore icmp type / code combinatory */
1340 if (src_num == 1 && dst_num == 1) {
1341 srcp.max_port = 0;
1342 dstp.max_port = 0;
1343 srcp.min_port = src[0].value;
1344 dstp.min_port = dst[0].value;
1345 if (add)
1346 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1347 vrf_id, src_address,
1348 dst_address,
1349 nh, rate, proto,
1350 pkt_len, &srcp, &dstp);
1351 else
1352 bgp_pbr_policyroute_remove_from_zebra(
1353 bgp,
1354 binfo,
1355 vrf_id,
1356 src_address,
1357 dst_address,
1358 proto, pkt_len,
1359 &srcp, &dstp);
1360 return;
1361 }
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
1365 */
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;
1371
1372 srcp.min_port = src[i].value;
1373 srcp.max_port = 0;
1374 dstp.max_port = 0;
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) {
1384 case 3:
1385 case 5:
1386 case 11:
1387 case 12:
1388 for (j = 0; j < dst_num; j++) {
1389 for (pnt = pnt_code;
1390 pnt && memcmp(pnt, &nt, sizeof(struct message));
1391 pnt++) {
1392 if (dst[i].value != pnt->key)
1393 continue;
1394 dstp.min_port = dst[i].value;
1395 icmp_typecode_configured = true;
1396 if (add)
1397 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1398 vrf_id, src_address,
1399 dst_address,
1400 nh, rate, proto,
1401 pkt_len, &srcp, &dstp);
1402 else
1403 bgp_pbr_policyroute_remove_from_zebra(
1404 bgp,
1405 binfo,
1406 vrf_id,
1407 src_address,
1408 dst_address,
1409 proto,
1410 pkt_len,
1411 &srcp, &dstp);
1412 }
1413 }
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));
1418 pnt++) {
1419 dstp.min_port = pnt->key;
1420 if (add)
1421 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1422 vrf_id, src_address,
1423 dst_address,
1424 nh, rate, proto,
1425 pkt_len,
1426 &srcp, &dstp);
1427 else
1428 bgp_pbr_policyroute_remove_from_zebra(
1429 bgp,
1430 binfo,
1431 vrf_id,
1432 src_address,
1433 dst_address,
1434 proto, pkt_len,
1435 &srcp, &dstp);
1436 }
1437
1438 }
1439 break;
1440 default:
1441 /* icmp type is not one of the above
1442 * forge an entry only based on the icmp type
1443 */
1444 dstp.min_port = 0;
1445 if (add)
1446 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1447 vrf_id, src_address,
1448 dst_address,
1449 nh, rate, proto,
1450 pkt_len, &srcp, &dstp);
1451 else
1452 bgp_pbr_policyroute_remove_from_zebra(
1453 bgp,
1454 binfo,
1455 vrf_id,
1456 src_address,
1457 dst_address,
1458 proto, pkt_len,
1459 &srcp, &dstp);
1460 break;
1461 }
1462 }
1463 }
1464
1465 static void bgp_pbr_handle_entry(struct bgp *bgp,
1466 struct bgp_info *binfo,
1467 struct bgp_pbr_entry_main *api,
1468 bool add)
1469 {
1470 struct nexthop nh;
1471 int i = 0;
1472 int continue_loop = 1;
1473 float rate = 0;
1474 struct prefix *src = NULL, *dst = NULL;
1475 uint8_t proto = 0;
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;
1480
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
1492 */
1493 if (api->match_port_num >= 1) {
1494 bgp_pbr_extract(api->port,
1495 api->match_port_num,
1496 &range);
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,
1501 &range);
1502 srcp = &range;
1503 dstp = NULL;
1504 } else if (api->match_dst_port_num >= 1) {
1505 bgp_pbr_extract(api->dst_port,
1506 api->match_dst_port_num,
1507 &range);
1508 dstp = &range;
1509 srcp = NULL;
1510 }
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))
1515 enum_icmp = true;
1516 else {
1517 bgp_pbr_extract(api->icmp_type,
1518 api->match_icmp_type_num,
1519 &range);
1520 srcp = &range;
1521 }
1522 }
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))
1527 enum_icmp = true;
1528 else {
1529 bgp_pbr_extract(api->icmp_code,
1530 api->match_icmp_code_num,
1531 &range_icmp_code);
1532 dstp = &range_icmp_code;
1533 }
1534 }
1535 if (api->match_packet_length_num >= 1)
1536 bgp_pbr_extract(api->packet_length,
1537 api->match_packet_length_num,
1538 &pkt_len);
1539 if (!add) {
1540 if (enum_icmp) {
1541 return bgp_pbr_enumerate_action_src_dst(api->icmp_type,
1542 api->match_icmp_type_num,
1543 api->icmp_code,
1544 api->match_icmp_code_num,
1545 src, dst, proto, &pkt_len,
1546 bgp, binfo, add,
1547 api->vrf_id, NULL, NULL);
1548 }
1549 return bgp_pbr_policyroute_remove_from_zebra(bgp,
1550 binfo,
1551 api->vrf_id,
1552 src, dst,
1553 proto, &pkt_len,
1554 srcp, dstp);
1555 }
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:
1560 /* drop packet */
1561 if (api->actions[i].u.r.rate == 0) {
1562 nh.vrf_id = api->vrf_id;
1563 nh.type = NEXTHOP_TYPE_BLACKHOLE;
1564 if (enum_icmp)
1565 bgp_pbr_enumerate_action_src_dst(api->icmp_type,
1566 api->match_icmp_type_num,
1567 api->icmp_code,
1568 api->match_icmp_code_num,
1569 src, dst, proto, &pkt_len,
1570 bgp, binfo, add,
1571 api->vrf_id, &nh, &rate);
1572 else
1573 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1574 api->vrf_id, src, dst,
1575 &nh, &rate, proto,
1576 &pkt_len, srcp, dstp);
1577 } else {
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);
1584 }
1585 }
1586 break;
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");
1593 }
1594 }
1595 #if 0
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");
1601 }
1602 continue_loop = 0;
1603 /* continue forwarding entry as before
1604 * no action
1605 */
1606 }
1607 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
1608 /* terminate action: run other filters
1609 */
1610 break;
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;
1616 if (enum_icmp)
1617 bgp_pbr_enumerate_action_src_dst(api->icmp_type,
1618 api->match_icmp_type_num,
1619 api->icmp_code,
1620 api->match_icmp_code_num,
1621 src, dst, proto, &pkt_len,
1622 bgp, binfo, add,
1623 api->vrf_id, &nh, &rate);
1624 else
1625 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1626 api->vrf_id,
1627 src, dst,
1628 &nh, &rate, proto,
1629 &pkt_len, srcp, dstp);
1630 /* XXX combination with REDIRECT_VRF
1631 * + REDIRECT_NH_IP not done
1632 */
1633 continue_loop = 0;
1634 break;
1635 case ACTION_REDIRECT:
1636 nh.vrf_id = api->actions[i].u.redirect_vrf;
1637 nh.type = NEXTHOP_TYPE_IPV4;
1638 if (enum_icmp)
1639 bgp_pbr_enumerate_action_src_dst(api->icmp_type,
1640 api->match_icmp_type_num,
1641 api->icmp_code,
1642 api->match_icmp_code_num,
1643 src, dst, proto, &pkt_len,
1644 bgp, binfo, add,
1645 api->vrf_id, &nh, &rate);
1646 else
1647 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
1648 api->vrf_id,
1649 src, dst,
1650 &nh, &rate, proto,
1651 &pkt_len, srcp, dstp);
1652 continue_loop = 0;
1653 break;
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);
1659 }
1660 break;
1661 default:
1662 break;
1663 }
1664 if (continue_loop == 0)
1665 break;
1666 }
1667 }
1668
1669 void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
1670 struct bgp_info *info, afi_t afi, safi_t safi,
1671 bool nlri_update)
1672 {
1673 struct bgp_pbr_entry_main api;
1674 struct bgp_info_extra *extra = bgp_info_extra_get(info);
1675
1676 if (afi == AFI_IP6)
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;
1683 api.afi = afi;
1684
1685 if (!bgp_zebra_tm_chunk_obtained()) {
1686 if (BGP_DEBUG(pbr, PBR_ERROR))
1687 zlog_err("%s: table chunk not obtained yet",
1688 __func__);
1689 return;
1690 }
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",
1695 __func__, info);
1696 return;
1697 }
1698
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",
1702 __func__, info);
1703 return;
1704 }
1705 bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
1706 }
1707
1708 int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
1709 const struct bgp_pbr_interface *b)
1710 {
1711 return strcmp(a->name, b->name);
1712 }
1713
1714 struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
1715 struct bgp_pbr_interface_head *head)
1716 {
1717 struct bgp_pbr_interface pbr_if;
1718
1719 strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
1720 return (RB_FIND(bgp_pbr_interface_head,
1721 head, &pbr_if));
1722 }
1723
1724 /* this function resets to the default policy routing
1725 * go back to default status
1726 */
1727 void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
1728 {
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;
1732
1733 if (!bgp_pbr_cfg || afi != AFI_IP)
1734 return;
1735 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
1736
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);
1741 }
1742 }