summaryrefslogtreecommitdiff
path: root/proto/bgp/bgp.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp/bgp.c')
-rw-r--r--proto/bgp/bgp.c166
1 files changed, 104 insertions, 62 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index dc845550..65673e37 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -101,6 +101,7 @@
* RFC 8203 - BGP Administrative Shutdown Communication
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
* RFC 8654 - Extended Message Support for BGP
+ * RFC 9117 - Revised Validation Procedure for BGP Flow Specifications
* draft-ietf-idr-ext-opt-param-07
* draft-uttaro-idr-bgp-persistence-04
* draft-walton-bgp-hostname-capability-02
@@ -113,7 +114,7 @@
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
-#include "nest/route.h"
+#include "nest/rt.h"
#include "nest/cli.h"
#include "nest/locks.h"
#include "conf/conf.h"
@@ -125,9 +126,7 @@
#include "bgp.h"
-struct linpool *bgp_linpool; /* Global temporary pool */
-struct linpool *bgp_linpool2; /* Global temporary pool for bgp_rt_notify() */
-static list bgp_sockets; /* Global list of listening sockets */
+static list STATIC_LIST_INIT(bgp_sockets); /* Global list of listening sockets */
static void bgp_connect(struct bgp_proto *p);
@@ -141,13 +140,7 @@ static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
static void bgp_listen_sock_err(sock *sk UNUSED, int err);
static void bgp_graceful_restart_feed(struct bgp_channel *c);
-static inline void channel_refresh_end_reload(struct channel *c)
-{
- channel_refresh_end(c);
- if (c->in_table)
- channel_request_reload(c);
-}
/**
* bgp_open - open a BGP instance
@@ -166,16 +159,17 @@ bgp_open(struct bgp_proto *p)
ip_addr addr = p->cf->strict_bind ? p->cf->local_ip :
(p->ipv4 ? IPA_NONE4 : IPA_NONE6);
uint port = p->cf->local_port;
-
- /* FIXME: Add some global init? */
- if (!bgp_linpool)
- init_list(&bgp_sockets);
+ uint flags = p->cf->free_bind ? SKF_FREEBIND : 0;
+ uint flag_mask = SKF_FREEBIND;
/* We assume that cf->iface is defined iff cf->local_ip is link-local */
WALK_LIST(bs, bgp_sockets)
- if (ipa_equal(bs->sk->saddr, addr) && (bs->sk->sport == port) &&
- (bs->sk->iface == ifa) && (bs->sk->vrf == p->p.vrf))
+ if (ipa_equal(bs->sk->saddr, addr) &&
+ (bs->sk->sport == port) &&
+ (bs->sk->iface == ifa) &&
+ (bs->sk->vrf == p->p.vrf) &&
+ ((bs->sk->flags & flag_mask) == flags))
{
bs->uc++;
p->sock = bs;
@@ -189,7 +183,7 @@ bgp_open(struct bgp_proto *p)
sk->sport = port;
sk->iface = ifa;
sk->vrf = p->p.vrf;
- sk->flags = 0;
+ sk->flags = flags;
sk->tos = IP_PREC_INTERNET_CONTROL;
sk->rbsize = BGP_RX_BUFFER_SIZE;
sk->tbsize = BGP_TX_BUFFER_SIZE;
@@ -207,12 +201,6 @@ bgp_open(struct bgp_proto *p)
add_tail(&bgp_sockets, &bs->n);
- if (!bgp_linpool)
- {
- bgp_linpool = lp_new_default(proto_pool);
- bgp_linpool2 = lp_new_default(proto_pool);
- }
-
return 0;
err:
@@ -241,15 +229,6 @@ bgp_close(struct bgp_proto *p)
rfree(bs->sk);
rem_node(&bs->n);
mb_free(bs);
-
- if (!EMPTY_LIST(bgp_sockets))
- return;
-
- rfree(bgp_linpool);
- bgp_linpool = NULL;
-
- rfree(bgp_linpool2);
- bgp_linpool2 = NULL;
}
static inline int
@@ -397,6 +376,7 @@ bgp_close_conn(struct bgp_conn *conn)
conn->keepalive_timer = NULL;
rfree(conn->hold_timer);
conn->hold_timer = NULL;
+
rfree(conn->tx_ev);
conn->tx_ev = NULL;
rfree(conn->sk);
@@ -535,8 +515,15 @@ void
bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len)
{
proto_notify_state(&p->p, PS_STOP);
+ p->uncork_ev->data = NULL;
bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
+
+ struct bgp_channel *c;
+ WALK_LIST(c, p->p.channels)
+ if (c->ptx)
+ bgp_free_pending_tx(c);
+
ev_schedule(p->event);
}
@@ -584,7 +571,6 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
p->link_addr = p->neigh->iface->llv6->ip;
conn->sk->fast_rx = 0;
- conn->sk->cork = &rt_cork;
p->conn = conn;
p->last_error_class = 0;
@@ -785,16 +771,16 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
{
case BGP_GRS_NONE:
c->gr_active = BGP_GRS_ACTIVE;
- channel_refresh_begin(&c->c);
+ rt_refresh_begin(&c->c.in_req);
break;
case BGP_GRS_ACTIVE:
- channel_refresh_end(&c->c);
- channel_refresh_begin(&c->c);
+ rt_refresh_end(&c->c.in_req);
+ rt_refresh_begin(&c->c.in_req);
break;
case BGP_GRS_LLGR:
- channel_refresh_begin(&c->c);
+ rt_refresh_begin(&c->c.in_req);
bgp_graceful_restart_feed(c);
break;
}
@@ -802,15 +788,13 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
else
{
/* Just flush the routes */
- channel_refresh_begin(&c->c);
- channel_refresh_end(&c->c);
+ rt_refresh_begin(&c->c.in_req);
+ rt_refresh_end(&c->c.in_req);
}
/* Reset bucket and prefix tables */
- bgp_free_bucket_table(c);
- bgp_free_prefix_table(c);
- bgp_init_bucket_table(c);
- bgp_init_prefix_table(c);
+ bgp_free_pending_tx(c);
+ bgp_init_pending_tx(c);
c->packets_to_send = 0;
}
@@ -862,10 +846,12 @@ bgp_graceful_restart_feed(struct bgp_channel *c)
.export_one = bgp_graceful_restart_drop_export,
};
- rt_request_export(c->c.table, &c->stale_feed);
+ rt_request_export(&c->c.table->exporter, &c->stale_feed);
}
+
+
/**
* bgp_graceful_restart_done - finish active BGP graceful restart
* @c: BGP channel
@@ -888,11 +874,8 @@ bgp_graceful_restart_done(struct bgp_channel *c)
if (!p->gr_active_num)
BGP_TRACE(D_EVENTS, "Neighbor graceful restart done");
- if (c->stale_feed.hook)
- rt_stop_export(&c->stale_feed, bgp_graceful_restart_feed_done);
-
tm_stop(c->stale_timer);
- channel_refresh_end_reload(&c->c);
+ rt_refresh_end(&c->c.in_req);
}
/**
@@ -972,7 +955,7 @@ bgp_refresh_begin(struct bgp_channel *c)
{ log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; }
c->load_state = BFS_REFRESHING;
- channel_refresh_begin(&c->c);
+ rt_refresh_begin(&c->c.in_req);
}
/**
@@ -993,7 +976,7 @@ bgp_refresh_end(struct bgp_channel *c)
{ log(L_WARN "%s: END-OF-RR received without prior BEGIN-OF-RR, ignoring", p->p.name); return; }
c->load_state = BFS_NONE;
- channel_refresh_end_reload(&c->c);
+ rt_refresh_end(&c->c.in_req);
}
@@ -1460,9 +1443,12 @@ bgp_reload_routes(struct channel *C)
struct bgp_proto *p = (void *) C->proto;
struct bgp_channel *c = (void *) C;
- ASSERT(p->conn && (p->route_refresh));
+ ASSERT(p->conn && (p->route_refresh || (C->in_keep & RIK_PREFILTER)));
- bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
+ if (C->in_keep & RIK_PREFILTER)
+ channel_schedule_reload(C);
+ else
+ bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
}
static void
@@ -1596,6 +1582,8 @@ bgp_start(struct proto *P)
p->last_rx_update = 0;
p->event = ev_new_init(p->p.pool, bgp_decision, p);
+ p->uncork_ev = ev_new_init(p->p.pool, bgp_uncork, p);
+
p->startup_timer = tm_new_init(p->p.pool, bgp_startup_timeout, p, 0, 0);
p->gr_timer = tm_new_init(p->p.pool, bgp_graceful_restart_timeout, p, 0, 0);
@@ -1790,6 +1778,9 @@ bgp_channel_init(struct channel *C, struct channel_config *CF)
if (cf->igp_table_ip6)
c->igp_table_ip6 = cf->igp_table_ip6->table;
+
+ if (cf->base_table)
+ c->base_table = cf->base_table->table;
}
static int
@@ -1805,15 +1796,21 @@ bgp_channel_start(struct channel *C)
if (c->igp_table_ip6)
rt_lock_table(c->igp_table_ip6);
+ if (c->base_table)
+ {
+ rt_lock_table(c->base_table);
+ rt_flowspec_link(c->base_table, c->c.table);
+ }
+
c->pool = p->p.pool; // XXXX
- bgp_init_bucket_table(c);
- bgp_init_prefix_table(c);
if (c->cf->import_table)
- channel_setup_in_table(C, 0);
+ channel_setup_in_table(C);
if (c->cf->export_table)
- channel_setup_out_table(C);
+ bgp_setup_out_table(c);
+
+ bgp_init_pending_tx(c);
c->stale_timer = tm_new_init(c->pool, bgp_long_lived_stale_timeout, c, 0, 0);
@@ -1889,6 +1886,12 @@ bgp_channel_cleanup(struct channel *C)
if (c->igp_table_ip6)
rt_unlock_table(c->igp_table_ip6);
+ if (c->base_table)
+ {
+ rt_flowspec_unlink(c->base_table, c->c.table);
+ rt_unlock_table(c->base_table);
+ }
+
c->index = 0;
/* Cleanup rest of bgp_channel starting at pool field */
@@ -1936,6 +1939,25 @@ bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32
cf_error("Undefined IGP table");
}
+static struct rtable_config *
+bgp_default_base_table(struct bgp_config *cf, struct bgp_channel_config *cc)
+{
+ /* Expected table type */
+ u32 type = (cc->afi == BGP_AF_FLOW4) ? NET_IP4 : NET_IP6;
+
+ /* First, try appropriate IP channel */
+ u32 afi2 = BGP_AF(BGP_AFI(cc->afi), BGP_SAFI_UNICAST);
+ struct bgp_channel_config *cc2 = bgp_find_channel_config(cf, afi2);
+ if (cc2 && (cc2->c.table->addr_type == type))
+ return cc2->c.table;
+
+ /* Last, try default table of given type */
+ struct rtable_config *tab = cf->c.global->def_tables[type];
+ if (tab)
+ return tab;
+
+ cf_error("Undefined base table");
+}
void
bgp_postconfig(struct proto_config *CF)
@@ -2080,6 +2102,14 @@ bgp_postconfig(struct proto_config *CF)
cf_error("Mismatched IGP table type");
}
+ /* Default value of base table */
+ if ((BGP_SAFI(cc->afi) == BGP_SAFI_FLOW) && cc->validate && !cc->base_table)
+ cc->base_table = bgp_default_base_table(cf, cc);
+
+ if (cc->base_table && !cc->base_table->trie_used)
+ cf_error("Flowspec validation requires base table (%s) with trie",
+ cc->base_table->name);
+
if (cf->multihop && (cc->gw_mode == GW_DIRECT))
cf_error("Multihop BGP cannot use direct gateway mode");
@@ -2148,7 +2178,7 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
return same;
}
-#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
+#define TABLE(cf, NAME) ((cf)->NAME ? (cf)->NAME->table : NULL )
static int
bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed, int *export_changed)
@@ -2159,6 +2189,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
struct bgp_channel_config *old = c->cf;
if ((new->secondary != old->secondary) ||
+ (new->validate != old->validate) ||
(new->gr_able != old->gr_able) ||
(new->llgr_able != old->llgr_able) ||
(new->llgr_time != old->llgr_time) ||
@@ -2166,8 +2197,9 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
(new->add_path != old->add_path) ||
(new->import_table != old->import_table) ||
(new->export_table != old->export_table) ||
- (IGP_TABLE(new, ip4) != IGP_TABLE(old, ip4)) ||
- (IGP_TABLE(new, ip6) != IGP_TABLE(old, ip6)))
+ (TABLE(new, igp_table_ip4) != TABLE(old, igp_table_ip4)) ||
+ (TABLE(new, igp_table_ip6) != TABLE(old, igp_table_ip6)) ||
+ (TABLE(new, base_table) != TABLE(old, base_table)))
return 0;
if (new->mandatory && !old->mandatory && (C->channel_state != CS_UP))
@@ -2178,7 +2210,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
(new->cost != old->cost))
{
/* import_changed itself does not force ROUTE_REFRESH when import_table is active */
- if (c->c.in_table && (c->c.channel_state == CS_UP))
+ if ((c->c.in_keep & RIK_PREFILTER) && (c->c.channel_state == CS_UP))
bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
*import_changed = 1;
@@ -2492,6 +2524,9 @@ bgp_show_proto_info(struct proto *P)
else
cli_msg(-1006, " Neighbor address: %I%J", p->remote_ip, p->cf->iface);
+ if ((p->conn == &p->outgoing_conn) && (p->cf->remote_port != BGP_PORT))
+ cli_msg(-1006, " Neighbor port: %u", p->cf->remote_port);
+
cli_msg(-1006, " Neighbor AS: %u", p->remote_as);
cli_msg(-1006, " Local AS: %u", p->cf->local_as);
@@ -2581,6 +2616,9 @@ bgp_show_proto_info(struct proto *P)
if (c->igp_table_ip6)
cli_msg(-1006, " IGP IPv6 table: %s", c->igp_table_ip6->name);
+
+ if (c->base_table)
+ cli_msg(-1006, " Base table: %s", c->base_table->name);
}
}
}
@@ -2598,7 +2636,6 @@ struct channel_class channel_bgp = {
struct protocol proto_bgp = {
.name = "BGP",
.template = "bgp%d",
- .class = PROTOCOL_BGP,
.preference = DEF_PREF_BGP,
.channel_mask = NB_IP | NB_VPN | NB_FLOW,
.proto_size = sizeof(struct bgp_proto),
@@ -2610,6 +2647,11 @@ struct protocol proto_bgp = {
.reconfigure = bgp_reconfigure,
.copy_config = bgp_copy_config,
.get_status = bgp_get_status,
- .get_attr = bgp_get_attr,
.show_proto_info = bgp_show_proto_info
};
+
+void bgp_build(void)
+{
+ proto_build(&proto_bgp);
+ bgp_register_attrs();
+}