diff --git a/NEWS b/NEWS index 1341fcd4..4e3349c3 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1,23 @@ -Version 1.3.12 (2013-11-23) +Version 1.4.0 (2013-11-25) o BFD protocol (RFC 5880). o BFD support for OSPF and BGP. o New 'allow local as' option for BGP. o Filters allows setting gw, ifname and ifindex. o Filter operator 'delete/filter' extended to bgp_paths. o Filter operator 'len' extended to [e]clists. - o PID file support. + o BIRD client now allows shorthands for noninteractive commands. + o Flag -P for PID file support. + o Flag -f added to force BIRD to run in foreground. + o Protocol export/import/receive limits are checked during reconfiguration. o Several bugfixes and minor improvements. + o Several minor but incompatible changes: + - IBGP is multihop by default. + - Changes primary address selection on BSD to the first one. + - Integers in filters are handled as unsigned. + - ISO 8601 time formats used by default. + - Import of device routes from kernel protocol allowed. + - Last state change now tracks just protocol state change. + - Minor changes to default router ID calculation. Version 1.3.11 (2013-07-27) o OSPF stub router option (RFC 3137). diff --git a/client/client.c b/client/client.c index a9d0096d..b938f344 100644 --- a/client/client.c +++ b/client/client.c @@ -137,6 +137,21 @@ submit_server_command(char *cmd) server_send(cmd); } +static inline void +submit_init_command(char *cmd_raw) +{ + char *cmd = cmd_expand(cmd_raw); + + if (!cmd) + { + cleanup(); + exit(0); + } + + submit_server_command(cmd); + free(cmd); +} + void submit_command(char *cmd_raw) { @@ -165,7 +180,7 @@ init_commands(void) { /* First transition - client received hello from BIRD and there is waiting initial command */ - submit_server_command(init_cmd); + submit_init_command(init_cmd); init_cmd = NULL; return; } diff --git a/conf/conf.c b/conf/conf.c index 14225d3b..fc674ef3 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -96,7 +96,8 @@ config_alloc(byte *name) cfg_mem = c->mem = l; c->file_name = cfg_strdup(name); c->load_time = now; - c->tf_base.fmt1 = c->tf_log.fmt1 = "%d-%m-%Y %T"; + c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; + c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; return c; } diff --git a/doc/bird.sgml b/doc/bird.sgml index 46d2e026..269743d5 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -256,7 +256,10 @@ which allows you to talk with BIRD in an extensive way.

