summaryrefslogtreecommitdiff
path: root/proto/rip
diff options
context:
space:
mode:
Diffstat (limited to 'proto/rip')
-rw-r--r--proto/rip/Makefile9
-rw-r--r--proto/rip/config.Y32
-rw-r--r--proto/rip/packets.c106
-rw-r--r--proto/rip/rip.c233
-rw-r--r--proto/rip/rip.h51
5 files changed, 222 insertions, 209 deletions
diff --git a/proto/rip/Makefile b/proto/rip/Makefile
index d2d3c987..7feabcd8 100644
--- a/proto/rip/Makefile
+++ b/proto/rip/Makefile
@@ -1,5 +1,6 @@
-source=rip.c packets.c
-root-rel=../../
-dir-name=proto/rip
+src := packets.c rip.c
+obj := $(src-o-files)
+$(all-daemon)
+$(cf-local)
-include ../../Rules
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 4ec45c7a..e3bc4ae3 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -32,34 +32,40 @@ rip_check_auth(void)
CF_DECLS
-CF_KEYWORDS(RIP, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
+CF_KEYWORDS(RIP, NG, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
GARBAGE, PORT, ADDRESS, MODE, BROADCAST, MULTICAST, PASSIVE,
VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO, TIME, BFD,
AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5, TTL, SECURITY,
RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, RIP_METRIC, RIP_TAG)
-%type <i> rip_auth
+%type <i> rip_variant rip_auth
CF_GRAMMAR
CF_ADDTO(proto, rip_proto)
-rip_proto_start: proto_start RIP
+rip_variant:
+ RIP { $$ = 1; }
+ | RIP NG { $$ = 0; }
+ ;
+
+rip_proto_start: proto_start rip_variant
{
this_proto = proto_config_new(&proto_rip, $1);
- init_list(&RIP_CFG->patt_list);
+ this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
- RIP_CFG->rip2 = RIP_IS_V2;
+ init_list(&RIP_CFG->patt_list);
+ RIP_CFG->rip2 = $2;
RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
-
- RIP_CFG->min_timeout_time = 60;
- RIP_CFG->max_garbage_time = 60;
+ RIP_CFG->min_timeout_time = 60 S_;
+ RIP_CFG->max_garbage_time = 60 S_;
};
rip_proto_item:
proto_item
+ | proto_channel
| ECMP bool { RIP_CFG->ecmp = $2 ? RIP_DEFAULT_ECMP_LIMIT : 0; }
- | ECMP bool LIMIT expr { RIP_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
+ | ECMP bool LIMIT expr { RIP_CFG->ecmp = $2 ? $4 : 0; }
| INFINITY expr { RIP_CFG->infinity = $2; }
| INTERFACE rip_iface
;
@@ -131,7 +137,7 @@ rip_iface_item:
| MODE MULTICAST { RIP_IFACE->mode = RIP_IM_MULTICAST; }
| MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); }
| PASSIVE bool { RIP_IFACE->passive = $2; }
- | ADDRESS ipa { RIP_IFACE->address = $2; }
+ | ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); }
| PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
| VERSION expr { RIP_IFACE->version = $2;
if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng");
@@ -141,9 +147,9 @@ rip_iface_item:
| SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; }
| POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
| CHECK ZERO bool { RIP_IFACE->check_zero = $3; }
- | UPDATE TIME expr { RIP_IFACE->update_time = $3; if ($3<=0) cf_error("Update time must be positive"); }
- | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3; if ($3<=0) cf_error("Timeout time must be positive"); }
- | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3; if ($3<=0) cf_error("Garbage time must be positive"); }
+ | UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
+ | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
+ | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
diff --git a/proto/rip/packets.c b/proto/rip/packets.c
index 722a9012..891f454f 100644
--- a/proto/rip/packets.c
+++ b/proto/rip/packets.c
@@ -9,6 +9,8 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
+#undef LOCAL_DEBUG
+
#include "rip.h"
#include "lib/mac.h"
@@ -76,8 +78,7 @@ struct rip_auth_tail
/* Internal representation of RTE block data */
struct rip_block
{
- ip_addr prefix;
- int pxlen;
+ net_addr net;
u32 metric;
u16 tag;
u16 no_af;
@@ -106,30 +107,30 @@ static inline uint rip_pkt_hdrlen(struct rip_iface *ifa)
{ return sizeof(struct rip_packet) + (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0); }
static inline void
-rip_put_block(struct rip_proto *p UNUSED4 UNUSED6, byte *pos, struct rip_block *rte)
+rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
{
if (rip_is_v2(p))
{
struct rip_block_v2 *block = (void *) pos;
block->family = rte->no_af ? 0 : htons(RIP_AF_IPV4);
block->tag = htons(rte->tag);
- block->network = ip4_hton(ipa_to_ip4(rte->prefix));
- block->netmask = ip4_hton(ip4_mkmask(rte->pxlen));
+ block->network = ip4_hton(net4_prefix(&rte->net));
+ block->netmask = ip4_hton(ip4_mkmask(net4_pxlen(&rte->net)));
block->next_hop = ip4_hton(ipa_to_ip4(rte->next_hop));
block->metric = htonl(rte->metric);
}
else /* RIPng */
{
struct rip_block_ng *block = (void *) pos;
- block->prefix = ip6_hton(ipa_to_ip6(rte->prefix));
+ block->prefix = ip6_hton(net6_prefix(&rte->net));
block->tag = htons(rte->tag);
- block->pxlen = rte->pxlen;
+ block->pxlen = net6_pxlen(&rte->net);
block->metric = rte->metric;
}
}
static inline void
-rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte UNUSED4)
+rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte)
{
struct rip_block_ng *block = (void *) pos;
block->prefix = ip6_hton(ipa_to_ip6(rte->next_hop));
@@ -139,7 +140,7 @@ rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte UN
}
static inline int
-rip_get_block(struct rip_proto *p UNUSED4 UNUSED6, byte *pos, struct rip_block *rte)
+rip_get_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
{
if (rip_is_v2(p))
{
@@ -149,8 +150,8 @@ rip_get_block(struct rip_proto *p UNUSED4 UNUSED6, byte *pos, struct rip_block *
if (block->family != (rte->no_af ? 0 : htons(RIP_AF_IPV4)))
return 0;
- rte->prefix = ipa_from_ip4(ip4_ntoh(block->network));
- rte->pxlen = ip4_masklen(ip4_ntoh(block->netmask));
+ uint pxlen = ip4_masklen(ip4_ntoh(block->netmask));
+ net_fill_ip4(&rte->net, ip4_ntoh(block->network), pxlen);
rte->metric = ntohl(block->metric);
rte->tag = ntohs(block->tag);
rte->next_hop = ipa_from_ip4(ip4_ntoh(block->next_hop));
@@ -169,8 +170,8 @@ rip_get_block(struct rip_proto *p UNUSED4 UNUSED6, byte *pos, struct rip_block *
return 0;
}
- rte->prefix = ipa_from_ip6(ip6_ntoh(block->prefix));
- rte->pxlen = block->pxlen;
+ uint pxlen = (block->pxlen <= IP6_MAX_PREFIX_LENGTH) ? block->pxlen : 255;
+ net_fill_ip6(&rte->net, ip6_ntoh(block->prefix), pxlen);
rte->metric = block->metric;
rte->tag = ntohs(block->tag);
/* rte->next_hop is deliberately kept unmodified */;
@@ -188,7 +189,10 @@ rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
* have the same CSN. We are using real time, but enforcing monotonicity.
*/
if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
- ifa->csn = (ifa->csn < (u32) now_real) ? (u32) now_real : ifa->csn + 1;
+ {
+ u32 now_real = (u32) (current_real_time() TO_S);
+ ifa->csn = (ifa->csn < now_real) ? now_real : ifa->csn + 1;
+ }
}
static void
@@ -406,8 +410,9 @@ rip_receive_request(struct rip_proto *p, struct rip_iface *ifa, struct rip_packe
if (!rip_get_block(p, pos, &b))
return;
- /* Special case - zero prefix, infinity metric */
- if (ipa_nonzero(b.prefix) || b.pxlen || (b.metric != p->infinity))
+ /* Special case - infinity metric, for RIPng also zero prefix */
+ if ((b.metric != p->infinity) ||
+ (rip_is_ng(p) && !net_zero_ip6((net_addr_ip6 *) &b.net)))
return;
/* We do nothing if TX is already active */
@@ -432,6 +437,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
(rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
ip_addr last_next_hop = IPA_NONE;
+ btime now_ = current_time();
int send = 0;
struct rip_packet *pkt = (void *) pos;
@@ -440,17 +446,15 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
pkt->unused = 0;
pos += rip_pkt_hdrlen(ifa);
- FIB_ITERATE_START(&p->rtable, &ifa->tx_fit, z)
+ FIB_ITERATE_START(&p->rtable, &ifa->tx_fit, struct rip_entry, en)
{
- struct rip_entry *en = (struct rip_entry *) z;
-
/* Dummy entries */
if (!en->valid)
goto next_entry;
/* Stale entries that should be removed */
if ((en->valid == RIP_ENTRY_STALE) &&
- ((en->changed + ifa->cf->garbage_time) <= now))
+ ((en->changed + ifa->cf->garbage_time) <= now_))
goto next_entry;
/* Triggered updates */
@@ -460,28 +464,28 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
/* Not enough space for current entry */
if (pos > max)
{
- FIB_ITERATE_PUT(&ifa->tx_fit, z);
+ FIB_ITERATE_PUT(&ifa->tx_fit);
goto break_loop;
}
struct rip_block rte = {
- .prefix = en->n.prefix,
- .pxlen = en->n.pxlen,
.metric = en->metric,
.tag = en->tag
};
+ net_copy(&rte.net, en->n.addr);
+
if (en->iface == ifa->iface)
rte.next_hop = en->next_hop;
if (rip_is_v2(p) && (ifa->cf->version == RIP_V1))
{
/* Skipping subnets (i.e. not hosts, classful networks or default route) */
- if (ip4_masklen(ip4_class_mask(ipa_to_ip4(en->n.prefix))) != en->n.pxlen)
+ if (ip4_masklen(ip4_class_mask(net4_prefix(&rte.net))) != rte.net.pxlen)
goto next_entry;
rte.tag = 0;
- rte.pxlen = 0;
+ rte.net.pxlen = 0;
rte.next_hop = IPA_NONE;
}
@@ -497,7 +501,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
goto next_entry;
}
- // TRACE(D_PACKETS, " %I/%d -> %I metric %d", rte.prefix, rte.pxlen, rte.next_hop, rte.metric);
+ // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net, rte.next_hop, rte.metric);
/* RIPng next hop entry */
if (rip_is_ng(p) && !ipa_equal(rte.next_hop, last_next_hop))
@@ -513,7 +517,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
next_entry: ;
}
- FIB_ITERATE_END(z);
+ FIB_ITERATE_END;
ifa->tx_active = 0;
/* Do not send empty packet */
@@ -540,9 +544,9 @@ break_loop:
* activating the new one.
*/
void
-rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed)
+rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed)
{
- DBG("RIP: Opening TX session to %I on %s\n", dst, ifa->iface->name);
+ DBG("RIP: Opening TX session to %I on %s\n", addr, ifa->iface->name);
rip_reset_tx_session(p, ifa);
@@ -591,6 +595,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
byte *pos = (byte *) pkt + sizeof(struct rip_packet);
byte *end = (byte *) pkt + plen;
+ btime now_ = current_time();
for (; pos < end; pos += RIP_BLOCK_LENGTH)
{
@@ -598,23 +603,25 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
if (!rip_get_block(p, pos, &rte))
continue;
- int c = ipa_classify_net(rte.prefix);
- if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
- SKIP("invalid prefix");
-
if (rip_is_v2(p) && (pkt->version == RIP_V1))
{
- if (ifa->cf->check_zero && (rte.tag || rte.pxlen || ipa_nonzero(rte.next_hop)))
+ if (ifa->cf->check_zero && (rte.tag || rte.net.pxlen || ipa_nonzero(rte.next_hop)))
SKIP("RIPv1 reserved field is nonzero");
rte.tag = 0;
- rte.pxlen = ip4_masklen(ip4_class_mask(ipa_to_ip4(rte.prefix)));
+ rte.net.pxlen = ip4_masklen(ip4_class_mask(net4_prefix(&rte.net)));
rte.next_hop = IPA_NONE;
}
- if ((rte.pxlen < 0) || (rte.pxlen > MAX_PREFIX_LENGTH))
+ if (rte.net.pxlen == 255)
SKIP("invalid prefix length");
+ net_normalize(&rte.net);
+
+ int c = net_classify(&rte.net);
+ if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
+ SKIP("invalid prefix");
+
if (rte.metric > p->infinity)
SKIP("invalid metric");
@@ -625,7 +632,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
rte.next_hop = IPA_NONE;
}
- // TRACE(D_PACKETS, " %I/%d -> %I metric %d", rte.prefix, rte.pxlen, rte.next_hop, rte.metric);
+ // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net.n, rte.next_hop, rte.metric);
rte.metric += ifa->cf->metric;
@@ -636,19 +643,19 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
.next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
.metric = rte.metric,
.tag = rte.tag,
- .expires = now + ifa->cf->timeout_time
+ .expires = now_ + ifa->cf->timeout_time
};
- rip_update_rte(p, &rte.prefix, rte.pxlen, &new);
+ rip_update_rte(p, &rte.net, &new);
}
else
- rip_withdraw_rte(p, &rte.prefix, rte.pxlen, from);
+ rip_withdraw_rte(p, &rte.net, from);
continue;
skip:
- LOG_RTE("Ignoring route %I/%d received from %I - %s",
- rte.prefix, rte.pxlen, from->nbr->addr, err_dsc);
+ LOG_RTE("Ignoring route %N received from %I - %s",
+ &rte.net, from->nbr->addr, err_dsc);
}
}
@@ -667,8 +674,7 @@ rip_rx_hook(sock *sk, uint len)
sk->iface->name, sk->faddr, sk->laddr);
/* Silently ignore my own packets */
- /* FIXME: Better local address check */
- if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
+ if (ipa_equal(sk->faddr, sk->saddr))
return 1;
if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr))
@@ -704,7 +710,7 @@ rip_rx_hook(sock *sk, uint len)
if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
DROP("invalid length", plen);
- n->last_seen = now;
+ n->last_seen = current_time();
rip_update_bfd(p, n);
switch (pkt->command)
@@ -736,19 +742,13 @@ rip_open_socket(struct rip_iface *ifa)
sock *sk = sk_new(p->p.pool);
sk->type = SK_UDP;
+ sk->subtype = rip_is_v2(p) ? SK_IPV4 : SK_IPV6;
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
+ sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
sk->vrf = p->p.vrf;
- /*
- * For RIPv2, we explicitly choose a primary address, mainly to ensure that
- * RIP and BFD uses the same one. For RIPng, we left it to kernel, which
- * should choose some link-local address based on the same scope rule.
- */
- if (rip_is_v2(p))
- sk->saddr = ifa->iface->addr->ip;
-
sk->rx_hook = rip_rx_hook;
sk->tx_hook = rip_tx_hook;
sk->err_hook = rip_err_hook;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 7b380097..a3eeaf17 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -92,15 +92,6 @@ static void rip_trigger_update(struct rip_proto *p);
* RIP routes
*/
-static void
-rip_init_entry(struct fib_node *fn)
-{
- // struct rip_entry *en = (void) *fn;
-
- const uint offset = OFFSETOF(struct rip_entry, routes);
- memset((byte *)fn + offset, 0, sizeof(struct rip_entry) - offset);
-}
-
static struct rip_rte *
rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src)
{
@@ -152,27 +143,20 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt)
{
/* Update */
- net *n = net_get(p->p.table, en->n.prefix, en->n.pxlen);
-
rta a0 = {
.src = p->p.main_source,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
- .cast = RTC_UNICAST
+ .dest = RTD_UNICAST,
};
u8 rt_metric = rt->metric;
u16 rt_tag = rt->tag;
- struct rip_rte *rt2 = rt->next;
- /* Find second valid rte */
- while (rt2 && !rip_valid_rte(rt2))
- rt2 = rt2->next;
-
- if (p->ecmp && rt2)
+ if (p->ecmp)
{
/* ECMP route */
- struct mpnh *nhs = NULL;
+ struct nexthop *nhs = NULL;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
@@ -180,54 +164,51 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (!rip_valid_rte(rt))
continue;
- struct mpnh *nh = alloca(sizeof(struct mpnh));
+ struct nexthop *nh = allocz(sizeof(struct nexthop));
+
nh->gw = rt->next_hop;
nh->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
- mpnh_insert(&nhs, nh);
+
+ nexthop_insert(&nhs, nh);
num++;
if (rt->tag != rt_tag)
rt_tag = 0;
}
- a0.dest = RTD_MULTIPATH;
- a0.nexthops = nhs;
+ a0.nh = *nhs;
}
else
{
/* Unipath route */
- a0.dest = RTD_ROUTER;
- a0.gw = rt->next_hop;
- a0.iface = rt->from->nbr->iface;
a0.from = rt->from->nbr->addr;
+ a0.nh.gw = rt->next_hop;
+ a0.nh.iface = rt->from->nbr->iface;
}
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
- e->u.rip.from = a0.iface;
+ e->u.rip.from = a0.nh.iface;
e->u.rip.metric = rt_metric;
e->u.rip.tag = rt_tag;
- e->net = n;
e->pflags = 0;
- rte_update(&p->p, n, e);
+ rte_update(&p->p, en->n.addr, e);
}
else
{
/* Withdraw */
- net *n = net_find(p->p.table, en->n.prefix, en->n.pxlen);
- rte_update(&p->p, n, NULL);
+ rte_update(&p->p, en->n.addr, NULL);
}
}
/**
* rip_update_rte - enter a route update to RIP routing table
* @p: RIP instance
- * @prefix: network prefix
- * @pxlen: network prefix length
+ * @addr: network address
* @new: a &rip_rte representing the new route
*
* The function is called by the RIP packet processing code whenever it receives
@@ -237,9 +218,9 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
* rip_withdraw_rte() should be called instead of rip_update_rte().
*/
void
-rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *new)
+rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new)
{
- struct rip_entry *en = fib_get(&p->rtable, prefix, pxlen);
+ struct rip_entry *en = fib_get(&p->rtable, n);
struct rip_rte *rt, **rp;
int changed = 0;
@@ -279,8 +260,7 @@ rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *
/**
* rip_withdraw_rte - enter a route withdraw to RIP routing table
* @p: RIP instance
- * @prefix: network prefix
- * @pxlen: network prefix length
+ * @addr: network address
* @from: a &rip_neighbor propagating the withdraw
*
* The function is called by the RIP packet processing code whenever it receives
@@ -288,9 +268,9 @@ rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *
* removed. Eventually, the change is also propagated by rip_announce_rte().
*/
void
-rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_neighbor *from)
+rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
{
- struct rip_entry *en = fib_find(&p->rtable, prefix, pxlen);
+ struct rip_entry *en = fib_find(&p->rtable, n);
struct rip_rte *rt, **rp;
if (!en)
@@ -317,7 +297,7 @@ rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_nei
* it into our data structures.
*/
static void
-rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net, struct rte *new,
+rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
struct rte *old UNUSED, struct ea_list *attrs)
{
struct rip_proto *p = (struct rip_proto *) P;
@@ -332,15 +312,15 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
if (rt_metric > p->infinity)
{
- log(L_WARN "%s: Invalid rip_metric value %u for route %I/%d",
- p->p.name, rt_metric, net->n.prefix, net->n.pxlen);
+ log(L_WARN "%s: Invalid rip_metric value %u for route %N",
+ p->p.name, rt_metric, net->n.addr);
rt_metric = p->infinity;
}
if (rt_tag > 0xffff)
{
- log(L_WARN "%s: Invalid rip_tag value %u for route %I/%d",
- p->p.name, rt_tag, net->n.prefix, net->n.pxlen);
+ log(L_WARN "%s: Invalid rip_tag value %u for route %N",
+ p->p.name, rt_tag, net->n.addr);
rt_metric = p->infinity;
rt_tag = 0;
}
@@ -352,7 +332,7 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
* collection.
*/
- en = fib_get(&p->rtable, &net->n.prefix, net->n.pxlen);
+ en = fib_get(&p->rtable, net->n.addr);
old_metric = en->valid ? en->metric : -1;
@@ -360,13 +340,13 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
en->metric = rt_metric;
en->tag = rt_tag;
en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
- en->iface = new->attrs->iface;
- en->next_hop = new->attrs->gw;
+ en->iface = new->attrs->nh.iface;
+ en->next_hop = new->attrs->nh.gw;
}
else
{
/* Withdraw */
- en = fib_find(&p->rtable, &net->n.prefix, net->n.pxlen);
+ en = fib_find(&p->rtable, net->n.addr);
if (!en || en->valid != RIP_ENTRY_VALID)
return;
@@ -384,7 +364,7 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
/* Activate triggered updates */
if (en->metric != old_metric)
{
- en->changed = now;
+ en->changed = current_time();
rip_trigger_update(p);
}
}
@@ -526,10 +506,10 @@ rip_iface_start(struct rip_iface *ifa)
TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
- ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
- ifa->next_triggered = now; /* Available immediately */
- ifa->want_triggered = 1; /* All routes in triggered update */
- tm_start(ifa->timer, 1); /* Or 100 ms */
+ 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 */
+ tm_start(ifa->timer, 100 MS);
ifa->up = 1;
if (!ifa->cf->passive)
@@ -650,13 +630,19 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
else if (ic->mode == RIP_IM_MULTICAST)
ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
else /* Broadcast */
- ifa->addr = iface->addr->brd;
+ 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
+ */
init_list(&ifa->neigh_list);
add_tail(&p->iface_list, NODE ifa);
- ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
+ ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
struct object_lock *lock = olock_new(p->p.pool);
lock->type = OBJLOCK_UDP;
@@ -704,8 +690,8 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
rip_iface_update_buffers(ifa);
- if (ifa->next_regular > (now + new->update_time))
- ifa->next_regular = now + (random() % new->update_time) + 1;
+ if (ifa->next_regular > (current_time() + new->update_time))
+ ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
if (new->check_link != old->check_link)
rip_iface_update_state(ifa);
@@ -726,7 +712,11 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
WALK_LIST(iface, iface_list)
{
- if (! (iface->flags & IF_UP))
+ if (!(iface->flags & IF_UP))
+ continue;
+
+ /* Ignore ifaces without appropriate address */
+ if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
continue;
struct rip_iface *ifa = rip_find_iface(p, iface);
@@ -764,6 +754,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
+ /* Ignore ifaces without appropriate address */
+ if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
+ return;
+
if (ic)
rip_add_iface(p, iface, ic);
@@ -822,24 +816,24 @@ rip_timer(timer *t)
struct rip_iface *ifa;
struct rip_neighbor *n, *nn;
struct fib_iterator fit;
- bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
- bird_clock_t expires = 0;
+ btime now_ = current_time();
+ btime next = now_ + MIN(cf->min_timeout_time, cf->max_garbage_time);
+ btime expires = 0;
TRACE(D_EVENTS, "Main timer fired");
FIB_ITERATE_INIT(&fit, &p->rtable);
loop:
- FIB_ITERATE_START(&p->rtable, &fit, node)
+ FIB_ITERATE_START(&p->rtable, &fit, struct rip_entry, en)
{
- struct rip_entry *en = (struct rip_entry *) node;
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 */)
{
- if (!rip_valid_rte(rt) || (rt->expires <= now))
+ if (!rip_valid_rte(rt) || (rt->expires <= now_))
{
rip_remove_rte(p, rp);
changed = 1;
@@ -859,7 +853,7 @@ rip_timer(timer *t)
* rip_rt_notify() -> p->rtable change, invalidating hidden variables.
*/
- FIB_ITERATE_PUT_NEXT(&fit, &p->rtable, node);
+ FIB_ITERATE_PUT_NEXT(&fit, &p->rtable);
rip_announce_rte(p, en);
goto loop;
}
@@ -869,9 +863,9 @@ rip_timer(timer *t)
{
expires = en->changed + cf->max_garbage_time;
- if (expires <= now)
+ if (expires <= now_)
{
- // TRACE(D_EVENTS, "entry is too old: %I/%d", en->n.prefix, en->n.pxlen);
+ // TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
en->valid = 0;
}
else
@@ -881,12 +875,12 @@ rip_timer(timer *t)
/* Remove empty nodes */
if (!en->valid && !en->routes)
{
- FIB_ITERATE_PUT(&fit, node);
- fib_delete(&p->rtable, node);
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(&p->rtable, en);
goto loop;
}
}
- FIB_ITERATE_END(node);
+ FIB_ITERATE_END;
p->rt_reload = 0;
@@ -897,20 +891,20 @@ rip_timer(timer *t)
{
expires = n->last_seen + n->ifa->cf->timeout_time;
- if (expires <= now)
+ if (expires <= now_)
rip_remove_neighbor(p, n);
else
next = MIN(next, expires);
}
- tm_start(p->timer, MAX(next - now, 1));
+ tm_start(p->timer, MAX(next - now_, 100 MS));
}
static inline void
rip_kick_timer(struct rip_proto *p)
{
- if (p->timer->expires > (now + 1))
- tm_start(p->timer, 1); /* Or 100 ms */
+ if (p->timer->expires > (current_time() + 100 MS))
+ tm_start(p->timer, 100 MS);
}
/**
@@ -928,7 +922,8 @@ rip_iface_timer(timer *t)
{
struct rip_iface *ifa = t->data;
struct rip_proto *p = ifa->rip;
- bird_clock_t period = ifa->cf->update_time;
+ btime now_ = current_time();
+ btime period = ifa->cf->update_time;
if (ifa->cf->passive)
return;
@@ -937,40 +932,40 @@ rip_iface_timer(timer *t)
if (ifa->tx_active)
{
- if (now < (ifa->next_regular + period))
- { tm_start(ifa->timer, 1); return; }
+ if (now_ < (ifa->next_regular + period))
+ { tm_start(ifa->timer, 100 MS); return; }
/* 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);
}
- if (now >= ifa->next_regular)
+ if (now_ >= ifa->next_regular)
{
/* 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);
- ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
+ ifa->next_regular += period * (1 + ((now_ - ifa->next_regular) / period));
ifa->want_triggered = 0;
p->triggered = 0;
}
- else if (ifa->want_triggered && (now >= ifa->next_triggered))
+ else if (ifa->want_triggered && (now_ >= ifa->next_triggered))
{
/* 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);
- ifa->next_triggered = now + MIN(5, period / 2 + 1);
+ ifa->next_triggered = now_ + MIN(5 S, period / 2);
ifa->want_triggered = 0;
p->triggered = 0;
}
- tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now));
+ tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
}
static inline void
rip_iface_kick_timer(struct rip_iface *ifa)
{
- if (ifa->timer->expires > (now + 1))
- tm_start(ifa->timer, 1); /* Or 100 ms */
+ if (ifa->timer->expires > (current_time() + 100 MS))
+ tm_start(ifa->timer, 100 MS);
}
static void
@@ -991,7 +986,7 @@ rip_trigger_update(struct rip_proto *p)
continue;
TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
- ifa->want_triggered = now;
+ ifa->want_triggered = current_time();
rip_iface_kick_timer(ifa);
}
@@ -1035,19 +1030,17 @@ rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **att
return 0;
}
-static int
-rip_reload_routes(struct proto *P)
+static void
+rip_reload_routes(struct channel *C)
{
- struct rip_proto *p = (struct rip_proto *) P;
+ struct rip_proto *p = (struct rip_proto *) C->proto;
if (p->rt_reload)
- return 1;
+ return;
TRACE(D_EVENTS, "Scheduling route reload");
p->rt_reload = 1;
rip_kick_timer(p);
-
- return 1;
}
static struct ea_list *
@@ -1078,12 +1071,23 @@ rip_rte_same(struct rte *new, struct rte *old)
}
+static void
+rip_postconfig(struct proto_config *CF)
+{
+ // struct rip_config *cf = (void *) CF;
+
+ /* Define default channel */
+ if (EMPTY_LIST(CF->channels))
+ channel_config_new(NULL, CF->net_type, CF);
+}
+
static struct proto *
-rip_init(struct proto_config *cfg)
+rip_init(struct proto_config *CF)
{
- struct proto *P = proto_new(cfg, sizeof(struct rip_proto));
+ struct proto *P = proto_new(CF);
+
+ P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- P->accept_ra_types = RA_OPTIMAL;
P->if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
@@ -1104,10 +1108,12 @@ rip_start(struct proto *P)
struct rip_config *cf = (void *) (P->cf);
init_list(&p->iface_list);
- fib_init(&p->rtable, P->pool, sizeof(struct rip_entry), 0, rip_init_entry);
+ fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6,
+ sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL);
p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
- p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
+ p->timer = tm_new_init(P->pool, rip_timer, p, 0, 0);
+ p->rip2 = cf->rip2;
p->ecmp = cf->ecmp;
p->infinity = cf->infinity;
p->triggered = 0;
@@ -1121,18 +1127,24 @@ rip_start(struct proto *P)
}
static int
-rip_reconfigure(struct proto *P, struct proto_config *c)
+rip_reconfigure(struct proto *P, struct proto_config *CF)
{
struct rip_proto *p = (void *) P;
- struct rip_config *new = (void *) c;
+ struct rip_config *new = (void *) CF;
// struct rip_config *old = (void *) (P->cf);
+ if (new->rip2 != p->rip2)
+ return 0;
+
if (new->infinity != p->infinity)
return 0;
+ if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ return 0;
+
TRACE(D_EVENTS, "Reconfiguring");
- p->p.cf = c;
+ p->p.cf = CF;
p->ecmp = new->ecmp;
rip_reconfigure_ifaces(p, new);
@@ -1184,7 +1196,7 @@ rip_show_interfaces(struct proto *P, char *iff)
}
cli_msg(-1021, "%s:", p->p.name);
- cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
+ cli_msg(-1021, "%-10s %-6s %6s %6s %7s",
"Interface", "State", "Metric", "Nbrs", "Timer");
WALK_LIST(ifa, p->iface_list)
@@ -1197,8 +1209,9 @@ rip_show_interfaces(struct proto *P, char *iff)
if (n->last_seen)
nbrs++;
- int timer = MAX(ifa->next_regular - now, 0);
- cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
+ btime now_ = current_time();
+ btime timer = (ifa->next_regular > now_) ? (ifa->next_regular - now_) : 0;
+ cli_msg(-1021, "%-10s %-6s %6u %6u %7t",
ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
}
@@ -1220,7 +1233,7 @@ rip_show_neighbors(struct proto *P, char *iff)
}
cli_msg(-1022, "%s:", p->p.name);
- cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
+ cli_msg(-1022, "%-25s %-10s %6s %6s %7s",
"IP address", "Interface", "Metric", "Routes", "Seen");
WALK_LIST(ifa, p->iface_list)
@@ -1233,8 +1246,8 @@ rip_show_neighbors(struct proto *P, char *iff)
if (!n->last_seen)
continue;
- int timer = now - n->last_seen;
- cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
+ btime timer = current_time() - n->last_seen;
+ cli_msg(-1022, "%-25I %-10s %6u %6u %7t",
n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
}
}
@@ -1250,12 +1263,11 @@ rip_dump(struct proto *P)
int i;
i = 0;
- FIB_WALK(&p->rtable, e)
+ FIB_WALK(&p->rtable, struct rip_entry, en)
{
- struct rip_entry *en = (struct rip_entry *) e;
- debug("RIP: entry #%d: %I/%d via %I dev %s valid %d metric %d age %d s\n",
- i++, en->n.prefix, en->n.pxlen, en->next_hop, en->iface->name,
- en->valid, en->metric, now - en->changed);
+ debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
+ i++, en->n.addr, en->next_hop, en->iface->name,
+ en->valid, en->metric, current_time() - en->changed);
}
FIB_WALK_END;
@@ -1274,7 +1286,10 @@ struct protocol proto_rip = {
.template = "rip%d",
.attr_class = EAP_RIP,
.preference = DEF_PREF_RIP,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct rip_proto),
.config_size = sizeof(struct rip_config),
+ .postconfig = rip_postconfig,
.init = rip_init,
.dump = rip_dump,
.start = rip_start,
diff --git a/proto/rip/rip.h b/proto/rip/rip.h
index b24d9536..55696333 100644
--- a/proto/rip/rip.h
+++ b/proto/rip/rip.h
@@ -27,12 +27,6 @@
#include "lib/timer.h"
-#ifdef IPV6
-#define RIP_IS_V2 0
-#else
-#define RIP_IS_V2 1
-#endif
-
#define RIP_V1 1
#define RIP_V2 2
@@ -44,9 +38,9 @@
#define RIP_DEFAULT_ECMP_LIMIT 16
#define RIP_DEFAULT_INFINITY 16
-#define RIP_DEFAULT_UPDATE_TIME 30
-#define RIP_DEFAULT_TIMEOUT_TIME 180
-#define RIP_DEFAULT_GARBAGE_TIME 120
+#define RIP_DEFAULT_UPDATE_TIME (30 S_)
+#define RIP_DEFAULT_TIMEOUT_TIME (180 S_)
+#define RIP_DEFAULT_GARBAGE_TIME (120 S_)
struct rip_config
@@ -58,8 +52,8 @@ struct rip_config
u8 ecmp; /* Maximum number of nexthops in ECMP route, or 0 */
u8 infinity; /* Maximum metric value, representing infinity */
- u32 min_timeout_time; /* Minimum of interface timeout_time */
- u32 max_garbage_time; /* Maximum of interface garbage_time */
+ btime min_timeout_time; /* Minimum of interface timeout_time */
+ btime max_garbage_time; /* Maximum of interface garbage_time */
};
struct rip_iface_config
@@ -84,9 +78,9 @@ struct rip_iface_config
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos;
int tx_priority;
- u32 update_time; /* Periodic update interval */
- u32 timeout_time; /* Route expiration timeout */
- u32 garbage_time; /* Unreachable entry GC timeout */
+ btime update_time; /* Periodic update interval */
+ btime timeout_time; /* Route expiration timeout */
+ btime garbage_time; /* Unreachable entry GC timeout */
list *passwords; /* Passwords for authentication */
};
@@ -98,6 +92,7 @@ struct rip_proto
slab *rte_slab; /* Slab for internal routes (struct rip_rte) */
timer *timer; /* Main protocol timer */
+ u8 rip2; /* RIPv2 (IPv4) or RIPng (IPv6) */
u8 ecmp; /* Maximum number of nexthops in ECMP route, or 0 */
u8 infinity; /* Maximum metric value, representing infinity */
u8 triggered; /* Logical AND of interface want_triggered values */
@@ -125,14 +120,14 @@ struct rip_iface
list neigh_list; /* List of iface neighbors (struct rip_neighbor) */
/* Update scheduling */
- bird_clock_t next_regular; /* Next time when regular update should be called */
- bird_clock_t next_triggered; /* Next time when triggerd update may be called */
- bird_clock_t want_triggered; /* Nonzero if triggered update is scheduled */
+ btime next_regular; /* Next time when regular update should be called */
+ btime next_triggered; /* Next time when triggerd update may be called */
+ btime want_triggered; /* Nonzero if triggered update is scheduled */
/* Active update */
int tx_active; /* Update session is active */
ip_addr tx_addr; /* Update session destination address */
- bird_clock_t tx_changed; /* Minimal changed time for triggered update */
+ btime tx_changed; /* Minimal changed time for triggered update */
struct fib_iterator tx_fit; /* FIB iterator in RIP routing table (p.rtable) */
};
@@ -142,14 +137,13 @@ struct rip_neighbor
struct rip_iface *ifa; /* Associated interface, may be NULL if stale */
struct neighbor *nbr; /* Associaded core neighbor, may be NULL if stale */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
- bird_clock_t last_seen; /* Time of last received and accepted message */
+ btime last_seen; /* Time of last received and accepted message */
u32 uc; /* Use count, number of routes linking the neighbor */
u32 csn; /* Last received crypto sequence number */
};
struct rip_entry
{
- struct fib_node n;
struct rip_rte *routes; /* List of incoming routes */
u8 valid; /* Entry validity state (RIP_ENTRY_*) */
@@ -159,7 +153,9 @@ struct rip_entry
struct iface *iface; /* Outgoing route iface (for next hop) */
ip_addr next_hop; /* Outgoing route next hop */
- bird_clock_t changed; /* Last time when the outgoing route metric changed */
+ btime changed; /* Last time when the outgoing route metric changed */
+
+ struct fib_node n;
};
struct rip_rte
@@ -171,7 +167,7 @@ struct rip_rte
u16 metric; /* Route metric (after increase) */
u16 tag; /* Route tag */
- bird_clock_t expires; /* Time of route expiration */
+ btime expires; /* Time of route expiration */
};
@@ -189,16 +185,11 @@ struct rip_rte
#define EA_RIP_METRIC EA_CODE(EAP_RIP, 0)
#define EA_RIP_TAG EA_CODE(EAP_RIP, 1)
-#define rip_is_v2(X) RIP_IS_V2
-#define rip_is_ng(X) (!RIP_IS_V2)
-
-/*
static inline int rip_is_v2(struct rip_proto *p)
{ return p->rip2; }
static inline int rip_is_ng(struct rip_proto *p)
{ return ! p->rip2; }
-*/
static inline void
rip_reset_tx_session(struct rip_proto *p, struct rip_iface *ifa)
@@ -211,8 +202,8 @@ rip_reset_tx_session(struct rip_proto *p, struct rip_iface *ifa)
}
/* rip.c */
-void rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *new);
-void rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_neighbor *from);
+void rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new);
+void rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from);
struct rip_neighbor * rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa);
void rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n);
void rip_show_interfaces(struct proto *P, char *iff);
@@ -220,7 +211,7 @@ void rip_show_neighbors(struct proto *P, char *iff);
/* packets.c */
void rip_send_request(struct rip_proto *p, struct rip_iface *ifa);
-void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed);
+void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed);
int rip_open_socket(struct rip_iface *ifa);