Statistics
| Branch: | Revision:

iof-bird-daemon / proto / rip / rip.c @ 153f02da

History | View | Annotate | Download (32 KB)

1 a103373f Pavel Machek
/*
2 8465dccb Ondrej Zajicek (work)
 *        BIRD -- Routing Information Protocol (RIP)
3 a103373f Pavel Machek
 *
4 8465dccb Ondrej Zajicek (work)
 *        (c) 1998--1999 Pavel Machek <pavel@ucw.cz>
5
 *        (c) 2004--2013 Ondrej Filip <feela@network.cz>
6
 *        (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
7
 *        (c) 2009--2015 CZ.NIC z.s.p.o.
8 a103373f Pavel Machek
 *
9
 *        Can be freely distributed and used under the terms of the GNU GPL.
10
 */
11
12 2337ade7 Pavel Machek
/**
13 8465dccb Ondrej Zajicek (work)
 * DOC: Routing Information Protocol (RIP)
14
 *
15
 * The RIP protocol is implemented in two files: |rip.c| containing the protocol
16
 * logic, route management and the protocol glue with BIRD core, and |packets.c|
17
 * handling RIP packet processing, RX, TX and protocol sockets.
18
 *
19
 * Each instance of RIP is described by a structure &rip_proto, which contains
20
 * an internal RIP routing table, a list of protocol interfaces and the main
21
 * timer responsible for RIP routing table cleanup.
22
 *
23
 * RIP internal routing table contains incoming and outgoing routes. For each
24
 * network (represented by structure &rip_entry) there is one outgoing route
25
 * stored directly in &rip_entry and an one-way linked list of incoming routes
26
 * (structures &rip_rte). The list contains incoming routes from different RIP
27
 * neighbors, but only routes with the lowest metric are stored (i.e., all
28
 * stored incoming routes have the same metric).
29
 *
30
 * Note that RIP itself does not select outgoing route, that is done by the core
31
 * routing table. When a new incoming route is received, it is propagated to the
32
 * RIP table by rip_update_rte() and possibly stored in the list of incoming
33
 * routes. Then the change may be propagated to the core by rip_announce_rte().
34
 * The core selects the best route and propagate it to RIP by rip_rt_notify(),
35
 * which updates outgoing route part of &rip_entry and possibly triggers route
36
 * propagation by rip_trigger_update().
37 2337ade7 Pavel Machek
 *
38 8465dccb Ondrej Zajicek (work)
 * RIP interfaces are represented by structures &rip_iface. A RIP interface
39
 * contains a per-interface socket, a list of associated neighbors, interface
40
 * configuration, and state information related to scheduled interface events
41
 * and running update sessions. RIP interfaces are added and removed based on
42
 * core interface notifications.
43 4c5f93d7 Pavel Machek
 *
44 8465dccb Ondrej Zajicek (work)
 * There are two RIP interface events - regular updates and triggered updates.
45
 * Both are managed from the RIP interface timer (rip_iface_timer()). Regular
46
 * updates are called at fixed interval and propagate the whole routing table,
47
 * while triggered updates are scheduled by rip_trigger_update() due to some
48
 * routing table change and propagate only the routes modified since the time
49
 * they were scheduled. There are also unicast-destined requested updates, but
50
 * these are sent directly as a reaction to received RIP request message. The
51
 * update session is started by rip_send_table(). There may be at most one
52
 * active update session per interface, as the associated state (including the
53
 * fib iterator) is stored directly in &rip_iface structure.
54 58f7d004 Martin Mares
 *
55 8465dccb Ondrej Zajicek (work)
 * RIP neighbors are represented by structures &rip_neighbor. Compared to
56
 * neighbor handling in other routing protocols, RIP does not have explicit
57
 * neighbor discovery and adjacency maintenance, which makes the &rip_neighbor
58
 * related code a bit peculiar. RIP neighbors are interlinked with core neighbor
59
 * structures (&neighbor) and use core neighbor notifications to ensure that RIP
60
 * neighbors are timely removed. RIP neighbors are added based on received route
61
 * notifications and removed based on core neighbor and RIP interface events.
62 2337ade7 Pavel Machek
 *
63 8465dccb Ondrej Zajicek (work)
 * RIP neighbors are linked by RIP routes and use counter to track the number of
64
 * associated routes, but when these RIP routes timeout, associated RIP neighbor
65
 * is still alive (with zero counter). When RIP neighbor is removed but still
66
 * has some associated routes, it is not freed, just changed to detached state
67
 * (core neighbors and RIP ifaces are unlinked), then during the main timer
68
 * cleanup phase the associated routes are removed and the &rip_neighbor
69
 * structure is finally freed.
70 2337ade7 Pavel Machek
 *
71 8465dccb Ondrej Zajicek (work)
 * Supported standards:
72
 * - RFC 1058 - RIPv1
73
 * - RFC 2453 - RIPv2
74
 * - RFC 2080 - RIPng
75
 * - RFC 4822 - RIP cryptographic authentication
76 2337ade7 Pavel Machek
 */
77
78 8465dccb Ondrej Zajicek (work)
#include <stdlib.h>
79 a103373f Pavel Machek
#include "rip.h"
80
81 293e313e Pavel Machek
82 8465dccb Ondrej Zajicek (work)
static inline void rip_lock_neighbor(struct rip_neighbor *n);
83
static inline void rip_unlock_neighbor(struct rip_neighbor *n);
84
static inline int rip_iface_link_up(struct rip_iface *ifa);
85
static inline void rip_kick_timer(struct rip_proto *p);
86
static inline void rip_iface_kick_timer(struct rip_iface *ifa);
87
static void rip_iface_timer(timer *timer);
88
static void rip_trigger_update(struct rip_proto *p);
89 cb822c07 Pavel Machek
90 b94bbe00 Pavel Machek
91 4c5f93d7 Pavel Machek
/*
92 8465dccb Ondrej Zajicek (work)
 *        RIP routes
93 279f4c7b Pavel Machek
 */
94
95 8465dccb Ondrej Zajicek (work)
static struct rip_rte *
96
rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src)
97 7e61cac3 Pavel Machek
{
98 8465dccb Ondrej Zajicek (work)
  struct rip_rte *rt = sl_alloc(p->rte_slab);
99 d0031c5e Pavel Machek
100 8465dccb Ondrej Zajicek (work)
  memcpy(rt, src, sizeof(struct rip_rte));
101
  rt->next = *rp;
102
  *rp = rt;
103 18b4d6bf Pavel Machek
104 8465dccb Ondrej Zajicek (work)
  rip_lock_neighbor(rt->from);
105 7f704c06 Pavel Machek
106 8465dccb Ondrej Zajicek (work)
  return rt;
107 7e61cac3 Pavel Machek
}
108
109 8465dccb Ondrej Zajicek (work)
static inline void
110
rip_remove_rte(struct rip_proto *p, struct rip_rte **rp)
111
{
112
  struct rip_rte *rt = *rp;
113
114
  rip_unlock_neighbor(rt->from);
115
116
  *rp = rt->next;
117
  sl_free(p->rte_slab, rt);
118
}
119
120
static inline int rip_same_rte(struct rip_rte *a, struct rip_rte *b)
121
{ return a->metric == b->metric && a->tag == b->tag && ipa_equal(a->next_hop, b->next_hop); }
122
123
static inline int rip_valid_rte(struct rip_rte *rt)
124
{ return rt->from->ifa != NULL; }
125
126
/**
127
 * rip_announce_rte - announce route from RIP routing table to the core
128
 * @p: RIP instance
129
 * @en: related network
130
 *
131
 * The function takes a list of incoming routes from @en, prepare appropriate
132
 * &rte for the core and propagate it by rte_update().
133 b093c328 Pavel Machek
 */
