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