Decode BGP Shutdown Communication messages (RFC 8203)
Hi all, Here is a patch to decode received BGP shutdown communication messages as specified in RFC 8203. In the following example scenario I'm sending a shutdown communication with openbgpd: $ bgpctl neighbor 94.142.241.204 down "TICKET-2331 we are upgrading, back in 30 min" request processed And can subsequently observe the message via logging and via 'show protocols all': job@irime:~/source/bird$ sudo ./bird -s test.sock -d -c bird2.conf bird: Started bird: bgp1: Received: Administrative shutdown: "TICKET-2331 we are upgrading, back in 30 min" job@irime:~/source/bird$ sudo ./birdc -s test.sock show protocols all .... BGP state: Active Neighbor address: 165.254.255.26 Neighbor AS: 15562 Connect delay: 3/5 Last error: Received: Administrative shutdown Message: "TICKET-2331 we are upgrading, back in 30 min" As for the remaining RFC 8203 work: I could use some help with _sending_ bgp shutdown communication messages. It is not clear to me where I should hook the message into the config/cli infrastructure. Ideally you can do things like: $ birdc disable bgp1 "hi, we will upgrade to bird 1.6.4" or via the configuration (also during reconfigure): protocol bgp { disabled "shutdown due to maintenance ticket 2424"; description "My BGP uplink"; local 94.142.241.204 as 65000; neighbor 165.254.255.26 as 15562; } Thoughts? Kind regards, Job --- proto/bgp/bgp.c | 13 ++++++++++ proto/bgp/bgp.h | 2 ++ proto/bgp/packets.c | 73 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f706e76..551b156 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1487,6 +1487,16 @@ bgp_last_errmsg(struct bgp_proto *p) } static const char * +bgp_last_shutmsg(struct bgp_proto *p) +{ + unsigned len; + char *buf = calloc (128, sizeof (char)); + len = p->last_received_shutmsg[0]; + bsnprintf(buf, len, "%s", p->last_received_shutmsg+1); + return(buf); +} + +static const char * bgp_state_dsc(struct bgp_proto *p) { if (p->p.proto_state == PS_DOWN) @@ -1580,7 +1590,10 @@ bgp_show_proto_info(struct proto *P) { const char *err1 = bgp_err_classes[p->last_error_class]; const char *err2 = bgp_last_errmsg(p); + const char *msg = bgp_last_shutmsg(p); cli_msg(-1006, " Last error: %s%s", err1, err2); + if (p->last_received_shutmsg[0] > 0) + cli_msg(-1006, " Message: \"%s\"", msg); } } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e47a0eb..d958716 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -157,6 +157,8 @@ struct bgp_proto { u8 last_error_class; /* Error class of last error */ u32 last_error_code; /* Error code of last error. BGP protocol errors are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ + byte last_received_shutmsg[129]; /* RFC 8203 */ + #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ab87bdc..1a021dd 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1460,9 +1460,9 @@ static struct { { 5, 3, "Unexpected message in Established state" }, { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */ { 6, 1, "Maximum number of prefixes reached" }, - { 6, 2, "Administrative shutdown" }, + { 6, 2, "Administrative shutdown" }, /* RFC 8203 can follow */ { 6, 3, "Peer de-configured" }, - { 6, 4, "Administrative reset" }, + { 6, 4, "Administrative reset" }, /* RFC 8203 can follow */ { 6, 5, "Connection rejected" }, { 6, 6, "Other configuration change" }, { 6, 7, "Connection collision resolution" }, @@ -1497,35 +1497,56 @@ bgp_error_dsc(unsigned code, unsigned subcode) void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len) { - const byte *name; - byte *t, argbuf[36]; - unsigned i; + const byte *name; + byte *t, argbuf[256]; + unsigned i; + unsigned shutdown_comm_length; - /* Don't report Cease messages generated by myself */ - if (code == 6 && class == BE_BGP_TX) - return; + /* Don't report Cease messages generated by myself */ + if (code == 6 && class == BE_BGP_TX) + return; + + name = bgp_error_dsc(code, subcode); + t = argbuf; + memset(p->last_received_shutmsg, 0, 129); // clear old RFC 8203 messages - name = bgp_error_dsc(code, subcode); - t = argbuf; - if (len) + if (len) { - *t++ = ':'; - *t++ = ' '; + *t++ = ':'; + *t++ = ' '; - if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) - { - /* Bad peer AS - we would like to print the AS */ - t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); - goto done; - } - if (len > 16) - len = 16; - for (i=0; i<len; i++) - t += bsprintf(t, "%02x", data[i]); + if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) + { + /* Bad peer AS - we would like to print the AS */ + t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); + goto done; + } + /* RFC 8203 */ + if ((code == 6) && ((subcode == 2 || subcode == 4)) && (len <= 129)) + { + shutdown_comm_length = data[0]; + if ((shutdown_comm_length <= 128) && (len == shutdown_comm_length + 1)) + { + t += bsprintf(t, "\""); + for (i=1; i<len; i++) + t += bsprintf(t, "%c", data[i]); + t += bsprintf(t, "\""); + memcpy(p->last_received_shutmsg, data, shutdown_comm_length + 1); + goto done; + } + } + else + { + if (len > 16) + len = 16; + for (i=0; i<len; i++) + t += bsprintf(t, "%02x", data[i]); + } } - done: - *t = 0; - log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); + + done: + *t = 0; + log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); } static void
Hi, Peter van Dijk pointed me at valgrind. It appears I can improve this patch a bit more, stay tuned. Kind regards, Job On Thu, Jul 27, 2017 at 05:55:40PM +0200, Job Snijders wrote:
Hi all,
Here is a patch to decode received BGP shutdown communication messages as specified in RFC 8203. In the following example scenario I'm sending a shutdown communication with openbgpd:
$ bgpctl neighbor 94.142.241.204 down "TICKET-2331 we are upgrading, back in 30 min" request processed
And can subsequently observe the message via logging and via 'show protocols all':
job@irime:~/source/bird$ sudo ./bird -s test.sock -d -c bird2.conf bird: Started bird: bgp1: Received: Administrative shutdown: "TICKET-2331 we are upgrading, back in 30 min"
job@irime:~/source/bird$ sudo ./birdc -s test.sock show protocols all .... BGP state: Active Neighbor address: 165.254.255.26 Neighbor AS: 15562 Connect delay: 3/5 Last error: Received: Administrative shutdown Message: "TICKET-2331 we are upgrading, back in 30 min"
As for the remaining RFC 8203 work:
I could use some help with _sending_ bgp shutdown communication messages. It is not clear to me where I should hook the message into the config/cli infrastructure. Ideally you can do things like:
$ birdc disable bgp1 "hi, we will upgrade to bird 1.6.4"
or via the configuration (also during reconfigure):
protocol bgp { disabled "shutdown due to maintenance ticket 2424"; description "My BGP uplink"; local 94.142.241.204 as 65000; neighbor 165.254.255.26 as 15562; }
Thoughts?
Kind regards,
Job
--- proto/bgp/bgp.c | 13 ++++++++++ proto/bgp/bgp.h | 2 ++ proto/bgp/packets.c | 73 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 26 deletions(-)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f706e76..551b156 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1487,6 +1487,16 @@ bgp_last_errmsg(struct bgp_proto *p) }
static const char * +bgp_last_shutmsg(struct bgp_proto *p) +{ + unsigned len; + char *buf = calloc (128, sizeof (char)); + len = p->last_received_shutmsg[0]; + bsnprintf(buf, len, "%s", p->last_received_shutmsg+1); + return(buf); +} + +static const char * bgp_state_dsc(struct bgp_proto *p) { if (p->p.proto_state == PS_DOWN) @@ -1580,7 +1590,10 @@ bgp_show_proto_info(struct proto *P) { const char *err1 = bgp_err_classes[p->last_error_class]; const char *err2 = bgp_last_errmsg(p); + const char *msg = bgp_last_shutmsg(p); cli_msg(-1006, " Last error: %s%s", err1, err2); + if (p->last_received_shutmsg[0] > 0) + cli_msg(-1006, " Message: \"%s\"", msg); } }
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e47a0eb..d958716 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -157,6 +157,8 @@ struct bgp_proto { u8 last_error_class; /* Error class of last error */ u32 last_error_code; /* Error code of last error. BGP protocol errors are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ + byte last_received_shutmsg[129]; /* RFC 8203 */ + #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ab87bdc..1a021dd 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1460,9 +1460,9 @@ static struct { { 5, 3, "Unexpected message in Established state" }, { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */ { 6, 1, "Maximum number of prefixes reached" }, - { 6, 2, "Administrative shutdown" }, + { 6, 2, "Administrative shutdown" }, /* RFC 8203 can follow */ { 6, 3, "Peer de-configured" }, - { 6, 4, "Administrative reset" }, + { 6, 4, "Administrative reset" }, /* RFC 8203 can follow */ { 6, 5, "Connection rejected" }, { 6, 6, "Other configuration change" }, { 6, 7, "Connection collision resolution" }, @@ -1497,35 +1497,56 @@ bgp_error_dsc(unsigned code, unsigned subcode) void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len) { - const byte *name; - byte *t, argbuf[36]; - unsigned i; + const byte *name; + byte *t, argbuf[256]; + unsigned i; + unsigned shutdown_comm_length;
- /* Don't report Cease messages generated by myself */ - if (code == 6 && class == BE_BGP_TX) - return; + /* Don't report Cease messages generated by myself */ + if (code == 6 && class == BE_BGP_TX) + return; + + name = bgp_error_dsc(code, subcode); + t = argbuf; + memset(p->last_received_shutmsg, 0, 129); // clear old RFC 8203 messages
- name = bgp_error_dsc(code, subcode); - t = argbuf; - if (len) + if (len) { - *t++ = ':'; - *t++ = ' '; + *t++ = ':'; + *t++ = ' ';
- if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) - { - /* Bad peer AS - we would like to print the AS */ - t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); - goto done; - } - if (len > 16) - len = 16; - for (i=0; i<len; i++) - t += bsprintf(t, "%02x", data[i]); + if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) + { + /* Bad peer AS - we would like to print the AS */ + t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); + goto done; + } + /* RFC 8203 */ + if ((code == 6) && ((subcode == 2 || subcode == 4)) && (len <= 129)) + { + shutdown_comm_length = data[0]; + if ((shutdown_comm_length <= 128) && (len == shutdown_comm_length + 1)) + { + t += bsprintf(t, "\""); + for (i=1; i<len; i++) + t += bsprintf(t, "%c", data[i]); + t += bsprintf(t, "\""); + memcpy(p->last_received_shutmsg, data, shutdown_comm_length + 1); + goto done; + } + } + else + { + if (len > 16) + len = 16; + for (i=0; i<len; i++) + t += bsprintf(t, "%02x", data[i]); + } } - done: - *t = 0; - log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); + + done: + *t = 0; + log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); }
static void
Spin #2 --- proto/bgp/bgp.c | 12 +++++++++ proto/bgp/bgp.h | 2 ++ proto/bgp/packets.c | 73 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f706e76..2a89c00 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1487,6 +1487,15 @@ bgp_last_errmsg(struct bgp_proto *p) } static const char * +bgp_last_shutmsg(struct bgp_proto *p) +{ + if (p->last_received_shutmsg) + return(p->last_received_shutmsg); + else + return(NULL); +} + +static const char * bgp_state_dsc(struct bgp_proto *p) { if (p->p.proto_state == PS_DOWN) @@ -1580,7 +1589,10 @@ bgp_show_proto_info(struct proto *P) { const char *err1 = bgp_err_classes[p->last_error_class]; const char *err2 = bgp_last_errmsg(p); + const char *msg = bgp_last_shutmsg(p); cli_msg(-1006, " Last error: %s%s", err1, err2); + if (msg) + cli_msg(-1006, " Message: \"%s\"", msg); } } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e47a0eb..d958716 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -157,6 +157,8 @@ struct bgp_proto { u8 last_error_class; /* Error class of last error */ u32 last_error_code; /* Error code of last error. BGP protocol errors are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ + byte last_received_shutmsg[129]; /* RFC 8203 */ + #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ab87bdc..a44f264 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1460,9 +1460,9 @@ static struct { { 5, 3, "Unexpected message in Established state" }, { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */ { 6, 1, "Maximum number of prefixes reached" }, - { 6, 2, "Administrative shutdown" }, + { 6, 2, "Administrative shutdown" }, /* RFC 8203 can follow */ { 6, 3, "Peer de-configured" }, - { 6, 4, "Administrative reset" }, + { 6, 4, "Administrative reset" }, /* RFC 8203 can follow */ { 6, 5, "Connection rejected" }, { 6, 6, "Other configuration change" }, { 6, 7, "Connection collision resolution" }, @@ -1497,35 +1497,56 @@ bgp_error_dsc(unsigned code, unsigned subcode) void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len) { - const byte *name; - byte *t, argbuf[36]; - unsigned i; + const byte *name; + byte *t, argbuf[256]; + unsigned i; + unsigned shutdown_comm_length; - /* Don't report Cease messages generated by myself */ - if (code == 6 && class == BE_BGP_TX) - return; + /* Don't report Cease messages generated by myself */ + if (code == 6 && class == BE_BGP_TX) + return; + + name = bgp_error_dsc(code, subcode); + t = argbuf; + memset(p->last_received_shutmsg, 0, 128 + 1); // clear old RFC 8203 messages - name = bgp_error_dsc(code, subcode); - t = argbuf; - if (len) + if (len) { - *t++ = ':'; - *t++ = ' '; + *t++ = ':'; + *t++ = ' '; - if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) - { - /* Bad peer AS - we would like to print the AS */ - t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); - goto done; - } - if (len > 16) - len = 16; - for (i=0; i<len; i++) - t += bsprintf(t, "%02x", data[i]); + if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) + { + /* Bad peer AS - we would like to print the AS */ + t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); + goto done; + } + /* RFC 8203 */ + if ((code == 6) && ((subcode == 2 || subcode == 4)) && (len <= 129)) + { + shutdown_comm_length = data[0]; + if ((shutdown_comm_length <= 128) && (len == shutdown_comm_length + 1)) + { + t += bsprintf(t, "\""); + for (i=1; i<len; i++) + t += bsprintf(t, "%c", data[i]); + t += bsprintf(t, "\""); + memcpy(p->last_received_shutmsg, data + 1, shutdown_comm_length); + goto done; + } + } + else + { + if (len > 16) + len = 16; + for (i=0; i<len; i++) + t += bsprintf(t, "%02x", data[i]); + } } - done: - *t = 0; - log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); + + done: + *t = 0; + log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); } static void
bump? :-) On Fri, Jul 28, 2017 at 12:26:59PM +0200, Job Snijders wrote:
Spin #2
--- proto/bgp/bgp.c | 12 +++++++++ proto/bgp/bgp.h | 2 ++ proto/bgp/packets.c | 73 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f706e76..2a89c00 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1487,6 +1487,15 @@ bgp_last_errmsg(struct bgp_proto *p) }
static const char * +bgp_last_shutmsg(struct bgp_proto *p) +{ + if (p->last_received_shutmsg) + return(p->last_received_shutmsg); + else + return(NULL); +} + +static const char * bgp_state_dsc(struct bgp_proto *p) { if (p->p.proto_state == PS_DOWN) @@ -1580,7 +1589,10 @@ bgp_show_proto_info(struct proto *P) { const char *err1 = bgp_err_classes[p->last_error_class]; const char *err2 = bgp_last_errmsg(p); + const char *msg = bgp_last_shutmsg(p); cli_msg(-1006, " Last error: %s%s", err1, err2); + if (msg) + cli_msg(-1006, " Message: \"%s\"", msg); } }
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e47a0eb..d958716 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -157,6 +157,8 @@ struct bgp_proto { u8 last_error_class; /* Error class of last error */ u32 last_error_code; /* Error code of last error. BGP protocol errors are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ + byte last_received_shutmsg[129]; /* RFC 8203 */ + #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ab87bdc..a44f264 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1460,9 +1460,9 @@ static struct { { 5, 3, "Unexpected message in Established state" }, { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */ { 6, 1, "Maximum number of prefixes reached" }, - { 6, 2, "Administrative shutdown" }, + { 6, 2, "Administrative shutdown" }, /* RFC 8203 can follow */ { 6, 3, "Peer de-configured" }, - { 6, 4, "Administrative reset" }, + { 6, 4, "Administrative reset" }, /* RFC 8203 can follow */ { 6, 5, "Connection rejected" }, { 6, 6, "Other configuration change" }, { 6, 7, "Connection collision resolution" }, @@ -1497,35 +1497,56 @@ bgp_error_dsc(unsigned code, unsigned subcode) void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len) { - const byte *name; - byte *t, argbuf[36]; - unsigned i; + const byte *name; + byte *t, argbuf[256]; + unsigned i; + unsigned shutdown_comm_length;
- /* Don't report Cease messages generated by myself */ - if (code == 6 && class == BE_BGP_TX) - return; + /* Don't report Cease messages generated by myself */ + if (code == 6 && class == BE_BGP_TX) + return; + + name = bgp_error_dsc(code, subcode); + t = argbuf; + memset(p->last_received_shutmsg, 0, 128 + 1); // clear old RFC 8203 messages
- name = bgp_error_dsc(code, subcode); - t = argbuf; - if (len) + if (len) { - *t++ = ':'; - *t++ = ' '; + *t++ = ':'; + *t++ = ' ';
- if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) - { - /* Bad peer AS - we would like to print the AS */ - t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); - goto done; - } - if (len > 16) - len = 16; - for (i=0; i<len; i++) - t += bsprintf(t, "%02x", data[i]); + if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) + { + /* Bad peer AS - we would like to print the AS */ + t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); + goto done; + } + /* RFC 8203 */ + if ((code == 6) && ((subcode == 2 || subcode == 4)) && (len <= 129)) + { + shutdown_comm_length = data[0]; + if ((shutdown_comm_length <= 128) && (len == shutdown_comm_length + 1)) + { + t += bsprintf(t, "\""); + for (i=1; i<len; i++) + t += bsprintf(t, "%c", data[i]); + t += bsprintf(t, "\""); + memcpy(p->last_received_shutmsg, data + 1, shutdown_comm_length); + goto done; + } + } + else + { + if (len > 16) + len = 16; + for (i=0; i<len; i++) + t += bsprintf(t, "%02x", data[i]); + } } - done: - *t = 0; - log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); + + done: + *t = 0; + log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); }
static void
On Thu, Jul 27, 2017 at 05:55:40PM +0200, Job Snijders wrote:
Hi all,
Here is a patch to decode received BGP shutdown communication messages as specified in RFC 8203. In the following example scenario I'm sending a shutdown communication with openbgpd:
$ bgpctl neighbor 94.142.241.204 down "TICKET-2331 we are upgrading, back in 30 min" request processed
Hi Merged with some significant changes, with support for both RX and TX of shutdown communication: https://gitlab.labs.nic.cz/labs/bird/commit/cd1d99611e445c9fe2452d05627ccfc6... I generalized it a bit, so the message is not specific to BGP, but can be attached to any protocol, so it makes sense that it can be changed by general commands like disable, restart. That means it also changed the output a bit: bird> show protocols all bgp2 name proto table state since info bgp2 BGP master down 19:39:00 Description: My BGP session Message: Planned shutdown, back in 30 min Preference: 100 Input filter: ACCEPT Output filter: (unnamed) BGP state: Down Neighbor address: 10.0.1.1 Neighbor AS: 10 Conceptually, it is one-item mailbox, which can be set by either the core (using enable/disable/restart commands) or the protocol (received BGP Notification with the RFC 8203 message). I am not sure if it would not be better to have two separate mailboxes for both directions, but it probably does not matter. The message can be send from BIRD shell: birdc> disable bgp1 "hi, we will upgrade to bird 1.6.4" Unfortunately, that means that from Unix shell you have to do double qouting: birdc disable bgp1 '"hi, we will upgrade to bird 1.6.4"' Currently no support for message associated with 'disabled' in bird.conf or for message associated with BIRD global shutdown. Otherwise, there are some minor changes w.r.t. your patch: 1) Your patch requires that RFC 8203 message fills the entire space of BGP notification (i.e. msg_len + 1 == remaining_len). I do not see any such requirement in RFC 8203, so i accept if (msg_len + 1 <= remaining_len) 2) I reset the message not with any RX notification, but only with administrative shutdown/reset notification. That prevents message reset with subsequent errors unrelated to administrative notification. 3) Proper handling of zero-length messages (should be handled equally like no message at all according to RFC 8203). 4) Some basic sanitization of received strings to avoid escape-attacks and newlines in logs. Any comments, suggestions, opposition? -- Elen sila lumenn' omentielvo Ondrej 'Santiago' Zajicek (email: santiago@crfreenet.org) OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net) "To err is human -- to blame it on a computer is even more so."
On 2017 Sep 19 (Tue) at 20:53:47 +0200 (+0200), Ondrej Zajicek wrote: :Merged with some significant changes, with support for both RX and TX of :shutdown communication: ... : :Unfortunately, that means that from Unix shell you have to do double qouting: : :birdc disable bgp1 '"hi, we will upgrade to bird 1.6.4"' : Um, requiring double quoting violates POLA. This isn't user friendly at all. I imagine the administrator's workflow will be something along the lines of: - send graceful shutdown - have a coffee while it propagates - shutdown the sessions with a message - do the things - bring the sessions back up - remove graceful shutdown Personally i would do all of these commands from the unix shell, and not from within a birdc session. It shouldn't be that hard to only require one set of quotes in both the unix shell and the birdc shell. -- Take it easy, we're in a hurry.
On Tue, Sep 26, 2017 at 10:14:11AM +0200, Peter Hessler wrote:
On 2017 Sep 19 (Tue) at 20:53:47 +0200 (+0200), Ondrej Zajicek wrote: :Merged with some significant changes, with support for both RX and TX of :shutdown communication: ... : :Unfortunately, that means that from Unix shell you have to do double qouting: : :birdc disable bgp1 '"hi, we will upgrade to bird 1.6.4"' :
Um, requiring double quoting violates POLA. This isn't user friendly at all.
Well, while i consider it cumbersome, i would argue that it is consistent with POLA. Anyone who take into account two premises, namely: 1) BIRD always requires quotes for string constants 2) Quoting is removed by shell would conclude that additional qouting is necessary, like it is common with other CLI tools with nontrivial arguments (e.g. grep). Not requiring quoting would be exception and therefore violating POLA.
It shouldn't be that hard to only require one set of quotes in both the unix shell and the birdc shell.
We use the same lexer and parser for both CLI and arguments and quotes are not just for token separation (which is already done by shell for arguments), but are intrinsic part of string tokens to distinquish them from symbol tokens. Changing that would require significant changes to lexer with likely impact on backward compatibility. -- Elen sila lumenn' omentielvo Ondrej 'Santiago' Zajicek (email: santiago@crfreenet.org) OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net) "To err is human -- to blame it on a computer is even more so."
Hi Ondrej, Thank you for your work on this patch. When sending in my code i realised it was a bit rough on the edges, and secretly hoped that a more experienced BIRD developer would take pity and polish it up. Appreciated! On Tue, Sep 26, 2017 at 02:22:20PM +0200, Ondrej Zajicek wrote:
On Tue, Sep 26, 2017 at 10:14:11AM +0200, Peter Hessler wrote:
On 2017 Sep 19 (Tue) at 20:53:47 +0200 (+0200), Ondrej Zajicek wrote: :Merged with some significant changes, with support for both RX and TX of :shutdown communication: : :Unfortunately, that means that from Unix shell you have to do double qouting: : :birdc disable bgp1 '"hi, we will upgrade to bird 1.6.4"' :
Um, requiring double quoting violates POLA. This isn't user friendly at all.
Well, while i consider it cumbersome, i would argue that it is consistent with POLA. Anyone who take into account two premises, namely:
1) BIRD always requires quotes for string constants 2) Quoting is removed by shell
I beg to differ... this is not what UNIX-style users expect from programs. I'd expect: $ sudo birdc disable bgp1 "hi, we will upgrade to bird 1.6.4" or maybe $ sudo birdc disable bgp1 message "hi, we will upgrade to bird 1.6.4" to work like that. Another aspect, from the $ sudo birdc show protocols all bgp1 output it is not entirely clear whether the Message is the last message that has been _sent_ to the EBGP neighbor, or is the last message that has been _received_ from that neighbor. Might be good to clarify that a bit (perhaps add RX or TX as prefix?).
It shouldn't be that hard to only require one set of quotes in both the unix shell and the birdc shell.
We use the same lexer and parser for both CLI and arguments and quotes are not just for token separation (which is already done by shell for arguments), but are intrinsic part of string tokens to distinquish them from symbol tokens. Changing that would require significant changes to lexer with likely impact on backward compatibility.
I see, that is unfortunate. Another challenge may be that the proposed patch doesn't offer feature parity in terms of the bird.conf approach. I'm aware of many deployments that never use "birdc enable|disable" from the command line, but just "generate && rsync && birdc configure" to push out configs. This way the running configuration and the startup configuration are always in sync, which often is a desirable property. Kind regards, Job
participants (4)
-
Job Snijders -
Job Snijders -
Ondrej Zajicek -
Peter Hessler