summaryrefslogtreecommitdiffstats
path: root/proto/bgp/packets.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c112
1 files changed, 97 insertions, 15 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index d126fe5..91b4792 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -64,6 +64,14 @@ bgp_put_cap_ipv4(struct bgp_conn *conn UNUSED, byte *buf)
#endif
static byte *
+bgp_put_cap_rr(struct bgp_conn *conn UNUSED, byte *buf)
+{
+ *buf++ = 2; /* Capability 2: Support for route refresh */
+ *buf++ = 0; /* Capability data length */
+ return buf;
+}
+
+static byte *
bgp_put_cap_as4(struct bgp_conn *conn, byte *buf)
{
*buf++ = 65; /* Capability 65: Support for 4-octet AS number */
@@ -105,6 +113,9 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
cap = bgp_put_cap_ipv6(conn, cap);
#endif
+ if (p->cf->enable_refresh)
+ cap = bgp_put_cap_rr(conn, cap);
+
if (conn->want_as4_support)
cap = bgp_put_cap_as4(conn, cap);
@@ -199,7 +210,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (a_size < 0)
{
- log(L_ERR "%s: Attribute list too long, skipping corresponding route group", p->p.name);
+ log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
bgp_flush_prefixes(p, buck);
rem_node(&buck->send_node);
bgp_free_bucket(p, buck);
@@ -234,9 +245,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
struct bgp_bucket *buck;
- int size, second;
+ int size, second, rem_stored;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
- byte *w, *tmp, *tstart;
+ byte *w, *w_stored, *tmp, *tstart;
ip_addr *ipp, ip, ip_ll;
ea_list *ea;
eattr *nh;
@@ -272,28 +283,25 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
}
DBG("Processing bucket %p\n", buck);
- size = bgp_encode_attrs(p, w, buck->eattrs, 2048);
+ rem_stored = remains;
+ w_stored = w;
+ size = bgp_encode_attrs(p, w, buck->eattrs, 2048);
if (size < 0)
{
- log(L_ERR "%s: Attribute list too long, ignoring corresponding route group", p->p.name);
+ log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
bgp_flush_prefixes(p, buck);
rem_node(&buck->send_node);
bgp_free_bucket(p, buck);
continue;
}
-
w += size;
remains -= size;
- tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
- *tmp++ = 0;
- *tmp++ = BGP_AF_IPV6;
- *tmp++ = 1;
- 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 NEXT_HOP eattr. Really.
Unless NEXT_HOP was modified by filter */
+ nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
+ ASSERT(nh);
second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
ipp = (ip_addr *) nh->u.ptr->data;
ip = ipp[0];
@@ -322,12 +330,32 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
ip_ll = ipp[1];
else
{
- ip = p->source_addr;
- ip_ll = p->local_link;
+ switch (p->cf->missing_lladdr)
+ {
+ case MLL_SELF:
+ ip = p->source_addr;
+ ip_ll = p->local_link;
+ break;
+ case MLL_DROP:
+ log(L_ERR "%s: Missing link-local next hop address, skipping corresponding routes", p->p.name);
+ w = w_stored;
+ remains = rem_stored;
+ bgp_flush_prefixes(p, buck);
+ rem_node(&buck->send_node);
+ bgp_free_bucket(p, buck);
+ continue;
+ case MLL_IGNORE:
+ break;
+ }
}
}
}
+ tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
+ *tmp++ = 0;
+ *tmp++ = BGP_AF_IPV6;
+ *tmp++ = 1;
+
if (ipa_nonzero(ip_ll))
{
*tmp++ = 32;
@@ -369,6 +397,24 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
#endif
+static byte *
+bgp_create_route_refresh(struct bgp_conn *conn, byte *buf)
+{
+ struct bgp_proto *p = conn->bgp;
+ BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH");
+
+#ifdef IPV6
+ *buf++ = 0; /* AFI IPv6 */
+ *buf++ = BGP_AF_IPV6;
+#else
+ *buf++ = 0; /* AFI IPv4 */
+ *buf++ = BGP_AF_IPV4;
+#endif
+ *buf++ = 0; /* RFU */
+ *buf++ = 1; /* and SAFI 1 */
+ return buf;
+}
+
static void
bgp_create_header(byte *buf, unsigned int len, unsigned int type)
{
@@ -430,6 +476,12 @@ bgp_fire_tx(struct bgp_conn *conn)
type = PKT_OPEN;
end = bgp_create_open(conn, pkt);
}
+ else if (s & (1 << PKT_ROUTE_REFRESH))
+ {
+ s &= ~(1 << PKT_ROUTE_REFRESH);
+ type = PKT_ROUTE_REFRESH;
+ end = bgp_create_route_refresh(conn, pkt);
+ }
else if (s & (1 << PKT_UPDATE))
{
end = bgp_create_update(conn, pkt);
@@ -500,6 +552,11 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
switch (opt[0])
{
+ case 2:
+ if (cl != 0)
+ goto err;
+ conn->peer_refresh_support = 1;
+ break;
case 65:
if (cl != 4)
goto err;
@@ -1067,6 +1124,30 @@ bgp_rx_keepalive(struct bgp_conn *conn)
}
}
+static void
+bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len)
+{
+ struct bgp_proto *p = conn->bgp;
+
+ BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
+
+ if (conn->state != BS_ESTABLISHED)
+ { bgp_error(conn, 5, 0, NULL, 0); return; }
+
+ if (!p->cf->enable_refresh)
+ { bgp_error(conn, 1, 3, pkt+18, 1); return; }
+
+ if (len != (BGP_HEADER_LENGTH + 4))
+ { bgp_error(conn, 1, 2, pkt+16, 2); return; }
+
+ /* FIXME - we ignore AFI/SAFI values, as we support
+ just one value and even an error code for an invalid
+ request is not defined */
+
+ proto_request_feeding(&p->p);
+}
+
+
/**
* bgp_rx_packet - handle a received packet
* @conn: BGP connection
@@ -1086,6 +1167,7 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
case PKT_UPDATE: return bgp_rx_update(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);
}
}