mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Merge commit '0bb04d5390f21b0c96fc4894ba5d5510c541f0ef' into HEAD
This commit is contained in:
215
nest/iface.c
215
nest/iface.c
@@ -34,6 +34,9 @@
|
||||
#include "conf/conf.h"
|
||||
#include "sysdep/unix/krt.h"
|
||||
|
||||
|
||||
static TLIST_LIST(ifsub) iface_sub_list;
|
||||
static slab *iface_sub_slab;
|
||||
static pool *if_pool;
|
||||
|
||||
list iface_list;
|
||||
@@ -140,13 +143,53 @@ if_copy(struct iface *to, struct iface *from)
|
||||
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
|
||||
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
ifa_send_notify(struct iface_subscription *s, unsigned c, struct ifa *a)
|
||||
{
|
||||
if (p->ifa_notify &&
|
||||
struct proto *p = SKIP_BACK(struct proto, iface_sub, s);
|
||||
|
||||
if (s->ifa_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == a->iface->master))
|
||||
{
|
||||
@@ -154,19 +197,21 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
log(L_TRACE "%s < address %N on interface %s %s",
|
||||
p->name, &a->prefix, a->iface->name,
|
||||
(c & IF_CHANGE_UP) ? "added" : "removed");
|
||||
p->ifa_notify(p, c, a);
|
||||
s->ifa_notify(p, c, a);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ifa_notify_change_(unsigned c, struct ifa *a)
|
||||
{
|
||||
struct proto *p;
|
||||
|
||||
DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
|
||||
|
||||
WALK_LIST(p, proto_list)
|
||||
ifa_send_notify(p, c, a);
|
||||
if_enqueue_notify((struct iface_notification) {
|
||||
.type = IFNOT_ADDRESS,
|
||||
.a = a,
|
||||
.flags = c,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -182,9 +227,11 @@ ifa_notify_change(unsigned c, struct ifa *a)
|
||||
}
|
||||
|
||||
static inline void
|
||||
if_send_notify(struct proto *p, unsigned c, struct iface *i)
|
||||
if_send_notify(struct iface_subscription *s, unsigned c, struct iface *i)
|
||||
{
|
||||
if (p->if_notify &&
|
||||
struct proto *p = SKIP_BACK(struct proto, iface_sub, s);
|
||||
|
||||
if (s->if_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == i->master))
|
||||
{
|
||||
@@ -197,14 +244,13 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
|
||||
(c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
|
||||
(c & IF_CHANGE_CREATE) ? "created" :
|
||||
"sends unknown event");
|
||||
p->if_notify(p, c, i);
|
||||
s->if_notify(p, c, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
if_notify_change(unsigned c, struct iface *i)
|
||||
{
|
||||
struct proto *p;
|
||||
struct ifa *a;
|
||||
|
||||
if (i->flags & IF_JUST_CREATED)
|
||||
@@ -225,8 +271,11 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
WALK_LIST(a, i->addrs)
|
||||
ifa_notify_change_(IF_CHANGE_DOWN, a);
|
||||
|
||||
WALK_LIST(p, proto_list)
|
||||
if_send_notify(p, c, i);
|
||||
if_enqueue_notify((struct iface_notification) {
|
||||
.type = IFNOT_INTERFACE,
|
||||
.i = i,
|
||||
.flags = c,
|
||||
});
|
||||
|
||||
if (c & IF_CHANGE_UP)
|
||||
WALK_LIST(a, i->addrs)
|
||||
@@ -320,6 +369,7 @@ if_update(struct iface *new)
|
||||
new->llv6 = i->llv6;
|
||||
new->sysdep = i->sysdep;
|
||||
memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
|
||||
memcpy(&new->neighbors, &i->neighbors, sizeof(i->neighbors));
|
||||
memcpy(i, new, sizeof(*i));
|
||||
i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
|
||||
goto newif;
|
||||
@@ -334,9 +384,10 @@ if_update(struct iface *new)
|
||||
}
|
||||
i = mb_alloc(if_pool, sizeof(struct iface));
|
||||
memcpy(i, new, sizeof(*i));
|
||||
if_link(i->master);
|
||||
init_list(&i->addrs);
|
||||
newif:
|
||||
init_list(&i->neighbors);
|
||||
newif:
|
||||
i->flags |= IF_UPDATED | IF_TMP_DOWN; /* Tmp down as we don't have addresses yet */
|
||||
add_tail(&iface_list, &i->n);
|
||||
return i;
|
||||
@@ -387,39 +438,117 @@ if_end_update(void)
|
||||
}
|
||||
|
||||
void
|
||||
if_flush_ifaces(struct proto *p)
|
||||
if_link(struct iface *i)
|
||||
{
|
||||
if (p->debug & D_EVENTS)
|
||||
log(L_TRACE "%s: Flushing interfaces", p->name);
|
||||
if_start_update();
|
||||
if_end_update();
|
||||
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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
void
|
||||
if_feed_baby(struct proto *p)
|
||||
iface_subscribe(struct iface_subscription *s)
|
||||
{
|
||||
struct iface *i;
|
||||
struct ifa *a;
|
||||
ifsub_add_tail(&iface_sub_list, s);
|
||||
s->event = (event) {
|
||||
.hook = iface_notify_hook,
|
||||
.data = s,
|
||||
};
|
||||
|
||||
if (!p->if_notify && !p->ifa_notify) /* shortcut */
|
||||
if (!s->if_notify && !s->ifa_notify) /* shortcut */
|
||||
return;
|
||||
|
||||
struct iface *i;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if_find_by_index - find interface by ifindex
|
||||
* @idx: ifindex
|
||||
@@ -609,6 +738,8 @@ ifa_update(struct ifa *a)
|
||||
|
||||
b = mb_alloc(if_pool, sizeof(struct ifa));
|
||||
memcpy(b, a, sizeof(struct ifa));
|
||||
ifa_link(b);
|
||||
if_link(i);
|
||||
add_tail(&i->addrs, &b->n);
|
||||
b->flags |= IA_UPDATED;
|
||||
|
||||
@@ -655,11 +786,36 @@ ifa_delete(struct ifa *a)
|
||||
if (i->flags & IF_UP)
|
||||
ifa_notify_change(IF_CHANGE_DOWN, b);
|
||||
|
||||
mb_free(b);
|
||||
ifa_unlink(b);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -715,6 +871,7 @@ if_init(void)
|
||||
{
|
||||
if_pool = rp_new(&root_pool, "Interfaces");
|
||||
init_list(&iface_list);
|
||||
iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
|
||||
strcpy(default_vrf.name, "default");
|
||||
neigh_init(if_pool);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user