Dear all,

The below is based on feedback from Sebastian Benoit, Theo de Raadt,
and Peter Hessler. The patch adds less lines of code, and adheres
better to style(9). Thank you for your time.

Kind regards,

Job


Index: bgpctl/bgpctl.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.8,v
retrieving revision 1.71
diff -u -p -r1.71 bgpctl.8
--- bgpctl/bgpctl.8     26 Oct 2016 17:24:13 -0000      1.71
+++ bgpctl/bgpctl.8     9 Jan 2017 21:52:31 -0000
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: October 26 2016 $
+.Dd $Mdocdate: January 9 2017 $
 .Dt BGPCTL 8
 .Os
 .Sh NAME
@@ -104,8 +104,14 @@ Destroy a previously cloned peer.
 The peer must be down before calling this function.
 .Ar peer
 may be the neighbor's address or description.
-.It Cm neighbor Ar peer Cm down
-Take the BGP session to the specified neighbor down.
+.It Cm neighbor Ar peer Cm down Op Ar reason
+Take the BGP session to the specified neighbor down. If a
+.Ar reason
+is provided, the
+.Ar reason
+is sent as Administrative Shutdown Communication to the neighbor. The
+.Ar reason
+cannot exceed 128 octets.
 .Ar peer
 may be the neighbor's address or description.
 .It Cm neighbor Ar peer Cm refresh
Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.190
diff -u -p -r1.190 bgpctl.c
--- bgpctl/bgpctl.c     14 Oct 2016 16:05:35 -0000      1.190
+++ bgpctl/bgpctl.c     9 Jan 2017 21:52:31 -0000
@@ -162,6 +162,7 @@ main(int argc, char *argv[])
 
        memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
        strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
+       strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm));
 
        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
                err(1, "control_init: socket");
@@ -722,6 +723,13 @@ show_neighbor_msg(struct imsg *imsg, enu
                    inet_ntoa(ina));
                printf("%s\n", print_auth_method(p->auth.method));
                printf("  BGP state = %s", statenames[p->state]);
