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