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