+               if (p->conf.down) {
+                       printf(", marked down");
+                       if (*(p->conf.shutcomm)) {
+                               printf(" with shutdown reason \"%s\"",
+                                   log_shutcomm(p->conf.shutcomm));
+                       }
+               }
                if (p->stats.last_updown != 0)
                        printf(", %s for %s",
                            p->state == STATE_ESTABLISHED ? "up" : "down",
@@ -756,6 +764,10 @@ show_neighbor_msg(struct imsg *imsg, enu
                        break;
                print_neighbor_msgstats(p);
                printf("\n");
+               if (*(p->stats.last_shutcomm)) {
+                       printf("  Last received shutdown reason: \"%s\"\n",
+                           log_shutcomm(p->stats.last_shutcomm));
+               }
                if (p->state == STATE_IDLE) {
                        static const char       *errstr;
 
Index: bgpctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
retrieving revision 1.74
diff -u -p -r1.74 parser.c
--- bgpctl/parser.c     14 Oct 2016 16:05:35 -0000      1.74
+++ bgpctl/parser.c     9 Jan 2017 21:52:31 -0000
@@ -45,6 +45,7 @@ enum token_type {
        PREFIX,
        PEERDESC,
        RIBNAME,
+       SHUTDOWN_COMMUNICATION,
        COMMUNITY,
        LARGE_COMMUNITY,
        LOCALPREF,
@@ -245,9 +246,15 @@ static const struct token t_neighbor[] =
        { ENDTOKEN,     "",             NONE,           NULL}
 };
 
+static const struct token t_nei_mod_shutc[] = {
+       { NOTOKEN,      "",             NONE,           NULL},
+       { SHUTDOWN_COMMUNICATION,       "",             NONE,           NULL},
+       { ENDTOKEN,     "",             NONE,           NULL}
+};
+
 static const struct token t_neighbor_modifiers[] = {
        { KEYWORD,      "up",           NEIGHBOR_UP,            NULL},
-       { KEYWORD,      "down",         NEIGHBOR_DOWN,          NULL},
+       { KEYWORD,      "down",         NEIGHBOR_DOWN,          
t_nei_mod_shutc},
        { KEYWORD,      "clear",        NEIGHBOR_CLEAR,         NULL},
        { KEYWORD,      "refresh",      NEIGHBOR_RREFRESH,      NULL},
        { KEYWORD,      "destroy",      NEIGHBOR_DESTROY,       NULL},
@@ -571,6 +578,16 @@ match_token(int *argc, char **argv[], co
                                t = &table[i];
                        }
                        break;
+               case SHUTDOWN_COMMUNICATION:
+                       if (!match && word != NULL && wordlen > 0) {
+                               if (strlcpy(res.shutcomm, word,
+                                       sizeof(res.shutcomm)) >=
+                                       sizeof(res.shutcomm))
+                                       errx(1, "shutdown reason too long");
+                               match++;
+                               t = &table[i];
+                       }
+                       break;
                case COMMUNITY:
                        if (word != NULL && wordlen > 0 &&
                            parse_community(word, &res)) {
@@ -693,6 +710,9 @@ show_valid_args(const struct token table
                        break;
                case RIBNAME:
                        fprintf(stderr, "  <rib name>\n");
+                       break;
+               case SHUTDOWN_COMMUNICATION:
+                       fprintf(stderr, "  <shutdown reason>\n");
                        break;
                case COMMUNITY:
                        fprintf(stderr, "  <community>\n");
Index: bgpctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
retrieving revision 1.28
diff -u -p -r1.28 parser.h
--- bgpctl/parser.h     14 Oct 2016 16:05:35 -0000      1.28
+++ bgpctl/parser.h     9 Jan 2017 21:52:31 -0000
@@ -66,6 +66,7 @@ struct parse_result {
        struct filter_largecommunity  large_community;
        char                     peerdesc[PEER_DESCR_LEN];
        char                     rib[PEER_DESCR_LEN];
+       char                     shutcomm[SHUT_COMM_LEN];
        char                    *irr_outdir;
        int                      flags;
        u_int                    rtableid;
Index: bgpd/bgpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v
retrieving revision 1.50
diff -u -p -r1.50 bgpd.8
--- bgpd/bgpd.8 10 Nov 2016 10:01:33 -0000      1.50
+++ bgpd/bgpd.8 9 Jan 2017 21:52:31 -0000
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: November 10 2016 $
+.Dd $Mdocdate: January 9 2017 $
 .Dt BGPD 8
 .Os
 .Sh NAME
@@ -238,17 +238,6 @@ control socket
 .Re
 .Pp
 .Rs
-.%A J. Snijders
-.%A J. Heitz
-.%A K. Patel
-.%A I. Bagdonas
-.%A A. Simpson
-.%D September 2016
-.%R draft-ietf-idr-large-community
-.%T Large BGP Communities Attribute
-.Re
-.Pp
-.Rs
 .%A A. Heffernan
 .%D August 1998
 .%R RFC 2385
@@ -380,6 +369,26 @@ control socket
 .%D May 2012
 .%R RFC 6608
 .%T Subcodes for BGP Finite State Machine Error
+.Re
+.Pp
+.Rs
+.%A J. Snijders
+.%A J. Heitz
+.%A K. Patel
+.%A I. Bagdonas
+.%A N. Hilliard
+.%D January 2017
+.%R draft-ietf-idr-large-community
+.%T Large BGP Communities Attribute
+.Re
+.Pp
+.Rs
+.%A J. Snijders
+.%A J. Heitz
+.%A J. Scudder
+.%D January 2017
+.%R draft-ietf-idr-shutdown
+.%T BGP Administrative Shutdown Communication
 .Re
 .Sh HISTORY
 The
Index: bgpd/bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.151
diff -u -p -r1.151 bgpd.conf.5
--- bgpd/bgpd.conf.5    30 Oct 2016 16:50:22 -0000      1.151
+++ bgpd/bgpd.conf.5    9 Jan 2017 21:52:31 -0000
@@ -737,9 +737,17 @@ The description is used when logging nei
 reports, for specifying neighbors, etc., but has no further meaning to
 .Xr bgpd 8 .
 .Pp
-.It Ic down
+.It Ic down Op Ar reason
 Do not start the session when bgpd comes up but stay in
 .Em IDLE .
+If the session is cleared at runtime, after a
+.Ic down
+.Ar reason
+was configured at runtime, the
+.Ar reason
+is sent as Administrative Shutdown Communication. The
+.Ar reason
+cannot exceed 128 octets.
 .Pp
 .It Xo
 .Ic dump
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.297
diff -u -p -r1.297 bgpd.h
--- bgpd/bgpd.h 14 Oct 2016 16:05:35 -0000      1.297
+++ bgpd/bgpd.h 9 Jan 2017 21:52:31 -0000
@@ -40,6 +40,7 @@
 #define        CONFFILE                        "/etc/bgpd.conf"
 #define        BGPD_USER                       "_bgpd"
 #define        PEER_DESCR_LEN                  32
+#define        SHUT_COMM_LEN                   129
 #define        PFTABLE_LEN                     32
 #define        TCP_MD5_KEY_LEN                 80
 #define        IPSEC_ENC_KEY_LEN               32
@@ -299,6 +300,7 @@ struct peer_config {
        struct capabilities      capabilities;
        char                     group[PEER_DESCR_LEN];
        char                     descr[PEER_DESCR_LEN];
+       char                     shutcomm[SHUT_COMM_LEN];
        char                     rib[PEER_DESCR_LEN];
        char                     if_depend[IFNAMSIZ];
        char                     demote_group[IFNAMSIZ];
@@ -586,6 +588,7 @@ struct ctl_show_nexthop {
 struct ctl_neighbor {
        struct bgpd_addr        addr;
        char                    descr[PEER_DESCR_LEN];
+       char                    shutcomm[SHUT_COMM_LEN];
        int                     show_timers;
 };
 
@@ -1084,6 +1087,7 @@ const char        *log_sockaddr(struct sockaddr
 const char     *log_as(u_int32_t);
 const char     *log_rd(u_int64_t);
 const char     *log_ext_subtype(u_int8_t);
+const char     *log_shutcomm(const char *);
 int             aspath_snprint(char *, size_t, void *, u_int16_t);
 int             aspath_asprint(char **, void *, u_int16_t);
 size_t          aspath_strlen(void *, u_int16_t);
Index: bgpd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.84
diff -u -p -r1.84 control.c
--- bgpd/control.c      8 Jan 2017 23:04:42 -0000       1.84
+++ bgpd/control.c      9 Jan 2017 21:52:31 -0000
@@ -340,9 +340,15 @@ control_dispatch_msg(struct pollfd *pfd,
                                switch (imsg.hdr.type) {
                                case IMSG_CTL_NEIGHBOR_UP:
                                        bgp_fsm(p, EVNT_START);
+                                       p->conf.down = 0;
+                                       p->conf.shutcomm[0] = '\0';
                                        control_result(c, CTL_RES_OK);
                                        break;
                                case IMSG_CTL_NEIGHBOR_DOWN:
+                                       p->conf.down = 1;
+                                       strlcpy(p->conf.shutcomm,
+                                           neighbor->shutcomm,
+                                           sizeof(neighbor->shutcomm));
                                        session_stop(p, ERR_CEASE_ADMIN_DOWN);
                                        control_result(c, CTL_RES_OK);
                                        break;
Index: bgpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.293
diff -u -p -r1.293 parse.y
--- bgpd/parse.y        5 Jan 2017 13:53:09 -0000       1.293
+++ bgpd/parse.y        9 Jan 2017 21:52:31 -0000
@@ -1052,8 +1052,19 @@ peeropts : REMOTEAS as4number    {
                | PASSIVE               {
                        curpeer->conf.passive = 1;
                }
-               | DOWN          {
+               | DOWN                  {
                        curpeer->conf.down = 1;
+               }
+               | DOWN STRING           {
+                       curpeer->conf.down = 1;
+                       if (strlcpy(curpeer->conf.shutcomm, $2,
+                               sizeof(curpeer->conf.shutcomm)) >=
+                               sizeof(curpeer->conf.shutcomm)) {
+                                   yyerror("shutdown reason too long");
+                                   free($2);
+                                   YYERROR;
+                       }
+                       free($2);
                }
                | RIB STRING    {
                        if (!find_rib($2)) {
Index: bgpd/session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.356
diff -u -p -r1.356 session.c
--- bgpd/session.c      19 Dec 2016 07:19:55 -0000      1.356
+++ bgpd/session.c      9 Jan 2017 21:52:31 -0000
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 2003, 2004, 2005 Henning Brauer <henn...@openbsd.org>
+ * Copyright (c) 2017 Peter van Dijk <peter.van.d...@powerdns.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -571,6 +572,9 @@ session_main(int debug, int verbose)
 
        while ((p = peers) != NULL) {
                peers = p->next;
+               strlcpy(p->conf.shutcomm,
+                   "bgpd shutting down",
+                   sizeof(p->conf.shutcomm));
                session_stop(p, ERR_CEASE_ADMIN_DOWN);
                pfkey_remove(p);
                free(p);
@@ -2221,6 +2225,7 @@ parse_notification(struct peer *peer)
        u_int8_t         subcode;
        u_int8_t         capa_code;
        u_int8_t         capa_len;
+       u_int8_t         shutcomm_len;
        u_int8_t         i;
 
        /* just log */
@@ -2315,6 +2320,31 @@ parse_notification(struct peer *peer)
                return (1);
        }
 
+       if (errcode == ERR_CEASE && subcode == ERR_CEASE_ADMIN_DOWN) {
+               if (datalen >= sizeof(shutcomm_len)) {
+                       memcpy(&shutcomm_len, p, sizeof(shutcomm_len));
+                       p += sizeof(shutcomm_len);
+                       datalen -= sizeof(shutcomm_len);
+                       if(datalen < shutcomm_len) {
+                           log_peer_warnx(&peer->conf,
+                               "received truncated shutdown reason");
+                           return (0);
+                       }
+                       if (shutcomm_len > (SHUT_COMM_LEN-1)) {
+                           log_peer_warnx(&peer->conf,
+                               "received overly long shutdown reason");
+                           return (0);
+                       }
+                       memcpy(peer->stats.last_shutcomm, p, shutcomm_len);
+                       peer->stats.last_shutcomm[shutcomm_len] = '\0';
+                       log_peer_warnx(&peer->conf,
+                           "received shutdown reason: \"%s\"",
+                           log_shutcomm(peer->stats.last_shutcomm));
+                       p += shutcomm_len;
+                       datalen -= shutcomm_len;
+               }
+       }
+
        return (0);
 }
 
@@ -3195,11 +3225,29 @@ session_demote(struct peer *p, int level
 void
 session_stop(struct peer *peer, u_int8_t subcode)
 {
+       char data[SHUT_COMM_LEN];
+       uint8_t datalen;
+       uint8_t shutcomm_len;
+       char *communication;
+
+       datalen = 0;
+
+       communication = peer->conf.shutcomm;
+
+       if (subcode == ERR_CEASE_ADMIN_DOWN && communication &&
+           *communication) {
+               shutcomm_len = strlen(communication);
+               if(shutcomm_len < SHUT_COMM_LEN) {
+                       data[0] = shutcomm_len;
+                       datalen = shutcomm_len + sizeof(data[0]);
+                       memcpy(data + 1, communication, shutcomm_len);
+               }
+       }
        switch (peer->state) {
        case STATE_OPENSENT:
        case STATE_OPENCONFIRM:
        case STATE_ESTABLISHED:
-               session_notification(peer, ERR_CEASE, subcode, NULL, 0);
+               session_notification(peer, ERR_CEASE, subcode, data, datalen);
                break;
        default:
                /* session not open, no need to send notification */
Index: bgpd/session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.121
diff -u -p -r1.121 session.h
--- bgpd/session.h      25 Oct 2015 18:49:01 -0000      1.121
+++ bgpd/session.h      9 Jan 2017 21:52:31 -0000
@@ -168,6 +168,7 @@ struct peer_stats {
        u_int32_t                prefix_cnt;
        u_int8_t                 last_sent_errcode;
        u_int8_t                 last_sent_suberr;
+       char                     last_shutcomm[SHUT_COMM_LEN];
 };
 
 enum Timer {
Index: bgpd/util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.21
diff -u -p -r1.21 util.c
--- bgpd/util.c 3 Jun 2016 17:36:37 -0000       1.21
+++ bgpd/util.c 9 Jan 2017 21:52:31 -0000
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <vis.h>
 
 #include "bgpd.h"
 #include "rde.h"
@@ -156,6 +157,15 @@ log_ext_subtype(u_int8_t subtype)
                snprintf(etype, sizeof(etype), "[%u]", subtype);
                return (etype);
        }
+}
+
+const char *
+log_shutcomm(const char *communication) {
+       static char buf[(SHUT_COMM_LEN - 1) * 4 + 1];
+
+       strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
+
+       return buf;
 }
 
 const char *

Reply via email to