File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / nest / iface.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (4 years, 8 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    1: /*
    2:  *	BIRD -- Management of Interfaces and Neighbor Cache
    3:  *
    4:  *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
    5:  *
    6:  *	Can be freely distributed and used under the terms of the GNU GPL.
    7:  */
    8: 
    9: /**
   10:  * DOC: Interfaces
   11:  *
   12:  * The interface module keeps track of all network interfaces in the
   13:  * system and their addresses.
   14:  *
   15:  * Each interface is represented by an &iface structure which carries
   16:  * interface capability flags (%IF_MULTIACCESS, %IF_BROADCAST etc.),
   17:  * MTU, interface name and index and finally a linked list of network
   18:  * prefixes assigned to the interface, each one represented by
   19:  * struct &ifa.
   20:  *
   21:  * The interface module keeps a `soft-up' state for each &iface which
   22:  * is a conjunction of link being up, the interface being of a `sane'
   23:  * type and at least one IP address assigned to it.
   24:  */
   25: 
   26: #undef LOCAL_DEBUG
   27: 
   28: #include "nest/bird.h"
   29: #include "nest/iface.h"
   30: #include "nest/protocol.h"
   31: #include "nest/cli.h"
   32: #include "lib/resource.h"
   33: #include "lib/string.h"
   34: #include "conf/conf.h"
   35: #include "sysdep/unix/krt.h"
   36: 
   37: static pool *if_pool;
   38: 
   39: list iface_list;
   40: 
   41: static void if_recalc_preferred(struct iface *i);
   42: 
   43: /**
   44:  * ifa_dump - dump interface address
   45:  * @a: interface address descriptor
   46:  *
   47:  * This function dumps contents of an &ifa to the debug output.
   48:  */
   49: void
   50: ifa_dump(struct ifa *a)
   51: {
   52:   debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
   53: 	(a->flags & IA_PRIMARY) ? " PRIMARY" : "",
   54: 	(a->flags & IA_SECONDARY) ? " SEC" : "",
   55: 	(a->flags & IA_HOST) ? " HOST" : "",
   56: 	(a->flags & IA_PEER) ? " PEER" : "");
   57: }
   58: 
   59: /**
   60:  * if_dump - dump interface
   61:  * @i: interface to dump
   62:  *
   63:  * This function dumps all information associated with a given
   64:  * network interface to the debug output.
   65:  */
   66: void
   67: if_dump(struct iface *i)
   68: {
   69:   struct ifa *a;
   70: 
   71:   debug("IF%d: %s", i->index, i->name);
   72:   if (i->flags & IF_SHUTDOWN)
   73:     debug(" SHUTDOWN");
   74:   if (i->flags & IF_UP)
   75:     debug(" UP");
   76:   else
   77:     debug(" DOWN");
   78:   if (i->flags & IF_ADMIN_UP)
   79:     debug(" LINK-UP");
   80:   if (i->flags & IF_MULTIACCESS)
   81:     debug(" MA");
   82:   if (i->flags & IF_BROADCAST)
   83:     debug(" BC");
   84:   if (i->flags & IF_MULTICAST)
   85:     debug(" MC");
   86:   if (i->flags & IF_LOOPBACK)
   87:     debug(" LOOP");
   88:   if (i->flags & IF_IGNORE)
   89:     debug(" IGN");
   90:   if (i->flags & IF_TMP_DOWN)
   91:     debug(" TDOWN");
   92:   debug(" MTU=%d\n", i->mtu);
   93:   WALK_LIST(a, i->addrs)
   94:     {
   95:       ifa_dump(a);
   96:       ASSERT(!!(a->flags & IA_PRIMARY) ==
   97: 	     ((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
   98:     }
   99: }
  100: 
  101: /**
  102:  * if_dump_all - dump all interfaces
  103:  *
  104:  * This function dumps information about all known network
  105:  * interfaces to the debug output.
  106:  */
  107: void
  108: if_dump_all(void)
  109: {
  110:   struct iface *i;
  111: 
  112:   debug("Known network interfaces:\n");
  113:   WALK_LIST(i, iface_list)
  114:     if_dump(i);
  115:   debug("Router ID: %08x\n", config->router_id);
  116: }
  117: 
  118: static inline unsigned
  119: if_what_changed(struct iface *i, struct iface *j)
  120: {
  121:   unsigned c;
  122: 
  123:   if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
  124:       || (i->index != j->index) || (i->master != j->master))
  125:     return IF_CHANGE_TOO_MUCH;
  126:   c = 0;
  127:   if ((i->flags ^ j->flags) & IF_UP)
  128:     c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
  129:   if ((i->flags ^ j->flags) & IF_LINK_UP)
  130:     c |= IF_CHANGE_LINK;
  131:   if (i->mtu != j->mtu)
  132:     c |= IF_CHANGE_MTU;
  133:   return c;
  134: }
  135: 
  136: static inline void
  137: if_copy(struct iface *to, struct iface *from)
  138: {
  139:   to->flags = from->flags | (to->flags & IF_TMP_DOWN);
  140:   to->mtu = from->mtu;
  141:   to->master_index = from->master_index;
  142:   to->master = from->master;
  143: }
  144: 
  145: static inline void
  146: ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
  147: {
  148:   if (p->ifa_notify &&
  149:       (p->proto_state != PS_DOWN) &&
  150:       (!p->vrf_set || p->vrf == a->iface->master))
  151:     {
  152:       if (p->debug & D_IFACES)
  153: 	log(L_TRACE "%s < address %N on interface %s %s",
  154: 	    p->name, &a->prefix, a->iface->name,
  155: 	    (c & IF_CHANGE_UP) ? "added" : "removed");
  156:       p->ifa_notify(p, c, a);
  157:     }
  158: }
  159: 
  160: static void
  161: ifa_notify_change_(unsigned c, struct ifa *a)
  162: {
  163:   struct proto *p;
  164: 
  165:   DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
  166: 
  167:   WALK_LIST(p, proto_list)
  168:     ifa_send_notify(p, c, a);
  169: }
  170: 
  171: static inline void
  172: ifa_notify_change(unsigned c, struct ifa *a)
  173: {
  174:   if (c & IF_CHANGE_DOWN)
  175:     neigh_ifa_update(a);
  176: 
  177:   ifa_notify_change_(c, a);
  178: 
  179:   if (c & IF_CHANGE_UP)
  180:     neigh_ifa_update(a);
  181: }
  182: 
  183: static inline void
  184: if_send_notify(struct proto *p, unsigned c, struct iface *i)
  185: {
  186:   if (p->if_notify &&
  187:       (p->proto_state != PS_DOWN) &&
  188:       (!p->vrf_set || p->vrf == i->master))
  189:     {
  190:       if (p->debug & D_IFACES)
  191: 	log(L_TRACE "%s < interface %s %s", p->name, i->name,
  192: 	    (c & IF_CHANGE_UP) ? "goes up" :
  193: 	    (c & IF_CHANGE_DOWN) ? "goes down" :
  194: 	    (c & IF_CHANGE_MTU) ? "changes MTU" :
  195: 	    (c & IF_CHANGE_LINK) ? "changes link" :
  196: 	    (c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
  197: 	    (c & IF_CHANGE_CREATE) ? "created" :
  198: 	    "sends unknown event");
  199:       p->if_notify(p, c, i);
  200:     }
  201: }
  202: 
  203: static void
  204: if_notify_change(unsigned c, struct iface *i)
  205: {
  206:   struct proto *p;
  207:   struct ifa *a;
  208: 
  209:   if (i->flags & IF_JUST_CREATED)
  210:     {
  211:       i->flags &= ~IF_JUST_CREATED;
  212:       c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
  213:     }
  214: 
  215:   DBG("Interface change notification (%x) for %s\n", c, i->name);
  216: #ifdef LOCAL_DEBUG
  217:   if_dump(i);
  218: #endif
  219: 
  220:   if (c & IF_CHANGE_DOWN)
  221:     neigh_if_down(i);
  222: 
  223:   if (c & IF_CHANGE_DOWN)
  224:     WALK_LIST(a, i->addrs)
  225:       ifa_notify_change_(IF_CHANGE_DOWN, a);
  226: 
  227:   WALK_LIST(p, proto_list)
  228:     if_send_notify(p, c, i);
  229: 
  230:   if (c & IF_CHANGE_UP)
  231:     WALK_LIST(a, i->addrs)
  232:       ifa_notify_change_(IF_CHANGE_UP, a);
  233: 
  234:   if (c & IF_CHANGE_UP)
  235:     neigh_if_up(i);
  236: 
  237:   if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
  238:     neigh_if_link(i);
  239: }
  240: 
  241: static uint
  242: if_recalc_flags(struct iface *i UNUSED, uint flags)
  243: {
  244:   if ((flags & IF_ADMIN_UP) &&
  245:       !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
  246:       !(i->master_index && !i->master))
  247:     flags |= IF_UP;
  248:   else
  249:     flags &= ~IF_UP;
  250: 
  251:   return flags;
  252: }
  253: 
  254: static void
  255: if_change_flags(struct iface *i, uint flags)
  256: {
  257:   uint of = i->flags;
  258:   i->flags = if_recalc_flags(i, flags);
  259: 
  260:   if ((i->flags ^ of) & IF_UP)
  261:     if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
  262: }
  263: 
  264: /**
  265:  * if_delete - remove interface
  266:  * @old: interface
  267:  *
  268:  * This function is called by the low-level platform dependent code
  269:  * whenever it notices an interface disappears. It is just a shorthand
  270:  * for if_update().
  271:  */
  272: 
  273: void
  274: if_delete(struct iface *old)
  275: {
  276:   struct iface f = {};
  277:   strncpy(f.name, old->name, sizeof(f.name)-1);
  278:   f.flags = IF_SHUTDOWN;
  279:   if_update(&f);
  280: }
  281: 
  282: /**
  283:  * if_update - update interface status
  284:  * @new: new interface status
  285:  *
  286:  * if_update() is called by the low-level platform dependent code
  287:  * whenever it notices an interface change.
  288:  *
  289:  * There exist two types of interface updates -- synchronous and asynchronous
  290:  * ones. In the synchronous case, the low-level code calls if_start_update(),
  291:  * scans all interfaces reported by the OS, uses if_update() and ifa_update()
  292:  * to pass them to the core and then it finishes the update sequence by
  293:  * calling if_end_update(). When working asynchronously, the sysdep code
  294:  * calls if_update() and ifa_update() whenever it notices a change.
  295:  *
  296:  * if_update() will automatically notify all other modules about the change.
  297:  */
  298: struct iface *
  299: if_update(struct iface *new)
  300: {
  301:   struct iface *i;
  302:   unsigned c;
  303: 
  304:   WALK_LIST(i, iface_list)
  305:     if (!strcmp(new->name, i->name))
  306:       {
  307: 	new->flags = if_recalc_flags(new, new->flags);
  308: 	c = if_what_changed(i, new);
  309: 	if (c & IF_CHANGE_TOO_MUCH)	/* Changed a lot, convert it to down/up */
  310: 	  {
  311: 	    DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
  312: 	    if_change_flags(i, i->flags | IF_TMP_DOWN);
  313: 	    rem_node(&i->n);
  314: 	    new->addr4 = i->addr4;
  315: 	    new->addr6 = i->addr6;
  316: 	    new->llv6 = i->llv6;
  317: 	    new->sysdep = i->sysdep;
  318: 	    memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
  319: 	    memcpy(i, new, sizeof(*i));
  320: 	    i->flags &= ~IF_UP;		/* IF_TMP_DOWN will be added later */
  321: 	    goto newif;
  322: 	  }
  323: 
  324: 	if_copy(i, new);
  325: 	if (c)
  326: 	  if_notify_change(c, i);
  327: 
  328: 	i->flags |= IF_UPDATED;
  329: 	return i;
  330:       }
  331:   i = mb_alloc(if_pool, sizeof(struct iface));
  332:   memcpy(i, new, sizeof(*i));
  333:   init_list(&i->addrs);
  334: newif:
  335:   init_list(&i->neighbors);
  336:   i->flags |= IF_UPDATED | IF_TMP_DOWN;		/* Tmp down as we don't have addresses yet */
  337:   add_tail(&iface_list, &i->n);
  338:   return i;
  339: }
  340: 
  341: void
  342: if_start_update(void)
  343: {
  344:   struct iface *i;
  345:   struct ifa *a;
  346: 
  347:   WALK_LIST(i, iface_list)
  348:     {
  349:       i->flags &= ~IF_UPDATED;
  350:       WALK_LIST(a, i->addrs)
  351: 	a->flags &= ~IA_UPDATED;
  352:     }
  353: }
  354: 
  355: void
  356: if_end_partial_update(struct iface *i)
  357: {
  358:   if (i->flags & IF_NEEDS_RECALC)
  359:     if_recalc_preferred(i);
  360: 
  361:   if (i->flags & IF_TMP_DOWN)
  362:     if_change_flags(i, i->flags & ~IF_TMP_DOWN);
  363: }
  364: 
  365: void
  366: if_end_update(void)
  367: {
  368:   struct iface *i;
  369:   struct ifa *a, *b;
  370: 
  371:   WALK_LIST(i, iface_list)
  372:     {
  373:       if (!(i->flags & IF_UPDATED))
  374: 	if_change_flags(i, (i->flags & ~IF_ADMIN_UP) | IF_SHUTDOWN);
  375:       else
  376: 	{
  377: 	  WALK_LIST_DELSAFE(a, b, i->addrs)
  378: 	    if (!(a->flags & IA_UPDATED))
  379: 	      ifa_delete(a);
  380: 	  if_end_partial_update(i);
  381: 	}
  382:     }
  383: }
  384: 
  385: void
  386: if_flush_ifaces(struct proto *p)
  387: {
  388:   if (p->debug & D_EVENTS)
  389:     log(L_TRACE "%s: Flushing interfaces", p->name);
  390:   if_start_update();
  391:   if_end_update();
  392: }
  393: 
  394: /**
  395:  * if_feed_baby - advertise interfaces to a new protocol
  396:  * @p: protocol to feed
  397:  *
  398:  * When a new protocol starts, this function sends it a series
  399:  * of notifications about all existing interfaces.
  400:  */
  401: void
  402: if_feed_baby(struct proto *p)
  403: {
  404:   struct iface *i;
  405:   struct ifa *a;
  406: 
  407:   if (!p->if_notify && !p->ifa_notify)	/* shortcut */
  408:     return;
  409:   DBG("Announcing interfaces to new protocol %s\n", p->name);
  410:   WALK_LIST(i, iface_list)
  411:     {
  412:       if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
  413:       if (i->flags & IF_UP)
  414: 	WALK_LIST(a, i->addrs)
  415: 	  ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
  416:     }
  417: }
  418: 
  419: /**
  420:  * if_find_by_index - find interface by ifindex
  421:  * @idx: ifindex
  422:  *
  423:  * This function finds an &iface structure corresponding to an interface
  424:  * of the given index @idx. Returns a pointer to the structure or %NULL
  425:  * if no such structure exists.
  426:  */
  427: struct iface *
  428: if_find_by_index(unsigned idx)
  429: {
  430:   struct iface *i;
  431: 
  432:   WALK_LIST(i, iface_list)
  433:     if (i->index == idx && !(i->flags & IF_SHUTDOWN))
  434:       return i;
  435:   return NULL;
  436: }
  437: 
  438: /**
  439:  * if_find_by_name - find interface by name
  440:  * @name: interface name
  441:  *
  442:  * This function finds an &iface structure corresponding to an interface
  443:  * of the given name @name. Returns a pointer to the structure or %NULL
  444:  * if no such structure exists.
  445:  */
  446: struct iface *
  447: if_find_by_name(char *name)
  448: {
  449:   struct iface *i;
  450: 
  451:   WALK_LIST(i, iface_list)
  452:     if (!strcmp(i->name, name) && !(i->flags & IF_SHUTDOWN))
  453:       return i;
  454:   return NULL;
  455: }
  456: 
  457: struct iface *
  458: if_get_by_name(char *name)
  459: {
  460:   struct iface *i;
  461: 
  462:   WALK_LIST(i, iface_list)
  463:     if (!strcmp(i->name, name))
  464:       return i;
  465: 
  466:   /* No active iface, create a dummy */
  467:   i = mb_allocz(if_pool, sizeof(struct iface));
  468:   strncpy(i->name, name, sizeof(i->name)-1);
  469:   i->flags = IF_SHUTDOWN;
  470:   init_list(&i->addrs);
  471:   init_list(&i->neighbors);
  472:   add_tail(&iface_list, &i->n);
  473:   return i;
  474: }
  475: 
  476: static inline void
  477: if_set_preferred(struct ifa **pos, struct ifa *new)
  478: {
  479:   if (*pos)
  480:     (*pos)->flags &= ~IA_PRIMARY;
  481:   if (new)
  482:     new->flags |= IA_PRIMARY;
  483: 
  484:   *pos = new;
  485: }
  486: 
  487: static void
  488: if_recalc_preferred(struct iface *i)
  489: {
  490:   /*
  491:    * Preferred address selection priority:
  492:    * 1) Address configured in Device protocol
  493:    * 2) Sysdep IPv4 address (BSD)
  494:    * 3) Old preferred address
  495:    * 4) First address in list
  496:    */
  497: 
  498:   struct kif_iface_config *ic = kif_get_iface_config(i);
  499:   struct ifa *a4 = i->addr4, *a6 = i->addr6, *ll = i->llv6;
  500:   ip_addr pref_v4 = ic->pref_v4;
  501:   uint change = 0;
  502: 
  503:   if (kif_update_sysdep_addr(i))
  504:     change |= IF_CHANGE_SYSDEP;
  505: 
  506:   /* BSD sysdep address */
  507:   if (ipa_zero(pref_v4) && ip4_nonzero(i->sysdep))
  508:     pref_v4 = ipa_from_ip4(i->sysdep);
  509: 
  510:   struct ifa *a;
  511:   WALK_LIST(a, i->addrs)
  512:     {
  513:       /* Secondary address is never selected */
  514:       if (a->flags & IA_SECONDARY)
  515: 	continue;
  516: 
  517:       if (ipa_is_ip4(a->ip)) {
  518: 	if (!a4 || ipa_equal(a->ip, pref_v4))
  519: 	  a4 = a;
  520:       } else if (!ipa_is_link_local(a->ip)) {
  521: 	if (!a6 || ipa_equal(a->ip, ic->pref_v6))
  522: 	  a6 = a;
  523:       } else {
  524: 	if (!ll || ipa_equal(a->ip, ic->pref_ll))
  525: 	  ll = a;
  526:       }
  527:     }
  528: 
  529:   if ((a4 != i->addr4) || (i->flags & IF_LOST_ADDR4))
  530:   {
  531:     if_set_preferred(&i->addr4, a4);
  532:     change |= IF_CHANGE_ADDR4;
  533:   }
  534: 
  535:   if ((a6 != i->addr6) || (i->flags & IF_LOST_ADDR6))
  536:   {
  537:     if_set_preferred(&i->addr6, a6);
  538:     change |= IF_CHANGE_ADDR6;
  539:   }
  540: 
  541:   if ((ll != i->llv6) || (i->flags & IF_LOST_LLV6))
  542:   {
  543:     if_set_preferred(&i->llv6, ll);
  544:     change |= IF_CHANGE_LLV6;
  545:   }
  546: 
  547:   i->flags &= ~(IF_NEEDS_RECALC | IF_LOST_ADDR4 | IF_LOST_ADDR6 | IF_LOST_LLV6);
  548: 
  549:   if (change)
  550:     if_notify_change(change, i);
  551: }
  552: 
  553: void
  554: if_recalc_all_preferred_addresses(void)
  555: {
  556:   struct iface *i;
  557: 
  558:   WALK_LIST(i, iface_list)
  559:   {
  560:     if_recalc_preferred(i);
  561: 
  562:     if (i->flags & IF_TMP_DOWN)
  563:       if_change_flags(i, i->flags & ~IF_TMP_DOWN);
  564:   }
  565: }
  566: 
  567: static inline int
  568: ifa_same(struct ifa *a, struct ifa *b)
  569: {
  570:   return ipa_equal(a->ip, b->ip) && net_equal(&a->prefix, &b->prefix);
  571: }
  572: 
  573: 
  574: /**
  575:  * ifa_update - update interface address
  576:  * @a: new interface address
  577:  *
  578:  * This function adds address information to a network
  579:  * interface. It's called by the platform dependent code during
  580:  * the interface update process described under if_update().
  581:  */
  582: struct ifa *
  583: ifa_update(struct ifa *a)
  584: {
  585:   struct iface *i = a->iface;
  586:   struct ifa *b;
  587: 
  588:   WALK_LIST(b, i->addrs)
  589:     if (ifa_same(b, a))
  590:       {
  591: 	if (ipa_equal(b->brd, a->brd) &&
  592: 	    ipa_equal(b->opposite, a->opposite) &&
  593: 	    b->scope == a->scope &&
  594: 	    !((b->flags ^ a->flags) & IA_PEER))
  595: 	  {
  596: 	    b->flags |= IA_UPDATED;
  597: 	    return b;
  598: 	  }
  599: 	ifa_delete(b);
  600: 	break;
  601:       }
  602: 
  603:   if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd))
  604:     log(L_WARN "Missing broadcast address for interface %s", i->name);
  605: 
  606:   b = mb_alloc(if_pool, sizeof(struct ifa));
  607:   memcpy(b, a, sizeof(struct ifa));
  608:   add_tail(&i->addrs, &b->n);
  609:   b->flags |= IA_UPDATED;
  610: 
  611:   i->flags |= IF_NEEDS_RECALC;
  612:   if (i->flags & IF_UP)
  613:     ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
  614:   return b;
  615: }
  616: 
  617: /**
  618:  * ifa_delete - remove interface address
  619:  * @a: interface address
  620:  *
  621:  * This function removes address information from a network
  622:  * interface. It's called by the platform dependent code during
  623:  * the interface update process described under if_update().
  624:  */
  625: void
  626: ifa_delete(struct ifa *a)
  627: {
  628:   struct iface *i = a->iface;
  629:   struct ifa *b;
  630: 
  631:   WALK_LIST(b, i->addrs)
  632:     if (ifa_same(b, a))
  633:       {
  634: 	rem_node(&b->n);
  635: 
  636: 	if (b->flags & IA_PRIMARY)
  637: 	  {
  638: 	    /*
  639: 	     * We unlink deleted preferred address and mark for recalculation.
  640: 	     * FIXME: This could break if we make iface scan non-atomic, as
  641: 	     * protocols still could use the freed address until they get
  642: 	     * if_notify from preferred route recalculation. We should fix and
  643: 	     * simplify this in the future by having struct ifa refcounted
  644: 	     */
  645: 	    if (b == i->addr4) { i->addr4 = NULL; i->flags |= IF_LOST_ADDR4; }
  646: 	    if (b == i->addr6) { i->addr6 = NULL; i->flags |= IF_LOST_ADDR6; }
  647: 	    if (b == i->llv6)  { i->llv6 = NULL;  i->flags |= IF_LOST_LLV6; }
  648: 	    i->flags |= IF_NEEDS_RECALC;
  649: 	  }
  650: 
  651: 	if (i->flags & IF_UP)
  652: 	  ifa_notify_change(IF_CHANGE_DOWN, b);
  653: 
  654: 	mb_free(b);
  655: 	return;
  656:       }
  657: }
  658: 
  659: u32
  660: if_choose_router_id(struct iface_patt *mask, u32 old_id)
  661: {
  662:   struct iface *i;
  663:   struct ifa *a, *b;
  664: 
  665:   b = NULL;
  666:   WALK_LIST(i, iface_list)
  667:     {
  668:       if (!(i->flags & IF_ADMIN_UP) ||
  669: 	  (i->flags & IF_SHUTDOWN))
  670: 	continue;
  671: 
  672:       WALK_LIST(a, i->addrs)
  673: 	{
  674: 	  if (a->prefix.type != NET_IP4)
  675: 	    continue;
  676: 
  677: 	  if (a->flags & IA_SECONDARY)
  678: 	    continue;
  679: 
  680: 	  if (a->scope <= SCOPE_LINK)
  681: 	    continue;
  682: 
  683: 	  /* Check pattern if specified */
  684: 	  if (mask && !iface_patt_match(mask, i, a))
  685: 	    continue;
  686: 
  687: 	  /* No pattern or pattern matched */
  688: 	  if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip))
  689: 	    b = a;
  690: 	}
  691:     }
  692: 
  693:   if (!b)
  694:     return 0;
  695: 
  696:   u32 id = ipa_to_u32(b->ip);
  697:   if (id != old_id)
  698:     log(L_INFO "Chosen router ID %R according to interface %s", id, b->iface->name);
  699: 
  700:   return id;
  701: }
  702: 
  703: /**
  704:  * if_init - initialize interface module
  705:  *
  706:  * This function is called during BIRD startup to initialize
  707:  * all data structures of the interface module.
  708:  */
  709: void
  710: if_init(void)
  711: {
  712:   if_pool = rp_new(&root_pool, "Interfaces");
  713:   init_list(&iface_list);
  714:   neigh_init(if_pool);
  715: }
  716: 
  717: /*
  718:  *	Interface Pattern Lists
  719:  */
  720: 
  721: int
  722: iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
  723: {
  724:   struct iface_patt_node *p;
  725: 
  726:   WALK_LIST(p, ifp->ipn_list)
  727:     {
  728:       char *t = p->pattern;
  729:       int pos = p->positive;
  730: 
  731:       if (t)
  732: 	{
  733: 	  if (*t == '-')
  734: 	    {
  735: 	      t++;
  736: 	      pos = !pos;
  737: 	    }
  738: 
  739: 	  if (!patmatch(t, i->name))
  740: 	    continue;
  741: 	}
  742: 
  743:       if (p->prefix.pxlen == 0)
  744: 	return pos;
  745: 
  746:       if (!a)
  747: 	continue;
  748: 
  749:       if (ipa_in_netX(a->ip, &p->prefix))
  750: 	return pos;
  751: 
  752:       if ((a->flags & IA_PEER) &&
  753: 	  ipa_in_netX(a->opposite, &p->prefix))
  754: 	return pos;
  755: 
  756:       continue;
  757:     }
  758: 
  759:   return 0;
  760: }
  761: 
  762: struct iface_patt *
  763: iface_patt_find(list *l, struct iface *i, struct ifa *a)
  764: {
  765:   struct iface_patt *p;
  766: 
  767:   WALK_LIST(p, *l)
  768:     if (iface_patt_match(p, i, a))
  769:       return p;
  770: 
  771:   return NULL;
  772: }
  773: 
  774: static int
  775: iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb)
  776: {
  777:   struct iface_patt_node *x, *y;
  778: 
  779:   x = HEAD(pa->ipn_list);
  780:   y = HEAD(pb->ipn_list);
  781:   while (x->n.next && y->n.next)
  782:     {
  783:       if ((x->positive != y->positive) ||
  784: 	  (!x->pattern && y->pattern) ||	/* This nasty lines where written by me... :-( Feela */
  785: 	  (!y->pattern && x->pattern) ||
  786: 	  ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) ||
  787: 	  !net_equal(&x->prefix, &y->prefix))
  788: 	return 0;
  789:       x = (void *) x->n.next;
  790:       y = (void *) y->n.next;
  791:     }
  792:   return (!x->n.next && !y->n.next);
  793: }
  794: 
  795: int
  796: iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
  797: {
  798:   struct iface_patt *x, *y;
  799: 
  800:   x = HEAD(*a);
  801:   y = HEAD(*b);
  802:   while (x->n.next && y->n.next)
  803:     {
  804:       if (!iface_plists_equal(x, y) ||
  805: 	  (comp && !comp(x, y)))
  806: 	return 0;
  807:       x = (void *) x->n.next;
  808:       y = (void *) y->n.next;
  809:     }
  810:   return (!x->n.next && !y->n.next);
  811: }
  812: 
  813: /*
  814:  *  CLI commands.
  815:  */
  816: 
  817: static void
  818: if_show_addr(struct ifa *a)
  819: {
  820:   byte *flg, opp[IPA_MAX_TEXT_LENGTH + 16];
  821: 
  822:   flg = (a->flags & IA_PRIMARY) ? "Preferred, " : (a->flags & IA_SECONDARY) ? "Secondary, " : "";
  823: 
  824:   if (ipa_nonzero(a->opposite))
  825:     bsprintf(opp, "opposite %I, ", a->opposite);
  826:   else
  827:     opp[0] = 0;
  828: 
  829:   cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
  830: 	  a->ip, a->prefix.pxlen, flg, opp, ip_scope_text(a->scope));
  831: }
  832: 
  833: void
  834: if_show(void)
  835: {
  836:   struct iface *i;
  837:   struct ifa *a;
  838:   char *type;
  839: 
  840:   WALK_LIST(i, iface_list)
  841:     {
  842:       if (i->flags & IF_SHUTDOWN)
  843: 	continue;
  844: 
  845:       char mbuf[16 + sizeof(i->name)] = {};
  846:       if (i->master)
  847: 	bsprintf(mbuf, " master=%s", i->master->name);
  848:       else if (i->master_index)
  849: 	bsprintf(mbuf, " master=#%u", i->master_index);
  850: 
  851:       cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "up" : "down", i->index, mbuf);
  852:       if (!(i->flags & IF_MULTIACCESS))
  853: 	type = "PtP";
  854:       else
  855: 	type = "MultiAccess";
  856:       cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
  857: 	      type,
  858: 	      (i->flags & IF_BROADCAST) ? " Broadcast" : "",
  859: 	      (i->flags & IF_MULTICAST) ? " Multicast" : "",
  860: 	      (i->flags & IF_ADMIN_UP) ? "Up" : "Down",
  861: 	      (i->flags & IF_LINK_UP) ? "Up" : "Down",
  862: 	      (i->flags & IF_LOOPBACK) ? " Loopback" : "",
  863: 	      (i->flags & IF_IGNORE) ? " Ignored" : "",
  864: 	      i->mtu);
  865: 
  866:       WALK_LIST(a, i->addrs)
  867: 	if (a->prefix.type == NET_IP4)
  868: 	  if_show_addr(a);
  869: 
  870:       WALK_LIST(a, i->addrs)
  871: 	if (a->prefix.type == NET_IP6)
  872: 	  if_show_addr(a);
  873:     }
  874:   cli_msg(0, "");
  875: }
  876: 
  877: void
  878: if_show_summary(void)
  879: {
  880:   struct iface *i;
  881: 
  882:   cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
  883:   WALK_LIST(i, iface_list)
  884:     {
  885:       byte a4[IPA_MAX_TEXT_LENGTH + 17];
  886:       byte a6[IPA_MAX_TEXT_LENGTH + 17];
  887: 
  888:       if (i->flags & IF_SHUTDOWN)
  889: 	continue;
  890: 
  891:       if (i->addr4)
  892: 	bsprintf(a4, "%I/%d", i->addr4->ip, i->addr4->prefix.pxlen);
  893:       else
  894: 	a4[0] = 0;
  895: 
  896:       if (i->addr6)
  897: 	bsprintf(a6, "%I/%d", i->addr6->ip, i->addr6->prefix.pxlen);
  898:       else
  899: 	a6[0] = 0;
  900: 
  901:       cli_msg(-1005, "%-10s %-6s %-18s %s",
  902: 	      i->name, (i->flags & IF_UP) ? "up" : "down", a4, a6);
  903:     }
  904:   cli_msg(0, "");
  905: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>