rip.c 32 KB
Newer Older
1
/*
Ondřej Zajíček's avatar
Ondřej Zajíček committed
2
 *	BIRD -- Routing Information Protocol (RIP)
3
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
4 5 6 7
 *	(c) 1998--1999 Pavel Machek <pavel@ucw.cz>
 *	(c) 2004--2013 Ondrej Filip <feela@network.cz>
 *	(c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2009--2015 CZ.NIC z.s.p.o.
8 9 10 11
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

12
/**
Ondřej Zajíček's avatar
Ondřej Zajíček committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 * DOC: Routing Information Protocol (RIP)
 *
 * The RIP protocol is implemented in two files: |rip.c| containing the protocol
 * logic, route management and the protocol glue with BIRD core, and |packets.c|
 * handling RIP packet processing, RX, TX and protocol sockets.
 *
 * Each instance of RIP is described by a structure &rip_proto, which contains
 * an internal RIP routing table, a list of protocol interfaces and the main
 * timer responsible for RIP routing table cleanup.
 *
 * RIP internal routing table contains incoming and outgoing routes. For each
 * network (represented by structure &rip_entry) there is one outgoing route
 * stored directly in &rip_entry and an one-way linked list of incoming routes
 * (structures &rip_rte). The list contains incoming routes from different RIP
 * neighbors, but only routes with the lowest metric are stored (i.e., all
 * stored incoming routes have the same metric).
 *
 * Note that RIP itself does not select outgoing route, that is done by the core
 * routing table. When a new incoming route is received, it is propagated to the
 * RIP table by rip_update_rte() and possibly stored in the list of incoming
 * routes. Then the change may be propagated to the core by rip_announce_rte().
 * The core selects the best route and propagate it to RIP by rip_rt_notify(),
 * which updates outgoing route part of &rip_entry and possibly triggers route
 * propagation by rip_trigger_update().
37
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
38 39 40 41 42
 * RIP interfaces are represented by structures &rip_iface. A RIP interface
 * contains a per-interface socket, a list of associated neighbors, interface
 * configuration, and state information related to scheduled interface events
 * and running update sessions. RIP interfaces are added and removed based on
 * core interface notifications.
43
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
44 45 46 47 48 49 50 51 52 53
 * There are two RIP interface events - regular updates and triggered updates.
 * Both are managed from the RIP interface timer (rip_iface_timer()). Regular
 * updates are called at fixed interval and propagate the whole routing table,
 * while triggered updates are scheduled by rip_trigger_update() due to some
 * routing table change and propagate only the routes modified since the time
 * they were scheduled. There are also unicast-destined requested updates, but
 * these are sent directly as a reaction to received RIP request message. The
 * update session is started by rip_send_table(). There may be at most one
 * active update session per interface, as the associated state (including the
 * fib iterator) is stored directly in &rip_iface structure.
Martin Mareš's avatar
Martin Mareš committed
54
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
55 56 57 58 59 60 61
 * RIP neighbors are represented by structures &rip_neighbor. Compared to
 * neighbor handling in other routing protocols, RIP does not have explicit
 * neighbor discovery and adjacency maintenance, which makes the &rip_neighbor
 * related code a bit peculiar. RIP neighbors are interlinked with core neighbor
 * structures (&neighbor) and use core neighbor notifications to ensure that RIP
 * neighbors are timely removed. RIP neighbors are added based on received route
 * notifications and removed based on core neighbor and RIP interface events.
62
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
63 64 65 66 67 68 69
 * RIP neighbors are linked by RIP routes and use counter to track the number of
 * associated routes, but when these RIP routes timeout, associated RIP neighbor
 * is still alive (with zero counter). When RIP neighbor is removed but still
 * has some associated routes, it is not freed, just changed to detached state
 * (core neighbors and RIP ifaces are unlinked), then during the main timer
 * cleanup phase the associated routes are removed and the &rip_neighbor
 * structure is finally freed.
70
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
71 72 73 74 75
 * Supported standards:
 * - RFC 1058 - RIPv1
 * - RFC 2453 - RIPv2
 * - RFC 2080 - RIPng
 * - RFC 4822 - RIP cryptographic authentication
76 77
 */

Ondřej Zajíček's avatar
Ondřej Zajíček committed
78
#include <stdlib.h>
79 80
#include "rip.h"

81

Ondřej Zajíček's avatar
Ondřej Zajíček committed
82 83 84 85 86 87 88
static inline void rip_lock_neighbor(struct rip_neighbor *n);
static inline void rip_unlock_neighbor(struct rip_neighbor *n);
static inline int rip_iface_link_up(struct rip_iface *ifa);
static inline void rip_kick_timer(struct rip_proto *p);
static inline void rip_iface_kick_timer(struct rip_iface *ifa);
static void rip_iface_timer(timer *timer);
static void rip_trigger_update(struct rip_proto *p);
89

90

