On Fri, Dec 18, 2020 at 11:36:33AM +0100, Claudio Jeker wrote:
> In preparation for RTR support this diff changes the internal
> representation of roa-set to a simple RB tree based on struct roa.
> The big difference is that overlapping roas, e.g.
>         10/8 source-as 3
>         10/8 maxlen 24 source-as 3
> are now merged in the RDE and so bgpd -nv will show both entries instead
> of only the second one.
> 
> On my testbox there is no difference in OVS state between a -current bgpd
> and the one with this diff applied. More testing welcome.

Ping. I would like to get this in so I can reduce the size of my RTR work
in progress diff.

-- 
:wq Claudio

Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
retrieving revision 1.230
diff -u -p -r1.230 bgpd.c
--- bgpd.c      5 Nov 2020 11:52:59 -0000       1.230
+++ bgpd.c      18 Dec 2020 10:27:44 -0000
@@ -502,6 +502,7 @@ send_config(struct bgpd_config *conf)
        struct as_set           *aset;
        struct prefixset        *ps;
        struct prefixset_item   *psi, *npsi;
+       struct roa              *roa, *nroa;
 
        reconfpending = 2;      /* one per child */
 
@@ -567,7 +568,6 @@ send_config(struct bgpd_config *conf)
                        if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
                            0, 0, -1, psi, sizeof(*psi)) == -1)
                                return (-1);
-                       set_free(psi->set);
                        free(psi);
                }
                free(ps);
@@ -579,23 +579,12 @@ send_config(struct bgpd_config *conf)
                if (imsg_compose(ibuf_rde, IMSG_RECONF_ORIGIN_SET, 0, 0, -1,
                    ps->name, sizeof(ps->name)) == -1)
                        return (-1);
-               RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
-                       struct roa_set *rs;
-                       size_t i, l, n;
-                       RB_REMOVE(prefixset_tree, &ps->psitems, psi);
-                       rs = set_get(psi->set, &n);
-                       for (i = 0; i < n; i += l) {
-                               l = (n - i > 1024 ? 1024 : n - i);
-                               if (imsg_compose(ibuf_rde,
-                                   IMSG_RECONF_ROA_SET_ITEMS,
-                                   0, 0, -1, rs + i, l * sizeof(*rs)) == -1)
-                                       return -1;
-                       }
-                       if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
-                           0, 0, -1, psi, sizeof(*psi)) == -1)
+               RB_FOREACH_SAFE(roa, roa_tree, &ps->roaitems, nroa) {
+                       RB_REMOVE(roa_tree, &conf->roa, roa);
+                       if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0,
+                           -1, roa, sizeof(*roa)) == -1)
                                return (-1);
-                       set_free(psi->set);
-                       free(psi);
+                       free(roa);
                }
                free(ps);
        }
@@ -604,23 +593,12 @@ send_config(struct bgpd_config *conf)
                if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1,
                    NULL, 0) == -1)
                        return (-1);
-               RB_FOREACH_SAFE(psi, prefixset_tree, &conf->roa, npsi) {
-                       struct roa_set *rs;
-                       size_t i, l, n;
-                       RB_REMOVE(prefixset_tree, &conf->roa, psi);
-                       rs = set_get(psi->set, &n);
-                       for (i = 0; i < n; i += l) {
-                               l = (n - i > 1024 ? 1024 : n - i);
-                               if (imsg_compose(ibuf_rde,
-                                   IMSG_RECONF_ROA_SET_ITEMS,
-                                   0, 0, -1, rs + i, l * sizeof(*rs)) == -1)
-                                       return -1;
-                       }
-                       if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
-                           0, 0, -1, psi, sizeof(*psi)) == -1)
+               RB_FOREACH_SAFE(roa, roa_tree, &conf->roa, nroa) {
+                       RB_REMOVE(roa_tree, &conf->roa, roa);
+                       if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0,
+                           -1, roa, sizeof(*roa)) == -1)
                                return (-1);
