]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/static/static.c
2 * BIRD -- Static Route Generator
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
12 * The Static protocol is implemented in a straightforward way. It keeps a list
13 * of static routes. Routes of dest RTD_UNICAST have associated sticky node in
14 * the neighbor cache to be notified about gaining or losing the neighbor and
15 * about interface-related events (e.g. link down). They may also have a BFD
16 * request if associated with a BFD session. When a route is notified,
17 * static_decide() is used to see whether the route activeness is changed. In
18 * such case, the route is marked as dirty and scheduled to be announced or
19 * withdrawn, which is done asynchronously from event hook. Routes of other
20 * types (e.g. black holes) are announced all the time.
22 * Multipath routes are a bit tricky. To represent additional next hops, dummy
23 * static_route nodes are used, which are chained using @mp_next field and link
24 * to the master node by @mp_head field. Each next hop has a separate neighbor
25 * entry and an activeness state, but the master node is used for most purposes.
26 * Note that most functions DO NOT accept dummy nodes as arguments.
28 * The only other thing worth mentioning is that when asked for reconfiguration,
29 * Static not only compares the two configurations, but it also calculates
30 * difference between the lists of static routes and it just inserts the newly
31 * added routes, removes the obsolete ones and reannounces changed ones.
38 #include "nest/bird.h"
39 #include "nest/iface.h"
40 #include "nest/protocol.h"
41 #include "nest/route.h"
43 #include "conf/conf.h"
44 #include "filter/filter.h"
45 #include "lib/string.h"
46 #include "lib/alloca.h"
50 static linpool
*static_lp
;
53 static_announce_rte(struct static_proto
*p
, struct static_route
*r
)
55 rta
*a
= allocz(RTA_MAX_SIZE
);
56 a
->src
= p
->p
.main_source
;
57 a
->source
= RTS_STATIC
;
58 a
->scope
= SCOPE_UNIVERSE
;
61 if (r
->dest
== RTD_UNICAST
)
63 struct static_route
*r2
;
64 struct nexthop
*nhs
= NULL
;
66 for (r2
= r
; r2
; r2
= r2
->mp_next
)
71 struct nexthop
*nh
= allocz(NEXTHOP_MAX_SIZE
);
73 nh
->iface
= r2
->neigh
->iface
;
74 nh
->flags
= r2
->onlink
? RNF_ONLINK
: 0;
75 nh
->weight
= r2
->weight
;
78 nh
->labels
= r2
->mls
->len
;
79 memcpy(nh
->label
, r2
->mls
->stack
, r2
->mls
->len
* sizeof(u32
));
82 nexthop_insert(&nhs
, nh
);
91 if (r
->dest
== RTDX_RECURSIVE
)
93 rtable
*tab
= ipa_is_ip4(r
->via
) ? p
->igp_table_ip4
: p
->igp_table_ip6
;
94 rta_set_recursive_next_hop(p
->p
.main_channel
->table
, a
, tab
, r
->via
, IPA_NONE
, r
->mls
);
97 /* Already announced */
98 if (r
->state
== SRS_CLEAN
)
101 /* We skip rta_lookup() here */
102 rte
*e
= rte_get_temp(a
);
106 f_eval_rte(r
->cmds
, &e
, static_lp
);
108 rte_update(&p
->p
, r
->net
, e
);
109 r
->state
= SRS_CLEAN
;
117 if (r
->state
== SRS_DOWN
)
120 rte_update(&p
->p
, r
->net
, NULL
);
125 static_mark_rte(struct static_proto
*p
, struct static_route
*r
)
127 if (r
->state
== SRS_DIRTY
)
130 r
->state
= SRS_DIRTY
;
131 BUFFER_PUSH(p
->marked
) = r
;
133 if (!ev_active(p
->event
))
134 ev_schedule(p
->event
);
138 static_announce_marked(void *P
)
140 struct static_proto
*p
= P
;
142 BUFFER_WALK(p
->marked
, r
)
143 static_announce_rte(P
, r
);
145 BUFFER_FLUSH(p
->marked
);
149 static_bfd_notify(struct bfd_request
*req
);
152 static_update_bfd(struct static_proto
*p
, struct static_route
*r
)
154 /* The @r is a RTD_UNICAST next hop, may be a dummy node */
156 struct neighbor
*nb
= r
->neigh
;
157 int bfd_up
= (nb
->scope
> 0) && r
->use_bfd
;
159 if (bfd_up
&& !r
->bfd_req
)
161 // ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip;
162 r
->bfd_req
= bfd_request_session(p
->p
.pool
, r
->via
, nb
->ifa
->ip
,
164 static_bfd_notify
, r
);
167 if (!bfd_up
&& r
->bfd_req
)
175 static_decide(struct static_proto
*p
, struct static_route
*r
)
177 /* The @r is a RTD_UNICAST next hop, may be a dummy node */
179 struct static_config
*cf
= (void *) p
->p
.cf
;
180 uint old_active
= r
->active
;
182 if (r
->neigh
->scope
< 0)
185 if (cf
->check_link
&& !(r
->neigh
->iface
->flags
& IF_LINK_UP
))
188 if (r
->bfd_req
&& (r
->bfd_req
->state
!= BFD_STATE_UP
))
200 static_add_rte(struct static_proto
*p
, struct static_route
*r
)
202 if (r
->dest
== RTD_UNICAST
)
204 struct static_route
*r2
;
207 for (r2
= r
; r2
; r2
= r2
->mp_next
)
209 n
= neigh_find(&p
->p
, r2
->via
, r2
->iface
, NEF_STICKY
|
210 (r2
->onlink
? NEF_ONLINK
: 0) |
211 (ipa_zero(r2
->via
) ? NEF_IFACE
: 0));
215 log(L_WARN
"Invalid next hop %I of static route %N", r2
->via
, r2
->net
);
223 static_update_bfd(p
, r2
);
224 static_decide(p
, r2
);
228 static_announce_rte(p
, r
);
232 static_reset_rte(struct static_proto
*p UNUSED
, struct static_route
*r
)
234 struct static_route
*r2
;
236 for (r2
= r
; r2
; r2
= r2
->mp_next
)
250 static_remove_rte(struct static_proto
*p
, struct static_route
*r
)
253 rte_update(&p
->p
, r
->net
, NULL
);
255 static_reset_rte(p
, r
);
260 static_same_dest(struct static_route
*x
, struct static_route
*y
)
262 if (x
->dest
!= y
->dest
)
268 for (; x
&& y
; x
= x
->mp_next
, y
= y
->mp_next
)
270 if (!ipa_equal(x
->via
, y
->via
) ||
271 (x
->iface
!= y
->iface
) ||
272 (x
->onlink
!= y
->onlink
) ||
273 (x
->weight
!= y
->weight
) ||
274 (x
->use_bfd
!= y
->use_bfd
) ||
275 (!x
->mls
!= !y
->mls
) ||
276 ((x
->mls
) && (y
->mls
) && (x
->mls
->len
!= y
->mls
->len
)))
282 for (uint i
= 0; i
< x
->mls
->len
; i
++)
283 if (x
->mls
->stack
[i
] != y
->mls
->stack
[i
])
289 if (!ipa_equal(x
->via
, y
->via
) ||
290 (!x
->mls
!= !y
->mls
) ||
291 ((x
->mls
) && (y
->mls
) && (x
->mls
->len
!= y
->mls
->len
)))
297 for (uint i
= 0; i
< x
->mls
->len
; i
++)
298 if (x
->mls
->stack
[i
] != y
->mls
->stack
[i
])
309 static_same_rte(struct static_route
*or, struct static_route
*nr
)
311 /* Note that i_same() requires arguments in (new, old) order */
312 return static_same_dest(or, nr
) && i_same(nr
->cmds
, or->cmds
);
316 static_reconfigure_rte(struct static_proto
*p
, struct static_route
*or, struct static_route
*nr
)
318 if ((or->state
== SRS_CLEAN
) && !static_same_rte(or, nr
))
319 nr
->state
= SRS_DIRTY
;
321 nr
->state
= or->state
;
323 static_add_rte(p
, nr
);
324 static_reset_rte(p
, or);
329 static_neigh_notify(struct neighbor
*n
)
331 struct static_proto
*p
= (void *) n
->proto
;
332 struct static_route
*r
;
334 DBG("Static: neighbor notify for %I: iface %p\n", n
->addr
, n
->iface
);
335 for (r
= n
->data
; r
; r
= r
->chain
)
337 static_update_bfd(p
, r
);
339 if (static_decide(p
, r
))
340 static_mark_rte(p
, r
->mp_head
);
345 static_bfd_notify(struct bfd_request
*req
)
347 struct static_route
*r
= req
->data
;
348 struct static_proto
*p
= (void *) r
->neigh
->proto
;
350 // if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX);
352 if (static_decide(p
, r
))
353 static_mark_rte(p
, r
->mp_head
);
357 static_rte_mergable(rte
*pri UNUSED
, rte
*sec UNUSED
)
364 static_postconfig(struct proto_config
*CF
)
366 struct static_config
*cf
= (void *) CF
;
367 struct static_route
*r
;
369 if (EMPTY_LIST(CF
->channels
))
370 cf_error("Channel not specified");
372 struct channel_config
*cc
= proto_cf_main_channel(CF
);
374 if (!cf
->igp_table_ip4
)
375 cf
->igp_table_ip4
= (cc
->table
->addr_type
== NET_IP4
) ?
376 cc
->table
: cf
->c
.global
->def_tables
[NET_IP4
];
378 if (!cf
->igp_table_ip6
)
379 cf
->igp_table_ip6
= (cc
->table
->addr_type
== NET_IP6
) ?
380 cc
->table
: cf
->c
.global
->def_tables
[NET_IP6
];
382 WALK_LIST(r
, cf
->routes
)
383 if (r
->net
&& (r
->net
->type
!= CF
->net_type
))
384 cf_error("Route %N incompatible with channel type", r
->net
);
387 static struct proto
*
388 static_init(struct proto_config
*CF
)
390 struct proto
*P
= proto_new(CF
);
391 struct static_proto
*p
= (void *) P
;
392 struct static_config
*cf
= (void *) CF
;
394 P
->main_channel
= proto_add_channel(P
, proto_cf_main_channel(CF
));
396 P
->neigh_notify
= static_neigh_notify
;
397 P
->rte_mergable
= static_rte_mergable
;
399 if (cf
->igp_table_ip4
)
400 p
->igp_table_ip4
= cf
->igp_table_ip4
->table
;
402 if (cf
->igp_table_ip6
)
403 p
->igp_table_ip6
= cf
->igp_table_ip6
->table
;
409 static_start(struct proto
*P
)
411 struct static_proto
*p
= (void *) P
;
412 struct static_config
*cf
= (void *) P
->cf
;
413 struct static_route
*r
;
416 static_lp
= lp_new(&root_pool
, LP_GOOD_SIZE(1024));
418 if (p
->igp_table_ip4
)
419 rt_lock_table(p
->igp_table_ip4
);
421 if (p
->igp_table_ip6
)
422 rt_lock_table(p
->igp_table_ip6
);
424 p
->event
= ev_new_init(p
->p
.pool
, static_announce_marked
, p
);
426 BUFFER_INIT(p
->marked
, p
->p
.pool
, 4);
428 /* We have to go UP before routes could be installed */
429 proto_notify_state(P
, PS_UP
);
431 WALK_LIST(r
, cf
->routes
)
432 static_add_rte(p
, r
);
438 static_shutdown(struct proto
*P
)
440 struct static_proto
*p
= (void *) P
;
441 struct static_config
*cf
= (void *) P
->cf
;
442 struct static_route
*r
;
444 /* Just reset the flag, the routes will be flushed by the nest */
445 WALK_LIST(r
, cf
->routes
)
446 static_reset_rte(p
, r
);
452 static_cleanup(struct proto
*P
)
454 struct static_proto
*p
= (void *) P
;
456 if (p
->igp_table_ip4
)
457 rt_unlock_table(p
->igp_table_ip4
);
459 if (p
->igp_table_ip6
)
460 rt_unlock_table(p
->igp_table_ip6
);
464 static_dump_rte(struct static_route
*r
)
466 debug("%-1N: ", r
->net
);
467 if (r
->dest
== RTD_UNICAST
)
468 if (r
->iface
&& ipa_zero(r
->via
))
469 debug("dev %s\n", r
->iface
->name
);
471 debug("via %I%J\n", r
->via
, r
->iface
);
473 debug("rtd %d\n", r
->dest
);
477 static_dump(struct proto
*P
)
479 struct static_config
*c
= (void *) P
->cf
;
480 struct static_route
*r
;
482 debug("Static routes:\n");
483 WALK_LIST(r
, c
->routes
)
487 #define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
490 static_cmp_rte(const void *X
, const void *Y
)
492 struct static_route
*x
= *(void **)X
, *y
= *(void **)Y
;
493 return net_compare(x
->net
, y
->net
);
497 static_reconfigure(struct proto
*P
, struct proto_config
*CF
)
499 struct static_proto
*p
= (void *) P
;
500 struct static_config
*o
= (void *) P
->cf
;
501 struct static_config
*n
= (void *) CF
;
502 struct static_route
*r
, *r2
, *or, *nr
;
504 /* Check change in IGP tables */
505 if ((IGP_TABLE(o
, ip4
) != IGP_TABLE(n
, ip4
)) ||
506 (IGP_TABLE(o
, ip6
) != IGP_TABLE(n
, ip6
)))
509 if (!proto_configure_channel(P
, &P
->main_channel
, proto_cf_main_channel(CF
)))
514 /* Reset route lists in neighbor entries */
515 WALK_LIST(r
, o
->routes
)
516 for (r2
= r
; r2
; r2
= r2
->mp_next
)
518 r2
->neigh
->data
= NULL
;
520 /* Reconfigure initial matching sequence */
521 for (or = HEAD(o
->routes
), nr
= HEAD(n
->routes
);
522 NODE_VALID(or) && NODE_VALID(nr
) && net_equal(or->net
, nr
->net
);
523 or = NODE_NEXT(or), nr
= NODE_NEXT(nr
))
524 static_reconfigure_rte(p
, or, nr
);
526 if (!NODE_VALID(or) && !NODE_VALID(nr
))
529 /* Reconfigure remaining routes, sort them to find matching pairs */
530 struct static_route
*or2
, *nr2
, **orbuf
, **nrbuf
;
531 uint ornum
= 0, nrnum
= 0, orpos
= 0, nrpos
= 0, i
;
533 for (or2
= or; NODE_VALID(or2
); or2
= NODE_NEXT(or2
))
536 for (nr2
= nr
; NODE_VALID(nr2
); nr2
= NODE_NEXT(nr2
))
539 orbuf
= xmalloc(ornum
* sizeof(void *));
540 nrbuf
= xmalloc(nrnum
* sizeof(void *));
542 for (i
= 0, or2
= or; i
< ornum
; i
++, or2
= NODE_NEXT(or2
))
545 for (i
= 0, nr2
= nr
; i
< nrnum
; i
++, nr2
= NODE_NEXT(nr2
))
548 qsort(orbuf
, ornum
, sizeof(struct static_route
*), static_cmp_rte
);
549 qsort(nrbuf
, nrnum
, sizeof(struct static_route
*), static_cmp_rte
);
551 while ((orpos
< ornum
) && (nrpos
< nrnum
))
553 int x
= net_compare(orbuf
[orpos
]->net
, nrbuf
[nrpos
]->net
);
555 static_remove_rte(p
, orbuf
[orpos
++]);
557 static_add_rte(p
, nrbuf
[nrpos
++]);
559 static_reconfigure_rte(p
, orbuf
[orpos
++], nrbuf
[nrpos
++]);
562 while (orpos
< ornum
)
563 static_remove_rte(p
, orbuf
[orpos
++]);
565 while (nrpos
< nrnum
)
566 static_add_rte(p
, nrbuf
[nrpos
++]);
575 static_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
577 struct static_config
*d
= (struct static_config
*) dest
;
578 struct static_config
*s
= (struct static_config
*) src
;
580 struct static_route
*srt
, *snh
;
582 /* Copy route list */
583 init_list(&d
->routes
);
584 WALK_LIST(srt
, s
->routes
)
586 struct static_route
*drt
= NULL
, *dnh
= NULL
, **dnp
= &drt
;
588 for (snh
= srt
; snh
; snh
= snh
->mp_next
)
590 dnh
= cfg_alloc(sizeof(struct static_route
));
591 memcpy(dnh
, snh
, sizeof(struct static_route
));
594 add_tail(&d
->routes
, &(dnh
->n
));
597 dnp
= &(dnh
->mp_next
);
606 static_show_rt(struct static_route
*r
)
612 struct static_route
*r2
;
614 cli_msg(-1009, "%N", r
->net
);
615 for (r2
= r
; r2
; r2
= r2
->mp_next
)
617 if (r2
->iface
&& ipa_zero(r2
->via
))
618 cli_msg(-1009, "\tdev %s%s", r2
->iface
->name
,
619 r2
->active
? "" : " (dormant)");
621 cli_msg(-1009, "\tvia %I%J%s%s%s", r2
->via
, r2
->iface
,
622 r2
->onlink
? " onlink" : "",
623 r2
->bfd_req
? " (bfd)" : "",
624 r2
->active
? "" : " (dormant)");
631 case RTD_UNREACHABLE
:
633 cli_msg(-1009, "%N\t%s", r
->net
, rta_dest_names
[r
->dest
]);
637 cli_msg(-1009, "%N\trecursive %I", r
->net
, r
->via
);
643 static_show(struct proto
*P
)
645 struct static_config
*c
= (void *) P
->cf
;
646 struct static_route
*r
;
648 WALK_LIST(r
, c
->routes
)
654 struct protocol proto_static
= {
656 .template = "static%d",
657 .class = PROTOCOL_STATIC
,
658 .preference
= DEF_PREF_STATIC
,
659 .channel_mask
= NB_ANY
,
660 .proto_size
= sizeof(struct static_proto
),
661 .config_size
= sizeof(struct static_config
),
662 .postconfig
= static_postconfig
,
665 .start
= static_start
,
666 .shutdown
= static_shutdown
,
667 .cleanup
= static_cleanup
,
668 .reconfigure
= static_reconfigure
,
669 .copy_config
= static_copy_config