diff --git a/conf/conf.c b/conf/conf.c index 6dfa3691..14225d3b 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -200,9 +200,19 @@ global_commit(struct config *new, struct config *old) log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD."); if (!new->router_id) - new->router_id = old->router_id; - if (new->router_id != old->router_id) - return 1; + { + new->router_id = old->router_id; + + if (new->router_id_from) + { + u32 id = if_choose_router_id(new->router_id_from, old->router_id); + if (!id) + log(L_WARN "Cannot determine router ID, using old one"); + else + new->router_id = id; + } + } + return 0; } diff --git a/conf/conf.h b/conf/conf.h index 19300f54..683374e0 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -26,6 +26,7 @@ struct config { int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */ char *syslog_name; /* Name used for syslog (NULL -> no syslog) */ struct rtable_config *master_rtc; /* Configuration of master routing table */ + struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ u32 router_id; /* Our Router ID */ ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */ diff --git a/doc/bird.sgml b/doc/bird.sgml index 615ced98..4e04a138 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -337,7 +337,18 @@ protocol rip { Besides, there are some predefined numeric constants based on /etc/iproute2/rt_* files. A list of defined constants can be seen (together with other symbols) using 'show symbols' command. - router id Set BIRD's router ID. It's a world-wide unique identification of your router, usually one of router's IPv4 addresses. Default: in IPv4 version, the lowest IP address of a non-loopback interface. In IPv6 version, this option is mandatory. + router id + Set BIRD's router ID. It's a world-wide unique identification + of your router, usually one of router's IPv4 addresses. + Default: in IPv4 version, the lowest IP address of a + non-loopback interface. In IPv6 version, this option is + mandatory. + + router id from [-] [ " + Set BIRD's router ID based on an IP address of an interface + specified by an interface pattern. The option is applicable + for IPv4 version only. See + section for detailed description of interface patterns. listen bgp [address This option allows to specify address and port where BGP diff --git a/nest/config.Y b/nest/config.Y index cb6a85c2..dbd72055 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -75,9 +75,9 @@ CF_GRAMMAR CF_ADDTO(conf, rtrid) -rtrid: ROUTER ID idval ';' { - new_config->router_id = $3; - } +rtrid: + ROUTER ID idval ';' { new_config->router_id = $3; } + | ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; } ; idval: @@ -264,6 +264,17 @@ iface_patt_list: | iface_patt_list ',' iface_patt_node ; +iface_patt_init: { + /* Generic this_ipatt init */ + this_ipatt = cfg_allocz(sizeof(struct iface_patt)); + init_list(&this_ipatt->ipn_list); + } + ; + +iface_patt: + iface_patt_init iface_patt_list + ; + /* Direct device route protocol */ diff --git a/nest/iface.c b/nest/iface.c index eea3d3b1..da79b21f 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -35,8 +35,6 @@ static pool *if_pool; -static void auto_router_id(void); - list iface_list; /** @@ -354,9 +352,6 @@ if_end_update(void) struct iface *i; struct ifa *a, *b; - if (!config->router_id) - auto_router_id(); - WALK_LIST(i, iface_list) { if (!(i->flags & IF_UPDATED)) @@ -583,24 +578,57 @@ ifa_delete(struct ifa *a) } } -static void -auto_router_id(void) +u32 +if_choose_router_id(struct iface_patt *mask, u32 old_id) { #ifndef IPV6 - struct iface *i, *j; + struct iface *i; + struct ifa *a, *b; - j = NULL; + b = NULL; WALK_LIST(i, iface_list) - if ((i->flags & IF_ADMIN_UP) && - !(i->flags & (IF_IGNORE | IF_SHUTDOWN)) && - i->addr && - !(i->addr->flags & IA_PEER) && - (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip))) - j = i; - if (!j) - die("Cannot determine router ID (no suitable network interface found), please configure it manually"); - log(L_INFO "Guessed router ID %I according to interface %s", j->addr->ip, j->name); - config->router_id = ipa_to_u32(j->addr->ip); + { + if (!(i->flags & IF_ADMIN_UP) || + (i->flags & (IF_IGNORE | IF_SHUTDOWN))) + continue; + + WALK_LIST(a, i->addrs) + { + if (a->flags & IA_SECONDARY) + continue; + + if (a->scope <= SCOPE_LINK) + continue; + + /* FIXME: This should go away */ + if (a->flags & IA_PEER) + continue; + + /* FIXME: This should go away too */ + if (!mask && (a != i->addr)) + continue; + + /* Check pattern if specified */ + if (mask && !iface_patt_match(mask, i, a)) + continue; + + /* No pattern or pattern matched */ + if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip)) + b = a; + } + } + + if (!b) + return 0; + + u32 id = ipa_to_u32(b->ip); + if (id != old_id) + log(L_INFO "Chosen router ID %R according to interface %s", id, b->iface->name); + + return id; + +#else + return 0; #endif } diff --git a/nest/iface.h b/nest/iface.h index 2416f82f..697ea543 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -101,6 +101,7 @@ struct iface *if_find_by_name(char *); struct iface *if_get_by_name(char *); void ifa_recalc_all_primary_addresses(void); + /* The Neighbor Cache */ typedef struct neighbor { @@ -161,4 +162,7 @@ int iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a); struct iface_patt *iface_patt_find(list *l, struct iface *i, struct ifa *a); int iface_patts_equal(list *, list *, int (*)(struct iface_patt *, struct iface_patt *)); + +u32 if_choose_router_id(struct iface_patt *mask, u32 old_id); + #endif diff --git a/nest/proto.c b/nest/proto.c index 1334884e..b976a6cb 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -382,11 +382,9 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config /* If there is a too big change in core attributes, ... */ if ((nc->protocol != oc->protocol) || (nc->disabled != p->disabled) || - (nc->table->table != oc->table->table) || - (proto_get_router_id(nc) != proto_get_router_id(oc))) + (nc->table->table != oc->table->table)) return 0; - p->debug = nc->debug; p->mrtdump = nc->mrtdump; proto_reconfig_type = type; @@ -552,6 +550,16 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty initial_device_proto = NULL; } + /* Determine router ID for the first time - it has to be here and not in + global_commit() because it is postponed after start of device protocol */ + if (!config->router_id) + { + config->router_id = if_choose_router_id(config->router_id_from, 0); + if (!config->router_id) + die("Cannot determine router ID, please configure it manually"); + } + + /* Start all other protocols */ WALK_LIST_DELSAFE(p, n, initial_proto_list) proto_rethink_goal(p); } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 346c641b..249d2e07 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1009,6 +1009,9 @@ bgp_reconfigure(struct proto *P, struct proto_config *C) struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_config *old = p->cf; + if (proto_get_router_id(C) != p->local_id) + return 0; + int same = !memcmp(((byte *) old) + sizeof(struct proto_config), ((byte *) new) + sizeof(struct proto_config), // password item is last and must be checked separately diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 6654e107..a3b6b2e7 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -729,6 +729,9 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) struct ospf_iface *ifa, *ifx; struct ospf_iface_patt *ip; + if (proto_get_router_id(c) != po->router_id) + return 0; + if (po->rfc1583 != new->rfc1583) return 0;