1 /* $OpenBSD: rde_prefix.c,v 1.57 2025/02/04 18:16:56 denis Exp $ */
2
3 /*
4 * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/queue.h>
21
22 #include <endian.h>
23 #include <errno.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "bgpd.h"
29 #include "rde.h"
30 #include "log.h"
31
32 /*
33 * Prefix Table functions:
34 * pt_add: create new prefix and link it into the prefix table
35 * pt_remove: Checks if there is no bgp prefix linked to the prefix,
36 * unlinks from the prefix table and frees the pt_entry.
37 * pt_get: get a prefix/prefixlen entry. While pt_lookup searches for the
38 * best matching prefix pt_get only finds the prefix/prefixlen
39 * entry. The speed of pt_get is important for the bgp updates.
40 * pt_getaddr: convert the address into a struct bgpd_addr.
41 * pt_lookup: lookup a IP in the prefix table. Mainly for "show ip bgp".
42 * pt_empty: returns true if there is no bgp prefix linked to the pt_entry.
43 * pt_init: initialize prefix table.
44 * pt_alloc: allocate a AF specific pt_entry. Internal function.
45 * pt_free: free a pt_entry. Internal function.
46 */
47
48 /* internal prototypes */
49 static struct pt_entry *pt_alloc(struct pt_entry *, int len);
50 static void pt_free(struct pt_entry *);
51
52 struct pt_entry4 {
53 RB_ENTRY(pt_entry) pt_e;
54 uint8_t aid;
55 uint8_t prefixlen;
56 uint16_t len;
57 uint32_t refcnt;
58 struct in_addr prefix4;
59 };
60
61 struct pt_entry6 {
62 RB_ENTRY(pt_entry) pt_e;
63 uint8_t aid;
64 uint8_t prefixlen;
65 uint16_t len;
66 uint32_t refcnt;
67 struct in6_addr prefix6;
68 };
69
70 struct pt_entry_vpn4 {
71 RB_ENTRY(pt_entry) pt_e;
72 uint8_t aid;
73 uint8_t prefixlen;
74 uint16_t len;
75 uint32_t refcnt;
76 uint64_t rd;
77 struct in_addr prefix4;
78 uint8_t labelstack[21];
79 uint8_t labellen;
80 uint8_t pad1;
81 uint8_t pad2;
82 };
83
84 struct pt_entry_vpn6 {
85 RB_ENTRY(pt_entry) pt_e;
86 uint8_t aid;
87 uint8_t prefixlen;
88 uint16_t len;
89 uint32_t refcnt;
90 uint64_t rd;
91 struct in6_addr prefix6;
92 uint8_t labelstack[21];
93 uint8_t labellen;
94 uint8_t pad1;
95 uint8_t pad2;
96 };
97
98 struct pt_entry_evpn {
99 RB_ENTRY(pt_entry) pt_e;
100 uint8_t aid;
101 uint8_t prefixlen;
102 uint16_t len;
103 uint32_t refcnt;
104 uint64_t rd;
105 uint32_t ethtag;
106 uint8_t esi[ESI_ADDR_LEN];
107 uint8_t mac[ETHER_ADDR_LEN];
108 uint8_t labelstack[6];
109 uint8_t labellen;
110 uint8_t type;
111 uint8_t vpnaid;
112 union {
113 struct in_addr prefix4;
114 struct in6_addr prefix6;
115 };
116 };
117
118 struct pt_entry_flow {
119 RB_ENTRY(pt_entry) pt_e;
120 uint8_t aid;
121 uint8_t prefixlen; /* unused ??? */
122 uint16_t len;
123 uint32_t refcnt;
124 uint64_t rd;
125 uint8_t flow[1]; /* NLRI */
126 };
127
128 #define PT_FLOW_SIZE (offsetof(struct pt_entry_flow, flow))
129
130 RB_HEAD(pt_tree, pt_entry);
131 RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp);
132 RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp);
133
134 struct pt_tree pttable;
135
136 void
pt_init(void)137 pt_init(void)
138 {
139 RB_INIT(&pttable);
140 }
141
142 void
pt_shutdown(void)143 pt_shutdown(void)
144 {
145 if (!RB_EMPTY(&pttable))
146 log_debug("pt_shutdown: tree is not empty.");
147 }
148
149 void
pt_getaddr(struct pt_entry * pte,struct bgpd_addr * addr)150 pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr)
151 {
152 struct pt_entry_flow *pflow;
153 struct pt_entry_evpn *evpn;
154
155 memset(addr, 0, sizeof(struct bgpd_addr));
156 addr->aid = pte->aid;
157 switch (addr->aid) {
158 case AID_INET:
159 addr->v4 = ((struct pt_entry4 *)pte)->prefix4;
160 break;
161 case AID_INET6:
162 addr->v6 = ((struct pt_entry6 *)pte)->prefix6;
163 /* XXX scope_id ??? */
164 break;
165 case AID_VPN_IPv4:
166 addr->v4 = ((struct pt_entry_vpn4 *)pte)->prefix4;
167 addr->rd = ((struct pt_entry_vpn4 *)pte)->rd;
168 addr->labellen = ((struct pt_entry_vpn4 *)pte)->labellen;
169 memcpy(addr->labelstack,
170 ((struct pt_entry_vpn4 *)pte)->labelstack,
171 addr->labellen);
172 break;
173 case AID_VPN_IPv6:
174 addr->v6 = ((struct pt_entry_vpn6 *)pte)->prefix6;
175 addr->rd = ((struct pt_entry_vpn6 *)pte)->rd;
176 addr->labellen = ((struct pt_entry_vpn6 *)pte)->labellen;
177 memcpy(addr->labelstack,
178 ((struct pt_entry_vpn6 *)pte)->labelstack,
179 addr->labellen);
180 break;
181 case AID_EVPN:
182 evpn = (struct pt_entry_evpn *)pte;
183 addr->evpn.type = evpn->type;
184 addr->rd = evpn->rd;
185 addr->evpn.ethtag = evpn->ethtag;
186 addr->labellen = evpn->labellen;
187 addr->evpn.aid = evpn->vpnaid;
188 memcpy(addr->labelstack, evpn->labelstack, addr->labellen);
189 memcpy(addr->evpn.esi, evpn->esi, sizeof(evpn->esi));
190 memcpy(addr->evpn.mac, evpn->mac, sizeof(evpn->mac));
191 switch (evpn->vpnaid) {
192 case AID_INET:
193 addr->evpn.v4 = evpn->prefix4;
194 break;
195 case AID_INET6:
196 addr->evpn.v6 = evpn->prefix6;
197 break;
198 }
199 break;
200 case AID_FLOWSPECv4:
201 case AID_FLOWSPECv6:
202 pflow = (struct pt_entry_flow *)pte;
203 flowspec_get_addr(pflow->flow, pflow->len - PT_FLOW_SIZE,
204 FLOWSPEC_TYPE_DEST, addr->aid == AID_FLOWSPECv6,
205 addr, &pflow->prefixlen, NULL);
206 break;
207 default:
208 fatalx("pt_getaddr: unknown af");
209 }
210 }
211
212 int
pt_getflowspec(struct pt_entry * pte,uint8_t ** flow)213 pt_getflowspec(struct pt_entry *pte, uint8_t **flow)
214 {
215 struct pt_entry_flow *pflow;
216
217 switch (pte->aid) {
218 case AID_FLOWSPECv4:
219 case AID_FLOWSPECv6:
220 pflow = (struct pt_entry_flow *)pte;
221 *flow = pflow->flow;
222 return pflow->len - PT_FLOW_SIZE;
223 default:
224 fatalx("pt_getflowspec: unknown af");
225 }
226 }
227
228 struct pt_entry *
pt_fill(struct bgpd_addr * prefix,int prefixlen)229 pt_fill(struct bgpd_addr *prefix, int prefixlen)
230 {
231 static struct pt_entry4 pte4;
232 static struct pt_entry6 pte6;
233 static struct pt_entry_vpn4 pte_vpn4;
234 static struct pt_entry_vpn6 pte_vpn6;
235 static struct pt_entry_evpn pte_evpn;
236
237 switch (prefix->aid) {
238 case AID_INET:
239 memset(&pte4, 0, sizeof(pte4));
240 pte4.len = sizeof(pte4);
241 pte4.refcnt = UINT32_MAX;
242 pte4.aid = prefix->aid;
243 if (prefixlen > 32)
244 fatalx("pt_fill: bad IPv4 prefixlen");
245 inet4applymask(&pte4.prefix4, &prefix->v4, prefixlen);
246 pte4.prefixlen = prefixlen;
247 return ((struct pt_entry *)&pte4);
248 case AID_INET6:
249 memset(&pte6, 0, sizeof(pte6));
250 pte6.len = sizeof(pte6);
251 pte6.refcnt = UINT32_MAX;
252 pte6.aid = prefix->aid;
253 if (prefixlen > 128)
254 fatalx("pt_fill: bad IPv6 prefixlen");
255 inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen);
256 pte6.prefixlen = prefixlen;
257 return ((struct pt_entry *)&pte6);
258 case AID_VPN_IPv4:
259 memset(&pte_vpn4, 0, sizeof(pte_vpn4));
260 pte_vpn4.len = sizeof(pte_vpn4);
261 pte_vpn4.refcnt = UINT32_MAX;
262 pte_vpn4.aid = prefix->aid;
263 if (prefixlen > 32)
264 fatalx("pt_fill: bad IPv4 prefixlen");
265 inet4applymask(&pte_vpn4.prefix4, &prefix->v4, prefixlen);
266 pte_vpn4.prefixlen = prefixlen;
267 pte_vpn4.rd = prefix->rd;
268 pte_vpn4.labellen = prefix->labellen;
269 memcpy(pte_vpn4.labelstack, prefix->labelstack,
270 prefix->labellen);
271 return ((struct pt_entry *)&pte_vpn4);
272 case AID_VPN_IPv6:
273 memset(&pte_vpn6, 0, sizeof(pte_vpn6));
274 pte_vpn6.len = sizeof(pte_vpn6);
275 pte_vpn6.refcnt = UINT32_MAX;
276 pte_vpn6.aid = prefix->aid;
277 if (prefixlen > 128)
278 fatalx("pt_fill: bad IPv6 prefixlen");
279 inet6applymask(&pte_vpn6.prefix6, &prefix->v6, prefixlen);
280 pte_vpn6.prefixlen = prefixlen;
281 pte_vpn6.rd = prefix->rd;
282 pte_vpn6.labellen = prefix->labellen;
283 memcpy(pte_vpn6.labelstack, prefix->labelstack,
284 prefix->labellen);
285 return ((struct pt_entry *)&pte_vpn6);
286 case AID_EVPN:
287 memset(&pte_evpn, 0, sizeof(pte_evpn));
288 pte_evpn.len = sizeof(pte_evpn);
289 pte_evpn.refcnt = UINT32_MAX;
290 switch (prefix->evpn.aid) {
291 case AID_UNSPEC:
292 /* See rfc7432 section 7.2 */
293 break;
294 case AID_INET:
295 pte_evpn.prefix4 = prefix->evpn.v4;
296 break;
297 case AID_INET6:
298 pte_evpn.prefix6 = prefix->evpn.v6;
299 break;
300 default:
301 fatalx("pt_fill: bad EVPN prefixlen");
302 }
303 pte_evpn.aid = prefix->aid;
304 pte_evpn.vpnaid = prefix->evpn.aid;
305 pte_evpn.prefixlen = prefixlen;
306 pte_evpn.type = prefix->evpn.type;
307 pte_evpn.rd = prefix->rd;
308 pte_evpn.ethtag = prefix->evpn.ethtag;
309 pte_evpn.labellen = prefix->labellen;
310 memcpy(pte_evpn.labelstack, prefix->labelstack,
311 pte_evpn.labellen);
312 memcpy(pte_evpn.esi, prefix->evpn.esi,
313 sizeof(prefix->evpn.esi));
314 memcpy(pte_evpn.mac, prefix->evpn.mac,
315 sizeof(prefix->evpn.mac));
316 return ((struct pt_entry *)&pte_evpn);
317 default:
318 fatalx("pt_fill: unknown af");
319 }
320 }
321
322 struct pt_entry *
pt_get(struct bgpd_addr * prefix,int prefixlen)323 pt_get(struct bgpd_addr *prefix, int prefixlen)
324 {
325 struct pt_entry *pte;
326
327 pte = pt_fill(prefix, prefixlen);
328 return RB_FIND(pt_tree, &pttable, pte);
329 }
330
331 struct pt_entry *
pt_add(struct bgpd_addr * prefix,int prefixlen)332 pt_add(struct bgpd_addr *prefix, int prefixlen)
333 {
334 struct pt_entry *p = NULL;
335
336 p = pt_fill(prefix, prefixlen);
337 p = pt_alloc(p, p->len);
338
339 if (RB_INSERT(pt_tree, &pttable, p) != NULL)
340 fatalx("pt_add: insert failed");
341
342 return (p);
343 }
344
345 struct pt_entry *
pt_get_flow(struct flowspec * f)346 pt_get_flow(struct flowspec *f)
347 {
348 struct pt_entry *needle;
349 union {
350 struct pt_entry_flow flow;
351 uint8_t buf[4096];
352 } x;
353
354 needle = (struct pt_entry *)&x.flow;
355
356 memset(needle, 0, PT_FLOW_SIZE);
357 needle->aid = f->aid;
358 needle->len = f->len + PT_FLOW_SIZE;
359 memcpy(((struct pt_entry_flow *)needle)->flow, f->data, f->len);
360
361 return RB_FIND(pt_tree, &pttable, (struct pt_entry *)needle);
362 }
363
364 struct pt_entry *
pt_add_flow(struct flowspec * f)365 pt_add_flow(struct flowspec *f)
366 {
367 struct pt_entry *p;
368 int len = f->len + PT_FLOW_SIZE;
369
370 p = malloc(len);
371 if (p == NULL)
372 fatal(__func__);
373 rdemem.pt_cnt[f->aid]++;
374 rdemem.pt_size[f->aid] += len;
375 memset(p, 0, PT_FLOW_SIZE);
376
377 p->len = len;
378 p->aid = f->aid;
379 memcpy(((struct pt_entry_flow *)p)->flow, f->data, f->len);
380
381 if (RB_INSERT(pt_tree, &pttable, p) != NULL)
382 fatalx("pt_add: insert failed");
383
384 return (p);
385 }
386
387 void
pt_remove(struct pt_entry * pte)388 pt_remove(struct pt_entry *pte)
389 {
390 if (pte->refcnt != 0)
391 fatalx("pt_remove: entry still holds references");
392
393 if (RB_REMOVE(pt_tree, &pttable, pte) == NULL)
394 log_warnx("pt_remove: remove failed.");
395 pt_free(pte);
396 }
397
398 struct pt_entry *
pt_lookup(struct bgpd_addr * addr)399 pt_lookup(struct bgpd_addr *addr)
400 {
401 struct pt_entry *p;
402 int i;
403
404 switch (addr->aid) {
405 case AID_INET:
406 case AID_VPN_IPv4:
407 i = 32;
408 break;
409 case AID_INET6:
410 case AID_VPN_IPv6:
411 i = 128;
412 break;
413 default:
414 fatalx("pt_lookup: unknown af");
415 }
416 for (; i >= 0; i--) {
417 p = pt_get(addr, i);
418 if (p != NULL)
419 return (p);
420 }
421 return (NULL);
422 }
423
424 int
pt_prefix_cmp(const struct pt_entry * a,const struct pt_entry * b)425 pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b)
426 {
427 const struct pt_entry4 *a4, *b4;
428 const struct pt_entry6 *a6, *b6;
429 const struct pt_entry_vpn4 *va4, *vb4;
430 const struct pt_entry_vpn6 *va6, *vb6;
431 const struct pt_entry_flow *af, *bf;
432 const struct pt_entry_evpn *ea, *eb;
433 int i;
434
435 if (a->aid > b->aid)
436 return (1);
437 if (a->aid < b->aid)
438 return (-1);
439
440 switch (a->aid) {
441 case AID_INET:
442 a4 = (const struct pt_entry4 *)a;
443 b4 = (const struct pt_entry4 *)b;
444 if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr))
445 return (1);
446 if (ntohl(a4->prefix4.s_addr) < ntohl(b4->prefix4.s_addr))
447 return (-1);
448 if (a4->prefixlen > b4->prefixlen)
449 return (1);
450 if (a4->prefixlen < b4->prefixlen)
451 return (-1);
452 return (0);
453 case AID_INET6:
454 a6 = (const struct pt_entry6 *)a;
455 b6 = (const struct pt_entry6 *)b;
456
457 i = memcmp(&a6->prefix6, &b6->prefix6, sizeof(struct in6_addr));
458 if (i > 0)
459 return (1);
460 if (i < 0)
461 return (-1);
462 if (a6->prefixlen < b6->prefixlen)
463 return (-1);
464 if (a6->prefixlen > b6->prefixlen)
465 return (1);
466 return (0);
467 case AID_VPN_IPv4:
468 va4 = (const struct pt_entry_vpn4 *)a;
469 vb4 = (const struct pt_entry_vpn4 *)b;
470 if (be64toh(va4->rd) > be64toh(vb4->rd))
471 return (1);
472 if (be64toh(va4->rd) < be64toh(vb4->rd))
473 return (-1);
474 if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr))
475 return (1);
476 if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr))
477 return (-1);
478 if (va4->prefixlen > vb4->prefixlen)
479 return (1);
480 if (va4->prefixlen < vb4->prefixlen)
481 return (-1);
482 return (0);
483 case AID_VPN_IPv6:
484 va6 = (const struct pt_entry_vpn6 *)a;
485 vb6 = (const struct pt_entry_vpn6 *)b;
486 if (be64toh(va6->rd) > be64toh(vb6->rd))
487 return (1);
488 if (be64toh(va6->rd) < be64toh(vb6->rd))
489 return (-1);
490 i = memcmp(&va6->prefix6, &vb6->prefix6,
491 sizeof(struct in6_addr));
492 if (i > 0)
493 return (1);
494 if (i < 0)
495 return (-1);
496 if (va6->prefixlen > vb6->prefixlen)
497 return (1);
498 if (va6->prefixlen < vb6->prefixlen)
499 return (-1);
500 return (0);
501 case AID_EVPN:
502 /* XXXX Need different comparator for different types */
503 ea = (const struct pt_entry_evpn *)a;
504 eb = (const struct pt_entry_evpn *)b;
505 if (ea->ethtag > eb->ethtag)
506 return (1);
507 if (ea->ethtag < eb->ethtag)
508 return (-1);
509 /* MAC length is always 48 */
510 i = memcmp(&ea->mac, &eb->mac, sizeof(ea->mac));
511 if (i > 0)
512 return (1);
513 if (i < 0)
514 return (-1);
515 if (ea->prefixlen > eb->prefixlen)
516 return (1);
517 if (ea->prefixlen < eb->prefixlen)
518 return (-1);
519 switch (ea->vpnaid) {
520 case AID_UNSPEC:
521 break;
522 case AID_INET:
523 i = memcmp(&ea->prefix4, &eb->prefix4,
524 sizeof(struct in_addr));
525 if (i > 0)
526 return (1);
527 if (i < 0)
528 return (-1);
529 break;
530 case AID_INET6:
531 i = memcmp(&ea->prefix6, &eb->prefix6,
532 sizeof(struct in6_addr));
533 if (i > 0)
534 return (1);
535 if (i < 0)
536 return (-1);
537 break;
538 default:
539 fatalx("pt_prefix_cmp: unknown evpn af %d", ea->vpnaid);
540 }
541 return (0);
542 case AID_FLOWSPECv4:
543 case AID_FLOWSPECv6:
544 af = (const struct pt_entry_flow *)a;
545 bf = (const struct pt_entry_flow *)b;
546 return flowspec_cmp(af->flow, af->len - PT_FLOW_SIZE,
547 bf->flow, bf->len - PT_FLOW_SIZE,
548 a->aid == AID_FLOWSPECv6);
549 default:
550 fatalx("pt_prefix_cmp: unknown af %d", a->aid);
551 }
552 return (-1);
553 }
554
555 /*
556 * Returns a pt_entry cloned from the one passed in.
557 * Function may not return on failure.
558 */
559 static struct pt_entry *
pt_alloc(struct pt_entry * op,int len)560 pt_alloc(struct pt_entry *op, int len)
561 {
562 struct pt_entry *p;
563
564 p = malloc(len);
565 if (p == NULL)
566 fatal("pt_alloc");
567 rdemem.pt_cnt[op->aid]++;
568 rdemem.pt_size[op->aid] += len;
569 memcpy(p, op, len);
570 p->refcnt = 0;
571
572 return (p);
573 }
574
575 static void
pt_free(struct pt_entry * pte)576 pt_free(struct pt_entry *pte)
577 {
578 rdemem.pt_cnt[pte->aid]--;
579 rdemem.pt_size[pte->aid] -= pte->len;
580 free(pte);
581 }
582
583 /* dump a prefix into specified buffer */
584 int
pt_writebuf(struct ibuf * buf,struct pt_entry * pte,int withdraw,int add_path,uint32_t pathid)585 pt_writebuf(struct ibuf *buf, struct pt_entry *pte, int withdraw,
586 int add_path, uint32_t pathid)
587 {
588 struct pt_entry_vpn4 *pvpn4 = (struct pt_entry_vpn4 *)pte;
589 struct pt_entry_vpn6 *pvpn6 = (struct pt_entry_vpn6 *)pte;
590 struct pt_entry_flow *pflow = (struct pt_entry_flow *)pte;
591 struct pt_entry_evpn *pevpn = (struct pt_entry_evpn *)pte;
592 struct ibuf *tmp;
593 int flowlen, psize;
594 uint16_t plen;
595
596 if ((tmp = ibuf_dynamic(32, UINT16_MAX)) == NULL)
597 goto fail;
598
599 if (add_path) {
600 if (ibuf_add_n32(tmp, pathid) == -1)
601 goto fail;
602 }
603
604 switch (pte->aid) {
605 case AID_INET:
606 case AID_INET6:
607 plen = pte->prefixlen;
608 if (ibuf_add_n8(tmp, plen) == -1)
609 goto fail;
610 if (ibuf_add(tmp, pte->data, PREFIX_SIZE(plen) - 1) == -1)
611 goto fail;
612 break;
613 case AID_VPN_IPv4:
614 plen = pvpn4->prefixlen;
615 psize = PREFIX_SIZE(plen) - 1;
616 plen += sizeof(pvpn4->rd) * 8;
617 if (withdraw) {
618 /* withdraw have one compat label as placeholder */
619 plen += 3 * 8;
620 } else {
621 plen += pvpn4->labellen * 8;
622 }
623
624 if (ibuf_add_n8(tmp, plen) == -1)
625 goto fail;
626 if (withdraw) {
627 /* magic compatibility label as per rfc8277 */
628 if (ibuf_add_n8(tmp, 0x80) == -1 ||
629 ibuf_add_zero(tmp, 2) == -1)
630 goto fail;
631 } else {
632 if (ibuf_add(tmp, &pvpn4->labelstack,
633 pvpn4->labellen) == -1)
634 goto fail;
635 }
636 if (ibuf_add(tmp, &pvpn4->rd, sizeof(pvpn4->rd)) == -1 ||
637 ibuf_add(tmp, &pvpn4->prefix4, psize) == -1)
638 goto fail;
639 break;
640 case AID_VPN_IPv6:
641 plen = pvpn6->prefixlen;
642 psize = PREFIX_SIZE(plen) - 1;
643 plen += sizeof(pvpn6->rd) * 8;
644 if (withdraw) {
645 /* withdraw have one compat label as placeholder */
646 plen += 3 * 8;
647 } else {
648 plen += pvpn6->labellen * 8;
649 }
650
651 if (ibuf_add_n8(tmp, plen) == -1)
652 goto fail;
653 if (withdraw) {
654 /* magic compatibility label as per rfc8277 */
655 if (ibuf_add_n8(tmp, 0x80) == -1 ||
656 ibuf_add_zero(tmp, 2) == -1)
657 goto fail;
658 } else {
659 if (ibuf_add(tmp, &pvpn6->labelstack,
660 pvpn6->labellen) == -1)
661 goto fail;
662 }
663 if (ibuf_add(tmp, &pvpn6->rd, sizeof(pvpn6->rd)) == -1 ||
664 ibuf_add(tmp, &pvpn6->prefix6, psize) == -1)
665 goto fail;
666 break;
667 case AID_EVPN:
668 if (ibuf_add_n8(tmp, pevpn->type) == -1)
669 goto fail;
670 switch (pevpn->type) {
671 case EVPN_ROUTE_TYPE_2:
672 plen = sizeof(pevpn->rd) * 8;
673 plen += sizeof(pevpn->esi) * 8;
674 plen += sizeof(pevpn->ethtag) * 8;
675 plen += 8; /* MAC length */
676 plen += sizeof(pevpn->mac) * 8;
677 plen += 8; /* IP length */
678 plen += pevpn->prefixlen;
679 plen += pevpn->labellen * 8;
680 if (ibuf_add_n8(tmp, PREFIX_SIZE(plen) - 1) == -1)
681 goto fail;
682 if (ibuf_add_h64(tmp, pevpn->rd) == -1 ||
683 ibuf_add(tmp, pevpn->esi,
684 sizeof(pevpn->esi)) == -1 ||
685 ibuf_add_h32(tmp, pevpn->ethtag) == -1)
686 goto fail;
687 if (ibuf_add_n8(tmp, sizeof(pevpn->mac) * 8) == -1 ||
688 ibuf_add(tmp, pevpn->mac, sizeof(pevpn->mac)) == -1)
689 goto fail;
690 if (ibuf_add_n8(tmp, pevpn->prefixlen) == -1)
691 goto fail;
692 switch(pevpn->vpnaid) {
693 case AID_UNSPEC:
694 /* See rfc7432 section 7.2 */
695 break;
696 case AID_INET:
697 if (ibuf_add(tmp, &pevpn->prefix4,
698 sizeof(pevpn->prefix4)) == -1)
699 goto fail;
700 break;
701 case AID_INET6:
702 if (ibuf_add(tmp, &pevpn->prefix6,
703 sizeof(pevpn->prefix6)) == -1)
704 goto fail;
705 break;
706 default:
707 goto fail;
708 }
709 if (ibuf_add(tmp, pevpn->labelstack,
710 pevpn->labellen) == -1)
711 goto fail;
712 break;
713 case EVPN_ROUTE_TYPE_3:
714 plen = sizeof(pevpn->rd) * 8;
715 plen += sizeof(pevpn->ethtag) * 8;
716 plen += 8; /* IP length */
717 plen += pevpn->prefixlen;
718 if (ibuf_add_n8(tmp, PREFIX_SIZE(plen) - 1) == -1)
719 goto fail;
720 if (ibuf_add_h64(tmp, pevpn->rd) == -1 ||
721 ibuf_add_h32(tmp, pevpn->ethtag) == -1)
722 goto fail;
723 if (ibuf_add_n8(tmp, pevpn->prefixlen) == -1)
724 goto fail;
725 switch(pevpn->vpnaid) {
726 case AID_INET:
727 if (ibuf_add(tmp, &pevpn->prefix4,
728 sizeof(pevpn->prefix4)) == -1)
729 goto fail;
730 break;
731 case AID_INET6:
732 if (ibuf_add(tmp, &pevpn->prefix6,
733 sizeof(pevpn->prefix6)) == -1)
734 goto fail;
735 break;
736 default:
737 goto fail;
738 }
739 }
740 break;
741 case AID_FLOWSPECv4:
742 case AID_FLOWSPECv6:
743 flowlen = pflow->len - PT_FLOW_SIZE;
744 if (flowlen < FLOWSPEC_LEN_LIMIT) {
745 if (ibuf_add_n8(tmp, flowlen) == -1)
746 goto fail;
747 } else {
748 if (ibuf_add_n8(tmp, 0xf0 | (flowlen >> 8)) == -1 ||
749 ibuf_add_n8(tmp, flowlen) == -1)
750 goto fail;
751 }
752 if (ibuf_add(tmp, &pflow->flow, flowlen) == -1)
753 goto fail;
754 break;
755 default:
756 fatalx("%s: unknown aid %d", __func__, pte->aid);
757 }
758
759 /* keep 2 bytes reserved in the withdraw case for IPv4 encoding */
760 if (withdraw && ibuf_left(buf) < ibuf_size(tmp) + 2)
761 goto fail;
762 if (ibuf_add_ibuf(buf, tmp) == -1)
763 goto fail;
764 ibuf_free(tmp);
765 return 0;
766
767 fail:
768 ibuf_free(tmp);
769 return -1;
770 }
771