From 689ec283927616e99845e92a74e05263b4f954d8 Mon Sep 17 00:00:00 2001 From: claudio Date: Wed, 19 Apr 2023 07:09:47 +0000 Subject: [PATCH] Extend the pt_entry api to handle flowspec. Introduce pt_get_flow() and pt_add_flow() to lookup and insert flowspec objects. Add pt_getflowspec() which works somewhat similar to pt_getaddr() to extract the flowspec NLRI from a pt_entry. Make pt_getaddr() to return the destination prefix of the flowspec rule and handle flowspec in pt_write(). OK tb@ --- usr.sbin/bgpd/rde.h | 5 +- usr.sbin/bgpd/rde_prefix.c | 117 ++++++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 4 deletions(-) diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index f244749d068..7660312d275 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.291 2023/04/07 13:49:03 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.292 2023/04/19 07:09:47 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -512,9 +512,12 @@ enum filter_actions rde_filter(struct filter_head *, struct rde_peer *, void pt_init(void); void pt_shutdown(void); void pt_getaddr(struct pt_entry *, struct bgpd_addr *); +int pt_getflowspec(struct pt_entry *, uint8_t **); struct pt_entry *pt_fill(struct bgpd_addr *, int); struct pt_entry *pt_get(struct bgpd_addr *, int); struct pt_entry *pt_add(struct bgpd_addr *, int); +struct pt_entry *pt_get_flow(struct flowspec *); +struct pt_entry *pt_add_flow(struct flowspec *); void pt_remove(struct pt_entry *); struct pt_entry *pt_lookup(struct bgpd_addr *); int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); diff --git a/usr.sbin/bgpd/rde_prefix.c b/usr.sbin/bgpd/rde_prefix.c index 60990b849db..2466018faef 100644 --- a/usr.sbin/bgpd/rde_prefix.c +++ b/usr.sbin/bgpd/rde_prefix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_prefix.c,v 1.48 2023/03/30 13:25:23 claudio Exp $ */ +/* $OpenBSD: rde_prefix.c,v 1.49 2023/04/19 07:09:47 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -95,6 +95,17 @@ struct pt_entry_vpn6 { uint8_t pad2; }; +struct pt_entry_flow { + RB_ENTRY(pt_entry) pt_e; + uint8_t aid; + uint8_t prefixlen; /* unused ??? */ + uint16_t len; + uint32_t refcnt; + uint64_t rd; + uint8_t flow[1]; /* NLRI */ +}; + +#define PT_FLOW_SIZE (offsetof(struct pt_entry_flow, flow)) RB_HEAD(pt_tree, pt_entry); RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); @@ -118,6 +129,8 @@ pt_shutdown(void) void pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) { + struct pt_entry_flow *pflow; + memset(addr, 0, sizeof(struct bgpd_addr)); addr->aid = pte->aid; switch (addr->aid) { @@ -144,11 +157,34 @@ pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) ((struct pt_entry_vpn6 *)pte)->labelstack, addr->labellen); break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + pflow = (struct pt_entry_flow *)pte; + flowspec_get_addr(pflow->flow, pflow->len - PT_FLOW_SIZE, + FLOWSPEC_TYPE_DEST, addr->aid == AID_FLOWSPECv6, + addr, &pflow->prefixlen, NULL); + break; default: fatalx("pt_getaddr: unknown af"); } } +int +pt_getflowspec(struct pt_entry *pte, uint8_t **flow) +{ + struct pt_entry_flow *pflow; + + switch (pte->aid) { + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + pflow = (struct pt_entry_flow *)pte; + *flow = pflow->flow; + return pflow->len - PT_FLOW_SIZE; + default: + fatalx("pt_getflowspec: unknown af"); + } +} + struct pt_entry * pt_fill(struct bgpd_addr *prefix, int prefixlen) { @@ -234,6 +270,48 @@ pt_add(struct bgpd_addr *prefix, int prefixlen) return (p); } +struct pt_entry * +pt_get_flow(struct flowspec *f) +{ + struct pt_entry *needle; + union { + struct pt_entry_flow flow; + uint8_t buf[4096]; + } x; + + needle = (struct pt_entry *)&x.flow; + + memset(needle, 0, PT_FLOW_SIZE); + needle->aid = f->aid; + needle->len = f->len + PT_FLOW_SIZE; + memcpy(((struct pt_entry_flow *)needle)->flow, f->data, f->len); + + return RB_FIND(pt_tree, &pttable, (struct pt_entry *)needle); +} + +struct pt_entry * +pt_add_flow(struct flowspec *f) +{ + struct pt_entry *p; + int len = f->len + PT_FLOW_SIZE; + + p = malloc(len); + if (p == NULL) + fatal(__func__); + rdemem.pt_cnt[f->aid]++; + rdemem.pt_size[f->aid] += len; + memset(p, 0, PT_FLOW_SIZE); + + p->len = len; + p->aid = f->aid; + memcpy(((struct pt_entry_flow *)p)->flow, f->data, f->len); + + if (RB_INSERT(pt_tree, &pttable, p) != NULL) + fatalx("pt_add: insert failed"); + + return (p); +} + void pt_remove(struct pt_entry *pte) { @@ -278,6 +356,7 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) const struct pt_entry6 *a6, *b6; const struct pt_entry_vpn4 *va4, *vb4; const struct pt_entry_vpn6 *va6, *vb6; + const struct pt_entry_flow *af, *bf; int i; if (a->aid > b->aid) @@ -346,6 +425,13 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) if (va6->prefixlen < vb6->prefixlen) return (-1); return (0); + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + af = (const struct pt_entry_flow *)a; + bf = (const struct pt_entry_flow *)b; + return flowspec_cmp(af->flow, af->len - PT_FLOW_SIZE, + bf->flow, bf->len - PT_FLOW_SIZE, + a->aid == AID_FLOWSPECv6); default: fatalx("pt_prefix_cmp: unknown af"); } @@ -386,7 +472,8 @@ pt_write(u_char *buf, int len, struct pt_entry *pte, int withdraw) { struct pt_entry_vpn4 *pvpn4 = (struct pt_entry_vpn4 *)pte; struct pt_entry_vpn6 *pvpn6 = (struct pt_entry_vpn6 *)pte; - int totlen, psize; + struct pt_entry_flow *pflow = (struct pt_entry_flow *)pte; + int totlen, flowlen, psize; uint8_t plen; switch (pte->aid) { @@ -460,6 +547,23 @@ pt_write(u_char *buf, int len, struct pt_entry *pte, int withdraw) buf += sizeof(pvpn6->rd); memcpy(buf, &pvpn6->prefix6, psize); return (totlen); + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + flowlen = pflow->len - PT_FLOW_SIZE; + totlen = flowlen < FLOWSPEC_LEN_LIMIT ? 1 : 2; + totlen += flowlen; + + if (totlen > len) + return (-1); + + if (flowlen < FLOWSPEC_LEN_LIMIT) { + *buf++ = flowlen; + } else { + *buf++ = 0xf0 | (flowlen >> 8); + *buf++ = flowlen & 0xff; + } + memcpy(buf, &pflow->flow, flowlen); + return (totlen); default: return (-1); } @@ -471,7 +575,8 @@ pt_writebuf(struct ibuf *buf, struct pt_entry *pte) { struct pt_entry_vpn4 *pvpn4 = (struct pt_entry_vpn4 *)pte; struct pt_entry_vpn6 *pvpn6 = (struct pt_entry_vpn6 *)pte; - int totlen; + struct pt_entry_flow *pflow = (struct pt_entry_flow *)pte; + int totlen, flowlen; void *bptr; switch (pte->aid) { @@ -487,6 +592,12 @@ pt_writebuf(struct ibuf *buf, struct pt_entry *pte) totlen = PREFIX_SIZE(pte->prefixlen) + sizeof(pvpn6->rd) + pvpn6->labellen; break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + flowlen = pflow->len - PT_FLOW_SIZE; + totlen = flowlen < FLOWSPEC_LEN_LIMIT ? 1 : 2; + totlen += flowlen; + break; default: return (-1); } -- 2.20.1