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