]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/a-path.c
dc36e6538951f1c3ca3401290b40e6663c4449ea
2 * BIRD -- Path Operations
4 * (c) 2000 Martin Mares <mj@ucw.cz>
5 * (c) 2000 Pavel Machek <pavel@ucw.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
10 #include "nest/bird.h"
11 #include "nest/route.h"
12 #include "nest/attrs.h"
13 #include "lib/resource.h"
14 #include "lib/unaligned.h"
15 #include "lib/string.h"
16 #include "filter/filter.h"
18 // static inline void put_as(byte *data, u32 as) { put_u32(data, as); }
19 // static inline u32 get_as(byte *data) { return get_u32(data); }
21 #define put_as put_u32
22 #define get_as get_u32
26 as_path_prepend(struct linpool
*pool
, struct adata
*olda
, u32 as
)
30 if (olda
->length
&& olda
->data
[0] == AS_PATH_SEQUENCE
&& olda
->data
[1] < 255)
31 /* Starting with sequence => just prepend the AS number */
33 int nl
= olda
->length
+ BS
;
34 newa
= lp_alloc(pool
, sizeof(struct adata
) + nl
);
36 newa
->data
[0] = AS_PATH_SEQUENCE
;
37 newa
->data
[1] = olda
->data
[1] + 1;
38 memcpy(newa
->data
+ BS
+ 2, olda
->data
+ 2, olda
->length
- 2);
40 else /* Create new path segment */
42 int nl
= olda
->length
+ BS
+ 2;
43 newa
= lp_alloc(pool
, sizeof(struct adata
) + nl
);
45 newa
->data
[0] = AS_PATH_SEQUENCE
;
47 memcpy(newa
->data
+ BS
+ 2, olda
->data
, olda
->length
);
49 put_as(newa
->data
+ 2, as
);
54 as_path_convert_to_old(struct adata
*path
, byte
*dst
, int *new_used
)
56 byte
*src
= path
->data
;
57 byte
*src_end
= src
+ path
->length
;
58 byte
*dst_start
= dst
;
83 return dst
- dst_start
;
87 as_path_convert_to_new(struct adata
*path
, byte
*dst
, int req_as
)
89 byte
*src
= path
->data
;
90 byte
*src_end
= src
+ path
->length
;
91 byte
*dst_start
= dst
;
96 while ((src
< src_end
) && (req_as
> 0))
101 if (t
== AS_PATH_SEQUENCE
)
108 else // t == AS_PATH_SET
123 return dst
- dst_start
;
127 as_path_format(struct adata
*path
, byte
*buf
, unsigned int size
)
129 byte
*p
= path
->data
;
130 byte
*e
= p
+ path
->length
;
131 byte
*end
= buf
+ size
- 16;
142 isset
= (*p
++ == AS_PATH_SET
);
151 while (l
-- && buf
<= end
)
155 buf
+= bsprintf(buf
, "%u", get_as(p
));
170 as_path_getlen(struct adata
*path
)
172 return as_path_getlen_int(path
, BS
);
176 as_path_getlen_int(struct adata
*path
, int bs
)
180 u8
*q
= p
+path
->length
;
187 case AS_PATH_SET
: len
= *p
++; res
++; p
+= bs
* len
; break;
188 case AS_PATH_SEQUENCE
: len
= *p
++; res
+= len
; p
+= bs
* len
; break;
189 default: bug("as_path_getlen: Invalid path segment");
196 as_path_get_last(struct adata
*path
, u32
*orig_as
)
201 u8
*q
= p
+path
->length
;
215 case AS_PATH_SEQUENCE
:
219 res
= get_as(p
+ BS
* (len
- 1));
223 default: bug("as_path_get_first: Invalid path segment");
233 as_path_get_first(struct adata
*path
, u32
*last_as
)
237 if ((path
->length
== 0) || (p
[0] != AS_PATH_SEQUENCE
) || (p
[1] == 0))
241 *last_as
= get_as(p
+2);
247 as_path_contains(struct adata
*path
, u32 as
, int min
)
250 u8
*q
= p
+path
->length
;
270 as_path_match_set(struct adata
*path
, struct f_tree
*set
)
273 u8
*q
= p
+path
->length
;
282 struct f_val v
= {T_INT
, .val
.i
= get_as(p
)};
283 if (find_tree(set
, v
))
293 as_path_filter(struct linpool
*pool
, struct adata
*path
, struct f_tree
*set
, u32 key
, int pos
)
298 int len
= path
->length
;
300 u8
*q
= path
->data
+ len
;
308 /* Read block header (type and length) */
315 for (i
= 0; i
< sn
; i
++)
321 match
= !!find_tree(set
, (struct f_val
){T_INT
, .val
.i
= as
});
337 /* Nonempty block, set block header and advance */
345 if (nl
== path
->length
)
348 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
) + nl
);
350 memcpy(res
->data
, buf
, nl
);
368 parse_path(struct adata
*path
, struct pm_pos
*pos
)
371 u8
*q
= p
+ path
->length
;
372 struct pm_pos
*opos
= pos
;
388 case AS_PATH_SEQUENCE
:
390 for (i
= 0; i
< len
; i
++)
394 pos
->val
.asn
= get_as(p
);
401 bug("as_path_match: Invalid path component");
409 pm_match(struct pm_pos
*pos
, u32 asn
)
412 return pos
->val
.asn
== asn
;
418 for (i
= 0; i
< len
; i
++)
419 if (get_as(p
+ i
* BS
) == asn
)
426 pm_mark(struct pm_pos
*pos
, int i
, int plen
, int *nl
, int *nh
)
433 for (j
= i
+ 1; (j
< plen
) && pos
[j
].set
&& (! pos
[j
].mark
); j
++)
437 /* We are going downwards, therefore every mark is
438 new low and just the first mark is new high */
440 *nl
= i
+ (pos
[i
].set
? 0 : 1);
446 /* AS path matching is nontrivial. Because AS path can
447 * contain sets, it is not a plain wildcard matching. A set
448 * in an AS path is interpreted as it might represent any
449 * sequence of AS numbers from that set (possibly with
450 * repetitions). So it is also a kind of a pattern,
451 * more complicated than a path mask.
453 * The algorithm for AS path matching is a variant
454 * of nondeterministic finite state machine, where
455 * positions in AS path are states, and items in
456 * path mask are input for that finite state machine.
457 * During execution of the algorithm we maintain a set
458 * of marked states - a state is marked if it can be
459 * reached by any walk through NFSM with regard to
460 * currently processed part of input. When we process
461 * next part of mask, we advance each marked state.
462 * We start with marked first position, when we
463 * run out of marked positions, we reject. When
464 * we process the whole mask, we accept iff final position
465 * (auxiliary position after last real position in AS path)
470 as_path_match(struct adata
*path
, struct f_path_mask
*mask
)
472 struct pm_pos pos
[2048 + 1];
473 int plen
= parse_path(path
, pos
);
477 /* l and h are bound of interval of positions where
488 /* We remove this mark to not step after pos[plen] */
494 for (i
= l
; i
<= plen
; i
++)
503 val
= f_eval_asn((struct f_inst
*) mask
->val
);
508 for (i
= h
; i
>= l
; i
--)
512 if ((mask
->kind
== PM_QUESTION
) || pm_match(pos
+ i
, val
))
513 pm_mark(pos
, i
, plen
, &nl
, &nh
);
527 return pos
[plen
].mark
;