]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '7b2c5f3d2826e3175bf31b1c36056c9efc587a2b' into int-new
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 7 Dec 2017 17:35:46 +0000 (18:35 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 7 Dec 2017 17:35:46 +0000 (18:35 +0100)
17 files changed:
1  2 
doc/bird.sgml
lib/socket.h
nest/config.Y
nest/iface.c
nest/iface.h
nest/neighbor.c
nest/proto.c
nest/protocol.h
nest/rt-fib.c
proto/babel/packets.c
proto/bgp/bgp.c
proto/ospf/iface.c
proto/radv/packets.c
proto/radv/radv.c
proto/rip/packets.c
sysdep/linux/netlink.c
sysdep/unix/io.c

diff --cc doc/bird.sgml
Simple merge
diff --cc lib/socket.h
Simple merge
diff --cc nest/config.Y
index ef29fb966d31deac65b9514d7f5e33bf2930e509,025e896955ade054e27c54c496636b9643ef4c1e..ad45a39dcb7ecf5794965397600c5c7c71cc79a9
@@@ -65,8 -55,7 +65,8 @@@ proto_postconfig(void
  CF_DECLS
  
  CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
- CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
+ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
 +CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
  CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
  CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
  CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
@@@ -223,57 -217,20 +223,58 @@@ proto_item
   | DISABLED bool { this_proto->disabled = $2; }
   | DEBUG debug_mask { this_proto->debug = $2; }
   | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
 - | IMPORT imexport { this_proto->in_filter = $2; }
 - | EXPORT imexport { this_proto->out_filter = $2; }
 - | RECEIVE LIMIT limit_spec { this_proto->rx_limit = $3; }
 - | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
 - | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
 - | IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; }
 - | VRF TEXT { this_proto->vrf = if_get_by_name($2); }
 - | TABLE rtable { this_proto->table = $2; }
   | ROUTER ID idval { this_proto->router_id = $3; }
   | DESCRIPTION text { this_proto->dsc = $2; }
++ | VRF text { this_proto->vrf = if_get_by_name($2); }
 + ;
 +
 +
 +channel_start: net_type
 +{
 +  $$ = this_channel = channel_config_new(NULL, $1, this_proto);
 +};
 +
 +channel_item:
 +   TABLE rtable {
 +     if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
 +       cf_error("Incompatible table type");
 +     this_channel->table = $2;
 +   }
 + | IMPORT imexport { this_channel->in_filter = $2; }
 + | EXPORT imexport { this_channel->out_filter = $2; }
 + | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
 + | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
 + | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
 + | PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
 + | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
 + ;
 +
 +channel_opts:
 +   /* empty */
 + | channel_opts channel_item ';'
 + ;
 +
 +channel_opt_list:
 +   /* empty */
 + | '{' channel_opts '}'
 + ;
 +
 +channel_end:
 +{
 +  if (!this_channel->table)
 +    cf_error("Routing table not specified");
 +
 +  this_channel = NULL;
 +};
 +
 +proto_channel: channel_start channel_opt_list channel_end;
 +
 +
 +rtable:
 +   SYM {
 +     if ($1->class != SYM_TABLE) cf_error("Table expected");
 +     $$ = $1->def;
 +   }
   ;
  
  imexport:
diff --cc nest/iface.c
index dbc4debe4ccb67efe169dcfb821502bfa162f56e,3dd4506538a3962ee4156fd4b753635a7b3266d0..5e0a2450fc5ebceaf509ac78dde4517ed70518eb
@@@ -142,11 -140,12 +144,13 @@@ if_copy(struct iface *to, struct iface 
  static inline void
  ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
  {
-   if (p->ifa_notify && (p->proto_state != PS_DOWN))
 -  if (p->ifa_notify && (!p->vrf || p->vrf == a->iface->master))
++  if (p->ifa_notify &&
++      (p->proto_state != PS_DOWN) &&
++      (!p->vrf || p->vrf == a->iface->master))
      {
        if (p->debug & D_IFACES)
 -      log(L_TRACE "%s <%s address %I/%d on interface %s %s",
 -          p->name, (a->flags & IA_PRIMARY) ? " primary" : "",
 -          a->prefix, a->pxlen, a->iface->name,
 +      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);
      }
@@@ -178,7 -177,7 +182,9 @@@ ifa_notify_change(unsigned c, struct if
  static inline void
  if_send_notify(struct proto *p, unsigned c, struct iface *i)
  {
-   if (p->if_notify && (p->proto_state != PS_DOWN))
 -  if (p->if_notify && (!p->vrf || p->vrf == i->master))
++  if (p->if_notify &&
++      (p->proto_state != PS_DOWN) &&
++      (!p->vrf || p->vrf == i->master))
      {
        if (p->debug & D_IFACES)
        log(L_TRACE "%s < interface %s %s", p->name, i->name,
@@@ -231,14 -235,16 +237,16 @@@ if_notify_change(unsigned c, struct ifa
      neigh_if_link(i);
  }
  
 -static unsigned
 -if_recalc_flags(struct iface *i, unsigned flags)
 +static uint
 +if_recalc_flags(struct iface *i UNUSED, uint flags)
  {
-   if ((flags & IF_ADMIN_UP) && !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)))
 -  if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) ||
 -      !(flags & IF_ADMIN_UP) ||
 -      !i->addr ||
 -      (i->master_index && !i->master))
 -    flags &= ~IF_UP;
 -  else
++  if ((flags & IF_ADMIN_UP) &&
++      !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
++      !(i->master_index && !i->master))
      flags |= IF_UP;
 +  else
 +    flags &= ~IF_UP;
 +
    return flags;
  }
  
@@@ -835,7 -774,13 +843,13 @@@ if_show(void
        if (i->flags & IF_SHUTDOWN)
        continue;
  
-       cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "Up" : "Down", i->index);
+       char mbuf[16 + sizeof(i->name)] = {};
+       if (i->master)
+       bsprintf(mbuf, " master=%s", i->master->name);
+       else if (i->master_index)
+       bsprintf(mbuf, " master=#%u", i->master_index);
 -      cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index, mbuf);
++      cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "Up" : "Down", i->index, mbuf);
        if (!(i->flags & IF_MULTIACCESS))
        type = "PtP";
        else
diff --cc nest/iface.h
index 59b1253c9777a2191a3d50f28b024f7a319a9f52,b8e6983846b2516373ecde70d3936e26be27b2a3..ab3f8f351646dd88010e6cee84672c76bd7e54a7
@@@ -34,11 -34,10 +34,13 @@@ struct iface 
    unsigned flags;
    unsigned mtu;
    unsigned index;                     /* OS-dependent interface index */
 -  list addrs;                         /* Addresses assigned to this interface */
 -  struct ifa *addr;                   /* Primary address */
+   unsigned master_index;              /* Interface index of master iface */
+   struct iface *master;                       /* Master iface (e.g. for VRF) */
 +  list addrs;                         /* Addresses assigned to this interface */
 +  struct ifa *addr4;                  /* Primary address for IPv4 */
 +  struct ifa *addr6;                  /* Primary address for IPv6 */
 +  struct ifa *llv6;                   /* Primary link-local address for IPv6 */
 +  ip4_addr sysdep;                    /* Arbitrary IPv4 address for internal sysdep use */
    list neighbors;                     /* All neighbors on this interface */
  };
  