91
/*
Ondřej Zajíček's avatar
Ondřej Zajíček committed
92
 *	RIP routes
93 94
 */

Ondřej Zajíček's avatar
Ondřej Zajíček committed
95 96
static struct rip_rte *
rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src)
97
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
98
  struct rip_rte *rt = sl_alloc(p->rte_slab);
99

Ondřej Zajíček's avatar
Ondřej Zajíček committed
100 101 102
  memcpy(rt, src, sizeof(struct rip_rte));
  rt->next = *rp;
  *rp = rt;
Pavel Machek's avatar
Pavel Machek committed
103

Ondřej Zajíček's avatar
Ondřej Zajíček committed
104
  rip_lock_neighbor(rt->from);
105

Ondřej Zajíček's avatar
Ondřej Zajíček committed
106
  return rt;
107 108
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static inline void
rip_remove_rte(struct rip_proto *p, struct rip_rte **rp)
{
  struct rip_rte *rt = *rp;

  rip_unlock_neighbor(rt->from);

  *rp = rt->next;
  sl_free(p->rte_slab, rt);
}

static inline int rip_same_rte(struct rip_rte *a, struct rip_rte *b)
{ return a->metric == b->metric && a->tag == b->tag && ipa_equal(a->next_hop, b->next_hop); }

static inline int rip_valid_rte(struct rip_rte *rt)
{ return rt->from->ifa != NULL; }

/**
 * rip_announce_rte - announce route from RIP routing table to the core
 * @p: RIP instance
 * @en: related network
 *
 * The function takes a list of incoming routes from @en, prepare appropriate
 * &rte for the core and propagate it by rte_update().
133
 */
134
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
135
rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
136
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
137 138 139 140 141 142 143 144 145 146 147 148 149
  struct rip_rte *rt = en->routes;

  /* Find first valid rte */
  while (rt && !rip_valid_rte(rt))
    rt = rt->next;

  if (rt)
  {
    /* Update */
    rta a0 = {
      .src = p->p.main_source,
      .source = RTS_RIP,
      .scope = SCOPE_UNIVERSE,
Ondřej Zajíček's avatar
Ondřej Zajíček committed
150
      .dest = RTD_UNICAST,
Ondřej Zajíček's avatar
Ondřej Zajíček committed
151
    };
152

Ondřej Zajíček's avatar
Ondřej Zajíček committed
153 154 155
    u8 rt_metric = rt->metric;
    u16 rt_tag = rt->tag;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
156
    if (p->ecmp)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
157 158
    {
      /* ECMP route */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
159
      struct nexthop *nhs = NULL;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
160
      int num = 0;
161

Ondřej Zajíček's avatar
Ondřej Zajíček committed
162 163 164 165 166
      for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
      {
	if (!rip_valid_rte(rt))
	    continue;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
167
	struct nexthop *nh = allocz(sizeof(struct nexthop));
168

Ondřej Zajíček's avatar
Ondřej Zajíček committed
169 170 171
	nh->gw = rt->next_hop;
	nh->iface = rt->from->nbr->iface;
	nh->weight = rt->from->ifa->cf->ecmp_weight;
172

Ondřej Zajíček's avatar
Ondřej Zajíček committed
173
	nexthop_insert(&nhs, nh);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
174 175 176 177 178
	num++;

	if (rt->tag != rt_tag)
	  rt_tag = 0;
      }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
179 180

      a0.nh = *nhs;
181
    }
182
    else
Ondřej Zajíček's avatar
Ondřej Zajíček committed
183 184
    {
      /* Unipath route */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
185
      a0.from = rt->from->nbr->addr;
186 187
      a0.nh.gw = rt->next_hop;
      a0.nh.iface = rt->from->nbr->iface;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
188
    }
189

Ondřej Zajíček's avatar
Ondřej Zajíček committed
190 191
    rta *a = rta_lookup(&a0);
    rte *e = rte_get_temp(a);
192

193
    e->u.rip.from = a0.nh.iface;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
194 195 196 197 198
    e->u.rip.metric = rt_metric;
    e->u.rip.tag = rt_tag;

    e->pflags = 0;

199
    rte_update(&p->p, en->n.addr, e);
200
  }
201
  else
Ondřej Zajíček's avatar
Ondřej Zajíček committed
202 203
  {
    /* Withdraw */
204
    rte_update(&p->p, en->n.addr, NULL);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
205
  }
206 207
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
208 209 210
/**
 * rip_update_rte - enter a route update to RIP routing table
 * @p: RIP instance
211
 * @addr: network address
Ondřej Zajíček's avatar
Ondřej Zajíček committed
212 213 214 215 216 217 218 219 220
 * @new: a &rip_rte representing the new route
 *
 * The function is called by the RIP packet processing code whenever it receives
 * a reachable route. The appropriate routing table entry is found and the list
 * of incoming routes is updated. Eventually, the change is also propagated to
 * the core by rip_announce_rte(). Note that for unreachable routes,
 * rip_withdraw_rte() should be called instead of rip_update_rte().
 */