134 7e61cac3 Pavel Machek
static void
135 8465dccb Ondrej Zajicek (work)
rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
136 279f4c7b Pavel Machek
{
137 8465dccb Ondrej Zajicek (work)
  struct rip_rte *rt = en->routes;
138
139
  /* Find first valid rte */
140
  while (rt && !rip_valid_rte(rt))
141
    rt = rt->next;
142
143
  if (rt)
144
  {
145
    /* Update */
146
    rta a0 = {
147
      .src = p->p.main_source,
148
      .source = RTS_RIP,
149
      .scope = SCOPE_UNIVERSE,
150 62e64905 Ondrej Zajicek (work)
      .dest = RTD_UNICAST,
151 8465dccb Ondrej Zajicek (work)
    };
152 6996f459 Pavel Machek
153 8465dccb Ondrej Zajicek (work)
    u8 rt_metric = rt->metric;
154
    u16 rt_tag = rt->tag;
155
156 62e64905 Ondrej Zajicek (work)
    if (p->ecmp)
157 8465dccb Ondrej Zajicek (work)
    {
158
      /* ECMP route */
159 62e64905 Ondrej Zajicek (work)
      struct nexthop *nhs = NULL;
160 8465dccb Ondrej Zajicek (work)
      int num = 0;
161 1b16029c Pavel Machek
162 8465dccb Ondrej Zajicek (work)
      for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
163
      {
164
        if (!rip_valid_rte(rt))
165
            continue;
166
167 62e64905 Ondrej Zajicek (work)
        struct nexthop *nh = allocz(sizeof(struct nexthop));
168 4e276a89 Jan Moskyto Matejka
169 8465dccb Ondrej Zajicek (work)
        nh->gw = rt->next_hop;
170
        nh->iface = rt->from->nbr->iface;
171
        nh->weight = rt->from->ifa->cf->ecmp_weight;
172 4e276a89 Jan Moskyto Matejka
173 62e64905 Ondrej Zajicek (work)
        nexthop_insert(&nhs, nh);
174 8465dccb Ondrej Zajicek (work)
        num++;
175
176
        if (rt->tag != rt_tag)
177
          rt_tag = 0;
178
      }
179 62e64905 Ondrej Zajicek (work)
180
      a0.nh = *nhs;
181 bd215f8b Pavel Machek
    }
182 772f4899 Pavel Machek
    else
183 8465dccb Ondrej Zajicek (work)
    {
184
      /* Unipath route */
185 62e64905 Ondrej Zajicek (work)
      a0.from = rt->from->nbr->addr;
186 4e276a89 Jan Moskyto Matejka
      a0.nh.gw = rt->next_hop;
187
      a0.nh.iface = rt->from->nbr->iface;
188 8465dccb Ondrej Zajicek (work)
    }
189 279f4c7b Pavel Machek
190 8465dccb Ondrej Zajicek (work)
    rta *a = rta_lookup(&a0);
191
    rte *e = rte_get_temp(a);
192 279f4c7b Pavel Machek
193 4e276a89 Jan Moskyto Matejka
    e->u.rip.from = a0.nh.iface;
194 8465dccb Ondrej Zajicek (work)
    e->u.rip.metric = rt_metric;
195
    e->u.rip.tag = rt_tag;
196
197
    e->pflags = 0;
198
199 2003a184 Jan Moskyto Matejka
    rte_update(&p->p, en->n.addr, e);
200 c3e9b2ab Pavel Machek
  }
201 28323d9d Martin Mares
  else
202 8465dccb Ondrej Zajicek (work)
  {
203
    /* Withdraw */
204 2003a184 Jan Moskyto Matejka
    rte_update(&p->p, en->n.addr, NULL);
205 8465dccb Ondrej Zajicek (work)
  }
206 279f4c7b Pavel Machek
}
207
208 8465dccb Ondrej Zajicek (work)
/**
209
 * rip_update_rte - enter a route update to RIP routing table
210
 * @p: RIP instance
211 fe9f1a6d Ondrej Zajicek (work)
 * @addr: network address
212 8465dccb Ondrej Zajicek (work)
 * @new: a &rip_rte representing the new route
213
 *
214
 * The function is called by the RIP packet processing code whenever it receives
215
 * a reachable route. The appropriate routing table entry is found and the list
216
 * of incoming routes is updated. Eventually, the change is also propagated to
217
 * the core by rip_announce_rte(). Note that for unreachable routes,
218
 * rip_withdraw_rte() should be called instead of rip_update_rte().
219
 */
220
void
221 fe9f1a6d Ondrej Zajicek (work)
rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new)
222 2d9290e9 Pavel Machek
{
223 fe9f1a6d Ondrej Zajicek (work)
  struct rip_entry *en = fib_get(&p->rtable, n);
224 8465dccb Ondrej Zajicek (work)
  struct rip_rte *rt, **rp;
225
  int changed = 0;
226
227
  /* If the new route is better, remove all current routes */
228
  if (en->routes && new->metric < en->routes->metric)
229
    while (en->routes)
230
      rip_remove_rte(p, &en->routes);
231
232
  /* Find the old route (also set rp for later) */
233
  for (rp = &en->routes; rt = *rp; rp = &rt->next)
234
    if (rt->from == new->from)
235
    {
236
      if (rip_same_rte(rt, new))
237
      {
238
        rt->expires = new->expires;
239
        return;
240
      }
241 02933ddb Pavel Machek
242 8465dccb Ondrej Zajicek (work)
      /* Remove the old route */
243
      rip_remove_rte(p, rp);
244
      changed = 1;
245
      break;
246
    }
247
248
  /* If the new route is optimal, add it to the list */
249
  if (!en->routes || new->metric == en->routes->metric)
250
  {
251
    rt = rip_add_rte(p, rp, new);
252
    changed = 1;
253
  }
254
255
  /* Announce change if on relevant position (the first or any for ECMP) */
256
  if (changed && (rp == &en->routes || p->ecmp))
257
    rip_announce_rte(p, en);
258 2d9290e9 Pavel Machek
}
259
260 8465dccb Ondrej Zajicek (work)
/**
261
 * rip_withdraw_rte - enter a route withdraw to RIP routing table
262
 * @p: RIP instance
263 fe9f1a6d Ondrej Zajicek (work)
 * @addr: network address
264 8465dccb Ondrej Zajicek (work)
 * @from: a &rip_neighbor propagating the withdraw
265 b093c328 Pavel Machek
 *
266 8465dccb Ondrej Zajicek (work)
 * The function is called by the RIP packet processing code whenever it receives
267
 * an unreachable route. The incoming route for given network from nbr @from is
268
 * removed. Eventually, the change is also propagated by rip_announce_rte().
269 279f4c7b Pavel Machek
 */
