]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_pbr.c
bgpd: rework icmp enumerate list
[mirror_frr.git] / bgpd / bgp_pbr.c
CommitLineData
bbe6ffd6
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"
f3d32faa 23#include "jhash.h"
2e1f721e 24#include "pbr.h"
bbe6ffd6 25
f3d32faa 26#include "bgpd/bgpd.h"
bbe6ffd6 27#include "bgpd/bgp_pbr.h"
b46b6f1a 28#include "bgpd/bgp_debug.h"
45918cfb
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"
d114b0d7 33#include "bgpd/bgp_zebra.h"
529efa23 34#include "bgpd/bgp_mplsvpn.h"
35703998 35#include "bgpd/bgp_flowspec_private.h"
d114b0d7
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")
4762c213 40DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
f7b2e630 41DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
4762c213
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);
d114b0d7
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;
b46b6f1a 52
1815c6fc
PG
53struct bgp_pbr_match_iptable_unique {
54 uint32_t unique;
55 struct bgp_pbr_match *bpm_found;
56};
57
c5d429e1
PG
58struct bgp_pbr_match_entry_unique {
59 uint32_t unique;
60 struct bgp_pbr_match_entry *bpme_found;
61};
62
70eabd12
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
c5d429e1
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
1815c6fc
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
c5d429e1
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
b46b6f1a
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
0e867886
PG
181/* this structure can be used for port range,
182 * but also for other values range like packet length range
183 */
1de7dfff
PG
184struct bgp_pbr_range_port {
185 uint16_t min_port;
186 uint16_t max_port;
187};
188
2da7d62e
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
0e867886
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;
2da7d62e 209 struct bgp_pbr_val_mask *tcp_flags;
4977bd6c 210 struct bgp_pbr_val_mask *dscp;
cfaf18ce 211 struct bgp_pbr_val_mask *pkt_len_val;
6f5617d8 212 struct bgp_pbr_val_mask *fragment;
0e867886
PG
213};
214
c5ee26cc
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;
56707a36 221 struct list *dscp;
cfaf18ce 222 struct list *pkt_len;
6f5617d8 223 struct list *fragment;
da3fa383
PG
224 struct list *icmp_type;
225 struct list *icmp_code;
c5ee26cc
PG
226};
227
da3fa383
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);
2da7d62e
PG
233/* TCP : FIN and SYN -> val = ALL; mask = 3
234 * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
6f5617d8
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
2da7d62e 238 */
f7b2e630
PG
239static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
240 int num, uint8_t unary_operator,
35703998 241 void *valmask, uint8_t type_entry)
932404b7
PG
242{
243 int i = 0;
f7b2e630
PG
244 struct bgp_pbr_val_mask *and_valmask = NULL;
245 struct list *or_valmask = NULL;
932404b7 246
f7b2e630
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 }
932404b7 255 for (i = 0; i < num; i++) {
2da7d62e
PG
256 if (i != 0 && list[i].unary_operator !=
257 unary_operator)
932404b7 258 return false;
2da7d62e
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)) {
35703998
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);
cfaf18ce 272 } else if (type_entry == FLOWSPEC_DSCP ||
6f5617d8
PG
273 type_entry == FLOWSPEC_PKT_LEN ||
274 type_entry == FLOWSPEC_FRAGMENT) {
35703998
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) {
f7b2e630
PG
279 and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
280 sizeof(struct bgp_pbr_val_mask));
35703998
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);
cfaf18ce 286 } else if (type_entry == FLOWSPEC_DSCP ||
6f5617d8 287 type_entry == FLOWSPEC_FRAGMENT ||
cfaf18ce 288 type_entry == FLOWSPEC_PKT_LEN) {
35703998
PG
289 and_valmask->val = list[i].value;
290 and_valmask->mask = 1; /* inverse */
291 }
f7b2e630 292 listnode_add (or_valmask, and_valmask);
da3fa383
PG
293 } else if (type_entry == FLOWSPEC_ICMP_CODE ||
294 type_entry == FLOWSPEC_ICMP_TYPE)
295 return false;
2da7d62e
PG
296 continue;
297 }
298 return false;
299 }
35703998
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) {
f7b2e630
PG
305 and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
306 sizeof(struct bgp_pbr_val_mask));
35703998
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;
cfaf18ce 311 } else if (type_entry == FLOWSPEC_DSCP ||
da3fa383
PG
312 type_entry == FLOWSPEC_ICMP_TYPE ||
313 type_entry == FLOWSPEC_ICMP_CODE ||
6f5617d8 314 type_entry == FLOWSPEC_FRAGMENT ||
cfaf18ce 315 type_entry == FLOWSPEC_PKT_LEN)
35703998 316 and_valmask->val = list[i].value;
f7b2e630
PG
317 listnode_add(or_valmask, and_valmask);
318 }
932404b7 319 }
35703998
PG
320 if (unary_operator == OPERATOR_UNARY_AND && and_valmask
321 && type_entry == FLOWSPEC_TCP_FLAGS)
322 and_valmask->val = TCP_HEADER_ALL_FLAGS;
932404b7
PG
323 return true;
324}
325
f7b2e630
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,
35703998 331 void *valmask, uint8_t type_entry)
f7b2e630
PG
332{
333 bool ret;
35703998 334 uint8_t unary_operator_val = unary_operator;
f7b2e630
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,
35703998 344 valmask, type_entry);
f7b2e630
PG
345 if (!ret && double_check)
346 ret = bgp_pbr_extract_enumerate_unary(list, num,
347 OPERATOR_UNARY_OR,
35703998
PG
348 valmask,
349 type_entry);
f7b2e630
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
1de7dfff
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
b46b6f1a
PG
427static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
428{
932404b7
PG
429 bool enumerate_icmp = false;
430
b46b6f1a
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
1de7dfff 438 * - combination srcport + @IP
b46b6f1a 439 */
1de7dfff
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 &&
932404b7 449 api->protocol[0].value != PROTOCOL_ICMP &&
1de7dfff
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 }
2da7d62e
PG
469 if (!bgp_pbr_extract_enumerate(api->tcpflags,
470 api->match_tcpflags_num,
c5ee26cc 471 OPERATOR_UNARY_AND |
35703998
PG
472 OPERATOR_UNARY_OR, NULL,
473 FLOWSPEC_TCP_FLAGS)) {
2da7d62e
PG
474 if (BGP_DEBUG(pbr, PBR))
475 zlog_debug("BGP: match tcp flags:"
476 "too complex. ignoring.");
477 return 0;
478 }
932404b7
PG
479 if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
480 if (!bgp_pbr_extract_enumerate(api->icmp_type,
2da7d62e 481 api->match_icmp_type_num,
35703998
PG
482 OPERATOR_UNARY_OR, NULL,
483 FLOWSPEC_ICMP_TYPE)) {
932404b7
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,
2da7d62e 493 api->match_icmp_code_num,
35703998
PG
494 OPERATOR_UNARY_OR, NULL,
495 FLOWSPEC_ICMP_CODE)) {
932404b7
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 }
1de7dfff
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 }
cfaf18ce
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:"
83360720 529 "too complex. ignoring.");
cfaf18ce
PG
530 return 0;
531 }
83360720 532 }
35703998
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 }
4977bd6c 542 }
6f5617d8
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
1de7dfff
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 }
932404b7
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 }
b46b6f1a
PG
595 if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
596 !(api->match_bitmask & PREFIX_DST_PRESENT)) {
ac7c35f8 597 if (BGP_DEBUG(pbr, PBR)) {
b46b6f1a 598 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
599 zlog_debug("BGP: match actions without src"
600 " or dst address can not operate."
601 " ignoring.");
602 }
b46b6f1a
PG
603 return 0;
604 }
605 return 1;
606}
bbe6ffd6 607
45918cfb
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 *)
149d272b
PG
632 (ecom->val + (i * ECOMMUNITY_SIZE));
633 action_count++;
45918cfb 634 if (action_count > ACTIONS_MAX_NUM) {
f146bb54
PG
635 if (BGP_DEBUG(pbr, PBR_ERROR))
636 zlog_err("%s: flowspec actions exceeds limit (max %u)",
637 __func__, action_count);
45918cfb
PG
638 break;
639 }
149d272b 640 api_action = &api->actions[action_count - 1];
45918cfb
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)) {
ac7c35f8 701 if (BGP_DEBUG(pbr, PBR)) {
45918cfb 702 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
703 zlog_debug("%s: inconsistency:"
704 " no match for afi src and dst (%u/%u)",
705 __func__, afi, family2afi(dst->family));
706 }
45918cfb
PG
707 return -1;
708 }
709 }
710 return 0;
711}
712
a6b07429
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
d114b0d7
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
a6b07429
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);
6ee20355 780 bpa->installed = false;
a6b07429
PG
781 }
782 }
783 XFREE(MTYPE_PBR_ACTION, bpa);
784}
785
d114b0d7
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
f3d32faa
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);
83360720
PG
819 key = jhash_1word(pbm->pkt_len_min, key);
820 key = jhash_1word(pbm->pkt_len_max, key);
2da7d62e
PG
821 key = jhash_1word(pbm->tcp_flags, key);
822 key = jhash_1word(pbm->tcp_mask_flags, key);
4977bd6c 823 key = jhash_1word(pbm->dscp_value, key);
6f5617d8 824 key = jhash_1word(pbm->fragment, key);
f3d32faa
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
83360720
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
2da7d62e
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
4977bd6c
PG
859 if (r1->dscp_value != r2->dscp_value)
860 return 0;
6f5617d8
PG
861
862 if (r1->fragment != r2->fragment)
863 return 0;
f3d32faa
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);
1de7dfff
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);
f3d32faa
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
1de7dfff
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
f3d32faa
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
e414819e 945 * rate is ignored
f3d32faa 946 */
f3d32faa
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}
bbe6ffd6 954
70eabd12
PG
955struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
956 uint32_t unique)
bbe6ffd6 957{
70eabd12
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;
bbe6ffd6
PG
967}
968
969struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
970 uint32_t unique)
971{
c5d429e1
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;
bbe6ffd6
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{
c5d429e1
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;
bbe6ffd6
PG
1005}
1006
1815c6fc
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
a6b07429
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 }
4762c213
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;
a6b07429
PG
1038}
1039
f3d32faa
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");
4762c213
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;
f3d32faa 1053}
b46b6f1a
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
588ec356 1131 if (api->match_fragment_num)
b46b6f1a 1132 INCREMENT_DISPLAY(ptr, nb_items);
588ec356
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 ");
b46b6f1a
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}
45918cfb 1190
d114b0d7
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;
b588b642
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 }
d114b0d7
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;
a6b07429 1224 bpm->action->refcnt--;
d114b0d7
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 }
a6b07429
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);
6ee20355 1242 bpa->installed = false;
a6b07429
PG
1243 }
1244 }
d114b0d7
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
9bba1455 1278static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp *bgp,
0e867886
PG
1279 struct bgp_info *binfo,
1280 struct bgp_pbr_filter *bpf)
d114b0d7
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;
0e867886
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;
d114b0d7
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));
0e867886 1303 if (bpf->src) {
d114b0d7 1304 temp.flags |= MATCH_IP_SRC_SET;
0e867886 1305 prefix_copy(&temp2.src, bpf->src);
d114b0d7
PG
1306 } else
1307 temp2.src.family = AF_INET;
0e867886 1308 if (bpf->dst) {
d114b0d7 1309 temp.flags |= MATCH_IP_DST_SET;
0e867886 1310 prefix_copy(&temp2.dst, bpf->dst);
d114b0d7
PG
1311 } else
1312 temp2.dst.family = AF_INET;
932404b7 1313 if (src_port && src_port->min_port) {
1de7dfff
PG
1314 temp.flags |= MATCH_PORT_SRC_SET;
1315 temp2.src_port_min = src_port->min_port;
1316 if (src_port->max_port) {
1317 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1318 temp2.src_port_max = src_port->max_port;
1319 }
1320 }
932404b7 1321 if (dst_port && dst_port->min_port) {
1de7dfff
PG
1322 temp.flags |= MATCH_PORT_DST_SET;
1323 temp2.dst_port_min = dst_port->min_port;
1324 if (dst_port->max_port) {
1325 temp.flags |= MATCH_PORT_DST_RANGE_SET;
1326 temp2.dst_port_max = dst_port->max_port;
1327 }
1328 }
0e867886 1329 temp2.proto = bpf->protocol;
1de7dfff 1330
cfaf18ce 1331 if (pkt_len) {
83360720 1332 temp.pkt_len_min = pkt_len->min_port;
cfaf18ce
PG
1333 if (pkt_len->max_port)
1334 temp.pkt_len_max = pkt_len->max_port;
1335 } else if (bpf->pkt_len_val) {
1336 if (bpf->pkt_len_val->mask)
1337 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
1338 temp.pkt_len_min = bpf->pkt_len_val->val;
1339 }
2da7d62e
PG
1340 if (bpf->tcp_flags) {
1341 temp.tcp_flags = bpf->tcp_flags->val;
1342 temp.tcp_mask_flags = bpf->tcp_flags->mask;
1343 }
4977bd6c
PG
1344 if (bpf->dscp) {
1345 if (bpf->dscp->mask)
1346 temp.flags |= MATCH_DSCP_INVERSE_SET;
1347 else
1348 temp.flags |= MATCH_DSCP_SET;
1349 temp.dscp_value = bpf->dscp->val;
1350 }
6f5617d8
PG
1351 if (bpf->fragment) {
1352 if (bpf->fragment->mask)
1353 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
1354 temp.fragment = bpf->fragment->val;
1355 }
83360720 1356
0e867886 1357 if (bpf->src == NULL || bpf->dst == NULL) {
1de7dfff
PG
1358 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1359 temp.type = IPSET_NET_PORT;
1360 else
1361 temp.type = IPSET_NET;
1362 } else {
1363 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1364 temp.type = IPSET_NET_PORT_NET;
1365 else
1366 temp.type = IPSET_NET_NET;
1367 }
0e867886 1368 if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
d114b0d7
PG
1369 temp.vrf_id = 0;
1370 else
0e867886 1371 temp.vrf_id = bpf->vrf_id;
d114b0d7
PG
1372 bpme = &temp2;
1373 bpm = &temp;
1374 bpme->backpointer = bpm;
1375 /* right now, a previous entry may already exist
1376 * flush previous entry if necessary
1377 */
1378 bpmer.bpme_to_match = bpme;
1379 bpmer.bpme_found = NULL;
1380 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1381 if (bpmer.bpme_found) {
1382 static struct bgp_pbr_match *local_bpm;
1383 static struct bgp_pbr_action *local_bpa;
1384
1385 local_bpm = bpmer.bpme_found->backpointer;
1386 local_bpa = local_bpm->action;
1387 bgp_pbr_flush_entry(bgp, local_bpa,
1388 local_bpm, bpmer.bpme_found);
1389 }
1390}
1391
e45aea59
PG
1392static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
1393{
1394 if (type_entry == FLOWSPEC_TCP_FLAGS)
1395 return FLOWSPEC_DSCP;
1396 if (type_entry == FLOWSPEC_DSCP)
1397 return FLOWSPEC_PKT_LEN;
1398 if (type_entry == FLOWSPEC_PKT_LEN)
1399 return FLOWSPEC_FRAGMENT;
da3fa383
PG
1400 if (type_entry == FLOWSPEC_FRAGMENT)
1401 return FLOWSPEC_ICMP_TYPE;
e45aea59
PG
1402 return 0;
1403}
1404
da3fa383
PG
1405static void bgp_pbr_icmp_action(struct bgp *bgp,
1406 struct bgp_info *binfo,
1407 struct bgp_pbr_filter *bpf,
1408 struct bgp_pbr_or_filter *bpof,
1409 bool add,
1410 struct nexthop *nh,
1411 float *rate)
1412{
1413 struct bgp_pbr_range_port srcp, dstp;
1414 struct bgp_pbr_val_mask *icmp_type, *icmp_code;
1415 struct listnode *tnode, *cnode;
1416
1417 if (!bpf)
1418 return;
1419 if (bpf->protocol != IPPROTO_ICMP)
1420 return;
1421 bpf->src_port = &srcp;
1422 bpf->dst_port = &dstp;
1423 /* parse icmp type and lookup appropriate icmp code
1424 * if no icmp code found, create as many entryes as
1425 * there are listed icmp codes for that icmp type
1426 */
1427 if (!bpof->icmp_type) {
1428 srcp.min_port = 0;
1429 srcp.max_port = 255;
1430 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
1431 dstp.min_port = icmp_code->val;
1432 if (add)
1433 bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
1434 bpf, nh, rate);
1435 else
1436 bgp_pbr_policyroute_remove_from_zebra_unit(
1437 bgp, binfo, bpf);
1438 }
1439 return;
1440 }
1441 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
1442 srcp.min_port = icmp_type->val;
1443 srcp.max_port = 0;
1444 dstp.max_port = 0;
1445 /* only icmp type. create an entry only with icmp type */
1446 if (!bpof->icmp_code) {
1447 /* icmp type is not one of the above
1448 * forge an entry only based on the icmp type
1449 */
1450 dstp.min_port = 0;
1451 dstp.max_port = 255;
1452 if (add)
1453 bgp_pbr_policyroute_add_to_zebra_unit(
1454 bgp, binfo,
1455 bpf, nh, rate);
1456 else
1457 bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
1458 binfo, bpf);
1459 continue;
1460 }
1461 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
1462 dstp.min_port = icmp_code->val;
1463 if (add)
1464 bgp_pbr_policyroute_add_to_zebra_unit(
1465 bgp, binfo,
1466 bpf, nh, rate);
1467 else
1468 bgp_pbr_policyroute_remove_from_zebra_unit(
1469 bgp, binfo, bpf);
1470 }
1471 }
1472}
1473
56707a36
PG
1474static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp *bgp,
1475 struct bgp_info *binfo,
1476 struct bgp_pbr_filter *bpf,
1477 struct bgp_pbr_or_filter *bpof,
1478 uint8_t type_entry)
1479{
1480 struct listnode *node, *nnode;
1481 struct bgp_pbr_val_mask *valmask;
1482 uint8_t next_type_entry;
1483 struct list *orig_list;
1484 struct bgp_pbr_val_mask **target_val;
1485
1486 if (type_entry == 0)
1487 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
1488 binfo, bpf);
e45aea59 1489 next_type_entry = bgp_pbr_next_type_entry(type_entry);
56707a36 1490 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
56707a36
PG
1491 orig_list = bpof->tcpflags;
1492 target_val = &bpf->tcp_flags;
1493 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
56707a36
PG
1494 orig_list = bpof->dscp;
1495 target_val = &bpf->dscp;
cfaf18ce 1496 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
cfaf18ce
PG
1497 orig_list = bpof->pkt_len;
1498 target_val = &bpf->pkt_len_val;
6f5617d8 1499 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
6f5617d8
PG
1500 orig_list = bpof->fragment;
1501 target_val = &bpf->fragment;
da3fa383
PG
1502 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
1503 (bpof->icmp_type || bpof->icmp_code)) {
1504 /* enumerate list for icmp - must be last one */
1505 bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, false, NULL, NULL);
1506 return;
56707a36 1507 } else {
e45aea59
PG
1508 return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp,
1509 binfo,
1510 bpf, bpof,
1511 next_type_entry);
56707a36
PG
1512 }
1513 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
1514 *target_val = valmask;
1515 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1516 bpf, bpof,
1517 next_type_entry);
1518 }
1519}
1520
9bba1455
PG
1521static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
1522 struct bgp_info *binfo,
1523 struct bgp_pbr_filter *bpf,
1524 struct bgp_pbr_or_filter *bpof)
1525{
56707a36
PG
1526 if (!bpof)
1527 return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
1528 binfo,
1529 bpf);
1530 if (bpof->tcpflags)
1531 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1532 bpf, bpof,
1533 FLOWSPEC_TCP_FLAGS);
1534 else if (bpof->dscp)
1535 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1536 bpf, bpof,
1537 FLOWSPEC_DSCP);
cfaf18ce
PG
1538 else if (bpof->pkt_len)
1539 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1540 bpf, bpof,
1541 FLOWSPEC_PKT_LEN);
6f5617d8
PG
1542 else if (bpof->fragment)
1543 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1544 bpf, bpof,
1545 FLOWSPEC_FRAGMENT);
da3fa383
PG
1546 else if (bpof->icmp_type || bpof->icmp_code)
1547 bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
1548 bpf, bpof,
1549 FLOWSPEC_ICMP_TYPE);
56707a36 1550 else
9bba1455 1551 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, binfo, bpf);
56707a36
PG
1552 /* flush bpof */
1553 if (bpof->tcpflags)
1554 list_delete_all_node(bpof->tcpflags);
1555 if (bpof->dscp)
1556 list_delete_all_node(bpof->dscp);
cfaf18ce
PG
1557 if (bpof->pkt_len)
1558 list_delete_all_node(bpof->pkt_len);
6f5617d8
PG
1559 if (bpof->fragment)
1560 list_delete_all_node(bpof->fragment);
9bba1455
PG
1561}
1562
1563static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
1de7dfff 1564 struct bgp_info *binfo,
0e867886 1565 struct bgp_pbr_filter *bpf,
1de7dfff 1566 struct nexthop *nh,
0e867886 1567 float *rate)
d114b0d7
PG
1568{
1569 struct bgp_pbr_match temp;
1570 struct bgp_pbr_match_entry temp2;
1571 struct bgp_pbr_match *bpm;
1572 struct bgp_pbr_match_entry *bpme = NULL;
1573 struct bgp_pbr_action temp3;
1574 struct bgp_pbr_action *bpa = NULL;
1575 struct bgp_pbr_match_entry_remain bpmer;
0e867886
PG
1576 struct bgp_pbr_range_port *src_port;
1577 struct bgp_pbr_range_port *dst_port;
1578 struct bgp_pbr_range_port *pkt_len;
1579
1580 if (!bpf)
1581 return;
1582 src_port = bpf->src_port;
1583 dst_port = bpf->dst_port;
1584 pkt_len = bpf->pkt_len;
d114b0d7 1585
538f0137
PG
1586 if (BGP_DEBUG(zebra, ZEBRA)) {
1587 char bufsrc[64], bufdst[64];
1588 char buffer[64];
1589 int remaining_len = 0;
1590 char protocol_str[16];
1591
1592 protocol_str[0] = '\0';
2da7d62e
PG
1593 if (bpf->tcp_flags && bpf->tcp_flags->mask)
1594 bpf->protocol = IPPROTO_TCP;
0e867886
PG
1595 if (bpf->protocol)
1596 snprintf(protocol_str, sizeof(protocol_str),
1597 "proto %d", bpf->protocol);
538f0137 1598 buffer[0] = '\0';
0e867886 1599 if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
2da7d62e
PG
1600 remaining_len += snprintf(buffer, sizeof(buffer),
1601 "type %d, code %d",
538f0137 1602 src_port->min_port, dst_port->min_port);
0e867886
PG
1603 else if (bpf->protocol == IPPROTO_UDP ||
1604 bpf->protocol == IPPROTO_TCP) {
538f0137
PG
1605
1606 if (src_port && src_port->min_port)
1607 remaining_len += snprintf(buffer,
1608 sizeof(buffer),
1609 "from [%u:%u]",
1610 src_port->min_port,
1611 src_port->max_port ?
1612 src_port->max_port :
1613 src_port->min_port);
1614 if (dst_port && dst_port->min_port)
1615 remaining_len += snprintf(buffer +
1616 remaining_len,
1617 sizeof(buffer)
1618 - remaining_len,
1619 "to [%u:%u]",
1620 dst_port->min_port,
1621 dst_port->max_port ?
1622 dst_port->max_port :
1623 dst_port->min_port);
1624 }
1625 if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
1626 remaining_len += snprintf(buffer + remaining_len,
1627 sizeof(buffer)
1628 - remaining_len,
1629 " len [%u:%u]",
1630 pkt_len->min_port,
1631 pkt_len->max_port ?
1632 pkt_len->max_port :
1633 pkt_len->min_port);
cfaf18ce
PG
1634 } else if (bpf->pkt_len_val) {
1635 remaining_len += snprintf(buffer + remaining_len,
1636 sizeof(buffer)
1637 - remaining_len,
1638 " %s len %u",
1639 bpf->pkt_len_val->mask
1640 ? "!" : "",
1641 bpf->pkt_len_val->val);
538f0137 1642 }
2da7d62e
PG
1643 if (bpf->tcp_flags) {
1644 remaining_len += snprintf(buffer + remaining_len,
1645 sizeof(buffer)
1646 - remaining_len,
1647 "tcpflags %x/%x",
1648 bpf->tcp_flags->val,
1649 bpf->tcp_flags->mask);
1650 }
4977bd6c
PG
1651 if (bpf->dscp) {
1652 snprintf(buffer + remaining_len,
1653 sizeof(buffer)
1654 - remaining_len,
1655 "%s dscp %d",
1656 bpf->dscp->mask
1657 ? "!" : "",
1658 bpf->dscp->val);
1659 }
538f0137 1660 zlog_info("BGP: adding FS PBR from %s to %s, %s %s",
0e867886
PG
1661 bpf->src == NULL ? "<all>" :
1662 prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
1663 bpf->dst == NULL ? "<all>" :
1664 prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
538f0137
PG
1665 protocol_str, buffer);
1666 }
d114b0d7
PG
1667 /* look for bpa first */
1668 memset(&temp3, 0, sizeof(temp3));
1669 if (rate)
1670 temp3.rate = *rate;
1671 if (nh)
1672 memcpy(&temp3.nh, nh, sizeof(struct nexthop));
0e867886 1673 temp3.vrf_id = bpf->vrf_id;
d114b0d7
PG
1674 bpa = hash_get(bgp->pbr_action_hash, &temp3,
1675 bgp_pbr_action_alloc_intern);
1676
1677 if (bpa->fwmark == 0) {
d114b0d7
PG
1678 /* drop is handled by iptable */
1679 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
1680 bpa->table_id = 0;
1681 bpa->installed = true;
1682 } else {
31c28cd7
PG
1683 bpa->fwmark = bgp_zebra_tm_get_id();
1684 bpa->table_id = bpa->fwmark;
d114b0d7
PG
1685 bpa->installed = false;
1686 }
a6b07429 1687 bpa->bgp = bgp;
d114b0d7
PG
1688 bpa->unique = ++bgp_pbr_action_counter_unique;
1689 /* 0 value is forbidden */
1690 bpa->install_in_progress = false;
1691 }
1692
1693 /* then look for bpm */
1694 memset(&temp, 0, sizeof(temp));
0e867886 1695 if (bpf->src == NULL || bpf->dst == NULL) {
1de7dfff
PG
1696 if ((src_port && src_port->min_port) ||
1697 (dst_port && dst_port->min_port))
1698 temp.type = IPSET_NET_PORT;
1699 else
1700 temp.type = IPSET_NET;
1701 } else {
1702 if ((src_port && src_port->min_port) ||
1703 (dst_port && dst_port->min_port))
1704 temp.type = IPSET_NET_PORT_NET;
1705 else
1706 temp.type = IPSET_NET_NET;
1707 }
0e867886
PG
1708 temp.vrf_id = bpf->vrf_id;
1709 if (bpf->src)
d114b0d7 1710 temp.flags |= MATCH_IP_SRC_SET;
0e867886 1711 if (bpf->dst)
d114b0d7 1712 temp.flags |= MATCH_IP_DST_SET;
1de7dfff
PG
1713
1714 if (src_port && src_port->min_port)
1715 temp.flags |= MATCH_PORT_SRC_SET;
1716 if (dst_port && dst_port->min_port)
1717 temp.flags |= MATCH_PORT_DST_SET;
1718 if (src_port && src_port->max_port)
1719 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1720 if (dst_port && dst_port->max_port)
1721 temp.flags |= MATCH_PORT_DST_RANGE_SET;
cfaf18ce 1722 if (pkt_len) {
83360720 1723 temp.pkt_len_min = pkt_len->min_port;
cfaf18ce
PG
1724 if (pkt_len->max_port)
1725 temp.pkt_len_max = pkt_len->max_port;
1726 } else if (bpf->pkt_len_val) {
1727 if (bpf->pkt_len_val->mask)
1728 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
1729 temp.pkt_len_min = bpf->pkt_len_val->val;
1730 }
2da7d62e
PG
1731 if (bpf->tcp_flags) {
1732 temp.tcp_flags = bpf->tcp_flags->val;
1733 temp.tcp_mask_flags = bpf->tcp_flags->mask;
1734 }
4977bd6c
PG
1735 if (bpf->dscp) {
1736 if (bpf->dscp->mask)
1737 temp.flags |= MATCH_DSCP_INVERSE_SET;
1738 else
1739 temp.flags |= MATCH_DSCP_SET;
1740 temp.dscp_value = bpf->dscp->val;
1741 }
6f5617d8
PG
1742 if (bpf->fragment) {
1743 if (bpf->fragment->mask)
1744 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
1745 temp.fragment = bpf->fragment->val;
1746 }
d114b0d7
PG
1747 temp.action = bpa;
1748 bpm = hash_get(bgp->pbr_match_hash, &temp,
1749 bgp_pbr_match_alloc_intern);
1750
1751 /* new, then self allocate ipset_name and unique */
1752 if (bpm && bpm->unique == 0) {
1753 bpm->unique = ++bgp_pbr_match_counter_unique;
1754 /* 0 value is forbidden */
1755 sprintf(bpm->ipset_name, "match%p", bpm);
1756 bpm->entry_hash = hash_create_size(8,
1757 bgp_pbr_match_entry_hash_key,
1758 bgp_pbr_match_entry_hash_equal,
1759 "Match Entry Hash");
1760 bpm->installed = false;
1761
1762 /* unique2 should be updated too */
1763 bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
1764 bpm->installed_in_iptable = false;
1765 bpm->install_in_progress = false;
1766 bpm->install_iptable_in_progress = false;
1767 }
1768
1769 memset(&temp2, 0, sizeof(temp2));
0e867886
PG
1770 if (bpf->src)
1771 prefix_copy(&temp2.src, bpf->src);
d114b0d7
PG
1772 else
1773 temp2.src.family = AF_INET;
0e867886
PG
1774 if (bpf->dst)
1775 prefix_copy(&temp2.dst, bpf->dst);
d114b0d7
PG
1776 else
1777 temp2.dst.family = AF_INET;
1de7dfff
PG
1778 temp2.src_port_min = src_port ? src_port->min_port : 0;
1779 temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
1780 temp2.src_port_max = src_port ? src_port->max_port : 0;
1781 temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
0e867886 1782 temp2.proto = bpf->protocol;
d114b0d7
PG
1783 if (bpm)
1784 bpme = hash_get(bpm->entry_hash, &temp2,
1de7dfff 1785 bgp_pbr_match_entry_alloc_intern);
d114b0d7
PG
1786 if (bpme && bpme->unique == 0) {
1787 bpme->unique = ++bgp_pbr_match_entry_counter_unique;
1788 /* 0 value is forbidden */
1789 bpme->backpointer = bpm;
1790 bpme->installed = false;
1791 bpme->install_in_progress = false;
b588b642
PG
1792 /* link bgp info to bpme */
1793 bpme->bgp_info = (void *)binfo;
d114b0d7
PG
1794 }
1795
1796 /* BGP FS: append entry to zebra
1797 * - policies are not routing entries and as such
1798 * route replace semantics don't necessarily follow
1799 * through to policy entries
1800 * - because of that, not all policing information will be stored
1801 * into zebra. and non selected policies will be suppressed from zebra
1802 * - as consequence, in order to bring consistency
1803 * a policy will be added, then ifan ecmp policy exists,
1804 * it will be suppressed subsequently
1805 */
1806 /* ip rule add */
1a1f4a4c 1807 if (!bpa->installed && !bpa->install_in_progress) {
d114b0d7 1808 bgp_send_pbr_rule_action(bpa, true);
f7df1907
PG
1809 bgp_zebra_announce_default(bgp, nh,
1810 AFI_IP, bpa->table_id, true);
1811 }
d114b0d7
PG
1812
1813 /* ipset create */
1814 if (bpm && !bpm->installed)
1815 bgp_send_pbr_ipset_match(bpm, true);
1816 /* ipset add */
1817 if (bpme && !bpme->installed)
1818 bgp_send_pbr_ipset_entry_match(bpme, true);
1819
1820 /* iptables */
1821 if (bpm && !bpm->installed_in_iptable)
1822 bgp_send_pbr_iptable(bpa, bpm, true);
1823
1824 /* A previous entry may already exist
1825 * flush previous entry if necessary
1826 */
1827 bpmer.bpme_to_match = bpme;
1828 bpmer.bpme_found = NULL;
1829 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1830 if (bpmer.bpme_found) {
1831 static struct bgp_pbr_match *local_bpm;
1832 static struct bgp_pbr_action *local_bpa;
1833
1834 local_bpm = bpmer.bpme_found->backpointer;
1835 local_bpa = local_bpm->action;
1836 bgp_pbr_flush_entry(bgp, local_bpa,
1837 local_bpm, bpmer.bpme_found);
1838 }
1839
1840
1841}
1842
56707a36
PG
1843static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp *bgp,
1844 struct bgp_info *binfo,
1845 struct bgp_pbr_filter *bpf,
1846 struct bgp_pbr_or_filter *bpof,
1847 struct nexthop *nh,
1848 float *rate,
1849 uint8_t type_entry)
1850{
1851 struct listnode *node, *nnode;
1852 struct bgp_pbr_val_mask *valmask;
1853 uint8_t next_type_entry;
1854 struct list *orig_list;
1855 struct bgp_pbr_val_mask **target_val;
1856
1857 if (type_entry == 0)
1858 return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
1859 nh, rate);
e45aea59 1860 next_type_entry = bgp_pbr_next_type_entry(type_entry);
56707a36 1861 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
56707a36
PG
1862 orig_list = bpof->tcpflags;
1863 target_val = &bpf->tcp_flags;
1864 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
56707a36
PG
1865 orig_list = bpof->dscp;
1866 target_val = &bpf->dscp;
cfaf18ce 1867 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
cfaf18ce
PG
1868 orig_list = bpof->pkt_len;
1869 target_val = &bpf->pkt_len_val;
6f5617d8 1870 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
6f5617d8
PG
1871 orig_list = bpof->fragment;
1872 target_val = &bpf->fragment;
da3fa383
PG
1873 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
1874 (bpof->icmp_type || bpof->icmp_code)) {
1875 /* enumerate list for icmp - must be last one */
1876 bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, true, nh, rate);
1877 return;
56707a36
PG
1878 } else {
1879 return bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
e45aea59
PG
1880 bpf, bpof, nh, rate,
1881 next_type_entry);
56707a36
PG
1882 }
1883 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
1884 *target_val = valmask;
1885 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1886 bpf, bpof,
1887 nh, rate,
1888 next_type_entry);
1889 }
1890}
1891
9bba1455
PG
1892static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
1893 struct bgp_info *binfo,
1894 struct bgp_pbr_filter *bpf,
1895 struct bgp_pbr_or_filter *bpof,
1896 struct nexthop *nh,
1897 float *rate)
1898{
56707a36 1899 if (!bpof)
9bba1455
PG
1900 return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
1901 bpf, nh, rate);
56707a36
PG
1902 if (bpof->tcpflags)
1903 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1904 bpf, bpof,
1905 nh, rate,
1906 FLOWSPEC_TCP_FLAGS);
1907 else if (bpof->dscp)
1908 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1909 bpf, bpof,
1910 nh, rate,
1911 FLOWSPEC_DSCP);
cfaf18ce
PG
1912 else if (bpof->pkt_len)
1913 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1914 bpf, bpof,
1915 nh, rate,
1916 FLOWSPEC_PKT_LEN);
6f5617d8
PG
1917 else if (bpof->fragment)
1918 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1919 bpf, bpof,
1920 nh, rate,
1921 FLOWSPEC_FRAGMENT);
da3fa383
PG
1922 else if (bpof->icmp_type || bpof->icmp_code)
1923 bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
1924 bpf, bpof, nh, rate,
1925 FLOWSPEC_ICMP_TYPE);
56707a36
PG
1926 else
1927 bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
1928 nh, rate);
1929 /* flush bpof */
1930 if (bpof->tcpflags)
1931 list_delete_all_node(bpof->tcpflags);
1932 if (bpof->dscp)
1933 list_delete_all_node(bpof->dscp);
cfaf18ce
PG
1934 if (bpof->pkt_len)
1935 list_delete_all_node(bpof->pkt_len);
6f5617d8
PG
1936 if (bpof->fragment)
1937 list_delete_all_node(bpof->fragment);
da3fa383
PG
1938 if (bpof->icmp_type)
1939 list_delete_all_node(bpof->icmp_type);
1940 if (bpof->icmp_code)
1941 list_delete_all_node(bpof->icmp_code);
932404b7
PG
1942}
1943
d114b0d7
PG
1944static void bgp_pbr_handle_entry(struct bgp *bgp,
1945 struct bgp_info *binfo,
1946 struct bgp_pbr_entry_main *api,
1947 bool add)
1948{
1949 struct nexthop nh;
1950 int i = 0;
1951 int continue_loop = 1;
1952 float rate = 0;
1953 struct prefix *src = NULL, *dst = NULL;
1de7dfff
PG
1954 uint8_t proto = 0;
1955 struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
932404b7 1956 struct bgp_pbr_range_port range, range_icmp_code;
83360720 1957 struct bgp_pbr_range_port pkt_len;
0e867886 1958 struct bgp_pbr_filter bpf;
c5ee26cc
PG
1959 uint8_t kind_enum;
1960 struct bgp_pbr_or_filter bpof;
9bba1455 1961 struct bgp_pbr_val_mask bpvm;
d114b0d7 1962
8cda9106 1963 memset(&nh, 0, sizeof(struct nexthop));
0e867886 1964 memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
c5ee26cc 1965 memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
d114b0d7
PG
1966 if (api->match_bitmask & PREFIX_SRC_PRESENT)
1967 src = &api->src_prefix;
1968 if (api->match_bitmask & PREFIX_DST_PRESENT)
1969 dst = &api->dst_prefix;
1970 memset(&nh, 0, sizeof(struct nexthop));
1971 nh.vrf_id = VRF_UNKNOWN;
1de7dfff
PG
1972 if (api->match_protocol_num)
1973 proto = (uint8_t)api->protocol[0].value;
1974 /* if match_port is selected, then either src or dst port will be parsed
1975 * but not both at the same time
1976 */
1977 if (api->match_port_num >= 1) {
1978 bgp_pbr_extract(api->port,
1979 api->match_port_num,
1980 &range);
1981 srcp = dstp = &range;
1982 } else if (api->match_src_port_num >= 1) {
1983 bgp_pbr_extract(api->src_port,
1984 api->match_src_port_num,
1985 &range);
1986 srcp = &range;
1987 dstp = NULL;
1988 } else if (api->match_dst_port_num >= 1) {
1989 bgp_pbr_extract(api->dst_port,
1990 api->match_dst_port_num,
1991 &range);
1992 dstp = &range;
1993 srcp = NULL;
1994 }
932404b7
PG
1995 if (api->match_icmp_type_num >= 1) {
1996 proto = IPPROTO_ICMP;
da3fa383
PG
1997 if (bgp_pbr_extract(api->icmp_type,
1998 api->match_icmp_type_num,
1999 &range))
932404b7 2000 srcp = &range;
da3fa383
PG
2001 else {
2002 bpof.icmp_type = list_new();
2003 bgp_pbr_extract_enumerate(api->icmp_type,
2004 api->match_icmp_type_num,
2005 OPERATOR_UNARY_OR,
2006 bpof.icmp_type,
2007 FLOWSPEC_ICMP_TYPE);
932404b7
PG
2008 }
2009 }
2010 if (api->match_icmp_code_num >= 1) {
2011 proto = IPPROTO_ICMP;
da3fa383
PG
2012 if (bgp_pbr_extract(api->icmp_code,
2013 api->match_icmp_code_num,
2014 &range_icmp_code))
932404b7 2015 dstp = &range_icmp_code;
da3fa383
PG
2016 else {
2017 bpof.icmp_code = list_new();
2018 bgp_pbr_extract_enumerate(api->icmp_code,
2019 api->match_icmp_code_num,
2020 OPERATOR_UNARY_OR,
2021 bpof.icmp_code,
2022 FLOWSPEC_ICMP_CODE);
932404b7
PG
2023 }
2024 }
2da7d62e 2025
c5ee26cc
PG
2026 if (api->match_tcpflags_num) {
2027 kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
2028 api->match_tcpflags_num);
2029 if (kind_enum == OPERATOR_UNARY_AND) {
9bba1455 2030 bpf.tcp_flags = &bpvm;
c5ee26cc
PG
2031 bgp_pbr_extract_enumerate(api->tcpflags,
2032 api->match_tcpflags_num,
35703998
PG
2033 OPERATOR_UNARY_AND,
2034 bpf.tcp_flags,
2035 FLOWSPEC_TCP_FLAGS);
c5ee26cc
PG
2036 } else if (kind_enum == OPERATOR_UNARY_OR) {
2037 bpof.tcpflags = list_new();
2038 bgp_pbr_extract_enumerate(api->tcpflags,
2039 api->match_tcpflags_num,
35703998
PG
2040 OPERATOR_UNARY_OR,
2041 bpof.tcpflags,
2042 FLOWSPEC_TCP_FLAGS);
c5ee26cc
PG
2043 }
2044 }
cfaf18ce
PG
2045 if (api->match_packet_length_num) {
2046 bool ret;
2047
2048 ret = bgp_pbr_extract(api->packet_length,
2049 api->match_packet_length_num,
2050 &pkt_len);
2051 if (ret)
2052 bpf.pkt_len = &pkt_len;
2053 else {
2054 bpof.pkt_len = list_new();
2055 bgp_pbr_extract_enumerate(api->packet_length,
2056 api->match_packet_length_num,
2057 OPERATOR_UNARY_OR,
2058 bpof.pkt_len,
2059 FLOWSPEC_PKT_LEN);
2060 }
2da7d62e 2061 }
4977bd6c 2062 if (api->match_dscp_num >= 1) {
35703998
PG
2063 bpof.dscp = list_new();
2064 bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
2065 OPERATOR_UNARY_OR,
2066 bpof.dscp, FLOWSPEC_DSCP);
4977bd6c 2067 }
6f5617d8
PG
2068 if (api->match_fragment_num) {
2069 bpof.fragment = list_new();
2070 bgp_pbr_extract_enumerate(api->fragment,
2071 api->match_fragment_num,
2072 OPERATOR_UNARY_OR,
2073 bpof.fragment,
2074 FLOWSPEC_FRAGMENT);
2075 }
0e867886
PG
2076 bpf.vrf_id = api->vrf_id;
2077 bpf.src = src;
2078 bpf.dst = dst;
2079 bpf.protocol = proto;
0e867886
PG
2080 bpf.src_port = srcp;
2081 bpf.dst_port = dstp;
da3fa383 2082 if (!add)
932404b7
PG
2083 return bgp_pbr_policyroute_remove_from_zebra(bgp,
2084 binfo,
9bba1455 2085 &bpf, &bpof);
d114b0d7
PG
2086 /* no action for add = true */
2087 for (i = 0; i < api->action_num; i++) {
2088 switch (api->actions[i].action) {
2089 case ACTION_TRAFFICRATE:
2090 /* drop packet */
2091 if (api->actions[i].u.r.rate == 0) {
2092 nh.vrf_id = api->vrf_id;
2093 nh.type = NEXTHOP_TYPE_BLACKHOLE;
da3fa383
PG
2094 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
2095 &bpf, &bpof,
2096 &nh, &rate);
d114b0d7
PG
2097 } else {
2098 /* update rate. can be reentrant */
2099 rate = api->actions[i].u.r.rate;
ac7c35f8 2100 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2101 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2102 zlog_warn("PBR: ignoring Set action rate %f",
2103 api->actions[i].u.r.rate);
2104 }
d114b0d7
PG
2105 }
2106 break;
2107 case ACTION_TRAFFIC_ACTION:
2108 if (api->actions[i].u.za.filter
2109 & TRAFFIC_ACTION_SAMPLE) {
ac7c35f8 2110 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2111 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2112 zlog_warn("PBR: Sample action Ignored");
2113 }
d114b0d7
PG
2114 }
2115#if 0
2116 if (api->actions[i].u.za.filter
2117 & TRAFFIC_ACTION_DISTRIBUTE) {
ac7c35f8 2118 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2119 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2120 zlog_warn("PBR: Distribute action Applies");
2121 }
d114b0d7
PG
2122 continue_loop = 0;
2123 /* continue forwarding entry as before
2124 * no action
2125 */
2126 }
2127#endif /* XXX to confirm behaviour of traffic action. for now , ignore */
2128 /* terminate action: run other filters
2129 */
2130 break;
2131 case ACTION_REDIRECT_IP:
2132 nh.type = NEXTHOP_TYPE_IPV4;
2133 nh.gate.ipv4.s_addr =
2134 api->actions[i].u.zr.redirect_ip_v4.s_addr;
2135 nh.vrf_id = api->vrf_id;
da3fa383
PG
2136 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
2137 &bpf, &bpof,
2138 &nh, &rate);
d114b0d7
PG
2139 /* XXX combination with REDIRECT_VRF
2140 * + REDIRECT_NH_IP not done
2141 */
2142 continue_loop = 0;
2143 break;
2144 case ACTION_REDIRECT:
2145 nh.vrf_id = api->actions[i].u.redirect_vrf;
2146 nh.type = NEXTHOP_TYPE_IPV4;
da3fa383
PG
2147 bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
2148 &bpf, &bpof,
2149 &nh, &rate);
d114b0d7
PG
2150 continue_loop = 0;
2151 break;
2152 case ACTION_MARKING:
ac7c35f8 2153 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2154 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2155 zlog_warn("PBR: Set DSCP %u Ignored",
2156 api->actions[i].u.marking_dscp);
2157 }
d114b0d7
PG
2158 break;
2159 default:
2160 break;
2161 }
2162 if (continue_loop == 0)
2163 break;
2164 }
2165}
2166
45918cfb
PG
2167void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
2168 struct bgp_info *info, afi_t afi, safi_t safi,
2169 bool nlri_update)
2170{
2171 struct bgp_pbr_entry_main api;
6818e7e5 2172 struct bgp_info_extra *extra = bgp_info_extra_get(info);
45918cfb
PG
2173
2174 if (afi == AFI_IP6)
2175 return; /* IPv6 not supported */
2176 if (safi != SAFI_FLOWSPEC)
2177 return; /* not supported */
2178 /* Make Zebra API structure. */
2179 memset(&api, 0, sizeof(api));
2180 api.vrf_id = bgp->vrf_id;
2181 api.afi = afi;
2182
6818e7e5 2183 if (!bgp_zebra_tm_chunk_obtained()) {
f146bb54 2184 if (BGP_DEBUG(pbr, PBR_ERROR))
6818e7e5 2185 zlog_err("%s: table chunk not obtained yet",
f146bb54 2186 __func__);
6818e7e5
PG
2187 return;
2188 }
2189 /* already installed */
2190 if (nlri_update && extra->bgp_fs_pbr) {
2191 if (BGP_DEBUG(pbr, PBR_ERROR))
2192 zlog_err("%s: entry %p already installed in bgp pbr",
2193 __func__, info);
2194 return;
2195 }
2196
2197 if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
2198 if (BGP_DEBUG(pbr, PBR_ERROR))
2199 zlog_err("%s: cancel updating entry %p in bgp pbr",
2200 __func__, info);
45918cfb
PG
2201 return;
2202 }
d114b0d7 2203 bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
45918cfb 2204}
4762c213
PG
2205
2206int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
2207 const struct bgp_pbr_interface *b)
2208{
2209 return strcmp(a->name, b->name);
2210}
2211
2212struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
2213 struct bgp_pbr_interface_head *head)
2214{
2215 struct bgp_pbr_interface pbr_if;
2216
2217 strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
2218 return (RB_FIND(bgp_pbr_interface_head,
2219 head, &pbr_if));
2220}
2221
2222/* this function resets to the default policy routing
2223 * go back to default status
2224 */
2225void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
2226{
2227 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
2228 struct bgp_pbr_interface_head *head;
2229 struct bgp_pbr_interface *pbr_if;
2230
2231 if (!bgp_pbr_cfg || afi != AFI_IP)
2232 return;
2233 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
2234
2235 while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
2236 pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
2237 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
2238 XFREE(MTYPE_TMP, pbr_if);
2239 }
2240}