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