270 8465dccb Ondrej Zajicek (work)
void
271 fe9f1a6d Ondrej Zajicek (work)
rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
272 8465dccb Ondrej Zajicek (work)
{
273 fe9f1a6d Ondrej Zajicek (work)
  struct rip_entry *en = fib_find(&p->rtable, n);
274 8465dccb Ondrej Zajicek (work)
  struct rip_rte *rt, **rp;
275 279f4c7b Pavel Machek
276 8465dccb Ondrej Zajicek (work)
  if (!en)
277
    return;
278 094d2bdb Ondrej Zajicek
279 8465dccb Ondrej Zajicek (work)
  /* Find the old route */
280
  for (rp = &en->routes; rt = *rp; rp = &rt->next)
281
    if (rt->from == from)
282
      break;
283 14758d87 Pavel Machek
284 8465dccb Ondrej Zajicek (work)
  if (!rt)
285
    return;
286
287
  /* Remove the old route */
288
  rip_remove_rte(p, rp);
289
290
  /* Announce change if on relevant position */
291
  if (rp == &en->routes || p->ecmp)
292
    rip_announce_rte(p, en);
293 14758d87 Pavel Machek
}
294
295 4c5f93d7 Pavel Machek
/*
296 8465dccb Ondrej Zajicek (work)
 * rip_rt_notify - core tells us about new route, so store
297
 * it into our data structures.
298 b093c328 Pavel Machek
 */
299 21580e30 Pavel Machek
static void
300 4bdf1881 Jan Moskyto Matejka
rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
301 8465dccb Ondrej Zajicek (work)
              struct rte *old UNUSED, struct ea_list *attrs)
302 21580e30 Pavel Machek
{
303 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (struct rip_proto *) P;
304
  struct rip_entry *en;
305
  int old_metric;
306
307
  if (new)
308
  {
309
    /* Update */
310
    u32 rt_metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
311
    u32 rt_tag = ea_get_int(attrs, EA_RIP_TAG, 0);
312
313
    if (rt_metric > p->infinity)
314
    {
315 fe9f1a6d Ondrej Zajicek (work)
      log(L_WARN "%s: Invalid rip_metric value %u for route %N",
316
          p->p.name, rt_metric, net->n.addr);
317 8465dccb Ondrej Zajicek (work)
      rt_metric = p->infinity;
318
    }
319
320
    if (rt_tag > 0xffff)
321
    {
322 fe9f1a6d Ondrej Zajicek (work)
      log(L_WARN "%s: Invalid rip_tag value %u for route %N",
323
          p->p.name, rt_tag, net->n.addr);
324 8465dccb Ondrej Zajicek (work)
      rt_metric = p->infinity;
325
      rt_tag = 0;
326
    }
327
328
    /*
329
     * Note that we accept exported routes with infinity metric (this could
330
     * happen if rip_metric is modified in filters). Such entry has infinity
331
     * metric but is RIP_ENTRY_VALID and therefore is not subject to garbage
332
     * collection.
333
     */
334
335 fe9f1a6d Ondrej Zajicek (work)
    en = fib_get(&p->rtable, net->n.addr);
336 8465dccb Ondrej Zajicek (work)
337
    old_metric = en->valid ? en->metric : -1;
338
339
    en->valid = RIP_ENTRY_VALID;
340
    en->metric = rt_metric;
341
    en->tag = rt_tag;
342
    en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
343 4e276a89 Jan Moskyto Matejka
    en->iface = new->attrs->nh.iface;
344
    en->next_hop = new->attrs->nh.gw;
345 491cd43b Martin Mares
  }
346 8465dccb Ondrej Zajicek (work)
  else
347
  {
348
    /* Withdraw */
349 fe9f1a6d Ondrej Zajicek (work)
    en = fib_find(&p->rtable, net->n.addr);
350 feb6abe0 Pavel Machek
351 8465dccb Ondrej Zajicek (work)
    if (!en || en->valid != RIP_ENTRY_VALID)
352
      return;
353
354
    old_metric = en->metric;
355
356
    en->valid = RIP_ENTRY_STALE;
357
    en->metric = p->infinity;
358
    en->tag = 0;
359
    en->from = NULL;
360
    en->iface = NULL;
361
    en->next_hop = IPA_NONE;
362 02933ddb Pavel Machek
  }
363 8465dccb Ondrej Zajicek (work)
364
  /* Activate triggered updates */
365
  if (en->metric != old_metric)
366
  {
367
    en->changed = now;
368
    rip_trigger_update(p);
369 29df5739 Pavel Machek
  }
370 21580e30 Pavel Machek
}
371 a103373f Pavel Machek
372 8465dccb Ondrej Zajicek (work)
373 4c5f93d7 Pavel Machek
/*
374 8465dccb Ondrej Zajicek (work)
 *        RIP neighbors
375 b093c328 Pavel Machek
 */
376 8465dccb Ondrej Zajicek (work)
377
struct rip_neighbor *
378
rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa)
379
{
380
  neighbor *nbr = neigh_find2(&p->p, a, ifa->iface, 0);
381
382
  if (!nbr || (nbr->scope == SCOPE_HOST) || !rip_iface_link_up(ifa))
383
    return NULL;
384
385
  if (nbr->data)
386
    return nbr->data;
387
388
  TRACE(D_EVENTS, "New neighbor %I on %s", *a, ifa->iface->name);
389
390
  struct rip_neighbor *n = mb_allocz(p->p.pool, sizeof(struct rip_neighbor));
391
  n->ifa = ifa;
392
  n->nbr = nbr;
393
  nbr->data = n;
394
  n->csn = nbr->aux;
395
396
  add_tail(&ifa->neigh_list, NODE n);
397
398
  return n;
399
}
400
401 a103373f Pavel Machek
static void
402 8465dccb Ondrej Zajicek (work)
rip_remove_neighbor(struct rip_proto *p, struct rip_neighbor *n)
403 a103373f Pavel Machek
{
404 8465dccb Ondrej Zajicek (work)
  neighbor *nbr = n->nbr;
405
406
  TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->iface->name);
407 a103373f Pavel Machek
408 8465dccb Ondrej Zajicek (work)
  rem_node(NODE n);
409
  n->ifa = NULL;
410
  n->nbr = NULL;
411
  nbr->data = NULL;
412
  nbr->aux = n->csn;
413
414
  rfree(n->bfd_req);
415
  n->bfd_req = NULL;
416
  n->last_seen = 0;
417
418
  if (!n->uc)
419
    mb_free(n);
420
421
  /* Related routes are removed in rip_timer() */
422
  rip_kick_timer(p);