void
221
rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new)
222
{
223
  struct rip_entry *en = fib_get(&p->rtable, n);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
  struct rip_rte *rt, **rp;
  int changed = 0;

  /* If the new route is better, remove all current routes */
  if (en->routes && new->metric < en->routes->metric)
    while (en->routes)
      rip_remove_rte(p, &en->routes);

  /* Find the old route (also set rp for later) */
  for (rp = &en->routes; rt = *rp; rp = &rt->next)
    if (rt->from == new->from)
    {
      if (rip_same_rte(rt, new))
      {
	rt->expires = new->expires;
	return;
      }
Pavel Machek's avatar
Pavel Machek committed
241

Ondřej Zajíček's avatar
Ondřej Zajíček committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
      /* Remove the old route */
      rip_remove_rte(p, rp);
      changed = 1;
      break;
    }

  /* If the new route is optimal, add it to the list */
  if (!en->routes || new->metric == en->routes->metric)
  {
    rt = rip_add_rte(p, rp, new);
    changed = 1;
  }

  /* Announce change if on relevant position (the first or any for ECMP) */
  if (changed && (rp == &en->routes || p->ecmp))
    rip_announce_rte(p, en);
258 259
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
260 261 262
/**
 * rip_withdraw_rte - enter a route withdraw to RIP routing table
 * @p: RIP instance
263
 * @addr: network address
Ondřej Zajíček's avatar
Ondřej Zajíček committed
264
 * @from: a &rip_neighbor propagating the withdraw
265
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
266 267 268
 * The function is called by the RIP packet processing code whenever it receives
 * an unreachable route. The incoming route for given network from nbr @from is
 * removed. Eventually, the change is also propagated by rip_announce_rte().
269
 */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
270
void
271
rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
272
{
273
  struct rip_entry *en = fib_find(&p->rtable, n);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
274
  struct rip_rte *rt, **rp;
275

Ondřej Zajíček's avatar
Ondřej Zajíček committed
276 277
  if (!en)
    return;
278

Ondřej Zajíček's avatar
Ondřej Zajíček committed
279 280 281 282
  /* Find the old route */
  for (rp = &en->routes; rt = *rp; rp = &rt->next)
    if (rt->from == from)
      break;
283

Ondřej Zajíček's avatar
Ondřej Zajíček committed
284 285 286 287 288 289 290 291 292
  if (!rt)
    return;

  /* Remove the old route */
  rip_remove_rte(p, rp);

  /* Announce change if on relevant position */
  if (rp == &en->routes || p->ecmp)
    rip_announce_rte(p, en);
293 294
}

295
/*
Ondřej Zajíček's avatar
Ondřej Zajíček committed
296 297
 * rip_rt_notify - core tells us about new route, so store
 * it into our data structures.
298
 */
299
static void
300
rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
Ondřej Zajíček's avatar
Ondřej Zajíček committed
301
	      struct rte *old UNUSED, struct ea_list *attrs)
302
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
303 304 305 306 307 308 309 310 311 312 313 314
  struct rip_proto *p = (struct rip_proto *) P;
  struct rip_entry *en;
  int old_metric;

  if (new)
  {
    /* Update */
    u32 rt_metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
    u32 rt_tag = ea_get_int(attrs, EA_RIP_TAG, 0);

    if (rt_metric > p->infinity)
    {
315 316
      log(L_WARN "%s: Invalid rip_metric value %u for route %N",
	  p->p.name, rt_metric, net->n.addr);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
317 318 319 320 321
      rt_metric = p->infinity;
    }

    if (rt_tag > 0xffff)
    {
322 323
      log(L_WARN "%s: Invalid rip_tag value %u for route %N",
	  p->p.name, rt_tag, net->n.addr);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
324 325 326 327 328 329 330 331 332 333 334
      rt_metric = p->infinity;
      rt_tag = 0;
    }

    /*
     * Note that we accept exported routes with infinity metric (this could
     * happen if rip_metric is modified in filters). Such entry has infinity
     * metric but is RIP_ENTRY_VALID and therefore is not subject to garbage
     * collection.
     */

335
    en = fib_get(&p->rtable, net->n.addr);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
336 337 338 339 340 341 342

    old_metric = en->valid ? en->metric : -1;

    en->valid = RIP_ENTRY_VALID;
    en->metric = rt_metric;
    en->tag = rt_tag;
    en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
343 344
    en->iface = new->attrs->nh.iface;
    en->next_hop = new->attrs->nh.gw;
345
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
346 347 348
  else
  {
    /* Withdraw */
349
    en = fib_find(&p->rtable, net->n.addr);
350

Ondřej Zajíček's avatar
Ondřej Zajíček committed
351 352 353 354 355 356 357 358 359 360 361
    if (!en || en->valid != RIP_ENTRY_VALID)
      return;

    old_metric = en->metric;

    en->valid = RIP_ENTRY_STALE;
    en->metric = p->infinity;
    en->tag = 0;
    en->from = NULL;
    en->iface = NULL;
    en->next_hop = IPA_NONE;
Pavel Machek's avatar
Pavel Machek committed
362
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
363 364 365 366

  /* Activate triggered updates */
  if (en->metric != old_metric)
  {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
367
    en->changed = current_time();
Ondřej Zajíček's avatar
Ondřej Zajíček committed
368
    rip_trigger_update(p);
369
  }
370
}
371

Ondřej Zajíček's avatar
Ondřej Zajíček committed
372

373
/*
Ondřej Zajíček's avatar
Ondřej Zajíček committed
374
 *	RIP neighbors
375
 */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400

struct rip_neighbor *
rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa)
{
  neighbor *nbr = neigh_find2(&p->p, a, ifa->iface, 0);

  if (!nbr || (nbr->scope == SCOPE_HOST) || !rip_iface_link_up(ifa))
    return NULL;

  if (nbr->data)
    return nbr->data;

  TRACE(D_EVENTS, "New neighbor %I on %s", *a, ifa->iface->name);

  struct rip_neighbor *n = mb_allocz(p->p.pool, sizeof(struct rip_neighbor));
  n->ifa = ifa;
  n->nbr = nbr;
  nbr->data = n;
  n->csn = nbr->aux;

  add_tail(&ifa->neigh_list, NODE n);

  return n;
}

