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