423 a103373f Pavel Machek
}
424
425 8465dccb Ondrej Zajicek (work)
static inline void
426
rip_lock_neighbor(struct rip_neighbor *n)
427
{
428
  n->uc++;
429
}
430 279f4c7b Pavel Machek
431 8465dccb Ondrej Zajicek (work)
static inline void
432
rip_unlock_neighbor(struct rip_neighbor *n)
433 a103373f Pavel Machek
{
434 8465dccb Ondrej Zajicek (work)
  n->uc--;
435
436
  if (!n->nbr && !n->uc)
437
    mb_free(n);
438
}
439
440
static void
441
rip_neigh_notify(struct neighbor *nbr)
442
{
443
  struct rip_proto *p = (struct rip_proto *) nbr->proto;
444
  struct rip_neighbor *n = nbr->data;
445
446
  if (!n)
447
    return;
448
449
  /*
450
   * We assume that rip_neigh_notify() is called before rip_if_notify() for
451
   * IF_CHANGE_DOWN and therefore n->ifa is still valid. We have no such
452
   * ordering assumption for IF_CHANGE_LINK, so we test link state of the
453
   * underlying iface instead of just rip_iface state.
454
   */
455
  if ((nbr->scope <= 0) || !rip_iface_link_up(n->ifa))
456
    rip_remove_neighbor(p, n);
457
}
458
459
static void
460
rip_bfd_notify(struct bfd_request *req)
461
{
462
  struct rip_neighbor *n = req->data;
463
  struct rip_proto *p = n->ifa->rip;
464 a103373f Pavel Machek
465 8465dccb Ondrej Zajicek (work)
  if (req->down)
466
  {
467
    TRACE(D_EVENTS, "BFD session down for nbr %I on %s",
468
          n->nbr->addr, n->ifa->iface->name);
469
    rip_remove_neighbor(p, n);
470 a103373f Pavel Machek
  }
471 8465dccb Ondrej Zajicek (work)
}
472
473
void
474
rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
475
{
476
  int use_bfd = n->ifa->cf->bfd && n->last_seen;
477 a103373f Pavel Machek
478 8465dccb Ondrej Zajicek (work)
  if (use_bfd && !n->bfd_req)
479
  {
480
    /*
481
     * For RIPv2, use the same address as rip_open_socket(). For RIPng, neighbor
482
     * should contain an address from the same prefix, thus also link-local. It
483
     * may cause problems if two link-local addresses are assigned to one iface.
484
     */
485
    ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
486
    n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
487
                                     n->nbr->iface, rip_bfd_notify, n);
488 a103373f Pavel Machek
  }
489
490 8465dccb Ondrej Zajicek (work)
  if (!use_bfd && n->bfd_req)
491
  {
492
    rfree(n->bfd_req);
493
    n->bfd_req = NULL;
494
  }
495 a103373f Pavel Machek
}
496
497 8465dccb Ondrej Zajicek (work)
498 4c5f93d7 Pavel Machek
/*
499 8465dccb Ondrej Zajicek (work)
 *        RIP interfaces
500 b093c328 Pavel Machek
 */
501 8465dccb Ondrej Zajicek (work)
502
static void
503
rip_iface_start(struct rip_iface *ifa)
504 a103373f Pavel Machek
{
505 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = ifa->rip;
506 a103373f Pavel Machek
507 8465dccb Ondrej Zajicek (work)
  TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
508 4a020137 Martin Mares
509 8465dccb Ondrej Zajicek (work)
  ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
510
  ifa->next_triggered = now;        /* Available immediately */
511
  ifa->want_triggered = 1;        /* All routes in triggered update */
512
  tm_start(ifa->timer, 1);        /* Or 100 ms */
513
  ifa->up = 1;
514 f7615037 Ondrej Zajicek
515 8465dccb Ondrej Zajicek (work)
  if (!ifa->cf->passive)
516
    rip_send_request(ifa->rip, ifa);
517
}
518 f7615037 Ondrej Zajicek
519 8465dccb Ondrej Zajicek (work)
static void
520
rip_iface_stop(struct rip_iface *ifa)
521
{
522
  struct rip_proto *p = ifa->rip;
523
  struct rip_neighbor *n;
524 70e212f9 Ondrej Zajicek
525 8465dccb Ondrej Zajicek (work)
  TRACE(D_EVENTS, "Stopping interface %s", ifa->iface->name);
526 70e212f9 Ondrej Zajicek
527 8465dccb Ondrej Zajicek (work)
  rip_reset_tx_session(p, ifa);
528 a103373f Pavel Machek
529 8465dccb Ondrej Zajicek (work)
  WALK_LIST_FIRST(n, ifa->neigh_list)
530
    rip_remove_neighbor(p, n);
531 0bff946c Pavel Machek
532 8465dccb Ondrej Zajicek (work)
  tm_stop(ifa->timer);
533
  ifa->up = 0;
534 a103373f Pavel Machek
}
535
536 8465dccb Ondrej Zajicek (work)
static inline int
537
rip_iface_link_up(struct rip_iface *ifa)
538
{
539
  return !ifa->cf->check_link || (ifa->iface->flags & IF_LINK_UP);
540
}
541 279f4c7b Pavel Machek
542 a103373f Pavel Machek
static void
543 8465dccb Ondrej Zajicek (work)
rip_iface_update_state(struct rip_iface *ifa)
544 a103373f Pavel Machek
{
545 8465dccb Ondrej Zajicek (work)
  int up = ifa->sk && rip_iface_link_up(ifa);
546 a103373f Pavel Machek
547 8465dccb Ondrej Zajicek (work)
  if (up == ifa->up)
548
    return;
549
550
  if (up)
551
    rip_iface_start(ifa);
552
  else
553
    rip_iface_stop(ifa);
554
}
555 4c5f93d7 Pavel Machek
556 a103373f Pavel Machek
static void
557 8465dccb Ondrej Zajicek (work)
rip_iface_update_buffers(struct rip_iface *ifa)
558 a103373f Pavel Machek
{
559 8465dccb Ondrej Zajicek (work)
  if (!ifa->sk)
560
    return;
561 a103373f Pavel Machek
562 8465dccb Ondrej Zajicek (work)
  uint rbsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
563
  uint tbsize = ifa->cf->tx_length ?: ifa->iface->mtu;
564
  rbsize = MAX(rbsize, tbsize);
565 de41dcd1 Ondrej Filip
566 8465dccb Ondrej Zajicek (work)
  sk_set_rbsize(ifa->sk, rbsize);
567
  sk_set_tbsize(ifa->sk, tbsize);
568 de41dcd1 Ondrej Filip
569 8465dccb Ondrej Zajicek (work)
  uint headers = (rip_is_v2(ifa->rip) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH) + UDP_HEADER_LENGTH;
570
  ifa->tx_plen = tbsize - headers;
571 feb6abe0 Pavel Machek
572 8465dccb Ondrej Zajicek (work)
  if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
573 390601f0 Ondrej Zajicek (work)
    ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords);
