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