Commit d37513a3 authored by Maria Matejka's avatar Maria Matejka
Browse files

Neighbors: Locking and asynchronous notifications

parent c651cef7
Loading
Loading
Loading
Loading
+64 −2
Original line number Diff line number Diff line
@@ -36,10 +36,12 @@

static pool *if_pool;

DOMAIN(attrs) iface_domain;
list global_iface_list;
struct iface default_vrf;

static void if_recalc_preferred(struct iface *i);
static void ifa_delete_locked(struct ifa *a);

/**
 * ifa_dump - dump interface address
@@ -50,6 +52,7 @@ static void if_recalc_preferred(struct iface *i);
void
ifa_dump(struct ifa *a)
{
  IFACE_LEGACY_ACCESS;
  debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
	(a->flags & IA_PRIMARY) ? " PRIMARY" : "",
	(a->flags & IA_SECONDARY) ? " SEC" : "",
@@ -69,6 +72,7 @@ if_dump(struct iface *i)
{
  struct ifa *a;

  IFACE_LEGACY_ACCESS;
  debug("IF%d: %s", i->index, i->name);
  if (i->flags & IF_SHUTDOWN)
    debug(" SHUTDOWN");
@@ -110,6 +114,7 @@ if_dump_all(void)
{
  struct iface *i;

  IFACE_LEGACY_ACCESS;
  debug("Known network interfaces:\n");
  WALK_LIST(i, global_iface_list)
    if_dump(i);
@@ -307,6 +312,9 @@ if_update(struct iface *new)
  if (!new->master)
    new->master = &default_vrf;

  IFACE_LEGACY_ACCESS;
  IFACE_LOCK;

  WALK_LIST(i, global_iface_list)
    if (!strcmp(new->name, i->name))
      {
@@ -328,6 +336,8 @@ if_update(struct iface *new)
	  }

	if_copy(i, new);
	IFACE_UNLOCK;

	if (c)
	  if_notify_change(c, i);

@@ -341,6 +351,8 @@ newif:
  init_list(&i->neighbors);
  i->flags |= IF_UPDATED | IF_TMP_DOWN;		/* Tmp down as we don't have addresses yet */
  add_tail(&global_iface_list, &i->n);
  IFACE_UNLOCK;

  return i;
}

