diff options
Diffstat (limited to 'proto/ospf')
-rw-r--r-- | proto/ospf/config.Y | 49 | ||||
-rw-r--r-- | proto/ospf/hello.c | 29 | ||||
-rw-r--r-- | proto/ospf/iface.c | 68 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 22 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 32 | ||||
-rw-r--r-- | proto/ospf/neighbor.h | 1 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 63 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 16 | ||||
-rw-r--r-- | proto/ospf/packet.c | 6 | ||||
-rw-r--r-- | proto/ospf/rt.c | 6 | ||||
-rw-r--r-- | proto/ospf/topology.c | 114 |
11 files changed, 306 insertions, 100 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 67b0785f..c47a8cd2 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -92,6 +92,7 @@ ospf_proto_finish(void) if (cf->abr && !backbone) { struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config)); + ac->type = OPT_E; /* Backbone is non-stub */ add_head(&cf->area_list, NODE ac); init_list(&ac->patt_list); init_list(&ac->net_list); @@ -124,16 +125,17 @@ CF_DECLS CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID) CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT) -CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST) +CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST, DEFAULT) CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP) -CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC) -CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK) +CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY) +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) +CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY) %type <t> opttext %type <ld> lsadb_args +%type <i> nbma_eligible CF_GRAMMAR @@ -156,6 +158,7 @@ ospf_proto: ospf_proto_item: proto_item | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } + | STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; } | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); } | TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); } @@ -288,19 +291,25 @@ ospf_iface_item: | TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; } | TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; } | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); } + | PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (OSPF_VERSION != 2) cf_error("Real netmask option requires OSPFv2"); } | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } | PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STUB bool { OSPF_PATT->stub = $2 ; } | CHECK LINK bool { OSPF_PATT->check_link = $3; } | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } - | NEIGHBORS '{' ipa_list '}' + | NEIGHBORS '{' nbma_list '}' | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } + | TX tos { OSPF_PATT->tx_tos = $2; } + | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; } + | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; } + | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } + | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } | password_list ; @@ -326,33 +335,24 @@ pref_opt: | TAG expr { this_pref->tag = $2; } ; -ipa_list: +nbma_list: /* empty */ - | ipa_list ipa_item + | nbma_list nbma_item ; -ipa_item: - ipa_el - | ipa_ne; +nbma_eligible: + /* empty */ { $$ = 0; } + | ELIGIBLE { $$ = 1; } + ; -ipa_el: IPA ';' +nbma_item: IPA nbma_eligible ';' { this_nbma = cfg_allocz(sizeof(struct nbma_node)); add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); this_nbma->ip=$1; - this_nbma->eligible=0; + this_nbma->eligible=$2; } ; - -ipa_ne: IPA ELIGIBLE ';' - { - this_nbma = cfg_allocz(sizeof(struct nbma_node)); - add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); - this_nbma->ip=$1; - this_nbma->eligible=1; - } -; - ospf_iface_start: { @@ -371,6 +371,9 @@ ospf_iface_start: OSPF_PATT->type = OSPF_IT_UNDEF; init_list(&OSPF_PATT->nbma_list); OSPF_PATT->autype = OSPF_AUTH_NONE; + OSPF_PATT->ptp_netmask = 2; /* not specified */ + OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL; + OSPF_PATT->tx_priority = sk_priority_control; reset_passwords(); } ; @@ -439,7 +442,7 @@ lsadb_args: $$ = cfg_allocz(sizeof(struct lsadb_show_data)); } | lsadb_args GLOBAL { $$ = $1; $$->scope = LSA_SCOPE_AS; } - | lsadb_args AREA idval { $$ = $1; $$->scope = LSA_SCOPE_AREA; $$->area = $3 } + | lsadb_args AREA idval { $$ = $1; $$->scope = LSA_SCOPE_AREA; $$->area = $3; } | lsadb_args LINK { $$ = $1; $$->scope = 1; /* hack, 0 is no filter */ } | lsadb_args TYPE NUM { $$ = $1; $$->type = $3; } | lsadb_args LSID idval { $$ = $1; $$->lsid = $3; } diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index f9ba28f6..b6b11004 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -101,6 +101,17 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, return; } +#ifdef OSPFv2 + if (n && (n->rid != ntohl(ps_i->routerid))) + { + OSPF_TRACE(D_EVENTS, + "Neighbor %I has changed router id from %R to %R.", + n->ip, n->rid, ntohl(ps_i->routerid)); + ospf_neigh_remove(n); + n = NULL; + } +#endif + if (!n) { if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) @@ -132,7 +143,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, n = ospf_neighbor_new(ifa); - n->rid = ntohl(((struct ospf_packet *) ps)->routerid); + n->rid = ntohl(ps_i->routerid); n->ip = faddr; n->dr = ntohl(ps->dr); n->bdr = ntohl(ps->bdr); @@ -140,7 +151,18 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, #ifdef OSPFv3 n->iface_id = ntohl(ps->iface_id); #endif + + if (n->ifa->cf->bfd) + ospf_neigh_update_bfd(n, n->ifa->bfd); } +#ifdef OSPFv3 /* NOTE: this could also be relevant for OSPFv2 on PtP ifaces */ + else if (!ipa_equal(faddr, n->ip)) + { + OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr); + n->ip = faddr; + } +#endif + ospf_neigh_sm(n, INM_HELLOREC); pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1)); @@ -253,7 +275,8 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) #ifdef OSPFv2 pkt->netmask = ipa_mkmask(ifa->addr->pxlen); ipa_hton(pkt->netmask); - if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP)) + if ((ifa->type == OSPF_IT_VLINK) || + ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask)) pkt->netmask = IPA_NONE; #endif @@ -261,7 +284,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) pkt->priority = ifa->priority; #ifdef OSPFv3 - pkt->iface_id = htonl(ifa->iface->index); + pkt->iface_id = htonl(ifa->iface_id); pkt->options3 = ifa->oa->options >> 16; pkt->options2 = ifa->oa->options >> 8; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index a6a0c6c1..f1409840 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -77,7 +77,8 @@ ospf_sk_open(struct ospf_iface *ifa) sk->dport = OSPF_PROTO; sk->saddr = IPA_NONE; - sk->tos = IP_PREC_INTERNET_CONTROL; + sk->tos = ifa->cf->tx_tos; + sk->priority = ifa->cf->tx_priority; sk->rx_hook = ospf_rx_hook; sk->tx_hook = ospf_tx_hook; sk->err_hook = ospf_err_hook; @@ -85,7 +86,8 @@ ospf_sk_open(struct ospf_iface *ifa) sk->rbsize = rxbufsize(ifa); sk->tbsize = rxbufsize(ifa); sk->data = (void *) ifa; - sk->flags = SKF_LADDR_RX; + sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0); + sk->ttl = ifa->cf->ttl_security ? 255 : -1; if (sk_open(sk) != 0) goto err; @@ -130,7 +132,7 @@ ospf_sk_open(struct ospf_iface *ifa) else { ifa->all_routers = AllSPFRouters; - sk->ttl = 1; /* Hack, this will affect just multicast packets */ + sk->ttl = ifa->cf->ttl_security ? 255 : 1; if (sk_setup_multicast(sk) < 0) goto err; @@ -533,10 +535,15 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->rxbuf = ip->rxbuf; ifa->check_link = ip->check_link; ifa->ecmp_weight = ip->ecmp_weight; + ifa->check_ttl = (ip->ttl_security == 1); + ifa->bfd = ip->bfd; #ifdef OSPFv2 ifa->autype = ip->autype; ifa->passwords = ip->passwords; + ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0; + if (ip->ptp_netmask < 2) + ifa->ptp_netmask = ip->ptp_netmask; #endif #ifdef OSPFv3 @@ -567,13 +574,29 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i log(L_WARN "%s: Cannot use interface %s as %s, forcing %s", p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); + /* Assign iface ID, for vlinks, this is ugly hack */ + ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++; init_list(&ifa->neigh_list); init_list(&ifa->nbma_list); WALK_LIST(nb, ip->nbma_list) - if (ipa_in_net(nb->ip, addr->prefix, addr->pxlen)) - add_nbma_node(ifa, nb, 0); + { + /* In OSPFv3, addr is link-local while configured neighbors could + have global IP (although RFC 5340 C.5 says link-local addresses + should be used). Because OSPFv3 iface is not subnet-specific, + there is no need for ipa_in_net() check */ + +#ifdef OSPFv2 + if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen)) + continue; +#else + if (!ipa_has_link_scope(nb->ip)) + log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip); +#endif + + add_nbma_node(ifa, nb, 0); + } ifa->state = OSPF_IS_DOWN; add_tail(&oa->po->iface_list, NODE ifa); @@ -640,7 +663,11 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) if (ifa->stub != new_stub) return 0; - if (new->real_bcast != ifa->cf->real_bcast) + /* Change of these options would require to reset the iface socket */ + if ((new->real_bcast != ifa->cf->real_bcast) || + (new->tx_tos != ifa->cf->tx_tos) || + (new->tx_priority != ifa->cf->tx_priority) || + (new->ttl_security != ifa->cf->ttl_security)) return 0; ifa->cf = new; @@ -769,8 +796,14 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* NBMA LIST - add new */ WALK_LIST(nb, new->nbma_list) { + /* See related note in ospf_iface_new() */ +#ifdef OSPFv2 if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen)) continue; +#else + if (!ipa_has_link_scope(nb->ip)) + log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip); +#endif if (! find_nbma_node(ifa, nb->ip)) { @@ -808,6 +841,19 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) ifa->ecmp_weight = new->ecmp_weight; } + /* BFD */ + if (ifa->bfd != new->bfd) + { + OSPF_TRACE(D_EVENTS, "%s BFD on interface %s", + new->bfd ? "Enabling" : "Disabling", ifname); + ifa->bfd = new->bfd; + + struct ospf_neighbor *n; + WALK_LIST(n, ifa->neigh_list) + ospf_neigh_update_bfd(n, ifa->bfd); + } + + /* instance_id is not updated - it is part of key */ return 1; @@ -884,6 +930,10 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) struct ifa *a; WALK_LIST(iface, iface_list) + { + if (! (iface->flags & IF_UP)) + continue; + WALK_LIST(a, iface->addrs) { if (a->flags & IA_SECONDARY) @@ -909,6 +959,7 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_iface_new(oa, a, ip); } } + } } @@ -1012,6 +1063,10 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) struct ifa *a; WALK_LIST(iface, iface_list) + { + if (! (iface->flags & IF_UP)) + continue; + WALK_LIST(a, iface->addrs) { if (a->flags & IA_SECONDARY) @@ -1040,6 +1095,7 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_iface_new(oa, a, ip); } } + } } #endif diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 16967a7f..beac6c83 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -112,6 +112,10 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i { u32 scope = LSA_SCOPE(lsa); + /* Handle inactive vlinks */ + if (ifa->state == OSPF_IS_DOWN) + return 0; + /* 4.5.2 (Case 2) */ if (unknown_lsa_type(lsa) && !(lsa->type & LSA_UBIT)) scope = LSA_SCOPE_LINK; @@ -119,7 +123,7 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i switch (scope) { case LSA_SCOPE_LINK: - return ifa->iface->index == domain; + return ifa->iface_id == domain; case LSA_SCOPE_AREA: return ifa->oa->areaid == domain; @@ -201,7 +205,7 @@ ospf_lsupd_flood(struct proto_ospf *po, en->lsa_body = NULL; DBG("Removing from lsreq list for neigh %R\n", nn->rid); ospf_hash_delete(nn->lsrqh, en); - if (EMPTY_SLIST(nn->lsrql)) + if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING)) ospf_neigh_sm(nn, INM_LOADDONE); continue; break; @@ -212,7 +216,7 @@ ospf_lsupd_flood(struct proto_ospf *po, en->lsa_body = NULL; DBG("Removing from lsreq list for neigh %R\n", nn->rid); ospf_hash_delete(nn->lsrqh, en); - if (EMPTY_SLIST(nn->lsrql)) + if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING)) ospf_neigh_sm(nn, INM_LOADDONE); break; default: @@ -280,6 +284,16 @@ ospf_lsupd_flood(struct proto_ospf *po, ospf_pkt_fill_hdr(ifa, pk, LSUPD_P); pk->lsano = htonl(1); + /* Check iface buffer size */ + int len2 = sizeof(struct ospf_lsupd_packet) + (hn ? ntohs(hn->length) : hh->length); + if (len2 > ospf_pkt_bufsize(ifa)) + { + /* Cannot fit in a tx buffer, skip that iface */ + log(L_ERR "OSPF: LSA too large to flood on %s (Type: %04x, Id: %R, Rt: %R)", + ifa->iface->name, hh->type, hh->id, hh->rt); + continue; + } + lh = (struct ospf_lsa_header *) (pk + 1); /* Copy LSA into the packet */ @@ -395,7 +409,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) if (len2 > ospf_pkt_bufsize(n->ifa)) { /* Cannot fit in a tx buffer, skip that */ - log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", + log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt); lsr = NODE_NEXT(lsr); continue; diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 642365b3..61224ec2 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -459,7 +459,7 @@ bdr_election(struct ospf_iface *ifa) #else /* OSPFv3 */ me.dr = ifa->drid; me.bdr = ifa->bdrid; - me.iface_id = ifa->iface->index; + me.iface_id = ifa->iface_id; #endif add_tail(&ifa->neigh_list, NODE & me); @@ -582,6 +582,36 @@ ospf_neigh_remove(struct ospf_neighbor *n) OSPF_TRACE(D_EVENTS, "Deleting neigbor."); } +static void +ospf_neigh_bfd_hook(struct bfd_request *req) +{ + struct ospf_neighbor *n = req->data; + struct proto *p = &n->ifa->oa->po->proto; + + if (req->down) + { + OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", + n->ip, n->ifa->iface->name); + + ospf_neigh_remove(n); + } +} + +void +ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd) +{ + if (use_bfd && !n->bfd_req) + n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, n->ifa->iface, + ospf_neigh_bfd_hook, n); + + if (!use_bfd && n->bfd_req) + { + rfree(n->bfd_req); + n->bfd_req = NULL; + } +} + + void ospf_sh_neigh_info(struct ospf_neighbor *n) { diff --git a/proto/ospf/neighbor.h b/proto/ospf/neighbor.h index f593faed..e674927d 100644 --- a/proto/ospf/neighbor.h +++ b/proto/ospf/neighbor.h @@ -16,6 +16,7 @@ void bdr_election(struct ospf_iface *ifa); struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid); struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip); void ospf_neigh_remove(struct ospf_neighbor *n); +void ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd); void ospf_sh_neigh_info(struct ospf_neighbor *n); #endif /* _BIRD_OSPF_NEIGHBOR_H_ */ diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 1aa7407a..232f3f6c 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -167,7 +167,7 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) #ifdef OSPFv2 oa->options = ac->type; #else /* OSPFv3 */ - oa->options = OPT_R | ac->type | OPT_V6; + oa->options = ac->type | OPT_V6 | (po->stub_router ? 0 : OPT_R); #endif /* @@ -232,7 +232,9 @@ ospf_start(struct proto *p) struct ospf_area_config *ac; po->router_id = proto_get_router_id(p->cf); + po->last_vlink_id = 0x80000000; po->rfc1583 = c->rfc1583; + po->stub_router = c->stub_router; po->ebit = 0; po->ecmp = c->ecmp; po->tick = c->tick; @@ -689,7 +691,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) #ifdef OSPFv2 oa->options = nac->type; #else /* OSPFv3 */ - oa->options = OPT_R | nac->type | OPT_V6; + oa->options = nac->type | OPT_V6 | (oa->po->stub_router ? 0 : OPT_R); #endif if (oa_is_nssa(oa) && (oa->po->areano > 1)) oa->po->ebit = 1; @@ -728,12 +730,16 @@ 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; if (old->abr != new->abr) return 0; + po->stub_router = new->stub_router; po->ecmp = new->ecmp; po->tick = new->tick; po->disp_timer->recurrent = po->tick; @@ -827,6 +833,7 @@ ospf_sh(struct proto *p) cli_msg(-1014, "%s:", p->name); cli_msg(-1014, "RFC1583 compatibility: %s", (po->rfc1583 ? "enable" : "disabled")); + cli_msg(-1014, "Stub router: %s", (po->stub_router ? "Yes" : "No")); cli_msg(-1014, "RT scheduler tick: %d", po->tick); cli_msg(-1014, "Number of areas: %u", po->areano); cli_msg(-1014, "Number of LSAs in DB:\t%u", po->gr->hash_entries); @@ -953,8 +960,10 @@ lsa_compare_for_state(const void *p1, const void *p2) struct ospf_lsa_header *lsa1 = &(he1->lsa); struct ospf_lsa_header *lsa2 = &(he2->lsa); - if (he1->domain != he2->domain) - return he1->domain - he2->domain; + if (he1->domain < he2->domain) + return -1; + if (he1->domain > he2->domain) + return 1; #ifdef OSPFv3 struct ospf_lsa_header lsatmp1, lsatmp2; @@ -979,14 +988,18 @@ lsa_compare_for_state(const void *p1, const void *p2) { #ifdef OSPFv3 /* In OSPFv3, neworks are named base on ID of DR */ - if (lsa1->rt != lsa2->rt) - return lsa1->rt - lsa2->rt; + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; #endif /* For OSPFv2, this is IP of the network, for OSPFv3, this is interface ID */ - if (lsa1->id != lsa2->id) - return lsa1->id - lsa2->id; + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; #ifdef OSPFv3 if (px1 != px2) @@ -997,14 +1010,20 @@ lsa_compare_for_state(const void *p1, const void *p2) } else { - if (lsa1->rt != lsa2->rt) - return lsa1->rt - lsa2->rt; + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; - if (lsa1->type != lsa2->type) - return lsa1->type - lsa2->type; - - if (lsa1->id != lsa2->id) - return lsa1->id - lsa2->id; + if (lsa1->type < lsa2->type) + return -1; + if (lsa1->type > lsa2->type) + return 1; + + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; #ifdef OSPFv3 if (px1 != px2) @@ -1023,12 +1042,16 @@ ext_compare_for_state(const void *p1, const void *p2) struct ospf_lsa_header *lsa1 = &(he1->lsa); struct ospf_lsa_header *lsa2 = &(he2->lsa); - if (lsa1->rt != lsa2->rt) - return lsa1->rt - lsa2->rt; + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; + + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; - if (lsa1->id != lsa2->id) - return lsa1->id - lsa2->id; - return lsa1->sn - lsa2->sn; } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 3bffaf91..46a1c3c1 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -46,6 +46,7 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ #include "nest/route.h" #include "nest/cli.h" #include "nest/locks.h" +#include "nest/bfd.h" #include "conf/conf.h" #include "lib/string.h" @@ -83,6 +84,7 @@ struct ospf_config struct proto_config c; unsigned tick; byte rfc1583; + byte stub_router; byte abr; int ecmp; list area_list; /* list of struct ospf_area_config */ @@ -189,7 +191,8 @@ struct ospf_iface u32 rxmtint; /* number of seconds between LSA retransmissions */ u32 pollint; /* Poll interval */ u32 deadint; /* after "deadint" missing hellos is router dead */ - u32 vid; /* Id of peer of virtual link */ + u32 iface_id; /* Interface ID (iface->index or new value for vlinks) */ + u32 vid; /* ID of peer of virtual link */ ip_addr vip; /* IP of peer of virtual link */ struct ospf_iface *vifa; /* OSPF iface which the vlink goes through */ struct ospf_area *voa; /* OSPF area which the vlink goes through */ @@ -272,6 +275,9 @@ struct ospf_iface u16 rxbuf; /* Buffer size */ u8 check_link; /* Whether iface link change is used */ u8 ecmp_weight; /* Weight used for ECMP */ + u8 ptp_netmask; /* Send real netmask for P2P */ + u8 check_ttl; /* Check incoming packets for TTL 255 */ + u8 bfd; /* Use BFD on iface */ }; struct ospf_md5 @@ -704,6 +710,7 @@ struct ospf_neighbor #define ACKL_DIRECT 0 #define ACKL_DELAY 1 timer *ackd_timer; /* Delayed ack timer */ + struct bfd_request *bfd_req; /* BFD request, if BFD is used */ u32 csn; /* Last received crypt seq number (for MD5) */ }; @@ -769,6 +776,7 @@ struct proto_ospf int areano; /* Number of area I belong to */ struct fib rtf; /* Routing table */ byte rfc1583; /* RFC1583 compatibility */ + byte stub_router; /* Do not forward transit traffic */ byte ebit; /* Did I originate any ext lsa? */ byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ struct ospf_area *backbone; /* If exists */ @@ -776,6 +784,7 @@ struct proto_ospf int lsab_size, lsab_used; linpool *nhpool; /* Linpool used for next hops computed in SPF */ u32 router_id; + u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ }; struct ospf_iface_patt @@ -795,6 +804,8 @@ struct ospf_iface_patt u32 priority; u32 voa; u32 vid; + int tx_tos; + int tx_priority; u16 rxbuf; #define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_LARGE 1 @@ -808,6 +819,9 @@ struct ospf_iface_patt u8 check_link; u8 ecmp_weight; u8 real_bcast; /* Not really used in OSPFv3 */ + u8 ptp_netmask; /* bool + 2 for unspecified */ + u8 ttl_security; /* bool + 2 for TX only */ + u8 bfd; #ifdef OSPFv2 list *passwords; diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 241a58f7..4338bc1a 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -309,6 +309,12 @@ ospf_rx_hook(sock *sk, int size) return 1; } + if (ifa->check_ttl && (sk->ttl < 255)) + { + log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->ttl); + return 1; + } + if ((unsigned) size < sizeof(struct ospf_packet)) { log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 1053fd07..52110aa1 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -501,6 +501,10 @@ ospf_rt_spfa(struct ospf_area *oa) #ifdef OSPFv2 ospf_rt_spfa_rtlinks(oa, act, act); #else /* OSPFv3 */ + /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */ + if ((act != oa->rt) && !(rt->options & OPT_R)) + break; + for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt); tmp; tmp = ospf_hash_find_rt_next(tmp)) ospf_rt_spfa_rtlinks(oa, act, tmp); @@ -1839,7 +1843,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (en->lsa.type == LSA_T_RT) { struct ospf_lsa_rt *rt = en->lsa_body; - if (!(rt->options & OPT_V6) || !(rt->options & OPT_R)) + if (!(rt->options & OPT_V6)) return; } #endif diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index ec012b22..f25db9a7 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -103,7 +103,8 @@ lsab_alloc(struct proto_ospf *po, unsigned size) if (po->lsab_used > po->lsab_size) { po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size); - po->lsab = mb_realloc(po->proto.pool, po->lsab, po->lsab_size); + po->lsab = po->lsab ? mb_realloc(po->lsab, po->lsab_size): + mb_alloc(po->proto.pool, po->lsab_size); } return ((byte *) po->lsab) + offset; } @@ -233,6 +234,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) WALK_LIST(ifa, po->iface_list) { int net_lsa = 0; + u32 link_cost = po->stub_router ? 0xffff : ifa->cost; if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && (!EMPTY_LIST(ifa->neigh_list))) @@ -258,9 +260,17 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); ln->type = LSART_PTP; ln->id = neigh->rid; - ln->data = (ifa->addr->flags & IA_PEER) ? - ifa->iface->index : ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; + + /* + * ln->data should be ifa->iface_id in case of no/ptp + * address (ifa->addr->flags & IA_PEER) on PTP link (see + * RFC 2328 12.4.1.1.), but the iface ID value has no use, + * while using IP address even in this case is here for + * compatibility with some broken implementations that use + * this address as a next-hop. + */ + ln->data = ipa_to_u32(ifa->addr->ip); + ln->metric = link_cost; ln->padding = 0; i++; } @@ -274,7 +284,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ln->type = LSART_NET; ln->id = ipa_to_u32(ifa->drip); ln->data = ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; + ln->metric = link_cost; ln->padding = 0; i++; net_lsa = 1; @@ -289,7 +299,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ln->type = LSART_VLNK; ln->id = neigh->rid; ln->data = ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; + ln->metric = link_cost; ln->padding = 0; i++; } @@ -305,7 +315,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) /* Now we will originate stub area if there is no primary */ if (net_lsa || (ifa->type == OSPF_IT_VLINK) || - (ifa->addr->flags & IA_PEER) || + ((ifa->addr->flags & IA_PEER) && ! ifa->cf->stub) || configured_stubnet(oa, ifa->addr)) continue; @@ -368,7 +378,7 @@ add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, ln->type = type; ln->padding = 0; ln->metric = ifa->cost; - ln->lif = ifa->iface->index; + ln->lif = ifa->iface_id; ln->nif = nif; ln->id = id; } @@ -546,7 +556,7 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, if (n->state == NEIGHBOR_FULL) { #ifdef OSPFv3 - en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK); + en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK); if (en) options |= ((struct ospf_lsa_link *) en->lsa_body)->options; #endif @@ -596,7 +606,7 @@ originate_net_lsa(struct ospf_iface *ifa) lsa.options = ifa->oa->options; lsa.id = ipa_to_u32(ifa->addr->ip); #else /* OSPFv3 */ - lsa.id = ifa->iface->index; + lsa.id = ifa->iface_id; #endif lsa.rt = po->router_id; @@ -1207,10 +1217,10 @@ originate_link_lsa(struct ospf_iface *ifa) lsa.age = 0; lsa.type = LSA_T_LINK; - lsa.id = ifa->iface->index; + lsa.id = ifa->iface_id; lsa.rt = po->router_id; lsa.sn = get_seqnum(ifa->link_lsa); - u32 dom = ifa->iface->index; + u32 dom = ifa->iface_id; body = originate_link_lsa_body(ifa, &lsa.length); lsasum_calculate(&lsa, body); @@ -1249,7 +1259,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) struct ospf_config *cf = (struct ospf_config *) (po->proto.cf); struct ospf_iface *ifa; struct ospf_lsa_prefix *lp; - struct ifa *vlink_addr = NULL; int host_addr = 0; int net_lsa; int i = 0; @@ -1263,7 +1272,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) WALK_LIST(ifa, po->iface_list) { - if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) + if ((ifa->oa != oa) || (ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN)) continue; ifa->px_pos_beg = i; @@ -1282,9 +1291,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) (a->scope <= SCOPE_LINK)) continue; - if (!vlink_addr) - vlink_addr = a; - if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) || configured_stubnet(oa, a)) continue; @@ -1304,23 +1310,41 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) ifa->px_pos_end = i; } - /* If there are some configured vlinks, add some global address, - which will be used as a vlink endpoint. */ - if (!EMPTY_LIST(cf->vlink_list) && !host_addr && vlink_addr) - { - lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0); - i++; - } - struct ospf_stubnet_config *sn; if (oa->ac) WALK_LIST(sn, oa->ac->stubnet_list) if (!sn->hidden) { lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost); + if (sn->px.len == MAX_PREFIX_LENGTH) + host_addr = 1; + i++; + } + + /* If there are some configured vlinks, find some global address + (even from another area), which will be used as a vlink endpoint. */ + if (!EMPTY_LIST(cf->vlink_list) && !host_addr) + { + WALK_LIST(ifa, po->iface_list) + { + if ((ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN)) + continue; + + struct ifa *a; + WALK_LIST(a, ifa->iface->addrs) + { + if ((a->flags & IA_SECONDARY) || (a->scope <= SCOPE_LINK)) + continue; + + /* Found some IP */ + lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0); i++; + goto done; } + } + } + done: lp = po->lsab; lp->pxcount = i; *length = po->lsab_used + sizeof(struct ospf_lsa_header); @@ -1389,15 +1413,12 @@ add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc) { u32 *pxl = lsab_offset(po, offset); int i; - for (i = 0; i < *pxc; i++) + for (i = 0; i < *pxc; pxl = prefix_advance(pxl), i++) + if (prefix_same(px, pxl)) { - if (prefix_same(px, pxl)) - { - /* Options should be logically OR'ed together */ - *pxl |= *px; - return; - } - pxl = prefix_advance(pxl); + /* Options should be logically OR'ed together */ + *pxl |= (*px & 0x00FF0000); + return; } ASSERT(pxl == lsab_end(po)); @@ -1405,6 +1426,7 @@ add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc) int pxspace = prefix_space(px); pxl = lsab_alloc(po, pxspace); memcpy(pxl, px, pxspace); + *pxl &= 0xFFFF0000; /* Set metric to zero */ (*pxc)++; } @@ -1415,11 +1437,21 @@ add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int * u32 *pxb = ll->rest; int j; - for (j = 0; j < ll->pxcount; j++) - { - add_prefix(po, pxb, offset, pxc); - pxb = prefix_advance(pxb); - } + for (j = 0; j < ll->pxcount; pxb = prefix_advance(pxb), j++) + { + u8 pxlen = (pxb[0] >> 24); + u8 pxopts = (pxb[0] >> 16); + + /* Skip NU or LA prefixes */ + if (pxopts & (OPT_PX_NU | OPT_PX_LA)) + continue; + + /* Skip link-local prefixes */ + if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000)) + continue; + + add_prefix(po, pxb, offset, pxc); + } } @@ -1449,7 +1481,7 @@ originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length) WALK_LIST(n, ifa->neigh_list) if ((n->state == NEIGHBOR_FULL) && - (en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK))) + (en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK))) add_link_lsa(po, en, offset, &pxc); lp = po->lsab; @@ -1471,7 +1503,7 @@ originate_prefix_net_lsa(struct ospf_iface *ifa) lsa.age = 0; lsa.type = LSA_T_PREFIX; - lsa.id = ifa->iface->index; + lsa.id = ifa->iface_id; lsa.rt = po->router_id; lsa.sn = get_seqnum(ifa->pxn_lsa); u32 dom = ifa->oa->areaid; @@ -1642,7 +1674,7 @@ ospf_lsa_domain(u32 type, struct ospf_iface *ifa) switch (type & LSA_SCOPE_MASK) { case LSA_SCOPE_LINK: - return ifa->iface->index; + return ifa->iface_id; case LSA_SCOPE_AREA: return ifa->oa->areaid; |