summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Filip <feela@network.cz>2018-02-27 06:08:03 +0100
committerOndrej Filip <feela@network.cz>2018-02-27 06:08:03 +0100
commit44062812600bd29f8edf30ebc871ff218069c5a2 (patch)
tree656c5cfcfe340cc8a12e7a88d930cfe839f7b97e /proto
parent6f46465af1b3d21ca67e3b4379640c008fc9d1a1 (diff)
parent1561ee799cfe79d208ce9588e487da4b62a88dad (diff)
Merge branch 'int-new' of ssh://gitlab.labs.nic.cz/labs/bird into int-new
Diffstat (limited to 'proto')
-rw-r--r--proto/babel/babel.c60
-rw-r--r--proto/babel/babel.h25
-rw-r--r--proto/babel/packets.c169
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/bgp/config.Y30
-rw-r--r--proto/bgp/packets.c10
-rw-r--r--proto/pipe/config.Y14
-rw-r--r--proto/pipe/pipe.c4
8 files changed, 280 insertions, 33 deletions
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index aa7e8b68..88c4711e 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1935,8 +1935,10 @@ babel_show_neighbors(struct proto *P, char *iff)
}
static void
-babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
+babel_show_entries_(struct babel_proto *p, struct fib *rtable)
{
+ int width = babel_sadr_enabled(p) ? -54 : -24;
+
FIB_WALK(rtable, struct babel_entry, e)
{
struct babel_route *r = NULL;
@@ -1950,13 +1952,13 @@ babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
srcs++;
if (e->valid)
- cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
+ cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
else if (r = e->selected)
- cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
+ cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
else
- cli_msg(-1025, "%-24N %-23s %6s %5s %7u %7u",
+ cli_msg(-1025, "%-*N %-23s %6s %5s %7u %7u", width,
e->n.addr, "<none>", "-", "-", rts, srcs);
}
FIB_WALK_END;
@@ -1966,6 +1968,7 @@ void
babel_show_entries(struct proto *P)
{
struct babel_proto *p = (void *) P;
+ int width = babel_sadr_enabled(p) ? -54 : -24;
if (p->p.proto_state != PS_UP)
{
@@ -1975,7 +1978,7 @@ babel_show_entries(struct proto *P)
}
cli_msg(-1025, "%s:", p->p.name);
- cli_msg(-1025, "%-24s %-23s %6s %5s %7s %7s",
+ cli_msg(-1025, "%-*s %-23s %6s %5s %7s %7s", width,
"Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
babel_show_entries_(p, &p->ip4_rtable);
@@ -1985,8 +1988,10 @@ babel_show_entries(struct proto *P)
}
static void
-babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
+babel_show_routes_(struct babel_proto *p, struct fib *rtable)
{
+ int width = babel_sadr_enabled(p) ? -54 : -24;
+
FIB_WALK(rtable, struct babel_entry, e)
{
struct babel_route *r;
@@ -1994,7 +1999,7 @@ babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
{
char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
btime time = r->expires ? r->expires - current_time() : 0;
- cli_msg(-1025, "%-24N %-25I %-10s %5u %c %5u %7t",
+ cli_msg(-1025, "%-*N %-25I %-10s %5u %c %5u %7t", width,
e->n.addr, r->next_hop, r->neigh->ifa->ifname,
r->metric, c, r->seqno, MAX(time, 0));
}
@@ -2006,6 +2011,7 @@ void
babel_show_routes(struct proto *P)
{
struct babel_proto *p = (void *) P;
+ int width = babel_sadr_enabled(p) ? -54 : -24;
if (p->p.proto_state != PS_UP)
{
@@ -2015,7 +2021,7 @@ babel_show_routes(struct proto *P)
}
cli_msg(-1025, "%s:", p->p.name);
- cli_msg(-1025, "%-24s %-25s %-9s %6s F %5s %7s",
+ cli_msg(-1025, "%-*s %-25s %-9s %6s F %5s %7s", width,
"Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
babel_show_routes_(p, &p->ip4_rtable);
@@ -2139,7 +2145,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
e = babel_get_entry(p, net->n.addr);
/* Activate triggered updates */
- if ((e->valid |= BABEL_ENTRY_VALID) ||
+ if ((e->valid != BABEL_ENTRY_VALID) ||
(e->router_id != rt_router_id))
{
babel_trigger_update(p);
@@ -2182,14 +2188,32 @@ babel_rte_same(struct rte *new, struct rte *old)
}
+static void
+babel_postconfig(struct proto_config *CF)
+{
+ struct babel_config *cf = (void *) CF;
+ struct channel_config *ip4, *ip6, *ip6_sadr;
+
+ ip4 = proto_cf_find_channel(CF, NET_IP4);
+ ip6 = proto_cf_find_channel(CF, NET_IP6);
+ ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);
+
+ if (ip6 && ip6_sadr)
+ cf_error("Both ipv6 and ipv6-sadr channels");
+
+ cf->ip4_channel = ip4;
+ cf->ip6_channel = ip6 ?: ip6_sadr;
+}
+
static struct proto *
babel_init(struct proto_config *CF)
{
struct proto *P = proto_new(CF);
struct babel_proto *p = (void *) P;
+ struct babel_config *cf = (void *) CF;
- proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
- proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
+ proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
+ proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
@@ -2207,10 +2231,11 @@ babel_start(struct proto *P)
{
struct babel_proto *p = (void *) P;
struct babel_config *cf = (void *) P->cf;
+ u8 ip6_type = cf->ip6_channel ? cf->ip6_channel->net_type : NET_IP6;
fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
- fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
+ fib_init(&p->ip6_rtable, P->pool, ip6_type, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
init_list(&p->interfaces);
@@ -2258,11 +2283,15 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
{
struct babel_proto *p = (void *) P;
struct babel_config *new = (void *) CF;
+ u8 ip6_type = new->ip6_channel ? new->ip6_channel->net_type : NET_IP6;
TRACE(D_EVENTS, "Reconfiguring");
- if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) ||
- !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)))
+ if (p->ip6_rtable.addr_type != ip6_type)
+ return 0;
+
+ if (!proto_configure_channel(P, &p->ip4_channel, new->ip4_channel) ||
+ !proto_configure_channel(P, &p->ip6_channel, new->ip6_channel))
return 0;
p->p.cf = CF;
@@ -2280,9 +2309,10 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
- .channel_mask = NB_IP,
+ .channel_mask = NB_IP | NB_IP6_SADR,
.proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config),
+ .postconfig = babel_postconfig,
.init = babel_init,
.dump = babel_dump,
.start = babel_start,
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 1128d261..b194ce30 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -85,7 +85,10 @@ enum babel_tlv_type {
enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0,
- BABEL_SUBTLV_PADN = 1
+ BABEL_SUBTLV_PADN = 1,
+
+ /* Mandatory subtlvs */
+ BABEL_SUBTLV_SOURCE_PREFIX = 128,
};
enum babel_iface_type {
@@ -109,6 +112,9 @@ struct babel_config {
struct proto_config c;
list iface_list; /* List of iface configs (struct babel_iface_config) */
uint hold_time; /* Time to hold stale entries and unreachable routes */
+
+ struct channel_config *ip4_channel;
+ struct channel_config *ip6_channel;
};
struct babel_iface_config {
@@ -303,7 +309,10 @@ struct babel_msg_update {
u16 seqno;
u16 metric;
u64 router_id;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
ip_addr next_hop;
ip_addr sender;
};
@@ -311,7 +320,10 @@ struct babel_msg_update {
struct babel_msg_route_request {
u8 type;
u8 full;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
};
struct babel_msg_seqno_request {
@@ -319,7 +331,10 @@ struct babel_msg_seqno_request {
u8 hop_count;
u16 seqno;
u64 router_id;
- net_addr net;
+ union {
+ net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
ip_addr sender;
};
@@ -339,6 +354,8 @@ struct babel_msg_node {
union babel_msg msg;
};
+static inline int babel_sadr_enabled(struct babel_proto *p)
+{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }
/* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index dd86222a..59678678 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -105,6 +105,13 @@ struct babel_tlv_seqno_request {
u8 addr[0];
} PACKED;
+struct babel_subtlv_source_prefix {
+ u8 type;
+ u8 length;
+ u8 plen;
+ u8 addr[0];
+} PACKED;
+
/* Hello flags */
#define BABEL_HF_UNICAST 0x8000
@@ -127,6 +134,7 @@ struct babel_parse_state {
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
+ u8 sadr_enabled;
};
enum parse_result {
@@ -237,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru
static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
+static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
@@ -244,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct
static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
+static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
struct babel_tlv_data {
u8 min_length;
@@ -640,6 +650,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
ip6_addr prefix6 = get_ip6(buf);
net_fill_ip6(&msg->net, prefix6, tlv->plen);
+ if (state->sadr_enabled)
+ net_make_ip6_sadr(&msg->net);
+
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
put_ip6(state->def_ip6_prefix, prefix6);
@@ -770,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_u16(&tlv->seqno, msg->seqno);
put_u16(&tlv->metric, msg->metric);
+ if (msg->net.type == NET_IP6_SADR)
+ {
+ int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len));
+ if (l < 0)
+ return 0;
+
+ len += l;
+ }
+
return len0 + len;
}
static int
babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
- struct babel_parse_state *state UNUSED)
+ struct babel_parse_state *state)
{
struct babel_tlv_route_request *tlv = (void *) hdr;
struct babel_msg_route_request *msg = &m->route_request;
@@ -812,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
+
+ if (state->sadr_enabled)
+ net_make_ip6_sadr(&msg->net);
+
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -856,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
put_ip6_px(tlv->addr, &msg->net);
}
+ if (msg->net.type == NET_IP6_SADR)
+ {
+ int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ len += l;
+ }
+
return len;
}
@@ -900,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
+
+ if (state->sadr_enabled)
+ net_make_ip6_sadr(&msg->net);
+
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -943,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id);
+ if (msg->net.type == NET_IP6_SADR)
+ {
+ int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ len += l;
+ }
+
return len;
}
+static int
+babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg,
+ struct babel_parse_state *state UNUSED)
+{
+ struct babel_subtlv_source_prefix *tlv = (void *) hdr;
+ net_addr_ip6_sadr *net;
+
+ /*
+ * We would like to skip the sub-TLV if SADR is not enabled, but we do not
+ * know AF of the enclosing TLV yet. We will do that later.
+ */
+
+ /* Check internal consistency */
+ if ((tlv->length < 1) ||
+ (tlv->plen > IP6_MAX_PREFIX_LENGTH) ||
+ (tlv->length < (1 + BYTES(tlv->plen))))
+ return PARSE_ERROR;
+
+ /* Plen MUST NOT be 0 */
+ if (tlv->plen == 0)
+ return PARSE_ERROR;
+
+ switch(msg->type)
+ {
+ case BABEL_TLV_UPDATE:
+ /* Wildcard updates with source prefix MUST be silently ignored */
+ if (msg->update.wildcard)
+ return PARSE_IGNORE;
+
+ net = (void *) &msg->update.net;
+ break;
+
+ case BABEL_TLV_ROUTE_REQUEST:
+ /* Wildcard requests with source addresses MUST be silently ignored */
+ if (msg->route_request.full)
+ return PARSE_IGNORE;
+
+ net = (void *) &msg->route_request.net;
+ break;
+
+ case BABEL_TLV_SEQNO_REQUEST:
+ net = (void *) &msg->seqno_request.net;
+ break;
+
+ default:
+ return PARSE_ERROR;
+ }
+
+ /* If SADR is active, the net has appropriate type */
+ if (net->type != NET_IP6_SADR)
+ return PARSE_IGNORE;
+
+ /* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */
+ if (net->src_pxlen > 0)
+ return PARSE_IGNORE;
+
+ net_addr_ip6 src;
+ read_ip6_px((void *) &src, tlv->addr, tlv->plen);
+ net->src_prefix = src.prefix;
+ net->src_pxlen = src.pxlen;
+
+ return PARSE_SUCCESS;
+}
+
+static int
+babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
+{
+ struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr);
+ net_addr_ip6_sadr *net = (void *) n;
+
+ /* Do not use this sub-TLV for default prefix */
+ if (net->src_pxlen == 0)
+ return 0;
+
+ uint len = sizeof(*tlv) + BYTES(net->src_pxlen);
+
+ if (len > max_len)
+ return -1;
+
+ TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len);
+ hdr->length += len;
+
+ net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen);
+ tlv->plen = src.pxlen;
+ put_ip6_px(tlv->addr, (void *) &src);
+
+ return len;
+}
+
+
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
- union babel_msg *msg UNUSED,
+ union babel_msg *msg,
struct babel_parse_state *state)
{
struct babel_tlv *tlv;
+ byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
+ int res;
for (tlv = (void *) hdr + state->current_tlv_endpos;
- (void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
+ (byte *) tlv < end;
tlv = NEXT_TLV(tlv))
{
+ /* Ugly special case */
+ if (tlv->type == BABEL_TLV_PAD1)
+ continue;
+
+ /* The end of the common TLV header */
+ pos = (byte *)tlv + sizeof(struct babel_tlv);
+ if ((pos > end) || (pos + tlv->length > end))
+ return PARSE_ERROR;
+
/*
* The subtlv type space is non-contiguous (due to the mandatory bit), so
* use a switch for dispatch instead of the mapping array we use for TLVs
*/
switch (tlv->type)
{
- case BABEL_SUBTLV_PAD1:
- case BABEL_SUBTLV_PADN:
- /* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
+ case BABEL_SUBTLV_SOURCE_PREFIX:
+ res = babel_read_source_prefix(tlv, msg, state);
+ if (res != PARSE_SUCCESS)
+ return res;
break;
+ case BABEL_SUBTLV_PADN:
default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
- if (tlv->type > 128)
- {
- DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
+ if (tlv->type >= 128)
return PARSE_IGNORE;
- }
break;
}
}
@@ -1197,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
.ifa = ifa,
.saddr = saddr,
.next_hop_ip6 = saddr,
+ .sadr_enabled = babel_sadr_enabled(p),
};
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 1310582b..30424abb 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -118,6 +118,7 @@ struct bgp_config {
unsigned error_delay_time_min; /* Time to wait after an error is detected */
unsigned error_delay_time_max;
unsigned disable_after_error; /* Disable the protocol when error is detected */
+ u32 disable_after_cease; /* Disable it when cease is received, bitfield */
char *password; /* Password used for MD5 authentication */
int check_link; /* Use iface link state for liveness detection */
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 04e6d666..41eaa729 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -32,6 +32,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
%type <i32> bgp_afi
+CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
+ CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
+ OUT, OF, RESOURCES)
+
+%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag
+
CF_GRAMMAR
CF_ADDTO(proto, bgp_proto '}' )
@@ -74,6 +80,29 @@ bgp_nbr_opts:
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
;
+bgp_cease_mask:
+ /* true -> all except connection collision */
+ bool { $$ = $1 ? ~(1 << 7) : 0; }
+ | '{' bgp_cease_list '}' { $$ = $2; }
+ ;
+
+bgp_cease_list:
+ bgp_cease_flag
+ | bgp_cease_list ',' bgp_cease_flag { $$ = $1 | $3; }
+ ;
+
+bgp_cease_flag:
+ CEASE { $$ = 1 << 0; }
+ | PREFIX LIMIT HIT { $$ = 1 << 1; }
+ | ADMINISTRATIVE SHUTDOWN { $$ = 1 << 2; }
+ | PEER DECONFIGURED { $$ = 1 << 3; }
+ | ADMINISTRATIVE RESET { $$ = 1 << 4; }
+ | CONNECTION REJECTED { $$ = 1 << 5; }
+ | CONFIGURATION CHANGE { $$ = 1 << 6; }
+ | CONNECTION COLLISION { $$ = 1 << 7; }
+ | OUT OF RESOURCES { $$ = 1 << 8; }
+ ;
+
bgp_proto:
bgp_proto_start proto_name '{'
| bgp_proto proto_item ';'
@@ -117,6 +146,7 @@ bgp_proto:
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
| bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
+ | bgp_proto DISABLE AFTER CEASE bgp_cease_mask ';' { BGP_CFG->disable_after_cease = $5; }
| bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 95a974eb..aa08732d 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -2772,6 +2772,16 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
bgp_update_startup_delay(p);
bgp_stop(p, 0, NULL, 0);
}
+ else
+ {
+ uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0);
+ if (p->cf->disable_after_cease & subcode_bit)
+ {
+ log(L_INFO "%s: Disabled after Cease notification", p->p.name);
+ p->startup_delay = 0;
+ p->p.disabled = 1;
+ }
+ }
}
static void
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 4f96fdcb..b3c332be 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -25,13 +25,19 @@ CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } )
pipe_proto_start: proto_start PIPE
{
this_proto = proto_config_new(&proto_pipe, $1);
- this_channel = channel_config_new(NULL, NULL, 0, this_proto);
- this_channel->in_filter = FILTER_ACCEPT;
- this_channel->out_filter = FILTER_ACCEPT;
+}
+proto_name
+{
+ this_channel = proto_cf_main_channel(this_proto);
+ if (!this_channel) {
+ this_channel = channel_config_new(NULL, NULL, 0, this_proto);
+ this_channel->in_filter = FILTER_ACCEPT;
+ this_channel->out_filter = FILTER_ACCEPT;
+ }
};
pipe_proto:
- pipe_proto_start proto_name '{'
+ pipe_proto_start '{'
| pipe_proto proto_item ';'
| pipe_proto channel_item ';'
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 310f3c01..49ff52e2 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -249,6 +249,8 @@ pipe_show_stats(struct pipe_proto *p)
s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
}
+static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
+
static void
pipe_show_proto_info(struct proto *P)
{
@@ -257,6 +259,8 @@ pipe_show_proto_info(struct proto *P)
cli_msg(-1006, " Channel %s", "main");
cli_msg(-1006, " Table: %s", p->pri->table->name);
cli_msg(-1006, " Peer table: %s", p->sec->table->name);
+ cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]);
+ cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]);
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));