From f7b381036b6fe56548a0642f4d449eaf23927501 Mon Sep 17 00:00:00 2001 From: claudio Date: Thu, 20 Apr 2023 12:53:27 +0000 Subject: [PATCH] Implement IMSG_CTL_SHOW_FLOWSPEC and IMSG_FLOWSPEC_FLUSH and add bits for IMSG_FLOWSPEC_ADD and IMSG_FLOWSPEC_REMOVE received from bgpctl via SE. OK tb@ --- usr.sbin/bgpd/bgpd.h | 4 +- usr.sbin/bgpd/control.c | 8 +- usr.sbin/bgpd/rde.c | 176 +++++++++++++++++++++++++++++++++++++++- usr.sbin/bgpd/session.c | 3 +- 4 files changed, 185 insertions(+), 6 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index b410d47b849..d0dd9850f65 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.473 2023/04/19 07:12:22 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.474 2023/04/20 12:53:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -599,6 +599,7 @@ enum imsg_type { IMSG_CTL_SHOW_RIB_COMMUNITIES, IMSG_CTL_SHOW_RIB_ATTR, IMSG_CTL_SHOW_NETWORK, + IMSG_CTL_SHOW_FLOWSPEC, IMSG_CTL_SHOW_RIB_MEM, IMSG_CTL_SHOW_TERSE, IMSG_CTL_SHOW_TIMER, @@ -616,6 +617,7 @@ enum imsg_type { IMSG_FLOWSPEC_ADD, IMSG_FLOWSPEC_DONE, IMSG_FLOWSPEC_REMOVE, + IMSG_FLOWSPEC_FLUSH, IMSG_FILTER_SET, IMSG_SOCKET_CONN, IMSG_SOCKET_CONN_CTL, diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c index a6248a074d2..fc516b8fd75 100644 --- a/usr.sbin/bgpd/control.c +++ b/usr.sbin/bgpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.109 2023/02/09 13:43:23 claudio Exp $ */ +/* $OpenBSD: control.c,v 1.110 2023/04/20 12:53:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -279,6 +279,7 @@ control_dispatch_msg(struct pollfd *pfd, struct peer_head *peers) case IMSG_CTL_SHOW_TERSE: case IMSG_CTL_SHOW_TIMER: case IMSG_CTL_SHOW_NETWORK: + case IMSG_CTL_SHOW_FLOWSPEC: case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_RIB_PREFIX: case IMSG_CTL_SHOW_SET: @@ -498,6 +499,7 @@ control_dispatch_msg(struct pollfd *pfd, struct peer_head *peers) imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_NETWORK: + case IMSG_CTL_SHOW_FLOWSPEC: c->terminate = 1; /* FALLTHROUGH */ case IMSG_CTL_SHOW_RIB_MEM: @@ -512,6 +514,10 @@ control_dispatch_msg(struct pollfd *pfd, struct peer_head *peers) case IMSG_NETWORK_REMOVE: case IMSG_NETWORK_FLUSH: case IMSG_NETWORK_DONE: + case IMSG_FLOWSPEC_ADD: + case IMSG_FLOWSPEC_REMOVE: + case IMSG_FLOWSPEC_DONE: + case IMSG_FLOWSPEC_FLUSH: case IMSG_FILTER_SET: imsg_ctl_rde(imsg.hdr.type, 0, 0, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index f71218a4042..1fecf6c5151 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.603 2023/04/19 13:23:33 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.604 2023/04/20 12:53:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -105,6 +105,9 @@ static void network_flush_upcall(struct rib_entry *, void *); void flowspec_add(struct flowspec *, struct filterstate *, struct filter_set_head *); void flowspec_delete(struct flowspec *); +static void flowspec_flush_upcall(struct rib_entry *, void *); +static void flowspec_dump_upcall(struct rib_entry *, void *); +static void flowspec_dump_done(void *, uint8_t); void rde_shutdown(void); static int ovs_match(struct prefix *, uint32_t); @@ -361,6 +364,7 @@ struct filter_set_head parent_set = TAILQ_HEAD_INITIALIZER(parent_set); void rde_dispatch_imsg_session(struct imsgbuf *ibuf) { + static struct flowspec *curflow; struct imsg imsg; struct rde_peer_stats stats; struct ctl_show_set cset; @@ -577,6 +581,97 @@ badnetdel: NULL, NULL) == -1) log_warn("rde_dispatch: IMSG_NETWORK_FLUSH"); break; + case IMSG_FLOWSPEC_ADD: + if (imsg.hdr.len - IMSG_HEADER_SIZE <= FLOWSPEC_SIZE) { + log_warnx("rde_dispatch: wrong imsg len"); + break; + } + if (curflow != NULL) { + log_warnx("rde_dispatch: " + "unexpected flowspec add"); + break; + } + curflow = malloc(imsg.hdr.len - IMSG_HEADER_SIZE); + if (curflow == NULL) + fatal(NULL); + memcpy(curflow, imsg.data, + imsg.hdr.len - IMSG_HEADER_SIZE); + if (curflow->len + FLOWSPEC_SIZE != + imsg.hdr.len - IMSG_HEADER_SIZE) { + free(curflow); + curflow = NULL; + log_warnx("rde_dispatch: wrong flowspec len"); + break; + } + rde_filterstate_init(&netconf_state); + asp = &netconf_state.aspath; + asp->aspath = aspath_get(NULL, 0); + asp->origin = ORIGIN_IGP; + asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH | + F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED | + F_ANN_DYNAMIC; + break; + case IMSG_FLOWSPEC_DONE: + if (curflow == NULL) { + log_warnx("rde_dispatch: " + "unexpected flowspec done"); + break; + } + + if (flowspec_valid(curflow->data, curflow->len, + curflow->aid == AID_FLOWSPECv6) == -1) + log_warnx("invalid flowspec update received " + "from bgpctl"); + else + flowspec_add(curflow, &netconf_state, + &session_set); + + rde_filterstate_clean(&netconf_state); + filterset_free(&session_set); + free(curflow); + curflow = NULL; + break; + case IMSG_FLOWSPEC_REMOVE: + if (imsg.hdr.len - IMSG_HEADER_SIZE <= FLOWSPEC_SIZE) { + log_warnx("rde_dispatch: wrong imsg len"); + break; + } + if (curflow != NULL) { + log_warnx("rde_dispatch: " + "unexpected flowspec remove"); + break; + } + curflow = malloc(imsg.hdr.len - IMSG_HEADER_SIZE); + if (curflow == NULL) + fatal(NULL); + memcpy(curflow, imsg.data, + imsg.hdr.len - IMSG_HEADER_SIZE); + if (curflow->len + FLOWSPEC_SIZE != + imsg.hdr.len - IMSG_HEADER_SIZE) { + free(curflow); + curflow = NULL; + log_warnx("rde_dispatch: wrong flowspec len"); + break; + } + + if (flowspec_valid(curflow->data, curflow->len, + curflow->aid == AID_FLOWSPECv6) == -1) + log_warnx("invalid flowspec withdraw received " + "from bgpctl"); + else + flowspec_delete(curflow); + + free(curflow); + curflow = NULL; + break; + case IMSG_FLOWSPEC_FLUSH: + if (imsg.hdr.len != IMSG_HEADER_SIZE) { + log_warnx("rde_dispatch: wrong imsg len"); + break; + } + prefix_flowspec_dump(AID_UNSPEC, NULL, + flowspec_flush_upcall, NULL); + break; case IMSG_FILTER_SET: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct filter_set)) { @@ -603,6 +698,15 @@ badnetdel: memcpy(&req, imsg.data, sizeof(req)); rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); break; + case IMSG_CTL_SHOW_FLOWSPEC: + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { + log_warnx("rde_dispatch: wrong imsg len"); + break; + } + memcpy(&req, imsg.data, sizeof(req)); + prefix_flowspec_dump(req.aid, &imsg.hdr.pid, + flowspec_dump_upcall, flowspec_dump_done); + break; case IMSG_CTL_SHOW_NEIGHBOR: if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { log_warnx("rde_dispatch: wrong imsg len"); @@ -893,12 +997,14 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) log_warnx("rde_dispatch: wrong flowspec len"); break; } + if (flowspec_valid(curflow->data, curflow->len, curflow->aid == AID_FLOWSPECv6) == -1) log_warnx("invalid flowspec withdraw received " "from parent"); else flowspec_delete(curflow); + free(curflow); curflow = NULL; break; @@ -4538,8 +4644,7 @@ network_dump_upcall(struct rib_entry *re, void *ptr) kf.flags = F_STATIC; if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0, ctx->req.pid, -1, &kf, sizeof(kf)) == -1) - log_warnx("network_dump_upcall: " - "imsg_compose error"); + log_warnx("%s: imsg_compose error", __func__); } } @@ -4609,6 +4714,71 @@ flowspec_delete(struct flowspec *f) peerself->stats.prefix_cnt--; } +static void +flowspec_flush_upcall(struct rib_entry *re, void *ptr) +{ + struct prefix *p; + + p = prefix_bypeer(re, peerself, 0); + if (p == NULL) + return; + if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC) + return; + if (prefix_flowspec_withdraw(peerself, re->prefix) == 1) + peerself->stats.prefix_cnt--; +} + +static void +flowspec_dump_upcall(struct rib_entry *re, void *ptr) +{ + pid_t *pid = ptr; + struct prefix *p; + struct rde_aspath *asp; + struct rde_community *comm; + struct flowspec ff; + struct ibuf *ibuf; + uint8_t *flow; + int len; + + TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) { + asp = prefix_aspath(p); + if (!(asp->flags & F_PREFIX_ANNOUNCED)) + continue; + comm = prefix_communities(p); + + len = pt_getflowspec(p->pt, &flow); + + memset(&ff, 0, sizeof(ff)); + ff.aid = p->pt->aid; + ff.len = len; + if ((asp->flags & F_ANN_DYNAMIC) == 0) + ff.flags = F_STATIC; + if ((ibuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_FLOWSPEC, 0, + *pid, FLOWSPEC_SIZE + len)) == NULL) + continue; + if (imsg_add(ibuf, &ff, FLOWSPEC_SIZE) == -1 || + imsg_add(ibuf, flow, len) == -1) + continue; + imsg_close(ibuf_se_ctl, ibuf); + if (comm->nentries > 0) { + if (imsg_compose(ibuf_se_ctl, + IMSG_CTL_SHOW_RIB_COMMUNITIES, 0, *pid, -1, + comm->communities, + comm->nentries * sizeof(struct community)) == -1) + continue; + } + } +} + +static void +flowspec_dump_done(void *ptr, uint8_t aid) +{ + pid_t *pid = ptr; + + imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, *pid, -1, NULL, 0); +} + + /* clean up */ void rde_shutdown(void) diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 68e76737d12..137fda97619 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.442 2023/03/09 13:12:19 claudio Exp $ */ +/* $OpenBSD: session.c,v 1.443 2023/04/20 12:53:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -3205,6 +3205,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) case IMSG_CTL_SHOW_RIB_ATTR: case IMSG_CTL_SHOW_RIB_MEM: case IMSG_CTL_SHOW_NETWORK: + case IMSG_CTL_SHOW_FLOWSPEC: case IMSG_CTL_SHOW_SET: if (idx != PFD_PIPE_ROUTE_CTL) fatalx("ctl rib request not from RDE"); -- 2.20.1