-                       set_free(psi->set);
-                       free(psi);
+                       free(roa);
                }
        }
 
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.405
diff -u -p -r1.405 bgpd.h
--- bgpd.h      5 Nov 2020 11:52:59 -0000       1.405
+++ bgpd.h      18 Dec 2020 10:27:21 -0000
@@ -264,6 +264,21 @@ struct rde_prefixset {
 };
 SIMPLEQ_HEAD(rde_prefixset_head, rde_prefixset);
 
+struct roa {
+       RB_ENTRY(roa)   entry;
+       uint8_t         aid;
+       uint8_t         prefixlen;
+       uint8_t         maxlen;
+       uint8_t         pad;
+       uint32_t        asnum;
+       union {
+               struct in_addr  inet;
+               struct in6_addr inet6;
+       }               prefix;
+};
+
+RB_HEAD(roa_tree, roa);
+
 struct set_table;
 struct as_set;
 SIMPLEQ_HEAD(as_set_head, as_set);
@@ -280,7 +295,7 @@ struct bgpd_config {
        struct mrt_head                         *mrt;
        struct prefixset_head                    prefixsets;
        struct prefixset_head                    originsets;
-       struct prefixset_tree                    roa;
+       struct roa_tree                          roa;
        struct rde_prefixset_head                rde_prefixsets;
        struct rde_prefixset_head                rde_originsets;
        struct rde_prefixset                     rde_roa;
@@ -492,7 +507,7 @@ enum imsg_type {
        IMSG_RECONF_AS_SET_DONE,
        IMSG_RECONF_ORIGIN_SET,
        IMSG_RECONF_ROA_SET,
-       IMSG_RECONF_ROA_SET_ITEMS,
+       IMSG_RECONF_ROA_ITEM,
        IMSG_RECONF_DRAIN,
        IMSG_RECONF_DONE,
        IMSG_UPDATE,
@@ -1035,13 +1050,13 @@ struct roa_set {
 struct prefixset_item {
        struct filter_prefix            p;
        RB_ENTRY(prefixset_item)        entry;
-       struct set_table                *set;
 };
 
 struct prefixset {
        int                              sflags;
        char                             name[SET_NAME_LEN];
        struct prefixset_tree            psitems;
+       struct roa_tree                  roaitems;
        SIMPLEQ_ENTRY(prefixset)         entry;
 };
 
@@ -1181,12 +1196,13 @@ void            free_config(struct bgpd_config *);
 void           free_prefixsets(struct prefixset_head *);
 void           free_rde_prefixsets(struct rde_prefixset_head *);
 void           free_prefixtree(struct prefixset_tree *);
+void           free_roatree(struct roa_tree *);
 void           filterlist_free(struct filter_head *);
 int            host(const char *, struct bgpd_addr *, u_int8_t *);
 u_int32_t      get_bgpid(void);
 void           expand_networks(struct bgpd_config *);
-int            prefixset_cmp(struct prefixset_item *, struct prefixset_item *);
 RB_PROTOTYPE(prefixset_tree, prefixset_item, entry, prefixset_cmp);
+RB_PROTOTYPE(roa_tree, roa, entry, roa_cmp);
 
 /* kroute.c */
 int             kr_init(int *);
@@ -1287,8 +1303,7 @@ int                        set_equal(const struct 
set_table 
 /* rde_trie.c */
 int    trie_add(struct trie_head *, struct bgpd_addr *, u_int8_t, u_int8_t,
            u_int8_t);
-int    trie_roa_add(struct trie_head *, struct bgpd_addr *, u_int8_t,
-           struct set_table *);
+int    trie_roa_add(struct trie_head *, struct roa *);
 void   trie_free(struct trie_head *);
 int    trie_match(struct trie_head *, struct bgpd_addr *, u_int8_t, int);
 int    trie_roa_check(struct trie_head *, struct bgpd_addr *, u_int8_t,
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
retrieving revision 1.95
diff -u -p -r1.95 config.c
--- config.c    14 Feb 2020 13:54:31 -0000      1.95
+++ config.c    18 Dec 2020 10:28:00 -0000
@@ -117,6 +117,7 @@ free_prefixsets(struct prefixset_head *p
 
        while (!SIMPLEQ_EMPTY(psh)) {
                ps = SIMPLEQ_FIRST(psh);
+               free_roatree(&ps->roaitems);
                free_prefixtree(&ps->psitems);
                SIMPLEQ_REMOVE_HEAD(psh, entry);
                free(ps);
@@ -146,12 +147,22 @@ free_prefixtree(struct prefixset_tree *p
 
        RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) {
                RB_REMOVE(prefixset_tree, p, psi);
-               set_free(psi->set);
                free(psi);
        }
 }
 
 void
+free_roatree(struct roa_tree *r)
+{
+       struct roa      *roa, *nroa;
+
+       RB_FOREACH_SAFE(roa, roa_tree, r, nroa) {
+               RB_REMOVE(roa_tree, r, roa);
+               free(roa);
+       }
+}
+
+void
 free_config(struct bgpd_config *conf)
 {
        struct peer             *p, *next;
@@ -166,7 +177,7 @@ free_config(struct bgpd_config *conf)
        free_rde_prefixsets(&conf->rde_prefixsets);
        free_rde_prefixsets(&conf->rde_originsets);
        as_sets_free(&conf->as_sets);
-       free_prefixtree(&conf->roa);
+       free_roatree(&conf->roa);
 
        while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
                TAILQ_REMOVE(conf->listen_addrs, la, entry);
@@ -230,7 +241,7 @@ merge_config(struct bgpd_config *xconf, 
        mrt_mergeconfig(xconf->mrt, conf->mrt);
 
        /* switch the roa, first remove the old one */
-       free_prefixtree(&xconf->roa);
+       free_roatree(&xconf->roa);
        /* then move the RB tree root */
        RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa);
        RB_ROOT(&conf->roa) = NULL;
@@ -527,7 +538,7 @@ expand_networks(struct bgpd_config *c)
        }
 }
 
-int
+static inline int
 prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b)
 {
        int i;
@@ -571,3 +582,20 @@ prefixset_cmp(struct prefixset_item *a, 
 }
 
 RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp);
+
+static inline int
+roa_cmp(struct roa *a, struct roa *b)
+{
+       size_t len = 4 + sizeof(a->asnum);
+
+       if (a->aid == b->aid) {
+               if (a->aid == AID_INET)
+                       len += sizeof(a->prefix.inet);
+               else
+                       len += sizeof(a->prefix.inet6);
+       }
+
+       return memcmp(&a->aid, &b->aid, len);
+}
+
+RB_GENERATE(roa_tree, roa, entry, roa_cmp);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.410
diff -u -p -r1.410 parse.y
--- parse.y     27 Oct 2020 19:13:34 -0000      1.410
+++ parse.y     18 Dec 2020 08:40:44 -0000
@@ -94,7 +94,7 @@ static struct peer            *curgroup;
 static struct rde_rib          *currib;
 static struct l3vpn            *curvpn;
 static struct prefixset                *curpset, *curoset;
-static struct prefixset_tree   *curpsitree;
+static struct roa_tree         *curroatree;
 static struct filter_head      *filter_l;
 static struct filter_head      *peerfilter_l;
 static struct filter_head      *groupfilter_l;
@@ -498,9 +498,9 @@ prefixset_item      : prefix prefixlenop                    
{
                ;
 
 roa_set                : ROASET '{' optnl              {
-                       curpsitree = &conf->roa;
+                       curroatree = &conf->roa;
                } roa_set_l optnl '}'                   {
-                       curpsitree = NULL;
+                       curroatree = NULL;
                }
                | ROASET '{' optnl '}'          /* nothing */
                ;
@@ -510,12 +510,12 @@ origin_set        : ORIGINSET STRING '{' optnl    
                                free($2);
                                YYERROR;
                        }
-                       curpsitree = &curoset->psitems;
+                       curroatree = &curoset->roaitems;
                        free($2);
                } roa_set_l optnl '}'                   {
                        SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
                        curoset = NULL;
-                       curpsitree = NULL;
+                       curroatree = NULL;
                }
                | ORIGINSET STRING '{' optnl '}'                {
                        if ((curoset = new_prefix_set($2, 1)) == NULL) {
@@ -525,7 +525,7 @@ origin_set  : ORIGINSET STRING '{' optnl    
                        free($2);
                        SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
                        curoset = NULL;
-                       curpsitree = NULL;
+                       curroatree = NULL;
                }
                ;
 
@@ -537,6 +537,7 @@ roa_set_l   : prefixset_item SOURCEAS as4n
                                YYERROR;
                        }
                        add_roa_set($1, $3, $1->p.len_max);
+                       free($1);
                }
                | roa_set_l comma prefixset_item SOURCEAS as4number_any {
                        if ($3->p.len_min != $3->p.len) {
@@ -546,6 +547,7 @@ roa_set_l   : prefixset_item SOURCEAS as4n
                                YYERROR;
                        }
                        add_roa_set($3, $5, $3->p.len_max);
+                       free($3);
                }
                ;
 
@@ -4502,7 +4504,7 @@ new_prefix_set(char *name, int is_roa)
        struct prefixset *pset;
 
        if (is_roa) {
-               type = "roa-set";
+               type = "origin-set";
                sets = &conf->originsets;
        }
 
@@ -4520,38 +4522,35 @@ new_prefix_set(char *name, int is_roa)
                return NULL;
        }
        RB_INIT(&pset->psitems);
+       RB_INIT(&pset->roaitems);
        return pset;
 }
 
 static void
 add_roa_set(struct prefixset_item *npsi, u_int32_t as, u_int8_t max)
 {
-       struct prefixset_item   *psi;
-       struct roa_set rs, *rsp;
+       struct roa *roa, *r;
 
-       /* no prefixlen option in this tree */
-       npsi->p.op = OP_NONE;
-       npsi->p.len_max = npsi->p.len_min = npsi->p.len;
-       psi = RB_INSERT(prefixset_tree, curpsitree, npsi);
-       if (psi == NULL)
-               psi = npsi;
-       else
-               free(npsi);
+       if ((roa = calloc(1, sizeof(*roa))) == NULL)
+               fatal("add_roa_set");
 
-       if (psi->set == NULL)
-               if ((psi->set = set_new(1, sizeof(rs))) == NULL)
-                       fatal("set_new");
-
-       /* merge sets with same key, longer maxlen wins */
-       if ((rsp = set_match(psi->set, as)) != NULL) {
-               if (rsp->maxlen < max)
-                       rsp->maxlen = max;
-       } else  {
-               rs.as = as;
-               rs.maxlen = max;
-               if (set_add(psi->set, &rs, 1) != 0)
-                       fatal("as_set_new");
-               /* prep data so that set_match works */
-               set_prep(psi->set);
+       roa->aid = npsi->p.addr.aid;
+       roa->prefixlen = npsi->p.len;
+       roa->maxlen = max;
+       roa->asnum = as;
+       switch (roa->aid) {
+       case AID_INET:
+               roa->prefix.inet = npsi->p.addr.v4;
+               break;
+       case AID_INET6:
+               roa->prefix.inet6 = npsi->p.addr.v6;
+               break;
+       default:
+               fatalx("Bad address family for roa_set address");
        }
+
+       r = RB_INSERT(roa_tree, curroatree, roa);
+       if (r != NULL)
+               /* just ignore duplicates */
+               free(roa);
 }
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.143
diff -u -p -r1.143 printconf.c
--- printconf.c 5 Nov 2020 11:51:13 -0000       1.143
+++ printconf.c 18 Dec 2020 08:40:44 -0000
@@ -41,7 +41,7 @@ void           print_network(struct network_conf
 void            print_as_sets(struct as_set_head *);
 void            print_prefixsets(struct prefixset_head *);
 void            print_originsets(struct prefixset_head *);
-void            print_roa(struct prefixset_tree *p);
+void            print_roa(struct roa_tree *);
 void            print_peer(struct peer_config *, struct bgpd_config *,
                    const char *);
 const char     *print_auth_alg(u_int8_t);
@@ -535,46 +535,42 @@ void
 print_originsets(struct prefixset_head *psh)
 {
        struct prefixset        *ps;
-       struct prefixset_item   *psi;
-       struct roa_set          *rs;
-       size_t                   i, n;
+       struct roa              *roa;
+       struct bgpd_addr         addr;
 
        SIMPLEQ_FOREACH(ps, psh, entry) {
                printf("origin-set \"%s\" {", ps->name);
-               RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
-                       rs = set_get(psi->set, &n);
-                       for (i = 0; i < n; i++) {
-                               printf("\n\t");
-                               print_prefix(&psi->p);
-                               if (psi->p.len != rs[i].maxlen)
-                                       printf(" maxlen %u", rs[i].maxlen);
-                               printf(" source-as %u", rs[i].as);
-                       }
+               RB_FOREACH(roa, roa_tree, &ps->roaitems) {
+                       printf("\n\t");
+                       addr.aid = roa->aid;
+                       addr.v6 = roa->prefix.inet6;
+                       printf("%s/%u", log_addr(&addr), roa->prefixlen);
+                       if (roa->prefixlen != roa->maxlen)
+                               printf(" maxlen %u", roa->maxlen);
+                       printf(" source-as %u", roa->asnum);
                }
                printf("\n}\n\n");
        }
 }
 
 void
-print_roa(struct prefixset_tree *p)
+print_roa(struct roa_tree *r)
 {
-       struct prefixset_item   *psi;
-       struct roa_set          *rs;
-       size_t                   i, n;
+       struct roa      *roa;
+       struct bgpd_addr addr;
 
-       if (RB_EMPTY(p))
+       if (RB_EMPTY(r))
                return;
 
        printf("roa-set {");
-       RB_FOREACH(psi, prefixset_tree, p) {
-               rs = set_get(psi->set, &n);
-               for (i = 0; i < n; i++) {
-                       printf("\n\t");
-                       print_prefix(&psi->p);
-                       if (psi->p.len != rs[i].maxlen)
-                               printf(" maxlen %u", rs[i].maxlen);
-                       printf(" source-as %u", rs[i].as);
-               }
+       RB_FOREACH(roa, roa_tree, r) {
+               printf("\n\t");
+               addr.aid = roa->aid;
+               addr.v6 = roa->prefix.inet6;
+               printf("%s/%u", log_addr(&addr), roa->prefixlen);
+               if (roa->prefixlen != roa->maxlen)
+                       printf(" maxlen %u", roa->maxlen);
+               printf(" source-as %u", roa->asnum);
        }
        printf("\n}\n\n");
 }
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.507
diff -u -p -r1.507 rde.c
--- rde.c       4 Dec 2020 11:57:13 -0000       1.507
+++ rde.c       18 Dec 2020 08:40:44 -0000
@@ -614,10 +614,10 @@ rde_dispatch_imsg_parent(struct imsgbuf 
 {
        static struct rde_prefixset     *last_prefixset;
        static struct as_set    *last_as_set;
-       static struct set_table *last_set;
        static struct l3vpn     *vpn;
        struct imsg              imsg;
        struct mrt               xmrt;
+       struct roa               roa;
        struct rde_rib           rr;
        struct filterstate       state;
        struct imsgbuf          *i;
@@ -813,24 +813,18 @@ rde_dispatch_imsg_parent(struct imsgbuf 
                                    entry);
                        }
                        last_prefixset = ps;
-                       last_set = NULL;
                        break;
                case IMSG_RECONF_ROA_SET:
                        strlcpy(nconf->rde_roa.name, "RPKI ROA",
                            sizeof(nconf->rde_roa.name));
                        last_prefixset = &nconf->rde_roa;
-                       last_set = NULL;
                        break;
-               case IMSG_RECONF_ROA_SET_ITEMS:
-                       nmemb = imsg.hdr.len - IMSG_HEADER_SIZE;
-                       nmemb /= sizeof(struct roa_set);
-                       if (last_set == NULL) {
-                               last_set = set_new(1, sizeof(struct roa_set));
-                               if (last_set == NULL)
-                                       fatal(NULL);
-                       }
-                       if (set_add(last_set, imsg.data, nmemb) != 0)
-                               fatal(NULL);
+               case IMSG_RECONF_ROA_ITEM:
+                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+                           sizeof(roa))
+                               fatalx("IMSG_RECONF_PREFIX_SET_ITEM bad len");
+                       memcpy(&roa, imsg.data, sizeof(roa));
+                       rv = trie_roa_add(&last_prefixset->th, &roa);
                        break;
                case IMSG_RECONF_PREFIX_SET_ITEM:
                        if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -839,16 +833,9 @@ rde_dispatch_imsg_parent(struct imsgbuf 
                        memcpy(&psi, imsg.data, sizeof(psi));
                        if (last_prefixset == NULL)
                                fatalx("King Bula has no prefixset");
-                       if (last_set) {
-                               set_prep(last_set);
-                               rv = trie_roa_add(&last_prefixset->th,
-                                   &psi.p.addr, psi.p.len, last_set);
-                               last_set = NULL;
-                       } else {
-                               rv = trie_add(&last_prefixset->th,
-                                   &psi.p.addr, psi.p.len,
-                                   psi.p.len_min, psi.p.len_max);
-                       }
+                       rv = trie_add(&last_prefixset->th,
+                           &psi.p.addr, psi.p.len,
+                           psi.p.len_min, psi.p.len_max);
                        if (rv == -1)
                                log_warnx("trie_add(%s) %s/%u) failed",
                                    last_prefixset->name, log_addr(&psi.p.addr),
Index: rde_trie.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_trie.c,v
retrieving revision 1.10
diff -u -p -r1.10 rde_trie.c
--- rde_trie.c  26 Oct 2018 16:53:55 -0000      1.10
+++ rde_trie.c  18 Dec 2020 08:40:44 -0000
@@ -378,30 +378,30 @@ trie_add(struct trie_head *th, struct bg
  * is a match.
  */
 int
-trie_roa_add(struct trie_head *th, struct bgpd_addr *prefix, u_int8_t plen,
-    struct set_table *set)
+trie_roa_add(struct trie_head *th, struct roa *roa)
 {
        struct tentry_v4 *n4;
        struct tentry_v6 *n6;
        struct set_table **stp;
+       struct roa_set rs, *rsp;
 
        /* ignore possible default route since it does not make sense */
 
-       switch (prefix->aid) {
+       switch (roa->aid) {
        case AID_INET:
-               if (plen > 32)
+               if (roa->prefixlen > 32)
                        return -1;
 
-               n4 = trie_add_v4(th, &prefix->v4, plen);
+               n4 = trie_add_v4(th, &roa->prefix.inet, roa->prefixlen);
                if (n4 == NULL)
                        return -1;
                stp = &n4->set;
                break;
        case AID_INET6:
-               if (plen > 128)
+               if (roa->prefixlen > 128)
                        return -1;
 
-               n6 = trie_add_v6(th, &prefix->v6, plen);
+               n6 = trie_add_v6(th, &roa->prefix.inet6, roa->prefixlen);
                if (n6 == NULL)
                        return -1;
                stp = &n6->set;
@@ -411,10 +411,22 @@ trie_roa_add(struct trie_head *th, struc
                return -1;
        }
 
-       /* set_table already set, error out */
-       if (*stp != NULL)
-               return -1;
-       *stp = set;
+       if (*stp == NULL)
+               if ((*stp = set_new(1, sizeof(rs))) == NULL)
+                       return -1;
+
+       /* merge sets with same key, longer maxlen wins */
+       if ((rsp = set_match(*stp, roa->asnum)) != NULL) {
+               if (rsp->maxlen < roa->maxlen)
+                       rsp->maxlen = roa->maxlen;
+       } else  {
+               rs.as = roa->asnum;
+               rs.maxlen = roa->maxlen;
+               if (set_add(*stp, &rs, 1) != 0)
+                       return -1;
+               /* prep data so that set_match works */
+               set_prep(*stp);
+       }
 
        return 0;
 }

Reply via email to