401
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
402
rip_remove_neighbor(struct rip_proto *p, struct rip_neighbor *n)
403
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
404 405 406
  neighbor *nbr = n->nbr;

  TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->iface->name);
407

Ondřej Zajíček's avatar
Ondřej Zajíček committed
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
  rem_node(NODE n);
  n->ifa = NULL;
  n->nbr = NULL;
  nbr->data = NULL;
  nbr->aux = n->csn;

  rfree(n->bfd_req);
  n->bfd_req = NULL;
  n->last_seen = 0;

  if (!n->uc)
    mb_free(n);

  /* Related routes are removed in rip_timer() */
  rip_kick_timer(p);
423 424
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
425 426 427 428 429
static inline void
rip_lock_neighbor(struct rip_neighbor *n)
{
  n->uc++;
}
430

Ondřej Zajíček's avatar
Ondřej Zajíček committed
431 432
static inline void
rip_unlock_neighbor(struct rip_neighbor *n)
433
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
  n->uc--;

  if (!n->nbr && !n->uc)
    mb_free(n);
}

static void
rip_neigh_notify(struct neighbor *nbr)
{
  struct rip_proto *p = (struct rip_proto *) nbr->proto;
  struct rip_neighbor *n = nbr->data;

  if (!n)
    return;

  /*
   * We assume that rip_neigh_notify() is called before rip_if_notify() for
   * IF_CHANGE_DOWN and therefore n->ifa is still valid. We have no such
   * ordering assumption for IF_CHANGE_LINK, so we test link state of the
   * underlying iface instead of just rip_iface state.
   */
  if ((nbr->scope <= 0) || !rip_iface_link_up(n->ifa))
    rip_remove_neighbor(p, n);
}

static void
rip_bfd_notify(struct bfd_request *req)
{
  struct rip_neighbor *n = req->data;
  struct rip_proto *p = n->ifa->rip;
464

Ondřej Zajíček's avatar
Ondřej Zajíček committed
465 466 467 468 469
  if (req->down)
  {
    TRACE(D_EVENTS, "BFD session down for nbr %I on %s",
	  n->nbr->addr, n->ifa->iface->name);
    rip_remove_neighbor(p, n);
470
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
471 472 473 474 475 476
}

void
rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
{
  int use_bfd = n->ifa->cf->bfd && n->last_seen;
477

Ondřej Zajíček's avatar
Ondřej Zajíček committed
478 479 480 481 482 483 484 485 486 487
  if (use_bfd && !n->bfd_req)
  {
    /*
     * For RIPv2, use the same address as rip_open_socket(). For RIPng, neighbor
     * should contain an address from the same prefix, thus also link-local. It
     * may cause problems if two link-local addresses are assigned to one iface.
     */
    ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
    n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
				     n->nbr->iface, rip_bfd_notify, n);
488 489
  }

Ondřej Zajíček's avatar
Ondřej Zajíček committed
490 491 492 493 494
  if (!use_bfd && n->bfd_req)
  {
    rfree(n->bfd_req);
    n->bfd_req = NULL;
  }
495 496
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
497

498
/*
Ondřej Zajíček's avatar
Ondřej Zajíček committed
499
 *	RIP interfaces
500
 */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
501 502 503

static void
rip_iface_start(struct rip_iface *ifa)
504
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
505
  struct rip_proto *p = ifa->rip;
506

Ondřej Zajíček's avatar
Ondřej Zajíček committed
507
  TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
508

Ondřej Zajíček's avatar
Ondřej Zajíček committed
509 510 511
  ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
  ifa->next_triggered = current_time();	/* Available immediately */
  ifa->want_triggered = 1;		/* All routes in triggered update */
512
  tm_start(ifa->timer, 100 MS);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
513
  ifa->up = 1;
514

Ondřej Zajíček's avatar
Ondřej Zajíček committed
515 516 517
  if (!ifa->cf->passive)
    rip_send_request(ifa->rip, ifa);
}
518

