to->flags = from->flags | (to->flags & IF_TMP_DOWN);
to->mtu = from->mtu;
to->master_index = from->master_index;
- to->master = from->master;
+
+ if_unlink(to->master);
+ if_link(to->master = from->master);
+ }
+
+ void
+ if_enqueue_notify_to(struct iface_notification x, struct iface_subscription *s)
+ {
+ switch (x.type) {
+ case IFNOT_ADDRESS:
+ if (!s->ifa_notify) return;
+ ifa_link(x.a);
+ break;
+ case IFNOT_INTERFACE:
+ if (!s->if_notify) return;
+ if_link(x.i);
+ break;
+ case IFNOT_NEIGHBOR:
+ if (!s->neigh_notify) return;
+ neigh_link(x.n);
+ break;
+ default:
+ bug("Unknown interface notification type: %d", x.type);
+ }
+
+ struct iface_notification *in = sl_alloc(iface_sub_slab);
+ *in = x;
+
++ debug("Enqueue notify %d/%p (%p) to %p\n", x.type, x.a, in, s);
++
+ ifnot_add_tail(&s->queue, in);
+ ev_schedule(&s->event);
+ }
+
+ void
+ if_enqueue_notify(struct iface_notification x)
+ {
+ WALK_TLIST(ifsub, s, &iface_sub_list)
+ if_enqueue_notify_to(x, s);
}
static inline void
}
void
- if_flush_ifaces(struct proto *p)
+ if_link(struct iface *i)
+ {
+ if (i)
+ i->uc++;
+ }
+
+ void
+ if_unlink(struct iface *i)
+ {
+ if (i)
+ i->uc--;
+ /* TODO: Do some interface object cleanup */
+ }
+
+ static void
+ iface_notify_hook(void *_s)
{
- if (p->debug & D_EVENTS)
- log(L_TRACE "%s: Flushing interfaces", p->name);
- if_start_update();
- if_end_update();
+ struct iface_subscription *s = _s;
+
+ while (!EMPTY_TLIST(ifnot, &s->queue))
+ {
+ struct iface_notification *n = THEAD(ifnot, &s->queue);
++ debug("Process notify %d/%p (%p) to %p\n", n->type, n->a, n, s);
+ switch (n->type) {
+ case IFNOT_ADDRESS:
+ ifa_send_notify(s, n->flags, n->a);
+ ifa_unlink(n->a);
+ break;
+ case IFNOT_INTERFACE:
+ if_send_notify(s, n->flags, n->i);
+ if_unlink(n->i);
+ break;
+ case IFNOT_NEIGHBOR:
+ s->neigh_notify(n->n);
+ neigh_unlink(n->n);
+ break;
+ default:
+ bug("Bad interface notification type: %d", n->type);
+ }
+
+ ifnot_rem_node(&s->queue, n);
+ sl_free(n);
+ }
}
+
/**
- * if_feed_baby - advertise interfaces to a new protocol
- * @p: protocol to feed
+ * iface_subscribe - request interface updates
+ * @s: subscription structure
*
* When a new protocol starts, this function sends it a series
* of notifications about all existing interfaces.
DBG("Announcing interfaces to new protocol %s\n", p->name);
WALK_LIST(i, iface_list)
{
- if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
+ if_send_notify(s, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
+
+ struct ifa *a;
if (i->flags & IF_UP)
WALK_LIST(a, i->addrs)
- ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
+ ifa_send_notify(s, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
+ }
+ }
+
+ /**
+ * iface_unsubscribe - unsubscribe from interface updates
+ * @s: subscription structure
+ */
+ void
+ iface_unsubscribe(struct iface_subscription *s)
+ {
+ ifsub_rem_node(&iface_sub_list, s);
+ ev_postpone(&s->event);
+
+ WALK_TLIST_DELSAFE(ifnot, n, &s->queue)
+ {
++ debug("Drop notify %d/%p (%p) to %p\n", n->type, n->a, n, s);
+ switch (n->type)
+ {
+ case IFNOT_ADDRESS:
+ ifa_unlink(n->a);
+ break;
+ case IFNOT_INTERFACE:
+ if_unlink(n->i);
+ break;
+ case IFNOT_NEIGHBOR:
+ neigh_unlink(n->n);
+ break;
+ default:
+ bug("Bad interface notification type: %d", n->type);
}
+
+ ifnot_rem_node(&s->queue, n);
+ sl_free(n);
+ }
}
/**
}
}
+ void ifa_link(struct ifa *a)
+ {
+ if (a)
++ {
++ debug("ifa_link: %p %d\n", a, a->uc);
+ a->uc++;
++ }
+ }
+
+ void ifa_unlink(struct ifa *a)
+ {
+ if (!a)
+ return;
+
++ debug("ifa_unlink: %p %d\n", a, a->uc);
+ if (--a->uc)
+ return;
+
+ if_unlink(a->iface);
++#if DEBUGGING
++ memset(a, 0x5b, sizeof(struct ifa));
++#endif
+ mb_free(a);
+ }
+
u32
if_choose_router_id(struct iface_patt *mask, u32 old_id)
{
return 1;
}
+static void
+proto_cleanup(struct proto *p)
+{
++ CALL(p->proto->cleanup, p);
++
+ rfree(p->pool);
+ p->pool = NULL;
+
+ p->active = 0;
+ proto_log_state_change(p);
+ proto_rethink_goal(p);
+}
static void
-proto_event(void *ptr)
+proto_loop_stopped(void *ptr)
{
struct proto *p = ptr;
proto_do_start(struct proto *p)
{
p->active = 1;
- p->do_start = 1;
- ev_schedule(p->event);
+
+ rt_init_sources(&p->sources, p->name, proto_event_list(p));
+ if (!p->sources.class)
+ p->sources.class = &default_rte_owner_class;
+
+ if (!p->cf->late_if_feed)
- if_feed_baby(p);
++ iface_subscribe(&p->iface_sub);
}
static void
proto_do_up(struct proto *p)
{
if (!p->main_source)
- {
p->main_source = rt_get_source(p, 0);
- rt_lock_source(p->main_source);
- }
+ // Locked automaticaly
proto_start_channels(p);
- if_feed_baby(p);
+
+ if (p->cf->late_if_feed)
++ iface_subscribe(&p->iface_sub);
}
static inline void
proto_do_down(struct proto *p)
{
p->down_code = 0;
- neigh_prune();
- rfree(p->pool);
- p->pool = NULL;
/* Shutdown is finished in the protocol event */
if (proto_is_done(p))
#ifndef _BIRD_PROTOCOL_H_
#define _BIRD_PROTOCOL_H_
- #include "lib/lists.h"
+ #include "lib/tlists.h"
#include "lib/resource.h"
#include "lib/event.h"
-#include "nest/route.h"
+ #include "nest/iface.h"
+#include "lib/settle.h"
+#include "nest/rt.h"
+#include "nest/limit.h"
#include "conf/conf.h"
struct iface;
void (*dump)(struct proto *); /* Debugging dump */
int (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */
- void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
++ void (*cleanup)(struct proto *); /* Cleanup the instance right before tearing it all down */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
- void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
- int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
+// int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
};
list channels; /* List of channels to rtables (struct channel) */
struct channel *main_channel; /* Primary channel */
struct rte_src *main_source; /* Primary route source */
+ struct rte_owner sources; /* Route source owner structure */
struct iface *vrf; /* Related VRF instance, NULL if global */
+ TLIST_LIST(proto_neigh) neighbors; /* List of neighbor structures */
+ struct iface_subscription iface_sub; /* Interface notification subscription */
- const char *name; /* Name of this instance (== cf->name) */
+ const char *name; /* Name of this instance (== cf->name) */
u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */
uint active_channels; /* Number of active channels */
* feed_end Notify channel about finish of route feeding.
*/
- void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
- void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
- void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
+ void (*rt_notify)(struct proto *, struct channel *, const net_addr *net, struct rte *new, const struct rte *old);
- void (*neigh_notify)(struct neighbor *neigh);
int (*preexport)(struct channel *, struct rte *rt);
void (*reload_routes)(struct channel *);
void (*feed_begin)(struct channel *, int initial);
* as a result of received ROUTE-REFRESH request).
*/
- { return (p->active_channels == 0) && (p->active_loops == 0) && (p->sources.uc == 0); }
+static inline int proto_is_inactive(struct proto *p)
++{
++ return (p->active_channels == 0)
++ && (p->active_loops == 0)
++ && (p->sources.uc == 0)
++ && EMPTY_TLIST(proto_neigh, &p->neighbors)
++ ;
++}
/*
proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
- P->if_notify = babel_if_notify;
+ P->iface_sub.if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
P->preexport = babel_preexport;
- P->rte_better = babel_rte_better;
- P->rte_igp_metric = babel_rte_igp_metric;
+
+ P->sources.class = &babel_rte_owner_class;
return P;
}
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
static void bgp_listen_sock_err(sock *sk UNUSED, int err);
+ static void bgp_initiate_disable(struct bgp_proto *p, int err_val);
- /**
- * bgp_open - open a BGP instance
- * @p: BGP instance
- *
- * This function allocates and configures shared BGP resources, mainly listening
- * sockets. Should be called as the last step during initialization (when lock
- * is acquired and neighbor is ready). When error, caller should change state to
- * PS_DOWN and return immediately.
- */
- static int
- bgp_open(struct bgp_proto *p)
+static void bgp_graceful_restart_feed(struct bgp_channel *c);
+
+
+ static inline int
+ bgp_setup_auth(struct bgp_proto *p, int enable)
{
- struct bgp_socket *bs = NULL;
- struct iface *ifa = p->cf->strict_bind ? p->cf->iface : NULL;
- ip_addr addr = p->cf->strict_bind ? p->cf->local_ip :
- (p->ipv4 ? IPA_NONE4 : IPA_NONE6);
- uint port = p->cf->local_port;
- 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 */
+ if (p->cf->password && p->listen.sock)
+ {
+ ip_addr prefix = p->cf->remote_ip;
+ int pxlen = -1;
- 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) &&
- ((bs->sk->flags & flag_mask) == flags))
+ if (p->cf->remote_range)
{
- bs->uc++;
- p->sock = bs;
- return 0;
+ prefix = net_prefix(p->cf->remote_range);
+ pxlen = net_pxlen(p->cf->remote_range);
}
- sock *sk = sk_new(proto_pool);
- sk->type = SK_TCP_PASSIVE;
- sk->ttl = 255;
- sk->saddr = addr;
- sk->sport = port;
- sk->iface = ifa;
- sk->vrf = p->p.vrf;
- sk->flags = flags;
- sk->tos = IP_PREC_INTERNET_CONTROL;
- sk->rbsize = BGP_RX_BUFFER_SIZE;
- sk->tbsize = BGP_TX_BUFFER_SIZE;
- sk->rx_hook = bgp_incoming_connection;
- sk->err_hook = bgp_listen_sock_err;
-
- if (sk_open(sk) < 0)
- goto err;
-
- bs = mb_allocz(proto_pool, sizeof(struct bgp_socket));
- bs->sk = sk;
- bs->uc = 1;
- p->sock = bs;
- sk->data = bs;
-
- add_tail(&bgp_sockets, &bs->n);
+ int rv = sk_set_md5_auth(p->listen.sock->sk,
+ p->cf->local_ip, prefix, pxlen, p->cf->iface,
+ enable ? p->cf->password : NULL, p->cf->setkey);
- return 0;
+ if (rv < 0)
+ sk_log_error(p->listen.sock->sk, p->p.name);
- err:
- sk_log_error(sk, p->p.name);
- log(L_ERR "%s: Cannot open listening socket", p->p.name);
- rfree(sk);
- return -1;
+ return rv;
+ }
+ else
+ return 0;
}
/**
struct bgp_conn incoming_conn; /* Incoming connection we have neither accepted nor rejected yet */
struct object_lock *lock; /* Lock for neighbor connection */
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
- struct bgp_socket *sock; /* Shared listening socket */
+ struct bgp_listen_request listen; /* Shared listening socket */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
struct birdsock *postponed_sk; /* Postponed incoming socket for dynamic BGP */
+ event *uncork_ev; /* Uncork event in case of congestion */
struct bgp_stats stats; /* BGP statistics */
btime last_established; /* Last time of enter/leave of established state */
btime last_rx_update; /* Last time of RX update */
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- P->if_notify = rip_if_notify;
+ P->iface_sub.if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify;
- P->neigh_notify = rip_neigh_notify;
+ P->iface_sub.neigh_notify = rip_neigh_notify;
P->reload_routes = rip_reload_routes;
- P->rte_better = rip_rte_better;
- P->rte_igp_metric = rip_rte_igp_metric;
+ P->sources.class = &rip_rte_owner_class;
return P;
}
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- P->neigh_notify = static_neigh_notify;
+ P->iface_sub.neigh_notify = static_neigh_notify;
P->reload_routes = static_reload_routes;
- P->rte_better = static_rte_better;
- P->rte_mergable = static_rte_mergable;
+ P->sources.class = &static_rte_owner_class;
if (cf->igp_table_ip4)
p->igp_table_ip4 = cf->igp_table_ip4->table;