People running ospfd should better test this diff. The diff is a start at supporting opaque LSA (type 9, 10 and 11). Those are used for things like graceful restart. Now even if you don't have systems emitting such LSA it is important to test the diff to make sure normal operation is still working. If you have systems announcing the new LSA I would be interested in ospfctl show da output. I do not have such systems around.
happy testing -- :wq Claudio Index: ospfctl/ospfctl.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfctl/ospfctl.c,v retrieving revision 1.55 diff -u -p -r1.55 ospfctl.c --- ospfctl/ospfctl.c 25 Sep 2010 13:29:56 -0000 1.55 +++ ospfctl/ospfctl.c 3 May 2011 09:54:44 -0000 @@ -47,7 +47,7 @@ const char *fmt_timeframe(time_t t); const char *fmt_timeframe_core(time_t t); const char *log_id(u_int32_t ); const char *log_adv_rtr(u_int32_t); -void show_database_head(struct in_addr, u_int8_t); +void show_database_head(struct in_addr, char *, u_int8_t); int show_database_msg(struct imsg *); char *print_ls_type(u_int8_t); void show_db_hdr_msg_detail(struct lsa_hdr *); @@ -183,6 +183,9 @@ main(int argc, char *argv[]) case SHOW_DBASBR: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0); break; + case SHOW_DBOPAQ: + imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0); + break; case SHOW_RIB: printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination", "Nexthop", "Path Type", "Type", "Cost", "Uptime"); @@ -283,6 +286,7 @@ main(int argc, char *argv[]) case SHOW_DBRTR: case SHOW_DBSUM: case SHOW_DBASBR: + case SHOW_DBOPAQ: done = show_db_msg_detail(&imsg); break; case SHOW_RIB: @@ -586,9 +590,10 @@ mask2prefixlen(in_addr_t ina) } void -show_database_head(struct in_addr aid, u_int8_t type) +show_database_head(struct in_addr aid, char *ifname, u_int8_t type) { char *header, *format; + int cleanup = 0; switch (type) { case LSA_TYPE_ROUTER: @@ -608,24 +613,47 @@ show_database_head(struct in_addr aid, u if ((header = strdup("Type-5 AS External Link States")) == NULL) err(1, NULL); break; + case LSA_TYPE_LINK_OPAQ: + format = "Type-9 Link Local Opaque Link States"; + break; + case LSA_TYPE_AREA_OPAQ: + format = "Type-10 Area Local Opaque Link States"; + break; + case LSA_TYPE_AS_OPAQ: + format = NULL; + if ((header = strdup("Type-11 AS Wide Opaque Link States")) == + NULL) + err(1, NULL); + break; default: - errx(1, "unknown LSA type"); + if (asprintf(&format, "LSA type %x", ntohs(type)) == -1) + err(1, NULL); + cleanup = 1; + break; } - if (type != LSA_TYPE_EXTERNAL) + if (type == LSA_TYPE_LINK_OPAQ) { + if (asprintf(&header, "%s (Area %s Interface %s)", format, + inet_ntoa(aid), ifname) == -1) + err(1, NULL); + } else if (type != LSA_TYPE_EXTERNAL && type != LSA_TYPE_AS_OPAQ) if (asprintf(&header, "%s (Area %s)", format, inet_ntoa(aid)) == -1) err(1, NULL); printf("\n%-15s %s\n\n", "", header); free(header); + if (cleanup) + free(format); } int show_database_msg(struct imsg *imsg) { static struct in_addr area_id; + static char ifname[IF_NAMESIZE]; static u_int8_t lasttype; struct area *area; + struct iface *iface; struct lsa_hdr *lsa; switch (imsg->hdr.type) { @@ -633,7 +661,7 @@ show_database_msg(struct imsg *imsg) case IMSG_CTL_SHOW_DB_SELF: lsa = imsg->data; if (lsa->type != lasttype) { - show_database_head(area_id, lsa->type); + show_database_head(area_id, ifname, lsa->type); printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID", "Adv Router", "Age", "Seq#", "Checksum"); } @@ -648,6 +676,11 @@ show_database_msg(struct imsg *imsg) area_id = area->id; lasttype = 0; break; + case IMSG_CTL_IFACE: + iface = imsg->data; + strlcpy(ifname, iface->name, sizeof(ifname)); + lasttype = 0; + break; case IMSG_CTL_END: printf("\n"); return (1); @@ -672,6 +705,12 @@ print_ls_type(u_int8_t type) return ("Summary (Router)"); case LSA_TYPE_EXTERNAL: return ("AS External"); + case LSA_TYPE_LINK_OPAQ: + return ("Type-9 Opaque"); + case LSA_TYPE_AREA_OPAQ: + return ("Type-10 Opaque"); + case LSA_TYPE_AS_OPAQ: + return ("Type-11 Opaque"); default: return ("Unknown"); } @@ -703,6 +742,13 @@ show_db_hdr_msg_detail(struct lsa_hdr *l printf("Link State ID: %s (External Network Number)\n", log_id(lsa->ls_id)); break; + case LSA_TYPE_LINK_OPAQ: + case LSA_TYPE_AREA_OPAQ: + case LSA_TYPE_AS_OPAQ: + printf("Link State ID: %s Type %d ID %d\n", log_id(lsa->ls_id), + LSA_24_GETHI(ntohl(lsa->ls_id)), + LSA_24_GETLO(ntohl(lsa->ls_id))); + break; } printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr)); @@ -744,9 +790,11 @@ int show_db_msg_detail(struct imsg *imsg) { static struct in_addr area_id; + static char ifname[IF_NAMESIZE]; static u_int8_t lasttype; struct in_addr addr, data; struct area *area; + struct iface *iface; struct lsa *lsa; struct lsa_rtr_link *rtr_link; struct lsa_asext *asext; @@ -758,7 +806,7 @@ show_db_msg_detail(struct imsg *imsg) case IMSG_CTL_SHOW_DB_EXT: lsa = imsg->data; if (lsa->hdr.type != lasttype) - show_database_head(area_id, lsa->hdr.type); + show_database_head(area_id, ifname, lsa->hdr.type); show_db_hdr_msg_detail(&lsa->hdr); addr.s_addr = lsa->data.asext.mask; printf("Network Mask: %s\n", inet_ntoa(addr)); @@ -781,7 +829,7 @@ show_db_msg_detail(struct imsg *imsg) case IMSG_CTL_SHOW_DB_NET: lsa = imsg->data; if (lsa->hdr.type != lasttype) - show_database_head(area_id, lsa->hdr.type); + show_database_head(area_id, ifname, lsa->hdr.type); show_db_hdr_msg_detail(&lsa->hdr); addr.s_addr = lsa->data.net.mask; printf("Network Mask: %s\n", inet_ntoa(addr)); @@ -802,7 +850,7 @@ show_db_msg_detail(struct imsg *imsg) case IMSG_CTL_SHOW_DB_RTR: lsa = imsg->data; if (lsa->hdr.type != lasttype) - show_database_head(area_id, lsa->hdr.type); + show_database_head(area_id, ifname, lsa->hdr.type); show_db_hdr_msg_detail(&lsa->hdr); printf("Flags: %s\n", print_ospf_flags(lsa->data.rtr.flags)); nlinks = ntohs(lsa->data.rtr.nlinks); @@ -859,7 +907,7 @@ show_db_msg_detail(struct imsg *imsg) case IMSG_CTL_SHOW_DB_ASBR: lsa = imsg->data; if (lsa->hdr.type != lasttype) - show_database_head(area_id, lsa->hdr.type); + show_database_head(area_id, ifname, lsa->hdr.type); show_db_hdr_msg_detail(&lsa->hdr); addr.s_addr = lsa->data.sum.mask; printf("Network Mask: %s\n", inet_ntoa(addr)); @@ -867,11 +915,24 @@ show_db_msg_detail(struct imsg *imsg) LSA_METRIC_MASK); lasttype = lsa->hdr.type; break; + case IMSG_CTL_SHOW_DB_OPAQ: + lsa = imsg->data; + if (lsa->hdr.type != lasttype) + show_database_head(area_id, ifname, lsa->hdr.type); + show_db_hdr_msg_detail(&lsa->hdr); + /* XXX should we hexdump the data? */ + lasttype = lsa->hdr.type; + break; case IMSG_CTL_AREA: area = imsg->data; area_id = area->id; lasttype = 0; break; + case IMSG_CTL_IFACE: + iface = imsg->data; + strlcpy(ifname, iface->name, sizeof(ifname)); + lasttype = 0; + break; case IMSG_CTL_END: return (1); default: @@ -914,12 +975,15 @@ print_ospf_options(u_int8_t opts) { static char optbuf[32]; - snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|%s|%s|*", + snprintf(optbuf, sizeof(optbuf), "%s|%s|%s|%s|%s|%s|%s|%s", + opts & OSPF_OPTION_DN ? "DN" : "-", + opts & OSPF_OPTION_O ? "O" : "-", opts & OSPF_OPTION_DC ? "DC" : "-", opts & OSPF_OPTION_EA ? "EA" : "-", opts & OSPF_OPTION_NP ? "N/P" : "-", opts & OSPF_OPTION_MC ? "MC" : "-", - opts & OSPF_OPTION_E ? "E" : "-"); + opts & OSPF_OPTION_E ? "E" : "-", + opts & OSPF_OPTION_MT ? "MT" : "-"); return (optbuf); } Index: ospfctl/parser.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfctl/parser.c,v retrieving revision 1.19 diff -u -p -r1.19 parser.c --- ospfctl/parser.c 4 Sep 2010 21:31:04 -0000 1.19 +++ ospfctl/parser.c 2 May 2011 11:58:14 -0000 @@ -102,6 +102,7 @@ static const struct token t_show_db[] = {KEYWORD, "router", SHOW_DBRTR, NULL}, {KEYWORD, "self-originated", SHOW_DBSELF, NULL}, {KEYWORD, "summary", SHOW_DBSUM, NULL}, + {KEYWORD, "opaque", SHOW_DBOPAQ, NULL}, {ENDTOKEN, "", NONE, NULL} }; Index: ospfctl/parser.h =================================================================== RCS file: /cvs/src/usr.sbin/ospfctl/parser.h,v retrieving revision 1.12 diff -u -p -r1.12 parser.h --- ospfctl/parser.h 4 Sep 2010 21:31:04 -0000 1.12 +++ ospfctl/parser.h 2 May 2011 11:58:06 -0000 @@ -46,6 +46,7 @@ enum actions { SHOW_DBSELF, SHOW_DBSUM, SHOW_DBASBR, + SHOW_DBOPAQ, SHOW_RIB, SHOW_RIB_DTAIL, SHOW_FIB, Index: ospfd/control.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/control.c,v retrieving revision 1.34 diff -u -p -r1.34 control.c --- ospfd/control.c 2 Sep 2010 14:03:22 -0000 1.34 +++ ospfd/control.c 2 May 2011 11:55:25 -0000 @@ -253,6 +253,7 @@ control_dispatch_imsg(int fd, short even case IMSG_CTL_SHOW_DB_SELF: case IMSG_CTL_SHOW_DB_SUM: case IMSG_CTL_SHOW_DB_ASBR: + case IMSG_CTL_SHOW_DB_OPAQ: case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_SUM: c->iev.ibuf.pid = imsg.hdr.pid; Index: ospfd/database.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/database.c,v retrieving revision 1.28 diff -u -p -r1.28 database.c @@ -138,7 +138,8 @@ send_db_description(struct nbr *nbr) fatalx("send_db_description: unknown interface type"); } - dd_hdr.opts = area_ospf_options(nbr->iface->area); + /* XXX button or not for opaque LSA? */ + dd_hdr.opts = area_ospf_options(nbr->iface->area) | OSPF_OPTION_O; dd_hdr.bits = bits; dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num); @@ -211,6 +212,13 @@ recv_db_description(struct nbr *nbr, cha case NBR_STA_XSTRT: if (dupe) return; + nbr->capa_options = dd_hdr.opts; + if ((nbr->capa_options & nbr->options) != nbr->options) { + log_warnx("recv_db_description: neighbor ID %s " + "sent inconsistent options %x vs. %x", + inet_ntoa(nbr->id), nbr->capa_options, + nbr->options); + } /* * check bits: either I,M,MS or only M */ Index: ospfd/interface.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/interface.c,v retrieving revision 1.70 diff -u -p -r1.70 interface.c --- ospfd/interface.c 3 Jul 2010 04:44:52 -0000 1.70 +++ ospfd/interface.c 1 May 2011 21:59:27 -0000 @@ -167,6 +167,7 @@ if_new(struct kif *kif, struct kif_addr LIST_INIT(&iface->nbr_list); TAILQ_INIT(&iface->ls_ack_list); TAILQ_INIT(&iface->auth_md_list); + RB_INIT(&iface->lsa_tree); iface->crypt_seq_num = arc4random() & 0x0fffffff; Index: ospfd/neighbor.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/neighbor.c,v retrieving revision 1.42 diff -u -p -r1.42 neighbor.c --- ospfd/neighbor.c 24 Mar 2011 08:35:59 -0000 1.42 +++ ospfd/neighbor.c 3 May 2011 09:57:17 -0000 @@ -313,6 +313,7 @@ nbr_new(u_int32_t nbr_id, struct iface * bzero(&rn, sizeof(rn)); rn.id.s_addr = nbr->id.s_addr; rn.area_id.s_addr = nbr->iface->area->id.s_addr; + rn.ifindex = nbr->iface->ifindex; rn.state = nbr->state; rn.self = self; ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn, @@ -519,6 +520,8 @@ nbr_act_snapshot(struct nbr *nbr) { stop_db_tx_timer(nbr); + ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CAPA, nbr->peerid, 0, + &nbr->capa_options, sizeof(nbr->capa_options)); ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0); return (0); @@ -677,7 +680,7 @@ nbr_to_ctl(struct nbr *nbr) nctl.state_chng_cnt = nbr->stats.sta_chng; nctl.priority = nbr->priority; - nctl.options = nbr->options; + nctl.options = nbr->options | nbr->capa_options; gettimeofday(&now, NULL); if (evtimer_pending(&nbr->inactivity_timer, &tv)) { Index: ospfd/ospf.h =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/ospf.h,v retrieving revision 1.20 diff -u -p -r1.20 ospf.h --- ospfd/ospf.h 25 Mar 2011 08:52:21 -0000 1.20 +++ ospfd/ospf.h 27 Apr 2011 09:38:37 -0000 @@ -81,11 +81,14 @@ #define MAX_SIMPLE_AUTH_LEN 8 /* OSPF compatibility flags */ +#define OSPF_OPTION_MT 0x01 #define OSPF_OPTION_E 0x02 #define OSPF_OPTION_MC 0x04 #define OSPF_OPTION_NP 0x08 #define OSPF_OPTION_EA 0x10 #define OSPF_OPTION_DC 0x20 +#define OSPF_OPTION_O 0x40 /* only on DD options */ +#define OSPF_OPTION_DN 0x80 /* only on LSA options */ /* OSPF packet types */ #define PACKET_TYPE_HELLO 1 @@ -177,6 +180,9 @@ struct ls_upd_hdr { #define LSA_TYPE_SUM_NETWORK 3 #define LSA_TYPE_SUM_ROUTER 4 #define LSA_TYPE_EXTERNAL 5 +#define LSA_TYPE_LINK_OPAQ 9 +#define LSA_TYPE_AREA_OPAQ 10 +#define LSA_TYPE_AS_OPAQ 11 #define LINK_TYPE_POINTTOPOINT 1 #define LINK_TYPE_TRANSIT_NET 2 @@ -186,6 +192,18 @@ struct ls_upd_hdr { /* LSA headers */ #define LSA_METRIC_MASK 0x00ffffff /* only for sum & as-ext */ #define LSA_ASEXT_E_FLAG 0x80000000 + +/* for some reason they thought 24bit types are fun, make them less a hazard */ +#define LSA_24_MASK 0xffffff +#define LSA_24_GETHI(x) \ + ((x) >> 24) +#define LSA_24_GETLO(x) \ + ((x) & LSA_24_MASK) +#define LSA_24_SETHI(x, y) \ + ((x) = ((x) & LSA_24_MASK) | (((y) & 0xff) << 24)) +#define LSA_24_SETLO(x, y) \ + ((x) = ((y) & LSA_24_MASK) | ((x) & ~LSA_24_MASK)) + #define OSPF_RTR_B 0x01 #define OSPF_RTR_E 0x02 Index: ospfd/ospfd.h =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/ospfd.h,v retrieving revision 1.89 diff -u -p -r1.89 ospfd.h --- ospfd/ospfd.h 12 Jan 2011 15:07:46 -0000 1.89 +++ ospfd/ospfd.h 2 May 2011 11:54:43 -0000 @@ -80,6 +80,7 @@ enum imsg_type { IMSG_CTL_SHOW_DB_SELF, IMSG_CTL_SHOW_DB_SUM, IMSG_CTL_SHOW_DB_ASBR, + IMSG_CTL_SHOW_DB_OPAQ, IMSG_CTL_SHOW_NBR, IMSG_CTL_SHOW_RIB, IMSG_CTL_SHOW_SUM, @@ -88,6 +89,7 @@ enum imsg_type { IMSG_CTL_FIB_DECOUPLE, IMSG_CTL_FIB_RELOAD, IMSG_CTL_AREA, + IMSG_CTL_IFACE, IMSG_CTL_KROUTE, IMSG_CTL_KROUTE_ADDR, IMSG_CTL_IFINFO, @@ -99,6 +101,7 @@ enum imsg_type { IMSG_NEIGHBOR_UP, IMSG_NEIGHBOR_DOWN, IMSG_NEIGHBOR_CHANGE, + IMSG_NEIGHBOR_CAPA, IMSG_NETWORK_ADD, IMSG_NETWORK_DEL, IMSG_DD, @@ -310,6 +313,7 @@ struct iface { LIST_HEAD(, nbr) nbr_list; struct auth_md_head auth_md_list; struct lsa_head ls_ack_list; + struct lsa_tree lsa_tree; char name[IF_NAMESIZE]; char demote_group[IFNAMSIZ]; Index: ospfd/ospfe.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/ospfe.c,v retrieving revision 1.81 diff -u -p -r1.81 ospfe.c --- ospfd/ospfe.c 2 May 2011 09:22:23 -0000 1.81 +++ ospfd/ospfe.c 2 May 2011 12:46:36 -0000 @@ -375,6 +375,7 @@ ospfe_dispatch_main(int fd, short event, LIST_INIT(&niface->nbr_list); TAILQ_INIT(&niface->ls_ack_list); TAILQ_INIT(&niface->auth_md_list); + RB_INIT(&niface->lsa_tree); niface->area = narea; LIST_INSERT_HEAD(&narea->iface_list, niface, entry); @@ -544,6 +545,12 @@ ospfe_dispatch_rde(int fd, short event, &lsa_hdr, imsg.data); } } + } else if (lsa_hdr.type == LSA_TYPE_LINK_OPAQ) { + /* + * Flood on interface only + */ + noack += lsa_flood(nbr->iface, nbr, + &lsa_hdr, imsg.data); } else { /* * Flood on all area interfaces. For @@ -676,6 +683,7 @@ ospfe_dispatch_rde(int fd, short event, } break; case IMSG_CTL_AREA: + case IMSG_CTL_IFACE: case IMSG_CTL_END: case IMSG_CTL_SHOW_DATABASE: case IMSG_CTL_SHOW_DB_EXT: @@ -684,6 +692,7 @@ ospfe_dispatch_rde(int fd, short event, case IMSG_CTL_SHOW_DB_SELF: case IMSG_CTL_SHOW_DB_SUM: case IMSG_CTL_SHOW_DB_ASBR: + case IMSG_CTL_SHOW_DB_OPAQ: case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_SUM: case IMSG_CTL_SHOW_SUM_AREA: Index: ospfd/ospfe.h =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/ospfe.h,v retrieving revision 1.43 diff -u -p -r1.43 ospfe.h --- ospfd/ospfe.h 25 Mar 2011 08:52:21 -0000 1.43 +++ ospfd/ospfe.h 20 Apr 2011 10:32:26 -0000 @@ -88,6 +88,7 @@ struct nbr { int state; u_int8_t priority; u_int8_t options; + u_int8_t capa_options; u_int8_t last_rx_options; u_int8_t last_rx_bits; u_int8_t dd_master; Index: ospfd/rde.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/rde.c,v retrieving revision 1.93 diff -u -p -r1.93 rde.c --- ospfd/rde.c 2 May 2011 11:17:03 -0000 1.93 +++ ospfd/rde.c 2 May 2011 11:56:41 -0000 @@ -42,6 +42,7 @@ void rde_sig_handler(int sig, short, v void rde_shutdown(void); void rde_dispatch_imsg(int, short, void *); void rde_dispatch_parent(int, short, void *); +void rde_dump_area(struct area *, int, pid_t); void rde_send_summary(pid_t); void rde_send_summary_area(struct area *, pid_t); @@ -61,7 +62,6 @@ void rde_asext_get(struct kroute *); void rde_asext_put(struct kroute *); void rde_asext_free(void); struct lsa *orig_asext_lsa(struct kroute *, u_int32_t, u_int16_t); - struct lsa *orig_sum_lsa(struct rt_node *, struct area *, u_int8_t, int); struct ospfd_conf *rdeconf = NULL, *nconf = NULL; @@ -305,12 +305,20 @@ rde_dispatch_imsg(int fd, short event, v if (nbr->state & NBR_STA_FULL) rde_req_list_free(nbr); break; + case IMSG_NEIGHBOR_CAPA: + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(u_int8_t)) + fatalx("invalid size of OE request"); + nbr = rde_nbr_find(imsg.hdr.peerid); + if (nbr == NULL) + break; + nbr->capa_options = *(u_int8_t *)imsg.data; + break; case IMSG_DB_SNAPSHOT: nbr = rde_nbr_find(imsg.hdr.peerid); if (nbr == NULL) break; - lsa_snap(nbr->area, imsg.hdr.peerid); + lsa_snap(nbr); imsg_compose_event(iev_ospfe, IMSG_DB_END, imsg.hdr.peerid, 0, -1, NULL, 0); @@ -332,7 +340,7 @@ rde_dispatch_imsg(int fd, short event, v error = 1; break; } - v = lsa_find(nbr->area, lsa_hdr.type, + v = lsa_find(nbr->iface, lsa_hdr.type, lsa_hdr.ls_id, lsa_hdr.adv_rtr); if (v == NULL) db_hdr = NULL; @@ -373,7 +381,7 @@ rde_dispatch_imsg(int fd, short event, v memcpy(&req_hdr, buf, sizeof(req_hdr)); buf += sizeof(req_hdr); - if ((v = lsa_find(nbr->area, + if ((v = lsa_find(nbr->iface, ntohl(req_hdr.type), req_hdr.ls_id, req_hdr.adv_rtr)) == NULL) { log_debug("rde_dispatch_imsg: " @@ -408,7 +416,7 @@ rde_dispatch_imsg(int fd, short event, v break; } - v = lsa_find(nbr->area, lsa->hdr.type, lsa->hdr.ls_id, + v = lsa_find(nbr->iface, lsa->hdr.type, lsa->hdr.ls_id, lsa->hdr.adv_rtr); if (v == NULL) db_hdr = NULL; @@ -504,7 +512,7 @@ rde_dispatch_imsg(int fd, short event, v if (rde_nbr_loading(nbr->area)) break; - v = lsa_find(nbr->area, lsa_hdr.type, lsa_hdr.ls_id, + v = lsa_find(nbr->iface, lsa_hdr.type, lsa_hdr.ls_id, lsa_hdr.adv_rtr); if (v == NULL) db_hdr = NULL; @@ -524,6 +532,7 @@ rde_dispatch_imsg(int fd, short event, v case IMSG_CTL_SHOW_DB_SELF: case IMSG_CTL_SHOW_DB_SUM: case IMSG_CTL_SHOW_DB_ASBR: + case IMSG_CTL_SHOW_DB_OPAQ: if (imsg.hdr.len != IMSG_HEADER_SIZE && imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(aid)) { log_warnx("rde_dispatch_imsg: wrong imsg len"); @@ -531,10 +540,7 @@ rde_dispatch_imsg(int fd, short event, v } if (imsg.hdr.len == IMSG_HEADER_SIZE) { LIST_FOREACH(area, &rdeconf->area_list, entry) { - imsg_compose_event(iev_ospfe, - IMSG_CTL_AREA, 0, imsg.hdr.pid, -1, - area, sizeof(*area)); - lsa_dump(&area->lsa_tree, imsg.hdr.type, + rde_dump_area(area, imsg.hdr.type, imsg.hdr.pid); } lsa_dump(&asext_tree, imsg.hdr.type, @@ -542,10 +548,7 @@ rde_dispatch_imsg(int fd, short event, v } else { memcpy(&aid, imsg.data, sizeof(aid)); if ((area = area_find(rdeconf, aid)) != NULL) { - imsg_compose_event(iev_ospfe, - IMSG_CTL_AREA, 0, imsg.hdr.pid, -1, - area, sizeof(*area)); - lsa_dump(&area->lsa_tree, imsg.hdr.type, + rde_dump_area(area, imsg.hdr.type, imsg.hdr.pid); if (!area->stub) lsa_dump(&asext_tree, @@ -686,6 +689,7 @@ rde_dispatch_parent(int fd, short event, LIST_INIT(&niface->nbr_list); TAILQ_INIT(&niface->ls_ack_list); TAILQ_INIT(&niface->auth_md_list); + RB_INIT(&niface->lsa_tree); niface->area = narea; LIST_INSERT_HEAD(&narea->iface_list, niface, entry); @@ -711,6 +715,26 @@ rde_dispatch_parent(int fd, short event, } } +void +rde_dump_area(struct area *area, int imsg_type, pid_t pid) +{ + struct iface *iface; + + /* dump header */ + imsg_compose_event(iev_ospfe, IMSG_CTL_AREA, 0, pid, -1, + area, sizeof(*area)); + + /* dump link local lsa */ + LIST_FOREACH(iface, &area->iface_list, entry) { + imsg_compose_event(iev_ospfe, IMSG_CTL_IFACE, + 0, pid, -1, iface, sizeof(*iface)); + lsa_dump(&iface->lsa_tree, imsg_type, pid); + } + + /* dump area lsa */ + lsa_dump(&area->lsa_tree, imsg_type, pid); +} + u_int32_t rde_router_id(void) { @@ -903,18 +927,27 @@ rde_nbr_new(u_int32_t peerid, struct rde struct rde_nbr_head *head; struct rde_nbr *nbr; struct area *area; + struct iface *iface; if (rde_nbr_find(peerid)) return (NULL); if ((area = area_find(rdeconf, new->area_id)) == NULL) fatalx("rde_nbr_new: unknown area"); + LIST_FOREACH(iface, &area->iface_list, entry) { + if (iface->ifindex == new->ifindex) + break; + } + if (iface == NULL) + fatalx("rde_nbr_new: unknown interface"); + if ((nbr = calloc(1, sizeof(*nbr))) == NULL) fatal("rde_nbr_new"); memcpy(nbr, new, sizeof(*nbr)); nbr->peerid = peerid; nbr->area = area; + nbr->iface = iface; TAILQ_INIT(&nbr->req_list); @@ -1335,12 +1368,13 @@ rde_summary_update(struct rt_node *rte, fatalx("rde_summary_update: unknown route type"); /* update lsa but only if it was changed */ - v = lsa_find(area, type, rte->prefix.s_addr, rde_router_id()); + v = lsa_find_area(area, type, rte->prefix.s_addr, rde_router_id()); lsa = orig_sum_lsa(rte, area, type, rte->invalid); lsa_merge(rde_nbr_self(area), lsa, v); if (v == NULL) - v = lsa_find(area, type, rte->prefix.s_addr, rde_router_id()); + v = lsa_find_area(area, type, rte->prefix.s_addr, + rde_router_id()); /* suppressed/deleted routes are not found in the second lsa_find */ if (v) Index: ospfd/rde.h =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/rde.h,v retrieving revision 1.37 diff -u -p -r1.37 rde.h --- ospfd/rde.h 2 May 2011 11:45:55 -0000 1.37 +++ ospfd/rde.h 2 May 2011 11:46:09 -0000 @@ -41,6 +41,7 @@ struct vertex { struct event ev; struct area *area; struct lsa *lsa; + struct lsa_tree *lsa_tree; time_t changed; time_t stamp; u_int32_t cost; @@ -67,9 +68,12 @@ struct rde_nbr { struct in_addr area_id; TAILQ_HEAD(, rde_req_entry) req_list; struct area *area; + struct iface *iface; u_int32_t peerid; /* unique ID in DB */ int state; - int self; + unsigned int ifindex; + u_int8_t self; + u_int8_t capa_options; }; struct rt_nexthop { @@ -133,10 +137,11 @@ int lsa_self(struct rde_nbr *, struct int lsa_add(struct rde_nbr *, struct lsa *); void lsa_del(struct rde_nbr *, struct lsa_hdr *); void lsa_age(struct vertex *); -struct vertex *lsa_find(struct area *, u_int8_t, u_int32_t, u_int32_t); +struct vertex *lsa_find(struct iface *, u_int8_t, u_int32_t, u_int32_t); +struct vertex *lsa_find_area(struct area *, u_int8_t, u_int32_t, u_int32_t); struct vertex *lsa_find_net(struct area *area, u_int32_t); u_int16_t lsa_num_links(struct vertex *); -void lsa_snap(struct area *, u_int32_t); +void lsa_snap(struct rde_nbr *); void lsa_dump(struct lsa_tree *, int, pid_t); void lsa_merge(struct rde_nbr *, struct lsa *, struct vertex *); void lsa_remove_invalid_sums(struct area *); Index: ospfd/rde_lsdb.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/rde_lsdb.c,v retrieving revision 1.46 diff -u -p -r1.46 rde_lsdb.c --- ospfd/rde_lsdb.c 2 May 2011 11:45:55 -0000 1.46 +++ ospfd/rde_lsdb.c 2 May 2011 12:01:06 -0000 @@ -27,9 +27,11 @@ #include "rde.h" #include "log.h" -struct vertex *vertex_get(struct lsa *, struct rde_nbr *); +struct vertex *vertex_get(struct lsa *, struct rde_nbr *, struct lsa_tree *); int lsa_router_check(struct lsa *, u_int16_t); +struct vertex *lsa_find_tree(struct lsa_tree *, u_int16_t, u_int32_t, + u_int32_t); void lsa_timeout(int, short, void *); void lsa_refresh(struct vertex *); int lsa_equal(struct lsa *, struct lsa *); @@ -49,20 +51,20 @@ lsa_compare(struct vertex *a, struct ver return (-1); if (a->type > b->type) return (1); - if (a->ls_id < b->ls_id) - return (-1); - if (a->ls_id > b->ls_id) - return (1); if (a->adv_rtr < b->adv_rtr) return (-1); if (a->adv_rtr > b->adv_rtr) return (1); + if (a->ls_id < b->ls_id) + return (-1); + if (a->ls_id > b->ls_id) + return (1); return (0); } struct vertex * -vertex_get(struct lsa *lsa, struct rde_nbr *nbr) +vertex_get(struct lsa *lsa, struct rde_nbr *nbr, struct lsa_tree *tree) { struct vertex *v; struct timespec tp; @@ -79,6 +81,7 @@ vertex_get(struct lsa *lsa, struct rde_n v->ls_id = ntohl(lsa->hdr.ls_id); v->adv_rtr = ntohl(lsa->hdr.adv_rtr); v->type = lsa->hdr.type; + v->lsa_tree = tree; if (!nbr->self) v->flooded = 1; /* XXX fix me */ @@ -92,10 +95,7 @@ vertex_get(struct lsa *lsa, struct rde_n void vertex_free(struct vertex *v) { - if (v->type == LSA_TYPE_EXTERNAL) - RB_REMOVE(lsa_tree, &asext_tree, v); - else - RB_REMOVE(lsa_tree, &v->area->lsa_tree, v); + RB_REMOVE(lsa_tree, v->lsa_tree, v); (void)evtimer_del(&v->ev); vertex_nexthop_clear(v); @@ -255,13 +255,24 @@ lsa_check(struct rde_nbr *nbr, struct ls if (area->stub) return (0); break; + case LSA_TYPE_LINK_OPAQ: + case LSA_TYPE_AREA_OPAQ: + case LSA_TYPE_AS_OPAQ: + if (len % sizeof(u_int32_t)) { + log_warnx("lsa_check: bad opaque LSA packet"); + return (0); + } + /* Type-11 Opaque-LSA are silently discarded in stub areas */ + if (lsa->hdr.type == LSA_TYPE_AS_OPAQ && area->stub) + return (0); + break; default: log_warnx("lsa_check: unknown type %u", lsa->hdr.type); return (0); } /* MaxAge handling */ - if (lsa->hdr.age == htons(MAX_AGE) && !nbr->self && lsa_find(area, + if (lsa->hdr.age == htons(MAX_AGE) && !nbr->self && lsa_find(nbr->iface, lsa->hdr.type, lsa->hdr.ls_id, lsa->hdr.adv_rtr) == NULL && !rde_nbr_loading(area)) { /* @@ -372,12 +383,15 @@ lsa_add(struct rde_nbr *nbr, struct lsa struct vertex *new, *old; struct timeval tv, now, res; - if (lsa->hdr.type == LSA_TYPE_EXTERNAL) + if (lsa->hdr.type == LSA_TYPE_EXTERNAL || + lsa->hdr.type == LSA_TYPE_AS_OPAQ) tree = &asext_tree; + else if (lsa->hdr.type == LSA_TYPE_LINK_OPAQ) + tree = &nbr->iface->lsa_tree; else tree = &nbr->area->lsa_tree; - new = vertex_get(lsa, nbr); + new = vertex_get(lsa, nbr, tree); old = RB_INSERT(lsa_tree, tree, new); if (old != NULL) { @@ -396,14 +410,16 @@ lsa_add(struct rde_nbr *nbr, struct lsa return (1); } if (!lsa_equal(new->lsa, old->lsa)) { - if (lsa->hdr.type != LSA_TYPE_EXTERNAL) + if (lsa->hdr.type != LSA_TYPE_EXTERNAL && + lsa->hdr.type != LSA_TYPE_AS_OPAQ) nbr->area->dirty = 1; start_spf_timer(); } vertex_free(old); RB_INSERT(lsa_tree, tree, new); } else { - if (lsa->hdr.type != LSA_TYPE_EXTERNAL) + if (lsa->hdr.type != LSA_TYPE_EXTERNAL && + lsa->hdr.type != LSA_TYPE_AS_OPAQ) nbr->area->dirty = 1; start_spf_timer(); } @@ -427,7 +443,7 @@ lsa_del(struct rde_nbr *nbr, struct lsa_ struct vertex *v; struct timeval tv; - v = lsa_find(nbr->area, lsa->type, lsa->ls_id, lsa->adv_rtr); + v = lsa_find(nbr->iface, lsa->type, lsa->ls_id, lsa->adv_rtr); if (v == NULL) return; @@ -469,21 +485,39 @@ lsa_age(struct vertex *v) } struct vertex * -lsa_find(struct area *area, u_int8_t type, u_int32_t ls_id, u_int32_t adv_rtr) +lsa_find(struct iface *iface, u_int8_t type, u_int32_t ls_id, u_int32_t adv_rtr) +{ + struct lsa_tree *tree; + + if (type == LSA_TYPE_EXTERNAL || + type == LSA_TYPE_AS_OPAQ) + tree = &asext_tree; + else if (type == LSA_TYPE_LINK_OPAQ) + tree = &iface->lsa_tree; + else + tree = &iface->area->lsa_tree; + + return lsa_find_tree(tree, type, ls_id, adv_rtr); +} + +struct vertex * +lsa_find_area(struct area *area, u_int8_t type, u_int32_t ls_id, + u_int32_t adv_rtr) +{ + return lsa_find_tree(&area->lsa_tree, type, ls_id, adv_rtr); +} + +struct vertex * +lsa_find_tree(struct lsa_tree *tree, u_int16_t type, u_int32_t ls_id, + u_int32_t adv_rtr) { struct vertex key; struct vertex *v; - struct lsa_tree *tree; key.ls_id = ntohl(ls_id); key.adv_rtr = ntohl(adv_rtr); key.type = type; - if (type == LSA_TYPE_EXTERNAL) - tree = &asext_tree; - else - tree = &area->lsa_tree; - v = RB_FIND(lsa_tree, tree, &key); /* LSA that are deleted are not findable */ @@ -532,26 +566,40 @@ lsa_num_links(struct vertex *v) } void -lsa_snap(struct area *area, u_int32_t peerid) +lsa_snap(struct rde_nbr *nbr) { - struct lsa_tree *tree = &area->lsa_tree; + struct lsa_tree *tree = &nbr->area->lsa_tree; struct vertex *v; do { RB_FOREACH(v, lsa_tree, tree) { if (v->deleted) continue; + switch (v->type) { + case LSA_TYPE_LINK_OPAQ: + case LSA_TYPE_AREA_OPAQ: + case LSA_TYPE_AS_OPAQ: + if (nbr->capa_options & OSPF_OPTION_O) + break; + continue; + } lsa_age(v); if (ntohs(v->lsa->hdr.age) >= MAX_AGE) - rde_imsg_compose_ospfe(IMSG_LS_UPD, peerid, + rde_imsg_compose_ospfe(IMSG_LS_UPD, nbr->peerid, 0, &v->lsa->hdr, ntohs(v->lsa->hdr.len)); else - rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT, peerid, - 0, &v->lsa->hdr, sizeof(struct lsa_hdr)); + rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT, + nbr->peerid, 0, &v->lsa->hdr, + sizeof(struct lsa_hdr)); } - if (tree != &area->lsa_tree || area->stub) + if (tree == &asext_tree) break; - tree = &asext_tree; + if (tree == &nbr->area->lsa_tree) + tree = &nbr->iface->lsa_tree; + else if (nbr->area->stub) + break; + else + tree = &asext_tree; } while (1); } @@ -566,9 +614,7 @@ lsa_dump(struct lsa_tree *tree, int imsg lsa_age(v); switch (imsg_type) { case IMSG_CTL_SHOW_DATABASE: - rde_imsg_compose_ospfe(IMSG_CTL_SHOW_DATABASE, 0, pid, - &v->lsa->hdr, ntohs(v->lsa->hdr.len)); - continue; + break; case IMSG_CTL_SHOW_DB_SELF: if (v->lsa->hdr.adv_rtr == rde_router_id()) break; @@ -593,6 +639,12 @@ lsa_dump(struct lsa_tree *tree, int imsg if (v->type == LSA_TYPE_SUM_ROUTER) break; continue; + case IMSG_CTL_SHOW_DB_OPAQ: + if (v->type == LSA_TYPE_LINK_OPAQ || + v->type == LSA_TYPE_AREA_OPAQ || + v->type == LSA_TYPE_AS_OPAQ) + break; + continue; default: log_warnx("lsa_dump: unknown imsg type"); return; @@ -618,7 +670,8 @@ lsa_timeout(int fd, short event, void *b v->deleted = 0; /* schedule recalculation of the RIB */ - if (v->lsa->hdr.type != LSA_TYPE_EXTERNAL) + if (v->type != LSA_TYPE_EXTERNAL && + v->type != LSA_TYPE_AS_OPAQ) v->area->dirty = 1; start_spf_timer(); @@ -713,7 +766,8 @@ lsa_merge(struct rde_nbr *nbr, struct ls free(v->lsa); v->lsa = lsa; start_spf_timer(); - if (v->type != LSA_TYPE_EXTERNAL) + if (v->type != LSA_TYPE_EXTERNAL && + v->type != LSA_TYPE_AS_OPAQ) nbr->area->dirty = 1; /* set correct timeout for reflooding the LSA */ @@ -774,13 +828,13 @@ lsa_generate_stub_sums(struct area *area rn.cost = r->metric & LSA_METRIC_MASK; /* update lsa but only if it was changed */ - v = lsa_find(area, LSA_TYPE_SUM_NETWORK, + v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK, rn.prefix.s_addr, rde_router_id()); lsa = orig_sum_lsa(&rn, area, LSA_TYPE_SUM_NETWORK, 0); lsa_merge(rde_nbr_self(area), lsa, v); if (v == NULL) - v = lsa_find(area, LSA_TYPE_SUM_NETWORK, + v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK, rn.prefix.s_addr, rde_router_id()); /* @@ -817,4 +871,3 @@ lsa_equal(struct lsa *a, struct lsa *b) return (1); } - Index: ospfd/rde_spf.c =================================================================== RCS file: /cvs/src/usr.sbin/ospfd/rde_spf.c,v retrieving revision 1.71 diff -u -p -r1.71 rde_spf.c --- ospfd/rde_spf.c 2 May 2011 11:45:55 -0000 1.71 +++ ospfd/rde_spf.c 2 May 2011 11:46:54 -0000 @@ -63,8 +63,8 @@ spf_calc(struct area *area) cand_list_clr(); /* initialize SPF tree */ - if ((v = spf_root = lsa_find(area, LSA_TYPE_ROUTER, rde_router_id(), - rde_router_id())) == NULL) + if ((v = spf_root = lsa_find_area(area, LSA_TYPE_ROUTER, + rde_router_id(), rde_router_id())) == NULL) /* empty area because no interface is active */ return; @@ -86,7 +86,7 @@ spf_calc(struct area *area) case LINK_TYPE_POINTTOPOINT: case LINK_TYPE_VIRTUAL: /* find router LSA */ - w = lsa_find(area, LSA_TYPE_ROUTER, + w = lsa_find_area(area, LSA_TYPE_ROUTER, rtr_link->id, rtr_link->id); break; case LINK_TYPE_TRANSIT_NET: @@ -100,7 +100,7 @@ spf_calc(struct area *area) case LSA_TYPE_NETWORK: net_link = get_net_link(v, i); /* find router LSA */ - w = lsa_find(area, LSA_TYPE_ROUTER, + w = lsa_find_area(area, LSA_TYPE_ROUTER, net_link->att_rtr, net_link->att_rtr); break; default: @@ -231,7 +231,7 @@ rt_calc(struct vertex *v, struct area *a /* TODO type 3 area address range check */ - if ((w = lsa_find(area, LSA_TYPE_ROUTER, + if ((w = lsa_find_area(area, LSA_TYPE_ROUTER, htonl(v->adv_rtr), htonl(v->adv_rtr))) == NULL) return;