1*560116d9Sdenis /* $OpenBSD: rde_prefix.c,v 1.56 2024/12/30 17:14:02 denis Exp $ */ 2a16c0992Shenning 3a16c0992Shenning /* 4e854144bSclaudio * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> 5a16c0992Shenning * 6a16c0992Shenning * Permission to use, copy, modify, and distribute this software for any 7a16c0992Shenning * purpose with or without fee is hereby granted, provided that the above 8a16c0992Shenning * copyright notice and this permission notice appear in all copies. 9a16c0992Shenning * 10a16c0992Shenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a16c0992Shenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a16c0992Shenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a16c0992Shenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a16c0992Shenning * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a16c0992Shenning * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a16c0992Shenning * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a16c0992Shenning */ 18a16c0992Shenning 19a16c0992Shenning #include <sys/types.h> 20a16c0992Shenning #include <sys/queue.h> 21a16c0992Shenning 22493f3852Sclaudio #include <endian.h> 23a16c0992Shenning #include <errno.h> 24064aed48Sclaudio #include <stdint.h> 25a16c0992Shenning #include <stdlib.h> 26a9e0de78Shenning #include <string.h> 27a16c0992Shenning 28a16c0992Shenning #include "bgpd.h" 29a16c0992Shenning #include "rde.h" 305e3f6f95Sbenno #include "log.h" 31a16c0992Shenning 32a16c0992Shenning /* 33a16c0992Shenning * Prefix Table functions: 34a16c0992Shenning * pt_add: create new prefix and link it into the prefix table 35a16c0992Shenning * pt_remove: Checks if there is no bgp prefix linked to the prefix, 36c5508ee4Sclaudio * unlinks from the prefix table and frees the pt_entry. 37a16c0992Shenning * pt_get: get a prefix/prefixlen entry. While pt_lookup searches for the 38a16c0992Shenning * best matching prefix pt_get only finds the prefix/prefixlen 39a16c0992Shenning * entry. The speed of pt_get is important for the bgp updates. 40f6ce8965Sclaudio * pt_getaddr: convert the address into a struct bgpd_addr. 41c5508ee4Sclaudio * pt_lookup: lookup a IP in the prefix table. Mainly for "show ip bgp". 42a16c0992Shenning * pt_empty: returns true if there is no bgp prefix linked to the pt_entry. 43a16c0992Shenning * pt_init: initialize prefix table. 44d6c2e4e8Sclaudio * pt_alloc: allocate a AF specific pt_entry. Internal function. 4504f2231bShenning * pt_free: free a pt_entry. Internal function. 46a16c0992Shenning */ 47a16c0992Shenning 48a16c0992Shenning /* internal prototypes */ 49064aed48Sclaudio static struct pt_entry *pt_alloc(struct pt_entry *, int len); 50a16c0992Shenning static void pt_free(struct pt_entry *); 51a16c0992Shenning 52448d73c9Sclaudio struct pt_entry4 { 53448d73c9Sclaudio RB_ENTRY(pt_entry) pt_e; 54448d73c9Sclaudio uint8_t aid; 55448d73c9Sclaudio uint8_t prefixlen; 56064aed48Sclaudio uint16_t len; 57064aed48Sclaudio uint32_t refcnt; 58448d73c9Sclaudio struct in_addr prefix4; 59448d73c9Sclaudio }; 60448d73c9Sclaudio 61448d73c9Sclaudio struct pt_entry6 { 62448d73c9Sclaudio RB_ENTRY(pt_entry) pt_e; 63448d73c9Sclaudio uint8_t aid; 64448d73c9Sclaudio uint8_t prefixlen; 65064aed48Sclaudio uint16_t len; 66064aed48Sclaudio uint32_t refcnt; 67448d73c9Sclaudio struct in6_addr prefix6; 68448d73c9Sclaudio }; 69448d73c9Sclaudio 70448d73c9Sclaudio struct pt_entry_vpn4 { 71448d73c9Sclaudio RB_ENTRY(pt_entry) pt_e; 72448d73c9Sclaudio uint8_t aid; 73448d73c9Sclaudio uint8_t prefixlen; 74064aed48Sclaudio uint16_t len; 75064aed48Sclaudio uint32_t refcnt; 76448d73c9Sclaudio uint64_t rd; 77064aed48Sclaudio struct in_addr prefix4; 78448d73c9Sclaudio uint8_t labelstack[21]; 79448d73c9Sclaudio uint8_t labellen; 80448d73c9Sclaudio uint8_t pad1; 81448d73c9Sclaudio uint8_t pad2; 82448d73c9Sclaudio }; 83448d73c9Sclaudio 84448d73c9Sclaudio struct pt_entry_vpn6 { 85448d73c9Sclaudio RB_ENTRY(pt_entry) pt_e; 86448d73c9Sclaudio uint8_t aid; 87448d73c9Sclaudio uint8_t prefixlen; 88064aed48Sclaudio uint16_t len; 89064aed48Sclaudio uint32_t refcnt; 90448d73c9Sclaudio uint64_t rd; 91064aed48Sclaudio struct in6_addr prefix6; 92448d73c9Sclaudio uint8_t labelstack[21]; 93448d73c9Sclaudio uint8_t labellen; 94448d73c9Sclaudio uint8_t pad1; 95448d73c9Sclaudio uint8_t pad2; 96448d73c9Sclaudio }; 97448d73c9Sclaudio 98689ec283Sclaudio struct pt_entry_flow { 99689ec283Sclaudio RB_ENTRY(pt_entry) pt_e; 100689ec283Sclaudio uint8_t aid; 101689ec283Sclaudio uint8_t prefixlen; /* unused ??? */ 102689ec283Sclaudio uint16_t len; 103689ec283Sclaudio uint32_t refcnt; 104689ec283Sclaudio uint64_t rd; 105689ec283Sclaudio uint8_t flow[1]; /* NLRI */ 106689ec283Sclaudio }; 107689ec283Sclaudio 108689ec283Sclaudio #define PT_FLOW_SIZE (offsetof(struct pt_entry_flow, flow)) 109d6c2e4e8Sclaudio 110b2c8317eSclaudio RB_HEAD(pt_tree, pt_entry); 111b2c8317eSclaudio RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); 112b2c8317eSclaudio RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); 113a16c0992Shenning 114d3371e77Sclaudio struct pt_tree pttable; 115a16c0992Shenning 116a16c0992Shenning void 117a16c0992Shenning pt_init(void) 118a16c0992Shenning { 119d3371e77Sclaudio RB_INIT(&pttable); 120a16c0992Shenning } 121a16c0992Shenning 1226f08c262Sclaudio void 1236f08c262Sclaudio pt_shutdown(void) 1246f08c262Sclaudio { 125d3371e77Sclaudio if (!RB_EMPTY(&pttable)) 126d3371e77Sclaudio log_debug("pt_shutdown: tree is not empty."); 1276f08c262Sclaudio } 1286f08c262Sclaudio 129b2c8317eSclaudio void 130b2c8317eSclaudio pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) 131b2c8317eSclaudio { 132689ec283Sclaudio struct pt_entry_flow *pflow; 133689ec283Sclaudio 134eafe309eSclaudio memset(addr, 0, sizeof(struct bgpd_addr)); 135d6c2e4e8Sclaudio addr->aid = pte->aid; 136d6c2e4e8Sclaudio switch (addr->aid) { 137d6c2e4e8Sclaudio case AID_INET: 138b2c8317eSclaudio addr->v4 = ((struct pt_entry4 *)pte)->prefix4; 139b2c8317eSclaudio break; 140d6c2e4e8Sclaudio case AID_INET6: 1413038d3d1Sclaudio addr->v6 = ((struct pt_entry6 *)pte)->prefix6; 142b2c8317eSclaudio /* XXX scope_id ??? */ 143b2c8317eSclaudio break; 14415d8de66Sclaudio case AID_VPN_IPv4: 1453038d3d1Sclaudio addr->v4 = ((struct pt_entry_vpn4 *)pte)->prefix4; 1463038d3d1Sclaudio addr->rd = ((struct pt_entry_vpn4 *)pte)->rd; 1473038d3d1Sclaudio addr->labellen = ((struct pt_entry_vpn4 *)pte)->labellen; 1483038d3d1Sclaudio memcpy(addr->labelstack, 14915d8de66Sclaudio ((struct pt_entry_vpn4 *)pte)->labelstack, 1503038d3d1Sclaudio addr->labellen); 15115d8de66Sclaudio break; 152290f96faSdenis case AID_VPN_IPv6: 1533038d3d1Sclaudio addr->v6 = ((struct pt_entry_vpn6 *)pte)->prefix6; 1543038d3d1Sclaudio addr->rd = ((struct pt_entry_vpn6 *)pte)->rd; 1553038d3d1Sclaudio addr->labellen = ((struct pt_entry_vpn6 *)pte)->labellen; 1563038d3d1Sclaudio memcpy(addr->labelstack, 157290f96faSdenis ((struct pt_entry_vpn6 *)pte)->labelstack, 1583038d3d1Sclaudio addr->labellen); 159290f96faSdenis break; 160689ec283Sclaudio case AID_FLOWSPECv4: 161689ec283Sclaudio case AID_FLOWSPECv6: 162689ec283Sclaudio pflow = (struct pt_entry_flow *)pte; 163689ec283Sclaudio flowspec_get_addr(pflow->flow, pflow->len - PT_FLOW_SIZE, 164689ec283Sclaudio FLOWSPEC_TYPE_DEST, addr->aid == AID_FLOWSPECv6, 165689ec283Sclaudio addr, &pflow->prefixlen, NULL); 166689ec283Sclaudio break; 167b2c8317eSclaudio default: 168b2c8317eSclaudio fatalx("pt_getaddr: unknown af"); 169b2c8317eSclaudio } 170b2c8317eSclaudio } 171b2c8317eSclaudio 172689ec283Sclaudio int 173689ec283Sclaudio pt_getflowspec(struct pt_entry *pte, uint8_t **flow) 174689ec283Sclaudio { 175689ec283Sclaudio struct pt_entry_flow *pflow; 176689ec283Sclaudio 177689ec283Sclaudio switch (pte->aid) { 178689ec283Sclaudio case AID_FLOWSPECv4: 179689ec283Sclaudio case AID_FLOWSPECv6: 180689ec283Sclaudio pflow = (struct pt_entry_flow *)pte; 181689ec283Sclaudio *flow = pflow->flow; 182689ec283Sclaudio return pflow->len - PT_FLOW_SIZE; 183689ec283Sclaudio default: 184689ec283Sclaudio fatalx("pt_getflowspec: unknown af"); 185689ec283Sclaudio } 186689ec283Sclaudio } 187689ec283Sclaudio 188a16c0992Shenning struct pt_entry * 18986f6dc6eSclaudio pt_fill(struct bgpd_addr *prefix, int prefixlen) 190a16c0992Shenning { 19186f6dc6eSclaudio static struct pt_entry4 pte4; 19286f6dc6eSclaudio static struct pt_entry6 pte6; 19315d8de66Sclaudio static struct pt_entry_vpn4 pte_vpn4; 194290f96faSdenis static struct pt_entry_vpn6 pte_vpn6; 195a16c0992Shenning 196d6c2e4e8Sclaudio switch (prefix->aid) { 197d6c2e4e8Sclaudio case AID_INET: 198eafe309eSclaudio memset(&pte4, 0, sizeof(pte4)); 199064aed48Sclaudio pte4.len = sizeof(pte4); 200064aed48Sclaudio pte4.refcnt = UINT32_MAX; 20115d8de66Sclaudio pte4.aid = prefix->aid; 202b2c8317eSclaudio if (prefixlen > 32) 203d6c2e4e8Sclaudio fatalx("pt_fill: bad IPv4 prefixlen"); 2042b5c88feSclaudio inet4applymask(&pte4.prefix4, &prefix->v4, prefixlen); 205b2c8317eSclaudio pte4.prefixlen = prefixlen; 20686f6dc6eSclaudio return ((struct pt_entry *)&pte4); 207d6c2e4e8Sclaudio case AID_INET6: 208eafe309eSclaudio memset(&pte6, 0, sizeof(pte6)); 209064aed48Sclaudio pte6.len = sizeof(pte6); 210064aed48Sclaudio pte6.refcnt = UINT32_MAX; 21115d8de66Sclaudio pte6.aid = prefix->aid; 212b2c8317eSclaudio if (prefixlen > 128) 21327434512Sdenis fatalx("pt_fill: bad IPv6 prefixlen"); 214b2c8317eSclaudio inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen); 2152b5c88feSclaudio pte6.prefixlen = prefixlen; 21686f6dc6eSclaudio return ((struct pt_entry *)&pte6); 21715d8de66Sclaudio case AID_VPN_IPv4: 218eafe309eSclaudio memset(&pte_vpn4, 0, sizeof(pte_vpn4)); 219064aed48Sclaudio pte_vpn4.len = sizeof(pte_vpn4); 220064aed48Sclaudio pte_vpn4.refcnt = UINT32_MAX; 22115d8de66Sclaudio pte_vpn4.aid = prefix->aid; 22215d8de66Sclaudio if (prefixlen > 32) 22315d8de66Sclaudio fatalx("pt_fill: bad IPv4 prefixlen"); 2243038d3d1Sclaudio inet4applymask(&pte_vpn4.prefix4, &prefix->v4, prefixlen); 22515d8de66Sclaudio pte_vpn4.prefixlen = prefixlen; 2263038d3d1Sclaudio pte_vpn4.rd = prefix->rd; 2273038d3d1Sclaudio pte_vpn4.labellen = prefix->labellen; 2283038d3d1Sclaudio memcpy(pte_vpn4.labelstack, prefix->labelstack, 2293038d3d1Sclaudio prefix->labellen); 23015d8de66Sclaudio return ((struct pt_entry *)&pte_vpn4); 231290f96faSdenis case AID_VPN_IPv6: 232290f96faSdenis memset(&pte_vpn6, 0, sizeof(pte_vpn6)); 233064aed48Sclaudio pte_vpn6.len = sizeof(pte_vpn6); 234064aed48Sclaudio pte_vpn6.refcnt = UINT32_MAX; 235290f96faSdenis pte_vpn6.aid = prefix->aid; 236290f96faSdenis if (prefixlen > 128) 237*560116d9Sdenis fatalx("pt_fill: bad IPv6 prefixlen"); 2383038d3d1Sclaudio inet6applymask(&pte_vpn6.prefix6, &prefix->v6, prefixlen); 239290f96faSdenis pte_vpn6.prefixlen = prefixlen; 2403038d3d1Sclaudio pte_vpn6.rd = prefix->rd; 2413038d3d1Sclaudio pte_vpn6.labellen = prefix->labellen; 2423038d3d1Sclaudio memcpy(pte_vpn6.labelstack, prefix->labelstack, 2433038d3d1Sclaudio prefix->labellen); 244290f96faSdenis return ((struct pt_entry *)&pte_vpn6); 24586f6dc6eSclaudio default: 24615d8de66Sclaudio fatalx("pt_fill: unknown af"); 24786f6dc6eSclaudio } 24886f6dc6eSclaudio } 24986f6dc6eSclaudio 25086f6dc6eSclaudio struct pt_entry * 25186f6dc6eSclaudio pt_get(struct bgpd_addr *prefix, int prefixlen) 25286f6dc6eSclaudio { 25386f6dc6eSclaudio struct pt_entry *pte; 25486f6dc6eSclaudio 25586f6dc6eSclaudio pte = pt_fill(prefix, prefixlen); 256d3371e77Sclaudio return RB_FIND(pt_tree, &pttable, pte); 257a16c0992Shenning } 258a16c0992Shenning 259a16c0992Shenning struct pt_entry * 26008575f87Sclaudio pt_add(struct bgpd_addr *prefix, int prefixlen) 261a16c0992Shenning { 262b2c8317eSclaudio struct pt_entry *p = NULL; 263a16c0992Shenning 264064aed48Sclaudio p = pt_fill(prefix, prefixlen); 265064aed48Sclaudio p = pt_alloc(p, p->len); 266a16c0992Shenning 267fab04e66Sclaudio if (RB_INSERT(pt_tree, &pttable, p) != NULL) 268fab04e66Sclaudio fatalx("pt_add: insert failed"); 269a16c0992Shenning 270b2c8317eSclaudio return (p); 271a16c0992Shenning } 272a16c0992Shenning 273689ec283Sclaudio struct pt_entry * 274689ec283Sclaudio pt_get_flow(struct flowspec *f) 275689ec283Sclaudio { 276689ec283Sclaudio struct pt_entry *needle; 277689ec283Sclaudio union { 278689ec283Sclaudio struct pt_entry_flow flow; 279689ec283Sclaudio uint8_t buf[4096]; 280689ec283Sclaudio } x; 281689ec283Sclaudio 282689ec283Sclaudio needle = (struct pt_entry *)&x.flow; 283689ec283Sclaudio 284689ec283Sclaudio memset(needle, 0, PT_FLOW_SIZE); 285689ec283Sclaudio needle->aid = f->aid; 286689ec283Sclaudio needle->len = f->len + PT_FLOW_SIZE; 287689ec283Sclaudio memcpy(((struct pt_entry_flow *)needle)->flow, f->data, f->len); 288689ec283Sclaudio 289689ec283Sclaudio return RB_FIND(pt_tree, &pttable, (struct pt_entry *)needle); 290689ec283Sclaudio } 291689ec283Sclaudio 292689ec283Sclaudio struct pt_entry * 293689ec283Sclaudio pt_add_flow(struct flowspec *f) 294689ec283Sclaudio { 295689ec283Sclaudio struct pt_entry *p; 296689ec283Sclaudio int len = f->len + PT_FLOW_SIZE; 297689ec283Sclaudio 298689ec283Sclaudio p = malloc(len); 299689ec283Sclaudio if (p == NULL) 300689ec283Sclaudio fatal(__func__); 301689ec283Sclaudio rdemem.pt_cnt[f->aid]++; 302689ec283Sclaudio rdemem.pt_size[f->aid] += len; 303689ec283Sclaudio memset(p, 0, PT_FLOW_SIZE); 304689ec283Sclaudio 305689ec283Sclaudio p->len = len; 306689ec283Sclaudio p->aid = f->aid; 307689ec283Sclaudio memcpy(((struct pt_entry_flow *)p)->flow, f->data, f->len); 308689ec283Sclaudio 309689ec283Sclaudio if (RB_INSERT(pt_tree, &pttable, p) != NULL) 310689ec283Sclaudio fatalx("pt_add: insert failed"); 311689ec283Sclaudio 312689ec283Sclaudio return (p); 313689ec283Sclaudio } 314689ec283Sclaudio 315a16c0992Shenning void 316a16c0992Shenning pt_remove(struct pt_entry *pte) 317a16c0992Shenning { 318e2c0fe86Sclaudio if (pte->refcnt != 0) 31986f6dc6eSclaudio fatalx("pt_remove: entry still holds references"); 320f6ce8965Sclaudio 321d3371e77Sclaudio if (RB_REMOVE(pt_tree, &pttable, pte) == NULL) 322b2c8317eSclaudio log_warnx("pt_remove: remove failed."); 323a16c0992Shenning pt_free(pte); 324a16c0992Shenning } 325a16c0992Shenning 326a16c0992Shenning struct pt_entry * 32786f6dc6eSclaudio pt_lookup(struct bgpd_addr *addr) 328a16c0992Shenning { 329a16c0992Shenning struct pt_entry *p; 330a16c0992Shenning int i; 331a16c0992Shenning 332d6c2e4e8Sclaudio switch (addr->aid) { 333d6c2e4e8Sclaudio case AID_INET: 33415d8de66Sclaudio case AID_VPN_IPv4: 335d3371e77Sclaudio i = 32; 336b2c8317eSclaudio break; 337d6c2e4e8Sclaudio case AID_INET6: 338290f96faSdenis case AID_VPN_IPv6: 339d3371e77Sclaudio i = 128; 340b2c8317eSclaudio break; 341b2c8317eSclaudio default: 342b2c8317eSclaudio fatalx("pt_lookup: unknown af"); 343b2c8317eSclaudio } 344d3371e77Sclaudio for (; i >= 0; i--) { 345d3371e77Sclaudio p = pt_get(addr, i); 346d3371e77Sclaudio if (p != NULL) 347d3371e77Sclaudio return (p); 348d3371e77Sclaudio } 349ad926354Sclaudio return (NULL); 350a16c0992Shenning } 351a16c0992Shenning 352b2c8317eSclaudio int 353b2c8317eSclaudio pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) 354b2c8317eSclaudio { 355b2c8317eSclaudio const struct pt_entry4 *a4, *b4; 356b2c8317eSclaudio const struct pt_entry6 *a6, *b6; 35715d8de66Sclaudio const struct pt_entry_vpn4 *va4, *vb4; 358290f96faSdenis const struct pt_entry_vpn6 *va6, *vb6; 359689ec283Sclaudio const struct pt_entry_flow *af, *bf; 360b2c8317eSclaudio int i; 361b2c8317eSclaudio 362d6c2e4e8Sclaudio if (a->aid > b->aid) 36386f6dc6eSclaudio return (1); 364d6c2e4e8Sclaudio if (a->aid < b->aid) 36586f6dc6eSclaudio return (-1); 366b2c8317eSclaudio 367d6c2e4e8Sclaudio switch (a->aid) { 368d6c2e4e8Sclaudio case AID_INET: 369b2c8317eSclaudio a4 = (const struct pt_entry4 *)a; 370b2c8317eSclaudio b4 = (const struct pt_entry4 *)b; 371b2c8317eSclaudio if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr)) 372b2c8317eSclaudio return (1); 373b2c8317eSclaudio if (ntohl(a4->prefix4.s_addr) < ntohl(b4->prefix4.s_addr)) 374b2c8317eSclaudio return (-1); 375b2c8317eSclaudio if (a4->prefixlen > b4->prefixlen) 376b2c8317eSclaudio return (1); 377b2c8317eSclaudio if (a4->prefixlen < b4->prefixlen) 378b2c8317eSclaudio return (-1); 379b2c8317eSclaudio return (0); 380d6c2e4e8Sclaudio case AID_INET6: 381b2c8317eSclaudio a6 = (const struct pt_entry6 *)a; 382b2c8317eSclaudio b6 = (const struct pt_entry6 *)b; 383b2c8317eSclaudio 384b2c8317eSclaudio i = memcmp(&a6->prefix6, &b6->prefix6, sizeof(struct in6_addr)); 385b2c8317eSclaudio if (i > 0) 386b2c8317eSclaudio return (1); 387b2c8317eSclaudio if (i < 0) 388b2c8317eSclaudio return (-1); 389b2c8317eSclaudio if (a6->prefixlen < b6->prefixlen) 390b2c8317eSclaudio return (-1); 391b2c8317eSclaudio if (a6->prefixlen > b6->prefixlen) 392b2c8317eSclaudio return (1); 393b2c8317eSclaudio return (0); 39415d8de66Sclaudio case AID_VPN_IPv4: 39515d8de66Sclaudio va4 = (const struct pt_entry_vpn4 *)a; 39615d8de66Sclaudio vb4 = (const struct pt_entry_vpn4 *)b; 397f4c0eb52Sclaudio if (be64toh(va4->rd) > be64toh(vb4->rd)) 398290f96faSdenis return (1); 399f4c0eb52Sclaudio if (be64toh(va4->rd) < be64toh(vb4->rd)) 400290f96faSdenis return (-1); 40115d8de66Sclaudio if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr)) 40215d8de66Sclaudio return (1); 40315d8de66Sclaudio if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr)) 40415d8de66Sclaudio return (-1); 40515d8de66Sclaudio if (va4->prefixlen > vb4->prefixlen) 40615d8de66Sclaudio return (1); 40715d8de66Sclaudio if (va4->prefixlen < vb4->prefixlen) 40815d8de66Sclaudio return (-1); 409290f96faSdenis return (0); 410290f96faSdenis case AID_VPN_IPv6: 411290f96faSdenis va6 = (const struct pt_entry_vpn6 *)a; 412290f96faSdenis vb6 = (const struct pt_entry_vpn6 *)b; 413f4c0eb52Sclaudio if (be64toh(va6->rd) > be64toh(vb6->rd)) 41415d8de66Sclaudio return (1); 415f4c0eb52Sclaudio if (be64toh(va6->rd) < be64toh(vb6->rd)) 416290f96faSdenis return (-1); 417290f96faSdenis i = memcmp(&va6->prefix6, &vb6->prefix6, 418290f96faSdenis sizeof(struct in6_addr)); 419290f96faSdenis if (i > 0) 420290f96faSdenis return (1); 421290f96faSdenis if (i < 0) 422290f96faSdenis return (-1); 423290f96faSdenis if (va6->prefixlen > vb6->prefixlen) 424290f96faSdenis return (1); 425290f96faSdenis if (va6->prefixlen < vb6->prefixlen) 42615d8de66Sclaudio return (-1); 42715d8de66Sclaudio return (0); 428689ec283Sclaudio case AID_FLOWSPECv4: 429689ec283Sclaudio case AID_FLOWSPECv6: 430689ec283Sclaudio af = (const struct pt_entry_flow *)a; 431689ec283Sclaudio bf = (const struct pt_entry_flow *)b; 432689ec283Sclaudio return flowspec_cmp(af->flow, af->len - PT_FLOW_SIZE, 433689ec283Sclaudio bf->flow, bf->len - PT_FLOW_SIZE, 434689ec283Sclaudio a->aid == AID_FLOWSPECv6); 435b2c8317eSclaudio default: 436b2c8317eSclaudio fatalx("pt_prefix_cmp: unknown af"); 437b2c8317eSclaudio } 438b2c8317eSclaudio return (-1); 439a16c0992Shenning } 440a16c0992Shenning 441d6c2e4e8Sclaudio /* 442d6c2e4e8Sclaudio * Returns a pt_entry cloned from the one passed in. 443d6c2e4e8Sclaudio * Function may not return on failure. 444d6c2e4e8Sclaudio */ 445d6c2e4e8Sclaudio static struct pt_entry * 446064aed48Sclaudio pt_alloc(struct pt_entry *op, int len) 447a16c0992Shenning { 448d6c2e4e8Sclaudio struct pt_entry *p; 449a16c0992Shenning 450064aed48Sclaudio p = malloc(len); 451a16c0992Shenning if (p == NULL) 452f87a5020Shenning fatal("pt_alloc"); 453d6c2e4e8Sclaudio rdemem.pt_cnt[op->aid]++; 454064aed48Sclaudio rdemem.pt_size[op->aid] += len; 455064aed48Sclaudio memcpy(p, op, len); 4561f391030Sclaudio p->refcnt = 0; 457b2c8317eSclaudio 458b2c8317eSclaudio return (p); 459a16c0992Shenning } 460a16c0992Shenning 461a16c0992Shenning static void 462a16c0992Shenning pt_free(struct pt_entry *pte) 463a16c0992Shenning { 464d6c2e4e8Sclaudio rdemem.pt_cnt[pte->aid]--; 465064aed48Sclaudio rdemem.pt_size[pte->aid] -= pte->len; 466a16c0992Shenning free(pte); 467a16c0992Shenning } 468de422abdSclaudio 469de422abdSclaudio /* dump a prefix into specified buffer */ 470de422abdSclaudio int 47166b1afa0Sclaudio pt_writebuf(struct ibuf *buf, struct pt_entry *pte, int withdraw, 47266b1afa0Sclaudio int add_path, uint32_t pathid) 473de422abdSclaudio { 474de422abdSclaudio struct pt_entry_vpn4 *pvpn4 = (struct pt_entry_vpn4 *)pte; 475de422abdSclaudio struct pt_entry_vpn6 *pvpn6 = (struct pt_entry_vpn6 *)pte; 476689ec283Sclaudio struct pt_entry_flow *pflow = (struct pt_entry_flow *)pte; 47766b1afa0Sclaudio struct ibuf *tmp; 47866b1afa0Sclaudio int flowlen, psize; 479de422abdSclaudio uint8_t plen; 480de422abdSclaudio 48166b1afa0Sclaudio if ((tmp = ibuf_dynamic(32, UINT16_MAX)) == NULL) 48266b1afa0Sclaudio goto fail; 48366b1afa0Sclaudio 48466b1afa0Sclaudio if (add_path) { 48566b1afa0Sclaudio if (ibuf_add_n32(tmp, pathid) == -1) 48666b1afa0Sclaudio goto fail; 48766b1afa0Sclaudio } 48866b1afa0Sclaudio 489de422abdSclaudio switch (pte->aid) { 490de422abdSclaudio case AID_INET: 491de422abdSclaudio case AID_INET6: 492de422abdSclaudio plen = pte->prefixlen; 49366b1afa0Sclaudio if (ibuf_add_n8(tmp, plen) == -1) 49466b1afa0Sclaudio goto fail; 49566b1afa0Sclaudio if (ibuf_add(tmp, pte->data, PREFIX_SIZE(plen) - 1) == -1) 49666b1afa0Sclaudio goto fail; 49766b1afa0Sclaudio break; 498de422abdSclaudio case AID_VPN_IPv4: 499de422abdSclaudio plen = pvpn4->prefixlen; 500de422abdSclaudio psize = PREFIX_SIZE(plen) - 1; 501de422abdSclaudio plen += sizeof(pvpn4->rd) * 8; 502de422abdSclaudio if (withdraw) { 503de422abdSclaudio /* withdraw have one compat label as placeholder */ 504de422abdSclaudio plen += 3 * 8; 505de422abdSclaudio } else { 506de422abdSclaudio plen += pvpn4->labellen * 8; 507de422abdSclaudio } 508de422abdSclaudio 50966b1afa0Sclaudio if (ibuf_add_n8(tmp, plen) == -1) 51066b1afa0Sclaudio goto fail; 511de422abdSclaudio if (withdraw) { 512de422abdSclaudio /* magic compatibility label as per rfc8277 */ 51366b1afa0Sclaudio if (ibuf_add_n8(tmp, 0x80) == -1 || 51466b1afa0Sclaudio ibuf_add_zero(tmp, 2) == -1) 51566b1afa0Sclaudio goto fail; 516de422abdSclaudio } else { 51766b1afa0Sclaudio if (ibuf_add(tmp, &pvpn4->labelstack, 51866b1afa0Sclaudio pvpn4->labellen) == -1) 51966b1afa0Sclaudio goto fail; 520de422abdSclaudio } 52166b1afa0Sclaudio if (ibuf_add(tmp, &pvpn4->rd, sizeof(pvpn4->rd)) == -1 || 52266b1afa0Sclaudio ibuf_add(tmp, &pvpn4->prefix4, psize) == -1) 52366b1afa0Sclaudio goto fail; 52466b1afa0Sclaudio break; 525de422abdSclaudio case AID_VPN_IPv6: 526de422abdSclaudio plen = pvpn6->prefixlen; 527de422abdSclaudio psize = PREFIX_SIZE(plen) - 1; 528de422abdSclaudio plen += sizeof(pvpn6->rd) * 8; 529de422abdSclaudio if (withdraw) { 530de422abdSclaudio /* withdraw have one compat label as placeholder */ 531de422abdSclaudio plen += 3 * 8; 532de422abdSclaudio } else { 533de422abdSclaudio plen += pvpn6->labellen * 8; 534de422abdSclaudio } 535de422abdSclaudio 53666b1afa0Sclaudio if (ibuf_add_n8(tmp, plen) == -1) 53766b1afa0Sclaudio goto fail; 538de422abdSclaudio if (withdraw) { 539de422abdSclaudio /* magic compatibility label as per rfc8277 */ 54066b1afa0Sclaudio if (ibuf_add_n8(tmp, 0x80) == -1 || 54166b1afa0Sclaudio ibuf_add_zero(tmp, 2) == -1) 54266b1afa0Sclaudio goto fail; 543de422abdSclaudio } else { 54466b1afa0Sclaudio if (ibuf_add(tmp, &pvpn6->labelstack, 54566b1afa0Sclaudio pvpn6->labellen) == -1) 54666b1afa0Sclaudio goto fail; 547de422abdSclaudio } 54866b1afa0Sclaudio if (ibuf_add(tmp, &pvpn6->rd, sizeof(pvpn6->rd)) == -1 || 54966b1afa0Sclaudio ibuf_add(tmp, &pvpn6->prefix6, psize) == -1) 55066b1afa0Sclaudio goto fail; 55166b1afa0Sclaudio break; 552689ec283Sclaudio case AID_FLOWSPECv4: 553689ec283Sclaudio case AID_FLOWSPECv6: 554689ec283Sclaudio flowlen = pflow->len - PT_FLOW_SIZE; 555689ec283Sclaudio if (flowlen < FLOWSPEC_LEN_LIMIT) { 55666b1afa0Sclaudio if (ibuf_add_n8(tmp, flowlen) == -1) 55766b1afa0Sclaudio goto fail; 558689ec283Sclaudio } else { 55966b1afa0Sclaudio if (ibuf_add_n8(tmp, 0xf0 | (flowlen >> 8)) == -1 || 56066b1afa0Sclaudio ibuf_add_n8(tmp, flowlen) == -1) 56166b1afa0Sclaudio goto fail; 562689ec283Sclaudio } 56366b1afa0Sclaudio if (ibuf_add(tmp, &pflow->flow, flowlen) == -1) 56466b1afa0Sclaudio goto fail; 565689ec283Sclaudio break; 566de422abdSclaudio default: 567fcf73b57Sclaudio fatalx("%s: unknown aid %d", __func__, pte->aid); 568de422abdSclaudio } 569de422abdSclaudio 570a48c3ad5Sclaudio /* keep 2 bytes reserved in the withdraw case for IPv4 encoding */ 571a48c3ad5Sclaudio if (withdraw && ibuf_left(buf) < ibuf_size(tmp) + 2) 572a48c3ad5Sclaudio goto fail; 573fa353a8fSclaudio if (ibuf_add_ibuf(buf, tmp) == -1) 57466b1afa0Sclaudio goto fail; 57566b1afa0Sclaudio ibuf_free(tmp); 57666b1afa0Sclaudio return 0; 57766b1afa0Sclaudio 57866b1afa0Sclaudio fail: 57966b1afa0Sclaudio ibuf_free(tmp); 58066b1afa0Sclaudio return -1; 581de422abdSclaudio } 582