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