Implement IMSG_CTL_SHOW_FLOWSPEC and IMSG_FLOWSPEC_FLUSH and add bits for
authorclaudio <claudio@openbsd.org>
Thu, 20 Apr 2023 12:53:27 +0000 (12:53 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 20 Apr 2023 12:53:27 +0000 (12:53 +0000)
IMSG_FLOWSPEC_ADD and IMSG_FLOWSPEC_REMOVE received from bgpctl via SE.
OK tb@

usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/control.c
usr.sbin/bgpd/rde.c
usr.sbin/bgpd/session.c

index b410d47..d0dd985 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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,
index a6248a0..fc516b8 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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);
index f71218a..1fecf6c 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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)
index 68e7673..137fda9 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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");