From dca75fd7c207f0bfc627cb6b74a484da3b27e05f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 13 Feb 2010 12:26:26 +0100 Subject: Removes phantom protocol from the pipe design. It seems that by adding one pipe-specific exception to route announcement code and by adding one argument to rt_notify() callback i could completely eliminate the need for the phantom protocol instance and therefore make the code more straightforward. It will also fix some minor bugs (like ignoring debug flag changes from the command line). --- sysdep/unix/krt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sysdep/unix/krt.c') diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 488447b7..6d94cada 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -742,7 +742,8 @@ krt_scan(timer *t UNUSED) */ static void -krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED) +krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, + rte *new, rte *old, struct ea_list *attrs UNUSED) { struct krt_proto *p = (struct krt_proto *) P; -- cgit v1.2.3 From ff2857b03db854f99902766ad842aaa5fa29ec3c Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 26 Feb 2010 10:55:58 +0100 Subject: Many changes in (mainly) kernel syncers. - BSD kernel syncer is now self-conscious and can learn alien routes - important bugfix in BSD kernel syncer (crash after protocol restart) - many minor changes and bugfixes in kernel syncers and neighbor cache - direct protocol does not generate host and link local routes - min_scope check is removed, all routes have SCOPE_UNIVERSE by default - also fixes some remaining compiler warnings --- doc/bird.sgml | 15 ++- lib/ip.h | 4 + nest/iface.h | 1 + nest/neighbor.c | 23 +++- nest/proto.c | 1 - nest/protocol.h | 1 - nest/rt-dev.c | 7 +- nest/rt-table.c | 52 ++------- proto/bgp/packets.c | 3 - proto/ospf/ospf.c | 12 +- proto/ospf/rt.c | 6 +- sysdep/bsd/krt-sock.c | 250 +++++++++++++++++++++-------------------- sysdep/cf/bsd-v6.h | 2 +- sysdep/cf/bsd.h | 2 +- sysdep/linux/netlink/netlink.c | 151 ++++++++++--------------- sysdep/unix/io.c | 2 +- sysdep/unix/krt.c | 40 +++---- sysdep/unix/krt.h | 1 + sysdep/unix/unix.h | 4 + 19 files changed, 279 insertions(+), 298 deletions(-) (limited to 'sysdep/unix/krt.c') diff --git a/doc/bird.sgml b/doc/bird.sgml index 3d82e45b..b70f0345 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -824,7 +824,14 @@ defined by using the defined( attribute ) operator. Network the route is talking about. Read-only. (See the chapter about routing tables.) - Address scope of the network ( Preference of the route. Valid values are 0-65535. (See the chapter about routing tables.) @@ -842,7 +849,11 @@ defined by using the defined( attribute ) operator. what protocol has told me about this route. Possible values: - Route type ( Type of destination the packets should be sent to (proto == p && ipa_equal(*a, n->addr)) + if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface))) return n; class = ipa_classify(*a); @@ -129,7 +129,12 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) return NULL; /* Bad scope or a somecast */ if (ifa) - scope = if_connected(a, ifa); + { + scope = if_connected(a, ifa); + + if ((scope < 0) && (flags & NEF_ONLINK)) + scope = class & IADDR_SCOPE_MASK; + } else WALK_LIST(i, iface_list) if ((scope = if_connected(a, i)) >= 0) @@ -138,22 +143,28 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) break; } - if (!ifa && !(flags & NEF_STICKY)) + /* scope < 0 means i don't know neighbor */ + /* scope >= 0 implies ifa != NULL */ + + if ((scope < 0) && !(flags & NEF_STICKY)) return NULL; n = sl_alloc(neigh_slab); n->addr = *a; - n->iface = ifa; - if (ifa) + if (scope >= 0) { add_tail(&neigh_hash_table[h], &n->n); add_tail(&ifa->neighbors, &n->if_n); } else { + /* sticky flag does not work for link-local neighbors; + fortunately, we don't use this combination */ add_tail(&sticky_neigh_list, &n->n); + ifa = NULL; scope = 0; } + n->iface = ifa; n->proto = p; n->data = NULL; n->aux = 0; diff --git a/nest/proto.c b/nest/proto.c index 48837055..db6bf9bf 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -113,7 +113,6 @@ proto_new(struct proto_config *c, unsigned size) p->table = c->table->table; p->in_filter = c->in_filter; p->out_filter = c->out_filter; - p->min_scope = SCOPE_SITE; p->hash_key = random_u32(); c->proto = p; return p; diff --git a/nest/protocol.h b/nest/protocol.h index 99356a3d..d94873e4 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -130,7 +130,6 @@ struct proto { u32 debug; /* Debugging flags */ u32 mrtdump; /* MRTDump flags */ unsigned preference; /* Default route preference */ - int min_scope; /* Minimal route scope accepted */ unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */ unsigned disabled; /* Manually disabled */ unsigned proto_state; /* Protocol state machine (see below) */ diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b86015df..bb8eb8ee 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -33,6 +33,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) !iface_patt_find(&P->iface_list, ad->iface)) /* Empty list is automagically treated as "*" */ return; + + if (ad->scope <= SCOPE_LINK) + return; + if (c & IF_CHANGE_DOWN) { net *n; @@ -56,7 +60,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) bzero(&A, sizeof(A)); A.proto = p; A.source = RTS_DEVICE; - A.scope = ad->scope; + A.scope = SCOPE_UNIVERSE; A.cast = RTC_UNICAST; A.dest = RTD_DEVICE; A.iface = ad->iface; @@ -76,7 +80,6 @@ dev_init(struct proto_config *c) struct proto *p = proto_new(c, sizeof(struct proto)); p->ifa_notify = dev_ifa_notify; - p->min_scope = SCOPE_HOST; return p; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 41ecf646..1860b1a1 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,7 +158,7 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) } static inline void -do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) +do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int refeed) { struct proto *p = a->proto; struct filter *filter = p->out_filter; @@ -183,13 +183,7 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt stats->exp_updates_received++; char *drop_reason = NULL; - if ((class & IADDR_SCOPE_MASK) < p->min_scope) - { - stats->exp_updates_rejected++; - drop_reason = "out of scope"; - fast_exit_hack = 1; - } - else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) + if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) { stats->exp_updates_rejected++; drop_reason = "rejected by protocol"; @@ -332,7 +326,6 @@ static void rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list *tmpa) { struct announce_hook *a; - int class = ipa_classify(net->n.prefix); if (type == RA_OPTIMAL) { @@ -346,7 +339,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list * { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); if (a->proto->accept_ra_types == type) - do_rte_announce(a, type, net, new, old, tmpa, class, 0); + do_rte_announce(a, type, net, new, old, tmpa, 0); } } @@ -362,33 +355,15 @@ rte_validate(rte *e) n->n.prefix, n->n.pxlen, e->sender->name); return 0; } - if (n->n.pxlen) + + c = ipa_classify_net(n->n.prefix); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { - c = ipa_classify(n->n.prefix); - if (c < 0 || !(c & IADDR_HOST)) - { - if (!ipa_nonzero(n->n.prefix)) - { - /* Various default routes */ -#ifdef IPV6 - if (n->n.pxlen == 96) -#else - if (n->n.pxlen <= 1) -#endif - return 1; - } - log(L_WARN "Ignoring bogus route %I/%d received via %s", - n->n.prefix, n->n.pxlen, e->sender->name); - return 0; - } - if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope) - { - log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s", - ip_scope_text(c & IADDR_SCOPE_MASK), - n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name); - return 0; - } + log(L_WARN "Ignoring bogus route %I/%d received via %s", + n->n.prefix, n->n.pxlen, e->sender->name); + return 0; } + return 1; } @@ -1018,7 +993,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) rte_update_lock(); tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; - do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding); + do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding); rte_update_unlock(); } @@ -1190,11 +1165,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (p2 && p2 != p0) ok = 0; if (ok && d->export_mode) { - int class = ipa_classify(n->n.prefix); int ic; - if ((class & IADDR_SCOPE_MASK) < p1->min_scope) - ok = 0; - else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) + if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) ok = 0; else if (!ic && d->export_mode > 1) { diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 3609c568..2baa6e34 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -914,7 +914,6 @@ bgp_do_rx_update(struct bgp_conn *conn, rta *a = NULL; ip_addr prefix; net *n; - rte e; int err = 0, pxlen; p->mp_reach_len = 0; @@ -936,8 +935,6 @@ bgp_do_rx_update(struct bgp_conn *conn, DO_NLRI(mp_reach) { - int i; - /* Create fake NEXT_HOP attribute */ if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) goto bad; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index edca5959..191aa456 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1234,7 +1234,6 @@ show_lsa_sum_rt(struct top_hash_entry *he) static inline void show_lsa_external(struct top_hash_entry *he) { - struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_ext *ext = he->lsa_body; char str_via[STD_ADDRESS_P_LENGTH + 8] = ""; char str_tag[16] = ""; @@ -1245,7 +1244,7 @@ show_lsa_external(struct top_hash_entry *he) rt_metric = ext->metric & METRIC_MASK; ebit = ext->metric & LSA_EXT_EBIT; #ifdef OSPFv2 - ip = ipa_and(ipa_from_u32(lsa->id), ext->netmask); + ip = ipa_and(ipa_from_u32(he->lsa.id), ext->netmask); pxlen = ipa_mklen(ext->netmask); rt_fwaddr = ext->fwaddr; rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); @@ -1282,10 +1281,7 @@ show_lsa_external(struct top_hash_entry *he) static inline void show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa) { - struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_prefix *px = he->lsa_body; - struct ospf_lsa_ext *ext = he->lsa_body; - char *msg; ip_addr pxa; int pxlen; u8 pxopts; @@ -1504,8 +1500,10 @@ ospf_sh_lsadb(struct proto *p) break; #ifdef OSPFv3 case LSA_SCOPE_LINK: - struct iface *ifa = if_find_by_index(hea[i]->domain); - cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); + { + struct iface *ifa = if_find_by_index(hea[i]->domain); + cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); + } break; #endif } diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 84e47252..c856eea1 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -170,7 +170,7 @@ static void process_prefixes(struct ospf_area *oa) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + // struct proto *p = &po->proto; struct top_hash_entry *en, *src; struct ospf_lsa_prefix *px; ip_addr pxa; @@ -228,7 +228,6 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to { // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; - orta nf; u32 i; struct ospf_lsa_rt *rt = en->lsa_body; @@ -249,6 +248,7 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to */ DBG("\n"); + orta nf; nf.type = RTS_OSPF; nf.options = 0; nf.metric1 = act->dist + rtl->metric; @@ -571,7 +571,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) type = ORT_NET; re = (ort *) fib_find(&po->rtf, &ip, pxlen); } - else if (en->lsa.type == LSA_T_SUM_RT) + else // en->lsa.type == LSA_T_SUM_RT { #ifdef OSPFv2 struct ospf_lsa_sum *ls = en->lsa_body; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index a5279657..dac2c2e6 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -33,39 +33,8 @@ #include "lib/string.h" #include "lib/socket.h" -#ifdef IPV6 -#define HOST_MASK 128 -#else -#define HOST_MASK 32 -#endif - int rt_sock = 0; -#define CHECK_FAMILY(sa) \ - ((((struct sockaddr *)sa)->sa_family) == BIRD_AF) - -static struct iface * -krt_temp_iface_index(struct krt_proto *p, unsigned index) -{ - struct iface *i, *j; - - WALK_LIST(i, p->scan.temp_ifs) - if (i->index == index) - return i; - i = mb_allocz(p->p.pool, sizeof(struct iface)); - if (j = if_find_by_index(index)) - { - strcpy(i->name, j->name); - i->addr = j->addr; - } - else - strcpy(i->name, "?"); - i->index = index; - add_tail(&p->scan.temp_ifs, &i->n); - return i; -} - - int krt_capable(rte *e) { @@ -83,7 +52,7 @@ krt_capable(rte *e) || a->dest == RTD_UNREACHABLE #endif #ifdef RTF_BLACKHOLE - || a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */ + || a->dest == RTD_BLACKHOLE #endif ); } @@ -96,6 +65,13 @@ krt_capable(rte *e) l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\ memmove(body, &(u), l); body += l;} +#define GETADDR(p, F) \ + bzero(p, sizeof(*p));\ + if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ + unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ + memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ + body += l;} + static void krt_sock_send(int cmd, rte *e) { @@ -108,7 +84,7 @@ krt_sock_send(int cmd, rte *e) char *body = (char *)msg.buf; sockaddr gate, mask, dst; - DBG("krt-sock: send %I/%d via %I", net->n.prefix, net->n.pxlen, a->gw); + DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw); fill_in_sockaddr(&dst, net->n.prefix, 0); fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 0); @@ -119,9 +95,9 @@ krt_sock_send(int cmd, rte *e) msg.rtm.rtm_type = cmd; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; - msg.rtm.rtm_flags = RTF_UP; + msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1; - if (net->n.pxlen == HOST_MASK) + if (net->n.pxlen == MAX_PREFIX_LENGTH) { msg.rtm.rtm_flags |= RTF_HOST; } @@ -200,12 +176,12 @@ krt_sock_send(int cmd, rte *e) msg.rtm.rtm_msglen = l; if ((l = write(rt_sock, (char *)&msg, l)) < 0) { - log(L_ERR "KIF: error writting route to socket (%I/%d)", net->n.prefix, net->n.pxlen); + log(L_ERR "KIF: Error sending route %I/%d to kernel", net->n.prefix, net->n.pxlen); } } void -krt_set_notify(struct krt_proto *p UNUSED, net *net UNUSED, rte *new, rte *old) +krt_set_notify(struct krt_proto *p UNUSED, net *net, rte *new, rte *old) { if (old) { @@ -258,68 +234,87 @@ krt_set_start(struct krt_proto *x, int first UNUSED) bug("krt-sock: sk_open failed"); } +#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) + static void krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) { - sockaddr gate, mask, dst; rta a; rte *e; net *net; + sockaddr dst, gate, mask; ip_addr idst, igate, imask; void *body = (char *)msg->buf; int new = (msg->rtm.rtm_type == RTM_ADD); int src; + char *errmsg = "KRT: Invalid route received"; int flags = msg->rtm.rtm_flags; int addrs = msg->rtm.rtm_addrs; - int masklen = -1; - - if (!(flags & RTF_UP)) - { - DBG("Down.\n"); - return; - } - if (flags & RTF_HOST) - masklen = HOST_MASK; + if (!(flags & RTF_UP) && scan) + SKIP("not up in scan\n"); - if(!CHECK_FAMILY(body)) return; + if (!(flags & RTF_DONE) && !scan) + SKIP("not done in async\n"); - if(msg->rtm.rtm_flags & RTF_LLINFO) return; /* ARPs etc. */ + if (flags & RTF_LLINFO) + SKIP("link-local\n"); -#define GETADDR(p, F) \ - bzero(p, sizeof(*p));\ - if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ - unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ - memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ - body += l;} + GETADDR(&dst, RTA_DST); + GETADDR(&gate, RTA_GATEWAY); + GETADDR(&mask, RTA_NETMASK); - GETADDR (&dst, RTA_DST); - GETADDR (&gate, RTA_GATEWAY); - GETADDR (&mask, RTA_NETMASK); + if (sa_family_check(&dst)) + get_sockaddr(&dst, &idst, NULL, 0); + else + SKIP("invalid DST"); - idst = IPA_NONE; - igate = IPA_NONE; - imask = IPA_NONE; + /* We will check later whether we have valid gateway addr */ + if (sa_family_check(&gate)) + get_sockaddr(&gate, &igate, NULL, 0); + else + igate = IPA_NONE; - get_sockaddr(&dst, &idst, NULL, 0); - if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0); + /* We do not test family for RTA_NETMASK, because BSD sends us + some strange values, but interpreting them as IPv4/IPv6 works */ get_sockaddr(&mask, &imask, NULL, 0); - if (masklen < 0) masklen = ipa_mklen(imask); + int c = ipa_classify_net(idst); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + SKIP("strange class/scope\n"); - if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) - { - log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate); - return; - } + int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask); + if (pxlen < 0) + { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; } - if (masklen < 0) - { - log(L_WARN "krt: Got invalid route from kernel!"); - return; - } + if ((flags & RTF_GATEWAY) && ipa_zero(igate)) + { log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; } + + u32 self_mask = RTF_PROTO1; + u32 alien_mask = RTF_STATIC | RTF_PROTO1; + +#ifdef RTF_PROTO2 + alien_mask |= RTF_PROTO2; +#endif - net = net_get(p->p.table, idst, masklen); +#ifdef RTF_PROTO3 + alien_mask |= RTF_PROTO3; +#endif + + if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) + src = KRT_SRC_REDIRECT; + else if (flags & self_mask) + { + if (!scan) + SKIP("echo\n"); + src = KRT_SRC_BIRD; + } + else if (flags & alien_mask) + src = KRT_SRC_ALIEN; + else + src = KRT_SRC_KERNEL; + + net = net_get(p->p.table, idst, pxlen); bzero(&a, sizeof(a)); @@ -333,56 +328,56 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) a.iface = NULL; a.eattrs = NULL; - a.dest = RTD_NONE; - - if (flags & RTF_GATEWAY) - { - neighbor *ng = neigh_find(&p->p, &igate, 0); - if (ng && ng->scope) - a.iface = ng->iface; - else - { - log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", igate, net->n.prefix, net->n.pxlen); - return; - } - - a.dest = RTD_ROUTER; - a.gw = igate; - } - else - { - a.dest = RTD_DEVICE; - a.gw = IPA_NONE; - a.iface = krt_temp_iface_index(p, msg->rtm.rtm_index); - } + /* reject/blackhole routes have also set RTF_GATEWAY, + we wil check them first. */ #ifdef RTF_REJECT if(flags & RTF_REJECT) { a.dest = RTD_UNREACHABLE; - a.gw = IPA_NONE; + goto done; } #endif #ifdef RTF_BLACKHOLE if(flags & RTF_BLACKHOLE) { a.dest = RTD_BLACKHOLE; - a.gw = IPA_NONE; + goto done; } #endif - if (a.dest == RTD_NONE) + a.iface = if_find_by_index(msg->rtm.rtm_index); + if (!a.iface) + { + log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u", + net->n.prefix, net->n.pxlen, msg->rtm.rtm_index); + return; + } + + if (flags & RTF_GATEWAY) { - log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen); - return; - } + neighbor *ng; + a.dest = RTD_ROUTER; + a.gw = igate; - src = KRT_SRC_UNKNOWN; /* FIXME */ + ng = neigh_find2(&p->p, &a.gw, a.iface, 0); + if (!ng || (ng->scope == SCOPE_HOST)) + { + log(L_ERR "KRT: Received route %I/%d with strange next-hop %I", + net->n.prefix, net->n.pxlen, a.gw); + return; + } + } + else + a.dest = RTD_DEVICE; + done: e = rte_get_temp(&a); e->net = net; e->u.krt.src = src; - //e->u.krt.proto = i->rtm_protocol; - //e->u.krt.type = i->rtm_type; + + /* These are probably too Linux-specific */ + e->u.krt.proto = 0; + e->u.krt.type = 0; e->u.krt.metric = 0; if (scan) @@ -471,6 +466,10 @@ krt_read_addr(struct ks_msg *msg) int scope, masklen = -1; int new = (ifam->ifam_type == RTM_NEWADDR); + /* Strange messages with zero (invalid) ifindex appear on OpenBSD */ + if (ifam->ifam_index == 0) + return; + if(!(iface = if_find_by_index(ifam->ifam_index))) { log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index); @@ -486,7 +485,9 @@ krt_read_addr(struct ks_msg *msg) GETADDR (&null, RTA_AUTHOR); GETADDR (&brd, RTA_BRD); - if(!CHECK_FAMILY(&addr)) return; /* Some other family address */ + /* Some other family address */ + if (!sa_family_check(&addr)) + return; get_sockaddr(&addr, &iaddr, NULL, 0); get_sockaddr(&mask, &imask, NULL, 0); @@ -593,27 +594,27 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) mib[4] = cmd; mib[5] = 0; - if( sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) + if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) { die("RT scan..."); } obl = *bl; - while(needed > *bl) *bl *= 2; - while(needed < (*bl/2)) *bl /= 2; + while (needed > *bl) *bl *= 2; + while (needed < (*bl/2)) *bl /= 2; - if( (obl!=*bl) || !*buf) + if ((obl!=*bl) || !*buf) { - if(*buf) mb_free(*buf); - if( (*buf = mb_alloc(pool, *bl)) == NULL ) die("RT scan buf alloc"); + if (*buf) mb_free(*buf); + if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc"); } on = needed; - if( sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0) + if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0) { - if(on != needed) return; /* The buffer size changed since last sysctl */ + if (on != needed) return; /* The buffer size changed since last sysctl */ die("RT scan 2"); } @@ -624,22 +625,23 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) } } +static byte *krt_buffer = NULL; +static byte *kif_buffer = NULL; +static size_t krt_buflen = 32768; +static size_t kif_buflen = 4096; + void krt_scan_fire(struct krt_proto *p) { - static byte *buf = NULL; - static size_t bl = 32768; - krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP); + krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP); } void krt_if_scan(struct kif_proto *p) { - static byte *buf = NULL; - static size_t bl = 4096; struct proto *P = (struct proto *)p; if_start_update(); - krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST); + krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST); if_end_update(); } @@ -652,7 +654,9 @@ krt_set_construct(struct krt_config *c UNUSED) void krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED) { -} + mb_free(krt_buffer); + krt_buffer = NULL; +} void krt_if_io_init(void) @@ -672,5 +676,7 @@ krt_if_start(struct kif_proto *p UNUSED) void krt_if_shutdown(struct kif_proto *p UNUSED) { + mb_free(kif_buffer); + kif_buffer = NULL; } diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h index f3aefeb4..66985abf 100644 --- a/sysdep/cf/bsd-v6.h +++ b/sysdep/cf/bsd-v6.h @@ -9,7 +9,7 @@ #define IPV6 #define CONFIG_AUTO_ROUTES -#undef CONFIG_SELF_CONSCIOUS +#define CONFIG_SELF_CONSCIOUS #undef CONFIG_MULTIPLE_TABLES #undef CONFIG_UNIX_IFACE diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h index 72b24720..acd1b58b 100644 --- a/sysdep/cf/bsd.h +++ b/sysdep/cf/bsd.h @@ -7,7 +7,7 @@ */ #define CONFIG_AUTO_ROUTES -#undef CONFIG_SELF_CONSCIOUS +#define CONFIG_SELF_CONSCIOUS #undef CONFIG_MULTIPLE_TABLES #undef CONFIG_UNIX_IFACE diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index f45fe159..b59b32f3 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -52,7 +52,6 @@ struct nl_sock static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */ static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */ - static void nl_open_sock(struct nl_sock *nl) { @@ -555,23 +554,7 @@ krt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old) nl_send_route(p, new, 1); } -static struct iface * -krt_temp_iface(struct krt_proto *p, unsigned index) -{ - struct iface *i, *j; - - WALK_LIST(i, p->scan.temp_ifs) - if (i->index == index) - return i; - i = mb_allocz(p->p.pool, sizeof(struct iface)); - if (j = if_find_by_index(index)) - strcpy(i->name, j->name); - else - strcpy(i->name, "?"); - i->index = index; - add_tail(&p->scan.temp_ifs, &i->n); - return i; -} +#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) static void nl_parse_route(struct nlmsghdr *h, int scan) @@ -599,31 +582,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) #endif (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))) { - log(L_ERR "nl_parse_route: Malformed message received"); - return; - } - - p = nl_table_map[i->rtm_table]; /* Do we know this table? */ - if (!p) - return; - -#ifdef IPV6 - if (a[RTA_IIF]) - { - DBG("KRT: Ignoring route with IIF set\n"); - return; - } -#else - if (i->rtm_tos != 0) /* We don't support TOS */ - { - DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos); - return; - } -#endif - - if (scan && !new) - { - DBG("KRT: Ignoring route deletion\n"); + log(L_ERR "KRT: Malformed message received"); return; } @@ -634,33 +593,57 @@ nl_parse_route(struct nlmsghdr *h, int scan) } else dst = IPA_NONE; + if (a[RTA_OIF]) memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif)); else oif = ~0; - DBG("Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name); + DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name); + + p = nl_table_map[i->rtm_table]; /* Do we know this table? */ + if (!p) + SKIP("unknown table %d", i->rtm_table); + +#ifdef IPV6 + if (a[RTA_IIF]) + SKIP("IIF set\n"); +#else + if (i->rtm_tos != 0) /* We don't support TOS */ + SKIP("TOS %02x\n", i->rtm_tos); +#endif + + if (scan && !new) + SKIP("RTM_DELROUTE in scan\n"); + + int c = ipa_classify_net(dst); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + SKIP("strange class/scope\n"); + + // ignore rtm_scope, it is not a real scope + // if (i->rtm_scope != RT_SCOPE_UNIVERSE) + // SKIP("scope %u\n", i->rtm_scope); switch (i->rtm_protocol) { + case RTPROT_UNSPEC: + SKIP("proto unspec\n"); + case RTPROT_REDIRECT: src = KRT_SRC_REDIRECT; break; + case RTPROT_KERNEL: - DBG("Route originated in kernel, ignoring\n"); + src = KRT_SRC_KERNEL; return; + case RTPROT_BIRD: -#ifdef IPV6 - case RTPROT_BOOT: - /* Current Linux kernels don't remember rtm_protocol for IPv6 routes and supply RTPROT_BOOT instead */ -#endif if (!scan) - { - DBG("Echo of our own route, ignoring\n"); - return; - } + SKIP("echo\n"); src = KRT_SRC_BIRD; break; + + case RTPROT_BOOT: default: src = KRT_SRC_ALIEN; } @@ -679,52 +662,48 @@ nl_parse_route(struct nlmsghdr *h, int scan) switch (i->rtm_type) { case RTN_UNICAST: - if (oif == ~0U) + ra.iface = if_find_by_index(oif); + if (!ra.iface) { - log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen); + log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u", + net->n.prefix, net->n.pxlen, oif); return; } + if (a[RTA_GATEWAY]) { - struct iface *ifa = if_find_by_index(oif); neighbor *ng; ra.dest = RTD_ROUTER; memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw)); ipa_ntoh(ra.gw); - if (i->rtm_flags & RTNH_F_ONLINK) - { - /* route with 'onlink' attribute */ - ra.iface = if_find_by_index(oif); - if (ra.iface == NULL) - { - log(L_WARN "Kernel told us to use unknown interface %u for %I/%d", - oif, net->n.prefix, net->n.pxlen); - return; - } - } - else + ng = neigh_find2(&p->p, &ra.gw, ra.iface, + (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); + if (!ng || (ng->scope == SCOPE_HOST)) { - ng = neigh_find2(&p->p, &ra.gw, ifa, 0); - if (ng && ng->scope) - { - if (ng->iface != ifa) - log(L_WARN "KRT: Route with unexpected iface for %I/%d", net->n.prefix, net->n.pxlen); - ra.iface = ng->iface; - } - else - { - log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen); - return; - } - + log(L_ERR "KRT: Received route %I/%d with strange next-hop %I", + net->n.prefix, net->n.pxlen, ra.gw); + return; } } else { ra.dest = RTD_DEVICE; - ra.iface = krt_temp_iface(p, oif); + + /* + * 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; case RTN_BLACKHOLE: ra.dest = RTD_BLACKHOLE; @@ -737,13 +716,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) break; /* FIXME: What about RTN_THROW? */ default: - DBG("KRT: Ignoring route with type=%d\n", i->rtm_type); - return; - } - - if (i->rtm_scope != RT_SCOPE_UNIVERSE) - { - DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope); + SKIP("type %d\n", i->rtm_type); return; } diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 915baf44..02d59abb 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -663,7 +663,6 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check) static char * sk_set_ttl_int(sock *s) { - int one = 1; #ifdef IPV6 if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) return "IPV6_UNICAST_HOPS"; @@ -671,6 +670,7 @@ sk_set_ttl_int(sock *s) if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) return "IP_TTL"; #ifdef CONFIG_UNIX_DONTROUTE + int one = 1; if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) return "SO_DONTROUTE"; #endif diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 6d94cada..47b96217 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -558,32 +558,30 @@ krt_got_route(struct krt_proto *p, rte *e) rte *old; net *net = e->net; int verdict; -#ifdef KRT_ALLOW_LEARN - int src = e->u.krt.src; -#endif -#ifdef CONFIG_AUTO_ROUTES - if (e->attrs->dest == RTD_DEVICE) +#ifdef KRT_ALLOW_LEARN + switch (e->u.krt.src) { - /* It's a device route. Probably a kernel-generated one. */ + case KRT_SRC_KERNEL: verdict = KRF_IGNORE; goto sentenced; - } -#endif -#ifdef KRT_ALLOW_LEARN - if (src == KRT_SRC_ALIEN) - { + case KRT_SRC_REDIRECT: + verdict = KRF_DELETE; + goto sentenced; + + case KRT_SRC_ALIEN: if (KRT_CF->learn) krt_learn_scan(p, e); else { - krt_trace_in_rl(&rl_alien_ignored, p, e, "alien route, ignored"); + krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored"); rte_free(e); } return; } #endif + /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ if (net->n.flags & KRF_VERDICT_MASK) { @@ -605,7 +603,7 @@ krt_got_route(struct krt_proto *p, rte *e) else verdict = KRF_DELETE; -sentenced: + sentenced: krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]); net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict; if (verdict == KRF_UPDATE || verdict == KRF_DELETE) @@ -680,19 +678,24 @@ krt_prune(struct krt_proto *p) } void -krt_got_route_async(struct krt_proto *p, rte *e, int new UNUSED) +krt_got_route_async(struct krt_proto *p, rte *e, int new) { net *net = e->net; - int src = e->u.krt.src; - switch (src) + switch (e->u.krt.src) { case KRT_SRC_BIRD: ASSERT(0); /* Should be filtered by the back end */ + case KRT_SRC_REDIRECT: - DBG("It's a redirect, kill him! Kill! Kill!\n"); - krt_set_notify(p, net, NULL, e); + if (new) + { + krt_trace_in(p, e, "[redirect] deleting"); + krt_set_notify(p, net, NULL, e); + } + /* If !new, it is probably echo of our deletion */ break; + #ifdef KRT_ALLOW_LEARN case KRT_SRC_ALIEN: if (KRT_CF->learn) @@ -878,7 +881,6 @@ krt_init(struct proto_config *c) p->p.accept_ra_types = RA_OPTIMAL; p->p.rt_notify = krt_notify; - p->p.min_scope = SCOPE_HOST; return &p->p; } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 607e6993..1d9e1448 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -83,6 +83,7 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); #define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */ #define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */ #define KRT_SRC_ALIEN 2 /* Route installed by someone else */ +#define KRT_SRC_KERNEL 3 /* Kernel routes, are ignored by krt syncer */ extern struct protocol proto_unix_iface; diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 1a461ee1..0b179e00 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -9,6 +9,8 @@ #ifndef _BIRD_UNIX_H_ #define _BIRD_UNIX_H_ +#include + struct pool; /* main.c */ @@ -29,10 +31,12 @@ volatile int async_shutdown_flag; #define BIRD_PF PF_INET6 #define BIRD_AF AF_INET6 typedef struct sockaddr_in6 sockaddr; +static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; } #else #define BIRD_PF PF_INET #define BIRD_AF AF_INET typedef struct sockaddr_in sockaddr; +static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; } #endif #ifndef SUN_LEN -- cgit v1.2.3 From 53434e44a95fe9334f4bdf5e0da987929addffb1 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 27 Feb 2010 16:00:07 +0100 Subject: Better flushing of interfaces. When device protocol goes down, interfaces should be flushed asynchronously (in the same way like routes from protocols are flushed), when protocol goes to DOWN/HUNGRY. This fixes the problem with static routes staying in kernel routing table after BIRD shutdown. --- nest/iface.c | 9 +++++++++ nest/iface.h | 3 ++- nest/proto.c | 7 +++++++ proto/static/static.c | 9 +++++---- sysdep/unix/krt.c | 9 --------- 5 files changed, 23 insertions(+), 14 deletions(-) (limited to 'sysdep/unix/krt.c') diff --git a/nest/iface.c b/nest/iface.c index 5e88b21b..82dead35 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -336,6 +336,15 @@ if_end_update(void) } } +void +if_flush_ifaces(struct proto *p) +{ + if (p->debug & D_EVENTS) + log(L_TRACE "%s: Flushing interfaces", p->name); + if_start_update(); + if_end_update(); +} + /** * if_feed_baby - advertise interfaces to a new protocol * @p: protocol to feed diff --git a/nest/iface.h b/nest/iface.h index 02129ac6..8fc2567d 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -75,8 +75,9 @@ struct iface *if_update(struct iface *); struct ifa *ifa_update(struct ifa *); void ifa_delete(struct ifa *); void if_start_update(void); -void if_end_update(void); void if_end_partial_update(struct iface *); +void if_end_update(void); +void if_flush_ifaces(struct proto *p); void if_feed_baby(struct proto *); struct iface *if_find_by_index(unsigned); struct iface *if_find_by_name(char *); diff --git a/nest/proto.c b/nest/proto.c index db6bf9bf..78fca99c 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -740,6 +740,8 @@ proto_notify_state(struct proto *p, unsigned ps) } } +extern struct protocol proto_unix_iface; + static void proto_flush_all(void *unused UNUSED) { @@ -748,6 +750,11 @@ proto_flush_all(void *unused UNUSED) rt_prune_all(); while ((p = HEAD(flush_proto_list))->n.next) { + /* This will flush interfaces in the same manner + like rt_prune_all() flushes routes */ + if (p->proto == &proto_unix_iface) + if_flush_ifaces(p); + DBG("Flushing protocol %s\n", p->name); p->core_state = FS_HUNGRY; proto_relink(p); diff --git a/proto/static/static.c b/proto/static/static.c index c71d1da9..9308c59a 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -125,11 +125,12 @@ static_shutdown(struct proto *p) struct static_config *c = (void *) p->cf; struct static_route *r; - DBG("Static: prepare for landing!\n"); + /* Just reset the flag, the routes will be flushed by the nest */ WALK_LIST(r, c->iface_routes) - static_remove(p, r); + r->installed = 0; WALK_LIST(r, c->other_routes) - static_remove(p, r); + r->installed = 0; + return PS_DOWN; } @@ -294,7 +295,7 @@ static_show_rt(struct static_route *r) switch (r->dest) { case RTD_ROUTER: bsprintf(via, "via %I", r->via); break; - case RTD_DEVICE: bsprintf(via, "to %s", r->if_name); break; + case RTD_DEVICE: bsprintf(via, "dev %s", r->if_name); break; case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 47b96217..c8887b72 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -139,15 +139,6 @@ kif_shutdown(struct proto *P) krt_if_shutdown(p); kif_proto = NULL; - if_start_update(); /* Remove all interfaces */ - if_end_update(); - /* - * FIXME: Is it really a good idea? It causes routes to be flushed, - * but at the same time it avoids sending of these deletions to the kernel, - * because krt thinks the kernel itself has already removed the route - * when downing the interface. Sad. - */ - return PS_DOWN; } -- cgit v1.2.3