]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/a-path.c
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
, uint 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("Invalid path segment");
233 as_path_get_last_nonaggregated(struct adata
*path
)
236 u8
*q
= p
+path
->length
;
247 case AS_PATH_SEQUENCE
:
249 res
= get_as(p
+ BS
* (len
- 1));
253 default: bug("Invalid path segment");
262 as_path_get_first(struct adata
*path
, u32
*last_as
)
266 if ((path
->length
== 0) || (p
[0] != AS_PATH_SEQUENCE
) || (p
[1] == 0))
270 *last_as
= get_as(p
+2);
276 as_path_contains(struct adata
*path
, u32 as
, int min
)
279 u8
*q
= p
+path
->length
;
299 as_path_match_set(struct adata
*path
, struct f_tree
*set
)
302 u8
*q
= p
+path
->length
;
311 struct f_val v
= {T_INT
, .val
.i
= get_as(p
)};
312 if (find_tree(set
, v
))
322 as_path_filter(struct linpool
*pool
, struct adata
*path
, struct f_tree
*set
, u32 key
, int pos
)
327 int len
= path
->length
;
329 u8
*q
= path
->data
+ len
;
337 /* Read block header (type and length) */
344 for (i
= 0; i
< sn
; i
++)
350 match
= !!find_tree(set
, (struct f_val
){T_INT
, .val
.i
= as
});
366 /* Nonempty block, set block header and advance */
374 if (nl
== path
->length
)
377 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
) + nl
);
379 memcpy(res
->data
, buf
, nl
);
397 parse_path(struct adata
*path
, struct pm_pos
*pos
)
400 u8
*q
= p
+ path
->length
;
401 struct pm_pos
*opos
= pos
;
417 case AS_PATH_SEQUENCE
:
419 for (i
= 0; i
< len
; i
++)
423 pos
->val
.asn
= get_as(p
);
430 bug("as_path_match: Invalid path component");
438 pm_match(struct pm_pos
*pos
, u32 asn
, u32 asn2
)
442 return ((pos
->val
.asn
>= asn
) && (pos
->val
.asn
<= asn2
));
448 for (i
= 0; i
< len
; i
++)
450 gas
= get_as(p
+ i
* BS
);
452 if ((gas
>= asn
) && (gas
<= asn2
))
460 pm_mark(struct pm_pos
*pos
, int i
, int plen
, int *nl
, int *nh
)
467 for (j
= i
+ 1; (j
< plen
) && pos
[j
].set
&& (! pos
[j
].mark
); j
++)
471 /* We are going downwards, therefore every mark is
472 new low and just the first mark is new high */
474 *nl
= i
+ (pos
[i
].set
? 0 : 1);
480 /* AS path matching is nontrivial. Because AS path can
481 * contain sets, it is not a plain wildcard matching. A set
482 * in an AS path is interpreted as it might represent any
483 * sequence of AS numbers from that set (possibly with
484 * repetitions). So it is also a kind of a pattern,
485 * more complicated than a path mask.
487 * The algorithm for AS path matching is a variant
488 * of nondeterministic finite state machine, where
489 * positions in AS path are states, and items in
490 * path mask are input for that finite state machine.
491 * During execution of the algorithm we maintain a set
492 * of marked states - a state is marked if it can be
493 * reached by any walk through NFSM with regard to
494 * currently processed part of input. When we process
495 * next part of mask, we advance each marked state.
496 * We start with marked first position, when we
497 * run out of marked positions, we reject. When
498 * we process the whole mask, we accept if final position
499 * (auxiliary position after last real position in AS path)
504 as_path_match(struct adata
*path
, struct f_path_mask
*mask
)
506 struct pm_pos pos
[2048 + 1];
507 int plen
= parse_path(path
, pos
);
512 /* l and h are bound of interval of positions where
523 /* We remove this mark to not step after pos[plen] */
529 for (i
= l
; i
<= plen
; i
++)
534 case PM_ASN
: /* Define single ASN as ASN..ASN - very narrow interval */
535 val2
= val
= mask
->val
;
546 for (i
= h
; i
>= l
; i
--)
550 if ((mask
->kind
== PM_QUESTION
) || pm_match(pos
+ i
, val
, val2
))
551 pm_mark(pos
, i
, plen
, &nl
, &nh
);
565 return pos
[plen
].mark
;