574 8465dccb Ondrej Zajicek (work)
}
575 3918b1b0 Pavel Machek
576 8465dccb Ondrej Zajicek (work)
static inline void
577
rip_iface_update_bfd(struct rip_iface *ifa)
578
{
579
  struct rip_proto *p = ifa->rip;
580
  struct rip_neighbor *n;
581
582
  WALK_LIST(n, ifa->neigh_list)
583
    rip_update_bfd(p, n);
584
}
585
586
587
static void
588
rip_iface_locked(struct object_lock *lock)
589
{
590
  struct rip_iface *ifa = lock->data;
591
  struct rip_proto *p = ifa->rip;
592 279f4c7b Pavel Machek
593 8465dccb Ondrej Zajicek (work)
  if (!rip_open_socket(ifa))
594 feb6abe0 Pavel Machek
  {
595 8465dccb Ondrej Zajicek (work)
    log(L_ERR "%s: Cannot open socket for %s", p->p.name, ifa->iface->name);
596
    return;
597
  }
598 a9c38203 Ondrej Filip
599 8465dccb Ondrej Zajicek (work)
  rip_iface_update_buffers(ifa);
600
  rip_iface_update_state(ifa);
601
}
602 a9c38203 Ondrej Filip
603 279f4c7b Pavel Machek
604 8465dccb Ondrej Zajicek (work)
static struct rip_iface *
605
rip_find_iface(struct rip_proto *p, struct iface *what)
606
{
607
  struct rip_iface *ifa;
608 feb6abe0 Pavel Machek
609 8465dccb Ondrej Zajicek (work)
  WALK_LIST(ifa, p->iface_list)
610
    if (ifa->iface == what)
611
      return ifa;
612 1d941de4 Pavel Machek
613 8465dccb Ondrej Zajicek (work)
  return NULL;
614 a103373f Pavel Machek
}
615
616 8465dccb Ondrej Zajicek (work)
static void
617
rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config *ic)
618 a103373f Pavel Machek
{
619 8465dccb Ondrej Zajicek (work)
  struct rip_iface *ifa;
620
621
  TRACE(D_EVENTS, "Adding interface %s", iface->name);
622
623
  ifa = mb_allocz(p->p.pool, sizeof(struct rip_iface));
624
  ifa->rip = p;
625
  ifa->iface = iface;
626
  ifa->cf = ic;
627
628
  if (ipa_nonzero(ic->address))
629
    ifa->addr = ic->address;
630
  else if (ic->mode == RIP_IM_MULTICAST)
631
    ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
632
  else /* Broadcast */
633 153f02da Ondrej Zajicek (work)
    ifa->addr = iface->addr4->brd;
634
  /*
635
   * The above is just a workaround for BSD as it can't send broadcasts
636
   * to 255.255.255.255. BSD systems need the network broadcast address instead.
637
   *
638
   * TODO: move this to sysdep code
639
   */
640 8465dccb Ondrej Zajicek (work)
641
  init_list(&ifa->neigh_list);
642
643
  add_tail(&p->iface_list, NODE ifa);
644
645
  ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
646
647
  struct object_lock *lock = olock_new(p->p.pool);
648
  lock->type = OBJLOCK_UDP;
649
  lock->port = ic->port;
650
  lock->iface = iface;
651
  lock->data = ifa;
652
  lock->hook = rip_iface_locked;
653
  ifa->lock = lock;
654
655
  olock_acquire(lock);
656 a103373f Pavel Machek
}
657
658
static void
659 8465dccb Ondrej Zajicek (work)
rip_remove_iface(struct rip_proto *p, struct rip_iface *ifa)
660 a103373f Pavel Machek
{
661 8465dccb Ondrej Zajicek (work)
  rip_iface_stop(ifa);
662 c748cdb9 Pavel Machek
663 8465dccb Ondrej Zajicek (work)
  TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
664
665
  rem_node(NODE ifa);
666
667
  rfree(ifa->sk);
668
  rfree(ifa->lock);
669
  rfree(ifa->timer);
670
671
  mb_free(ifa);
672
}
673
674
static int
675
rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_iface_config *new)
676
{
677
  struct rip_iface_config *old = ifa->cf;
678
679
  /* Change of these options would require to reset the iface socket */
680
  if ((new->mode != old->mode) ||
681
      (new->port != old->port) ||
682
      (new->tx_tos != old->tx_tos) ||
683
      (new->tx_priority != old->tx_priority) ||
684
      (new->ttl_security != old->ttl_security))
685
    return 0;
686
687
  TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);
688
689
  ifa->cf = new;
690
691 390601f0 Ondrej Zajicek (work)
  rip_iface_update_buffers(ifa);
692
693 734e9fb8 Ondrej Zajicek (work)
  if (ifa->next_regular > (now + (bird_clock_t) new->update_time))
694 8465dccb Ondrej Zajicek (work)
    ifa->next_regular = now + (random() % new->update_time) + 1;
695
696
  if (new->check_link != old->check_link)
697
    rip_iface_update_state(ifa);
698
699
  if (new->bfd != old->bfd)
700
    rip_iface_update_bfd(ifa);
701
702
  if (ifa->up)
703
    rip_iface_kick_timer(ifa);
704
705
  return 1;
706 c3e9b2ab Pavel Machek
}
707
708 dff1f579 Pavel Machek
static void
709 8465dccb Ondrej Zajicek (work)
rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
710 dff1f579 Pavel Machek
{
711 8465dccb Ondrej Zajicek (work)
  struct iface *iface;
712
713
  WALK_LIST(iface, iface_list)
714
  {
715 153f02da Ondrej Zajicek (work)
    if (!(iface->flags & IF_UP))
716
      continue;
717
718
    /* Ignore ifaces without appropriate address */
719
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
720 8465dccb Ondrej Zajicek (work)
      continue;
721
722
    struct rip_iface *ifa = rip_find_iface(p, iface);
723
    struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
724 ce1da96e Martin Mares
725 8465dccb Ondrej Zajicek (work)
    if (ifa && ic)
726
    {
727
      if (rip_reconfigure_iface(p, ifa, ic))
728
        continue;
729
730
      /* Hard restart */
731
      log(L_INFO "%s: Restarting interface %s", p->p.name, ifa->iface->name);
732
      rip_remove_iface(p, ifa);
733
      rip_add_iface(p, iface, ic);
734
    }
735
736
    if (ifa && !ic)
737
      rip_remove_iface(p, ifa);
738
739
    if (!ifa && ic)
740
      rip_add_iface(p, iface, ic);
741
  }
742 dff1f579 Pavel Machek
}
743
744 c3e9b2ab Pavel Machek
static void
745 8465dccb Ondrej Zajicek (work)
rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
746 c3e9b2ab Pavel Machek
{
747 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (void *) P;
748
  struct rip_config *cf = (void *) P->cf;
749
750
  if (iface->flags & IF_IGNORE)
751
    return;
752
753
  if (flags & IF_CHANGE_UP)
754
  {
755
    struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
756
757 153f02da Ondrej Zajicek (work)
    /* Ignore ifaces without appropriate address */
758
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
759
      return;
760
761 8465dccb Ondrej Zajicek (work)
    if (ic)
762
      rip_add_iface(p, iface, ic);
763
764
    return;
765
  }
766
767
  struct rip_iface *ifa = rip_find_iface(p, iface);
768
769
  if (!ifa)
770
    return;
771
772
  if (flags & IF_CHANGE_DOWN)
773
  {
774
    rip_remove_iface(p, ifa);
775
    return;
776
  }
777
778
  if (flags & IF_CHANGE_MTU)
779
    rip_iface_update_buffers(ifa);
780
781
  if (flags & IF_CHANGE_LINK)
782
    rip_iface_update_state(ifa);
783 c3e9b2ab Pavel Machek
}
784
785 8465dccb Ondrej Zajicek (work)
786
/*
787
 *        RIP timer events
788
 */
789
790 6c0a7174 Pavel Machek
/**
791 8465dccb Ondrej Zajicek (work)
 * rip_timer - RIP main timer hook
792
 * @t: timer
793 4c5f93d7 Pavel Machek
 *
794 8465dccb Ondrej Zajicek (work)
 * The RIP main timer is responsible for routing table maintenance. Invalid or
795
 * expired routes (&rip_rte) are removed and garbage collection of stale routing
796
 * table entries (&rip_entry) is done. Changes are propagated to core tables,
797
 * route reload is also done here. Note that garbage collection uses a maximal
798
 * GC time, while interfaces maintain an illusion of per-interface GC times in
799
 * rip_send_response().
800
 *
801
 * Keeping incoming routes and the selected outgoing route are two independent
802
 * functions, therefore after garbage collection some entries now considered
803
 * invalid (RIP_ENTRY_DUMMY) still may have non-empty list of incoming routes,
804
 * while some valid entries (representing an outgoing route) may have that list
805
 * empty.
806
 *
807
 * The main timer is not scheduled periodically but it uses the time of the
808
 * current next event and the minimal interval of any possible event to compute
809
 * the time of the next run.
810 06fa1453 Pavel Machek
 */
