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