diff options
Diffstat (limited to 'proto/rip')
-rw-r--r-- | proto/rip/Makefile | 9 | ||||
-rw-r--r-- | proto/rip/config.Y | 32 | ||||
-rw-r--r-- | proto/rip/packets.c | 106 | ||||
-rw-r--r-- | proto/rip/rip.c | 233 | ||||
-rw-r--r-- | proto/rip/rip.h | 51 |
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); |