Ondřej Zajíček's avatar
Ondřej Zajíček committed
519 520 521 522 523
static void
rip_iface_stop(struct rip_iface *ifa)
{
  struct rip_proto *p = ifa->rip;
  struct rip_neighbor *n;
524

Ondřej Zajíček's avatar
Ondřej Zajíček committed
525
  TRACE(D_EVENTS, "Stopping interface %s", ifa->iface->name);
526

Ondřej Zajíček's avatar
Ondřej Zajíček committed
527
  rip_reset_tx_session(p, ifa);
528

Ondřej Zajíček's avatar
Ondřej Zajíček committed
529 530
  WALK_LIST_FIRST(n, ifa->neigh_list)
    rip_remove_neighbor(p, n);
Pavel Machek's avatar
Pavel Machek committed
531

532
  tm_stop(ifa->timer);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
533
  ifa->up = 0;
534 535
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
536 537 538 539 540
static inline int
rip_iface_link_up(struct rip_iface *ifa)
{
  return !ifa->cf->check_link || (ifa->iface->flags & IF_LINK_UP);
}
541

542
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
543
rip_iface_update_state(struct rip_iface *ifa)
544
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
545
  int up = ifa->sk && rip_iface_link_up(ifa);
546

Ondřej Zajíček's avatar
Ondřej Zajíček committed
547 548 549 550 551 552 553 554
  if (up == ifa->up)
    return;

  if (up)
    rip_iface_start(ifa);
  else
    rip_iface_stop(ifa);
}
555

556
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
557
rip_iface_update_buffers(struct rip_iface *ifa)
558
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
559 560
  if (!ifa->sk)
    return;
561

Ondřej Zajíček's avatar
Ondřej Zajíček committed
562 563 564
  uint rbsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
  uint tbsize = ifa->cf->tx_length ?: ifa->iface->mtu;
  rbsize = MAX(rbsize, tbsize);
Ondřej Filip's avatar
Ondřej Filip committed
565

Ondřej Zajíček's avatar
Ondřej Zajíček committed
566 567
  sk_set_rbsize(ifa->sk, rbsize);
  sk_set_tbsize(ifa->sk, tbsize);
Ondřej Filip's avatar
Ondřej Filip committed
568

Ondřej Zajíček's avatar
Ondřej Zajíček committed
569 570
  uint headers = (rip_is_v2(ifa->rip) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH) + UDP_HEADER_LENGTH;
  ifa->tx_plen = tbsize - headers;
571

Ondřej Zajíček's avatar
Ondřej Zajíček committed
572
  if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
573
    ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
574
}
575

Ondřej Zajíček's avatar
Ondřej Zajíček committed
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
static inline void
rip_iface_update_bfd(struct rip_iface *ifa)
{
  struct rip_proto *p = ifa->rip;
  struct rip_neighbor *n;

  WALK_LIST(n, ifa->neigh_list)
    rip_update_bfd(p, n);
}


static void
rip_iface_locked(struct object_lock *lock)
{
  struct rip_iface *ifa = lock->data;
  struct rip_proto *p = ifa->rip;
592

Ondřej Zajíček's avatar
Ondřej Zajíček committed
593
  if (!rip_open_socket(ifa))
594
  {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
595 596 597
    log(L_ERR "%s: Cannot open socket for %s", p->p.name, ifa->iface->name);
    return;
  }
Ondřej Filip's avatar
Ondřej Filip committed
598

Ondřej Zajíček's avatar
Ondřej Zajíček committed
599 600 601
  rip_iface_update_buffers(ifa);
  rip_iface_update_state(ifa);
}
Ondřej Filip's avatar
Ondřej Filip committed
602

603

Ondřej Zajíček's avatar
Ondřej Zajíček committed
604 605 606 607
static struct rip_iface *
rip_find_iface(struct rip_proto *p, struct iface *what)
{
  struct rip_iface *ifa;
608

Ondřej Zajíček's avatar
Ondřej Zajíček committed
609 610 611
  WALK_LIST(ifa, p->iface_list)
    if (ifa->iface == what)
      return ifa;
612

Ondřej Zajíček's avatar
Ondřej Zajíček committed
613
  return NULL;
614 615
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
616 617
static void
rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config *ic)
618
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632
  struct rip_iface *ifa;

  TRACE(D_EVENTS, "Adding interface %s", iface->name);

  ifa = mb_allocz(p->p.pool, sizeof(struct rip_iface));
  ifa->rip = p;
  ifa->iface = iface;
  ifa->cf = ic;

  if (ipa_nonzero(ic->address))
    ifa->addr = ic->address;
  else if (ic->mode == RIP_IM_MULTICAST)
    ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
  else /* Broadcast */
