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.
There is a hack in pt_getaddr() to return something. This is the
destination prefix of the flowspec rule (or a default route if that is
missing). Also extend pt_write() to handle flowspec NLRI.
--
:wq Claudio
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.291
diff -u -p -r1.291 rde.h
--- rde.h 7 Apr 2023 13:49:03 -0000 1.291
+++ rde.h 18 Apr 2023 13:18:48 -0000
@@ -512,9 +512,12 @@ enum filter_actions rde_filter(struct fi
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 *);
Index: rde_prefix.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_prefix.c,v
retrieving revision 1.48
diff -u -p -r1.48 rde_prefix.c
--- rde_prefix.c 30 Mar 2023 13:25:23 -0000 1.48
+++ rde_prefix.c 18 Apr 2023 13:18:48 -0000
@@ -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
((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 pre
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_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,
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
{
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
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_
{
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) {
@@ -486,6 +591,12 @@ pt_writebuf(struct ibuf *buf, struct pt_
case AID_VPN_IPv6:
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);