diff --cc nest/neighbor.c
Simple merge
diff --cc nest/proto.c
index b28ac569612fc6623c60412a53c2ec68bba47005,64422ee372db4c1d7413c4feeb821f7c296fe847..ecc3b0fe3b31380338132ccd519bdcb057cbcfdf
@@@ -13,6 -13,6 +13,7 @@@
  #include "lib/resource.h"
  #include "lib/lists.h"
  #include "lib/event.h"
++#include "lib/timer.h"
  #include "lib/string.h"
  #include "conf/conf.h"
  #include "nest/route.h"
@@@ -433,265 -207,38 +434,266 @@@ channel_reloadable(struct channel *c
  }
  
  static void
 -proto_link_ahooks(struct proto *p)
 +channel_request_reload(struct channel *c)
  {
 -  struct announce_hook *h;
 +  ASSERT(c->channel_state == CS_UP);
 +  // ASSERT(channel_reloadable(c));
 +
 +  c->proto->reload_routes(c);
  
 -  if (p->rt_notify)
 -    for(h=p->ahooks; h; h=h->next)
 -      add_tail(&h->table->hooks, &h->n);
 +  /*
 +   * Should this be done before reload_routes() hook?
 +   * Perhaps, but routes are updated asynchronously.
 +   */
 +  channel_reset_limit(&c->rx_limit);
 +  channel_reset_limit(&c->in_limit);
  }
  
 -static void
 -proto_unlink_ahooks(struct proto *p)
 +const struct channel_class channel_basic = {
 +  .channel_size = sizeof(struct channel),
 +  .config_size = sizeof(struct channel_config)
 +};
 +
 +void *
 +channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto)
 +{
 +  struct channel_config *cf = NULL;
 +  struct rtable_config *tab = NULL;
 +  const char *name = NULL;
 +
 +  if (net_type)
 +  {
 +    if (!net_val_match(net_type, proto->protocol->channel_mask))
 +      cf_error("Unsupported channel type");
 +
 +    if (proto->net_type && (net_type != proto->net_type))
 +      cf_error("Different channel type");
 +
 +    tab = new_config->def_tables[net_type];
 +    name = net_label[net_type];
 +  }
 +
 +  if (!cc)
 +    cc = &channel_basic;
 +
 +  cf = cfg_allocz(cc->config_size);
 +  cf->name = name;
 +  cf->channel = cc;
 +  cf->table = tab;
 +  cf->out_filter = FILTER_REJECT;
 +
 +  cf->net_type = net_type;
 +  cf->ra_mode = RA_OPTIMAL;
 +  cf->preference = proto->protocol->preference;
 +
 +  add_tail(&proto->channels, &cf->n);
 +
 +  return cf;
 +}
 +
 +struct channel_config *
 +channel_copy_config(struct channel_config *src, struct proto_config *proto)
  {
 -  struct announce_hook *h;
 +  struct channel_config *dst = cfg_alloc(src->channel->config_size);
  
 -  if (p->rt_notify)
 -    for(h=p->ahooks; h; h=h->next)
 -      rem_node(&h->n);
 +  memcpy(dst, src, src->channel->config_size);
 +  add_tail(&proto->channels, &dst->n);
 +  CALL(src->channel->copy_config, dst, src);
 +
 +  return dst;
  }
  
 +
 +static int reconfigure_type;  /* Hack to propagate type info to channel_reconfigure() */
 +
 +int
 +channel_reconfigure(struct channel *c, struct channel_config *cf)
 +{
 +  /* FIXME: better handle these changes, also handle in_keep_filtered */
 +  if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)))
 +    return 0;
 +
 +  int import_changed = !filter_same(c->in_filter, cf->in_filter);
 +  int export_changed = !filter_same(c->out_filter, cf->out_filter);
 +
 +  if (c->preference != cf->preference)
 +    import_changed = 1;
 +
 +  if (c->merge_limit != cf->merge_limit)
 +    export_changed = 1;
 +
 +  /* Reconfigure channel fields */
 +  c->in_filter = cf->in_filter;
 +  c->out_filter = cf->out_filter;
 +  c->rx_limit = cf->rx_limit;
 +  c->in_limit = cf->in_limit;
 +  c->out_limit = cf->out_limit;
 +
 +  // c->ra_mode = cf->ra_mode;
 +  c->merge_limit = cf->merge_limit;
 +  c->preference = cf->preference;
 +  c->in_keep_filtered = cf->in_keep_filtered;
 +
 +  channel_verify_limits(c);
 +
 +  /* Execute channel-specific reconfigure hook */
 +  if (c->channel->reconfigure && !c->channel->reconfigure(c, cf))
 +    return 0;
 +
 +  /* If the channel is not open, it has no routes and we cannot reload it anyways */
 +  if (c->channel_state != CS_UP)
 +    return 1;
 +
 +  if (reconfigure_type == RECONFIG_SOFT)
 +  {
 +    if (import_changed)
 +      log(L_INFO "Channel %s.%s changed import", c->proto->name, c->name);
 +
 +    if (export_changed)
 +      log(L_INFO "Channel %s.%s changed export", c->proto->name, c->name);
 +
 +    return 1;
 +  }
 +
 +  /* Route reload may be not supported */
 +  if (import_changed && !channel_reloadable(c))
 +    return 0;
 +
 +  if (import_changed || export_changed)
 +    log(L_INFO "Reloading channel %s.%s", c->proto->name, c->name);
 +
 +  if (import_changed)
 +    channel_request_reload(c);
 +
 +  if (export_changed)
 +    channel_request_feeding(c);
 +
 +  return 1;
 +}
 +
 +
 +int
 +proto_configure_channel(struct proto *p, struct channel **pc, struct channel_config *cf)
 +{
 +  struct channel *c = *pc;
 +
 +  if (!c && cf)
 +  {
 +    *pc = proto_add_channel(p, cf);
 +  }
 +  else if (c && !cf)
 +  {
 +    if (c->channel_state != CS_DOWN)
 +    {
 +      log(L_INFO "Cannot remove channel %s.%s", c->proto->name, c->name);
 +      return 0;
 +    }
 +
 +    proto_remove_channel(p, c);
 +    *pc = NULL;
 +  }
 +  else if (c && cf)
 +  {
 +    if (!channel_reconfigure(c, cf))
 +    {
 +      log(L_INFO "Cannot reconfigure channel %s.%s", c->proto->name, c->name);
 +      return 0;
 +    }
 +  }
 +
 +  return 1;
 +}
 +
 +
  static void
 -proto_free_ahooks(struct proto *p)
 +proto_event(void *ptr)
  {
 -  struct announce_hook *h, *hn;
 +  struct proto *p = ptr;
  
 -  for(h = p->ahooks; h; h = hn)
 +  if (p->do_start)
    {
 -    hn = h->next;
 -    mb_free(h);
 +    if_feed_baby(p);
 +    p->do_start = 0;
    }
  
 -  p->ahooks = NULL;
 -  p->main_ahook = NULL;
 +  if (p->do_stop)
 +  {
 +    if (p->proto == &proto_unix_iface)
 +      if_flush_ifaces(p);
 +    p->do_stop = 0;
 +  }
 +
 +  if (proto_is_done(p))
 +  {
 +    if (p->proto->cleanup)
 +      p->proto->cleanup(p);
 +
 +    p->active = 0;
 +    proto_log_state_change(p);
 +    proto_rethink_goal(p);
 +  }
 +}
 +
 +
 +/**
 + * proto_new - create a new protocol instance
 + * @c: protocol configuration
 + *
 + * When a new configuration has been read in, the core code starts
 + * initializing all the protocol instances configured by calling their
 + * init() hooks with the corresponding instance configuration. The initialization
 + * code of the protocol is expected to create a new instance according to the
 + * configuration by calling this function and then modifying the default settings
 + * to values wanted by the protocol.
 + */
 +void *
 +proto_new(struct proto_config *cf)
 +{
 +  struct proto *p = mb_allocz(proto_pool, cf->protocol->proto_size);
 +
 +  p->cf = cf;
 +  p->debug = cf->debug;
 +  p->mrtdump = cf->mrtdump;
 +  p->name = cf->name;
 +  p->proto = cf->protocol;
 +  p->net_type = cf->net_type;
 +  p->disabled = cf->disabled;
 +  p->hash_key = random_u32();
 +  cf->proto = p;
 +
 +  init_list(&p->channels);
 +
 +  return p;
 +}
 +
 +static struct proto *
 +proto_init(struct proto_config *c, node *n)
 +{
 +  struct protocol *pr = c->protocol;
 +  struct proto *p = pr->init(c);
 +
 +  p->proto_state = PS_DOWN;
 +  p->last_state_change = current_time();
++  p->vrf = c->vrf;
 +  insert_node(&p->n, n);
 +
 +  p->event = ev_new(proto_pool);
 +  p->event->hook = proto_event;
 +  p->event->data = p;
 +
 +  PD(p, "Initializing%s", p->disabled ? " [disabled]" : "");
 +
 +  return p;
 +}
 +
 +static void
 +proto_start(struct proto *p)
 +{
 +  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
 +  p->pool = rp_new(proto_pool, p->proto->name);
 +
 +  if (graceful_restart_state == GRS_INIT)
 +    p->gr_recovery = 1;
  }
  
  