@@ -350,6 +362,7 @@ if_start_update(void)
  struct iface *i;
  struct ifa *a;

  IFACE_LEGACY_ACCESS;
  WALK_LIST(i, global_iface_list)
    {
      i->flags &= ~IF_UPDATED;
@@ -361,6 +374,8 @@ if_start_update(void)
void
if_end_partial_update(struct iface *i)
{
  IFACE_LEGACY_ACCESS;

  if (i->flags & IF_NEEDS_RECALC)
    if_recalc_preferred(i);

@@ -374,6 +389,7 @@ if_end_update(void)
  struct iface *i;
  struct ifa *a, *b;

  IFACE_LEGACY_ACCESS;
  WALK_LIST(i, global_iface_list)
    {
      if (!(i->flags & IF_UPDATED))
@@ -382,7 +398,11 @@ if_end_update(void)
	{
	  WALK_LIST_DELSAFE(a, b, i->addrs)
	    if (!(a->flags & IA_UPDATED))
	      ifa_delete(a);
	    {
	      IFACE_LOCK;
	      ifa_delete_locked(a);
	      IFACE_UNLOCK;
	    }
	  if_end_partial_update(i);
	}
    }
@@ -391,6 +411,7 @@ if_end_update(void)
void
if_flush_ifaces(struct proto *p)
{
  IFACE_LEGACY_ACCESS;
  if (p->debug & D_EVENTS)
    log(L_TRACE "%s: Flushing interfaces", p->name);
  if_start_update();
@@ -410,6 +431,8 @@ if_feed_baby(struct proto *p)
  struct iface *i;
  struct ifa *a;

  IFACE_LEGACY_ACCESS;

  if (!p->if_notify && !p->ifa_notify)	/* shortcut */
    return;
  DBG("Announcing interfaces to new protocol %s\n", p->name);
@@ -435,9 +458,15 @@ if_find_by_index(unsigned idx)
{
  struct iface *i;

  IFACE_LOCK;
  WALK_LIST(i, global_iface_list)
    if (i->index == idx && !(i->flags & IF_SHUTDOWN))
    {
      IFACE_UNLOCK;
      return i;
    }

  IFACE_UNLOCK;
  return NULL;
}

@@ -454,9 +483,15 @@ if_find_by_name(const char *name)
{
  struct iface *i;

  IFACE_LOCK;
  WALK_LIST(i, global_iface_list)
    if (!strcmp(i->name, name) && !(i->flags & IF_SHUTDOWN))
    {
      IFACE_UNLOCK;
      return i;
    }

  IFACE_UNLOCK;
  return NULL;
}

@@ -465,17 +500,21 @@ if_get_by_name(const char *name)
{
  struct iface *i;

  IFACE_LEGACY_ACCESS;

  WALK_LIST(i, global_iface_list)
    if (!strcmp(i->name, name))
      return i;

  /* No active iface, create a dummy */
  IFACE_LOCK;
  i = mb_allocz(if_pool, sizeof(struct iface));
  strncpy(i->name, name, sizeof(i->name)-1);
  i->flags = IF_SHUTDOWN;
  init_list(&i->addrs);
  init_list(&i->neighbors);
  add_tail(&global_iface_list, &i->n);
  IFACE_UNLOCK;
  return i;
}

@@ -561,6 +600,8 @@ if_recalc_all_preferred_addresses(void)
{
  struct iface *i;

  IFACE_LEGACY_ACCESS;

  WALK_LIST(i, global_iface_list)
  {
    if_recalc_preferred(i);
@@ -591,6 +632,8 @@ ifa_update(struct ifa *a)
  struct iface *i = a->iface;
  struct ifa *b;

  IFACE_LEGACY_ACCESS;

  WALK_LIST(b, i->addrs)
    if (ifa_same(b, a))
      {
@@ -609,10 +652,12 @@ ifa_update(struct ifa *a)
  if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd))
    log(L_WARN "Missing broadcast address for interface %s", i->name);

  IFACE_LOCK;
  b = mb_alloc(if_pool, sizeof(struct ifa));
  memcpy(b, a, sizeof(struct ifa));
  add_tail(&i->addrs, &b->n);
  b->flags |= IA_UPDATED;
  IFACE_UNLOCK;

  i->flags |= IF_NEEDS_RECALC;
  if (i->flags & IF_UP)
@@ -637,6 +682,17 @@ ifa_delete(struct ifa *a)
  WALK_LIST(b, i->addrs)
    if (ifa_same(b, a))
      {
	IFACE_LOCK;
	ifa_delete_locked(b);
	IFACE_UNLOCK;
	return;
      }
}

static void
ifa_delete_locked(struct ifa *b)
{
	struct iface *i = b->iface;
	rem_node(&b->n);

	if (b->flags & IA_PRIMARY)
@@ -660,7 +716,6 @@ ifa_delete(struct ifa *a)
	mb_free(b);
	return;
}
}

u32
if_choose_router_id(struct iface_patt *mask, u32 old_id)
@@ -668,6 +723,8 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id)
  struct iface *i;
  struct ifa *a, *b;

  IFACE_LEGACY_ACCESS;

  b = NULL;
  WALK_LIST(i, global_iface_list)
    {
@@ -715,6 +772,7 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id)
void
if_init(void)
{
  iface_domain = DOMAIN_NEW(attrs, "Interfaces");
  if_pool = rp_new(&root_pool, &main_birdloop, "Interfaces");
  init_list(&global_iface_list);
  strcpy(default_vrf.name, "default");
@@ -844,6 +902,8 @@ if_show(void)
  struct ifa *a;
  char *type;

  IFACE_LEGACY_ACCESS;

  WALK_LIST(i, global_iface_list)
    {
      if (i->flags & IF_SHUTDOWN)
@@ -886,6 +946,8 @@ if_show_summary(void)
{
  struct iface *i;

  IFACE_LEGACY_ACCESS;

  cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
  WALK_LIST(i, global_iface_list)
    {
+11 −0
Original line number Diff line number Diff line
@@ -9,10 +9,20 @@
#ifndef _BIRD_IFACE_H_
#define _BIRD_IFACE_H_

#include "lib/event.h"
#include "lib/lists.h"
#include "lib/ip.h"
#include "lib/locking.h"

DEFINE_DOMAIN(attrs);
extern list global_iface_list;
extern DOMAIN(attrs) iface_domain;

#define IFACE_LEGACY_ACCESS	ASSERT_DIE(birdloop_inside(&main_birdloop))

#define IFACE_LOCK	  LOCK_DOMAIN(attrs, iface_domain)
#define IFACE_UNLOCK	UNLOCK_DOMAIN(attrs, iface_domain)
#define ASSERT_IFACE_LOCKED	ASSERT_DIE(DOMAIN_IS_LOCKED(attrs, iface_domain))

struct proto;
struct pool;
@@ -131,6 +141,7 @@ typedef struct neighbor {
  struct ifa *ifa;			/* Ifa on related iface */
  struct iface *iface;			/* Interface it's connected to */
  struct iface *ifreq;			/* Requested iface, NULL for any */
  struct event event;			/* Notification event */
  struct proto *proto;			/* Protocol this belongs to */
  void *data;				/* Protocol-specific data */
  uint aux;				/* Protocol-specific data */
+71 −10
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@

static slab *neigh_slab;
static list neigh_hash_table[NEIGH_HASH_SIZE], sticky_neigh_list;
static void neigh_do_notify(void *);

static inline uint
neigh_hash(struct proto *p, ip_addr a, struct iface *i)
@@ -210,36 +211,40 @@ if_intersect(struct iface *ia, struct iface *ib)
neighbor *
neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
{
  ASSERT_DIE(birdloop_inside(&main_birdloop));

  neighbor *n;
  int class, scope = -1;
  uint h = neigh_hash(p, a, iface);
  struct iface *ifreq = iface;
  struct ifa *addr = NULL;

  IFACE_LOCK;
  WALK_LIST(n, neigh_hash_table[h])	/* Search the cache */
    if ((n->proto == p) && ipa_equal(n->addr, a) && (n->ifreq == iface))
    {
      IFACE_UNLOCK;
      return n;
    }

#define NOT_FOUND goto not_found

  if (flags & NEF_IFACE)
  {
    if (ipa_nonzero(a) || !iface)
      return NULL;
      NOT_FOUND;
  }
  else
  {
    class = ipa_classify(a);
    if (class < 0)			/* Invalid address */
      return NULL;
      NOT_FOUND;
    if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) ||
	(((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && !iface) ||
	!(class & IADDR_HOST))
      return NULL;			/* Bad scope or a somecast */
      NOT_FOUND;			/* Bad scope or a somecast */
  }

  if ((flags & NEF_ONLINK) && !iface)
      return NULL;
    NOT_FOUND;

  if (iface)
  {
@@ -253,7 +258,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
  /* scope >= 0  <=>  iface != NULL */

  if ((scope < 0) && !(flags & NEF_STICKY))
    return NULL;
    NOT_FOUND;

  n = sl_allocz(neigh_slab);
  add_tail(&neigh_hash_table[h], &n->n);
@@ -265,8 +270,23 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
  n->proto = p;
  n->flags = flags;
  n->scope = scope;
  n->event = (event) { .hook = neigh_do_notify, .data = n };
  ASSERT_DIE(birdloop_inside(p->loop));

  if (p->loop == &main_birdloop)
    n->event.list = &global_event_list;
  else
  {
    birdloop_link(p->loop);
    n->event.list = birdloop_event_list(p->loop);
  }

  IFACE_UNLOCK;
  return n;

not_found:
  IFACE_UNLOCK;
  return NULL;
}

/**
@@ -300,11 +320,15 @@ neigh_dump_all(void)
  neighbor *n;
  int i;

  IFACE_LOCK;

  debug("Known neighbors:\n");
  for(i=0; i<NEIGH_HASH_SIZE; i++)
    WALK_LIST(n, neigh_hash_table[i])
      neigh_dump(n);
  debug("\n");

  IFACE_UNLOCK;
}

static inline void
@@ -313,7 +337,16 @@ neigh_notify(neighbor *n)
  if (!n->proto->neigh_notify)
    return;

  PROTO_LOCKED_FROM_MAIN(n->proto)
  ev_send(n->event.list, &n->event);
}

static void
neigh_do_notify(void *data)
{
  neighbor *n = data;

  ASSERT_DIE(birdloop_inside(n->proto->loop));

  if (n->proto->proto_state != PS_STOP)
    n->proto->neigh_notify(n);
}
@@ -351,6 +384,8 @@ neigh_free(neighbor *n)
{
  rem_node(&n->n);
  rem_node(&n->if_n);
  ev_postpone(&n->event);
  birdloop_unlink(n->proto->loop);
  sl_free(neigh_slab, n);
}

@@ -366,6 +401,8 @@ neigh_free(neighbor *n)
void
neigh_update(neighbor *n, struct iface *iface)
{
  ASSERT_IFACE_LOCKED;

  struct proto *p = n->proto;
  struct ifa *ifa = NULL;
  int scope = -1;
@@ -439,6 +476,8 @@ neigh_if_up(struct iface *i)
  neighbor *n;
  node *x, *y;

  IFACE_LOCK;

  /* Update neighbors that might be better off with the new iface */
  WALK_LIST(ii, global_iface_list)
    if (!EMPTY_LIST(ii->neighbors) && (ii != i) && if_intersect(i, ii))
@@ -447,6 +486,8 @@ neigh_if_up(struct iface *i)

  WALK_LIST2_DELSAFE(n, x, y, sticky_neigh_list, if_n)
    neigh_update(n, i);

  IFACE_UNLOCK;
}

/**
@@ -463,8 +504,12 @@ neigh_if_down(struct iface *i)
  neighbor *n;
  node *x, *y;

  IFACE_LOCK;

  WALK_LIST2_DELSAFE(n, x, y, i->neighbors, if_n)
    neigh_update(n, i);

  IFACE_UNLOCK;
}

/**
@@ -480,8 +525,12 @@ neigh_if_link(struct iface *i)
  neighbor *n;
  node *x, *y;

  IFACE_LOCK;

  WALK_LIST2_DELSAFE(n, x, y, i->neighbors, if_n)
    neigh_notify(n);

  IFACE_UNLOCK;
}

/**
@@ -501,6 +550,8 @@ neigh_ifa_up(struct ifa *a)
  neighbor *n;
  node *x, *y;

  IFACE_LOCK;

  /* Update neighbors that might be better off with the new ifa */
  WALK_LIST(ii, global_iface_list)
    if (!EMPTY_LIST(ii->neighbors) && ifa_intersect(a, ii))
@@ -510,6 +561,8 @@ neigh_ifa_up(struct ifa *a)
  /* Wake up all sticky neighbors that are reachable now */
  WALK_LIST2_DELSAFE(n, x, y, sticky_neigh_list, if_n)
    neigh_update(n, i);

  IFACE_UNLOCK;
}

void
@@ -519,10 +572,14 @@ neigh_ifa_down(struct ifa *a)
  neighbor *n;
  node *x, *y;

  IFACE_LOCK;

  /* Update all neighbors whose scope has changed */
  WALK_LIST2_DELSAFE(n, x, y, i->neighbors, if_n)
    if (n->ifa == a)
      neigh_update(n, i);

  IFACE_UNLOCK;
}

static inline void
@@ -548,10 +605,14 @@ neigh_prune(void)
  node *m;
  int i;

  IFACE_LOCK;

  DBG("Pruning neighbors\n");
  for(i=0; i<NEIGH_HASH_SIZE; i++)
    WALK_LIST_DELSAFE(n, m, neigh_hash_table[i])
      neigh_prune_one(n);

  IFACE_UNLOCK;
}

/**
+0 −1
Original line number Diff line number Diff line
@@ -86,7 +86,6 @@ const char * rta_dest_names[RTD_MAX] = {
  [RTD_PROHIBIT]	= "prohibited",
};

DEFINE_DOMAIN(attrs);
static DOMAIN(attrs) src_domain;

#define SRC_LOCK	LOCK_DOMAIN(attrs, src_domain)
+1 −0
Original line number Diff line number Diff line
@@ -1907,6 +1907,7 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
{
  struct iface *iface;

  IFACE_LEGACY_ACCESS;
  WALK_LIST(iface, global_iface_list)
  {
    if (!(iface->flags & IF_UP))
Loading