]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_pbr.c
*: Replace s_addr 0 => INADDR_ANY
[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 #include "pbr.h"
25
26 #include "bgpd/bgpd.h"
27 #include "bgpd/bgp_pbr.h"
28 #include "bgpd/bgp_debug.h"
29 #include "bgpd/bgp_flowspec_util.h"
30 #include "bgpd/bgp_ecommunity.h"
31 #include "bgpd/bgp_route.h"
32 #include "bgpd/bgp_attr.h"
33 #include "bgpd/bgp_zebra.h"
34 #include "bgpd/bgp_mplsvpn.h"
35 #include "bgpd/bgp_flowspec_private.h"
36 #include "bgpd/bgp_errors.h"
37
38 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
39 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
40 DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
41 DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule")
42 DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
43 DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
44
45 RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
46 id_entry, bgp_pbr_interface_compare);
47 struct bgp_pbr_interface_head ifaces_by_name_ipv4 =
48 RB_INITIALIZER(&ifaces_by_name_ipv4);
49
50 static int bgp_pbr_match_counter_unique;
51 static int bgp_pbr_match_entry_counter_unique;
52 static int bgp_pbr_action_counter_unique;
53 static int bgp_pbr_match_iptable_counter_unique;
54
55 struct bgp_pbr_match_iptable_unique {
56 uint32_t unique;
57 struct bgp_pbr_match *bpm_found;
58 };
59
60 struct bgp_pbr_match_entry_unique {
61 uint32_t unique;
62 struct bgp_pbr_match_entry *bpme_found;
63 };
64
65 struct bgp_pbr_action_unique {
66 uint32_t unique;
67 struct bgp_pbr_action *bpa_found;
68 };
69
70 struct bgp_pbr_rule_unique {
71 uint32_t unique;
72 struct bgp_pbr_rule *bpr_found;
73 };
74
75 static int bgp_pbr_rule_walkcb(struct hash_bucket *bucket, void *arg)
76 {
77 struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)bucket->data;
78 struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *)
79 arg;
80 uint32_t unique = bpru->unique;
81
82 if (bpr->unique == unique) {
83 bpru->bpr_found = bpr;
84 return HASHWALK_ABORT;
85 }
86 return HASHWALK_CONTINUE;
87 }
88
89 static int bgp_pbr_action_walkcb(struct hash_bucket *bucket, void *arg)
90 {
91 struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)bucket->data;
92 struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *)
93 arg;
94 uint32_t unique = bpau->unique;
95
96 if (bpa->unique == unique) {
97 bpau->bpa_found = bpa;
98 return HASHWALK_ABORT;
99 }
100 return HASHWALK_CONTINUE;
101 }
102
103 static int bgp_pbr_match_entry_walkcb(struct hash_bucket *bucket, void *arg)
104 {
105 struct bgp_pbr_match_entry *bpme =
106 (struct bgp_pbr_match_entry *)bucket->data;
107 struct bgp_pbr_match_entry_unique *bpmeu =
108 (struct bgp_pbr_match_entry_unique *)arg;
109 uint32_t unique = bpmeu->unique;
110
111 if (bpme->unique == unique) {
112 bpmeu->bpme_found = bpme;
113 return HASHWALK_ABORT;
114 }
115 return HASHWALK_CONTINUE;
116 }
117
118 struct bgp_pbr_match_ipsetname {
119 char *ipsetname;
120 struct bgp_pbr_match *bpm_found;
121 };
122
123 static int bgp_pbr_match_pername_walkcb(struct hash_bucket *bucket, void *arg)
124 {
125 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
126 struct bgp_pbr_match_ipsetname *bpmi =
127 (struct bgp_pbr_match_ipsetname *)arg;
128 char *ipset_name = bpmi->ipsetname;
129
130 if (!strncmp(ipset_name, bpm->ipset_name,
131 ZEBRA_IPSET_NAME_SIZE)) {
132 bpmi->bpm_found = bpm;
133 return HASHWALK_ABORT;
134 }
135 return HASHWALK_CONTINUE;
136 }
137
138 static int bgp_pbr_match_iptable_walkcb(struct hash_bucket *bucket, void *arg)
139 {
140 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
141 struct bgp_pbr_match_iptable_unique *bpmiu =
142 (struct bgp_pbr_match_iptable_unique *)arg;
143 uint32_t unique = bpmiu->unique;
144
145 if (bpm->unique2 == unique) {
146 bpmiu->bpm_found = bpm;
147 return HASHWALK_ABORT;
148 }
149 return HASHWALK_CONTINUE;
150 }
151
152 struct bgp_pbr_match_unique {
153 uint32_t unique;
154 struct bgp_pbr_match *bpm_found;
155 };
156
157 static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg)
158 {
159 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
160 struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *)
161 arg;
162 uint32_t unique = bpmu->unique;
163
164 if (bpm->unique == unique) {
165 bpmu->bpm_found = bpm;
166 return HASHWALK_ABORT;
167 }
168 return HASHWALK_CONTINUE;
169 }
170
171 static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
172 const char *prepend)
173 {
174 char *ptr = str;
175
176 if (prepend)
177 ptr += sprintf(ptr, "%s", prepend);
178 else {
179 if (mval->unary_operator & OPERATOR_UNARY_OR)
180 ptr += sprintf(ptr, ", or ");
181 if (mval->unary_operator & OPERATOR_UNARY_AND)
182 ptr += sprintf(ptr, ", and ");
183 }
184 if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN)
185 ptr += sprintf(ptr, "<");
186 if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN)
187 ptr += sprintf(ptr, ">");
188 if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO)
189 ptr += sprintf(ptr, "=");
190 if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH)
191 ptr += sprintf(ptr, "match");
192 ptr += sprintf(ptr, " %u", mval->value);
193 return (int)(ptr - str);
194 }
195
196 #define INCREMENT_DISPLAY(_ptr, _cnt) do { \
197 if (_cnt) \
198 (_ptr) += sprintf((_ptr), "; "); \
199 _cnt++; \
200 } while (0)
201
202 /* this structure can be used for port range,
203 * but also for other values range like packet length range
204 */
205 struct bgp_pbr_range_port {
206 uint16_t min_port;
207 uint16_t max_port;
208 };
209
210 /* this structure can be used to filter with a mask
211 * for instance it supports not instructions like for
212 * tcpflags
213 */
214 struct bgp_pbr_val_mask {
215 uint16_t val;
216 uint16_t mask;
217 };
218
219 /* this structure is used to pass instructs
220 * so that BGP can create pbr instructions to ZEBRA
221 */
222 struct bgp_pbr_filter {
223 uint8_t type;
224 vrf_id_t vrf_id;
225 struct prefix *src;
226 struct prefix *dst;
227 uint8_t bitmask_iprule;
228 uint8_t protocol;
229 struct bgp_pbr_range_port *pkt_len;
230 struct bgp_pbr_range_port *src_port;
231 struct bgp_pbr_range_port *dst_port;
232 struct bgp_pbr_val_mask *tcp_flags;
233 struct bgp_pbr_val_mask *dscp;
234 struct bgp_pbr_val_mask *pkt_len_val;
235 struct bgp_pbr_val_mask *fragment;
236 };
237
238 /* this structure is used to contain OR instructions
239 * so that BGP can create multiple pbr instructions
240 * to ZEBRA
241 */
242 struct bgp_pbr_or_filter {
243 struct list *tcpflags;
244 struct list *dscp;
245 struct list *pkt_len;
246 struct list *fragment;
247 struct list *icmp_type;
248 struct list *icmp_code;
249 };
250
251 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
252 struct bgp_path_info *path,
253 struct bgp_pbr_filter *bpf,
254 struct nexthop *nh,
255 float *rate);
256
257 static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add);
258
259 static bool bgp_pbr_extract_enumerate_unary_opposite(
260 uint8_t unary_operator,
261 struct bgp_pbr_val_mask *and_valmask,
262 struct list *or_valmask, uint32_t value,
263 uint8_t type_entry)
264 {
265 if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
266 if (type_entry == FLOWSPEC_TCP_FLAGS) {
267 and_valmask->mask |=
268 TCP_HEADER_ALL_FLAGS &
269 ~(value);
270 } else if (type_entry == FLOWSPEC_DSCP ||
271 type_entry == FLOWSPEC_PKT_LEN ||
272 type_entry == FLOWSPEC_FRAGMENT) {
273 and_valmask->val = value;
274 and_valmask->mask = 1; /* inverse */
275 }
276 } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
277 and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
278 sizeof(struct bgp_pbr_val_mask));
279 if (type_entry == FLOWSPEC_TCP_FLAGS) {
280 and_valmask->val = TCP_HEADER_ALL_FLAGS;
281 and_valmask->mask |=
282 TCP_HEADER_ALL_FLAGS &
283 ~(value);
284 } else if (type_entry == FLOWSPEC_DSCP ||
285 type_entry == FLOWSPEC_FRAGMENT ||
286 type_entry == FLOWSPEC_PKT_LEN) {
287 and_valmask->val = value;
288 and_valmask->mask = 1; /* inverse */
289 }
290 listnode_add(or_valmask, and_valmask);
291 } else if (type_entry == FLOWSPEC_ICMP_CODE ||
292 type_entry == FLOWSPEC_ICMP_TYPE)
293 return false;
294 return true;
295 }
296
297 /* TCP : FIN and SYN -> val = ALL; mask = 3
298 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
299 * other variables type: dscp, pkt len, fragment
300 * - value is copied in bgp_pbr_val_mask->val value
301 * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
302 */
303 static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
304 int num, uint8_t unary_operator,
305 void *valmask, uint8_t type_entry)
306 {
307 int i = 0;
308 struct bgp_pbr_val_mask *and_valmask = NULL;
309 struct list *or_valmask = NULL;
310 bool ret;
311
312 if (valmask) {
313 if (unary_operator == OPERATOR_UNARY_AND) {
314 and_valmask = (struct bgp_pbr_val_mask *)valmask;
315 memset(and_valmask, 0, sizeof(struct bgp_pbr_val_mask));
316 } else if (unary_operator == OPERATOR_UNARY_OR) {
317 or_valmask = (struct list *)valmask;
318 }
319 }
320 for (i = 0; i < num; i++) {
321 if (i != 0 && list[i].unary_operator !=
322 unary_operator)
323 return false;
324 if (!(list[i].compare_operator &
325 OPERATOR_COMPARE_EQUAL_TO) &&
326 !(list[i].compare_operator &
327 OPERATOR_COMPARE_EXACT_MATCH)) {
328 if ((list[i].compare_operator &
329 OPERATOR_COMPARE_LESS_THAN) &&
330 (list[i].compare_operator &
331 OPERATOR_COMPARE_GREATER_THAN)) {
332 ret = bgp_pbr_extract_enumerate_unary_opposite(
333 unary_operator, and_valmask,
334 or_valmask, list[i].value,
335 type_entry);
336 if (!ret)
337 return ret;
338 continue;
339 }
340 return false;
341 }
342 if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
343 if (type_entry == FLOWSPEC_TCP_FLAGS)
344 and_valmask->mask |=
345 TCP_HEADER_ALL_FLAGS & list[i].value;
346 } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
347 and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
348 sizeof(struct bgp_pbr_val_mask));
349 if (type_entry == FLOWSPEC_TCP_FLAGS) {
350 and_valmask->val = TCP_HEADER_ALL_FLAGS;
351 and_valmask->mask |=
352 TCP_HEADER_ALL_FLAGS & list[i].value;
353 } else if (type_entry == FLOWSPEC_DSCP ||
354 type_entry == FLOWSPEC_ICMP_TYPE ||
355 type_entry == FLOWSPEC_ICMP_CODE ||
356 type_entry == FLOWSPEC_FRAGMENT ||
357 type_entry == FLOWSPEC_PKT_LEN)
358 and_valmask->val = list[i].value;
359 listnode_add(or_valmask, and_valmask);
360 }
361 }
362 if (unary_operator == OPERATOR_UNARY_AND && and_valmask
363 && type_entry == FLOWSPEC_TCP_FLAGS)
364 and_valmask->val = TCP_HEADER_ALL_FLAGS;
365 return true;
366 }
367
368 /* if unary operator can either be UNARY_OR/AND/OR-AND.
369 * in the latter case, combinationf of both is not handled
370 */
371 static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
372 int num, uint8_t unary_operator,
373 void *valmask, uint8_t type_entry)
374 {
375 bool ret;
376 uint8_t unary_operator_val;
377 bool double_check = false;
378
379 if ((unary_operator & OPERATOR_UNARY_OR) &&
380 (unary_operator & OPERATOR_UNARY_AND)) {
381 unary_operator_val = OPERATOR_UNARY_AND;
382 double_check = true;
383 } else
384 unary_operator_val = unary_operator;
385 ret = bgp_pbr_extract_enumerate_unary(list, num, unary_operator_val,
386 valmask, type_entry);
387 if (!ret && double_check)
388 ret = bgp_pbr_extract_enumerate_unary(list, num,
389 OPERATOR_UNARY_OR,
390 valmask,
391 type_entry);
392 return ret;
393 }
394
395 /* returns the unary operator that is in the list
396 * return 0 if both operators are used
397 */
398 static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
399 int num)
400
401 {
402 int i;
403 uint8_t unary_operator = OPERATOR_UNARY_AND;
404
405 for (i = 0; i < num; i++) {
406 if (i == 0)
407 continue;
408 if (list[i].unary_operator & OPERATOR_UNARY_OR)
409 unary_operator = OPERATOR_UNARY_OR;
410 if ((list[i].unary_operator & OPERATOR_UNARY_AND
411 && unary_operator == OPERATOR_UNARY_OR) ||
412 (list[i].unary_operator & OPERATOR_UNARY_OR
413 && unary_operator == OPERATOR_UNARY_AND))
414 return 0;
415 }
416 return unary_operator;
417 }
418
419
420 /* return true if extraction ok
421 */
422 static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
423 int num,
424 struct bgp_pbr_range_port *range)
425 {
426 int i = 0;
427 bool exact_match = false;
428
429 if (range)
430 memset(range, 0, sizeof(struct bgp_pbr_range_port));
431
432 if (num > 2)
433 return false;
434 for (i = 0; i < num; i++) {
435 if (i != 0 && (list[i].compare_operator ==
436 OPERATOR_COMPARE_EQUAL_TO))
437 return false;
438 if (i == 0 && (list[i].compare_operator ==
439 OPERATOR_COMPARE_EQUAL_TO)) {
440 if (range)
441 range->min_port = list[i].value;
442 exact_match = true;
443 }
444 if (exact_match && i > 0)
445 return false;
446 if (list[i].compare_operator ==
447 (OPERATOR_COMPARE_GREATER_THAN +
448 OPERATOR_COMPARE_EQUAL_TO)) {
449 if (range)
450 range->min_port = list[i].value;
451 } else if (list[i].compare_operator ==
452 (OPERATOR_COMPARE_LESS_THAN +
453 OPERATOR_COMPARE_EQUAL_TO)) {
454 if (range)
455 range->max_port = list[i].value;
456 } else if (list[i].compare_operator ==
457 OPERATOR_COMPARE_LESS_THAN) {
458 if (range)
459 range->max_port = list[i].value - 1;
460 } else if (list[i].compare_operator ==
461 OPERATOR_COMPARE_GREATER_THAN) {
462 if (range)
463 range->min_port = list[i].value + 1;
464 }
465 }
466 return true;
467 }
468
469 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
470 {
471 bool enumerate_icmp = false;
472
473 if (api->type == BGP_PBR_UNDEFINED) {
474 if (BGP_DEBUG(pbr, PBR))
475 zlog_debug("BGP: pbr entry undefined. cancel.");
476 return 0;
477 }
478 /* because bgp pbr entry may contain unsupported
479 * combinations, a message will be displayed here if
480 * not supported.
481 * for now, only match/set supported is
482 * - combination src/dst => redirect nexthop [ + rate]
483 * - combination src/dst => redirect VRF [ + rate]
484 * - combination src/dst => drop
485 * - combination srcport + @IP
486 */
487 if (api->match_protocol_num > 1) {
488 if (BGP_DEBUG(pbr, PBR))
489 zlog_debug("BGP: match protocol operations:"
490 "multiple protocols ( %d). ignoring.",
491 api->match_protocol_num);
492 return 0;
493 }
494 if (api->match_protocol_num == 1 &&
495 api->protocol[0].value != PROTOCOL_UDP &&
496 api->protocol[0].value != PROTOCOL_ICMP &&
497 api->protocol[0].value != PROTOCOL_TCP) {
498 if (BGP_DEBUG(pbr, PBR))
499 zlog_debug("BGP: match protocol operations:"
500 "protocol (%d) not supported. ignoring",
501 api->match_protocol_num);
502 return 0;
503 }
504 if (!bgp_pbr_extract(api->src_port, api->match_src_port_num, NULL)) {
505 if (BGP_DEBUG(pbr, PBR))
506 zlog_debug("BGP: match src port operations:"
507 "too complex. ignoring.");
508 return 0;
509 }
510 if (!bgp_pbr_extract(api->dst_port, api->match_dst_port_num, NULL)) {
511 if (BGP_DEBUG(pbr, PBR))
512 zlog_debug("BGP: match dst port operations:"
513 "too complex. ignoring.");
514 return 0;
515 }
516 if (!bgp_pbr_extract_enumerate(api->tcpflags,
517 api->match_tcpflags_num,
518 OPERATOR_UNARY_AND |
519 OPERATOR_UNARY_OR, NULL,
520 FLOWSPEC_TCP_FLAGS)) {
521 if (BGP_DEBUG(pbr, PBR))
522 zlog_debug("BGP: match tcp flags:"
523 "too complex. ignoring.");
524 return 0;
525 }
526 if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
527 if (!bgp_pbr_extract_enumerate(api->icmp_type,
528 api->match_icmp_type_num,
529 OPERATOR_UNARY_OR, NULL,
530 FLOWSPEC_ICMP_TYPE)) {
531 if (BGP_DEBUG(pbr, PBR))
532 zlog_debug("BGP: match icmp type operations:"
533 "too complex. ignoring.");
534 return 0;
535 }
536 enumerate_icmp = true;
537 }
538 if (!bgp_pbr_extract(api->icmp_code, api->match_icmp_code_num, NULL)) {
539 if (!bgp_pbr_extract_enumerate(api->icmp_code,
540 api->match_icmp_code_num,
541 OPERATOR_UNARY_OR, NULL,
542 FLOWSPEC_ICMP_CODE)) {
543 if (BGP_DEBUG(pbr, PBR))
544 zlog_debug("BGP: match icmp code operations:"
545 "too complex. ignoring.");
546 return 0;
547 } else if (api->match_icmp_type_num > 1 &&
548 !enumerate_icmp) {
549 if (BGP_DEBUG(pbr, PBR))
550 zlog_debug("BGP: match icmp code is enumerate"
551 ", and icmp type is not."
552 " too complex. ignoring.");
553 return 0;
554 }
555 }
556 if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
557 if (BGP_DEBUG(pbr, PBR))
558 zlog_debug("BGP: match port operations:"
559 "too complex. ignoring.");
560 return 0;
561 }
562 if (api->match_packet_length_num) {
563 bool ret;
564
565 ret = bgp_pbr_extract(api->packet_length,
566 api->match_packet_length_num, NULL);
567 if (!ret)
568 ret = bgp_pbr_extract_enumerate(api->packet_length,
569 api->match_packet_length_num,
570 OPERATOR_UNARY_OR
571 | OPERATOR_UNARY_AND,
572 NULL, FLOWSPEC_PKT_LEN);
573 if (!ret) {
574 if (BGP_DEBUG(pbr, PBR))
575 zlog_debug("BGP: match packet length operations:"
576 "too complex. ignoring.");
577 return 0;
578 }
579 }
580 if (api->match_dscp_num) {
581 if (!bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
582 OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
583 NULL, FLOWSPEC_DSCP)) {
584 if (BGP_DEBUG(pbr, PBR))
585 zlog_debug("BGP: match DSCP operations:"
586 "too complex. ignoring.");
587 return 0;
588 }
589 }
590 if (api->match_fragment_num) {
591 char fail_str[64];
592 bool success;
593
594 success = bgp_pbr_extract_enumerate(api->fragment,
595 api->match_fragment_num,
596 OPERATOR_UNARY_OR
597 | OPERATOR_UNARY_AND,
598 NULL, FLOWSPEC_FRAGMENT);
599 if (success) {
600 int i;
601
602 for (i = 0; i < api->match_fragment_num; i++) {
603 if (api->fragment[i].value != 1 &&
604 api->fragment[i].value != 2 &&
605 api->fragment[i].value != 4 &&
606 api->fragment[i].value != 8) {
607 success = false;
608 sprintf(fail_str,
609 "Value not valid (%d) for this implementation",
610 api->fragment[i].value);
611 }
612 }
613 } else
614 sprintf(fail_str, "too complex. ignoring");
615 if (!success) {
616 if (BGP_DEBUG(pbr, PBR))
617 zlog_debug("BGP: match fragment operation (%d) %s",
618 api->match_fragment_num,
619 fail_str);
620 return 0;
621 }
622 }
623
624 /* no combinations with both src_port and dst_port
625 * or port with src_port and dst_port
626 */
627 if (api->match_src_port_num + api->match_dst_port_num +
628 api->match_port_num > 3) {
629 if (BGP_DEBUG(pbr, PBR))
630 zlog_debug("BGP: match multiple port operations:"
631 " too complex. ignoring.");
632 return 0;
633 }
634 if ((api->match_src_port_num || api->match_dst_port_num
635 || api->match_port_num) && (api->match_icmp_type_num
636 || api->match_icmp_code_num)) {
637 if (BGP_DEBUG(pbr, PBR))
638 zlog_debug("BGP: match multiple port/imcp operations:"
639 " too complex. ignoring.");
640 return 0;
641 }
642 /* iprule only supports redirect IP */
643 if (api->type == BGP_PBR_IPRULE) {
644 int i;
645
646 for (i = 0; i < api->action_num; i++) {
647 if (api->actions[i].action == ACTION_TRAFFICRATE &&
648 api->actions[i].u.r.rate == 0) {
649 if (BGP_DEBUG(pbr, PBR)) {
650 bgp_pbr_print_policy_route(api);
651 zlog_debug("BGP: iprule match actions"
652 " drop not supported");
653 }
654 return 0;
655 }
656 if (api->actions[i].action == ACTION_MARKING) {
657 if (BGP_DEBUG(pbr, PBR)) {
658 bgp_pbr_print_policy_route(api);
659 zlog_warn("PBR: iprule set DSCP %u"
660 " not supported",
661 api->actions[i].u.marking_dscp);
662 }
663 }
664 if (api->actions[i].action == ACTION_REDIRECT) {
665 if (BGP_DEBUG(pbr, PBR)) {
666 bgp_pbr_print_policy_route(api);
667 zlog_warn("PBR: iprule redirect VRF %u"
668 " not supported",
669 api->actions[i].u.redirect_vrf);
670 }
671 }
672 }
673
674 } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
675 !(api->match_bitmask & PREFIX_DST_PRESENT)) {
676 if (BGP_DEBUG(pbr, PBR)) {
677 bgp_pbr_print_policy_route(api);
678 zlog_debug("BGP: match actions without src"
679 " or dst address can not operate."
680 " ignoring.");
681 }
682 return 0;
683 }
684 return 1;
685 }
686
687 /* return -1 if build or validation failed */
688 int bgp_pbr_build_and_validate_entry(struct prefix *p,
689 struct bgp_path_info *path,
690 struct bgp_pbr_entry_main *api)
691 {
692 int ret;
693 int i, action_count = 0;
694 struct ecommunity *ecom;
695 struct ecommunity_val *ecom_eval;
696 struct bgp_pbr_entry_action *api_action;
697 struct prefix *src = NULL, *dst = NULL;
698 int valid_prefix = 0;
699 afi_t afi = AFI_IP;
700 struct bgp_pbr_entry_action *api_action_redirect_ip = NULL;
701 bool discard_action_found = false;
702
703 /* extract match from flowspec entries */
704 ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr,
705 p->u.prefix_flowspec.prefixlen, api);
706 if (ret < 0)
707 return -1;
708 /* extract actiosn from flowspec ecom list */
709 if (path && path->attr->ecommunity) {
710 ecom = path->attr->ecommunity;
711 for (i = 0; i < ecom->size; i++) {
712 ecom_eval = (struct ecommunity_val *)
713 (ecom->val + (i * ECOMMUNITY_SIZE));
714 action_count++;
715 if (action_count > ACTIONS_MAX_NUM) {
716 if (BGP_DEBUG(pbr, PBR_ERROR))
717 flog_err(
718 EC_BGP_FLOWSPEC_PACKET,
719 "%s: flowspec actions exceeds limit (max %u)",
720 __func__, action_count);
721 break;
722 }
723 api_action = &api->actions[action_count - 1];
724
725 if ((ecom_eval->val[1] ==
726 (char)ECOMMUNITY_REDIRECT_VRF) &&
727 (ecom_eval->val[0] ==
728 (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
729 ecom_eval->val[0] ==
730 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
731 ecom_eval->val[0] ==
732 (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
733 struct ecommunity *eckey = ecommunity_new();
734 struct ecommunity_val ecom_copy;
735
736 memcpy(&ecom_copy, ecom_eval,
737 sizeof(struct ecommunity_val));
738 ecom_copy.val[0] &=
739 ~ECOMMUNITY_ENCODE_TRANS_EXP;
740 ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
741 ecommunity_add_val(eckey, &ecom_copy);
742
743 api_action->action = ACTION_REDIRECT;
744 api_action->u.redirect_vrf =
745 get_first_vrf_for_redirect_with_rt(
746 eckey);
747 ecommunity_free(&eckey);
748 } else if ((ecom_eval->val[0] ==
749 (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
750 (ecom_eval->val[1] ==
751 (char)ECOMMUNITY_REDIRECT_IP_NH)) {
752 /* in case the 2 ecom present,
753 * do not overwrite
754 * draft-ietf-idr-flowspec-redirect
755 */
756 if (api_action_redirect_ip) {
757 if (api_action_redirect_ip->u.zr
758 .redirect_ip_v4.s_addr
759 != INADDR_ANY)
760 continue;
761 if (path->attr->nexthop.s_addr
762 == INADDR_ANY)
763 continue;
764 api_action_redirect_ip->u.zr
765 .redirect_ip_v4.s_addr =
766 path->attr->nexthop.s_addr;
767 api_action_redirect_ip->u.zr.duplicate
768 = ecom_eval->val[7];
769 continue;
770 } else {
771 api_action->action = ACTION_REDIRECT_IP;
772 api_action->u.zr.redirect_ip_v4.s_addr =
773 path->attr->nexthop.s_addr;
774 api_action->u.zr.duplicate =
775 ecom_eval->val[7];
776 api_action_redirect_ip = api_action;
777 }
778 } else if ((ecom_eval->val[0] ==
779 (char)ECOMMUNITY_ENCODE_IP) &&
780 (ecom_eval->val[1] ==
781 (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
782 /* in case the 2 ecom present,
783 * overwrite simpson draft
784 * update redirect ip fields
785 */
786 if (api_action_redirect_ip) {
787 memcpy(&(api_action_redirect_ip->u
788 .zr.redirect_ip_v4.s_addr),
789 (ecom_eval->val+2), 4);
790 api_action_redirect_ip->u
791 .zr.duplicate =
792 ecom_eval->val[7];
793 continue;
794 } else {
795 api_action->action = ACTION_REDIRECT_IP;
796 memcpy(&(api_action->u
797 .zr.redirect_ip_v4.s_addr),
798 (ecom_eval->val+2), 4);
799 api_action->u.zr.duplicate =
800 ecom_eval->val[7];
801 api_action_redirect_ip = api_action;
802 }
803 } else {
804 if (ecom_eval->val[0] !=
805 (char)ECOMMUNITY_ENCODE_TRANS_EXP)
806 continue;
807 ret = ecommunity_fill_pbr_action(ecom_eval,
808 api_action);
809 if (ret != 0)
810 continue;
811 if ((api_action->action == ACTION_TRAFFICRATE) &&
812 api->actions[i].u.r.rate == 0)
813 discard_action_found = true;
814 }
815 api->action_num++;
816 }
817 }
818 /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
819 * then reduce the API action list to that action
820 */
821 if (api->action_num > 1 && discard_action_found) {
822 api->action_num = 1;
823 memset(&api->actions[0], 0,
824 sizeof(struct bgp_pbr_entry_action));
825 api->actions[0].action = ACTION_TRAFFICRATE;
826 }
827
828 /* validate if incoming matc/action is compatible
829 * with our policy routing engine
830 */
831 if (!bgp_pbr_validate_policy_route(api))
832 return -1;
833
834 /* check inconsistency in the match rule */
835 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
836 src = &api->src_prefix;
837 afi = family2afi(src->family);
838 valid_prefix = 1;
839 }
840 if (api->match_bitmask & PREFIX_DST_PRESENT) {
841 dst = &api->dst_prefix;
842 if (valid_prefix && afi != family2afi(dst->family)) {
843 if (BGP_DEBUG(pbr, PBR)) {
844 bgp_pbr_print_policy_route(api);
845 zlog_debug("%s: inconsistency:"
846 " no match for afi src and dst (%u/%u)",
847 __func__, afi, family2afi(dst->family));
848 }
849 return -1;
850 }
851 }
852 return 0;
853 }
854
855 static void bgp_pbr_match_entry_free(void *arg)
856 {
857 struct bgp_pbr_match_entry *bpme;
858
859 bpme = (struct bgp_pbr_match_entry *)arg;
860
861 if (bpme->installed) {
862 bgp_send_pbr_ipset_entry_match(bpme, false);
863 bpme->installed = false;
864 bpme->backpointer = NULL;
865 }
866 XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
867 }
868
869 static void bgp_pbr_match_free(void *arg)
870 {
871 struct bgp_pbr_match *bpm;
872
873 bpm = (struct bgp_pbr_match *)arg;
874
875 hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
876
877 if (hashcount(bpm->entry_hash) == 0) {
878 /* delete iptable entry first */
879 /* then delete ipset match */
880 if (bpm->installed) {
881 if (bpm->installed_in_iptable) {
882 bgp_send_pbr_iptable(bpm->action,
883 bpm, false);
884 bpm->installed_in_iptable = false;
885 bpm->action->refcnt--;
886 }
887 bgp_send_pbr_ipset_match(bpm, false);
888 bpm->installed = false;
889 bpm->action = NULL;
890 }
891 }
892 hash_free(bpm->entry_hash);
893
894 XFREE(MTYPE_PBR_MATCH, bpm);
895 }
896
897 static void *bgp_pbr_match_alloc_intern(void *arg)
898 {
899 struct bgp_pbr_match *bpm, *new;
900
901 bpm = (struct bgp_pbr_match *)arg;
902
903 new = XCALLOC(MTYPE_PBR_MATCH, sizeof(*new));
904 memcpy(new, bpm, sizeof(*bpm));
905
906 return new;
907 }
908
909 static void bgp_pbr_rule_free(void *arg)
910 {
911 struct bgp_pbr_rule *bpr;
912
913 bpr = (struct bgp_pbr_rule *)arg;
914
915 /* delete iprule */
916 if (bpr->installed) {
917 bgp_send_pbr_rule_action(bpr->action, bpr, false);
918 bpr->installed = false;
919 bpr->action->refcnt--;
920 bpr->action = NULL;
921 }
922 XFREE(MTYPE_PBR_RULE, bpr);
923 }
924
925 static void *bgp_pbr_rule_alloc_intern(void *arg)
926 {
927 struct bgp_pbr_rule *bpr, *new;
928
929 bpr = (struct bgp_pbr_rule *)arg;
930
931 new = XCALLOC(MTYPE_PBR_RULE, sizeof(*new));
932 memcpy(new, bpr, sizeof(*bpr));
933
934 return new;
935 }
936
937 static void bgp_pbr_action_free(void *arg)
938 {
939 struct bgp_pbr_action *bpa;
940
941 bpa = (struct bgp_pbr_action *)arg;
942
943 if (bpa->refcnt == 0) {
944 if (bpa->installed && bpa->table_id != 0) {
945 bgp_send_pbr_rule_action(bpa, NULL, false);
946 bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
947 AFI_IP,
948 bpa->table_id,
949 false);
950 bpa->installed = false;
951 }
952 }
953 XFREE(MTYPE_PBR_ACTION, bpa);
954 }
955
956 static void *bgp_pbr_action_alloc_intern(void *arg)
957 {
958 struct bgp_pbr_action *bpa, *new;
959
960 bpa = (struct bgp_pbr_action *)arg;
961
962 new = XCALLOC(MTYPE_PBR_ACTION, sizeof(*new));
963
964 memcpy(new, bpa, sizeof(*bpa));
965
966 return new;
967 }
968
969 static void *bgp_pbr_match_entry_alloc_intern(void *arg)
970 {
971 struct bgp_pbr_match_entry *bpme, *new;
972
973 bpme = (struct bgp_pbr_match_entry *)arg;
974
975 new = XCALLOC(MTYPE_PBR_MATCH_ENTRY, sizeof(*new));
976
977 memcpy(new, bpme, sizeof(*bpme));
978
979 return new;
980 }
981
982 uint32_t bgp_pbr_match_hash_key(const void *arg)
983 {
984 const struct bgp_pbr_match *pbm = arg;
985 uint32_t key;
986
987 key = jhash_1word(pbm->vrf_id, 0x4312abde);
988 key = jhash_1word(pbm->flags, key);
989 key = jhash(&pbm->pkt_len_min, 2, key);
990 key = jhash(&pbm->pkt_len_max, 2, key);
991 key = jhash(&pbm->tcp_flags, 2, key);
992 key = jhash(&pbm->tcp_mask_flags, 2, key);
993 key = jhash(&pbm->dscp_value, 1, key);
994 key = jhash(&pbm->fragment, 1, key);
995 key = jhash(&pbm->protocol, 1, key);
996 return jhash_1word(pbm->type, key);
997 }
998
999 bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
1000 {
1001 const struct bgp_pbr_match *r1, *r2;
1002
1003 r1 = (const struct bgp_pbr_match *)arg1;
1004 r2 = (const struct bgp_pbr_match *)arg2;
1005
1006 if (r1->vrf_id != r2->vrf_id)
1007 return false;
1008
1009 if (r1->type != r2->type)
1010 return false;
1011
1012 if (r1->flags != r2->flags)
1013 return false;
1014
1015 if (r1->action != r2->action)
1016 return false;
1017
1018 if (r1->pkt_len_min != r2->pkt_len_min)
1019 return false;
1020
1021 if (r1->pkt_len_max != r2->pkt_len_max)
1022 return false;
1023
1024 if (r1->tcp_flags != r2->tcp_flags)
1025 return false;
1026
1027 if (r1->tcp_mask_flags != r2->tcp_mask_flags)
1028 return false;
1029
1030 if (r1->dscp_value != r2->dscp_value)
1031 return false;
1032
1033 if (r1->fragment != r2->fragment)
1034 return false;
1035
1036 if (r1->protocol != r2->protocol)
1037 return false;
1038 return true;
1039 }
1040
1041 uint32_t bgp_pbr_rule_hash_key(const void *arg)
1042 {
1043 const struct bgp_pbr_rule *pbr = arg;
1044 uint32_t key;
1045
1046 key = prefix_hash_key(&pbr->src);
1047 key = jhash_1word(pbr->vrf_id, key);
1048 key = jhash_1word(pbr->flags, key);
1049 return jhash_1word(prefix_hash_key(&pbr->dst), key);
1050 }
1051
1052 bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
1053 {
1054 const struct bgp_pbr_rule *r1, *r2;
1055
1056 r1 = (const struct bgp_pbr_rule *)arg1;
1057 r2 = (const struct bgp_pbr_rule *)arg2;
1058
1059 if (r1->vrf_id != r2->vrf_id)
1060 return false;
1061
1062 if (r1->flags != r2->flags)
1063 return false;
1064
1065 if (r1->action != r2->action)
1066 return false;
1067
1068 if ((r1->flags & MATCH_IP_SRC_SET) &&
1069 !prefix_same(&r1->src, &r2->src))
1070 return false;
1071
1072 if ((r1->flags & MATCH_IP_DST_SET) &&
1073 !prefix_same(&r1->dst, &r2->dst))
1074 return false;
1075
1076 return true;
1077 }
1078
1079 uint32_t bgp_pbr_match_entry_hash_key(const void *arg)
1080 {
1081 const struct bgp_pbr_match_entry *pbme;
1082 uint32_t key;
1083
1084 pbme = arg;
1085 key = prefix_hash_key(&pbme->src);
1086 key = jhash_1word(prefix_hash_key(&pbme->dst), key);
1087 key = jhash(&pbme->dst_port_min, 2, key);
1088 key = jhash(&pbme->src_port_min, 2, key);
1089 key = jhash(&pbme->dst_port_max, 2, key);
1090 key = jhash(&pbme->src_port_max, 2, key);
1091 key = jhash(&pbme->proto, 1, key);
1092
1093 return key;
1094 }
1095
1096 bool bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
1097 {
1098 const struct bgp_pbr_match_entry *r1, *r2;
1099
1100 r1 = (const struct bgp_pbr_match_entry *)arg1;
1101 r2 = (const struct bgp_pbr_match_entry *)arg2;
1102
1103 /*
1104 * on updates, comparing backpointer is not necessary
1105 * unique value is self calculated
1106 * rate is ignored for now
1107 */
1108
1109 if (!prefix_same(&r1->src, &r2->src))
1110 return false;
1111
1112 if (!prefix_same(&r1->dst, &r2->dst))
1113 return false;
1114
1115 if (r1->src_port_min != r2->src_port_min)
1116 return false;
1117
1118 if (r1->dst_port_min != r2->dst_port_min)
1119 return false;
1120
1121 if (r1->src_port_max != r2->src_port_max)
1122 return false;
1123
1124 if (r1->dst_port_max != r2->dst_port_max)
1125 return false;
1126
1127 if (r1->proto != r2->proto)
1128 return false;
1129
1130 return true;
1131 }
1132
1133 uint32_t bgp_pbr_action_hash_key(const void *arg)
1134 {
1135 const struct bgp_pbr_action *pbra;
1136 uint32_t key;
1137
1138 pbra = arg;
1139 key = jhash_1word(pbra->table_id, 0x4312abde);
1140 key = jhash_1word(pbra->fwmark, key);
1141 return key;
1142 }
1143
1144 bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
1145 {
1146 const struct bgp_pbr_action *r1, *r2;
1147
1148 r1 = (const struct bgp_pbr_action *)arg1;
1149 r2 = (const struct bgp_pbr_action *)arg2;
1150
1151 /* unique value is self calculated
1152 * table and fwmark is self calculated
1153 * rate is ignored
1154 */
1155 if (r1->vrf_id != r2->vrf_id)
1156 return false;
1157
1158 if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop)))
1159 return false;
1160
1161 return true;
1162 }
1163
1164 struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,
1165 uint32_t unique)
1166 {
1167 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1168 struct bgp_pbr_rule_unique bpru;
1169
1170 if (!bgp || unique == 0)
1171 return NULL;
1172 bpru.unique = unique;
1173 bpru.bpr_found = NULL;
1174 hash_walk(bgp->pbr_rule_hash, bgp_pbr_rule_walkcb, &bpru);
1175 return bpru.bpr_found;
1176 }
1177
1178 struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
1179 uint32_t unique)
1180 {
1181 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1182 struct bgp_pbr_action_unique bpau;
1183
1184 if (!bgp || unique == 0)
1185 return NULL;
1186 bpau.unique = unique;
1187 bpau.bpa_found = NULL;
1188 hash_walk(bgp->pbr_action_hash, bgp_pbr_action_walkcb, &bpau);
1189 return bpau.bpa_found;
1190 }
1191
1192 struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
1193 uint32_t unique)
1194 {
1195 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1196 struct bgp_pbr_match_unique bpmu;
1197
1198 if (!bgp || unique == 0)
1199 return NULL;
1200 bpmu.unique = unique;
1201 bpmu.bpm_found = NULL;
1202 hash_walk(bgp->pbr_match_hash, bgp_pbr_match_walkcb, &bpmu);
1203 return bpmu.bpm_found;
1204 }
1205
1206 struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id,
1207 char *ipset_name,
1208 uint32_t unique)
1209 {
1210 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1211 struct bgp_pbr_match_entry_unique bpmeu;
1212 struct bgp_pbr_match_ipsetname bpmi;
1213
1214 if (!bgp || unique == 0)
1215 return NULL;
1216 bpmi.ipsetname = XCALLOC(MTYPE_TMP, ZEBRA_IPSET_NAME_SIZE);
1217 snprintf(bpmi.ipsetname, ZEBRA_IPSET_NAME_SIZE, "%s", ipset_name);
1218 bpmi.bpm_found = NULL;
1219 hash_walk(bgp->pbr_match_hash, bgp_pbr_match_pername_walkcb, &bpmi);
1220 XFREE(MTYPE_TMP, bpmi.ipsetname);
1221 if (!bpmi.bpm_found)
1222 return NULL;
1223 bpmeu.bpme_found = NULL;
1224 bpmeu.unique = unique;
1225 hash_walk(bpmi.bpm_found->entry_hash,
1226 bgp_pbr_match_entry_walkcb, &bpmeu);
1227 return bpmeu.bpme_found;
1228 }
1229
1230 struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
1231 uint32_t unique)
1232 {
1233 struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
1234 struct bgp_pbr_match_iptable_unique bpmiu;
1235
1236 if (!bgp || unique == 0)
1237 return NULL;
1238 bpmiu.unique = unique;
1239 bpmiu.bpm_found = NULL;
1240 hash_walk(bgp->pbr_match_hash, bgp_pbr_match_iptable_walkcb, &bpmiu);
1241 return bpmiu.bpm_found;
1242 }
1243
1244 void bgp_pbr_cleanup(struct bgp *bgp)
1245 {
1246 if (bgp->pbr_match_hash) {
1247 hash_clean(bgp->pbr_match_hash, bgp_pbr_match_free);
1248 hash_free(bgp->pbr_match_hash);
1249 bgp->pbr_match_hash = NULL;
1250 }
1251 if (bgp->pbr_rule_hash) {
1252 hash_clean(bgp->pbr_rule_hash, bgp_pbr_rule_free);
1253 hash_free(bgp->pbr_rule_hash);
1254 bgp->pbr_rule_hash = NULL;
1255 }
1256 if (bgp->pbr_action_hash) {
1257 hash_clean(bgp->pbr_action_hash, bgp_pbr_action_free);
1258 hash_free(bgp->pbr_action_hash);
1259 bgp->pbr_action_hash = NULL;
1260 }
1261 if (bgp->bgp_pbr_cfg == NULL)
1262 return;
1263 bgp_pbr_reset(bgp, AFI_IP);
1264 XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
1265 }
1266
1267 void bgp_pbr_init(struct bgp *bgp)
1268 {
1269 bgp->pbr_match_hash =
1270 hash_create_size(8, bgp_pbr_match_hash_key,
1271 bgp_pbr_match_hash_equal,
1272 "Match Hash");
1273 bgp->pbr_action_hash =
1274 hash_create_size(8, bgp_pbr_action_hash_key,
1275 bgp_pbr_action_hash_equal,
1276 "Match Hash Entry");
1277
1278 bgp->pbr_rule_hash =
1279 hash_create_size(8, bgp_pbr_rule_hash_key,
1280 bgp_pbr_rule_hash_equal,
1281 "Match Rule");
1282
1283 bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
1284 bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
1285 }
1286
1287 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
1288 {
1289 int i = 0;
1290 char return_string[512];
1291 char *ptr = return_string;
1292 char buff[64];
1293 int nb_items = 0;
1294
1295 ptr += sprintf(ptr, "MATCH : ");
1296 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
1297 struct prefix *p = &(api->src_prefix);
1298
1299 ptr += sprintf(ptr, "@src %s", prefix2str(p, buff, 64));
1300 INCREMENT_DISPLAY(ptr, nb_items);
1301 }
1302 if (api->match_bitmask & PREFIX_DST_PRESENT) {
1303 struct prefix *p = &(api->dst_prefix);
1304
1305 INCREMENT_DISPLAY(ptr, nb_items);
1306 ptr += sprintf(ptr, "@dst %s", prefix2str(p, buff, 64));
1307 }
1308
1309 if (api->match_protocol_num)
1310 INCREMENT_DISPLAY(ptr, nb_items);
1311 for (i = 0; i < api->match_protocol_num; i++)
1312 ptr += sprintf_bgp_pbr_match_val(ptr, &api->protocol[i],
1313 i > 0 ? NULL : "@proto ");
1314
1315 if (api->match_src_port_num)
1316 INCREMENT_DISPLAY(ptr, nb_items);
1317 for (i = 0; i < api->match_src_port_num; i++)
1318 ptr += sprintf_bgp_pbr_match_val(ptr, &api->src_port[i],
1319 i > 0 ? NULL : "@srcport ");
1320
1321 if (api->match_dst_port_num)
1322 INCREMENT_DISPLAY(ptr, nb_items);
1323 for (i = 0; i < api->match_dst_port_num; i++)
1324 ptr += sprintf_bgp_pbr_match_val(ptr, &api->dst_port[i],
1325 i > 0 ? NULL : "@dstport ");
1326
1327 if (api->match_port_num)
1328 INCREMENT_DISPLAY(ptr, nb_items);
1329 for (i = 0; i < api->match_port_num; i++)
1330 ptr += sprintf_bgp_pbr_match_val(ptr, &api->port[i],
1331 i > 0 ? NULL : "@port ");
1332
1333 if (api->match_icmp_type_num)
1334 INCREMENT_DISPLAY(ptr, nb_items);
1335 for (i = 0; i < api->match_icmp_type_num; i++)
1336 ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_type[i],
1337 i > 0 ? NULL : "@icmptype ");
1338
1339 if (api->match_icmp_code_num)
1340 INCREMENT_DISPLAY(ptr, nb_items);
1341 for (i = 0; i < api->match_icmp_code_num; i++)
1342 ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_code[i],
1343 i > 0 ? NULL : "@icmpcode ");
1344
1345 if (api->match_packet_length_num)
1346 INCREMENT_DISPLAY(ptr, nb_items);
1347 for (i = 0; i < api->match_packet_length_num; i++)
1348 ptr += sprintf_bgp_pbr_match_val(ptr, &api->packet_length[i],
1349 i > 0 ? NULL : "@plen ");
1350
1351 if (api->match_dscp_num)
1352 INCREMENT_DISPLAY(ptr, nb_items);
1353 for (i = 0; i < api->match_dscp_num; i++)
1354 ptr += sprintf_bgp_pbr_match_val(ptr, &api->dscp[i],
1355 i > 0 ? NULL : "@dscp ");
1356
1357 if (api->match_tcpflags_num)
1358 INCREMENT_DISPLAY(ptr, nb_items);
1359 for (i = 0; i < api->match_tcpflags_num; i++)
1360 ptr += sprintf_bgp_pbr_match_val(ptr, &api->tcpflags[i],
1361 i > 0 ? NULL : "@tcpflags ");
1362
1363 if (api->match_fragment_num)
1364 INCREMENT_DISPLAY(ptr, nb_items);
1365 for (i = 0; i < api->match_fragment_num; i++)
1366 ptr += sprintf_bgp_pbr_match_val(ptr, &api->fragment[i],
1367 i > 0 ? NULL : "@fragment ");
1368 if (!nb_items)
1369 ptr = return_string;
1370 else
1371 ptr += sprintf(ptr, "; ");
1372 if (api->action_num)
1373 ptr += sprintf(ptr, "SET : ");
1374 nb_items = 0;
1375 for (i = 0; i < api->action_num; i++) {
1376 switch (api->actions[i].action) {
1377 case ACTION_TRAFFICRATE:
1378 INCREMENT_DISPLAY(ptr, nb_items);
1379 ptr += sprintf(ptr, "@set rate %f",
1380 api->actions[i].u.r.rate);
1381 break;
1382 case ACTION_TRAFFIC_ACTION:
1383 INCREMENT_DISPLAY(ptr, nb_items);
1384 ptr += sprintf(ptr, "@action ");
1385 if (api->actions[i].u.za.filter
1386 & TRAFFIC_ACTION_TERMINATE)
1387 ptr += sprintf(ptr,
1388 " terminate (apply filter(s))");
1389 if (api->actions[i].u.za.filter
1390 & TRAFFIC_ACTION_DISTRIBUTE)
1391 ptr += sprintf(ptr, " distribute");
1392 if (api->actions[i].u.za.filter
1393 & TRAFFIC_ACTION_SAMPLE)
1394 ptr += sprintf(ptr, " sample");
1395 break;
1396 case ACTION_REDIRECT_IP:
1397 INCREMENT_DISPLAY(ptr, nb_items);
1398 char local_buff[INET_ADDRSTRLEN];
1399
1400 if (inet_ntop(AF_INET,
1401 &api->actions[i].u.zr.redirect_ip_v4,
1402 local_buff, INET_ADDRSTRLEN) != NULL)
1403 ptr += sprintf(ptr,
1404 "@redirect ip nh %s", local_buff);
1405 break;
1406 case ACTION_REDIRECT:
1407 INCREMENT_DISPLAY(ptr, nb_items);
1408 ptr += sprintf(ptr, "@redirect vrf %u",
1409 api->actions[i].u.redirect_vrf);
1410 break;
1411 case ACTION_MARKING:
1412 INCREMENT_DISPLAY(ptr, nb_items);
1413 ptr += sprintf(ptr, "@set dscp %u",
1414 api->actions[i].u.marking_dscp);
1415 break;
1416 default:
1417 break;
1418 }
1419 }
1420 zlog_info("%s", return_string);
1421 }
1422
1423 static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa,
1424 struct bgp_pbr_rule *bpr)
1425 {
1426 /* if bpr is null, do nothing
1427 */
1428 if (bpr == NULL)
1429 return;
1430 if (bpr->installed) {
1431 bgp_send_pbr_rule_action(bpa, bpr, false);
1432 bpr->installed = false;
1433 bpr->action->refcnt--;
1434 bpr->action = NULL;
1435 if (bpr->path) {
1436 struct bgp_path_info *path;
1437 struct bgp_path_info_extra *extra;
1438
1439 /* unlink path to bpme */
1440 path = (struct bgp_path_info *)bpr->path;
1441 extra = bgp_path_info_extra_get(path);
1442 if (extra->bgp_fs_iprule)
1443 listnode_delete(extra->bgp_fs_iprule, bpr);
1444 bpr->path = NULL;
1445 }
1446 }
1447 hash_release(bgp->pbr_rule_hash, bpr);
1448 if (bpa->refcnt == 0) {
1449 if (bpa->installed && bpa->table_id != 0) {
1450 bgp_send_pbr_rule_action(bpa, NULL, false);
1451 bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
1452 AFI_IP,
1453 bpa->table_id,
1454 false);
1455 bpa->installed = false;
1456 }
1457 }
1458 }
1459
1460 static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
1461 struct bgp_pbr_match *bpm,
1462 struct bgp_pbr_match_entry *bpme)
1463 {
1464 /* if bpme is null, bpm is also null
1465 */
1466 if (bpme == NULL)
1467 return;
1468 /* ipset del entry */
1469 if (bpme->installed) {
1470 bgp_send_pbr_ipset_entry_match(bpme, false);
1471 bpme->installed = false;
1472 bpme->backpointer = NULL;
1473 if (bpme->path) {
1474 struct bgp_path_info *path;
1475 struct bgp_path_info_extra *extra;
1476
1477 /* unlink path to bpme */
1478 path = (struct bgp_path_info *)bpme->path;
1479 extra = bgp_path_info_extra_get(path);
1480 if (extra->bgp_fs_pbr)
1481 listnode_delete(extra->bgp_fs_pbr, bpme);
1482 bpme->path = NULL;
1483 }
1484 }
1485 hash_release(bpm->entry_hash, bpme);
1486 if (hashcount(bpm->entry_hash) == 0) {
1487 /* delete iptable entry first */
1488 /* then delete ipset match */
1489 if (bpm->installed) {
1490 if (bpm->installed_in_iptable) {
1491 bgp_send_pbr_iptable(bpm->action,
1492 bpm, false);
1493 bpm->installed_in_iptable = false;
1494 bpm->action->refcnt--;
1495 }
1496 bgp_send_pbr_ipset_match(bpm, false);
1497 bpm->installed = false;
1498 bpm->action = NULL;
1499 }
1500 hash_release(bgp->pbr_match_hash, bpm);
1501 /* XXX release pbr_match_action if not used
1502 * note that drop does not need to call send_pbr_action
1503 */
1504 }
1505 if (bpa->refcnt == 0) {
1506 if (bpa->installed && bpa->table_id != 0) {
1507 bgp_send_pbr_rule_action(bpa, NULL, false);
1508 bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
1509 AFI_IP,
1510 bpa->table_id,
1511 false);
1512 bpa->installed = false;
1513 }
1514 }
1515 }
1516
1517 struct bgp_pbr_match_entry_remain {
1518 struct bgp_pbr_match_entry *bpme_to_match;
1519 struct bgp_pbr_match_entry *bpme_found;
1520 };
1521
1522 struct bgp_pbr_rule_remain {
1523 struct bgp_pbr_rule *bpr_to_match;
1524 struct bgp_pbr_rule *bpr_found;
1525 };
1526
1527 static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
1528 {
1529 struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data;
1530 struct bgp_pbr_rule_remain *ctxt =
1531 (struct bgp_pbr_rule_remain *)arg;
1532 struct bgp_pbr_rule *r2;
1533
1534 r2 = ctxt->bpr_to_match;
1535
1536 if (r1->vrf_id != r2->vrf_id)
1537 return HASHWALK_CONTINUE;
1538
1539 if (r1->flags != r2->flags)
1540 return HASHWALK_CONTINUE;
1541
1542 if ((r1->flags & MATCH_IP_SRC_SET) &&
1543 !prefix_same(&r1->src, &r2->src))
1544 return HASHWALK_CONTINUE;
1545
1546 if ((r1->flags & MATCH_IP_DST_SET) &&
1547 !prefix_same(&r1->dst, &r2->dst))
1548 return HASHWALK_CONTINUE;
1549
1550 /* this function is used for two cases:
1551 * - remove an entry upon withdraw request
1552 * (case r2->action is null)
1553 * - replace an old iprule with different action
1554 * (case r2->action is != null)
1555 * the old one is removed after the new one
1556 * this is to avoid disruption in traffic
1557 */
1558 if (r2->action == NULL ||
1559 r1->action != r2->action) {
1560 ctxt->bpr_found = r1;
1561 return HASHWALK_ABORT;
1562 }
1563 return HASHWALK_CONTINUE;
1564 }
1565
1566 static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg)
1567 {
1568 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
1569 struct bgp_pbr_match_entry_remain *bpmer =
1570 (struct bgp_pbr_match_entry_remain *)arg;
1571 struct bgp_pbr_match *bpm_temp;
1572 struct bgp_pbr_match_entry *bpme = bpmer->bpme_to_match;
1573
1574 if (!bpme->backpointer ||
1575 bpm == bpme->backpointer ||
1576 bpme->backpointer->action == bpm->action)
1577 return HASHWALK_CONTINUE;
1578 /* ensure bpm other characteristics are equal */
1579 bpm_temp = bpme->backpointer;
1580 if (bpm_temp->vrf_id != bpm->vrf_id ||
1581 bpm_temp->type != bpm->type ||
1582 bpm_temp->flags != bpm->flags ||
1583 bpm_temp->tcp_flags != bpm->tcp_flags ||
1584 bpm_temp->tcp_mask_flags != bpm->tcp_mask_flags ||
1585 bpm_temp->pkt_len_min != bpm->pkt_len_min ||
1586 bpm_temp->pkt_len_max != bpm->pkt_len_max ||
1587 bpm_temp->dscp_value != bpm->dscp_value ||
1588 bpm_temp->fragment != bpm->fragment)
1589 return HASHWALK_CONTINUE;
1590
1591 /* look for remaining bpme */
1592 bpmer->bpme_found = hash_lookup(bpm->entry_hash, bpme);
1593 if (!bpmer->bpme_found)
1594 return HASHWALK_CONTINUE;
1595 return HASHWALK_ABORT;
1596 }
1597
1598 static void bgp_pbr_policyroute_remove_from_zebra_unit(
1599 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf)
1600 {
1601 struct bgp_pbr_match temp;
1602 struct bgp_pbr_match_entry temp2;
1603 struct bgp_pbr_rule pbr_rule;
1604 struct bgp_pbr_rule *bpr;
1605 struct bgp_pbr_match *bpm;
1606 struct bgp_pbr_match_entry *bpme;
1607 struct bgp_pbr_match_entry_remain bpmer;
1608 struct bgp_pbr_range_port *src_port;
1609 struct bgp_pbr_range_port *dst_port;
1610 struct bgp_pbr_range_port *pkt_len;
1611 struct bgp_pbr_rule_remain bprr;
1612
1613 if (!bpf)
1614 return;
1615 src_port = bpf->src_port;
1616 dst_port = bpf->dst_port;
1617 pkt_len = bpf->pkt_len;
1618
1619 if (BGP_DEBUG(zebra, ZEBRA))
1620 bgp_pbr_dump_entry(bpf, false);
1621
1622 /* as we don't know information from EC
1623 * look for bpm that have the bpm
1624 * with vrf_id characteristics
1625 */
1626 memset(&temp2, 0, sizeof(temp2));
1627 memset(&temp, 0, sizeof(temp));
1628
1629 if (bpf->type == BGP_PBR_IPRULE) {
1630 memset(&pbr_rule, 0, sizeof(pbr_rule));
1631 pbr_rule.vrf_id = bpf->vrf_id;
1632 if (bpf->src) {
1633 prefix_copy(&pbr_rule.src, bpf->src);
1634 pbr_rule.flags |= MATCH_IP_SRC_SET;
1635 }
1636 if (bpf->dst) {
1637 prefix_copy(&pbr_rule.dst, bpf->dst);
1638 pbr_rule.flags |= MATCH_IP_DST_SET;
1639 }
1640 bpr = &pbr_rule;
1641 /* A previous entry may already exist
1642 * flush previous entry if necessary
1643 */
1644 bprr.bpr_to_match = bpr;
1645 bprr.bpr_found = NULL;
1646 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
1647 if (bprr.bpr_found) {
1648 static struct bgp_pbr_rule *local_bpr;
1649 static struct bgp_pbr_action *local_bpa;
1650
1651 local_bpr = bprr.bpr_found;
1652 local_bpa = local_bpr->action;
1653 bgp_pbr_flush_iprule(bgp, local_bpa,
1654 local_bpr);
1655 }
1656 return;
1657 }
1658
1659 if (bpf->src) {
1660 temp.flags |= MATCH_IP_SRC_SET;
1661 prefix_copy(&temp2.src, bpf->src);
1662 } else
1663 temp2.src.family = AF_INET;
1664 if (bpf->dst) {
1665 temp.flags |= MATCH_IP_DST_SET;
1666 prefix_copy(&temp2.dst, bpf->dst);
1667 } else
1668 temp2.dst.family = AF_INET;
1669 if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
1670 if (bpf->protocol == IPPROTO_ICMP)
1671 temp.flags |= MATCH_ICMP_SET;
1672 temp.flags |= MATCH_PORT_SRC_SET;
1673 temp2.src_port_min = src_port->min_port;
1674 if (src_port->max_port) {
1675 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1676 temp2.src_port_max = src_port->max_port;
1677 }
1678 }
1679 if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
1680 if (bpf->protocol == IPPROTO_ICMP)
1681 temp.flags |= MATCH_ICMP_SET;
1682 temp.flags |= MATCH_PORT_DST_SET;
1683 temp2.dst_port_min = dst_port->min_port;
1684 if (dst_port->max_port) {
1685 temp.flags |= MATCH_PORT_DST_RANGE_SET;
1686 temp2.dst_port_max = dst_port->max_port;
1687 }
1688 }
1689 temp2.proto = bpf->protocol;
1690
1691 if (pkt_len) {
1692 temp.pkt_len_min = pkt_len->min_port;
1693 if (pkt_len->max_port)
1694 temp.pkt_len_max = pkt_len->max_port;
1695 } else if (bpf->pkt_len_val) {
1696 if (bpf->pkt_len_val->mask)
1697 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
1698 temp.pkt_len_min = bpf->pkt_len_val->val;
1699 }
1700 if (bpf->tcp_flags) {
1701 temp.tcp_flags = bpf->tcp_flags->val;
1702 temp.tcp_mask_flags = bpf->tcp_flags->mask;
1703 }
1704 if (bpf->dscp) {
1705 if (bpf->dscp->mask)
1706 temp.flags |= MATCH_DSCP_INVERSE_SET;
1707 else
1708 temp.flags |= MATCH_DSCP_SET;
1709 temp.dscp_value = bpf->dscp->val;
1710 }
1711 if (bpf->fragment) {
1712 if (bpf->fragment->mask)
1713 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
1714 temp.fragment = bpf->fragment->val;
1715 }
1716
1717 if (bpf->src == NULL || bpf->dst == NULL) {
1718 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1719 temp.type = IPSET_NET_PORT;
1720 else
1721 temp.type = IPSET_NET;
1722 } else {
1723 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1724 temp.type = IPSET_NET_PORT_NET;
1725 else
1726 temp.type = IPSET_NET_NET;
1727 }
1728 if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
1729 temp.vrf_id = VRF_DEFAULT;
1730 else
1731 temp.vrf_id = bpf->vrf_id;
1732 bpme = &temp2;
1733 bpm = &temp;
1734 bpme->backpointer = bpm;
1735 /* right now, a previous entry may already exist
1736 * flush previous entry if necessary
1737 */
1738 bpmer.bpme_to_match = bpme;
1739 bpmer.bpme_found = NULL;
1740 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1741 if (bpmer.bpme_found) {
1742 static struct bgp_pbr_match *local_bpm;
1743 static struct bgp_pbr_action *local_bpa;
1744
1745 local_bpm = bpmer.bpme_found->backpointer;
1746 local_bpa = local_bpm->action;
1747 bgp_pbr_flush_entry(bgp, local_bpa,
1748 local_bpm, bpmer.bpme_found);
1749 }
1750 }
1751
1752 static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
1753 {
1754 if (type_entry == FLOWSPEC_TCP_FLAGS)
1755 return FLOWSPEC_DSCP;
1756 if (type_entry == FLOWSPEC_DSCP)
1757 return FLOWSPEC_PKT_LEN;
1758 if (type_entry == FLOWSPEC_PKT_LEN)
1759 return FLOWSPEC_FRAGMENT;
1760 if (type_entry == FLOWSPEC_FRAGMENT)
1761 return FLOWSPEC_ICMP_TYPE;
1762 return 0;
1763 }
1764
1765 static void bgp_pbr_icmp_action(struct bgp *bgp, struct bgp_path_info *path,
1766 struct bgp_pbr_filter *bpf,
1767 struct bgp_pbr_or_filter *bpof, bool add,
1768 struct nexthop *nh, float *rate)
1769 {
1770 struct bgp_pbr_range_port srcp, dstp;
1771 struct bgp_pbr_val_mask *icmp_type, *icmp_code;
1772 struct listnode *tnode, *cnode;
1773
1774 if (!bpf)
1775 return;
1776 if (bpf->protocol != IPPROTO_ICMP)
1777 return;
1778 bpf->src_port = &srcp;
1779 bpf->dst_port = &dstp;
1780 /* parse icmp type and lookup appropriate icmp code
1781 * if no icmp code found, create as many entryes as
1782 * there are listed icmp codes for that icmp type
1783 */
1784 if (!bpof->icmp_type) {
1785 srcp.min_port = 0;
1786 srcp.max_port = 255;
1787 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
1788 dstp.min_port = icmp_code->val;
1789 if (add)
1790 bgp_pbr_policyroute_add_to_zebra_unit(
1791 bgp, path, bpf, nh, rate);
1792 else
1793 bgp_pbr_policyroute_remove_from_zebra_unit(
1794 bgp, path, bpf);
1795 }
1796 return;
1797 }
1798 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
1799 srcp.min_port = icmp_type->val;
1800 srcp.max_port = 0;
1801 dstp.max_port = 0;
1802 /* only icmp type. create an entry only with icmp type */
1803 if (!bpof->icmp_code) {
1804 /* icmp type is not one of the above
1805 * forge an entry only based on the icmp type
1806 */
1807 dstp.min_port = 0;
1808 dstp.max_port = 255;
1809 if (add)
1810 bgp_pbr_policyroute_add_to_zebra_unit(
1811 bgp, path, bpf, nh, rate);
1812 else
1813 bgp_pbr_policyroute_remove_from_zebra_unit(
1814 bgp, path, bpf);
1815 continue;
1816 }
1817 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
1818 dstp.min_port = icmp_code->val;
1819 if (add)
1820 bgp_pbr_policyroute_add_to_zebra_unit(
1821 bgp, path, bpf, nh, rate);
1822 else
1823 bgp_pbr_policyroute_remove_from_zebra_unit(
1824 bgp, path, bpf);
1825 }
1826 }
1827 }
1828
1829 static void bgp_pbr_policyroute_remove_from_zebra_recursive(
1830 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
1831 struct bgp_pbr_or_filter *bpof, uint8_t type_entry)
1832 {
1833 struct listnode *node, *nnode;
1834 struct bgp_pbr_val_mask *valmask;
1835 uint8_t next_type_entry;
1836 struct list *orig_list;
1837 struct bgp_pbr_val_mask **target_val;
1838
1839 if (type_entry == 0) {
1840 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
1841 return;
1842 }
1843 next_type_entry = bgp_pbr_next_type_entry(type_entry);
1844 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
1845 orig_list = bpof->tcpflags;
1846 target_val = &bpf->tcp_flags;
1847 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
1848 orig_list = bpof->dscp;
1849 target_val = &bpf->dscp;
1850 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
1851 orig_list = bpof->pkt_len;
1852 target_val = &bpf->pkt_len_val;
1853 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
1854 orig_list = bpof->fragment;
1855 target_val = &bpf->fragment;
1856 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
1857 (bpof->icmp_type || bpof->icmp_code)) {
1858 /* enumerate list for icmp - must be last one */
1859 bgp_pbr_icmp_action(bgp, path, bpf, bpof, false, NULL, NULL);
1860 return;
1861 } else {
1862 bgp_pbr_policyroute_remove_from_zebra_recursive(
1863 bgp, path, bpf, bpof, next_type_entry);
1864 return;
1865 }
1866 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
1867 *target_val = valmask;
1868 bgp_pbr_policyroute_remove_from_zebra_recursive(
1869 bgp, path, bpf, bpof, next_type_entry);
1870 }
1871 }
1872
1873 static void bgp_pbr_policyroute_remove_from_zebra(
1874 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
1875 struct bgp_pbr_or_filter *bpof)
1876 {
1877 if (!bpof) {
1878 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
1879 return;
1880 }
1881 if (bpof->tcpflags)
1882 bgp_pbr_policyroute_remove_from_zebra_recursive(
1883 bgp, path, bpf, bpof, FLOWSPEC_TCP_FLAGS);
1884 else if (bpof->dscp)
1885 bgp_pbr_policyroute_remove_from_zebra_recursive(
1886 bgp, path, bpf, bpof, FLOWSPEC_DSCP);
1887 else if (bpof->pkt_len)
1888 bgp_pbr_policyroute_remove_from_zebra_recursive(
1889 bgp, path, bpf, bpof, FLOWSPEC_PKT_LEN);
1890 else if (bpof->fragment)
1891 bgp_pbr_policyroute_remove_from_zebra_recursive(
1892 bgp, path, bpf, bpof, FLOWSPEC_FRAGMENT);
1893 else if (bpof->icmp_type || bpof->icmp_code)
1894 bgp_pbr_policyroute_remove_from_zebra_recursive(
1895 bgp, path, bpf, bpof, FLOWSPEC_ICMP_TYPE);
1896 else
1897 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
1898 /* flush bpof */
1899 if (bpof->tcpflags)
1900 list_delete_all_node(bpof->tcpflags);
1901 if (bpof->dscp)
1902 list_delete_all_node(bpof->dscp);
1903 if (bpof->pkt_len)
1904 list_delete_all_node(bpof->pkt_len);
1905 if (bpof->fragment)
1906 list_delete_all_node(bpof->fragment);
1907 }
1908
1909 static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add)
1910 {
1911 struct bgp_pbr_range_port *src_port;
1912 struct bgp_pbr_range_port *dst_port;
1913 struct bgp_pbr_range_port *pkt_len;
1914 char bufsrc[64], bufdst[64];
1915 char buffer[64];
1916 int remaining_len = 0;
1917 char protocol_str[16];
1918
1919 if (!bpf)
1920 return;
1921 src_port = bpf->src_port;
1922 dst_port = bpf->dst_port;
1923 pkt_len = bpf->pkt_len;
1924
1925 protocol_str[0] = '\0';
1926 if (bpf->tcp_flags && bpf->tcp_flags->mask)
1927 bpf->protocol = IPPROTO_TCP;
1928 if (bpf->protocol)
1929 snprintf(protocol_str, sizeof(protocol_str),
1930 "proto %d", bpf->protocol);
1931 buffer[0] = '\0';
1932 if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
1933 remaining_len += snprintf(buffer, sizeof(buffer),
1934 "type %d, code %d",
1935 src_port->min_port,
1936 dst_port->min_port);
1937 else if (bpf->protocol == IPPROTO_UDP ||
1938 bpf->protocol == IPPROTO_TCP) {
1939
1940 if (src_port && src_port->min_port)
1941 remaining_len += snprintf(buffer,
1942 sizeof(buffer),
1943 "from [%u:%u]",
1944 src_port->min_port,
1945 src_port->max_port ?
1946 src_port->max_port :
1947 src_port->min_port);
1948 if (dst_port && dst_port->min_port)
1949 remaining_len += snprintf(buffer +
1950 remaining_len,
1951 sizeof(buffer)
1952 - remaining_len,
1953 "to [%u:%u]",
1954 dst_port->min_port,
1955 dst_port->max_port ?
1956 dst_port->max_port :
1957 dst_port->min_port);
1958 }
1959 if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
1960 remaining_len += snprintf(buffer + remaining_len,
1961 sizeof(buffer)
1962 - remaining_len,
1963 " len [%u:%u]",
1964 pkt_len->min_port,
1965 pkt_len->max_port ?
1966 pkt_len->max_port :
1967 pkt_len->min_port);
1968 } else if (bpf->pkt_len_val) {
1969 remaining_len += snprintf(buffer + remaining_len,
1970 sizeof(buffer)
1971 - remaining_len,
1972 " %s len %u",
1973 bpf->pkt_len_val->mask
1974 ? "!" : "",
1975 bpf->pkt_len_val->val);
1976 }
1977 if (bpf->tcp_flags) {
1978 remaining_len += snprintf(buffer + remaining_len,
1979 sizeof(buffer)
1980 - remaining_len,
1981 "tcpflags %x/%x",
1982 bpf->tcp_flags->val,
1983 bpf->tcp_flags->mask);
1984 }
1985 if (bpf->dscp) {
1986 snprintf(buffer + remaining_len,
1987 sizeof(buffer)
1988 - remaining_len,
1989 "%s dscp %d",
1990 bpf->dscp->mask
1991 ? "!" : "",
1992 bpf->dscp->val);
1993 }
1994 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
1995 add ? "adding" : "removing",
1996 bpf->src == NULL ? "<all>" :
1997 prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
1998 bpf->dst == NULL ? "<all>" :
1999 prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
2000 protocol_str, buffer);
2001
2002 }
2003
2004 static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
2005 struct bgp_path_info *path,
2006 struct bgp_pbr_filter *bpf,
2007 struct nexthop *nh,
2008 float *rate)
2009 {
2010 struct bgp_pbr_match temp;
2011 struct bgp_pbr_match_entry temp2;
2012 struct bgp_pbr_match *bpm;
2013 struct bgp_pbr_match_entry *bpme = NULL;
2014 struct bgp_pbr_action temp3;
2015 struct bgp_pbr_action *bpa = NULL;
2016 struct bgp_pbr_match_entry_remain bpmer;
2017 struct bgp_pbr_rule_remain bprr;
2018 struct bgp_pbr_range_port *src_port;
2019 struct bgp_pbr_range_port *dst_port;
2020 struct bgp_pbr_range_port *pkt_len;
2021 struct bgp_pbr_rule pbr_rule;
2022 struct bgp_pbr_rule *bpr;
2023 bool bpr_found = false;
2024 bool bpme_found = false;
2025
2026 if (!bpf)
2027 return;
2028 src_port = bpf->src_port;
2029 dst_port = bpf->dst_port;
2030 pkt_len = bpf->pkt_len;
2031
2032 if (BGP_DEBUG(zebra, ZEBRA))
2033 bgp_pbr_dump_entry(bpf, true);
2034
2035 /* look for bpa first */
2036 memset(&temp3, 0, sizeof(temp3));
2037 if (rate)
2038 temp3.rate = *rate;
2039 if (nh)
2040 memcpy(&temp3.nh, nh, sizeof(struct nexthop));
2041 temp3.vrf_id = bpf->vrf_id;
2042 bpa = hash_get(bgp->pbr_action_hash, &temp3,
2043 bgp_pbr_action_alloc_intern);
2044
2045 if (bpa->fwmark == 0) {
2046 /* drop is handled by iptable */
2047 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
2048 bpa->table_id = 0;
2049 bpa->installed = true;
2050 } else {
2051 bpa->fwmark = bgp_zebra_tm_get_id();
2052 bpa->table_id = bpa->fwmark;
2053 bpa->installed = false;
2054 }
2055 bpa->bgp = bgp;
2056 bpa->unique = ++bgp_pbr_action_counter_unique;
2057 /* 0 value is forbidden */
2058 bpa->install_in_progress = false;
2059 }
2060 if (bpf->type == BGP_PBR_IPRULE) {
2061 memset(&pbr_rule, 0, sizeof(pbr_rule));
2062 pbr_rule.vrf_id = bpf->vrf_id;
2063 pbr_rule.priority = 20;
2064 if (bpf->src) {
2065 pbr_rule.flags |= MATCH_IP_SRC_SET;
2066 prefix_copy(&pbr_rule.src, bpf->src);
2067 }
2068 if (bpf->dst) {
2069 pbr_rule.flags |= MATCH_IP_DST_SET;
2070 prefix_copy(&pbr_rule.dst, bpf->dst);
2071 }
2072 pbr_rule.action = bpa;
2073 bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule,
2074 bgp_pbr_rule_alloc_intern);
2075 if (bpr && bpr->unique == 0) {
2076 bpr->unique = ++bgp_pbr_action_counter_unique;
2077 bpr->installed = false;
2078 bpr->install_in_progress = false;
2079 /* link bgp info to bpr */
2080 bpr->path = (void *)path;
2081 } else
2082 bpr_found = true;
2083 /* already installed */
2084 if (bpr_found && bpr) {
2085 struct bgp_path_info_extra *extra =
2086 bgp_path_info_extra_get(path);
2087
2088 if (extra &&
2089 listnode_lookup_nocheck(extra->bgp_fs_iprule,
2090 bpr)) {
2091 if (BGP_DEBUG(pbr, PBR_ERROR))
2092 zlog_err("%s: entry %p/%p already "
2093 "installed in bgp pbr iprule",
2094 __func__, path, bpr);
2095 return;
2096 }
2097 }
2098 if (!bpa->installed && !bpa->install_in_progress) {
2099 bgp_send_pbr_rule_action(bpa, NULL, true);
2100 bgp_zebra_announce_default(bgp, nh,
2101 AFI_IP, bpa->table_id, true);
2102 }
2103 /* ip rule add */
2104 if (bpr && !bpr->installed)
2105 bgp_send_pbr_rule_action(bpa, bpr, true);
2106
2107 /* A previous entry may already exist
2108 * flush previous entry if necessary
2109 */
2110 bprr.bpr_to_match = bpr;
2111 bprr.bpr_found = NULL;
2112 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
2113 if (bprr.bpr_found) {
2114 static struct bgp_pbr_rule *local_bpr;
2115 static struct bgp_pbr_action *local_bpa;
2116
2117 local_bpr = bprr.bpr_found;
2118 local_bpa = local_bpr->action;
2119 bgp_pbr_flush_iprule(bgp, local_bpa,
2120 local_bpr);
2121 }
2122 return;
2123 }
2124 /* then look for bpm */
2125 memset(&temp, 0, sizeof(temp));
2126 temp.vrf_id = bpf->vrf_id;
2127 if (bpf->src)
2128 temp.flags |= MATCH_IP_SRC_SET;
2129 if (bpf->dst)
2130 temp.flags |= MATCH_IP_DST_SET;
2131
2132 if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2133 if (bpf->protocol == IPPROTO_ICMP)
2134 temp.flags |= MATCH_ICMP_SET;
2135 temp.flags |= MATCH_PORT_SRC_SET;
2136 }
2137 if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2138 if (bpf->protocol == IPPROTO_ICMP)
2139 temp.flags |= MATCH_ICMP_SET;
2140 temp.flags |= MATCH_PORT_DST_SET;
2141 }
2142 if (src_port && src_port->max_port)
2143 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
2144 if (dst_port && dst_port->max_port)
2145 temp.flags |= MATCH_PORT_DST_RANGE_SET;
2146
2147 if (bpf->src == NULL || bpf->dst == NULL) {
2148 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2149 temp.type = IPSET_NET_PORT;
2150 else
2151 temp.type = IPSET_NET;
2152 } else {
2153 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2154 temp.type = IPSET_NET_PORT_NET;
2155 else
2156 temp.type = IPSET_NET_NET;
2157 }
2158 if (pkt_len) {
2159 temp.pkt_len_min = pkt_len->min_port;
2160 if (pkt_len->max_port)
2161 temp.pkt_len_max = pkt_len->max_port;
2162 } else if (bpf->pkt_len_val) {
2163 if (bpf->pkt_len_val->mask)
2164 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
2165 temp.pkt_len_min = bpf->pkt_len_val->val;
2166 }
2167 if (bpf->tcp_flags) {
2168 temp.tcp_flags = bpf->tcp_flags->val;
2169 temp.tcp_mask_flags = bpf->tcp_flags->mask;
2170 }
2171 if (bpf->dscp) {
2172 if (bpf->dscp->mask)
2173 temp.flags |= MATCH_DSCP_INVERSE_SET;
2174 else
2175 temp.flags |= MATCH_DSCP_SET;
2176 temp.dscp_value = bpf->dscp->val;
2177 }
2178 if (bpf->fragment) {
2179 if (bpf->fragment->mask)
2180 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
2181 temp.fragment = bpf->fragment->val;
2182 }
2183 if (bpf->protocol) {
2184 temp.protocol = bpf->protocol;
2185 temp.flags |= MATCH_PROTOCOL_SET;
2186 }
2187 temp.action = bpa;
2188 bpm = hash_get(bgp->pbr_match_hash, &temp,
2189 bgp_pbr_match_alloc_intern);
2190
2191 /* new, then self allocate ipset_name and unique */
2192 if (bpm->unique == 0) {
2193 bpm->unique = ++bgp_pbr_match_counter_unique;
2194 /* 0 value is forbidden */
2195 sprintf(bpm->ipset_name, "match%p", bpm);
2196 bpm->entry_hash = hash_create_size(8,
2197 bgp_pbr_match_entry_hash_key,
2198 bgp_pbr_match_entry_hash_equal,
2199 "Match Entry Hash");
2200 bpm->installed = false;
2201
2202 /* unique2 should be updated too */
2203 bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
2204 bpm->installed_in_iptable = false;
2205 bpm->install_in_progress = false;
2206 bpm->install_iptable_in_progress = false;
2207 }
2208
2209 memset(&temp2, 0, sizeof(temp2));
2210 if (bpf->src)
2211 prefix_copy(&temp2.src, bpf->src);
2212 else
2213 temp2.src.family = AF_INET;
2214 if (bpf->dst)
2215 prefix_copy(&temp2.dst, bpf->dst);
2216 else
2217 temp2.dst.family = AF_INET;
2218 temp2.src_port_min = src_port ? src_port->min_port : 0;
2219 temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
2220 temp2.src_port_max = src_port ? src_port->max_port : 0;
2221 temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
2222 temp2.proto = bpf->protocol;
2223 bpme = hash_get(bpm->entry_hash, &temp2,
2224 bgp_pbr_match_entry_alloc_intern);
2225 if (bpme->unique == 0) {
2226 bpme->unique = ++bgp_pbr_match_entry_counter_unique;
2227 /* 0 value is forbidden */
2228 bpme->backpointer = bpm;
2229 bpme->installed = false;
2230 bpme->install_in_progress = false;
2231 /* link bgp info to bpme */
2232 bpme->path = (void *)path;
2233 } else
2234 bpme_found = true;
2235
2236 /* already installed */
2237 if (bpme_found) {
2238 struct bgp_path_info_extra *extra =
2239 bgp_path_info_extra_get(path);
2240
2241 if (extra &&
2242 listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) {
2243 if (BGP_DEBUG(pbr, PBR_ERROR))
2244 zlog_err(
2245 "%s: entry %p/%p already installed in bgp pbr",
2246 __func__, path, bpme);
2247 return;
2248 }
2249 }
2250 /* BGP FS: append entry to zebra
2251 * - policies are not routing entries and as such
2252 * route replace semantics don't necessarily follow
2253 * through to policy entries
2254 * - because of that, not all policing information will be stored
2255 * into zebra. and non selected policies will be suppressed from zebra
2256 * - as consequence, in order to bring consistency
2257 * a policy will be added, then ifan ecmp policy exists,
2258 * it will be suppressed subsequently
2259 */
2260 /* ip rule add */
2261 if (!bpa->installed && !bpa->install_in_progress) {
2262 bgp_send_pbr_rule_action(bpa, NULL, true);
2263 bgp_zebra_announce_default(bgp, nh,
2264 AFI_IP, bpa->table_id, true);
2265 }
2266
2267 /* ipset create */
2268 if (!bpm->installed)
2269 bgp_send_pbr_ipset_match(bpm, true);
2270 /* ipset add */
2271 if (!bpme->installed)
2272 bgp_send_pbr_ipset_entry_match(bpme, true);
2273
2274 /* iptables */
2275 if (!bpm->installed_in_iptable)
2276 bgp_send_pbr_iptable(bpa, bpm, true);
2277
2278 /* A previous entry may already exist
2279 * flush previous entry if necessary
2280 */
2281 bpmer.bpme_to_match = bpme;
2282 bpmer.bpme_found = NULL;
2283 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
2284 if (bpmer.bpme_found) {
2285 static struct bgp_pbr_match *local_bpm;
2286 static struct bgp_pbr_action *local_bpa;
2287
2288 local_bpm = bpmer.bpme_found->backpointer;
2289 local_bpa = local_bpm->action;
2290 bgp_pbr_flush_entry(bgp, local_bpa,
2291 local_bpm, bpmer.bpme_found);
2292 }
2293
2294
2295 }
2296
2297 static void bgp_pbr_policyroute_add_to_zebra_recursive(
2298 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2299 struct bgp_pbr_or_filter *bpof, struct nexthop *nh, float *rate,
2300 uint8_t type_entry)
2301 {
2302 struct listnode *node, *nnode;
2303 struct bgp_pbr_val_mask *valmask;
2304 uint8_t next_type_entry;
2305 struct list *orig_list;
2306 struct bgp_pbr_val_mask **target_val;
2307
2308 if (type_entry == 0) {
2309 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2310 return;
2311 }
2312 next_type_entry = bgp_pbr_next_type_entry(type_entry);
2313 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
2314 orig_list = bpof->tcpflags;
2315 target_val = &bpf->tcp_flags;
2316 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
2317 orig_list = bpof->dscp;
2318 target_val = &bpf->dscp;
2319 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
2320 orig_list = bpof->pkt_len;
2321 target_val = &bpf->pkt_len_val;
2322 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
2323 orig_list = bpof->fragment;
2324 target_val = &bpf->fragment;
2325 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
2326 (bpof->icmp_type || bpof->icmp_code)) {
2327 /* enumerate list for icmp - must be last one */
2328 bgp_pbr_icmp_action(bgp, path, bpf, bpof, true, nh, rate);
2329 return;
2330 } else {
2331 bgp_pbr_policyroute_add_to_zebra_recursive(
2332 bgp, path, bpf, bpof, nh, rate, next_type_entry);
2333 return;
2334 }
2335 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
2336 *target_val = valmask;
2337 bgp_pbr_policyroute_add_to_zebra_recursive(
2338 bgp, path, bpf, bpof, nh, rate, next_type_entry);
2339 }
2340 }
2341
2342 static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
2343 struct bgp_path_info *path,
2344 struct bgp_pbr_filter *bpf,
2345 struct bgp_pbr_or_filter *bpof,
2346 struct nexthop *nh, float *rate)
2347 {
2348 if (!bpof) {
2349 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2350 return;
2351 }
2352 if (bpof->tcpflags)
2353 bgp_pbr_policyroute_add_to_zebra_recursive(
2354 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_TCP_FLAGS);
2355 else if (bpof->dscp)
2356 bgp_pbr_policyroute_add_to_zebra_recursive(
2357 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_DSCP);
2358 else if (bpof->pkt_len)
2359 bgp_pbr_policyroute_add_to_zebra_recursive(
2360 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_PKT_LEN);
2361 else if (bpof->fragment)
2362 bgp_pbr_policyroute_add_to_zebra_recursive(
2363 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_FRAGMENT);
2364 else if (bpof->icmp_type || bpof->icmp_code)
2365 bgp_pbr_policyroute_add_to_zebra_recursive(
2366 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_ICMP_TYPE);
2367 else
2368 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2369 /* flush bpof */
2370 if (bpof->tcpflags)
2371 list_delete_all_node(bpof->tcpflags);
2372 if (bpof->dscp)
2373 list_delete_all_node(bpof->dscp);
2374 if (bpof->pkt_len)
2375 list_delete_all_node(bpof->pkt_len);
2376 if (bpof->fragment)
2377 list_delete_all_node(bpof->fragment);
2378 if (bpof->icmp_type)
2379 list_delete_all_node(bpof->icmp_type);
2380 if (bpof->icmp_code)
2381 list_delete_all_node(bpof->icmp_code);
2382 }
2383
2384 static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
2385 struct bgp_pbr_entry_main *api, bool add)
2386 {
2387 struct nexthop nh;
2388 int i = 0;
2389 int continue_loop = 1;
2390 float rate = 0;
2391 struct prefix *src = NULL, *dst = NULL;
2392 uint8_t proto = 0;
2393 struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
2394 struct bgp_pbr_range_port range, range_icmp_code;
2395 struct bgp_pbr_range_port pkt_len;
2396 struct bgp_pbr_filter bpf;
2397 uint8_t kind_enum;
2398 struct bgp_pbr_or_filter bpof;
2399 struct bgp_pbr_val_mask bpvm;
2400
2401 memset(&nh, 0, sizeof(struct nexthop));
2402 memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
2403 memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
2404 if (api->match_bitmask & PREFIX_SRC_PRESENT ||
2405 (api->type == BGP_PBR_IPRULE &&
2406 api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
2407 src = &api->src_prefix;
2408 if (api->match_bitmask & PREFIX_DST_PRESENT ||
2409 (api->type == BGP_PBR_IPRULE &&
2410 api->match_bitmask_iprule & PREFIX_DST_PRESENT))
2411 dst = &api->dst_prefix;
2412 if (api->type == BGP_PBR_IPRULE)
2413 bpf.type = api->type;
2414 memset(&nh, 0, sizeof(struct nexthop));
2415 nh.vrf_id = VRF_UNKNOWN;
2416 if (api->match_protocol_num)
2417 proto = (uint8_t)api->protocol[0].value;
2418 /* if match_port is selected, then either src or dst port will be parsed
2419 * but not both at the same time
2420 */
2421 if (api->match_port_num >= 1) {
2422 bgp_pbr_extract(api->port,
2423 api->match_port_num,
2424 &range);
2425 srcp = dstp = &range;
2426 } else if (api->match_src_port_num >= 1) {
2427 bgp_pbr_extract(api->src_port,
2428 api->match_src_port_num,
2429 &range);
2430 srcp = &range;
2431 dstp = NULL;
2432 } else if (api->match_dst_port_num >= 1) {
2433 bgp_pbr_extract(api->dst_port,
2434 api->match_dst_port_num,
2435 &range);
2436 dstp = &range;
2437 srcp = NULL;
2438 }
2439 if (api->match_icmp_type_num >= 1) {
2440 proto = IPPROTO_ICMP;
2441 if (bgp_pbr_extract(api->icmp_type,
2442 api->match_icmp_type_num,
2443 &range))
2444 srcp = &range;
2445 else {
2446 bpof.icmp_type = list_new();
2447 bgp_pbr_extract_enumerate(api->icmp_type,
2448 api->match_icmp_type_num,
2449 OPERATOR_UNARY_OR,
2450 bpof.icmp_type,
2451 FLOWSPEC_ICMP_TYPE);
2452 }
2453 }
2454 if (api->match_icmp_code_num >= 1) {
2455 proto = IPPROTO_ICMP;
2456 if (bgp_pbr_extract(api->icmp_code,
2457 api->match_icmp_code_num,
2458 &range_icmp_code))
2459 dstp = &range_icmp_code;
2460 else {
2461 bpof.icmp_code = list_new();
2462 bgp_pbr_extract_enumerate(api->icmp_code,
2463 api->match_icmp_code_num,
2464 OPERATOR_UNARY_OR,
2465 bpof.icmp_code,
2466 FLOWSPEC_ICMP_CODE);
2467 }
2468 }
2469
2470 if (api->match_tcpflags_num) {
2471 kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
2472 api->match_tcpflags_num);
2473 if (kind_enum == OPERATOR_UNARY_AND) {
2474 bpf.tcp_flags = &bpvm;
2475 bgp_pbr_extract_enumerate(api->tcpflags,
2476 api->match_tcpflags_num,
2477 OPERATOR_UNARY_AND,
2478 bpf.tcp_flags,
2479 FLOWSPEC_TCP_FLAGS);
2480 } else if (kind_enum == OPERATOR_UNARY_OR) {
2481 bpof.tcpflags = list_new();
2482 bgp_pbr_extract_enumerate(api->tcpflags,
2483 api->match_tcpflags_num,
2484 OPERATOR_UNARY_OR,
2485 bpof.tcpflags,
2486 FLOWSPEC_TCP_FLAGS);
2487 }
2488 }
2489 if (api->match_packet_length_num) {
2490 bool ret;
2491
2492 ret = bgp_pbr_extract(api->packet_length,
2493 api->match_packet_length_num,
2494 &pkt_len);
2495 if (ret)
2496 bpf.pkt_len = &pkt_len;
2497 else {
2498 bpof.pkt_len = list_new();
2499 bgp_pbr_extract_enumerate(api->packet_length,
2500 api->match_packet_length_num,
2501 OPERATOR_UNARY_OR,
2502 bpof.pkt_len,
2503 FLOWSPEC_PKT_LEN);
2504 }
2505 }
2506 if (api->match_dscp_num >= 1) {
2507 bpof.dscp = list_new();
2508 bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
2509 OPERATOR_UNARY_OR,
2510 bpof.dscp, FLOWSPEC_DSCP);
2511 }
2512 if (api->match_fragment_num) {
2513 bpof.fragment = list_new();
2514 bgp_pbr_extract_enumerate(api->fragment,
2515 api->match_fragment_num,
2516 OPERATOR_UNARY_OR,
2517 bpof.fragment,
2518 FLOWSPEC_FRAGMENT);
2519 }
2520 bpf.vrf_id = api->vrf_id;
2521 bpf.src = src;
2522 bpf.dst = dst;
2523 bpf.protocol = proto;
2524 bpf.src_port = srcp;
2525 bpf.dst_port = dstp;
2526 if (!add) {
2527 bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
2528 return;
2529 }
2530 /* no action for add = true */
2531 for (i = 0; i < api->action_num; i++) {
2532 switch (api->actions[i].action) {
2533 case ACTION_TRAFFICRATE:
2534 /* drop packet */
2535 if (api->actions[i].u.r.rate == 0) {
2536 nh.vrf_id = api->vrf_id;
2537 nh.type = NEXTHOP_TYPE_BLACKHOLE;
2538 bgp_pbr_policyroute_add_to_zebra(
2539 bgp, path, &bpf, &bpof, &nh, &rate);
2540 } else {
2541 /* update rate. can be reentrant */
2542 rate = api->actions[i].u.r.rate;
2543 if (BGP_DEBUG(pbr, PBR)) {
2544 bgp_pbr_print_policy_route(api);
2545 zlog_warn("PBR: ignoring Set action rate %f",
2546 api->actions[i].u.r.rate);
2547 }
2548 }
2549 break;
2550 case ACTION_TRAFFIC_ACTION:
2551 if (api->actions[i].u.za.filter
2552 & TRAFFIC_ACTION_SAMPLE) {
2553 if (BGP_DEBUG(pbr, PBR)) {
2554 bgp_pbr_print_policy_route(api);
2555 zlog_warn("PBR: Sample action Ignored");
2556 }
2557 }
2558 #if 0
2559 if (api->actions[i].u.za.filter
2560 & TRAFFIC_ACTION_DISTRIBUTE) {
2561 if (BGP_DEBUG(pbr, PBR)) {
2562 bgp_pbr_print_policy_route(api);
2563 zlog_warn("PBR: Distribute action Applies");
2564 }
2565 continue_loop = 0;
2566 /* continue forwarding entry as before
2567 * no action
2568 */
2569 }
2570 #endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2571 /* terminate action: run other filters
2572 */
2573 break;
2574 case ACTION_REDIRECT_IP:
2575 nh.type = NEXTHOP_TYPE_IPV4;
2576 nh.gate.ipv4.s_addr =
2577 api->actions[i].u.zr.redirect_ip_v4.s_addr;
2578 nh.vrf_id = api->vrf_id;
2579 bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
2580 &nh, &rate);
2581 /* XXX combination with REDIRECT_VRF
2582 * + REDIRECT_NH_IP not done
2583 */
2584 continue_loop = 0;
2585 break;
2586 case ACTION_REDIRECT:
2587 nh.vrf_id = api->actions[i].u.redirect_vrf;
2588 nh.type = NEXTHOP_TYPE_IPV4;
2589 bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
2590 &nh, &rate);
2591 continue_loop = 0;
2592 break;
2593 case ACTION_MARKING:
2594 if (BGP_DEBUG(pbr, PBR)) {
2595 bgp_pbr_print_policy_route(api);
2596 zlog_warn("PBR: Set DSCP %u Ignored",
2597 api->actions[i].u.marking_dscp);
2598 }
2599 break;
2600 default:
2601 break;
2602 }
2603 if (continue_loop == 0)
2604 break;
2605 }
2606 }
2607
2608 void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
2609 struct bgp_path_info *info, afi_t afi, safi_t safi,
2610 bool nlri_update)
2611 {
2612 struct bgp_pbr_entry_main api;
2613
2614 if (afi == AFI_IP6)
2615 return; /* IPv6 not supported */
2616 if (safi != SAFI_FLOWSPEC)
2617 return; /* not supported */
2618 /* Make Zebra API structure. */
2619 memset(&api, 0, sizeof(api));
2620 api.vrf_id = bgp->vrf_id;
2621 api.afi = afi;
2622
2623 if (!bgp_zebra_tm_chunk_obtained()) {
2624 if (BGP_DEBUG(pbr, PBR_ERROR))
2625 flog_err(EC_BGP_TABLE_CHUNK,
2626 "%s: table chunk not obtained yet", __func__);
2627 return;
2628 }
2629
2630 if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
2631 if (BGP_DEBUG(pbr, PBR_ERROR))
2632 flog_err(EC_BGP_FLOWSPEC_INSTALLATION,
2633 "%s: cancel updating entry %p in bgp pbr",
2634 __func__, info);
2635 return;
2636 }
2637 bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
2638 }
2639
2640 int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
2641 const struct bgp_pbr_interface *b)
2642 {
2643 return strcmp(a->name, b->name);
2644 }
2645
2646 struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
2647 struct bgp_pbr_interface_head *head)
2648 {
2649 struct bgp_pbr_interface pbr_if;
2650
2651 strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
2652 return (RB_FIND(bgp_pbr_interface_head,
2653 head, &pbr_if));
2654 }
2655
2656 /* this function resets to the default policy routing
2657 * go back to default status
2658 */
2659 void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
2660 {
2661 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
2662 struct bgp_pbr_interface_head *head;
2663 struct bgp_pbr_interface *pbr_if;
2664
2665 if (!bgp_pbr_cfg || afi != AFI_IP)
2666 return;
2667 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
2668
2669 while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
2670 pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
2671 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
2672 XFREE(MTYPE_TMP, pbr_if);
2673 }
2674 }