811 8465dccb Ondrej Zajicek (work)
static void
812
rip_timer(timer *t)
813 c3e9b2ab Pavel Machek
{
814 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = t->data;
815
  struct rip_config *cf = (void *) (p->p.cf);
816
  struct rip_iface *ifa;
817
  struct rip_neighbor *n, *nn;
818
  struct fib_iterator fit;
819
  bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
820
  bird_clock_t expires = 0;
821
822
  TRACE(D_EVENTS, "Main timer fired");
823
824
  FIB_ITERATE_INIT(&fit, &p->rtable);
825
826
  loop:
827 600998fc Ondrej Zajicek (work)
  FIB_ITERATE_START(&p->rtable, &fit, struct rip_entry, en)
828 8465dccb Ondrej Zajicek (work)
  {
829
    struct rip_rte *rt, **rp;
830
    int changed = 0;
831
832
    /* Checking received routes for timeout and for dead neighbors */
833
    for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
834 e24ddd9b Martin Mares
    {
835 8465dccb Ondrej Zajicek (work)
      if (!rip_valid_rte(rt) || (rt->expires <= now))
836
      {
837
        rip_remove_rte(p, rp);
838
        changed = 1;
839
        continue;
840
      }
841 06fa1453 Pavel Machek
842 8465dccb Ondrej Zajicek (work)
      next = MIN(next, rt->expires);
843
      rp = &rt->next;
844 28323d9d Martin Mares
    }
845 06fa1453 Pavel Machek
846 8465dccb Ondrej Zajicek (work)
    /* Propagating eventual change */
847
    if (changed || p->rt_reload)
848
    {
849
      /*
850
       * We have to restart the iteration because there may be a cascade of
851
       * synchronous events rip_announce_rte() -> nest table change ->
852
       * rip_rt_notify() -> p->rtable change, invalidating hidden variables.
853
       */
854
855 600998fc Ondrej Zajicek (work)
      FIB_ITERATE_PUT_NEXT(&fit, &p->rtable);
856 8465dccb Ondrej Zajicek (work)
      rip_announce_rte(p, en);
857
      goto loop;
858
    }
859 f9c799a0 Ondrej Zajicek
860 8465dccb Ondrej Zajicek (work)
    /* Checking stale entries for garbage collection timeout */
861
    if (en->valid == RIP_ENTRY_STALE)
862
    {
863
      expires = en->changed + cf->max_garbage_time;
864 f9c799a0 Ondrej Zajicek
865 8465dccb Ondrej Zajicek (work)
      if (expires <= now)
866 f9c799a0 Ondrej Zajicek
      {
867 fe9f1a6d Ondrej Zajicek (work)
        // TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
868 8465dccb Ondrej Zajicek (work)
        en->valid = 0;
869 f9c799a0 Ondrej Zajicek
      }
870 8465dccb Ondrej Zajicek (work)
      else
871
        next = MIN(next, expires);
872
    }
873
874
    /* Remove empty nodes */
875
    if (!en->valid && !en->routes)
876
    {
877 600998fc Ondrej Zajicek (work)
      FIB_ITERATE_PUT(&fit);
878
      fib_delete(&p->rtable, en);
879 8465dccb Ondrej Zajicek (work)
      goto loop;
880
    }
881
  }
882 600998fc Ondrej Zajicek (work)
  FIB_ITERATE_END;
883 8465dccb Ondrej Zajicek (work)
884
  p->rt_reload = 0;
885
886
  /* Handling neighbor expiration */
887
  WALK_LIST(ifa, p->iface_list)
888
    WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
889
      if (n->last_seen)
890 f9c799a0 Ondrej Zajicek
      {
891 8465dccb Ondrej Zajicek (work)
        expires = n->last_seen + n->ifa->cf->timeout_time;
892
893
        if (expires <= now)
894
          rip_remove_neighbor(p, n);
895
        else
896
          next = MIN(next, expires);
897 f9c799a0 Ondrej Zajicek
      }
898 b94bbe00 Pavel Machek
899 8465dccb Ondrej Zajicek (work)
  tm_start(p->timer, MAX(next - now, 1));
900
}
901
902
static inline void
903
rip_kick_timer(struct rip_proto *p)
904
{
905
  if (p->timer->expires > (now + 1))
906
    tm_start(p->timer, 1);        /* Or 100 ms */
907
}
908 f9c799a0 Ondrej Zajicek
909 8465dccb Ondrej Zajicek (work)
/**
910
 * rip_iface_timer - RIP interface timer hook
911
 * @t: timer
912
 *
913
 * RIP interface timers are responsible for scheduling both regular and
914
 * triggered updates. Fixed, delay-independent period is used for regular
915
 * updates, while minimal separating interval is enforced for triggered updates.
916
 * The function also ensures that a new update is not started when the old one
917
 * is still running.
918
 */
919
static void
920
rip_iface_timer(timer *t)
921
{
922
  struct rip_iface *ifa = t->data;
923
  struct rip_proto *p = ifa->rip;
924
  bird_clock_t period = ifa->cf->update_time;
925
926
  if (ifa->cf->passive)
927
    return;
928
929
  TRACE(D_EVENTS, "Interface timer fired for %s", ifa->iface->name);
930
931
  if (ifa->tx_active)
932
  {
933
    if (now < (ifa->next_regular + period))
934
      { tm_start(ifa->timer, 1); return; }
935
936
    /* We are too late, reset is done by rip_send_table() */
937
    log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
938 f9c799a0 Ondrej Zajicek
  }
939 8465dccb Ondrej Zajicek (work)
940
  if (now >= ifa->next_regular)
941
  {
942
    /* Send regular update, set timer for next period (or following one if necessay) */
943
    TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
944
    rip_send_table(p, ifa, ifa->addr, 0);
945
    ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
946
    ifa->want_triggered = 0;
947
    p->triggered = 0;
948
  }
949
  else if (ifa->want_triggered && (now >= ifa->next_triggered))
950
  {
951
    /* Send triggered update, enforce interval between triggered updates */
952
    TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
953
    rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
954
    ifa->next_triggered = now + MIN(5, period / 2 + 1);
955
    ifa->want_triggered = 0;
956
    p->triggered = 0;
957
  }
958
959
  tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now));
960 a103373f Pavel Machek
}
961
962 8465dccb Ondrej Zajicek (work)
static inline void
963
rip_iface_kick_timer(struct rip_iface *ifa)
964 ff8ed632 Pavel Machek
{
965 8465dccb Ondrej Zajicek (work)
  if (ifa->timer->expires > (now + 1))
966
    tm_start(ifa->timer, 1);        /* Or 100 ms */
967 ff8ed632 Pavel Machek
}
968
969
static void
970 8465dccb Ondrej Zajicek (work)
rip_trigger_update(struct rip_proto *p)
971 279f4c7b Pavel Machek
{
972 8465dccb Ondrej Zajicek (work)
  if (p->triggered)
973 9a158361 Martin Mares
    return;
974 8465dccb Ondrej Zajicek (work)
975
  struct rip_iface *ifa;
976
  WALK_LIST(ifa, p->iface_list)
977
  {
978
    /* Interface not active */
979
    if (! ifa->up)
980
      continue;
981
982
    /* Already scheduled */
983
    if (ifa->want_triggered)
984
      continue;
985
986
    TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
987
    ifa->want_triggered = now;
988
    rip_iface_kick_timer(ifa);
989 c3e9b2ab Pavel Machek
  }
990 8465dccb Ondrej Zajicek (work)
991
  p->triggered = 1;
992 279f4c7b Pavel Machek
}
993
994 8465dccb Ondrej Zajicek (work)
995
/*
996
 *        RIP protocol glue
997
 */
