diff options
-rw-r--r-- | doc/bird.sgml | 15 | ||||
-rw-r--r-- | lib/birdlib.h | 7 | ||||
-rw-r--r-- | nest/proto.c | 8 | ||||
-rw-r--r-- | nest/protocol.h | 1 | ||||
-rw-r--r-- | nest/rt-table.c | 48 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 5 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 8 | ||||
-rw-r--r-- | proto/ospf/config.Y | 2 | ||||
-rw-r--r-- | proto/ospf/dbdes.c | 35 | ||||
-rw-r--r-- | proto/ospf/lsack.c | 7 | ||||
-rw-r--r-- | proto/ospf/lsalib.c | 95 | ||||
-rw-r--r-- | proto/ospf/lsalib.h | 9 | ||||
-rw-r--r-- | proto/ospf/lsreq.c | 2 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 9 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 10 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 6 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 90 | ||||
-rw-r--r-- | proto/ospf/topology.c | 49 |
18 files changed, 322 insertions, 84 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index b3ac38b0..e531da40 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -3491,6 +3491,11 @@ protocol ospf [v2|v3] <name> { Specifies interval in seconds between retransmissions of unacknowledged updates. Default value is 5. + <tag><label id="ospf-transmit-delay">transmit delay <M>num</M></tag> + Specifies estimated transmission delay of link state updates send over + the interface. The value is added to LSA age of LSAs propagated through + it. Default value is 1. + <tag><label id="ospf-priority">priority <M>num</M></tag> On every multiple access network (e.g., the Ethernet) Designated Router and Backup Designated router are elected. These routers have some special @@ -3511,16 +3516,6 @@ protocol ospf [v2|v3] <name> { <m/dead/ seconds, it will consider the neighbor down. If both directives <cf/dead count/ and <cf/dead/ are used, <cf/dead/ has precedence. - <tag><label id="ospf-secondary">secondary <M>switch</M></tag> - On BSD systems, older versions of BIRD supported OSPFv2 only for the - primary IP address of an interface, other IP ranges on the interface - were handled as stub networks. Since v1.4.1, regular operation on - secondary IP addresses is supported, but disabled by default for - compatibility. This option allows to enable it. The option is a - transitional measure, will be removed in the next major release as the - behavior will be changed. On Linux systems, the option is irrelevant, as - operation on non-primary addresses is already the regular behavior. - <tag><label id="ospf-rx-buffer">rx buffer <M>num</M></tag> This option allows to specify the size of buffers used for packet processing. The buffer size should be bigger than maximal size of any diff --git a/lib/birdlib.h b/lib/birdlib.h index 428b3209..7cd78032 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -56,6 +56,13 @@ static inline int u64_cmp(u64 i1, u64 i2) #define BIT32_CLR(b,p) ((b)[(p)/32] &= ~BIT32_VAL(p)) #define BIT32_ZERO(b,l) memset((b), 0, (l)/8) +/* The same, but counting bits from MSB */ +#define BIT32R_VAL(p) ((((u32) 1) << 31) >> ((p) % 32)) +#define BIT32R_TEST(b,p) ((b)[(p)/32] & BIT32R_VAL(p)) +#define BIT32R_SET(b,p) ((b)[(p)/32] |= BIT32R_VAL(p)) +#define BIT32R_CLR(b,p) ((b)[(p)/32] &= ~BIT32R_VAL(p)) +#define BIT32R_ZERO(b,l) memset((b), 0, (l)/8) + #ifndef NULL #define NULL ((void *) 0) #endif diff --git a/nest/proto.c b/nest/proto.c index fadce6c7..d4a333d0 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1693,11 +1693,11 @@ channel_show_stats(struct channel *c) struct proto_stats *s = &c->stats; if (c->in_keep_filtered) - cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported", - s->imp_routes, s->filt_routes, s->exp_routes); + cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred", + s->imp_routes, s->filt_routes, s->exp_routes, s->pref_routes); else - cli_msg(-1006, " Routes: %u imported, %u exported", - s->imp_routes, s->exp_routes); + cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", + s->imp_routes, s->exp_routes, s->pref_routes); cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", diff --git a/nest/protocol.h b/nest/protocol.h index 7f539aef..6c04071b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -134,6 +134,7 @@ struct proto_stats { /* Import - from protocol to core */ u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ u32 filt_routes; /* Number of routes rejected in import filter but kept in the routing table */ + u32 pref_routes; /* Number of routes selected as best in the (adjacent) routing table */ u32 imp_updates_received; /* Number of route updates received */ u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ u32 imp_updates_filtered; /* Number of route updates rejected by filters */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 61ddb8c0..a1900532 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -564,33 +564,47 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed) * and the end of refeed - if a newly filtered route disappears during this * period, proper withdraw is not sent (because old would be also filtered) * and the route is not refeeded (because it disappeared before that). - * Therefore, we also do not try to run the filter on old routes that are - * older than the last filter change. + * This is handled below as a special case. */ if (new) new = export_filter(c, new, &new_free, 0); - if (old && !(refeed || (old->lastmod <= c->last_tx_filter_change))) + if (old && !refeed) old = export_filter(c, old, &old_free, 1); if (!new && !old) { /* * As mentioned above, 'old' value may be incorrect in some race conditions. - * We generally ignore it with the exception of withdraw to pipe protocol. - * In that case we rather propagate unfiltered withdraws regardless of - * export filters to ensure that when a protocol is flushed, its routes are - * removed from all tables. Possible spurious unfiltered withdraws are not - * problem here as they are ignored if there is no corresponding route at - * the other end of the pipe. We directly call rt_notify() hook instead of + * We generally ignore it with two exceptions: + * + * First, withdraw to pipe protocol. In that case we rather propagate + * unfiltered withdraws regardless of export filters to ensure that when a + * protocol is flushed, its routes are removed from all tables. Possible + * spurious unfiltered withdraws are not problem here as they are ignored if + * there is no corresponding route at the other end of the pipe. + * + * Second, recent filter change. If old route is older than filter change, + * then it was previously evaluated by a different filter and we do not know + * whether it was really propagated. In that case we rather send spurious + * withdraw than do nothing and possibly cause phantom routes. + * + * In both cases wqe directly call rt_notify() hook instead of * do_rt_notify() to avoid logging and stat counters. */ + int pipe_withdraw = 0, filter_change = 0; #ifdef CONFIG_PIPE - if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto)) - p->rt_notify(p, c, net, NULL, old0); + pipe_withdraw = (p->proto == &proto_pipe) && !new0; #endif + filter_change = old0 && (old0->lastmod <= c->last_tx_filter_change); + + if ((pipe_withdraw || filter_change) && (p != old0->sender->proto)) + { + c->stats.exp_withdraws_accepted++; + p->rt_notify(p, c, net, NULL, old0); + } return; } @@ -900,8 +914,16 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, if (!old && !new) return; - if ((type == RA_OPTIMAL) && tab->hostcache) - rt_notify_hostcache(tab, net); + if (type == RA_OPTIMAL) + { + if (new) + new->sender->stats.pref_routes++; + if (old) + old->sender->stats.pref_routes--; + + if (tab->hostcache) + rt_notify_hostcache(tab, net); + } struct channel *c; node *n; WALK_LIST2(c, n, tab->channels, table_node) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 43f9f134..8dedde9f 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1692,6 +1692,11 @@ bgp_channel_cleanup(struct channel *C) if (c->igp_table_ip6) rt_unlock_table(c->igp_table_ip6); + + c->index = 0; + + /* Cleanup rest of bgp_channel starting at pool field */ + memset(&(c->pool), 0, sizeof(struct bgp_channel) - OFFSETOF(struct bgp_channel, pool)); } static inline struct bgp_channel_config * diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 2b60f90f..cfc88d8e 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -299,12 +299,16 @@ struct bgp_channel { /* Rest are BGP specific data */ struct bgp_channel_config *cf; - pool *pool; /* XXXX */ u32 afi; u32 index; const struct bgp_af_desc *desc; + rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */ + rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */ + + /* Rest are zeroed when down */ + pool *pool; HASH(struct bgp_bucket) bucket_hash; /* Hash table of route buckets */ struct bgp_bucket *withdraw_bucket; /* Withdrawn routes */ list bucket_queue; /* Queue of buckets to send (struct bgp_bucket) */ @@ -312,8 +316,6 @@ struct bgp_channel { HASH(struct bgp_prefix) prefix_hash; /* Prefixes to be sent */ slab *prefix_slab; /* Slab holding prefix nodes */ - rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */ - rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */ ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */ ip_addr link_addr; /* Link-local version of next_hop_addr */ diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index b89584e1..2ec9babe 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -199,7 +199,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD) CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH) -CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838) +CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838) %type <ld> lsadb_args %type <i> ospf_variant ospf_af_mc nbma_eligible diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 019aff04..a1559782 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -127,7 +127,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) { struct ospf_dbdes2_packet *ps = (void *) pkt; ps->iface_mtu = htons(iface_mtu); - ps->options = ifa->oa->options; + ps->options = ifa->oa->options | OPT_O; ps->imms = 0; /* Will be set later */ ps->ddseq = htonl(n->dds); length = sizeof(struct ospf_dbdes2_packet); @@ -162,7 +162,8 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) } if ((en->lsa.age < LSA_MAXAGE) && - lsa_flooding_allowed(en->lsa_type, en->domain, ifa)) + lsa_flooding_allowed(en->lsa_type, en->domain, ifa) && + lsa_is_acceptable(en->lsa_type, n, p)) { lsa_hton_hdr(&(en->lsa), lsas + i); i++; @@ -237,6 +238,14 @@ ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) ospf_do_send_dbdes(p, n); } +void +ospf_reset_ldd(struct ospf_proto *p UNUSED, struct ospf_neighbor *n) +{ + mb_free(n->ldd_buffer); + n->ldd_buffer = NULL; + n->ldd_bsize = 0; +} + static int ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n) { @@ -341,6 +350,16 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, rcv_ddseq = ntohl(ps->ddseq); } + /* Reject packets with non-matching MTU */ + if ((ifa->type != OSPF_IT_VLINK) && + (rcv_iface_mtu != ifa->iface->mtu) && + (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0)) + { + LOG_PKT("MTU mismatch with nbr %R on %s (remote %d, local %d)", + n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); + return; + } + switch (n->state) { case NEIGHBOR_DOWN: @@ -356,13 +375,6 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, /* fallthrough */ case NEIGHBOR_EXSTART: - if ((ifa->type != OSPF_IT_VLINK) && - (rcv_iface_mtu != ifa->iface->mtu) && - (rcv_iface_mtu != 0) && - (ifa->iface->mtu != 0)) - LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)", - n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); - if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) && (n->rid > p->router_id) && (plen == ospf_dbdes_hdrlen(p))) @@ -430,6 +442,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) { tm_stop(n->dbdes_timer); + ospf_reset_ldd(p, n); ospf_neigh_sm(n, INM_EXDONE); break; } @@ -453,7 +466,11 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_send_dbdes(p, n); if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) + { + /* Use dbdes timer to postpone freeing of Last DBDES packet buffer */ + tm_start(n->dbdes_timer, n->ifa->deadint S); ospf_neigh_sm(n, INM_EXDONE); + } } break; diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 251b5e47..9198dd92 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -106,6 +106,13 @@ ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue) length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header); pkt->length = htons(length); + if (queue == ACKL_DIRECT) + { + OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent to nbr %R on %s", n->rid, ifa->ifname); + ospf_send_to(ifa, n->ip); + return; + } + OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname); if (ifa->type == OSPF_IT_BCAST) diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index fbfd8d29..e66d3dc0 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -91,6 +91,30 @@ lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa) } } +int +lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p) +{ + if (ospf_is_v2(p)) + { + if (type == LSA_T_NSSA) + return !!(n->options & OPT_N); + + if (lsa_is_opaque(type)) + return !!(n->options & OPT_O); + + return 1; + } + else + { + /* + * There should be check whether receiving router understands that type + * of LSA (for LSA types with U-bit == 0). But as we do not support any + * optional LSA types, this is not needed yet. + */ + + return 1; + } +} static int unknown_lsa_type(u32 type) @@ -105,6 +129,9 @@ unknown_lsa_type(u32 type) case LSA_T_NSSA: case LSA_T_LINK: case LSA_T_PREFIX: + case LSA_T_RI_LINK: + case LSA_T_RI_AREA: + case LSA_T_RI_AS: return 0; default: @@ -112,28 +139,47 @@ unknown_lsa_type(u32 type) } } -#define LSA_V2_TMAX 8 -static const u16 lsa_v2_types[LSA_V2_TMAX] = - {0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA}; +/* Maps OSPFv2 types to OSPFv3 types */ +static const u16 lsa_v2_types[] = { + 0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA, + 0, LSA_T_OPAQUE_LINK, LSA_T_OPAQUE_AREA, LSA_T_OPAQUE_AS +}; + +/* Maps OSPFv2 opaque types to OSPFv3 function codes */ +static const u16 opaque_lsa_types[] = { + [LSA_OT_RI] = LSA_T_RI_, +}; + +/* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */ +static const u8 opaque_lsa_types_inv[] = { + [LSA_T_RI_] = LSA_OT_RI, +}; + +#define LOOKUP(a, i) ({ uint _i = (i); (_i < ARRAY_SIZE(a)) ? a[_i] : 0; }) void -lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain) +lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain) { if (ospf_is_v2(ifa->oa->po)) { - itype = itype & LSA_T_V2_MASK; - itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0; + type = type & LSA_T_V2_MASK; + type = LOOKUP(lsa_v2_types, type); + + uint code; + if (LSA_FUNCTION(type) == LSA_T_OPAQUE_) + if (code = LOOKUP(opaque_lsa_types, id >> 24)) + type = code | LSA_UBIT | LSA_SCOPE(type); } else { /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */ - if (unknown_lsa_type(itype) && !(itype & LSA_UBIT)) - itype = itype & ~LSA_SCOPE_MASK; + if (unknown_lsa_type(type) && !(type & LSA_UBIT)) + type = type & ~LSA_SCOPE_MASK; } - *otype = itype; + *otype = type; - switch (LSA_SCOPE(itype)) + switch (LSA_SCOPE(type)) { case LSA_SCOPE_LINK: *domain = ifa->iface_id; @@ -150,6 +196,12 @@ lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain) } } +u32 +lsa_get_opaque_type(u32 type) +{ + return LOOKUP(opaque_lsa_types_inv, LSA_FUNCTION(type)); +} + void lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body) @@ -548,6 +600,17 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); } +static int +lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED) +{ + /* + * There should be proper validation. But we do not really process RI LSAs, so + * we can just accept them like another unknown opaque LSAs. + */ + + return 1; +} + /** * lsa_validate - check whether given LSA is valid @@ -577,6 +640,14 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body) case LSA_T_EXT: case LSA_T_NSSA: return lsa_validate_ext2(lsa, body); + case LSA_T_RI_LINK: + case LSA_T_RI_AREA: + case LSA_T_RI_AS: + return lsa_validate_ri(lsa, body); + case LSA_T_OPAQUE_LINK: + case LSA_T_OPAQUE_AREA: + case LSA_T_OPAQUE_AS: + return 1; /* Unknown Opaque LSAs */ default: return 0; /* Should not happen, unknown LSAs are already rejected */ } @@ -600,6 +671,10 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body) return lsa_validate_link(lsa, body); case LSA_T_PREFIX: return lsa_validate_prefix(lsa, body); + case LSA_T_RI_LINK: + case LSA_T_RI_AREA: + case LSA_T_RI_AS: + return lsa_validate_ri(lsa, body); default: return 1; /* Unknown LSAs are OK in OSPFv3 */ } diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index fca7faec..af8901ce 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -36,16 +36,21 @@ struct ospf_lsa_rt_walk { }; -void lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain); +void lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain); static inline void lsa_get_type_domain(struct ospf_lsa_header *lsa, struct ospf_iface *ifa, u32 *otype, u32 *domain) -{ lsa_get_type_domain_(lsa->type_raw, ifa, otype, domain); } +{ lsa_get_type_domain_(lsa->type_raw, lsa->id, ifa, otype, domain); } static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p) { return ospf_is_v2(p) ? (h->type_raw & LSA_T_V2_MASK) : h->type_raw; } +/* Assuming OSPFv2 - All U-bit LSAs are mapped to Opaque LSAs */ +static inline int lsa_is_opaque(u32 type) +{ return !!(type & LSA_UBIT); } +u32 lsa_get_opaque_type(u32 type); int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa); +int lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p); void lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body); u16 lsa_verify_checksum(const void *lsa_n, int lsa_len); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 657c0247..45af7533 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -125,7 +125,7 @@ ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, id = ntohl(lsrs[i].id); rt = ntohl(lsrs[i].rt); - lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain); + lsa_get_type_domain_(ntohl(lsrs[i].type), id, ifa, &type, &domain); DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt); diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index a98c9098..7318b751 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -171,7 +171,8 @@ ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n) WALK_SLIST(en, p->lsal) if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) && - lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa)) + lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa) && + lsa_is_acceptable(en->lsa_type, n, p)) ospf_lsa_lsrt_up(en, n); /* If we found any flushed LSA, we send them ASAP */ @@ -287,9 +288,9 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig if (n == from) continue; - /* In OSPFv3, there should be check whether receiving router understand - that type of LSA (for LSA types with U-bit == 0). But as we do not support - any optional LSA types, this is not needed yet */ + /* Check whether optional LSAs are supported by neighbor */ + if (!lsa_is_acceptable(en->lsa_type, n, p)) + continue; /* 13.3 (1d) - add LSA to the link state retransmission list */ ospf_lsa_lsrt_up(en, n); diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 7ce682b0..c143b130 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -176,8 +176,8 @@ ospf_neigh_chstate(struct ospf_neighbor *n, u8 state) if (state == NEIGHBOR_EXSTART) { - /* First time adjacency */ - if (n->adj == 0) + /* First time adjacency attempt */ + if (old_state < NEIGHBOR_EXSTART) n->dds = random_u32(); n->dds++; @@ -608,6 +608,12 @@ dbdes_timer_hook(timer *t) if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS)) ospf_rxmt_dbdes(p, n); + + if ((n->state > NEIGHBOR_LOADING) && !(n->myimms & DBDES_MS)) + { + ospf_reset_ldd(p, n); + tm_stop(n->dbdes_timer); + } } static void diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index a5e22269..73500604 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -92,11 +92,13 @@ * - RFC 2328 - main OSPFv2 standard * - RFC 5340 - main OSPFv3 standard * - RFC 3101 - OSPFv2 NSSA areas + * - RFC 5250 - OSPFv2 Opaque LSAs * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication * - RFC 5838 - OSPFv3 Support of Address Families * - RFC 6549 - OSPFv2 Multi-Instance Extensions * - RFC 6987 - OSPF Stub Router Advertisement * - RFC 7166 - OSPFv3 Authentication Trailer + * - RFC 7770 - OSPF Router Information LSA */ #include <stdlib.h> @@ -239,6 +241,7 @@ ospf_start(struct proto *P) p->rfc1583 = c->rfc1583; p->stub_router = c->stub_router; p->merge_external = c->merge_external; + p->instance_id = c->instance_id; p->asbr = c->asbr; p->ecmp = c->ecmp; p->tick = c->tick; @@ -648,6 +651,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF) if (p->rfc1583 != new->rfc1583) return 0; + if (p->instance_id != new->instance_id) + return 0; + if (old->abr != new->abr) return 0; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index ff55621a..d3f12738 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -223,6 +223,7 @@ struct ospf_proto u8 rfc1583; /* RFC1583 compatibility */ u8 stub_router; /* Do not forward transit traffic */ u8 merge_external; /* Should i merge external routes? */ + u8 instance_id; /* Differentiate between more OSPF instances */ u8 asbr; /* May i originate any ext/NSSA lsa? */ u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ u64 csn64; /* Last used cryptographic sequence number */ @@ -352,7 +353,6 @@ struct ospf_neighbor u32 rid; /* Router ID */ ip_addr ip; /* IP of it's interface */ u8 priority; /* Priority */ - u8 adj; /* built adjacency? */ u32 options; /* Options received */ /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in @@ -466,6 +466,7 @@ struct ospf_neighbor #define OPT_L_V2 0x0010 /* OSPFv2, link-local signaling, not used */ #define OPT_R 0x0010 /* OSPFv3, originator is active router */ #define OPT_DC 0x0020 /* Related to demand circuits, not used */ +#define OPT_O 0x0040 /* OSPFv2 Opaque LSA (RFC 5250) */ #define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */ #define OPT_L_V3 0x0200 /* OSPFv3, link-local signaling */ #define OPT_AT 0x0400 /* OSPFv3, authentication trailer */ @@ -541,25 +542,44 @@ struct ospf_auth3 #define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS) -#define LSA_T_RT 0x2001 -#define LSA_T_NET 0x2002 -#define LSA_T_SUM_NET 0x2003 -#define LSA_T_SUM_RT 0x2004 -#define LSA_T_EXT 0x4005 -#define LSA_T_NSSA 0x2007 -#define LSA_T_LINK 0x0008 -#define LSA_T_PREFIX 0x2009 - -#define LSA_T_V2_MASK 0x00ff - -#define LSA_UBIT 0x8000 - -#define LSA_SCOPE_LINK 0x0000 -#define LSA_SCOPE_AREA 0x2000 -#define LSA_SCOPE_AS 0x4000 -#define LSA_SCOPE_RES 0x6000 -#define LSA_SCOPE_MASK 0x6000 -#define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK) +/* OSPFv3 LSA Types / LSA Function Codes */ +/* https://www.iana.org/assignments/ospfv3-parameters/ospfv3-parameters.xhtml#ospfv3-parameters-3 */ +#define LSA_T_RT 0x2001 +#define LSA_T_NET 0x2002 +#define LSA_T_SUM_NET 0x2003 +#define LSA_T_SUM_RT 0x2004 +#define LSA_T_EXT 0x4005 +#define LSA_T_NSSA 0x2007 +#define LSA_T_LINK 0x0008 +#define LSA_T_PREFIX 0x2009 +#define LSA_T_RI_ 0x000C +#define LSA_T_RI_LINK 0x800C +#define LSA_T_RI_AREA 0xA00C +#define LSA_T_RI_AS 0xC00C +#define LSA_T_OPAQUE_ 0x1FFF +#define LSA_T_OPAQUE_LINK 0x9FFF +#define LSA_T_OPAQUE_AREA 0xBFFF +#define LSA_T_OPAQUE_AS 0xDFFF + +#define LSA_T_V2_OPAQUE_ 0x0009 +#define LSA_T_V2_MASK 0x00ff + +/* OSPFv2 Opaque LSA Types */ +/* https://www.iana.org/assignments/ospf-opaque-types/ospf-opaque-types.xhtml#ospf-opaque-types-2 */ +#define LSA_OT_RI 0x04 + +#define LSA_FUNCTION_MASK 0x1FFF +#define LSA_FUNCTION(type) ((type) & LSA_FUNCTION_MASK) + +#define LSA_UBIT 0x8000 + +#define LSA_SCOPE_LINK 0x0000 +#define LSA_SCOPE_AREA 0x2000 +#define LSA_SCOPE_AS 0x4000 +#define LSA_SCOPE_RES 0x6000 +#define LSA_SCOPE_MASK 0x6000 +#define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK) +#define LSA_SCOPE_ORDER(type) (((type) >> 13) & 0x3) #define LSA_MAXAGE 3600 /* 1 hour */ @@ -586,9 +606,20 @@ struct ospf_auth3 #define LSA_EXT2_TOS 0x7F000000 #define LSA_EXT2_EBIT 0x80000000 -#define LSA_EXT3_EBIT 0x4000000 -#define LSA_EXT3_FBIT 0x2000000 -#define LSA_EXT3_TBIT 0x1000000 +#define LSA_EXT3_EBIT 0x04000000 +#define LSA_EXT3_FBIT 0x02000000 +#define LSA_EXT3_TBIT 0x01000000 + +/* OSPF Router Information (RI) TLVs */ +/* https://www.iana.org/assignments/ospf-parameters/ospf-parameters.xhtml#ri-tlv */ +#define LSA_RI_RIC 1 +#define LSA_RI_RFC 2 + +/* OSPF Router Informational Capability Bits */ +/* https://www.iana.org/assignments/ospf-parameters/ospf-parameters.xhtml#router-informational-capability */ +#define LSA_RIC_GR_CAPABLE 0 +#define LSA_RIC_GR_HELPER 1 +#define LSA_RIC_STUB_ROUTER 2 struct ospf_lsa_header @@ -731,6 +762,18 @@ struct ospf_lsa_prefix u32 rest[]; }; +struct ospf_tlv +{ +#ifdef CPU_BIG_ENDIAN + u16 type; + u16 length; +#else + u16 length; + u16 type; +#endif + u32 data[]; +}; + static inline uint lsa_net_count(struct ospf_lsa_header *lsa) @@ -998,6 +1041,7 @@ uint ospf_hello3_options(struct ospf_packet *pkt); /* dbdes.c */ void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); +void ospf_reset_ldd(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); uint ospf_dbdes3_options(struct ospf_packet *pkt); diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index e58f1375..f9ca7bfc 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -224,12 +224,17 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa /* * lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type. * lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that - * old type is just new type masked by 0xff. That is not universally true, - * but it holds for all OSPFv2 types currently supported by BIRD. + * old type is just new type masked by 0xff. That holds for most OSPFv2 types, + * but we have to fix it for opaque LSAs. */ if (ospf_is_v2(p)) + { + if (lsa_is_opaque(en->lsa_type)) + en->lsa.type_raw = LSA_T_V2_OPAQUE_ + LSA_SCOPE_ORDER(en->lsa_type); + lsa_set_options(&en->lsa, lsa_opts); + } mb_free(en->lsa_body); en->lsa_body = lsa_body; @@ -273,6 +278,10 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa) u16 lsa_blen = p->lsab_used; u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_blen; + /* For OSPFv2 Opaque LSAs, LS ID consists of Opaque Type and Opaque ID */ + if (ospf_is_v2(p) && lsa_is_opaque(lsa->type)) + lsa->id |= (u32) lsa_get_opaque_type(lsa->type) << 24; + en = ospf_hash_get(p->gr, lsa->dom, lsa->id, p->router_id, lsa->type); if (!SNODE_VALID(en)) @@ -1658,6 +1667,41 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa) ifa->pxn_lsa = ospf_originate_lsa(p, &lsa); } + +/* + * Router Information LSA handling + * Type = LSA_T_RI_AREA, opaque type = LSA_OT_RI + */ + +void +ospf_add_ric_tlv(struct ospf_proto *p) +{ + struct ospf_tlv *ri = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32)); + ri->type = LSA_RI_RIC; + ri->length = sizeof(struct ospf_tlv) + sizeof(u32); + + BIT32R_SET(ri->data, LSA_RIC_STUB_ROUTER); +} + +void +ospf_originate_ri_lsa(struct ospf_proto *p, struct ospf_area *oa) +{ + struct ospf_new_lsa lsa = { + .type = LSA_T_RI_AREA, + .dom = oa->areaid, + .id = p->instance_id + }; + + ospf_add_ric_tlv(p); + + ospf_originate_lsa(p, &lsa); +} + + +/* + * Generic topology code + */ + static inline int breaks_minlsinterval(struct top_hash_entry *en) { return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); } @@ -1692,6 +1736,7 @@ ospf_update_topology(struct ospf_proto *p) ospf_originate_rt_lsa(p, oa); ospf_originate_prefix_rt_lsa(p, oa); + ospf_originate_ri_lsa(p, oa); oa->update_rt_lsa = 0; } } |