summaryrefslogtreecommitdiff
path: root/proto/rip/rip.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/rip/rip.c')
-rw-r--r--proto/rip/rip.c221
1 files changed, 127 insertions, 94 deletions
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 6ca7a6b5..ab0e3f4b 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -78,6 +78,7 @@
#include <stdlib.h>
#include "rip.h"
+#include "lib/macro.h"
static inline void rip_lock_neighbor(struct rip_neighbor *n);
@@ -88,6 +89,7 @@ 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);
+static struct ea_class ea_rip_metric, ea_rip_tag, ea_rip_from;
/*
* RIP routes
@@ -149,91 +151,94 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt)
{
/* Update */
- rta a0 = {
- .pref = p->p.main_channel->preference,
- .source = RTS_RIP,
- .scope = SCOPE_UNIVERSE,
- .dest = RTD_UNICAST,
+ struct {
+ ea_list l;
+ eattr a[3];
+ } ea_block = {
+ .l.count = ARRAY_SIZE(ea_block.a),
+ .a = {
+ EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference),
+ EA_LITERAL_EMBEDDED(&ea_gen_source, 0, RTS_RIP),
+ EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt->metric),
+ },
};
- u8 rt_metric = rt->metric;
+ ea_list *ea = &ea_block.l;
+
u16 rt_tag = rt->tag;
+ struct iface *rt_from = NULL;
if (p->ecmp)
{
/* ECMP route */
- struct nexthop *nhs = NULL;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
+ if (rip_valid_rte(rt))
+ num++;
+
+ struct nexthop_adata *nhad = (struct nexthop_adata *) tmp_alloc_adata((num+1) * sizeof(struct nexthop));
+ struct nexthop *nh = &nhad->nh;
+
+ for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
{
if (!rip_valid_rte(rt))
- continue;
+ continue;
- struct nexthop *nh = allocz(sizeof(struct nexthop));
+ *nh = (struct nexthop) {
+ .gw = rt->next_hop,
+ .iface = rt->from->ifa->iface,
+ .weight = rt->from->ifa->cf->ecmp_weight,
+ };
- nh->gw = rt->next_hop;
- nh->iface = rt->from->ifa->iface;
- nh->weight = rt->from->ifa->cf->ecmp_weight;
+ if (!rt_from)
+ rt_from = rt->from->ifa->iface;
- nexthop_insert(&nhs, nh);
- num++;
+ nh = NEXTHOP_NEXT(nh);
if (rt->tag != rt_tag)
rt_tag = 0;
}
- a0.nh = *nhs;
+ nhad->ad.length = ((void *) nh - (void *) nhad->ad.data);
+
+ ea_set_attr(&ea,
+ EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0,
+ &(nexthop_sort(nhad, tmp_linpool)->ad)));
}
else
{
/* Unipath route */
- a0.from = rt->from->nbr->addr;
- a0.nh.gw = rt->next_hop;
- a0.nh.iface = rt->from->ifa->iface;
+ rt_from = rt->from->ifa->iface;
+
+ struct nexthop_adata nhad = {
+ .nh.gw = rt->next_hop,
+ .nh.iface = rt->from->ifa->iface,
+ };
+
+ ea_set_attr_data(&ea, &ea_gen_nexthop, 0,
+ &nhad.ad.data, sizeof nhad - sizeof nhad.ad);
+ ea_set_attr_data(&ea, &ea_gen_from, 0, &rt->from->nbr->addr, sizeof(ip_addr));
}
- struct {
- ea_list l;
- eattr e[3];
- struct rip_iface_adata riad;
- } ea_block = {
- .l = { .count = 3, },
- .e = {
- {
- .id = EA_RIP_METRIC,
- .type = EAF_TYPE_INT,
- .u.data = rt_metric,
- },
- {
- .id = EA_RIP_TAG,
- .type = EAF_TYPE_INT,
- .u.data = rt_tag,
- },
- {
- .id = EA_RIP_FROM,
- .type = EAF_TYPE_IFACE,
- .u.ptr = &ea_block.riad.ad,
- }
- },
- .riad = {
- .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) },
- .iface = a0.nh.iface,
- },
- };
+ ea_set_attr_u32(&ea, &ea_rip_tag, 0, rt_tag);
- a0.eattrs = &ea_block.l;
+ struct rip_iface_adata riad = {
+ .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) },
+ .iface = rt_from,
+ };
+ ea_set_attr(&ea,
+ EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &riad.ad));
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a, p->p.main_source);
+ rte e0 = {
+ .attrs = ea,
+ .src = p->p.main_source,
+ };
- rte_update(&p->p, en->n.addr, e);
+ rte_update(p->p.main_channel, en->n.addr, &e0, p->p.main_source);
}
else
- {
- /* Withdraw */
- rte_update(&p->p, en->n.addr, NULL);
- }
+ rte_update(p->p.main_channel, en->n.addr, NULL, p->p.main_source);
}
/**
@@ -328,8 +333,8 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
* it into our data structures.
*/
static void
-rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
- struct rte *old UNUSED)
+rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, struct rte *new,
+ const struct rte *old UNUSED)
{
struct rip_proto *p = (struct rip_proto *) P;
struct rip_entry *en;
@@ -338,22 +343,22 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
if (new)
{
/* Update */
- u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0);
- u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1);
- const eattr *rie = ea_find(new->attrs->eattrs, EA_RIP_FROM);
+ u32 rt_tag = ea_get_int(new->attrs, &ea_rip_tag, 0);
+ u32 rt_metric = ea_get_int(new->attrs, &ea_rip_metric, 1);
+ const eattr *rie = ea_find(new->attrs, &ea_rip_from);
struct iface *rt_from = rie ? ((struct rip_iface_adata *) rie->u.ptr)->iface : NULL;
if (rt_metric > p->infinity)
{
log(L_WARN "%s: Invalid rip_metric value %u for route %N",
- p->p.name, rt_metric, net->n.addr);
+ p->p.name, rt_metric, net);
rt_metric = p->infinity;
}
if (rt_tag > 0xffff)
{
log(L_WARN "%s: Invalid rip_tag value %u for route %N",
- p->p.name, rt_tag, net->n.addr);
+ p->p.name, rt_tag, net);
rt_metric = p->infinity;
rt_tag = 0;
}
@@ -365,21 +370,27 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
* collection.
*/
- en = fib_get(&p->rtable, net->n.addr);
+ en = fib_get(&p->rtable, net);
old_metric = en->valid ? en->metric : -1;
en->valid = RIP_ENTRY_VALID;
en->metric = rt_metric;
en->tag = rt_tag;
- en->from = (new->src->proto == P) ? rt_from : NULL;
- en->iface = new->attrs->nh.iface;
- en->next_hop = new->attrs->nh.gw;
+ en->from = (new->src->owner == &P->sources) ? rt_from : NULL;
+
+ eattr *nhea = ea_find(new->attrs, &ea_gen_nexthop);
+ if (nhea)
+ {
+ struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
+ en->iface = nhad->nh.iface;
+ en->next_hop = nhad->nh.gw;
+ }
}
else
{
/* Withdraw */
- en = fib_find(&p->rtable, net->n.addr);
+ en = fib_find(&p->rtable, net);
if (!en || en->valid != RIP_ENTRY_VALID)
return;
@@ -1101,22 +1112,31 @@ rip_reload_routes(struct channel *C)
rip_kick_timer(p);
}
+static struct rte_owner_class rip_rte_owner_class;
+
+static inline struct rip_proto *
+rip_rte_proto(struct rte *rte)
+{
+ return (rte->src->owner->class == &rip_rte_owner_class) ?
+ SKIP_BACK(struct rip_proto, p.sources, rte->src->owner) : NULL;
+}
+
static int
rip_rte_better(struct rte *new, struct rte *old)
{
ASSERT_DIE(new->src == old->src);
- struct rip_proto *p = (struct rip_proto *) new->src->proto;
+ struct rip_proto *p = rip_rte_proto(new);
- u32 new_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, p->infinity);
- u32 old_metric = ea_get_int(old->attrs->eattrs, EA_RIP_METRIC, p->infinity);
+ u32 new_metric = ea_get_int(new->attrs, &ea_rip_metric, p->infinity);
+ u32 old_metric = ea_get_int(old->attrs, &ea_rip_metric, p->infinity);
return new_metric < old_metric;
}
static u32
-rip_rte_igp_metric(struct rte *rt)
+rip_rte_igp_metric(const rte *rt)
{
- return ea_get_int(rt->attrs->eattrs, EA_RIP_METRIC, IGP_METRIC_UNKNOWN);
+ return ea_get_int(rt->attrs, &ea_rip_metric, IGP_METRIC_UNKNOWN);
}
static void
@@ -1140,8 +1160,7 @@ rip_init(struct proto_config *CF)
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
P->reload_routes = rip_reload_routes;
- P->rte_better = rip_rte_better;
- P->rte_igp_metric = rip_rte_igp_metric;
+ P->sources.class = &rip_rte_owner_class;
return P;
}
@@ -1216,33 +1235,38 @@ rip_reconfigure(struct proto *P, struct proto_config *CF)
static void
rip_get_route_info(rte *rte, byte *buf)
{
- struct rip_proto *p = (struct rip_proto *) rte->src->proto;
- u32 rt_metric = ea_get_int(rte->attrs->eattrs, EA_RIP_METRIC, p->infinity);
- u32 rt_tag = ea_get_int(rte->attrs->eattrs, EA_RIP_TAG, 0);
+ struct rip_proto *p = rip_rte_proto(rte);
+ u32 rt_metric = ea_get_int(rte->attrs, &ea_rip_metric, p->infinity);
+ u32 rt_tag = ea_get_int(rte->attrs, &ea_rip_tag, 0);
- buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rt_metric);
+ buf += bsprintf(buf, " (%d/%d)", rt_get_preference(rte), rt_metric);
if (rt_tag)
bsprintf(buf, " [%04x]", rt_tag);
}
-static int
-rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
+static void
+rip_tag_format(const eattr *a, byte *buf, uint buflen)
{
- switch (a->id)
- {
- case EA_RIP_METRIC:
- bsprintf(buf, "metric: %d", a->u.data);
- return GA_FULL;
+ bsnprintf(buf, buflen, "%04x", a->u.data);
+}
- case EA_RIP_TAG:
- bsprintf(buf, "tag: %04x", a->u.data);
- return GA_FULL;
+static struct ea_class ea_rip_metric = {
+ .name = "rip_metric",
+ .type = T_INT,
+};
- default:
- return GA_UNKNOWN;
- }
-}
+static struct ea_class ea_rip_tag = {
+ .name = "rip_tag",
+ .type = T_INT,
+ .format = rip_tag_format,
+};
+
+static struct ea_class ea_rip_from = {
+ .name = "rip_from",
+ .type = T_IFACE,
+ .readonly = 1,
+};
void
rip_show_interfaces(struct proto *P, const char *iff)
@@ -1343,10 +1367,15 @@ rip_dump(struct proto *P)
}
+static struct rte_owner_class rip_rte_owner_class = {
+ .get_route_info = rip_get_route_info,
+ .rte_better = rip_rte_better,
+ .rte_igp_metric = rip_rte_igp_metric,
+};
+
struct protocol proto_rip = {
.name = "RIP",
.template = "rip%d",
- .class = PROTOCOL_RIP,
.preference = DEF_PREF_RIP,
.channel_mask = NB_IP,
.proto_size = sizeof(struct rip_proto),
@@ -1357,12 +1386,16 @@ struct protocol proto_rip = {
.start = rip_start,
.shutdown = rip_shutdown,
.reconfigure = rip_reconfigure,
- .get_route_info = rip_get_route_info,
- .get_attr = rip_get_attr
};
void
rip_build(void)
{
proto_build(&proto_rip);
+
+ EA_REGISTER_ALL(
+ &ea_rip_metric,
+ &ea_rip_tag,
+ &ea_rip_from
+ );
}