998
999 91c7c741 Pavel Machek
static struct ea_list *
1000 8465dccb Ondrej Zajicek (work)
rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
1001 91c7c741 Pavel Machek
{
1002 8465dccb Ondrej Zajicek (work)
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
1003 91c7c741 Pavel Machek
1004 8465dccb Ondrej Zajicek (work)
  l->next = next;
1005 91c7c741 Pavel Machek
  l->flags = EALF_SORTED;
1006
  l->count = 2;
1007 8465dccb Ondrej Zajicek (work)
1008
  l->attrs[0].id = EA_RIP_METRIC;
1009 91c7c741 Pavel Machek
  l->attrs[0].flags = 0;
1010 9f4929e7 Martin Mares
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
1011 8465dccb Ondrej Zajicek (work)
  l->attrs[0].u.data = metric;
1012
1013
  l->attrs[1].id = EA_RIP_TAG;
1014 91c7c741 Pavel Machek
  l->attrs[1].flags = 0;
1015 9f4929e7 Martin Mares
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
1016 8465dccb Ondrej Zajicek (work)
  l->attrs[1].u.data = tag;
1017
1018 91c7c741 Pavel Machek
  return l;
1019
}
1020
1021
static int
1022 3e236955 Jan Moskyto Matejka
rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
1023 91c7c741 Pavel Machek
{
1024 8465dccb Ondrej Zajicek (work)
  /* Prepare attributes with initial values */
1025
  if ((*rt)->attrs->source != RTS_RIP)
1026
    *attrs = rip_prepare_attrs(pool, *attrs, 1, 0);
1027 91c7c741 Pavel Machek
1028
  return 0;
1029
}
1030
1031 f4a60a9b Ondrej Zajicek (work)
static void
1032
rip_reload_routes(struct channel *C)
1033 8465dccb Ondrej Zajicek (work)
{
1034 f4a60a9b Ondrej Zajicek (work)
  struct rip_proto *p = (struct rip_proto *) C->proto;
1035 8465dccb Ondrej Zajicek (work)
1036
  if (p->rt_reload)
1037 f4a60a9b Ondrej Zajicek (work)
    return;
1038 8465dccb Ondrej Zajicek (work)
1039
  TRACE(D_EVENTS, "Scheduling route reload");
1040
  p->rt_reload = 1;
1041
  rip_kick_timer(p);
1042
}
1043
1044 91c7c741 Pavel Machek
static struct ea_list *
1045
rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
1046
{
1047 8465dccb Ondrej Zajicek (work)
  return rip_prepare_attrs(pool, NULL, rt->u.rip.metric, rt->u.rip.tag);
1048 91c7c741 Pavel Machek
}
1049
1050 8465dccb Ondrej Zajicek (work)
static void
1051 91c7c741 Pavel Machek
rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
1052
{
1053 4bfe4e85 Pavel Machek
  rt->u.rip.metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
1054 8465dccb Ondrej Zajicek (work)
  rt->u.rip.tag = ea_get_int(attrs, EA_RIP_TAG, 0);
1055 91c7c741 Pavel Machek
}
1056
1057 8465dccb Ondrej Zajicek (work)
static int
1058
rip_rte_better(struct rte *new, struct rte *old)
1059 1d941de4 Pavel Machek
{
1060 8465dccb Ondrej Zajicek (work)
  return new->u.rip.metric < old->u.rip.metric;
1061 1d941de4 Pavel Machek
}
1062
1063 feb6abe0 Pavel Machek
static int
1064 16c2d48d Ondrej Filip
rip_rte_same(struct rte *new, struct rte *old)
1065
{
1066 8465dccb Ondrej Zajicek (work)
  return ((new->u.rip.metric == old->u.rip.metric) &&
1067
          (new->u.rip.tag == old->u.rip.tag) &&
1068
          (new->u.rip.from == old->u.rip.from));
1069 16c2d48d Ondrej Filip
}
1070
1071
1072 f4a60a9b Ondrej Zajicek (work)
static void
1073
rip_postconfig(struct proto_config *CF)
1074
{
1075
  // struct rip_config *cf = (void *) CF;
1076
1077
  /* Define default channel */
1078
  if (EMPTY_LIST(CF->channels))
1079
    channel_config_new(NULL, CF->net_type, CF);
1080
}
1081
1082 8465dccb Ondrej Zajicek (work)
static struct proto *
1083 f4a60a9b Ondrej Zajicek (work)
rip_init(struct proto_config *CF)
1084 8465dccb Ondrej Zajicek (work)
{
1085 f4a60a9b Ondrej Zajicek (work)
  struct proto *P = proto_new(CF);
1086
1087
  P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
1088 8465dccb Ondrej Zajicek (work)
1089
  P->if_notify = rip_if_notify;
1090
  P->rt_notify = rip_rt_notify;
1091
  P->neigh_notify = rip_neigh_notify;
1092
  P->import_control = rip_import_control;
1093
  P->reload_routes = rip_reload_routes;
1094
  P->make_tmp_attrs = rip_make_tmp_attrs;
1095
  P->store_tmp_attrs = rip_store_tmp_attrs;
1096
  P->rte_better = rip_rte_better;
1097
  P->rte_same = rip_rte_same;
1098
1099
  return P;
1100
}
1101
1102 16c2d48d Ondrej Filip
static int
1103 8465dccb Ondrej Zajicek (work)
rip_start(struct proto *P)
1104 21580e30 Pavel Machek
{
1105 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (void *) P;
1106
  struct rip_config *cf = (void *) (P->cf);
1107 8d2e3eba Pavel Machek
1108 8465dccb Ondrej Zajicek (work)
  init_list(&p->iface_list);
1109 23c212e7 Ondrej Zajicek (work)
  fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6,
1110 fe9f1a6d Ondrej Zajicek (work)
           sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL);
1111 8465dccb Ondrej Zajicek (work)
  p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
1112
  p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
1113 3918b1b0 Pavel Machek
1114 23c212e7 Ondrej Zajicek (work)
  p->rip2 = cf->rip2;
1115 8465dccb Ondrej Zajicek (work)
  p->ecmp = cf->ecmp;
1116
  p->infinity = cf->infinity;
1117
  p->triggered = 0;
1118 21580e30 Pavel Machek
1119 8465dccb Ondrej Zajicek (work)
  p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
1120
  p->log_rte_tbf = (struct tbf){ .rate = 4, .burst = 20 };
1121 21580e30 Pavel Machek
1122 8465dccb Ondrej Zajicek (work)
  tm_start(p->timer, MIN(cf->min_timeout_time, cf->max_garbage_time));
1123 21580e30 Pavel Machek
1124 8465dccb Ondrej Zajicek (work)
  return PS_UP;