@@@ -818,17 -409,17 +820,18 @@@ proto_reconfigure(struct proto *p, stru
  
    /* If there is a too big change in core attributes, ... */
    if ((nc->protocol != oc->protocol) ||
-       (nc->disabled != p->disabled))
 +      (nc->net_type != oc->net_type) ||
 -      (nc->vrf != oc->vrf) ||
 -      (nc->table->table != oc->table->table))
+       (nc->disabled != p->disabled) ||
++      (nc->vrf != oc->vrf))
      return 0;
  
 +  p->name = nc->name;
    p->debug = nc->debug;
    p->mrtdump = nc->mrtdump;
 -  proto_reconfig_type = type;
 +  reconfigure_type = type;
  
    /* Execute protocol specific reconfigure hook */
 -  if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
 +  if (!p->proto->reconfigure || !p->proto->reconfigure(p, nc))
      return 0;
  
    DBG("\t%s: same\n", oc->name);
@@@ -1638,25 -1516,20 +1641,27 @@@ proto_cmd_show(struct proto *p, uint ve
          proto_state_name(p),
          tbuf,
          buf);
 +
    if (verbose)
 +  {
 +    if (p->cf->dsc)
 +      cli_msg(-1006, "  Description:    %s", p->cf->dsc);
 +    if (p->cf->router_id)
 +      cli_msg(-1006, "  Router ID:      %R", p->cf->router_id);
++    if (p->vrf)
++      cli_msg(-1006, "  VRF:            %s", p->vrf->name);
 +
 +    if (p->proto->show_proto_info)
 +      p->proto->show_proto_info(p);
 +    else
      {
 -      if (p->cf->dsc)
 -      cli_msg(-1006, "  Description:    %s", p->cf->dsc);
 -      if (p->cf->router_id)
 -      cli_msg(-1006, "  Router ID:      %R", p->cf->router_id);
 -
 -      if (p->proto->show_proto_info)
 -      p->proto->show_proto_info(p);
 -      else
 -      proto_show_basic_info(p);
 -
 -      cli_msg(-1006, "");
 +      struct channel *c;
 +      WALK_LIST(c, p->channels)
 +      channel_show_info(c);
      }
 +
 +    cli_msg(-1006, "");
 +  }
  }
  
  void