633 634 635 636 637 638 639
    ifa->addr = iface->addr4->brd;
  /*
   * The above is just a workaround for BSD as it can't send broadcasts
   * to 255.255.255.255. BSD systems need the network broadcast address instead.
   *
   * TODO: move this to sysdep code
   */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
640 641 642 643 644

  init_list(&ifa->neigh_list);

  add_tail(&p->iface_list, NODE ifa);

645
  ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
646 647 648 649 650 651 652 653 654 655

  struct object_lock *lock = olock_new(p->p.pool);
  lock->type = OBJLOCK_UDP;
  lock->port = ic->port;
  lock->iface = iface;
  lock->data = ifa;
  lock->hook = rip_iface_locked;
  ifa->lock = lock;

  olock_acquire(lock);
656 657 658
}

static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
659
rip_remove_iface(struct rip_proto *p, struct rip_iface *ifa)
660
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
661
  rip_iface_stop(ifa);
662

Ondřej Zajíček's avatar
Ondřej Zajíček committed
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
  TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);

  rem_node(NODE ifa);

  rfree(ifa->sk);
  rfree(ifa->lock);
  rfree(ifa->timer);

  mb_free(ifa);
}

static int
rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_iface_config *new)
{
  struct rip_iface_config *old = ifa->cf;

  /* Change of these options would require to reset the iface socket */
  if ((new->mode != old->mode) ||
      (new->port != old->port) ||
      (new->tx_tos != old->tx_tos) ||
      (new->tx_priority != old->tx_priority) ||
      (new->ttl_security != old->ttl_security))
    return 0;

  TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);

  ifa->cf = new;

691 692
  rip_iface_update_buffers(ifa);

Ondřej Zajíček's avatar
Ondřej Zajíček committed
693 694
  if (ifa->next_regular > (current_time() + new->update_time))
    ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
695 696 697 698 699 700 701 702 703 704 705

  if (new->check_link != old->check_link)
    rip_iface_update_state(ifa);

  if (new->bfd != old->bfd)
    rip_iface_update_bfd(ifa);

  if (ifa->up)
    rip_iface_kick_timer(ifa);

  return 1;
706 707
}

Pavel Machek's avatar
Pavel Machek committed
708
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
709
rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
Pavel Machek's avatar
Pavel Machek committed
710
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
711 712 713 714
  struct iface *iface;

  WALK_LIST(iface, iface_list)
  {
715 716 717 718 719
    if (!(iface->flags & IF_UP))
      continue;

    /* Ignore ifaces without appropriate address */
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
720 721 722 723
      continue;

    struct rip_iface *ifa = rip_find_iface(p, iface);
    struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
724

Ondřej Zajíček's avatar
Ondřej Zajíček committed
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
    if (ifa && ic)
    {
      if (rip_reconfigure_iface(p, ifa, ic))
	continue;

      /* Hard restart */
      log(L_INFO "%s: Restarting interface %s", p->p.name, ifa->iface->name);
      rip_remove_iface(p, ifa);
      rip_add_iface(p, iface, ic);
    }

    if (ifa && !ic)
      rip_remove_iface(p, ifa);

    if (!ifa && ic)
      rip_add_iface(p, iface, ic);
  }
Pavel Machek's avatar
Pavel Machek committed
742 743
}

744
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
745
rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
746
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
747 748 749 750 751 752 753 754 755 756
  struct rip_proto *p = (void *) P;
  struct rip_config *cf = (void *) P->cf;

  if (iface->flags & IF_IGNORE)
    return;

  if (flags & IF_CHANGE_UP)
  {
    struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);

757 758 759 760
    /* Ignore ifaces without appropriate address */
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
      return;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
    if (ic)
      rip_add_iface(p, iface, ic);

    return;
  }

  struct rip_iface *ifa = rip_find_iface(p, iface);

  if (!ifa)
    return;

  if (flags & IF_CHANGE_DOWN)
  {
    rip_remove_iface(p, ifa);
    return;
  }

  if (flags & IF_CHANGE_MTU)
    rip_iface_update_buffers(ifa);

  if (flags & IF_CHANGE_LINK)
    rip_iface_update_state(ifa);
783 784
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
785 786 787 788 789

/*
 *	RIP timer events
 */