1125 21580e30 Pavel Machek
}
1126
1127 8465dccb Ondrej Zajicek (work)
static int
1128 f4a60a9b Ondrej Zajicek (work)
rip_reconfigure(struct proto *P, struct proto_config *CF)
1129 feb6abe0 Pavel Machek
{
1130 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (void *) P;
1131 f4a60a9b Ondrej Zajicek (work)
  struct rip_config *new = (void *) CF;
1132 8465dccb Ondrej Zajicek (work)
  // struct rip_config *old = (void *) (P->cf);
1133 feb6abe0 Pavel Machek
1134 23c212e7 Ondrej Zajicek (work)
  if (new->rip2 != p->rip2)
1135
    return 0;
1136
1137 8465dccb Ondrej Zajicek (work)
  if (new->infinity != p->infinity)
1138
    return 0;
1139 feb6abe0 Pavel Machek
1140 f4a60a9b Ondrej Zajicek (work)
  if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
1141
    return 0;
1142
1143 8465dccb Ondrej Zajicek (work)
  TRACE(D_EVENTS, "Reconfiguring");
1144
1145 f4a60a9b Ondrej Zajicek (work)
  p->p.cf = CF;
1146 8465dccb Ondrej Zajicek (work)
  p->ecmp = new->ecmp;
1147
  rip_reconfigure_ifaces(p, new);
1148
1149
  p->rt_reload = 1;
1150
  rip_kick_timer(p);
1151
1152
  return 1;
1153 c748cdb9 Pavel Machek
}
1154 2d9290e9 Pavel Machek
1155 8465dccb Ondrej Zajicek (work)
static void
1156 3e236955 Jan Moskyto Matejka
rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED)
1157 c748cdb9 Pavel Machek
{
1158 8465dccb Ondrej Zajicek (work)
  buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
1159
1160
  if (rte->u.rip.tag)
1161
    bsprintf(buf, " [%04x]", rte->u.rip.tag);
1162 a103373f Pavel Machek
}
1163
1164 a769a180 Pavel Machek
static int
1165 aebe06b4 Ondrej Zajicek
rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
1166 a769a180 Pavel Machek
{
1167 8465dccb Ondrej Zajicek (work)
  switch (a->id)
1168
  {
1169
  case EA_RIP_METRIC:
1170
    bsprintf(buf, "metric: %d", a->u.data);
1171
    return GA_FULL;
1172
1173
  case EA_RIP_TAG:
1174
    bsprintf(buf, "tag: %04x", a->u.data);
1175
    return GA_FULL;
1176
1177
  default:
1178
    return GA_UNKNOWN;
1179 a769a180 Pavel Machek
  }
1180
}
1181
1182 8465dccb Ondrej Zajicek (work)
void
1183
rip_show_interfaces(struct proto *P, char *iff)
1184 898fdd85 Pavel Machek
{
1185 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (void *) P;
1186
  struct rip_iface *ifa = NULL;
1187
  struct rip_neighbor *n = NULL;
1188
1189
  if (p->p.proto_state != PS_UP)
1190
  {
1191
    cli_msg(-1021, "%s: is not up", p->p.name);
1192
    cli_msg(0, "");
1193
    return;
1194
  }
1195
1196
  cli_msg(-1021, "%s:", p->p.name);
1197
  cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
1198
          "Interface", "State", "Metric", "Nbrs", "Timer");
1199
1200
  WALK_LIST(ifa, p->iface_list)
1201
  {
1202
    if (iff && !patmatch(iff, ifa->iface->name))
1203
      continue;
1204
1205
    int nbrs = 0;
1206
    WALK_LIST(n, ifa->neigh_list)
1207
      if (n->last_seen)
1208
        nbrs++;
1209
1210
    int timer = MAX(ifa->next_regular - now, 0);
1211
    cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
1212
            ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
1213
  }
1214
1215
  cli_msg(0, "");
1216 898fdd85 Pavel Machek
}
1217
1218 8465dccb Ondrej Zajicek (work)
void
1219
rip_show_neighbors(struct proto *P, char *iff)
1220 7f5f44bb Pavel Machek
{
1221 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (void *) P;
1222
  struct rip_iface *ifa = NULL;
1223
  struct rip_neighbor *n = NULL;
1224 7f5f44bb Pavel Machek
1225 8465dccb Ondrej Zajicek (work)
  if (p->p.proto_state != PS_UP)
1226
  {
1227
    cli_msg(-1022, "%s: is not up", p->p.name);
1228
    cli_msg(0, "");
1229
    return;
1230
  }
1231
1232
  cli_msg(-1022, "%s:", p->p.name);
1233
  cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
1234
          "IP address", "Interface", "Metric", "Routes", "Seen");
1235
1236
  WALK_LIST(ifa, p->iface_list)
1237
  {
1238
    if (iff && !patmatch(iff, ifa->iface->name))
1239
      continue;
1240
1241
    WALK_LIST(n, ifa->neigh_list)
1242
    {
1243
      if (!n->last_seen)
1244
        continue;
1245
1246
      int timer = now - n->last_seen;
1247
      cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
1248
              n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
1249
    }
1250
  }
1251
1252
  cli_msg(0, "");
1253 7f5f44bb Pavel Machek
}
1254
1255 a7f23f58 Ondrej Zajicek
static void
1256 8465dccb Ondrej Zajicek (work)
rip_dump(struct proto *P)
1257 a7f23f58 Ondrej Zajicek
{
1258 8465dccb Ondrej Zajicek (work)
  struct rip_proto *p = (struct rip_proto *) P;
1259
  struct rip_iface *ifa;
1260
  int i;
1261 a7f23f58 Ondrej Zajicek
1262 8465dccb Ondrej Zajicek (work)
  i = 0;
1263 600998fc Ondrej Zajicek (work)
  FIB_WALK(&p->rtable, struct rip_entry, en)
1264 8465dccb Ondrej Zajicek (work)
  {
1265 fe9f1a6d Ondrej Zajicek (work)
    debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %d s\n",
1266
          i++, en->n.addr, en->next_hop, en->iface->name,
1267 8465dccb Ondrej Zajicek (work)
          en->valid, en->metric, now - en->changed);
1268
  }
1269
  FIB_WALK_END;
1270 a7f23f58 Ondrej Zajicek
1271 8465dccb Ondrej Zajicek (work)
  i = 0;
1272
  WALK_LIST(ifa, p->iface_list)
1273
  {
1274
    debug("RIP: interface #%d: %s, %I, up = %d, busy = %d\n",
1275
          i++, ifa->iface->name, ifa->sk ? ifa->sk->daddr : IPA_NONE,
1276
          ifa->up, ifa->tx_active);
1277
  }
1278 a7f23f58 Ondrej Zajicek
}
1279
1280
1281 a103373f Pavel Machek
struct protocol proto_rip = {
1282 4a591d4b Pavel Tvrdik
  .name =                "RIP",
1283
  .template =                "rip%d",
1284
  .attr_class =                EAP_RIP,
1285
  .preference =                DEF_PREF_RIP,
1286 f4a60a9b Ondrej Zajicek (work)
  .channel_mask =        NB_IP,
1287
  .proto_size =                sizeof(struct rip_proto),
1288 8465dccb Ondrej Zajicek (work)
  .config_size =        sizeof(struct rip_config),
1289 f4a60a9b Ondrej Zajicek (work)
  .postconfig =                rip_postconfig,
1290 4a591d4b Pavel Tvrdik
  .init =                rip_init,
1291
  .dump =                rip_dump,
1292
  .start =                rip_start,
1293
  .reconfigure =        rip_reconfigure,
1294 2bbc3083 Ondrej Zajicek
  .get_route_info =        rip_get_route_info,
1295
  .get_attr =                rip_get_attr
1296 a103373f Pavel Machek
};