xref: /openbsd-src/usr.sbin/bgpd/rde_prefix.c (revision 560116d97c2c0a6e29edf4a595300c5a0b08f0d9)
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