From bc6e1915003b00c70fc586aa340f61bd00ac67d4 Mon Sep 17 00:00:00 2001 From: renato Date: Wed, 21 Oct 2015 03:52:12 +0000 Subject: [PATCH] Add support for route summarization. Working great but need more testing, especially with ipv6. For now we don't validate if one configured summary is inside another or the presence of duplicates. Will address these issues in a future commit. --- usr.sbin/eigrpd/eigrpd.c | 3 +- usr.sbin/eigrpd/eigrpd.h | 12 +++++++- usr.sbin/eigrpd/eigrpe.c | 3 +- usr.sbin/eigrpd/interface.c | 9 +++++- usr.sbin/eigrpd/kroute.c | 5 ++-- usr.sbin/eigrpd/parse.y | 28 ++++++++++++++++++- usr.sbin/eigrpd/printconf.c | 8 +++++- usr.sbin/eigrpd/rde.c | 22 +++++++++++++-- usr.sbin/eigrpd/rde.h | 6 +++- usr.sbin/eigrpd/rde_dual.c | 56 +++++++++++++++++++++++++++++-------- usr.sbin/eigrpd/util.c | 43 +++++++++++++++++++++++++++- 11 files changed, 171 insertions(+), 24 deletions(-) diff --git a/usr.sbin/eigrpd/eigrpd.c b/usr.sbin/eigrpd/eigrpd.c index 64658969337..559bf056214 100644 --- a/usr.sbin/eigrpd/eigrpd.c +++ b/usr.sbin/eigrpd/eigrpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eigrpd.c,v 1.2 2015/10/10 05:12:33 renato Exp $ */ +/* $OpenBSD: eigrpd.c,v 1.3 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -590,6 +590,7 @@ merge_config(struct eigrpd_conf *conf, struct eigrpd_conf *xconf) conf->rdomain= xconf->rdomain; conf->fib_priority_internal = xconf->fib_priority_internal; conf->fib_priority_external = xconf->fib_priority_external; + conf->fib_priority_summary = xconf->fib_priority_summary; /* merge instances */ TAILQ_FOREACH_SAFE(eigrp, &conf->instances, entry, etmp) { diff --git a/usr.sbin/eigrpd/eigrpd.h b/usr.sbin/eigrpd/eigrpd.h index e9b52ab44bb..473501b8cf0 100644 --- a/usr.sbin/eigrpd/eigrpd.h +++ b/usr.sbin/eigrpd/eigrpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eigrpd.h,v 1.4 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: eigrpd.h,v 1.5 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -176,6 +176,12 @@ TAILQ_HEAD(rinfo_head, rinfo_entry); #define IF_STA_DOWN 0x01 #define IF_STA_ACTIVE 0x02 +struct summary_addr { + TAILQ_ENTRY(summary_addr) entry; + union eigrpd_addr prefix; + uint8_t prefixlen; +}; + struct eigrp_iface { RB_ENTRY(eigrp_iface) id_tree; TAILQ_ENTRY(eigrp_iface) e_entry; @@ -196,6 +202,7 @@ struct eigrp_iface { struct nbr *self; struct rinfo_head update_list; /* multicast updates */ struct rinfo_head query_list; /* multicast queries */ + TAILQ_HEAD(, summary_addr) summary_list; }; #define INADDRSZ 4 @@ -289,6 +296,7 @@ struct eigrpd_conf { unsigned int rdomain; uint8_t fib_priority_internal; uint8_t fib_priority_external; + uint8_t fib_priority_summary; TAILQ_HEAD(, iface) iface_list; TAILQ_HEAD(, eigrp) instances; char *csock; @@ -424,6 +432,8 @@ void eigrp_applymask(int, union eigrpd_addr *, const union eigrpd_addr *, int); int eigrp_addrcmp(int, union eigrpd_addr *, union eigrpd_addr *); int eigrp_addrisset(int, union eigrpd_addr *); +int eigrp_prefixcmp(int, const union eigrpd_addr *, + const union eigrpd_addr *, uint8_t); void embedscope(struct sockaddr_in6 *); void recoverscope(struct sockaddr_in6 *); void addscope(struct sockaddr_in6 *, uint32_t); diff --git a/usr.sbin/eigrpd/eigrpe.c b/usr.sbin/eigrpd/eigrpe.c index eb515a7dc23..0aae0686767 100644 --- a/usr.sbin/eigrpd/eigrpe.c +++ b/usr.sbin/eigrpd/eigrpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eigrpe.c,v 1.5 2015/10/10 05:12:33 renato Exp $ */ +/* $OpenBSD: eigrpe.c,v 1.6 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -373,6 +373,7 @@ eigrpe_dispatch_main(int fd, short event, void *bula) TAILQ_INIT(&nei->nbr_list); TAILQ_INIT(&nei->update_list); TAILQ_INIT(&nei->query_list); + TAILQ_INIT(&nei->summary_list); TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry); TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry); if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) != diff --git a/usr.sbin/eigrpd/interface.c b/usr.sbin/eigrpd/interface.c index 824d96c8f6c..b2d7260cc62 100644 --- a/usr.sbin/eigrpd/interface.c +++ b/usr.sbin/eigrpd/interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: interface.c,v 1.7 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: interface.c,v 1.8 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -298,6 +298,7 @@ eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif) TAILQ_INIT(&ei->nbr_list); TAILQ_INIT(&ei->update_list); TAILQ_INIT(&ei->query_list); + TAILQ_INIT(&ei->summary_list); TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry); TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry); if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL) @@ -309,9 +310,15 @@ eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif) void eigrp_if_del(struct eigrp_iface *ei) { + struct summary_addr *summary; + RB_REMOVE(iface_id_head, &ifaces_by_id, ei); TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry); TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry); + while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) { + TAILQ_REMOVE(&ei->summary_list, summary, entry); + free(summary); + } message_list_clr(&ei->query_list); message_list_clr(&ei->update_list); diff --git a/usr.sbin/eigrpd/kroute.c b/usr.sbin/eigrpd/kroute.c index e1b879d595d..869745f2c1f 100644 --- a/usr.sbin/eigrpd/kroute.c +++ b/usr.sbin/eigrpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.2 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: kroute.c,v 1.3 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -1564,7 +1564,8 @@ rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX]) } if (kr.priority == eigrpd_conf->fib_priority_internal || - kr.priority == eigrpd_conf->fib_priority_external) { + kr.priority == eigrpd_conf->fib_priority_external || + kr.priority == eigrpd_conf->fib_priority_summary) { log_warnx("alien EIGRP route %s/%d", log_addr(kr.af, &kr.prefix), kr.prefixlen); return (send_rtmsg(kr_state.fd, RTM_DELETE, &kr)); diff --git a/usr.sbin/eigrpd/parse.y b/usr.sbin/eigrpd/parse.y index 99b6903423c..6e0e2d51bbd 100644 --- a/usr.sbin/eigrpd/parse.y +++ b/usr.sbin/eigrpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.3 2015/10/19 14:15:59 jsg Exp $ */ +/* $OpenBSD: parse.y,v 1.4 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -125,6 +125,7 @@ typedef struct { %token ROUTERID AS FIBUPDATE RDOMAIN REDISTRIBUTE METRIC DFLTMETRIC %token MAXHOPS MAXPATHS VARIANCE FIBPRIORITY_INT FIBPRIORITY_EXT +%token FIBPRIORITY_SUMM SUMMARY_ADDR %token AF IPV4 IPV6 HELLOINTERVAL HOLDTIME KVALUES ACTIVETIMEOUT %token INTERFACE PASSIVE DELAY BANDWIDTH SPLITHORIZON %token YES NO @@ -234,6 +235,13 @@ conf_main : ROUTERID STRING { } conf->fib_priority_external = $2; } + | FIBPRIORITY_SUMM NUMBER { + if ($2 <= RTP_NONE || $2 > RTP_MAX) { + yyerror("invalid fib-priority"); + YYERROR; + } + conf->fib_priority_summary = $2; + } | defaults ; @@ -522,6 +530,21 @@ interfaceopts_l : interfaceopts_l interfaceoptsl nl ; interfaceoptsl : PASSIVE { ei->passive = 1; } + | SUMMARY_ADDR STRING { + struct summary_addr *s; + + if ((s = calloc(1, sizeof(*s))) == NULL) + fatal(NULL); + if (host($2, &s->prefix, &s->prefixlen) < 0) { + yyerror("invalid summary-address"); + free($2); + free(s); + YYERROR; + } + + free($2); + TAILQ_INSERT_TAIL(&ei->summary_list, s, entry); + } | iface_defaults ; @@ -567,6 +590,7 @@ lookup(char *s) {"delay", DELAY}, {"fib-priority-external", FIBPRIORITY_EXT}, {"fib-priority-internal", FIBPRIORITY_INT}, + {"fib-priority-summary", FIBPRIORITY_SUMM}, {"fib-update", FIBUPDATE}, {"hello-interval", HELLOINTERVAL}, {"holdtime", HOLDTIME}, @@ -584,6 +608,7 @@ lookup(char *s) {"redistribute", REDISTRIBUTE}, {"router-id", ROUTERID}, {"split-horizon", SPLITHORIZON}, + {"summary-address", SUMMARY_ADDR}, {"variance", VARIANCE}, {"yes", YES} }; @@ -919,6 +944,7 @@ parse_config(char *filename, int opts) conf->rdomain = 0; conf->fib_priority_internal = RTP_EIGRP; conf->fib_priority_external = RTP_EIGRP; + conf->fib_priority_summary = RTP_EIGRP; memset(&globaldefs, 0, sizeof(globaldefs)); defs = &globaldefs; diff --git a/usr.sbin/eigrpd/printconf.c b/usr.sbin/eigrpd/printconf.c index 5d9ad72845b..a5eb6fd0359 100644 --- a/usr.sbin/eigrpd/printconf.c +++ b/usr.sbin/eigrpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.2 2015/10/04 22:54:38 renato Exp $ */ +/* $OpenBSD: printconf.c,v 1.3 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -45,6 +45,7 @@ print_mainconf(struct eigrpd_conf *conf) printf("rdomain %u\n", conf->rdomain); printf("fib-priority-internal %u\n", conf->fib_priority_internal); printf("fib-priority-external %u\n", conf->fib_priority_external); + printf("fib-priority-summary %u\n", conf->fib_priority_summary); } const char * @@ -108,6 +109,8 @@ print_redistribute(struct eigrp *eigrp) void print_iface(struct eigrp_iface *ei) { + struct summary_addr *summary; + printf("\t\tinterface %s {\n", ei->iface->name); printf("\t\t\thello-interval %u\n", ei->hello_interval); printf("\t\t\tholdtime %u\n", ei->hello_holdtime); @@ -116,6 +119,9 @@ print_iface(struct eigrp_iface *ei) printf("\t\t\tsplit-horizon %s\n", (ei->splithorizon) ? "yes" : "no"); if (ei->passive) printf("\t\t\tpassive\n"); + TAILQ_FOREACH(summary, &ei->summary_list, entry) + printf("\t\t\tsummary-address %s/%u\n", log_addr(ei->eigrp->af, + &summary->prefix), summary->prefixlen); printf("\t\t}\n"); } diff --git a/usr.sbin/eigrpd/rde.c b/usr.sbin/eigrpd/rde.c index d20d29821d2..c9dbdd97822 100644 --- a/usr.sbin/eigrpd/rde.c +++ b/usr.sbin/eigrpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.5 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: rde.c,v 1.6 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -422,6 +422,7 @@ rde_dispatch_parent(int fd, short event, void *bula) TAILQ_INIT(&nei->nbr_list); TAILQ_INIT(&nei->update_list); TAILQ_INIT(&nei->query_list); + TAILQ_INIT(&nei->summary_list); TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry); TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry); if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) != @@ -665,6 +666,22 @@ rt_redist_set(struct kroute *kr, int withdraw) } } +void +rt_summary_set(struct eigrp *eigrp, struct summary_addr *summary, + struct classic_metric *metric) +{ + struct rinfo ri; + + memset(&ri, 0, sizeof(ri)); + ri.af = eigrp->af; + ri.type = EIGRP_ROUTE_INTERNAL; + memcpy(&ri.prefix, &summary->prefix, sizeof(ri.prefix)); + ri.prefixlen = summary->prefixlen; + memcpy(&ri.metric, metric, sizeof(ri.metric)); + + rde_check_update(eigrp->rnbr_summary, &ri); +} + /* send all known routing information to new neighbor */ void rt_snap(struct rde_nbr *nbr) @@ -674,7 +691,8 @@ rt_snap(struct rde_nbr *nbr) struct rinfo ri; RB_FOREACH(rn, rt_tree, &eigrp->topology) - if (rn->state == DUAL_STA_PASSIVE) { + if (rn->state == DUAL_STA_PASSIVE && + !rde_summary_check(nbr->ei, &rn->prefix, rn->prefixlen)) { rinfo_fill_successor(rn, &ri); rde_imsg_compose_eigrpe(IMSG_SEND_UPDATE, nbr->peerid, 0, &ri, sizeof(ri)); diff --git a/usr.sbin/eigrpd/rde.h b/usr.sbin/eigrpd/rde.h index a010f0ae38e..7235bdeae9c 100644 --- a/usr.sbin/eigrpd/rde.h +++ b/usr.sbin/eigrpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.3 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: rde.h,v 1.4 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -133,6 +133,8 @@ void rde_instance_del(struct eigrp *); void rde_send_change_kroute(struct rt_node *, struct eigrp_route *); void rde_send_delete_kroute(struct rt_node *, struct eigrp_route *); void rt_redist_set(struct kroute *, int); +void rt_summary_set(struct eigrp *, struct summary_addr *, + struct classic_metric *); void rt_snap(struct rde_nbr *); struct ctl_rt *rt_to_ctl(struct rt_node *, struct eigrp_route *); void rt_dump(struct ctl_show_topology_req *, pid_t); @@ -171,6 +173,8 @@ void rt_set_successor(struct rt_node *, struct eigrp_route *); struct eigrp_route *rt_get_successor_fc(struct rt_node *); +struct summary_addr *rde_summary_check(struct eigrp_iface *, + union eigrpd_addr *, uint8_t); void rde_send_update(struct eigrp_iface *, struct rinfo *); void rde_send_update_all(struct rt_node *, struct rinfo *); void rde_send_query(struct eigrp_iface *, struct rinfo *, diff --git a/usr.sbin/eigrpd/rde_dual.c b/usr.sbin/eigrpd/rde_dual.c index ad7e32b584b..d9a6de14d9b 100644 --- a/usr.sbin/eigrpd/rde_dual.c +++ b/usr.sbin/eigrpd/rde_dual.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_dual.c,v 1.6 2015/10/21 03:48:09 renato Exp $ */ +/* $OpenBSD: rde_dual.c,v 1.7 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -613,6 +613,10 @@ uninstall: void rt_set_successor(struct rt_node *rn, struct eigrp_route *successor) { + struct eigrp *eigrp = rn->eigrp; + struct eigrp_iface *ei; + struct summary_addr *summary; + if (successor == NULL) { rn->successor.nbr = NULL; rn->successor.type = 0; @@ -622,17 +626,22 @@ rt_set_successor(struct rt_node *rn, struct eigrp_route *successor) sizeof(rn->successor.metric)); memset(&rn->successor.emetric, 0, sizeof(rn->successor.emetric)); - return; + } else { + rn->successor.nbr = successor->nbr; + rn->successor.type = successor->type; + rn->successor.fdistance = successor->distance; + rn->successor.rdistance = successor->rdistance; + memcpy(&rn->successor.metric, &successor->metric, + sizeof(rn->successor.metric)); + memcpy(&rn->successor.emetric, &successor->emetric, + sizeof(rn->successor.emetric)); } - rn->successor.nbr = successor->nbr; - rn->successor.type = successor->type; - rn->successor.fdistance = successor->distance; - rn->successor.rdistance = successor->rdistance; - memcpy(&rn->successor.metric, &successor->metric, - sizeof(rn->successor.metric)); - memcpy(&rn->successor.emetric, &successor->emetric, - sizeof(rn->successor.emetric)); + TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) { + summary = rde_summary_check(ei, &rn->prefix, rn->prefixlen); + if (summary) + rt_summary_set(eigrp, summary, &rn->successor.metric); + } } struct eigrp_route * @@ -674,10 +683,32 @@ rt_get_successor_fc(struct rt_node *rn) return (successor); } +struct summary_addr * +rde_summary_check(struct eigrp_iface *ei, union eigrpd_addr *prefix, + uint8_t prefixlen) +{ + struct summary_addr *summary; + + TAILQ_FOREACH(summary, &ei->summary_list, entry) { + /* do not filter the summary itself */ + if (summary->prefixlen == prefixlen && + !eigrp_addrcmp(ei->eigrp->af, prefix, &summary->prefix)) + return (NULL); + + if (summary->prefixlen <= prefixlen && + !eigrp_prefixcmp(ei->eigrp->af, prefix, &summary->prefix, + summary->prefixlen)) + return (summary); + } + + return (NULL); +} + void rde_send_update(struct eigrp_iface *ei, struct rinfo *ri) { - if (ri->metric.hop_count >= ei->eigrp->maximum_hops) + if (ri->metric.hop_count >= ei->eigrp->maximum_hops || + rde_summary_check(ei, &ri->prefix, ri->prefixlen)) ri->metric.delay = EIGRP_INFINITE_METRIC; rde_imsg_compose_eigrpe(IMSG_SEND_MUPDATE, ei->ifaceid, 0, @@ -768,7 +799,8 @@ rde_send_reply(struct rde_nbr *nbr, struct rinfo *ri, int siareply) { int type; - if (ri->metric.hop_count >= nbr->eigrp->maximum_hops) + if (ri->metric.hop_count >= nbr->eigrp->maximum_hops || + rde_summary_check(nbr->ei, &ri->prefix, ri->prefixlen)) ri->metric.delay = EIGRP_INFINITE_METRIC; if (!siareply) diff --git a/usr.sbin/eigrpd/util.c b/usr.sbin/eigrpd/util.c index 844b1565296..61b19652a38 100644 --- a/usr.sbin/eigrpd/util.c +++ b/usr.sbin/eigrpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.2 2015/10/04 23:00:10 renato Exp $ */ +/* $OpenBSD: util.c,v 1.3 2015/10/21 03:52:12 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -175,6 +175,47 @@ eigrp_addrisset(int af, union eigrpd_addr *addr) return (0); } +int +eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b, + uint8_t prefixlen) +{ + in_addr_t mask, aa, ba; + int i; + uint8_t m; + + switch (af) { + case AF_INET: + if (prefixlen == 0) + return (0); + if (prefixlen > 32) + fatalx("eigrp_prefixcmp: bad IPv4 prefixlen"); + mask = htonl(prefixlen2mask(prefixlen)); + aa = htonl(a->v4.s_addr) & mask; + ba = htonl(b->v4.s_addr) & mask; + return (aa - ba); + case AF_INET6: + if (prefixlen == 0) + return (0); + if (prefixlen > 128) + fatalx("eigrp_prefixcmp: bad IPv6 prefixlen"); + for (i = 0; i < prefixlen / 8; i++) + if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) + return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); + i = prefixlen % 8; + if (i) { + m = 0xff00 >> i; + if ((a->v6.s6_addr[prefixlen / 8] & m) != + (b->v6.s6_addr[prefixlen / 8] & m)) + return ((a->v6.s6_addr[prefixlen / 8] & m) - + (b->v6.s6_addr[prefixlen / 8] & m)); + } + return (0); + default: + fatalx("eigrp_prefixcmp: unknown af"); + } + return (-1); +} + #define IN6_IS_SCOPE_EMBED(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \ -- 2.20.1