In the config, everything on a line after /* */ is a comment, whitespace characters are treated as a single space. If there's a variable number of options, they are grouped using the Here is an example of a simple config file. It enables synchronization of routing tables with OS kernel, scans for @@ -377,7 +380,7 @@ protocol rip { " and "table Create a new routing table. The default routing table is @@ -922,9 +929,10 @@ incompatible with each other (that is to prevent you from shooting in the foot). - local [ Define which AS we - are part of. (Note that contrary to other IP routers, BIRD is - able to act as a router located in multiple AS'es - simultaneously, but in such cases you need to tweak the BGP - paths manually in the filters to get consistent behavior.) - Optional local [ Define which AS we are part + of. (Note that contrary to other IP routers, BIRD is able to act as a + router located in multiple AS'es simultaneously, but in such cases you + need to tweak the BGP paths manually in the filters to get consistent + behavior.) Optional neighbor Define neighboring router this + instance will be talking to and what AS it's located in. In case the + neighbor is in the same AS as we are, we automatically switch to iBGP. This parameter is mandatory. - neighbor Define neighboring router - this instance will be talking to and what AS it's located in. Unless - you use the direct Specify that the neighbor is directly connected. The + IP address of the neighbor must be from a directly reachable IP range + (i.e. associated with one of your router's interfaces), otherwise the + BGP session wouldn't start but it would wait for such interface to + appear. The alternative is the multihop [ Configure multihop BGP - session to a neighbor that isn't directly connected. - Accurately, this option should be used if the configured - neighbor IP address does not match with any local network - subnets. Such IP address have to be reachable through system - routing table. For multihop BGP it is recommended to - explicitly configure multihop [ Configure multihop BGP session to a + neighbor that isn't directly connected. Accurately, this option should + be used if the configured neighbor IP address does not match with any + local network subnets. Such IP address have to be reachable through + system routing table. The alternative is the source address Define local address we should use for next hop calculation and as a source address @@ -1605,8 +1617,8 @@ for each neighbor using the following configuration parameters: table, and was used in older versions of BIRD, but does not handle well nontrivial iBGP setups and multihop. Recursive mode is incompatible with . Default: . Default: igp table Specifies a table that is used as an IGP routing table. Default: the same as the table BGP is diff --git a/doc/reply_codes b/doc/reply_codes index e9996eef..45b42e00 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -53,6 +53,7 @@ Reply codes of BIRD command-line interface 1017 Show ospf lsadb 1018 Show memory 1019 Show ROA list +1020 Show BFD sessions 8000 Reply too long 8001 Route not found diff --git a/filter/filter.c b/filter/filter.c index ed8efd54..88763302 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -90,12 +90,6 @@ pm_format(struct f_path_mask *p, buffer *buf) buffer_puts(buf, "=]"); } -static inline int -int_cmp(int i1, int i2) -{ - return (i1 > i2) - (i1 < i2); -} - static inline int uint_cmp(uint i1, uint i2) { @@ -146,7 +140,6 @@ val_compare(struct f_val v1, struct f_val v2) case T_ENUM: case T_INT: case T_BOOL: - return int_cmp(v1.val.i, v2.val.i); case T_PAIR: case T_QUAD: return uint_cmp(v1.val.i, v2.val.i); @@ -157,7 +150,7 @@ val_compare(struct f_val v1, struct f_val v2) case T_PREFIX: if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip)) return rc; - return int_cmp(v1.val.px.len, v2.val.px.len); + return uint_cmp(v1.val.px.len, v2.val.px.len); case T_STRING: return strcmp(v1.val.s, v2.val.s); default: @@ -442,16 +435,16 @@ val_format(struct f_val v, buffer *buf) { case T_VOID: buffer_puts(buf, "(void)"); return; case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return; - case T_INT: buffer_print(buf, "%d", v.val.i); return; + case T_INT: buffer_print(buf, "%u", v.val.i); return; case T_STRING: buffer_print(buf, "%s", v.val.s); return; case T_IP: buffer_print(buf, "%I", v.val.px.ip); return; case T_PREFIX: buffer_print(buf, "%I/%d", v.val.px.ip, v.val.px.len); return; - case T_PAIR: buffer_print(buf, "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return; + case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return; case T_QUAD: buffer_print(buf, "%R", v.val.i); return; case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return; case T_PREFIX_SET: trie_format(v.val.ti, buf); return; case T_SET: tree_format(v.val.t, buf); return; - case T_ENUM: buffer_print(buf, "(enum %x)%d", v.type, v.val.i); return; + case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return; case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; @@ -1167,14 +1160,14 @@ interpret(struct f_inst *what) /* Community (or cluster) list */ struct f_val dummy; int arg_set = 0; - i = 0; + uint n = 0; if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) - i = v2.val.i; + n = v2.val.i; #ifndef IPV6 /* IP->Quad implicit conversion */ else if (v2.type == T_IP) - i = ipa_to_u32(v2.val.px.ip); + n = ipa_to_u32(v2.val.px.ip); #endif else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy)) arg_set = 1; @@ -1190,14 +1183,14 @@ interpret(struct f_inst *what) if (arg_set == 1) runtime("Can't add set"); else if (!arg_set) - res.val.ad = int_set_add(f_pool, v1.val.ad, i); + res.val.ad = int_set_add(f_pool, v1.val.ad, n); else res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) - res.val.ad = int_set_del(f_pool, v1.val.ad, i); + res.val.ad = int_set_del(f_pool, v1.val.ad, n); else res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0); break; @@ -1502,7 +1495,7 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc log( L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); return F_ERROR; } - DBG( "done (%d)\n", res.val.i ); + DBG( "done (%u)\n", res.val.i ); return res.val.i; } @@ -1519,7 +1512,7 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool) return interpret(expr); } -int +uint f_eval_int(struct f_inst *expr) { /* Called independently in parse-time to eval expressions */ diff --git a/filter/filter.h b/filter/filter.h index 07a4c9e4..3a6b66d9 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -51,7 +51,7 @@ struct f_prefix { struct f_val { int type; union { - int i; + uint i; u64 ec; /* ip_addr ip; Folded into prefix */ struct f_prefix px; @@ -108,7 +108,7 @@ struct rte; int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags); struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); -int f_eval_int(struct f_inst *expr); +uint f_eval_int(struct f_inst *expr); u32 f_eval_asn(struct f_inst *expr); char *filter_name(struct filter *filter); diff --git a/misc/bird.spec b/misc/bird.spec index c27eabbf..162dac55 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.3.12 +Version: 1.4.0 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/nest/iface.c b/nest/iface.c index b4ab70c3..298698a7 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -600,22 +600,10 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id) 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; - /* FIXME: This should go away too */ - if ((i->flags & IF_IGNORE) && !mask) - continue; - /* No pattern or pattern matched */ if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip)) b = a; diff --git a/nest/proto.c b/nest/proto.c index 019b846e..cfa6ff4b 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -48,7 +48,6 @@ static void proto_enqueue(list *l, struct proto *p) { add_tail(l, &p->n); - p->last_state_change = now; } static void @@ -363,6 +362,8 @@ proto_init(struct proto_config *c) q->proto_state = PS_DOWN; q->core_state = FS_HUNGRY; + q->last_state_change = now; + proto_enqueue(&initial_proto_list, q); if (p == &proto_unix_iface) initial_device_proto = q; @@ -1084,6 +1085,7 @@ proto_notify_state(struct proto *p, unsigned ps) return; p->proto_state = ps; + p->last_state_change = now; switch (ps) { diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 5ebfadc1..89355483 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1070,13 +1070,13 @@ bfd_show_sessions(struct proto *P) if (p->p.proto_state != PS_UP) { - cli_msg(-1013, "%s: is not up", p->p.name); + cli_msg(-1020, "%s: is not up", p->p.name); cli_msg(0, ""); return; } - cli_msg(-1013, "%s:", p->p.name); - cli_msg(-1013, "%-25s %-10s %-10s %-10s %8s %8s", + cli_msg(-1020, "%s:", p->p.name); + cli_msg(-1020, "%-25s %-10s %-10s %-10s %8s %8s", "IP address", "Interface", "State", "Since", "Interval", "Timeout"); @@ -1092,7 +1092,7 @@ bfd_show_sessions(struct proto *P) state = (state < 4) ? state : 0; tm_format_datetime(tbuf, &config->tf_proto, s->last_state_change); - cli_msg(-1013, "%-25I %-10s %-10s %-10s %3u.%03u %3u.%03u", + cli_msg(-1020, "%-25I %-10s %-10s %-10s %3u.%03u %3u.%03u", s->addr, ifname, bfd_state_names[state], tbuf, tx_int / 1000, tx_int % 1000, timeout / 1000, timeout % 1000); } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 81a263bb..f05a85d4 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1009,6 +1009,24 @@ bgp_check_config(struct bgp_config *c) if (c->c.class == SYM_TEMPLATE) return; + + /* EBGP direct by default, IBGP multihop by default */ + if (c->multihop < 0) + c->multihop = internal ? 64 : 0; + + /* Different default for gw_mode */ + if (!c->gw_mode) + c->gw_mode = c->multihop ? GW_RECURSIVE : GW_DIRECT; + + /* Different default based on rs_client */ + if (!c->missing_lladdr) + c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; + + /* Disable after error incompatible with restart limit action */ + if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error) + c->c.in_limit->action = PLA_DISABLE; + + if (!c->local_as) cf_error("Local AS number must be set"); @@ -1024,7 +1042,6 @@ bgp_check_config(struct bgp_config *c) if (internal && c->rs_client) cf_error("Only external neighbor can be RS client"); - if (c->multihop && (c->gw_mode == GW_DIRECT)) cf_error("Multihop BGP cannot use direct gateway mode"); @@ -1035,20 +1052,6 @@ bgp_check_config(struct bgp_config *c) if (c->multihop && c->bfd && ipa_zero(c->source_addr)) cf_error("Multihop BGP with BFD requires specified source address"); - - /* Different default based on rs_client */ - if (!c->missing_lladdr) - c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; - - /* Different default for gw_mode */ - if (!c->gw_mode) - c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT; - - /* Disable after error incompatible with restart limit action */ - if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error) - c->c.in_limit->action = PLA_DISABLE; - - if ((c->gw_mode == GW_RECURSIVE) && c->c.table->sorted) cf_error("BGP in recursive mode prohibits sorted table"); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index ab12fed5..76a76470 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -34,6 +34,7 @@ CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } ) bgp_proto_start: proto_start BGP { this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1); + BGP_CFG->multihop = -1; /* undefined */ BGP_CFG->hold_time = 240; BGP_CFG->connect_retry_time = 120; BGP_CFG->initial_hold_time = 240; @@ -74,6 +75,7 @@ bgp_proto: | bgp_proto STARTUP HOLD TIME expr ';' { BGP_CFG->initial_hold_time = $5; } | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; } | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; } + | bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; } | bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; } | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); } | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; BGP_CFG->next_hop_keep = 0; } diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index f1409840..333c2a6d 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -472,10 +472,14 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr) if (! addr) return 0; - /* a host/loopback address */ + /* a host address */ if (addr->flags & IA_HOST) return 1; + /* a loopback iface */ + if (addr->iface->flags & IF_LOOPBACK) + return 1; + /* * We cannot properly support multiple OSPF ifaces on real iface * with multiple prefixes, therefore we force OSPF ifaces with diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 69a476d9..176e11ed 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -1058,3 +1058,36 @@ kif_sys_shutdown(struct kif_proto *p) krt_buffer_release(&p->p); } + +struct ifa * +kif_get_primary_ip(struct iface *i) +{ +#ifndef IPV6 + static int fd = -1; + + if (fd < 0) + fd = socket(AF_INET, SOCK_DGRAM, 0); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, i->name, IFNAMSIZ); + + int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr); + if (rv < 0) + return NULL; + + ip_addr addr; + struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr; + memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr)); + ipa_ntoh(addr); + + struct ifa *a; + WALK_LIST(a, i->addrs) + { + if (ipa_equal(a->ip, addr)) + return a; + } +#endif + + return NULL; +} diff --git a/sysdep/config.h b/sysdep/config.h index 914c1090..eb5606ac 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.3.12" +#define BIRD_VERSION "1.4.0" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 7b3043a7..7e97968a 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -27,6 +27,8 @@ static inline void kif_sys_postconfig(struct kif_config *c UNUSED) { } static inline void kif_sys_init_config(struct kif_config *c UNUSED) { } static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_config *s UNUSED) { } +static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } + /* Kernel routes */ diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 90443ed6..ed8769b7 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -862,19 +862,6 @@ nl_parse_route(struct nlmsghdr *h, int scan) else { ra.dest = RTD_DEVICE; - - /* - * In Linux IPv6, 'native' device routes have proto - * RTPROT_BOOT and not RTPROT_KERNEL (which they have in - * IPv4 and which is expected). We cannot distinguish - * 'native' and user defined device routes, so we ignore all - * such device routes and for consistency, we have the same - * behavior in IPv4. Anyway, users should use RTPROT_STATIC - * for their 'alien' routes. - */ - - if (i->rtm_protocol == RTPROT_BOOT) - src = KRT_SRC_KERNEL; } break; diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 7bade918..1bba9a0d 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -14,7 +14,7 @@ CF_HDR CF_DECLS CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT) -CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, BASE, NAME, CONFIRM, UNDO, CHECK, TIMEOUT) +CF_KEYWORDS(TIMEFORMAT, ISO, OLD, SHORT, LONG, BASE, NAME, CONFIRM, UNDO, CHECK, TIMEOUT) %type log_mask log_mask_list log_cat cfg_timeout %type log_file @@ -96,6 +96,8 @@ timeformat_spec: | timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, $3}; } | timeformat_which ISO SHORT { *$1 = (struct timeformat){"%T", "%F", 20*3600}; } | timeformat_which ISO LONG { *$1 = (struct timeformat){"%F %T", NULL, 0}; } + | timeformat_which OLD SHORT { *$1 = (struct timeformat){NULL, NULL, 0}; } + | timeformat_which OLD LONG { *$1 = (struct timeformat){"%d-%m-%Y %T", NULL, 0}; } ; timeformat_base: diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 3f9e1479..6fdef619 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -159,6 +159,9 @@ kif_choose_primary(struct iface *i) return a; } + if (a = kif_get_primary_ip(i)) + return a; + return find_preferred_ifa(i, IPA_NONE, IPA_NONE); } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 446914d2..99983ccd 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -142,5 +142,6 @@ void kif_sys_copy_config(struct kif_config *, struct kif_config *); void kif_do_scan(struct kif_proto *); +struct ifa *kif_get_primary_ip(struct iface *i); #endif