]>
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
, nb
->iface
,
163 static_bfd_notify
, r
);
166 if (!bfd_up
&& r
->bfd_req
)
174 static_decide(struct static_proto
*p
, struct static_route
*r
)
176 /* The @r is a RTD_UNICAST next hop, may be a dummy node */
178 struct static_config
*cf
= (void *) p
->p
.cf
;
179 uint old_active
= r
->active
;
181 if (r
->neigh
->scope
< 0)
184 if (cf
->check_link
&& !(r
->neigh
->iface
->flags
& IF_LINK_UP
))
187 if (r
->bfd_req
&& (r
->bfd_req
->state
!= BFD_STATE_UP
))
199 static_add_rte(struct static_proto
*p
, struct static_route
*r
)
201 if (r
->dest
== RTD_UNICAST
)
203 struct static_route
*r2
;
206 for (r2
= r
; r2
; r2
= r2
->mp_next
)
208 n
= neigh_find(&p
->p
, r2
->via
, r2
->iface
, NEF_STICKY
|
209 (r2
->onlink
? NEF_ONLINK
: 0) |
210 (ipa_zero(r2
->via
) ? NEF_IFACE
: 0));
214 log(L_WARN
"Invalid next hop %I of static route %N", r2
->via
, r2
->net
);
222 static_update_bfd(p
, r2
);
223 static_decide(p
, r2
);
227 static_announce_rte(p
, r
);
231 static_reset_rte(struct static_proto
*p UNUSED
, struct static_route
*r
)
233 struct static_route
*r2
;
235 for (r2
= r
; r2
; r2
= r2
->mp_next
)
249 static_remove_rte(struct static_proto
*p
, struct static_route
*r
)
252 rte_update(&p
->p
, r
->net
, NULL
);
254 static_reset_rte(p
, r
);
259 static_same_dest(struct static_route
*x
, struct static_route
*y
)
261 if (x
->dest
!= y
->dest
)
267 for (; x
&& y
; x
= x
->mp_next
, y
= y
->mp_next
)
269 if (!ipa_equal(x
->via
, y
->via
) ||
270 (x
->iface
!= y
->iface
) ||
271 (x
->onlink
!= y
->onlink
) ||
272 (x
->weight
!= y
->weight
) ||
273 (x
->use_bfd
!= y
->use_bfd
) ||
274 (!x
->mls
!= !y
->mls
) ||
275 ((x
->mls
) && (y
->mls
) && (x
->mls
->len
!= y
->mls
->len
)))
281 for (uint i
= 0; i
< x
->mls
->len
; i
++)
282 if (x
->mls
->stack
[i
] != y
->mls
->stack
[i
])
288 if (!ipa_equal(x
->via
, y
->via
) ||
289 (!x
->mls
!= !y
->mls
) ||
290 ((x
->mls
) && (y
->mls
) && (x
->mls
->len
!= y
->mls
->len
)))
296 for (uint i
= 0; i
< x
->mls
->len
; i
++)
297 if (x
->mls
->stack
[i
] != y
->mls
->stack
[i
])
308 static_same_rte(struct static_route
*or, struct static_route
*nr
)
310 /* Note that i_same() requires arguments in (new, old) order */
311 return static_same_dest(or, nr
) && i_same(nr
->cmds
, or->cmds
);
315 static_reconfigure_rte(struct static_proto
*p
, struct static_route
*or, struct static_route
*nr
)
317 if ((or->state
== SRS_CLEAN
) && !static_same_rte(or, nr
))
318 nr
->state
= SRS_DIRTY
;
320 nr
->state
= or->state
;
322 static_add_rte(p
, nr
);
323 static_reset_rte(p
, or);
328 static_neigh_notify(struct neighbor
*n
)
330 struct static_proto
*p
= (void *) n
->proto
;
331 struct static_route
*r
;
333 DBG("Static: neighbor notify for %I: iface %p\n", n
->addr
, n
->iface
);
334 for (r
= n
->data
; r
; r
= r
->chain
)
336 static_update_bfd(p
, r
);
338 if (static_decide(p
, r
))
339 static_mark_rte(p
, r
->mp_head
);
344 static_bfd_notify(struct bfd_request
*req
)
346 struct static_route
*r
= req
->data
;
347 struct static_proto
*p
= (void *) r
->neigh
->proto
;
349 // if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX);
351 if (static_decide(p
, r
))
352 static_mark_rte(p
, r
->mp_head
);
356 static_rte_mergable(rte
*pri UNUSED
, rte
*sec UNUSED
)
363 static_postconfig(struct proto_config
*CF
)
365 struct static_config
*cf
= (void *) CF
;
366 struct static_route
*r
;
368 if (EMPTY_LIST(CF
->channels
))
369 cf_error("Channel not specified");
371 struct channel_config
*cc
= proto_cf_main_channel(CF
);
373 if (!cf
->igp_table_ip4
)
374 cf
->igp_table_ip4
= (cc
->table
->addr_type
== NET_IP4
) ?
375 cc
->table
: cf
->c
.global
->def_tables
[NET_IP4
];
377 if (!cf
->igp_table_ip6
)
378 cf
->igp_table_ip6
= (cc
->table
->addr_type
== NET_IP6
) ?
379 cc
->table
: cf
->c
.global
->def_tables
[NET_IP6
];
381 WALK_LIST(r
, cf
->routes
)
382 if (r
->net
&& (r
->net
->type
!= CF
->net_type
))
383 cf_error("Route %N incompatible with channel type", r
->net
);
386 static struct proto
*
387 static_init(struct proto_config
*CF
)
389 struct proto
*P
= proto_new(CF
);
390 struct static_proto
*p
= (void *) P
;
391 struct static_config
*cf
= (void *) CF
;
393 P
->main_channel
= proto_add_channel(P
, proto_cf_main_channel(CF
));
395 P
->neigh_notify
= static_neigh_notify
;
396 P
->rte_mergable
= static_rte_mergable
;
398 if (cf
->igp_table_ip4
)
399 p
->igp_table_ip4
= cf
->igp_table_ip4
->table
;
401 if (cf
->igp_table_ip6
)
402 p
->igp_table_ip6
= cf
->igp_table_ip6
->table
;
408 static_start(struct proto
*P
)
410 struct static_proto
*p
= (void *) P
;
411 struct static_config
*cf
= (void *) P
->cf
;
412 struct static_route
*r
;
415 static_lp
= lp_new(&root_pool
, LP_GOOD_SIZE(1024));
417 if (p
->igp_table_ip4
)
418 rt_lock_table(p
->igp_table_ip4
);
420 if (p
->igp_table_ip6
)
421 rt_lock_table(p
->igp_table_ip6
);
423 p
->event
= ev_new_init(p
->p
.pool
, static_announce_marked
, p
);
425 BUFFER_INIT(p
->marked
, p
->p
.pool
, 4);
427 /* We have to go UP before routes could be installed */
428 proto_notify_state(P
, PS_UP
);
430 WALK_LIST(r
, cf
->routes
)
431 static_add_rte(p
, r
);
437 static_shutdown(struct proto
*P
)
439 struct static_proto
*p
= (void *) P
;
440 struct static_config
*cf
= (void *) P
->cf
;
441 struct static_route
*r
;
443 /* Just reset the flag, the routes will be flushed by the nest */
444 WALK_LIST(r
, cf
->routes
)
445 static_reset_rte(p
, r
);
451 static_cleanup(struct proto
*P
)
453 struct static_proto
*p
= (void *) P
;
455 if (p
->igp_table_ip4
)
456 rt_unlock_table(p
->igp_table_ip4
);
458 if (p
->igp_table_ip6
)
459 rt_unlock_table(p
->igp_table_ip6
);
463 static_dump_rte(struct static_route
*r
)
465 debug("%-1N: ", r
->net
);
466 if (r
->dest
== RTD_UNICAST
)
467 if (r
->iface
&& ipa_zero(r
->via
))
468 debug("dev %s\n", r
->iface
->name
);
470 debug("via %I%J\n", r
->via
, r
->iface
);
472 debug("rtd %d\n", r
->dest
);
476 static_dump(struct proto
*P
)
478 struct static_config
*c
= (void *) P
->cf
;
479 struct static_route
*r
;
481 debug("Static routes:\n");
482 WALK_LIST(r
, c
->routes
)
486 #define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
489 static_cmp_rte(const void *X
, const void *Y
)
491 struct static_route
*x
= *(void **)X
, *y
= *(void **)Y
;
492 return net_compare(x
->net
, y
->net
);
496 static_reconfigure(struct proto
*P
, struct proto_config
*CF
)
498 struct static_proto
*p
= (void *) P
;
499 struct static_config
*o
= (void *) P
->cf
;
500 struct static_config
*n
= (void *) CF
;
501 struct static_route
*r
, *r2
, *or, *nr
;
503 /* Check change in IGP tables */
504 if ((IGP_TABLE(o
, ip4
) != IGP_TABLE(n
, ip4
)) ||
505 (IGP_TABLE(o
, ip6
) != IGP_TABLE(n
, ip6
)))
508 if (!proto_configure_channel(P
, &P
->main_channel
, proto_cf_main_channel(CF
)))
513 /* Reset route lists in neighbor entries */
514 WALK_LIST(r
, o
->routes
)
515 for (r2
= r
; r2
; r2
= r2
->mp_next
)
517 r2
->neigh
->data
= NULL
;
519 /* Reconfigure initial matching sequence */
520 for (or = HEAD(o
->routes
), nr
= HEAD(n
->routes
);
521 NODE_VALID(or) && NODE_VALID(nr
) && net_equal(or->net
, nr
->net
);
522 or = NODE_NEXT(or), nr
= NODE_NEXT(nr
))
523 static_reconfigure_rte(p
, or, nr
);
525 if (!NODE_VALID(or) && !NODE_VALID(nr
))
528 /* Reconfigure remaining routes, sort them to find matching pairs */
529 struct static_route
*or2
, *nr2
, **orbuf
, **nrbuf
;
530 uint ornum
= 0, nrnum
= 0, orpos
= 0, nrpos
= 0, i
;
532 for (or2
= or; NODE_VALID(or2
); or2
= NODE_NEXT(or2
))
535 for (nr2
= nr
; NODE_VALID(nr2
); nr2
= NODE_NEXT(nr2
))
538 orbuf
= xmalloc(ornum
* sizeof(void *));
539 nrbuf
= xmalloc(nrnum
* sizeof(void *));
541 for (i
= 0, or2
= or; i
< ornum
; i
++, or2
= NODE_NEXT(or2
))
544 for (i
= 0, nr2
= nr
; i
< nrnum
; i
++, nr2
= NODE_NEXT(nr2
))
547 qsort(orbuf
, ornum
, sizeof(struct static_route
*), static_cmp_rte
);
548 qsort(nrbuf
, nrnum
, sizeof(struct static_route
*), static_cmp_rte
);
550 while ((orpos
< ornum
) && (nrpos
< nrnum
))
552 int x
= net_compare(orbuf
[orpos
]->net
, nrbuf
[nrpos
]->net
);
554 static_remove_rte(p
, orbuf
[orpos
++]);
556 static_add_rte(p
, nrbuf
[nrpos
++]);
558 static_reconfigure_rte(p
, orbuf
[orpos
++], nrbuf
[nrpos
++]);
561 while (orpos
< ornum
)
562 static_remove_rte(p
, orbuf
[orpos
++]);
564 while (nrpos
< nrnum
)
565 static_add_rte(p
, nrbuf
[nrpos
++]);
574 static_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
576 struct static_config
*d
= (struct static_config
*) dest
;
577 struct static_config
*s
= (struct static_config
*) src
;
579 struct static_route
*srt
, *snh
;
581 /* Copy route list */
582 init_list(&d
->routes
);
583 WALK_LIST(srt
, s
->routes
)
585 struct static_route
*drt
= NULL
, *dnh
= NULL
, **dnp
= &drt
;
587 for (snh
= srt
; snh
; snh
= snh
->mp_next
)
589 dnh
= cfg_alloc(sizeof(struct static_route
));
590 memcpy(dnh
, snh
, sizeof(struct static_route
));
593 add_tail(&d
->routes
, &(dnh
->n
));
596 dnp
= &(dnh
->mp_next
);
605 static_show_rt(struct static_route
*r
)
611 struct static_route
*r2
;
613 cli_msg(-1009, "%N", r
->net
);
614 for (r2
= r
; r2
; r2
= r2
->mp_next
)
616 if (r2
->iface
&& ipa_zero(r2
->via
))
617 cli_msg(-1009, "\tdev %s%s", r2
->iface
->name
,
618 r2
->active
? "" : " (dormant)");
620 cli_msg(-1009, "\tvia %I%J%s%s%s", r2
->via
, r2
->iface
,
621 r2
->onlink
? " onlink" : "",
622 r2
->bfd_req
? " (bfd)" : "",
623 r2
->active
? "" : " (dormant)");
630 case RTD_UNREACHABLE
:
632 cli_msg(-1009, "%N\t%s", r
->net
, rta_dest_names
[r
->dest
]);
636 cli_msg(-1009, "%N\trecursive %I", r
->net
, r
->via
);
642 static_show(struct proto
*P
)
644 struct static_config
*c
= (void *) P
->cf
;
645 struct static_route
*r
;
647 WALK_LIST(r
, c
->routes
)
653 struct protocol proto_static
= {
655 .template = "static%d",
656 .class = PROTOCOL_STATIC
,
657 .preference
= DEF_PREF_STATIC
,
658 .channel_mask
= NB_ANY
,
659 .proto_size
= sizeof(struct static_proto
),
660 .config_size
= sizeof(struct static_config
),
661 .postconfig
= static_postconfig
,
664 .start
= static_start
,
665 .shutdown
= static_shutdown
,
666 .cleanup
= static_cleanup
,
667 .reconfigure
= static_reconfigure
,
668 .copy_config
= static_copy_config