]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_pbr.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[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 }
d8bc11a5 1017 hash_clean_and_free(&bpm->entry_hash, NULL);
a6b07429
PG
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{
d8bc11a5
DS
1389 hash_clean_and_free(&bgp->pbr_match_hash, bgp_pbr_match_free);
1390 hash_clean_and_free(&bgp->pbr_rule_hash, bgp_pbr_rule_free);
1391 hash_clean_and_free(&bgp->pbr_action_hash, bgp_pbr_action_free);
1392
4762c213
PG
1393 if (bgp->bgp_pbr_cfg == NULL)
1394 return;
d8bc11a5 1395
4762c213 1396 bgp_pbr_reset(bgp, AFI_IP);
8f242187 1397 bgp_pbr_reset(bgp, AFI_IP6);
4762c213 1398 XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
a6b07429
PG
1399}
1400
f3d32faa
PG
1401void bgp_pbr_init(struct bgp *bgp)
1402{
1403 bgp->pbr_match_hash =
1404 hash_create_size(8, bgp_pbr_match_hash_key,
1405 bgp_pbr_match_hash_equal,
1406 "Match Hash");
1407 bgp->pbr_action_hash =
1408 hash_create_size(8, bgp_pbr_action_hash_key,
1409 bgp_pbr_action_hash_equal,
1410 "Match Hash Entry");
4762c213 1411
27e376d4
PG
1412 bgp->pbr_rule_hash =
1413 hash_create_size(8, bgp_pbr_rule_hash_key,
1414 bgp_pbr_rule_hash_equal,
1415 "Match Rule");
1416
4762c213
PG
1417 bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
1418 bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
f3d32faa 1419}
b46b6f1a
PG
1420
1421void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
1422{
1423 int i = 0;
1424 char return_string[512];
1425 char *ptr = return_string;
b46b6f1a 1426 int nb_items = 0;
9cec4121 1427 int delta, len = sizeof(return_string);
b46b6f1a 1428
9cec4121
PG
1429 delta = snprintf(ptr, sizeof(return_string), "MATCH : ");
1430 len -= delta;
1431 ptr += delta;
b46b6f1a
PG
1432 if (api->match_bitmask & PREFIX_SRC_PRESENT) {
1433 struct prefix *p = &(api->src_prefix);
1434
9cec4121 1435 if (api->src_prefix_offset)
2dbe669b
DA
1436 delta = snprintfrr(ptr, len, "@src %pFX/off%u", p,
1437 api->src_prefix_offset);
9cec4121 1438 else
2dbe669b 1439 delta = snprintfrr(ptr, len, "@src %pFX", p);
9cec4121
PG
1440 len -= delta;
1441 ptr += delta;
1442 INCREMENT_DISPLAY(ptr, nb_items, len);
b46b6f1a
PG
1443 }
1444 if (api->match_bitmask & PREFIX_DST_PRESENT) {
1445 struct prefix *p = &(api->dst_prefix);
1446
9cec4121
PG
1447 INCREMENT_DISPLAY(ptr, nb_items, len);
1448 if (api->dst_prefix_offset)
2dbe669b
DA
1449 delta = snprintfrr(ptr, len, "@dst %pFX/off%u", p,
1450 api->dst_prefix_offset);
9cec4121 1451 else
2dbe669b 1452 delta = snprintfrr(ptr, len, "@dst %pFX", p);
9cec4121
PG
1453 len -= delta;
1454 ptr += delta;
b46b6f1a
PG
1455 }
1456
1457 if (api->match_protocol_num)
9cec4121
PG
1458 INCREMENT_DISPLAY(ptr, nb_items, len);
1459 for (i = 0; i < api->match_protocol_num; i++) {
1460 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->protocol[i],
1461 i > 0 ? NULL : "@proto ");
1462 len -= delta;
1463 ptr += delta;
1464 }
b46b6f1a
PG
1465
1466 if (api->match_src_port_num)
9cec4121
PG
1467 INCREMENT_DISPLAY(ptr, nb_items, len);
1468 for (i = 0; i < api->match_src_port_num; i++) {
1469 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->src_port[i],
1470 i > 0 ? NULL : "@srcport ");
1471 len -= delta;
1472 ptr += delta;
1473 }
b46b6f1a
PG
1474
1475 if (api->match_dst_port_num)
9cec4121
PG
1476 INCREMENT_DISPLAY(ptr, nb_items, len);
1477 for (i = 0; i < api->match_dst_port_num; i++) {
1478 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dst_port[i],
1479 i > 0 ? NULL : "@dstport ");
1480 len -= delta;
1481 ptr += delta;
1482 }
b46b6f1a
PG
1483
1484 if (api->match_port_num)
9cec4121
PG
1485 INCREMENT_DISPLAY(ptr, nb_items, len);
1486 for (i = 0; i < api->match_port_num; i++) {
1487 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->port[i],
1488 i > 0 ? NULL : "@port ");
1489 len -= delta;
1490 ptr += delta;
1491 }
b46b6f1a
PG
1492
1493 if (api->match_icmp_type_num)
9cec4121
PG
1494 INCREMENT_DISPLAY(ptr, nb_items, len);
1495 for (i = 0; i < api->match_icmp_type_num; i++) {
1496 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_type[i],
1497 i > 0 ? NULL : "@icmptype ");
1498 len -= delta;
1499 ptr += delta;
1500 }
b46b6f1a
PG
1501
1502 if (api->match_icmp_code_num)
9cec4121
PG
1503 INCREMENT_DISPLAY(ptr, nb_items, len);
1504 for (i = 0; i < api->match_icmp_code_num; i++) {
1505 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_code[i],
1506 i > 0 ? NULL : "@icmpcode ");
1507 len -= delta;
1508 ptr += delta;
1509 }
b46b6f1a
PG
1510
1511 if (api->match_packet_length_num)
9cec4121
PG
1512 INCREMENT_DISPLAY(ptr, nb_items, len);
1513 for (i = 0; i < api->match_packet_length_num; i++) {
4371bf91
PG
1514 delta = snprintf_bgp_pbr_match_val(ptr, len,
1515 &api->packet_length[i],
9cec4121
PG
1516 i > 0 ? NULL : "@plen ");
1517 len -= delta;
1518 ptr += delta;
1519 }
b46b6f1a
PG
1520
1521 if (api->match_dscp_num)
9cec4121
PG
1522 INCREMENT_DISPLAY(ptr, nb_items, len);
1523 for (i = 0; i < api->match_dscp_num; i++) {
1524 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dscp[i],
1525 i > 0 ? NULL : "@dscp ");
1526 len -= delta;
1527 ptr += delta;
1528 }
b46b6f1a 1529
40881800
PG
1530 if (api->match_flowlabel_num)
1531 INCREMENT_DISPLAY(ptr, nb_items, len);
1532 for (i = 0; i < api->match_flowlabel_num; i++) {
4371bf91
PG
1533 delta = snprintf_bgp_pbr_match_val(ptr, len,
1534 &api->flow_label[i],
40881800
PG
1535 i > 0 ? NULL : "@flowlabel ");
1536 len -= delta;
1537 ptr += delta;
1538 }
1539
b46b6f1a 1540 if (api->match_tcpflags_num)
9cec4121
PG
1541 INCREMENT_DISPLAY(ptr, nb_items, len);
1542 for (i = 0; i < api->match_tcpflags_num; i++) {
1543 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->tcpflags[i],
1544 i > 0 ? NULL : "@tcpflags ");
1545 len -= delta;
1546 ptr += delta;
1547 }
b46b6f1a 1548
588ec356 1549 if (api->match_fragment_num)
9cec4121
PG
1550 INCREMENT_DISPLAY(ptr, nb_items, len);
1551 for (i = 0; i < api->match_fragment_num; i++) {
1552 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->fragment[i],
1553 i > 0 ? NULL : "@fragment ");
1554 len -= delta;
1555 ptr += delta;
1556 }
1557
1558 len = sizeof(return_string);
1559 if (!nb_items) {
b46b6f1a 1560 ptr = return_string;
9cec4121
PG
1561 } else {
1562 len -= (ptr - return_string);
1563 delta = snprintf(ptr, len, "; ");
1564 len -= delta;
1565 ptr += delta;
1566 }
1567 if (api->action_num) {
1568 delta = snprintf(ptr, len, "SET : ");
1569 len -= delta;
1570 ptr += delta;
1571 }
b46b6f1a
PG
1572 nb_items = 0;
1573 for (i = 0; i < api->action_num; i++) {
1574 switch (api->actions[i].action) {
1575 case ACTION_TRAFFICRATE:
9cec4121
PG
1576 INCREMENT_DISPLAY(ptr, nb_items, len);
1577 delta = snprintf(ptr, len, "@set rate %f",
1578 api->actions[i].u.r.rate);
1579 len -= delta;
1580 ptr += delta;
b46b6f1a
PG
1581 break;
1582 case ACTION_TRAFFIC_ACTION:
9cec4121
PG
1583 INCREMENT_DISPLAY(ptr, nb_items, len);
1584 delta = snprintf(ptr, len, "@action ");
1585 len -= delta;
1586 ptr += delta;
b46b6f1a 1587 if (api->actions[i].u.za.filter
9cec4121
PG
1588 & TRAFFIC_ACTION_TERMINATE) {
1589 delta = snprintf(ptr, len,
1590 " terminate (apply filter(s))");
1591 len -= delta;
1592 ptr += delta;
1593 }
b46b6f1a 1594 if (api->actions[i].u.za.filter
9cec4121
PG
1595 & TRAFFIC_ACTION_DISTRIBUTE) {
1596 delta = snprintf(ptr, len, " distribute");
1597 len -= delta;
1598 ptr += delta;
1599 }
b46b6f1a 1600 if (api->actions[i].u.za.filter
9cec4121
PG
1601 & TRAFFIC_ACTION_SAMPLE) {
1602 delta = snprintf(ptr, len, " sample");
1603 len -= delta;
1604 ptr += delta;
1605 }
b46b6f1a 1606 break;
f01e580f
PG
1607 case ACTION_REDIRECT_IP: {
1608 char local_buff[INET6_ADDRSTRLEN];
1609 void *ptr_ip;
b46b6f1a 1610
9cec4121 1611 INCREMENT_DISPLAY(ptr, nb_items, len);
f01e580f
PG
1612 if (api->afi == AF_INET)
1613 ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
1614 else
1615 ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
07380148
DA
1616 if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff,
1617 sizeof(local_buff)) != NULL) {
9cec4121 1618 delta = snprintf(ptr, len,
b46b6f1a 1619 "@redirect ip nh %s", local_buff);
9cec4121
PG
1620 len -= delta;
1621 ptr += delta;
f01e580f 1622 }
b46b6f1a 1623 break;
f01e580f 1624 }
137147c6
DS
1625 case ACTION_REDIRECT: {
1626 struct vrf *vrf;
1627
1628 vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf);
9cec4121
PG
1629 INCREMENT_DISPLAY(ptr, nb_items, len);
1630 delta = snprintf(ptr, len, "@redirect vrf %s(%u)",
1631 VRF_LOGNAME(vrf),
1632 api->actions[i].u.redirect_vrf);
1633 len -= delta;
1634 ptr += delta;
b46b6f1a 1635 break;
137147c6 1636 }
b46b6f1a 1637 case ACTION_MARKING:
9cec4121 1638 INCREMENT_DISPLAY(ptr, nb_items, len);
40881800 1639 delta = snprintf(ptr, len, "@set dscp/flowlabel %u",
9cec4121
PG
1640 api->actions[i].u.marking_dscp);
1641 len -= delta;
1642 ptr += delta;
b46b6f1a
PG
1643 break;
1644 default:
1645 break;
1646 }
1647 }
1648 zlog_info("%s", return_string);
1649}
45918cfb 1650
9350f1df
PG
1651static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa,
1652 struct bgp_pbr_rule *bpr)
1653{
1654 /* if bpr is null, do nothing
1655 */
1656 if (bpr == NULL)
1657 return;
1658 if (bpr->installed) {
1659 bgp_send_pbr_rule_action(bpa, bpr, false);
1660 bpr->installed = false;
1661 bpr->action->refcnt--;
1662 bpr->action = NULL;
ce3c0614
PG
1663 if (bpr->path) {
1664 struct bgp_path_info *path;
1665 struct bgp_path_info_extra *extra;
1666
1667 /* unlink path to bpme */
1668 path = (struct bgp_path_info *)bpr->path;
1669 extra = bgp_path_info_extra_get(path);
3e3708cb
PG
1670 if (extra->bgp_fs_iprule)
1671 listnode_delete(extra->bgp_fs_iprule, bpr);
ce3c0614
PG
1672 bpr->path = NULL;
1673 }
9350f1df
PG
1674 }
1675 hash_release(bgp->pbr_rule_hash, bpr);
ebd1a47c 1676 bgp_pbr_bpa_remove(bpa);
9350f1df
PG
1677}
1678
d114b0d7
PG
1679static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
1680 struct bgp_pbr_match *bpm,
1681 struct bgp_pbr_match_entry *bpme)
1682{
1683 /* if bpme is null, bpm is also null
1684 */
1685 if (bpme == NULL)
1686 return;
1687 /* ipset del entry */
1688 if (bpme->installed) {
1689 bgp_send_pbr_ipset_entry_match(bpme, false);
1690 bpme->installed = false;
1691 bpme->backpointer = NULL;
9b6d8fcf
DS
1692 if (bpme->path) {
1693 struct bgp_path_info *path;
4b7e6066 1694 struct bgp_path_info_extra *extra;
b588b642 1695
ce3c0614 1696 /* unlink path to bpme */
9b6d8fcf
DS
1697 path = (struct bgp_path_info *)bpme->path;
1698 extra = bgp_path_info_extra_get(path);
3e3708cb
PG
1699 if (extra->bgp_fs_pbr)
1700 listnode_delete(extra->bgp_fs_pbr, bpme);
9b6d8fcf 1701 bpme->path = NULL;
b588b642 1702 }
d114b0d7
PG
1703 }
1704 hash_release(bpm->entry_hash, bpme);
1705 if (hashcount(bpm->entry_hash) == 0) {
1706 /* delete iptable entry first */
1707 /* then delete ipset match */
1708 if (bpm->installed) {
1709 if (bpm->installed_in_iptable) {
1710 bgp_send_pbr_iptable(bpm->action,
1711 bpm, false);
1712 bpm->installed_in_iptable = false;
a6b07429 1713 bpm->action->refcnt--;
d114b0d7
PG
1714 }
1715 bgp_send_pbr_ipset_match(bpm, false);
1716 bpm->installed = false;
1717 bpm->action = NULL;
1718 }
1719 hash_release(bgp->pbr_match_hash, bpm);
1720 /* XXX release pbr_match_action if not used
1721 * note that drop does not need to call send_pbr_action
1722 */
1723 }
ebd1a47c 1724 bgp_pbr_bpa_remove(bpa);
d114b0d7
PG
1725}
1726
1727struct bgp_pbr_match_entry_remain {
1728 struct bgp_pbr_match_entry *bpme_to_match;
1729 struct bgp_pbr_match_entry *bpme_found;
1730};
1731
9350f1df
PG
1732struct bgp_pbr_rule_remain {
1733 struct bgp_pbr_rule *bpr_to_match;
1734 struct bgp_pbr_rule *bpr_found;
1735};
1736
e3b78da8 1737static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
9350f1df 1738{
e3b78da8 1739 struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data;
9350f1df
PG
1740 struct bgp_pbr_rule_remain *ctxt =
1741 (struct bgp_pbr_rule_remain *)arg;
1742 struct bgp_pbr_rule *r2;
1743
1744 r2 = ctxt->bpr_to_match;
1745
1746 if (r1->vrf_id != r2->vrf_id)
1747 return HASHWALK_CONTINUE;
1748
1749 if (r1->flags != r2->flags)
1750 return HASHWALK_CONTINUE;
1751
1752 if ((r1->flags & MATCH_IP_SRC_SET) &&
1753 !prefix_same(&r1->src, &r2->src))
1754 return HASHWALK_CONTINUE;
1755
1756 if ((r1->flags & MATCH_IP_DST_SET) &&
1757 !prefix_same(&r1->dst, &r2->dst))
1758 return HASHWALK_CONTINUE;
1759
1760 /* this function is used for two cases:
1761 * - remove an entry upon withdraw request
1762 * (case r2->action is null)
1763 * - replace an old iprule with different action
1764 * (case r2->action is != null)
1765 * the old one is removed after the new one
1766 * this is to avoid disruption in traffic
1767 */
1768 if (r2->action == NULL ||
1769 r1->action != r2->action) {
1770 ctxt->bpr_found = r1;
1771 return HASHWALK_ABORT;
1772 }
1773 return HASHWALK_CONTINUE;
1774}
1775
e3b78da8 1776static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg)
d114b0d7 1777{
e3b78da8 1778 struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
d114b0d7
PG
1779 struct bgp_pbr_match_entry_remain *bpmer =
1780 (struct bgp_pbr_match_entry_remain *)arg;
1781 struct bgp_pbr_match *bpm_temp;
1782 struct bgp_pbr_match_entry *bpme = bpmer->bpme_to_match;
1783
1784 if (!bpme->backpointer ||
1785 bpm == bpme->backpointer ||
1786 bpme->backpointer->action == bpm->action)
1787 return HASHWALK_CONTINUE;
1788 /* ensure bpm other characteristics are equal */
1789 bpm_temp = bpme->backpointer;
1790 if (bpm_temp->vrf_id != bpm->vrf_id ||
1791 bpm_temp->type != bpm->type ||
836b6953
PG
1792 bpm_temp->flags != bpm->flags ||
1793 bpm_temp->tcp_flags != bpm->tcp_flags ||
1794 bpm_temp->tcp_mask_flags != bpm->tcp_mask_flags ||
1795 bpm_temp->pkt_len_min != bpm->pkt_len_min ||
1796 bpm_temp->pkt_len_max != bpm->pkt_len_max ||
1797 bpm_temp->dscp_value != bpm->dscp_value ||
40881800 1798 bpm_temp->flow_label != bpm->flow_label ||
a60b7031 1799 bpm_temp->family != bpm->family ||
836b6953 1800 bpm_temp->fragment != bpm->fragment)
d114b0d7
PG
1801 return HASHWALK_CONTINUE;
1802
1803 /* look for remaining bpme */
1804 bpmer->bpme_found = hash_lookup(bpm->entry_hash, bpme);
1805 if (!bpmer->bpme_found)
1806 return HASHWALK_CONTINUE;
1807 return HASHWALK_ABORT;
1808}
1809
9b6d8fcf
DS
1810static void bgp_pbr_policyroute_remove_from_zebra_unit(
1811 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf)
d114b0d7
PG
1812{
1813 struct bgp_pbr_match temp;
1814 struct bgp_pbr_match_entry temp2;
9350f1df
PG
1815 struct bgp_pbr_rule pbr_rule;
1816 struct bgp_pbr_rule *bpr;
d114b0d7
PG
1817 struct bgp_pbr_match *bpm;
1818 struct bgp_pbr_match_entry *bpme;
1819 struct bgp_pbr_match_entry_remain bpmer;
0e867886
PG
1820 struct bgp_pbr_range_port *src_port;
1821 struct bgp_pbr_range_port *dst_port;
1822 struct bgp_pbr_range_port *pkt_len;
9350f1df 1823 struct bgp_pbr_rule_remain bprr;
0e867886
PG
1824
1825 if (!bpf)
1826 return;
1827 src_port = bpf->src_port;
1828 dst_port = bpf->dst_port;
1829 pkt_len = bpf->pkt_len;
d114b0d7 1830
064a9d52
PG
1831 if (BGP_DEBUG(zebra, ZEBRA))
1832 bgp_pbr_dump_entry(bpf, false);
1833
d114b0d7
PG
1834 /* as we don't know information from EC
1835 * look for bpm that have the bpm
1836 * with vrf_id characteristics
1837 */
1838 memset(&temp2, 0, sizeof(temp2));
1839 memset(&temp, 0, sizeof(temp));
9350f1df
PG
1840
1841 if (bpf->type == BGP_PBR_IPRULE) {
1842 memset(&pbr_rule, 0, sizeof(pbr_rule));
1843 pbr_rule.vrf_id = bpf->vrf_id;
1844 if (bpf->src) {
1845 prefix_copy(&pbr_rule.src, bpf->src);
1846 pbr_rule.flags |= MATCH_IP_SRC_SET;
1847 }
1848 if (bpf->dst) {
1849 prefix_copy(&pbr_rule.dst, bpf->dst);
1850 pbr_rule.flags |= MATCH_IP_DST_SET;
1851 }
1852 bpr = &pbr_rule;
1853 /* A previous entry may already exist
1854 * flush previous entry if necessary
1855 */
1856 bprr.bpr_to_match = bpr;
1857 bprr.bpr_found = NULL;
1858 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
1859 if (bprr.bpr_found) {
1860 static struct bgp_pbr_rule *local_bpr;
1861 static struct bgp_pbr_action *local_bpa;
1862
1863 local_bpr = bprr.bpr_found;
1864 local_bpa = local_bpr->action;
1865 bgp_pbr_flush_iprule(bgp, local_bpa,
1866 local_bpr);
1867 }
1868 return;
1869 }
1870
a60b7031 1871 temp.family = bpf->family;
0e867886 1872 if (bpf->src) {
d114b0d7 1873 temp.flags |= MATCH_IP_SRC_SET;
0e867886 1874 prefix_copy(&temp2.src, bpf->src);
d114b0d7 1875 } else
f01e580f 1876 temp2.src.family = bpf->family;
0e867886 1877 if (bpf->dst) {
d114b0d7 1878 temp.flags |= MATCH_IP_DST_SET;
0e867886 1879 prefix_copy(&temp2.dst, bpf->dst);
d114b0d7 1880 } else
f01e580f 1881 temp2.dst.family = bpf->family;
3bed2363
PG
1882 if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
1883 if (bpf->protocol == IPPROTO_ICMP)
1884 temp.flags |= MATCH_ICMP_SET;
1de7dfff
PG
1885 temp.flags |= MATCH_PORT_SRC_SET;
1886 temp2.src_port_min = src_port->min_port;
1887 if (src_port->max_port) {
1888 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
1889 temp2.src_port_max = src_port->max_port;
1890 }
1891 }
3bed2363
PG
1892 if (dst_port && (dst_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_DST_SET;
1896 temp2.dst_port_min = dst_port->min_port;
1897 if (dst_port->max_port) {
1898 temp.flags |= MATCH_PORT_DST_RANGE_SET;
1899 temp2.dst_port_max = dst_port->max_port;
1900 }
1901 }
0e867886 1902 temp2.proto = bpf->protocol;
1de7dfff 1903
cfaf18ce 1904 if (pkt_len) {
83360720 1905 temp.pkt_len_min = pkt_len->min_port;
cfaf18ce
PG
1906 if (pkt_len->max_port)
1907 temp.pkt_len_max = pkt_len->max_port;
1908 } else if (bpf->pkt_len_val) {
1909 if (bpf->pkt_len_val->mask)
1910 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
1911 temp.pkt_len_min = bpf->pkt_len_val->val;
1912 }
2da7d62e
PG
1913 if (bpf->tcp_flags) {
1914 temp.tcp_flags = bpf->tcp_flags->val;
1915 temp.tcp_mask_flags = bpf->tcp_flags->mask;
1916 }
4977bd6c
PG
1917 if (bpf->dscp) {
1918 if (bpf->dscp->mask)
1919 temp.flags |= MATCH_DSCP_INVERSE_SET;
1920 else
1921 temp.flags |= MATCH_DSCP_SET;
1922 temp.dscp_value = bpf->dscp->val;
1923 }
40881800
PG
1924 if (bpf->flow_label) {
1925 if (bpf->flow_label->mask)
1926 temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
1927 else
1928 temp.flags |= MATCH_FLOW_LABEL_SET;
1929 temp.flow_label = bpf->flow_label->val;
1930 }
1931
6f5617d8
PG
1932 if (bpf->fragment) {
1933 if (bpf->fragment->mask)
1934 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
1935 temp.fragment = bpf->fragment->val;
1936 }
83360720 1937
0e867886 1938 if (bpf->src == NULL || bpf->dst == NULL) {
1de7dfff
PG
1939 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1940 temp.type = IPSET_NET_PORT;
1941 else
1942 temp.type = IPSET_NET;
1943 } else {
1944 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
1945 temp.type = IPSET_NET_PORT_NET;
1946 else
1947 temp.type = IPSET_NET_NET;
1948 }
0e867886 1949 if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
946de1b9 1950 temp.vrf_id = VRF_DEFAULT;
d114b0d7 1951 else
0e867886 1952 temp.vrf_id = bpf->vrf_id;
d114b0d7
PG
1953 bpme = &temp2;
1954 bpm = &temp;
1955 bpme->backpointer = bpm;
1956 /* right now, a previous entry may already exist
1957 * flush previous entry if necessary
1958 */
1959 bpmer.bpme_to_match = bpme;
1960 bpmer.bpme_found = NULL;
1961 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
1962 if (bpmer.bpme_found) {
1963 static struct bgp_pbr_match *local_bpm;
1964 static struct bgp_pbr_action *local_bpa;
1965
1966 local_bpm = bpmer.bpme_found->backpointer;
1967 local_bpa = local_bpm->action;
1968 bgp_pbr_flush_entry(bgp, local_bpa,
1969 local_bpm, bpmer.bpme_found);
1970 }
1971}
1972
e45aea59
PG
1973static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
1974{
1975 if (type_entry == FLOWSPEC_TCP_FLAGS)
1976 return FLOWSPEC_DSCP;
1977 if (type_entry == FLOWSPEC_DSCP)
40881800
PG
1978 return FLOWSPEC_FLOW_LABEL;
1979 if (type_entry == FLOWSPEC_FLOW_LABEL)
e45aea59
PG
1980 return FLOWSPEC_PKT_LEN;
1981 if (type_entry == FLOWSPEC_PKT_LEN)
1982 return FLOWSPEC_FRAGMENT;
da3fa383
PG
1983 if (type_entry == FLOWSPEC_FRAGMENT)
1984 return FLOWSPEC_ICMP_TYPE;
e45aea59
PG
1985 return 0;
1986}
1987
9b6d8fcf 1988static void bgp_pbr_icmp_action(struct bgp *bgp, struct bgp_path_info *path,
4b7e6066
DS
1989 struct bgp_pbr_filter *bpf,
1990 struct bgp_pbr_or_filter *bpof, bool add,
1991 struct nexthop *nh, float *rate)
da3fa383
PG
1992{
1993 struct bgp_pbr_range_port srcp, dstp;
1994 struct bgp_pbr_val_mask *icmp_type, *icmp_code;
1995 struct listnode *tnode, *cnode;
1996
1997 if (!bpf)
1998 return;
1999 if (bpf->protocol != IPPROTO_ICMP)
2000 return;
60031a55
DS
2001
2002 memset(&srcp, 0, sizeof(srcp));
2003 memset(&dstp, 0, sizeof(dstp));
da3fa383
PG
2004 bpf->src_port = &srcp;
2005 bpf->dst_port = &dstp;
2006 /* parse icmp type and lookup appropriate icmp code
2007 * if no icmp code found, create as many entryes as
2008 * there are listed icmp codes for that icmp type
2009 */
2010 if (!bpof->icmp_type) {
2011 srcp.min_port = 0;
2012 srcp.max_port = 255;
2013 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
2014 dstp.min_port = icmp_code->val;
2015 if (add)
9b6d8fcf
DS
2016 bgp_pbr_policyroute_add_to_zebra_unit(
2017 bgp, path, bpf, nh, rate);
da3fa383
PG
2018 else
2019 bgp_pbr_policyroute_remove_from_zebra_unit(
9b6d8fcf 2020 bgp, path, bpf);
da3fa383
PG
2021 }
2022 return;
2023 }
2024 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
2025 srcp.min_port = icmp_type->val;
2026 srcp.max_port = 0;
2027 dstp.max_port = 0;
2028 /* only icmp type. create an entry only with icmp type */
2029 if (!bpof->icmp_code) {
2030 /* icmp type is not one of the above
2031 * forge an entry only based on the icmp type
2032 */
2033 dstp.min_port = 0;
2034 dstp.max_port = 255;
2035 if (add)
2036 bgp_pbr_policyroute_add_to_zebra_unit(
9b6d8fcf 2037 bgp, path, bpf, nh, rate);
da3fa383 2038 else
9b6d8fcf
DS
2039 bgp_pbr_policyroute_remove_from_zebra_unit(
2040 bgp, path, bpf);
da3fa383
PG
2041 continue;
2042 }
2043 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
2044 dstp.min_port = icmp_code->val;
2045 if (add)
2046 bgp_pbr_policyroute_add_to_zebra_unit(
9b6d8fcf 2047 bgp, path, bpf, nh, rate);
da3fa383
PG
2048 else
2049 bgp_pbr_policyroute_remove_from_zebra_unit(
9b6d8fcf 2050 bgp, path, bpf);
da3fa383
PG
2051 }
2052 }
c34a7afc
DL
2053
2054 bpf->src_port = NULL;
2055 bpf->dst_port = NULL;
da3fa383
PG
2056}
2057
4b7e6066 2058static void bgp_pbr_policyroute_remove_from_zebra_recursive(
9b6d8fcf
DS
2059 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2060 struct bgp_pbr_or_filter *bpof, uint8_t type_entry)
56707a36
PG
2061{
2062 struct listnode *node, *nnode;
2063 struct bgp_pbr_val_mask *valmask;
2064 uint8_t next_type_entry;
2065 struct list *orig_list;
2066 struct bgp_pbr_val_mask **target_val;
2067
d90b788e
A
2068 if (type_entry == 0) {
2069 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
2070 return;
2071 }
e45aea59 2072 next_type_entry = bgp_pbr_next_type_entry(type_entry);
56707a36 2073 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
56707a36
PG
2074 orig_list = bpof->tcpflags;
2075 target_val = &bpf->tcp_flags;
2076 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
56707a36
PG
2077 orig_list = bpof->dscp;
2078 target_val = &bpf->dscp;
40881800
PG
2079 } else if (type_entry == FLOWSPEC_FLOW_LABEL && bpof->flowlabel) {
2080 orig_list = bpof->flowlabel;
2081 target_val = &bpf->flow_label;
cfaf18ce 2082 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
cfaf18ce
PG
2083 orig_list = bpof->pkt_len;
2084 target_val = &bpf->pkt_len_val;
6f5617d8 2085 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
6f5617d8
PG
2086 orig_list = bpof->fragment;
2087 target_val = &bpf->fragment;
da3fa383
PG
2088 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
2089 (bpof->icmp_type || bpof->icmp_code)) {
2090 /* enumerate list for icmp - must be last one */
9b6d8fcf 2091 bgp_pbr_icmp_action(bgp, path, bpf, bpof, false, NULL, NULL);
da3fa383 2092 return;
56707a36 2093 } else {
d90b788e 2094 bgp_pbr_policyroute_remove_from_zebra_recursive(
9b6d8fcf 2095 bgp, path, bpf, bpof, next_type_entry);
d90b788e 2096 return;
56707a36
PG
2097 }
2098 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
2099 *target_val = valmask;
9b6d8fcf
DS
2100 bgp_pbr_policyroute_remove_from_zebra_recursive(
2101 bgp, path, bpf, bpof, next_type_entry);
56707a36
PG
2102 }
2103}
2104
4b7e6066 2105static void bgp_pbr_policyroute_remove_from_zebra(
9b6d8fcf
DS
2106 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2107 struct bgp_pbr_or_filter *bpof)
9bba1455 2108{
d90b788e
A
2109 if (!bpof) {
2110 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
2111 return;
2112 }
56707a36 2113 if (bpof->tcpflags)
9b6d8fcf
DS
2114 bgp_pbr_policyroute_remove_from_zebra_recursive(
2115 bgp, path, bpf, bpof, FLOWSPEC_TCP_FLAGS);
56707a36 2116 else if (bpof->dscp)
9b6d8fcf
DS
2117 bgp_pbr_policyroute_remove_from_zebra_recursive(
2118 bgp, path, bpf, bpof, FLOWSPEC_DSCP);
40881800
PG
2119 else if (bpof->flowlabel)
2120 bgp_pbr_policyroute_remove_from_zebra_recursive(
2121 bgp, path, bpf, bpof, FLOWSPEC_FLOW_LABEL);
cfaf18ce 2122 else if (bpof->pkt_len)
9b6d8fcf
DS
2123 bgp_pbr_policyroute_remove_from_zebra_recursive(
2124 bgp, path, bpf, bpof, FLOWSPEC_PKT_LEN);
6f5617d8 2125 else if (bpof->fragment)
9b6d8fcf
DS
2126 bgp_pbr_policyroute_remove_from_zebra_recursive(
2127 bgp, path, bpf, bpof, FLOWSPEC_FRAGMENT);
da3fa383 2128 else if (bpof->icmp_type || bpof->icmp_code)
9b6d8fcf
DS
2129 bgp_pbr_policyroute_remove_from_zebra_recursive(
2130 bgp, path, bpf, bpof, FLOWSPEC_ICMP_TYPE);
56707a36 2131 else
9b6d8fcf 2132 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
56707a36
PG
2133 /* flush bpof */
2134 if (bpof->tcpflags)
2135 list_delete_all_node(bpof->tcpflags);
2136 if (bpof->dscp)
2137 list_delete_all_node(bpof->dscp);
40881800
PG
2138 if (bpof->flowlabel)
2139 list_delete_all_node(bpof->flowlabel);
cfaf18ce
PG
2140 if (bpof->pkt_len)
2141 list_delete_all_node(bpof->pkt_len);
6f5617d8
PG
2142 if (bpof->fragment)
2143 list_delete_all_node(bpof->fragment);
9bba1455
PG
2144}
2145
064a9d52
PG
2146static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add)
2147{
2148 struct bgp_pbr_range_port *src_port;
2149 struct bgp_pbr_range_port *dst_port;
2150 struct bgp_pbr_range_port *pkt_len;
2151 char bufsrc[64], bufdst[64];
2152 char buffer[64];
2153 int remaining_len = 0;
2154 char protocol_str[16];
2155
2156 if (!bpf)
2157 return;
2158 src_port = bpf->src_port;
2159 dst_port = bpf->dst_port;
2160 pkt_len = bpf->pkt_len;
2161
2162 protocol_str[0] = '\0';
2163 if (bpf->tcp_flags && bpf->tcp_flags->mask)
2164 bpf->protocol = IPPROTO_TCP;
2165 if (bpf->protocol)
2166 snprintf(protocol_str, sizeof(protocol_str),
2167 "proto %d", bpf->protocol);
2168 buffer[0] = '\0';
2169 if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
2170 remaining_len += snprintf(buffer, sizeof(buffer),
2171 "type %d, code %d",
2172 src_port->min_port,
2173 dst_port->min_port);
2174 else if (bpf->protocol == IPPROTO_UDP ||
2175 bpf->protocol == IPPROTO_TCP) {
2176
2177 if (src_port && src_port->min_port)
2178 remaining_len += snprintf(buffer,
2179 sizeof(buffer),
2180 "from [%u:%u]",
2181 src_port->min_port,
2182 src_port->max_port ?
2183 src_port->max_port :
2184 src_port->min_port);
2185 if (dst_port && dst_port->min_port)
2186 remaining_len += snprintf(buffer +
2187 remaining_len,
2188 sizeof(buffer)
2189 - remaining_len,
2190 "to [%u:%u]",
2191 dst_port->min_port,
2192 dst_port->max_port ?
2193 dst_port->max_port :
2194 dst_port->min_port);
2195 }
2196 if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
2197 remaining_len += snprintf(buffer + remaining_len,
2198 sizeof(buffer)
2199 - remaining_len,
2200 " len [%u:%u]",
2201 pkt_len->min_port,
2202 pkt_len->max_port ?
2203 pkt_len->max_port :
2204 pkt_len->min_port);
2205 } else if (bpf->pkt_len_val) {
2206 remaining_len += snprintf(buffer + remaining_len,
2207 sizeof(buffer)
2208 - remaining_len,
2209 " %s len %u",
2210 bpf->pkt_len_val->mask
2211 ? "!" : "",
2212 bpf->pkt_len_val->val);
2213 }
2214 if (bpf->tcp_flags) {
2215 remaining_len += snprintf(buffer + remaining_len,
2216 sizeof(buffer)
2217 - remaining_len,
2218 "tcpflags %x/%x",
2219 bpf->tcp_flags->val,
2220 bpf->tcp_flags->mask);
2221 }
2222 if (bpf->dscp) {
2223 snprintf(buffer + remaining_len,
2224 sizeof(buffer)
2225 - remaining_len,
2226 "%s dscp %d",
2227 bpf->dscp->mask
2228 ? "!" : "",
2229 bpf->dscp->val);
2230 }
40881800
PG
2231 if (bpf->flow_label) {
2232 snprintf(buffer + remaining_len,
2233 sizeof(buffer)
2234 - remaining_len,
2235 "%s flow_label %d",
2236 bpf->flow_label->mask
2237 ? "!" : "",
2238 bpf->flow_label->val);
2239 }
45837bc4 2240 zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
064a9d52
PG
2241 add ? "adding" : "removing",
2242 bpf->src == NULL ? "<all>" :
2243 prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
2244 bpf->dst == NULL ? "<all>" :
2245 prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
2246 protocol_str, buffer);
2247
2248}
2249
9bba1455 2250static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
9b6d8fcf 2251 struct bgp_path_info *path,
4b7e6066
DS
2252 struct bgp_pbr_filter *bpf,
2253 struct nexthop *nh,
2254 float *rate)
d114b0d7
PG
2255{
2256 struct bgp_pbr_match temp;
2257 struct bgp_pbr_match_entry temp2;
2258 struct bgp_pbr_match *bpm;
2259 struct bgp_pbr_match_entry *bpme = NULL;
2260 struct bgp_pbr_action temp3;
2261 struct bgp_pbr_action *bpa = NULL;
2262 struct bgp_pbr_match_entry_remain bpmer;
9350f1df 2263 struct bgp_pbr_rule_remain bprr;
0e867886
PG
2264 struct bgp_pbr_range_port *src_port;
2265 struct bgp_pbr_range_port *dst_port;
2266 struct bgp_pbr_range_port *pkt_len;
9350f1df
PG
2267 struct bgp_pbr_rule pbr_rule;
2268 struct bgp_pbr_rule *bpr;
ce3c0614 2269 bool bpr_found = false;
c26edcda 2270 bool bpme_found = false;
7afeaffa 2271 struct vrf *vrf = NULL;
0e867886
PG
2272
2273 if (!bpf)
2274 return;
2275 src_port = bpf->src_port;
2276 dst_port = bpf->dst_port;
2277 pkt_len = bpf->pkt_len;
d114b0d7 2278
064a9d52
PG
2279 if (BGP_DEBUG(zebra, ZEBRA))
2280 bgp_pbr_dump_entry(bpf, true);
2281
d114b0d7
PG
2282 /* look for bpa first */
2283 memset(&temp3, 0, sizeof(temp3));
2284 if (rate)
2285 temp3.rate = *rate;
2286 if (nh)
2287 memcpy(&temp3.nh, nh, sizeof(struct nexthop));
0e867886 2288 temp3.vrf_id = bpf->vrf_id;
f01e580f 2289 temp3.afi = family2afi(bpf->family);
d114b0d7
PG
2290 bpa = hash_get(bgp->pbr_action_hash, &temp3,
2291 bgp_pbr_action_alloc_intern);
2292
7afeaffa
PG
2293 if (nh)
2294 vrf = vrf_lookup_by_id(nh->vrf_id);
d114b0d7 2295 if (bpa->fwmark == 0) {
d114b0d7
PG
2296 /* drop is handled by iptable */
2297 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
2298 bpa->table_id = 0;
2299 bpa->installed = true;
2300 } else {
31c28cd7 2301 bpa->fwmark = bgp_zebra_tm_get_id();
7afeaffa
PG
2302 /* if action is redirect-vrf, then
2303 * use directly table_id of vrf
2304 */
2305 if (nh && vrf && !vrf_is_backend_netns()
2306 && bpf->vrf_id != vrf->vrf_id)
2307 bpa->table_id = vrf->data.l.table_id;
2308 else
2309 bpa->table_id = bpa->fwmark;
d114b0d7
PG
2310 bpa->installed = false;
2311 }
a6b07429 2312 bpa->bgp = bgp;
d114b0d7
PG
2313 bpa->unique = ++bgp_pbr_action_counter_unique;
2314 /* 0 value is forbidden */
2315 bpa->install_in_progress = false;
2316 }
9350f1df
PG
2317 if (bpf->type == BGP_PBR_IPRULE) {
2318 memset(&pbr_rule, 0, sizeof(pbr_rule));
2319 pbr_rule.vrf_id = bpf->vrf_id;
8112a7a0 2320 pbr_rule.priority = 20;
9350f1df
PG
2321 if (bpf->src) {
2322 pbr_rule.flags |= MATCH_IP_SRC_SET;
2323 prefix_copy(&pbr_rule.src, bpf->src);
2324 }
2325 if (bpf->dst) {
2326 pbr_rule.flags |= MATCH_IP_DST_SET;
2327 prefix_copy(&pbr_rule.dst, bpf->dst);
2328 }
2329 pbr_rule.action = bpa;
2330 bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule,
2331 bgp_pbr_rule_alloc_intern);
8e3aae66 2332 if (bpr->unique == 0) {
9350f1df
PG
2333 bpr->unique = ++bgp_pbr_action_counter_unique;
2334 bpr->installed = false;
2335 bpr->install_in_progress = false;
ce3c0614
PG
2336 /* link bgp info to bpr */
2337 bpr->path = (void *)path;
2338 } else
2339 bpr_found = true;
2340 /* already installed */
8e3aae66 2341 if (bpr_found) {
ce3c0614
PG
2342 struct bgp_path_info_extra *extra =
2343 bgp_path_info_extra_get(path);
2344
e0c7edb0
PG
2345 if (extra &&
2346 listnode_lookup_nocheck(extra->bgp_fs_iprule,
2347 bpr)) {
ce3c0614 2348 if (BGP_DEBUG(pbr, PBR_ERROR))
3efd0893 2349 zlog_err("%s: entry %p/%p already installed in bgp pbr iprule",
ce3c0614
PG
2350 __func__, path, bpr);
2351 return;
2352 }
9350f1df 2353 }
db1fcc98
DS
2354
2355 bgp_pbr_bpa_add(bpa);
2356
9350f1df 2357 /* ip rule add */
8e3aae66 2358 if (!bpr->installed)
9350f1df 2359 bgp_send_pbr_rule_action(bpa, bpr, true);
d114b0d7 2360
9350f1df
PG
2361 /* A previous entry may already exist
2362 * flush previous entry if necessary
2363 */
2364 bprr.bpr_to_match = bpr;
2365 bprr.bpr_found = NULL;
2366 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
2367 if (bprr.bpr_found) {
2368 static struct bgp_pbr_rule *local_bpr;
2369 static struct bgp_pbr_action *local_bpa;
2370
2371 local_bpr = bprr.bpr_found;
2372 local_bpa = local_bpr->action;
2373 bgp_pbr_flush_iprule(bgp, local_bpa,
2374 local_bpr);
2375 }
2376 return;
2377 }
d114b0d7
PG
2378 /* then look for bpm */
2379 memset(&temp, 0, sizeof(temp));
0e867886 2380 temp.vrf_id = bpf->vrf_id;
a60b7031 2381 temp.family = bpf->family;
0e867886 2382 if (bpf->src)
d114b0d7 2383 temp.flags |= MATCH_IP_SRC_SET;
0e867886 2384 if (bpf->dst)
d114b0d7 2385 temp.flags |= MATCH_IP_DST_SET;
1de7dfff 2386
3bed2363
PG
2387 if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2388 if (bpf->protocol == IPPROTO_ICMP)
2389 temp.flags |= MATCH_ICMP_SET;
1de7dfff 2390 temp.flags |= MATCH_PORT_SRC_SET;
3bed2363
PG
2391 }
2392 if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
2393 if (bpf->protocol == IPPROTO_ICMP)
2394 temp.flags |= MATCH_ICMP_SET;
1de7dfff 2395 temp.flags |= MATCH_PORT_DST_SET;
3bed2363 2396 }
1de7dfff
PG
2397 if (src_port && src_port->max_port)
2398 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
2399 if (dst_port && dst_port->max_port)
2400 temp.flags |= MATCH_PORT_DST_RANGE_SET;
3bed2363
PG
2401
2402 if (bpf->src == NULL || bpf->dst == NULL) {
2403 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2404 temp.type = IPSET_NET_PORT;
2405 else
2406 temp.type = IPSET_NET;
2407 } else {
2408 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
2409 temp.type = IPSET_NET_PORT_NET;
2410 else
2411 temp.type = IPSET_NET_NET;
2412 }
cfaf18ce 2413 if (pkt_len) {
83360720 2414 temp.pkt_len_min = pkt_len->min_port;
cfaf18ce
PG
2415 if (pkt_len->max_port)
2416 temp.pkt_len_max = pkt_len->max_port;
2417 } else if (bpf->pkt_len_val) {
2418 if (bpf->pkt_len_val->mask)
2419 temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
2420 temp.pkt_len_min = bpf->pkt_len_val->val;
2421 }
2da7d62e
PG
2422 if (bpf->tcp_flags) {
2423 temp.tcp_flags = bpf->tcp_flags->val;
2424 temp.tcp_mask_flags = bpf->tcp_flags->mask;
2425 }
4977bd6c
PG
2426 if (bpf->dscp) {
2427 if (bpf->dscp->mask)
2428 temp.flags |= MATCH_DSCP_INVERSE_SET;
2429 else
2430 temp.flags |= MATCH_DSCP_SET;
2431 temp.dscp_value = bpf->dscp->val;
2432 }
40881800
PG
2433 if (bpf->flow_label) {
2434 if (bpf->flow_label->mask)
2435 temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
2436 else
2437 temp.flags |= MATCH_FLOW_LABEL_SET;
2438 temp.flow_label = bpf->flow_label->val;
2439 }
6f5617d8
PG
2440 if (bpf->fragment) {
2441 if (bpf->fragment->mask)
2442 temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
2443 temp.fragment = bpf->fragment->val;
2444 }
f449d223
PG
2445 if (bpf->protocol) {
2446 temp.protocol = bpf->protocol;
2447 temp.flags |= MATCH_PROTOCOL_SET;
2448 }
d114b0d7
PG
2449 temp.action = bpa;
2450 bpm = hash_get(bgp->pbr_match_hash, &temp,
2451 bgp_pbr_match_alloc_intern);
2452
2453 /* new, then self allocate ipset_name and unique */
5a430eee 2454 if (bpm->unique == 0) {
d114b0d7
PG
2455 bpm->unique = ++bgp_pbr_match_counter_unique;
2456 /* 0 value is forbidden */
4371bf91
PG
2457 snprintf(bpm->ipset_name, sizeof(bpm->ipset_name),
2458 "match%p", bpm);
d114b0d7
PG
2459 bpm->entry_hash = hash_create_size(8,
2460 bgp_pbr_match_entry_hash_key,
2461 bgp_pbr_match_entry_hash_equal,
2462 "Match Entry Hash");
2463 bpm->installed = false;
2464
2465 /* unique2 should be updated too */
2466 bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
2467 bpm->installed_in_iptable = false;
2468 bpm->install_in_progress = false;
2469 bpm->install_iptable_in_progress = false;
2470 }
2471
2472 memset(&temp2, 0, sizeof(temp2));
0e867886
PG
2473 if (bpf->src)
2474 prefix_copy(&temp2.src, bpf->src);
d114b0d7 2475 else
f01e580f 2476 temp2.src.family = bpf->family;
0e867886
PG
2477 if (bpf->dst)
2478 prefix_copy(&temp2.dst, bpf->dst);
d114b0d7 2479 else
f01e580f 2480 temp2.dst.family = bpf->family;
1de7dfff
PG
2481 temp2.src_port_min = src_port ? src_port->min_port : 0;
2482 temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
2483 temp2.src_port_max = src_port ? src_port->max_port : 0;
2484 temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
0e867886 2485 temp2.proto = bpf->protocol;
5a430eee
PG
2486 bpme = hash_get(bpm->entry_hash, &temp2,
2487 bgp_pbr_match_entry_alloc_intern);
2488 if (bpme->unique == 0) {
d114b0d7
PG
2489 bpme->unique = ++bgp_pbr_match_entry_counter_unique;
2490 /* 0 value is forbidden */
2491 bpme->backpointer = bpm;
2492 bpme->installed = false;
2493 bpme->install_in_progress = false;
b588b642 2494 /* link bgp info to bpme */
9b6d8fcf 2495 bpme->path = (void *)path;
c26edcda
PG
2496 } else
2497 bpme_found = true;
d114b0d7 2498
c26edcda 2499 /* already installed */
5a430eee 2500 if (bpme_found) {
18ee8310 2501 struct bgp_path_info_extra *extra =
9b6d8fcf 2502 bgp_path_info_extra_get(path);
c26edcda 2503
e0c7edb0
PG
2504 if (extra &&
2505 listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) {
c26edcda 2506 if (BGP_DEBUG(pbr, PBR_ERROR))
9b6d8fcf
DS
2507 zlog_err(
2508 "%s: entry %p/%p already installed in bgp pbr",
2509 __func__, path, bpme);
c26edcda
PG
2510 return;
2511 }
2512 }
d114b0d7
PG
2513 /* BGP FS: append entry to zebra
2514 * - policies are not routing entries and as such
2515 * route replace semantics don't necessarily follow
2516 * through to policy entries
2517 * - because of that, not all policing information will be stored
2518 * into zebra. and non selected policies will be suppressed from zebra
2519 * - as consequence, in order to bring consistency
2520 * a policy will be added, then ifan ecmp policy exists,
2521 * it will be suppressed subsequently
2522 */
2523 /* ip rule add */
db1fcc98 2524 bgp_pbr_bpa_add(bpa);
d114b0d7
PG
2525
2526 /* ipset create */
6ea591c7 2527 if (!bpm->installed)
d114b0d7
PG
2528 bgp_send_pbr_ipset_match(bpm, true);
2529 /* ipset add */
6ea591c7 2530 if (!bpme->installed)
d114b0d7
PG
2531 bgp_send_pbr_ipset_entry_match(bpme, true);
2532
2533 /* iptables */
6ea591c7 2534 if (!bpm->installed_in_iptable)
d114b0d7
PG
2535 bgp_send_pbr_iptable(bpa, bpm, true);
2536
2537 /* A previous entry may already exist
2538 * flush previous entry if necessary
2539 */
2540 bpmer.bpme_to_match = bpme;
2541 bpmer.bpme_found = NULL;
2542 hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
2543 if (bpmer.bpme_found) {
2544 static struct bgp_pbr_match *local_bpm;
2545 static struct bgp_pbr_action *local_bpa;
2546
2547 local_bpm = bpmer.bpme_found->backpointer;
2548 local_bpa = local_bpm->action;
2549 bgp_pbr_flush_entry(bgp, local_bpa,
2550 local_bpm, bpmer.bpme_found);
2551 }
2552
2553
2554}
2555
4b7e6066 2556static void bgp_pbr_policyroute_add_to_zebra_recursive(
9b6d8fcf
DS
2557 struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
2558 struct bgp_pbr_or_filter *bpof, struct nexthop *nh, float *rate,
2559 uint8_t type_entry)
56707a36
PG
2560{
2561 struct listnode *node, *nnode;
2562 struct bgp_pbr_val_mask *valmask;
2563 uint8_t next_type_entry;
2564 struct list *orig_list;
2565 struct bgp_pbr_val_mask **target_val;
2566
d90b788e
A
2567 if (type_entry == 0) {
2568 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2569 return;
2570 }
e45aea59 2571 next_type_entry = bgp_pbr_next_type_entry(type_entry);
56707a36 2572 if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
56707a36
PG
2573 orig_list = bpof->tcpflags;
2574 target_val = &bpf->tcp_flags;
2575 } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
56707a36
PG
2576 orig_list = bpof->dscp;
2577 target_val = &bpf->dscp;
cfaf18ce 2578 } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
cfaf18ce
PG
2579 orig_list = bpof->pkt_len;
2580 target_val = &bpf->pkt_len_val;
6f5617d8 2581 } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
6f5617d8
PG
2582 orig_list = bpof->fragment;
2583 target_val = &bpf->fragment;
da3fa383
PG
2584 } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
2585 (bpof->icmp_type || bpof->icmp_code)) {
2586 /* enumerate list for icmp - must be last one */
9b6d8fcf 2587 bgp_pbr_icmp_action(bgp, path, bpf, bpof, true, nh, rate);
da3fa383 2588 return;
56707a36 2589 } else {
d90b788e 2590 bgp_pbr_policyroute_add_to_zebra_recursive(
9b6d8fcf 2591 bgp, path, bpf, bpof, nh, rate, next_type_entry);
d90b788e 2592 return;
56707a36
PG
2593 }
2594 for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
2595 *target_val = valmask;
9b6d8fcf
DS
2596 bgp_pbr_policyroute_add_to_zebra_recursive(
2597 bgp, path, bpf, bpof, nh, rate, next_type_entry);
56707a36
PG
2598 }
2599}
2600
9bba1455 2601static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
9b6d8fcf 2602 struct bgp_path_info *path,
4b7e6066
DS
2603 struct bgp_pbr_filter *bpf,
2604 struct bgp_pbr_or_filter *bpof,
2605 struct nexthop *nh, float *rate)
9bba1455 2606{
d90b788e
A
2607 if (!bpof) {
2608 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
2609 return;
2610 }
56707a36 2611 if (bpof->tcpflags)
9b6d8fcf
DS
2612 bgp_pbr_policyroute_add_to_zebra_recursive(
2613 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_TCP_FLAGS);
56707a36 2614 else if (bpof->dscp)
9b6d8fcf
DS
2615 bgp_pbr_policyroute_add_to_zebra_recursive(
2616 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_DSCP);
cfaf18ce 2617 else if (bpof->pkt_len)
9b6d8fcf
DS
2618 bgp_pbr_policyroute_add_to_zebra_recursive(
2619 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_PKT_LEN);
6f5617d8 2620 else if (bpof->fragment)
9b6d8fcf
DS
2621 bgp_pbr_policyroute_add_to_zebra_recursive(
2622 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_FRAGMENT);
da3fa383 2623 else if (bpof->icmp_type || bpof->icmp_code)
9b6d8fcf
DS
2624 bgp_pbr_policyroute_add_to_zebra_recursive(
2625 bgp, path, bpf, bpof, nh, rate, FLOWSPEC_ICMP_TYPE);
56707a36 2626 else
9b6d8fcf 2627 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
56707a36
PG
2628 /* flush bpof */
2629 if (bpof->tcpflags)
2630 list_delete_all_node(bpof->tcpflags);
2631 if (bpof->dscp)
2632 list_delete_all_node(bpof->dscp);
cfaf18ce
PG
2633 if (bpof->pkt_len)
2634 list_delete_all_node(bpof->pkt_len);
6f5617d8
PG
2635 if (bpof->fragment)
2636 list_delete_all_node(bpof->fragment);
da3fa383
PG
2637 if (bpof->icmp_type)
2638 list_delete_all_node(bpof->icmp_type);
2639 if (bpof->icmp_code)
2640 list_delete_all_node(bpof->icmp_code);
932404b7
PG
2641}
2642
9b6d8fcf 2643static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
4b7e6066 2644 struct bgp_pbr_entry_main *api, bool add)
d114b0d7
PG
2645{
2646 struct nexthop nh;
2647 int i = 0;
2648 int continue_loop = 1;
2649 float rate = 0;
2650 struct prefix *src = NULL, *dst = NULL;
1de7dfff
PG
2651 uint8_t proto = 0;
2652 struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
932404b7 2653 struct bgp_pbr_range_port range, range_icmp_code;
83360720 2654 struct bgp_pbr_range_port pkt_len;
0e867886 2655 struct bgp_pbr_filter bpf;
c5ee26cc
PG
2656 uint8_t kind_enum;
2657 struct bgp_pbr_or_filter bpof;
9bba1455 2658 struct bgp_pbr_val_mask bpvm;
d114b0d7 2659
645a1f1d 2660 memset(&range, 0, sizeof(range));
6006b807
DA
2661 memset(&nh, 0, sizeof(nh));
2662 memset(&bpf, 0, sizeof(bpf));
2663 memset(&bpof, 0, sizeof(bpof));
9350f1df
PG
2664 if (api->match_bitmask & PREFIX_SRC_PRESENT ||
2665 (api->type == BGP_PBR_IPRULE &&
2666 api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
d114b0d7 2667 src = &api->src_prefix;
9350f1df
PG
2668 if (api->match_bitmask & PREFIX_DST_PRESENT ||
2669 (api->type == BGP_PBR_IPRULE &&
2670 api->match_bitmask_iprule & PREFIX_DST_PRESENT))
d114b0d7 2671 dst = &api->dst_prefix;
9350f1df
PG
2672 if (api->type == BGP_PBR_IPRULE)
2673 bpf.type = api->type;
6006b807 2674 memset(&nh, 0, sizeof(nh));
d114b0d7 2675 nh.vrf_id = VRF_UNKNOWN;
f2ead0a5 2676 if (api->match_protocol_num) {
1de7dfff 2677 proto = (uint8_t)api->protocol[0].value;
f2ead0a5
PG
2678 if (api->afi == AF_INET6 && proto == IPPROTO_ICMPV6)
2679 proto = IPPROTO_ICMP;
2680 }
1de7dfff
PG
2681 /* if match_port is selected, then either src or dst port will be parsed
2682 * but not both at the same time
2683 */
2684 if (api->match_port_num >= 1) {
2685 bgp_pbr_extract(api->port,
2686 api->match_port_num,
2687 &range);
2688 srcp = dstp = &range;
2689 } else if (api->match_src_port_num >= 1) {
2690 bgp_pbr_extract(api->src_port,
2691 api->match_src_port_num,
2692 &range);
2693 srcp = &range;
2694 dstp = NULL;
2695 } else if (api->match_dst_port_num >= 1) {
2696 bgp_pbr_extract(api->dst_port,
2697 api->match_dst_port_num,
2698 &range);
2699 dstp = &range;
2700 srcp = NULL;
2701 }
932404b7
PG
2702 if (api->match_icmp_type_num >= 1) {
2703 proto = IPPROTO_ICMP;
da3fa383
PG
2704 if (bgp_pbr_extract(api->icmp_type,
2705 api->match_icmp_type_num,
2706 &range))
932404b7 2707 srcp = &range;
da3fa383
PG
2708 else {
2709 bpof.icmp_type = list_new();
2710 bgp_pbr_extract_enumerate(api->icmp_type,
2711 api->match_icmp_type_num,
2712 OPERATOR_UNARY_OR,
2713 bpof.icmp_type,
2714 FLOWSPEC_ICMP_TYPE);
932404b7
PG
2715 }
2716 }
2717 if (api->match_icmp_code_num >= 1) {
2718 proto = IPPROTO_ICMP;
da3fa383
PG
2719 if (bgp_pbr_extract(api->icmp_code,
2720 api->match_icmp_code_num,
2721 &range_icmp_code))
932404b7 2722 dstp = &range_icmp_code;
da3fa383
PG
2723 else {
2724 bpof.icmp_code = list_new();
2725 bgp_pbr_extract_enumerate(api->icmp_code,
2726 api->match_icmp_code_num,
2727 OPERATOR_UNARY_OR,
2728 bpof.icmp_code,
2729 FLOWSPEC_ICMP_CODE);
932404b7
PG
2730 }
2731 }
2da7d62e 2732
c5ee26cc
PG
2733 if (api->match_tcpflags_num) {
2734 kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
2735 api->match_tcpflags_num);
2736 if (kind_enum == OPERATOR_UNARY_AND) {
9bba1455 2737 bpf.tcp_flags = &bpvm;
c5ee26cc
PG
2738 bgp_pbr_extract_enumerate(api->tcpflags,
2739 api->match_tcpflags_num,
35703998
PG
2740 OPERATOR_UNARY_AND,
2741 bpf.tcp_flags,
2742 FLOWSPEC_TCP_FLAGS);
c5ee26cc
PG
2743 } else if (kind_enum == OPERATOR_UNARY_OR) {
2744 bpof.tcpflags = list_new();
2745 bgp_pbr_extract_enumerate(api->tcpflags,
2746 api->match_tcpflags_num,
35703998
PG
2747 OPERATOR_UNARY_OR,
2748 bpof.tcpflags,
2749 FLOWSPEC_TCP_FLAGS);
c5ee26cc
PG
2750 }
2751 }
cfaf18ce
PG
2752 if (api->match_packet_length_num) {
2753 bool ret;
2754
2755 ret = bgp_pbr_extract(api->packet_length,
2756 api->match_packet_length_num,
2757 &pkt_len);
2758 if (ret)
2759 bpf.pkt_len = &pkt_len;
2760 else {
2761 bpof.pkt_len = list_new();
2762 bgp_pbr_extract_enumerate(api->packet_length,
2763 api->match_packet_length_num,
2764 OPERATOR_UNARY_OR,
2765 bpof.pkt_len,
2766 FLOWSPEC_PKT_LEN);
2767 }
2da7d62e 2768 }
4977bd6c 2769 if (api->match_dscp_num >= 1) {
35703998
PG
2770 bpof.dscp = list_new();
2771 bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
2772 OPERATOR_UNARY_OR,
2773 bpof.dscp, FLOWSPEC_DSCP);
4977bd6c 2774 }
6f5617d8
PG
2775 if (api->match_fragment_num) {
2776 bpof.fragment = list_new();
2777 bgp_pbr_extract_enumerate(api->fragment,
2778 api->match_fragment_num,
2779 OPERATOR_UNARY_OR,
2780 bpof.fragment,
2781 FLOWSPEC_FRAGMENT);
2782 }
0e867886
PG
2783 bpf.vrf_id = api->vrf_id;
2784 bpf.src = src;
2785 bpf.dst = dst;
2786 bpf.protocol = proto;
0e867886
PG
2787 bpf.src_port = srcp;
2788 bpf.dst_port = dstp;
f01e580f 2789 bpf.family = afi2family(api->afi);
d90b788e
A
2790 if (!add) {
2791 bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
2792 return;
2793 }
d114b0d7
PG
2794 /* no action for add = true */
2795 for (i = 0; i < api->action_num; i++) {
2796 switch (api->actions[i].action) {
2797 case ACTION_TRAFFICRATE:
2798 /* drop packet */
2799 if (api->actions[i].u.r.rate == 0) {
2800 nh.vrf_id = api->vrf_id;
2801 nh.type = NEXTHOP_TYPE_BLACKHOLE;
9b6d8fcf
DS
2802 bgp_pbr_policyroute_add_to_zebra(
2803 bgp, path, &bpf, &bpof, &nh, &rate);
d114b0d7
PG
2804 } else {
2805 /* update rate. can be reentrant */
2806 rate = api->actions[i].u.r.rate;
ac7c35f8 2807 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2808 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2809 zlog_warn("PBR: ignoring Set action rate %f",
2810 api->actions[i].u.r.rate);
2811 }
d114b0d7
PG
2812 }
2813 break;
2814 case ACTION_TRAFFIC_ACTION:
2815 if (api->actions[i].u.za.filter
2816 & TRAFFIC_ACTION_SAMPLE) {
ac7c35f8 2817 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2818 bgp_pbr_print_policy_route(api);
ac7c35f8
PG
2819 zlog_warn("PBR: Sample action Ignored");
2820 }
d114b0d7 2821 }
d114b0d7
PG
2822 /* terminate action: run other filters
2823 */
2824 break;
2825 case ACTION_REDIRECT_IP:
d114b0d7 2826 nh.vrf_id = api->vrf_id;
f01e580f
PG
2827 if (api->afi == AFI_IP) {
2828 nh.type = NEXTHOP_TYPE_IPV4;
2829 nh.gate.ipv4.s_addr =
2830 api->actions[i].u.zr.
2831 redirect_ip_v4.s_addr;
2832 } else {
2833 nh.type = NEXTHOP_TYPE_IPV6;
2834 memcpy(&nh.gate.ipv6,
2835 &api->actions[i].u.zr.redirect_ip_v6,
2836 sizeof(struct in6_addr));
2837 }
9b6d8fcf 2838 bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
da3fa383 2839 &nh, &rate);
d114b0d7
PG
2840 /* XXX combination with REDIRECT_VRF
2841 * + REDIRECT_NH_IP not done
2842 */
2843 continue_loop = 0;
2844 break;
2845 case ACTION_REDIRECT:
9a659715
PG
2846 if (api->afi == AFI_IP)
2847 nh.type = NEXTHOP_TYPE_IPV4;
2848 else
2849 nh.type = NEXTHOP_TYPE_IPV6;
d114b0d7 2850 nh.vrf_id = api->actions[i].u.redirect_vrf;
9b6d8fcf 2851 bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
da3fa383 2852 &nh, &rate);
d114b0d7
PG
2853 continue_loop = 0;
2854 break;
2855 case ACTION_MARKING:
ac7c35f8 2856 if (BGP_DEBUG(pbr, PBR)) {
d114b0d7 2857 bgp_pbr_print_policy_route(api);
40881800 2858 zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
ac7c35f8
PG
2859 api->actions[i].u.marking_dscp);
2860 }
d114b0d7
PG
2861 break;
2862 default:
2863 break;
2864 }
2865 if (continue_loop == 0)
2866 break;
2867 }
2868}
2869
5a1ae2c2 2870void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p,
4b7e6066
DS
2871 struct bgp_path_info *info, afi_t afi, safi_t safi,
2872 bool nlri_update)
45918cfb
PG
2873{
2874 struct bgp_pbr_entry_main api;
2875
45918cfb
PG
2876 if (safi != SAFI_FLOWSPEC)
2877 return; /* not supported */
2878 /* Make Zebra API structure. */
2879 memset(&api, 0, sizeof(api));
2880 api.vrf_id = bgp->vrf_id;
2881 api.afi = afi;
2882
6818e7e5 2883 if (!bgp_zebra_tm_chunk_obtained()) {
f146bb54 2884 if (BGP_DEBUG(pbr, PBR_ERROR))
e50f7cfd 2885 flog_err(EC_BGP_TABLE_CHUNK,
1c50c1c0 2886 "%s: table chunk not obtained yet", __func__);
6818e7e5
PG
2887 return;
2888 }
6818e7e5
PG
2889
2890 if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
2891 if (BGP_DEBUG(pbr, PBR_ERROR))
e50f7cfd 2892 flog_err(EC_BGP_FLOWSPEC_INSTALLATION,
1c50c1c0
QY
2893 "%s: cancel updating entry %p in bgp pbr",
2894 __func__, info);
45918cfb
PG
2895 return;
2896 }
d114b0d7 2897 bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
45918cfb 2898}
4762c213
PG
2899
2900int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
2901 const struct bgp_pbr_interface *b)
2902{
2903 return strcmp(a->name, b->name);
2904}
2905
2906struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
2907 struct bgp_pbr_interface_head *head)
2908{
2909 struct bgp_pbr_interface pbr_if;
2910
2911 strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
2912 return (RB_FIND(bgp_pbr_interface_head,
2913 head, &pbr_if));
2914}
2915
2916/* this function resets to the default policy routing
2917 * go back to default status
2918 */
2919void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
2920{
2921 struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
2922 struct bgp_pbr_interface_head *head;
2923 struct bgp_pbr_interface *pbr_if;
2924
8f242187 2925 if (!bgp_pbr_cfg)
4762c213 2926 return;
8f242187
PG
2927 if (afi == AFI_IP)
2928 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
2929 else
2930 head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
4762c213
PG
2931 while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
2932 pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
2933 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
2934 XFREE(MTYPE_TMP, pbr_if);
2935 }
2936}