summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c7
-rw-r--r--proto/bgp/bgp.c20
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/bgp/packets.c29
5 files changed, 46 insertions, 16 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index d0ec41f9..d839ed09 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -996,7 +996,7 @@ bgp_get_neighbor(rte *r)
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
u32 as;
- if (e && as_path_get_last(e->u.ptr, &as))
+ if (e && as_path_get_first(e->u.ptr, &as))
return as;
else
return ((struct bgp_proto *) r->attrs->proto)->remote_as;
@@ -1191,7 +1191,7 @@ bgp_reconstruct_4b_atts(struct bgp_proto *p, rta *a, struct linpool *pool)
if (a4)
log(L_WARN "%s: AS4_AGGREGATOR attribute received, but AGGREGATOR attribute is missing", p->p.name);
- int p2_len = as_path_getlen(p2->u.ptr);
+ int p2_len = as_path_getlen_int(p2->u.ptr, 2);
int p4_len = p4 ? validate_as4_path(p, p4->u.ptr) : -1;
if (p4 && (p4_len < 0))
@@ -1247,7 +1247,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
int errcode;
byte *z, *attr_start;
byte seen[256/8];
- eattr *e;
ea_list *ea;
struct adata *ad;
@@ -1471,7 +1470,7 @@ bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
u32 origas;
buf += bsprintf(buf, " (%d) [", e->pref);
- if (p && as_path_get_first(p->u.ptr, &origas))
+ if (p && as_path_get_last(p->u.ptr, &origas))
buf += bsprintf(buf, "AS%u", origas);
if (o)
buf += bsprintf(buf, "%c", "ie?"[o->u.data]);
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 0c8ee6da..b38c6b13 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -120,7 +120,9 @@ bgp_startup(struct bgp_proto *p)
{
BGP_TRACE(D_EVENTS, "Started");
p->start_state = p->cf->capabilities ? BSS_CONNECT : BSS_CONNECT_NOCAP;
- bgp_active(p);
+
+ if (!p->cf->passive)
+ bgp_active(p);
}
static void
@@ -292,7 +294,8 @@ bgp_decision(void *vp)
DBG("BGP: Decision start\n");
if ((p->p.proto_state == PS_START)
- && (p->outgoing_conn.state == BS_IDLE))
+ && (p->outgoing_conn.state == BS_IDLE)
+ && (!p->cf->passive))
bgp_active(p);
if ((p->p.proto_state == PS_STOP)
@@ -428,8 +431,15 @@ bgp_hold_timeout(timer *t)
{
struct bgp_conn *conn = t->data;
- DBG("BGP: Hold timeout, closing connection\n");
- bgp_error(conn, 4, 0, NULL, 0);
+ DBG("BGP: Hold timeout\n");
+
+ /* If there is something in input queue, we are probably congested
+ and perhaps just not processed BGP packets in time. */
+
+ if (sk_rx_ready(conn->sk) > 0)
+ bgp_start_timer(conn->hold_timer, 10);
+ else
+ bgp_error(conn, 4, 0, NULL, 0);
}
static void
@@ -679,7 +689,7 @@ bgp_start_locked(struct object_lock *lock)
}
DBG("BGP: Got lock\n");
- p->local_id = cf->c.global->router_id;
+ p->local_id = proto_get_router_id(&cf->c);
p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip;
p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 9bbdab8e..0a82be2b 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -9,6 +9,7 @@
#ifndef _BIRD_BGP_H_
#define _BIRD_BGP_H_
+#include <stdint.h>
#include "nest/route.h"
struct linpool;
@@ -32,6 +33,7 @@ struct bgp_config {
int rs_client; /* Whether neighbor is RS client of me */
int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */
u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */
+ int passive; /* Do not initiate outgoing connection */
unsigned connect_retry_time;
unsigned hold_time, initial_hold_time;
unsigned keepalive_time;
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 872fb271..7360820f 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -22,7 +22,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4,
- CAPABILITIES, LIMIT)
+ CAPABILITIES, LIMIT, PASSIVE)
CF_GRAMMAR
@@ -34,7 +34,6 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
BGP_CFG->initial_hold_time = 240;
- BGP_CFG->default_med = 0;
BGP_CFG->compare_path_lengths = 1;
BGP_CFG->start_delay_time = 5;
BGP_CFG->error_amnesia_time = 300;
@@ -78,6 +77,7 @@ bgp_proto:
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
| bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
+ | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
;
CF_ADDTO(dynamic_attr, BGP_PATH
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index ac697be1..d126fe5f 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -234,7 +234,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
struct bgp_bucket *buck;
- int size;
+ int size, second;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
byte *w, *tmp, *tstart;
ip_addr *ipp, ip, ip_ll;
@@ -292,7 +292,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(nh);
- /* We have two addresses here in 'nh'. Really. */
+ /* We have two addresses here in 'nh'. Really.
+ Unless NEXT_HOP was modified by filter */
+ second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
ipp = (ip_addr *) nh->u.ptr->data;
ip = ipp[0];
ip_ll = IPA_NONE;
@@ -316,7 +318,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
n = neigh_find(&p->p, &ip, 0);
if (n && n->iface == p->neigh->iface)
{
- if (ipa_nonzero(ipp[1]))
+ if (second && ipa_nonzero(ipp[1]))
ip_ll = ipp[1];
else
{
@@ -569,7 +571,6 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
{
struct bgp_conn *other;
struct bgp_proto *p = conn->bgp;
- struct bgp_config *cf = p->cf;
unsigned hold;
u16 base_as;
u32 id;
@@ -601,7 +602,17 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
log(L_WARN "%s: Peer advertised inconsistent AS numbers", p->p.name);
if (conn->advertised_as != p->remote_as)
- { bgp_error(conn, 2, 2, (byte *) &(conn->advertised_as), -4); return; }
+ {
+ if (conn->peer_as4_support)
+ {
+ u32 val = htonl(conn->advertised_as);
+ bgp_error(conn, 2, 2, (byte *) &val, 4);
+ }
+ else
+ bgp_error(conn, 2, 2, pkt+20, 2);
+
+ return;
+ }
/* Check the other connection */
other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
@@ -973,11 +984,19 @@ bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned
{
*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]);
}
+ done:
*t = 0;
log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);
}