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