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