diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 0f41f818..e53b09d8 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1094,8 +1094,10 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) ADVANCE(pos, len, alen); } +#define FAIL(KEY) ({ STATS(KEY); goto fail; }) + if (s->err_withdraw) - goto withdraw; + FAIL(bad_attribute); /* If there is no reachability NLRI, we are finished */ if (!s->ip_reach_len && !s->mp_reach_len) @@ -1104,10 +1106,10 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) /* Handle missing mandatory attributes; RFC 7606 3 (d) */ if (!BIT32_TEST(s->attrs_seen, BA_ORIGIN)) - { REPORT(NO_MANDATORY, "ORIGIN"); goto withdraw; } + { REPORT(NO_MANDATORY, "ORIGIN"); FAIL(no_mandatory); } if (!BIT32_TEST(s->attrs_seen, BA_AS_PATH)) - { REPORT(NO_MANDATORY, "AS_PATH"); goto withdraw; } + { REPORT(NO_MANDATORY, "AS_PATH"); FAIL(no_mandatory); } /* When receiving attributes from non-AS4-aware BGP speaker, we have to reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */ @@ -1116,19 +1118,19 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) /* Reject routes with our ASN in AS_PATH attribute */ if (bgp_as_path_loopy(p, attrs, p->local_as)) - goto withdraw; + FAIL(loopy); /* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */ if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as)) - goto withdraw; + FAIL(loopy); /* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */ if (p->is_internal && bgp_originator_id_loopy(p, attrs)) - goto withdraw; + FAIL(loopy); /* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */ if (p->rr_client && bgp_cluster_list_loopy(p, attrs)) - goto withdraw; + FAIL(loopy); /* If there is no local preference, define one */ if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF)) @@ -1141,8 +1143,11 @@ framing_error: /* RFC 7606 4 - handle attribute framing errors */ REPORT("Malformed attribute list - framing error (%u/%u) at %d", alen, len, (int) (pos - s->attrs)); + FAIL(bad_alist); -withdraw: +#undef FAIL + +fail: /* RFC 7606 5.2 - handle missing NLRI during errors */ if (!s->ip_reach_len && !s->mp_reach_len) bgp_parse_error(s, 1); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 9db26050..0e60d88d 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1328,6 +1328,8 @@ bgp_start(struct proto *P) p->source_addr = p->cf->local_ip; p->link_addr = IPA_NONE; + memset(&(p->stats), 0, sizeof(struct bgp_stats)); + /* Lock all channels when in GR recovery mode */ if (p->p.gr_recovery && p->cf->gr_mode) { @@ -2104,6 +2106,15 @@ bgp_show_proto_info(struct proto *P) tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time); } + struct bgp_stats *s = &p->stats; + cli_msg(-1006, " Statistics:"); + cli_msg(-1006, " rx-open %u rx-update %u rx-notify %u rx-keepalive %u rx-refresh %u", + s->rx_pkts[0], s->rx_pkts[1], s->rx_pkts[2], s->rx_pkts[3], s->rx_pkts[4]); + cli_msg(-1006, " tx-open %u tx-update %u tx-notify %u tx-keepalive %u tx-refresh %u", + s->tx_pkts[0], s->tx_pkts[1], s->tx_pkts[2], s->tx_pkts[3], s->tx_pkts[4]); + cli_msg(-1006, " bad-alist %u bad-attribute %u bad-next-hop %u no-mandatory %u loopy %u", + s->bad_alist, s->bad_attribute, s->bad_next_hop, s->no_mandatory, s->loopy); + if ((p->last_error_class != BE_NONE) && (p->last_error_class != BE_MAN_DOWN)) { @@ -2120,6 +2131,9 @@ bgp_show_proto_info(struct proto *P) if (c->c.channel_state == CS_UP) { + cli_msg(-1006, " Enqueued updates: %u", c->bucket_hash.count); + cli_msg(-1006, " Enqueued prefixes: %u", c->prefix_hash.count); + if (ipa_zero(c->link_addr)) cli_msg(-1006, " BGP Next hop: %I", c->next_hop_addr); else diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 30424abb..3a1efc8c 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -55,6 +55,8 @@ struct eattr; #define BGP_AF_FLOW4 BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW ) #define BGP_AF_FLOW6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW ) +#define BGP_PKT_TYPES 5 /* PKT_OPEN .. PKT_ROUTE_REFRESH */ + struct bgp_write_state; struct bgp_parse_state; @@ -196,6 +198,14 @@ struct bgp_caps { #define WALK_AF_CAPS(caps,ac) \ for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++) +struct bgp_stats { + uint rx_pkts[BGP_PKT_TYPES], tx_pkts[BGP_PKT_TYPES]; + uint bad_alist, bad_attribute, bad_next_hop, no_mandatory, loopy; +}; + +#ifndef PARSER +#define STATS(KEY) ({ p->stats.KEY++; }) +#endif struct bgp_socket { node n; /* Node in global bgp_sockets */ @@ -254,6 +264,7 @@ struct bgp_proto { struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */ struct bgp_socket *sock; /* Shared listening socket */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */ + struct bgp_stats stats; /* Packet statistics */ ip_addr source_addr; /* Local address used as an advertised next hop */ ip_addr link_addr; /* Link-local version of source_addr */ event *event; /* Event for respawning and shutting process */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index aa08732d..1376ba67 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2174,6 +2174,7 @@ bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi) static inline void bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_list *ea, byte *nh, uint nh_len) { + struct bgp_proto *p = s->proto; struct bgp_channel *c = bgp_get_channel(s->proto, afi); rta *a = NULL; @@ -2207,7 +2208,10 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis /* Handle withdraw during next hop decoding */ if (s->err_withdraw) + { + STATS(bad_next_hop); a = NULL; + } } c->desc->decode_nlri(s, nlri, len, a); @@ -2446,6 +2450,7 @@ found: static inline int bgp_send(struct bgp_conn *conn, uint type, uint len) { + struct bgp_proto *p = conn->bgp; sock *sk = conn->sk; byte *buf = sk->tbuf; @@ -2453,6 +2458,7 @@ bgp_send(struct bgp_conn *conn, uint type, uint len) put_u16(buf+16, len); buf[18] = type; + STATS(tx_pkts[type - 1]); return sk_send(sk, len); } @@ -2812,13 +2818,22 @@ bgp_rx_keepalive(struct bgp_conn *conn) static void bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len) { + struct bgp_proto *p = conn->bgp; byte type = pkt[18]; DBG("BGP: Got packet %02x (%d bytes)\n", type, len); - if (conn->bgp->p.mrtdump & MD_MESSAGES) + if (p->p.mrtdump & MD_MESSAGES) mrt_dump_bgp_packet(conn, pkt, len); + if (type < PKT_OPEN || type > PKT_ROUTE_REFRESH) + { + bgp_error(conn, 1, 3, pkt+18, 1); + return; + } + + STATS(rx_pkts[type - 1]); + switch (type) { case PKT_OPEN: return bgp_rx_open(conn, pkt, len); @@ -2826,7 +2841,6 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len) case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len); case PKT_KEEPALIVE: return bgp_rx_keepalive(conn); case PKT_ROUTE_REFRESH: return bgp_rx_route_refresh(conn, pkt, len); - default: bgp_error(conn, 1, 3, pkt+18, 1); } }