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