790
/**
Ondřej Zajíček's avatar
Ondřej Zajíček committed
791 792
 * rip_timer - RIP main timer hook
 * @t: timer
793
 *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
 * The RIP main timer is responsible for routing table maintenance. Invalid or
 * expired routes (&rip_rte) are removed and garbage collection of stale routing
 * table entries (&rip_entry) is done. Changes are propagated to core tables,
 * route reload is also done here. Note that garbage collection uses a maximal
 * GC time, while interfaces maintain an illusion of per-interface GC times in
 * rip_send_response().
 *
 * Keeping incoming routes and the selected outgoing route are two independent
 * functions, therefore after garbage collection some entries now considered
 * invalid (RIP_ENTRY_DUMMY) still may have non-empty list of incoming routes,
 * while some valid entries (representing an outgoing route) may have that list
 * empty.
 *
 * The main timer is not scheduled periodically but it uses the time of the
 * current next event and the minimal interval of any possible event to compute
 * the time of the next run.
810
 */
Ondřej Zajíček's avatar
Ondřej Zajíček committed
811 812
static void
rip_timer(timer *t)
813
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
814 815 816 817 818
  struct rip_proto *p = t->data;
  struct rip_config *cf = (void *) (p->p.cf);
  struct rip_iface *ifa;
  struct rip_neighbor *n, *nn;
  struct fib_iterator fit;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
819 820 821
  btime now_ = current_time();
  btime next = now_ + MIN(cf->min_timeout_time, cf->max_garbage_time);
  btime expires = 0;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
822 823 824 825 826 827

  TRACE(D_EVENTS, "Main timer fired");

  FIB_ITERATE_INIT(&fit, &p->rtable);

  loop:
828
  FIB_ITERATE_START(&p->rtable, &fit, struct rip_entry, en)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
829 830 831 832 833 834
  {
    struct rip_rte *rt, **rp;
    int changed = 0;

    /* Checking received routes for timeout and for dead neighbors */
    for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
835
    {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
836
      if (!rip_valid_rte(rt) || (rt->expires <= now_))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
837 838 839 840 841
      {
	rip_remove_rte(p, rp);
	changed = 1;
	continue;
      }
842

Ondřej Zajíček's avatar
Ondřej Zajíček committed
843 844
      next = MIN(next, rt->expires);
      rp = &rt->next;
845
    }
846

Ondřej Zajíček's avatar
Ondřej Zajíček committed
847 848 849 850 851 852 853 854 855
    /* Propagating eventual change */
    if (changed || p->rt_reload)
    {
      /*
       * We have to restart the iteration because there may be a cascade of
       * synchronous events rip_announce_rte() -> nest table change ->
       * rip_rt_notify() -> p->rtable change, invalidating hidden variables.
       */

856
      FIB_ITERATE_PUT_NEXT(&fit, &p->rtable);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
857 858 859
      rip_announce_rte(p, en);
      goto loop;
    }
860

Ondřej Zajíček's avatar
Ondřej Zajíček committed
861 862 863 864
    /* Checking stale entries for garbage collection timeout */
    if (en->valid == RIP_ENTRY_STALE)
    {
      expires = en->changed + cf->max_garbage_time;
865

Ondřej Zajíček's avatar
Ondřej Zajíček committed
866
      if (expires <= now_)
867
      {
868
	// TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
869
	en->valid = 0;
870
      }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
871 872 873 874 875 876 877
      else
	next = MIN(next, expires);
    }

    /* Remove empty nodes */
    if (!en->valid && !en->routes)
    {
878 879
      FIB_ITERATE_PUT(&fit);
      fib_delete(&p->rtable, en);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
880 881 882
      goto loop;
    }
  }
883
  FIB_ITERATE_END;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
884 885 886 887 888 889 890

  p->rt_reload = 0;

  /* Handling neighbor expiration */
  WALK_LIST(ifa, p->iface_list)
    WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
      if (n->last_seen)
891
      {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
892 893
	expires = n->last_seen + n->ifa->cf->timeout_time;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
894
	if (expires <= now_)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
895 896 897
	  rip_remove_neighbor(p, n);
	else
	  next = MIN(next, expires);
898
      }
899

900
  tm_start(p->timer, MAX(next - now_, 100 MS));
Ondřej Zajíček's avatar
Ondřej Zajíček committed
901 902 903 904 905
}

static inline void
rip_kick_timer(struct rip_proto *p)
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
906
  if (p->timer->expires > (current_time() + 100 MS))
907
    tm_start(p->timer, 100 MS);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
908
}
909

Ondřej Zajíček's avatar
Ondřej Zajíček committed
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
/**
 * rip_iface_timer - RIP interface timer hook
 * @t: timer
 *
 * RIP interface timers are responsible for scheduling both regular and
 * triggered updates. Fixed, delay-independent period is used for regular
 * updates, while minimal separating interval is enforced for triggered updates.
 * The function also ensures that a new update is not started when the old one
 * is still running.
 */
