Add support for route summarization.
authorrenato <renato@openbsd.org>
Wed, 21 Oct 2015 03:52:12 +0000 (03:52 +0000)
committerrenato <renato@openbsd.org>
Wed, 21 Oct 2015 03:52:12 +0000 (03:52 +0000)
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
usr.sbin/eigrpd/eigrpd.h
usr.sbin/eigrpd/eigrpe.c
usr.sbin/eigrpd/interface.c
usr.sbin/eigrpd/kroute.c
usr.sbin/eigrpd/parse.y
usr.sbin/eigrpd/printconf.c
usr.sbin/eigrpd/rde.c
usr.sbin/eigrpd/rde.h
usr.sbin/eigrpd/rde_dual.c
usr.sbin/eigrpd/util.c

index 6465896..559bf05 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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) {
index e9b52ab..473501b 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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);
index eb515a7..0aae068 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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) !=
index 824d96c..b2d7260 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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);
 
index e1b879d..869745f 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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));
index 99b6903..6e0e2d5 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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;
index 5d9ad72..a5eb6fd 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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");
 }
 
index d20d298..c9dbdd9 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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));
index a010f0a..7235bde 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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 *,
index ad7e32b..d9a6de1 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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)
index 844b156..61b1965 100644 (file)
@@ -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 <renato@openbsd.org>
@@ -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)) || \