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)
/* 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 */
/* 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))
/* 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);
+
+#undef FAIL
-withdraw:
+fail:
/* RFC 7606 5.2 - handle missing NLRI during errors */
if (!s->ip_reach_len && !s->mp_reach_len)
bgp_parse_error(s, 1);
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)
{
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))
{
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
#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;
#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 */
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 */
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;
/* Handle withdraw during next hop decoding */
if (s->err_withdraw)
+ {
+ STATS(bad_next_hop);
a = NULL;
+ }
}
c->desc->decode_nlri(s, nlri, len, a);
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;
put_u16(buf+16, len);
buf[18] = type;
+ STATS(tx_pkts[type - 1]);
return sk_send(sk, len);
}
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);
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);
}
}