Annotation of embedaddon/bird/proto/radv/radv.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD -- Router Advertisement
                      3:  *
                      4:  *
                      5:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      6:  */
                      7: 
                      8: 
                      9: #include <stdlib.h>
                     10: #include "radv.h"
                     11: 
                     12: /**
                     13:  * DOC: Router Advertisements
                     14:  *
                     15:  * The RAdv protocol is implemented in two files: |radv.c| containing
                     16:  * the interface with BIRD core and the protocol logic and |packets.c|
                     17:  * handling low level protocol stuff (RX, TX and packet formats).
                     18:  * The protocol does not export any routes.
                     19:  *
                     20:  * The RAdv is structured in the usual way - for each handled interface
                     21:  * there is a structure &radv_iface that contains a state related to
                     22:  * that interface together with its resources (a socket, a timer).
                     23:  * There is also a prepared RA stored in a TX buffer of the socket
                     24:  * associated with an iface. These iface structures are created
                     25:  * and removed according to iface events from BIRD core handled by
                     26:  * radv_if_notify() callback.
                     27:  *
                     28:  * The main logic of RAdv consists of two functions:
                     29:  * radv_iface_notify(), which processes asynchronous events (specified
                     30:  * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
                     31:  * computes the next timeout.
                     32:  *
                     33:  * The RAdv protocol could receive routes (through
                     34:  * radv_import_control() and radv_rt_notify()), but only the
                     35:  * configured trigger route is tracked (in &active var).  When a radv
                     36:  * protocol is reconfigured, the connected routing table is examined
                     37:  * (in radv_check_active()) to have proper &active value in case of
                     38:  * the specified trigger prefix was changed.
                     39:  *
                     40:  * Supported standards:
                     41:  * - RFC 4861 - main RA standard
                     42:  * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
                     43:  * - RFC 4191 (partial) - Default Router Preference
                     44:  */
                     45: 
                     46: static void
                     47: radv_timer(timer *tm)
                     48: {
                     49:   struct radv_iface *ifa = tm->data;
                     50:   struct proto_radv *ra = ifa->ra;
                     51: 
                     52:   RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
                     53: 
                     54:   radv_send_ra(ifa, 0);
                     55: 
                     56:   /* Update timer */
                     57:   ifa->last = now;
                     58:   unsigned after = ifa->cf->min_ra_int;
                     59:   after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
                     60: 
                     61:   if (ifa->initial)
                     62:     ifa->initial--;
                     63: 
                     64:   if (ifa->initial)
                     65:     after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
                     66: 
                     67:   tm_start(ifa->timer, after);
                     68: }
                     69: 
                     70: static char* ev_name[] = { NULL, "Init", "Change", "RS" };
                     71: 
                     72: void
                     73: radv_iface_notify(struct radv_iface *ifa, int event)
                     74: {
                     75:   struct proto_radv *ra = ifa->ra;
                     76: 
                     77:   if (!ifa->sk)
                     78:     return;
                     79: 
                     80:   RADV_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
                     81: 
                     82:   switch (event)
                     83:   {
                     84:   case RA_EV_CHANGE:
                     85:     ifa->plen = 0;
                     86:   case RA_EV_INIT:
                     87:     ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
                     88:     break;
                     89: 
                     90:   case RA_EV_RS:
                     91:     break;
                     92:   }
                     93: 
                     94:   /* Update timer */
                     95:   unsigned delta = now - ifa->last;
                     96:   unsigned after = 0;
                     97: 
                     98:   if (delta < ifa->cf->min_delay)
                     99:     after = ifa->cf->min_delay - delta;
                    100: 
                    101:   tm_start(ifa->timer, after);
                    102: }
                    103: 
                    104: static void
                    105: radv_iface_notify_all(struct proto_radv *ra, int event)
                    106: {
                    107:   struct radv_iface *ifa;
                    108: 
                    109:   WALK_LIST(ifa, ra->iface_list)
                    110:     radv_iface_notify(ifa, event);
                    111: }
                    112: 
                    113: 
                    114: static struct radv_iface *
                    115: radv_iface_find(struct proto_radv *ra, struct iface *what)
                    116: {
                    117:   struct radv_iface *ifa;
                    118: 
                    119:   WALK_LIST(ifa, ra->iface_list)
                    120:     if (ifa->iface == what)
                    121:       return ifa;
                    122: 
                    123:   return NULL;
                    124: }
                    125: 
                    126: static void
                    127: radv_iface_add(struct object_lock *lock)
                    128: {
                    129:   struct radv_iface *ifa = lock->data;
                    130:   struct proto_radv *ra = ifa->ra;
                    131: 
                    132:   if (! radv_sk_open(ifa))
                    133:   {
                    134:     log(L_ERR "%s: Socket open failed on interface %s", ra->p.name, ifa->iface->name);
                    135:     return;
                    136:   }
                    137: 
                    138:   radv_iface_notify(ifa, RA_EV_INIT);
                    139: }
                    140: 
                    141: static inline struct ifa *
                    142: find_lladdr(struct iface *iface)
                    143: {
                    144:   struct ifa *a;
                    145:   WALK_LIST(a, iface->addrs)
                    146:     if (a->scope == SCOPE_LINK)
                    147:       return a;
                    148: 
                    149:   return NULL;
                    150: }
                    151: 
                    152: static void
                    153: radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_config *cf)
                    154: {
                    155:   pool *pool = ra->p.pool;
                    156:   struct radv_iface *ifa;
                    157: 
                    158:   RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
                    159: 
                    160:   ifa = mb_allocz(pool, sizeof(struct radv_iface));
                    161:   ifa->ra = ra;
                    162:   ifa->cf = cf;
                    163:   ifa->iface = iface;
                    164: 
                    165:   add_tail(&ra->iface_list, NODE ifa);
                    166: 
                    167:   ifa->addr = find_lladdr(iface);
                    168:   if (!ifa->addr)
                    169:   {
                    170:     log(L_ERR "%s: Cannot find link-locad addr on interface %s", ra->p.name, iface->name);
                    171:     return;
                    172:   }
                    173: 
                    174:   timer *tm = tm_new(pool);
                    175:   tm->hook = radv_timer;
                    176:   tm->data = ifa;
                    177:   tm->randomize = 0;
                    178:   tm->recurrent = 0;
                    179:   ifa->timer = tm;
                    180: 
                    181:   struct object_lock *lock = olock_new(pool);
                    182:   lock->addr = IPA_NONE;
                    183:   lock->type = OBJLOCK_IP;
                    184:   lock->port = ICMPV6_PROTO;
                    185:   lock->iface = iface;
                    186:   lock->data = ifa;
                    187:   lock->hook = radv_iface_add;
                    188:   ifa->lock = lock;
                    189: 
                    190:   olock_acquire(lock);
                    191: }
                    192: 
                    193: static void
                    194: radv_iface_remove(struct radv_iface *ifa)
                    195: {
                    196:   struct proto_radv *ra = ifa->ra;
                    197:   RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
                    198: 
                    199:   rem_node(NODE ifa);
                    200: 
                    201:   rfree(ifa->sk);
                    202:   rfree(ifa->timer);
                    203:   rfree(ifa->lock);
                    204: 
                    205:   mb_free(ifa);
                    206: }
                    207: 
                    208: static void
                    209: radv_if_notify(struct proto *p, unsigned flags, struct iface *iface)
                    210: {
                    211:   struct proto_radv *ra = (struct proto_radv *) p;
                    212:   struct radv_config *cf = (struct radv_config *) (p->cf);
                    213: 
                    214:   if (iface->flags & IF_IGNORE)
                    215:     return;
                    216: 
                    217:   if (flags & IF_CHANGE_UP)
                    218:   {
                    219:     struct radv_iface_config *ic = (struct radv_iface_config *)
                    220:       iface_patt_find(&cf->patt_list, iface, NULL);
                    221: 
                    222:     if (ic)
                    223:       radv_iface_new(ra, iface, ic);
                    224: 
                    225:     return;
                    226:   }
                    227: 
                    228:   struct radv_iface *ifa = radv_iface_find(ra, iface);
                    229:   if (!ifa)
                    230:     return;
                    231: 
                    232:   if (flags & IF_CHANGE_DOWN)
                    233:   {
                    234:     radv_iface_remove(ifa);
                    235:     return;
                    236:   }
                    237: 
                    238:   if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
                    239:     radv_iface_notify(ifa, RA_EV_INIT);
                    240: }
                    241: 
                    242: static void
                    243: radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
                    244: {
                    245:   struct proto_radv *ra = (struct proto_radv *) p;
                    246: 
                    247:   if (a->flags & IA_SECONDARY)
                    248:     return;
                    249: 
                    250:   if (a->scope <= SCOPE_LINK)
                    251:     return;
                    252: 
                    253:   struct radv_iface *ifa = radv_iface_find(ra, a->iface);
                    254: 
                    255:   if (ifa)
                    256:     radv_iface_notify(ifa, RA_EV_CHANGE);
                    257: }
                    258: 
                    259: static inline int radv_net_match_trigger(struct radv_config *cf, net *n)
                    260: {
                    261:   return cf->trigger_valid &&
                    262:     (n->n.pxlen == cf->trigger_pxlen) &&
                    263:     ipa_equal(n->n.prefix, cf->trigger_prefix);
                    264: }
                    265: 
                    266: int
                    267: radv_import_control(struct proto *p, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
                    268: {
                    269:   // struct proto_radv *ra = (struct proto_radv *) p;
                    270:   struct radv_config *cf = (struct radv_config *) (p->cf);
                    271: 
                    272:   if (radv_net_match_trigger(cf, (*new)->net))
                    273:     return RIC_PROCESS;
                    274: 
                    275:   return RIC_DROP;
                    276: }
                    277: 
                    278: static void
                    279: radv_rt_notify(struct proto *p, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs UNUSED)
                    280: {
                    281:   struct proto_radv *ra = (struct proto_radv *) p;
                    282:   struct radv_config *cf = (struct radv_config *) (p->cf);
                    283: 
                    284:   if (radv_net_match_trigger(cf, n))
                    285:   {
                    286:     u8 old_active = ra->active;
                    287:     ra->active = !!new;
                    288: 
                    289:     if (ra->active == old_active)
                    290:       return;
                    291: 
                    292:     if (ra->active)
                    293:       RADV_TRACE(D_EVENTS, "Triggered");
                    294:     else
                    295:       RADV_TRACE(D_EVENTS, "Suppressed");
                    296: 
                    297:     radv_iface_notify_all(ra, RA_EV_CHANGE);
                    298:   }
                    299: }
                    300: 
                    301: static int
                    302: radv_check_active(struct proto_radv *ra)
                    303: {
                    304:   struct radv_config *cf = (struct radv_config *) (ra->p.cf);
                    305: 
                    306:   if (! cf->trigger_valid)
                    307:     return 1;
                    308: 
                    309:   return rt_examine(ra->p.table, cf->trigger_prefix, cf->trigger_pxlen,
                    310:                    &(ra->p), ra->p.cf->out_filter);
                    311: }
                    312: 
                    313: static struct proto *
                    314: radv_init(struct proto_config *c)
                    315: {
                    316:   struct proto *p = proto_new(c, sizeof(struct proto_radv));
                    317: 
                    318:   p->accept_ra_types = RA_OPTIMAL;
                    319:   p->import_control = radv_import_control;
                    320:   p->rt_notify = radv_rt_notify;
                    321:   p->if_notify = radv_if_notify;
                    322:   p->ifa_notify = radv_ifa_notify;
                    323:   return p;
                    324: }
                    325: 
                    326: static int
                    327: radv_start(struct proto *p)
                    328: {
                    329:   struct proto_radv *ra = (struct proto_radv *) p;
                    330:   struct radv_config *cf = (struct radv_config *) (p->cf);
                    331: 
                    332:   init_list(&(ra->iface_list));
                    333:   ra->active = !cf->trigger_valid;
                    334: 
                    335:   return PS_UP;
                    336: }
                    337: 
                    338: static inline void
                    339: radv_iface_shutdown(struct radv_iface *ifa)
                    340: {
                    341:   if (ifa->sk)
                    342:     radv_send_ra(ifa, 1);
                    343: }
                    344: 
                    345: static int
                    346: radv_shutdown(struct proto *p)
                    347: {
                    348:   struct proto_radv *ra = (struct proto_radv *) p;
                    349: 
                    350:   struct radv_iface *ifa;
                    351:   WALK_LIST(ifa, ra->iface_list)
                    352:     radv_iface_shutdown(ifa);
                    353: 
                    354:   return PS_DOWN;
                    355: }
                    356: 
                    357: static int
                    358: radv_reconfigure(struct proto *p, struct proto_config *c)
                    359: {
                    360:   struct proto_radv *ra = (struct proto_radv *) p;
                    361:   // struct radv_config *old = (struct radv_config *) (p->cf);
                    362:   struct radv_config *new = (struct radv_config *) c;
                    363: 
                    364:   /*
                    365:    * The question is why there is a reconfigure function for RAdv if
                    366:    * it has almost none internal state so restarting the protocol
                    367:    * would probably suffice. One small reason is that restarting the
                    368:    * protocol would lead to sending a RA with Router Lifetime 0
                    369:    * causing nodes to temporary remove their default routes.
                    370:    */
                    371: 
                    372:   p->cf = c; /* radv_check_active() requires proper p->cf */
                    373:   ra->active = radv_check_active(ra);
                    374: 
                    375:   struct iface *iface;
                    376:   WALK_LIST(iface, iface_list)
                    377:   {
                    378:     struct radv_iface *ifa = radv_iface_find(ra, iface);
                    379:     struct radv_iface_config *ic = (struct radv_iface_config *)
                    380:       iface_patt_find(&new->patt_list, iface, NULL);
                    381: 
                    382:     if (ifa && ic)
                    383:     {
                    384:       ifa->cf = ic;
                    385: 
                    386:       /* We cheat here - always notify the change even if there isn't
                    387:         any. That would leads just to a few unnecessary RAs. */
                    388:       radv_iface_notify(ifa, RA_EV_CHANGE);
                    389:     }
                    390: 
                    391:     if (ifa && !ic)
                    392:     {
                    393:       radv_iface_shutdown(ifa);
                    394:       radv_iface_remove(ifa);
                    395:     }
                    396: 
                    397:     if (!ifa && ic)
                    398:       radv_iface_new(ra, iface, ic);
                    399:   }
                    400: 
                    401:   return 1;
                    402: }
                    403: 
                    404: static void
                    405: radv_copy_config(struct proto_config *dest, struct proto_config *src)
                    406: {
                    407:   struct radv_config *d = (struct radv_config *) dest;
                    408:   struct radv_config *s = (struct radv_config *) src;
                    409: 
                    410:   /* We clean up patt_list, ifaces are non-sharable */
                    411:   init_list(&d->patt_list);
                    412: 
                    413:   /* We copy pref_list, shallow copy suffices */
                    414:   cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
                    415: }
                    416: 
                    417: static void
                    418: radv_get_status(struct proto *p, byte *buf)
                    419: {
                    420:   struct proto_radv *ra = (struct proto_radv *) p;
                    421: 
                    422:   if (!ra->active)
                    423:     strcpy(buf, "Suppressed");
                    424: }
                    425: 
                    426: struct protocol proto_radv = {
                    427:   .name =              "RAdv",
                    428:   .template =          "radv%d",
                    429:   .config_size =       sizeof(struct radv_config),
                    430:   .init =              radv_init,
                    431:   .start =             radv_start,
                    432:   .shutdown =          radv_shutdown,
                    433:   .reconfigure =       radv_reconfigure,
                    434:   .copy_config =       radv_copy_config,
                    435:   .get_status =                radv_get_status
                    436: };

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