static void
rip_iface_timer(timer *t)
{
  struct rip_iface *ifa = t->data;
  struct rip_proto *p = ifa->rip;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
925 926
  btime now_ = current_time();
  btime period = ifa->cf->update_time;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
927 928 929 930 931 932 933 934

  if (ifa->cf->passive)
    return;

  TRACE(D_EVENTS, "Interface timer fired for %s", ifa->iface->name);

  if (ifa->tx_active)
  {
Ondřej Zajíček's avatar
Ondřej Zajíček committed
935
    if (now_ < (ifa->next_regular + period))
936
    { tm_start(ifa->timer, 100 MS); return; }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
937 938 939

    /* We are too late, reset is done by rip_send_table() */
    log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
940
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
941

Ondřej Zajíček's avatar
Ondřej Zajíček committed
942
  if (now_ >= ifa->next_regular)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
943 944 945 946
  {
    /* Send regular update, set timer for next period (or following one if necessay) */
    TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
    rip_send_table(p, ifa, ifa->addr, 0);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
947
    ifa->next_regular += period * (1 + ((now_ - ifa->next_regular) / period));
Ondřej Zajíček's avatar
Ondřej Zajíček committed
948 949 950
    ifa->want_triggered = 0;
    p->triggered = 0;
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
951
  else if (ifa->want_triggered && (now_ >= ifa->next_triggered))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
952 953 954 955
  {
    /* Send triggered update, enforce interval between triggered updates */
    TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
    rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
956
    ifa->next_triggered = now_ + MIN(5 S, period / 2);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
957 958 959 960
    ifa->want_triggered = 0;
    p->triggered = 0;
  }

961
  tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
962 963
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
964 965
static inline void
rip_iface_kick_timer(struct rip_iface *ifa)
966
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
967
  if (ifa->timer->expires > (current_time() + 100 MS))
968
    tm_start(ifa->timer, 100 MS);
969 970
}

971
static void
Ondřej Zajíček's avatar
Ondřej Zajíček committed
972
rip_trigger_update(struct rip_proto *p)
973
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
974
  if (p->triggered)
975
    return;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
976 977 978 979 980 981 982 983 984 985 986 987 988

  struct rip_iface *ifa;
  WALK_LIST(ifa, p->iface_list)
  {
    /* Interface not active */
    if (! ifa->up)
      continue;

    /* Already scheduled */
    if (ifa->want_triggered)
      continue;

    TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
989
    ifa->want_triggered = current_time();
Ondřej Zajíček's avatar
Ondřej Zajíček committed
990
    rip_iface_kick_timer(ifa);
991
  }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
992 993

  p->triggered = 1;
994 995
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
996 997 998 999 1000

/*
 *	RIP protocol glue
 */

1001
static struct ea_list *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1002
rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
1003
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1004
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
1005

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1006
  l->next = next;
1007 1008
  l->flags = EALF_SORTED;
  l->count = 2;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1009 1010

  l->attrs[0].id = EA_RIP_METRIC;
1011
  l->attrs[0].flags = 0;
1012
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1013 1014 1015
  l->attrs[0].u.data = metric;

  l->attrs[1].id = EA_RIP_TAG;
1016
  l->attrs[1].flags = 0;
1017
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1018 1019
  l->attrs[1].u.data = tag;

1020 1021 1022
  return l;
}

1023 1024
static void
rip_reload_routes(struct channel *C)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1025
{
1026
  struct rip_proto *p = (struct rip_proto *) C->proto;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1027 1028

  if (p->rt_reload)
1029
    return;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1030 1031 1032 1033 1034 1035

  TRACE(D_EVENTS, "Scheduling route reload");
  p->rt_reload = 1;
  rip_kick_timer(p);
}

1036 1037 1038
static struct ea_list *
rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1039
  return rip_prepare_attrs(pool, NULL, rt->u.rip.metric, rt->u.rip.tag);
1040 1041
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1042
static void
1043 1044
rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
{
1045
  rt->u.rip.metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1046
  rt->u.rip.tag = ea_get_int(attrs, EA_RIP_TAG, 0);
1047 1048
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1049 1050
static int
rip_rte_better(struct rte *new, struct rte *old)
1051
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1052
  return new->u.rip.metric < old->u.rip.metric;
1053 1054
}

1055 1056 1057
static int
rip_rte_same(struct rte *new, struct rte *old)
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1058 1059 1060
  return ((new->u.rip.metric == old->u.rip.metric) &&
	  (new->u.rip.tag == old->u.rip.tag) &&
	  (new->u.rip.from == old->u.rip.from));
1061 1062 1063
}


1064 1065 1066 1067 1068 1069 1070
static void
rip_postconfig(struct proto_config *CF)
{
  // struct rip_config *cf = (void *) CF;

  /* Define default channel */
  if (EMPTY_LIST(CF->channels))
1071
    channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
1072 1073
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1074
static struct proto *
1075
rip_init(struct proto_config *CF)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1076
{
1077 1078 1079
  struct proto *P = proto_new(CF);

  P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1080 1081 1082 1083

  P->if_notify = rip_if_notify;
  P->rt_notify = rip_rt_notify;
  P->neigh_notify = rip_neigh_notify;
1084
  // P->import_control = rip_import_control;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1085 1086 1087 1088 1089 1090 1091 1092 1093