diff --cc nest/protocol.h
index e843b0b41164c6219247d2199d48d5e6acb50395,18dfbd6fb71ff2138fde6ecf3b2156799f1e2504..d7e84a4417d3091c014f18b7a428e03f4892f69b
@@@ -94,12 -91,17 +94,13 @@@ struct proto_config 
    char *name;
    char *dsc;
    int class;                          /* SYM_PROTO or SYM_TEMPLATE */
 +  u8 net_type;                                /* Protocol network type (NET_*), 0 for undefined */
 +  u8 disabled;                                /* Protocol enabled/disabled by default */
    u32 debug, mrtdump;                 /* Debugging bitfields, both use D_* constants */
 -  unsigned preference, disabled;      /* Generic parameters */
 -  int in_keep_filtered;                       /* Routes rejected in import filter are kept */
    u32 router_id;                      /* Protocol specific router ID */
 -  struct rtable_config *table;                /* Table we're attached to */
 -  struct filter *in_filter, *out_filter; /* Attached filters */
 -  struct proto_limit *rx_limit;               /* Limit for receiving routes from protocol
 -                                         (relevant when in_keep_filtered is active) */
 -  struct proto_limit *in_limit;               /* Limit for importing routes from protocol */
 -  struct proto_limit *out_limit;      /* Limit for exporting routes to protocol */
 +
 +  list channels;                      /* List of channel configs (struct channel_config) */
+   struct iface *vrf;                  /* Related VRF instance, NULL if global */
  
    /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
  
@@@ -137,11 -141,7 +138,12 @@@ struct proto 
    struct proto_config *cf;            /* Configuration data */
    struct proto_config *cf_new;                /* Configuration we want to switch to after shutdown (NULL=delete) */
    pool *pool;                         /* Pool containing local objects */
 -  struct event *attn;                 /* "Pay attention" event */
 +  event *event;                               /* Protocol event */
 +
 +  list channels;                      /* List of channels to rtables (struct channel) */
 +  struct channel *main_channel;               /* Primary channel */
 +  struct rte_src *main_source;                /* Primary route source */
++  struct iface *vrf;                  /* Related VRF instance, NULL if global */
  
    char *name;                         /* Name of this instance (== cf->name) */
    u32 debug;                          /* Debugging flags */
diff --cc nest/rt-fib.c
Simple merge
index 4abcf7e4c1e41e91b243c2b528862fa6f13bb366,9042183652c3f60b1738fe2274aa015a94eab10f..5b356fae78730d6977cc4a1fd4eaaccdff2f14b4
@@@ -1331,7 -1080,7 +1331,8 @@@ babel_open_socket(struct babel_iface *i
    sk->sport = ifa->cf->port;
    sk->dport = ifa->cf->port;
    sk->iface = ifa->iface;
 +  sk->saddr = ifa->addr;
+   sk->vrf = p->p.vrf;
  
    sk->rx_hook = babel_rx_hook;
    sk->tx_hook = babel_tx_hook;
diff --cc proto/bgp/bgp.c
Simple merge
index 29d21a07c0af92298aa209b0fe2d54eb466100cc,1795ec2203f189f727965cc7a79c566f6ada1fad..e3d8d61bdb0ce9f3770fd496140ec089c0df4248
@@@ -202,8 -200,8 +203,9 @@@ ospf_open_vlink_sk(struct ospf_proto *p
  {
    sock *sk = sk_new(p->p.pool);
    sk->type = SK_IP;
 +  sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
    sk->dport = OSPF_PROTO;
+   sk->vrf = p->p.vrf;
  
    /* FIXME: configurable tos/priority ? */
    sk->tos = IP_PREC_INTERNET_CONTROL;
index e07296e107021714f039f35d39ad5001407104fe,8a301854823910cea65c16562cf4b584f68dcea6..7c148b7dc94779378b408cf38ce7b4003fc18bdb
@@@ -384,9 -386,9 +384,10 @@@ radv_sk_open(struct radv_iface *ifa
  {
    sock *sk = sk_new(ifa->pool);
    sk->type = SK_IP;
 +  sk->subtype = SK_IPV6;
    sk->dport = ICMPV6_PROTO;
    sk->saddr = ifa->addr->ip;
+   sk->vrf = ifa->ra->p.vrf;
  
    sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
    sk->rx_hook = radv_rx_hook;
index c96d772488a063784286cb79fd1541c041481746,c53a0a95267a9b6c38fea6b8325403e6705b6a09..e9140115a2d5a295393fa2b3dd98b7e3a36685a1
@@@ -294,10 -306,21 +294,9 @@@ radv_iface_new(struct radv_proto *p, st
  
    add_tail(&p->iface_list, NODE ifa);
  
 -  ifa->addr = find_lladdr(iface);
 -  if (!ifa->addr)
 -  {
 -    log(L_ERR "%s: Missing link-local address on interface %s", p->p.name, iface->name);
 -    return;
 -  }
 -
 -  timer *tm = tm_new(pool);
 -  tm->hook = radv_timer;
 -  tm->data = ifa;
 -  tm->randomize = 0;
 -  tm->recurrent = 0;
 -  ifa->timer = tm;
 +  ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
  
    struct object_lock *lock = olock_new(pool);
-   lock->addr = IPA_NONE;
    lock->type = OBJLOCK_IP;
    lock->port = ICMPV6_PROTO;
    lock->iface = iface;
index 4925ca36be8702fde252e8ec9b18ce2ae4b8fef6,722a9012d95da1dc2e327f22a826d6f5476f4985..891f454f024b4b91d03d4775d3cd360186659bd1
@@@ -746,8 -739,16 +746,9 @@@ rip_open_socket(struct rip_iface *ifa
    sk->sport = ifa->cf->port;
    sk->dport = ifa->cf->port;
    sk->iface = ifa->iface;
 +  sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
+   sk->vrf = p->p.vrf;
  
 -  /*
 -   * For RIPv2, we explicitly choose a primary address, mainly to ensure that
 -   * RIP and BFD uses the same one. For RIPng, we left it to kernel, which
 -   * should choose some link-local address based on the same scope rule.
 -   */
 -  if (rip_is_v2(p))
 -    sk->saddr = ifa->iface->addr->ip;
 -
    sk->rx_hook = rip_rx_hook;
    sk->tx_hook = rip_tx_hook;
    sk->err_hook = rip_err_hook;
index 279f3c9c811f8801feb7b850cf8348bd98e6c3e4,4802897b0243f0ec62065d9c3db51102d6d51a08..05c1fa8ca539a7393786a88465b3a80b0a4fd384
@@@ -1091,14 -842,27 +1098,34 @@@ kif_do_scan(struct kif_proto *p UNUSED
      else
        log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
  
 -  nl_request_dump(BIRD_AF, RTM_GETADDR);
+   /* Re-resolve master interface for slaves */
+   struct iface *i;
+   WALK_LIST(i, iface_list)
+     if (i->master_index)
+     {
+       struct iface f = {
+       .flags = i->flags,
+       .mtu = i->mtu,
+       .index = i->index,
+       .master_index = i->master_index,
+       .master = if_find_by_index(i->master_index)
+       };
+       if (f.master != i->master)
+       {
+       memcpy(f.name, i->name, sizeof(f.name));
+       if_update(&f);
+       }
+     }
 +  nl_request_dump(AF_INET, RTM_GETADDR);
 +  while (h = nl_get_scan())
 +    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
 +      nl_parse_addr(h, 1);
 +    else
 +      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
 +
 +  nl_request_dump(AF_INET6, RTM_GETADDR);
    while (h = nl_get_scan())
      if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
        nl_parse_addr(h, 1);
Simple merge