Commit 2a95e633 by Michal 'vorner' Vaner Committed by Ondřej Zajíček

RAdv: Support for more specific routes (RFC 4191)

The patch implements Default Router Preferences and More-Specific Routes
(RFC 4191) for RAdv protocol, allowing to announce router preference and
more specific routes in router advertisements. Routes can be exported to
RAdv like to regular routing protocols.

Some cleanups, bugfixes and other changes done by Ondrej Zajicek.
parent 5a8b1fb0
......@@ -168,6 +168,7 @@ void val_format(struct f_val v, buffer *buf);
#define T_ENUM_RTC 0x33
#define T_ENUM_RTD 0x34
#define T_ENUM_ROA 0x35
#define T_ENUM_RA_PREFERENCE 0x36
/* new enums go here */
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
......
......@@ -430,7 +430,8 @@ typedef struct eattr {
#define EAP_OSPF 3 /* OSPF */
#define EAP_KRT 4 /* Kernel route attributes */
#define EAP_BABEL 5 /* Babel attributes */
#define EAP_MAX 6
#define EAP_RADV 6 /* Router advertisment attributes */
#define EAP_MAX 7
#define EA_CODE(proto,id) (((proto) << 8) | (id))
#define EA_PROTO(ea) ((ea) >> 8)
......
......@@ -30,7 +30,10 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, RETRANS,
TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH)
LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE,
ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME)
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
%type<i> radv_mult radv_sensitive radv_preference
......@@ -45,6 +48,8 @@ radv_proto_start: proto_start RADV
init_list(&RADV_CFG->pref_list);
init_list(&RADV_CFG->rdnss_list);
init_list(&RADV_CFG->dnssl_list);
RADV_CFG->route_lifetime = DEFAULT_VALID_LIFETIME;
RADV_CFG->route_linger_time = DEFAULT_LINGER_TIME;
};
radv_proto_item:
......@@ -58,6 +63,16 @@ radv_proto_item:
RADV_CFG->trigger_pxlen = $2.len;
RADV_CFG->trigger_valid = 1;
}
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
| ROUTE LIFETIME expr radv_sensitive {
RADV_CFG->route_lifetime = $3;
if ($4 != -1) RADV_CFG->route_lifetime_sensitive = $4;
}
| ROUTE LINGER TIME expr {
RADV_CFG->route_linger_time = $4;
if (($4 < 0) || ($4 > 3600))
cf_error("Linger time must be in range 0-3600");
}
;
radv_proto_opts:
......@@ -168,12 +183,10 @@ radv_prefix_item:
| AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; }
| VALID LIFETIME expr radv_sensitive {
RADV_PREFIX->valid_lifetime = $3;
if ($3 < 0) cf_error("Valid lifetime must be 0 or positive");
if ($4 != -1) RADV_PREFIX->valid_lifetime_sensitive = $4;
}
| PREFERRED LIFETIME expr radv_sensitive {
RADV_PREFIX->preferred_lifetime = $3;
if ($3 < 0) cf_error("Preferred lifetime must be 0 or positive");
if ($4 != -1) RADV_PREFIX->preferred_lifetime_sensitive = $4;
}
;
......@@ -303,6 +316,9 @@ radv_sensitive:
| SENSITIVE bool { $$ = $2; }
;
CF_ADDTO(dynamic_attr, RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); })
CF_ADDTO(dynamic_attr, RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); })
CF_CODE
CF_END
......@@ -26,6 +26,7 @@ struct radv_ra_packet
#define OPT_PREFIX 3
#define OPT_MTU 5
#define OPT_ROUTE 24
#define OPT_RDNSS 25
#define OPT_DNSSL 31
......@@ -52,6 +53,15 @@ struct radv_opt_mtu
u32 mtu;
};
struct radv_opt_route {
u8 type;
u8 length;
u8 pxlen;
u8 flags;
u32 lifetime;
u8 prefix[];
};
struct radv_opt_rdnss
{
u8 type;
......@@ -71,6 +81,41 @@ struct radv_opt_dnssl
};
static int
radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
char **buf, char *bufend)
{
struct radv_proto *p = ifa->ra;
struct radv_config *cf = (void *) p->p.cf;
u8 px_blocks = (rt->n.pxlen + 63) / 64;
u8 opt_len = 8 * (1 + px_blocks);
if (*buf + opt_len > bufend)
{
log(L_WARN, "%s: Too many RA options on interface %s",
p->p.name, ifa->iface->name);
return -1;
}
struct radv_opt_route *opt = (void *) *buf;
*buf += opt_len;
opt->type = OPT_ROUTE;
opt->length = 1 + px_blocks;
opt->pxlen = rt->n.pxlen;
opt->flags = rt->preference;
if (p->valid && (p->active || !cf->route_lifetime_sensitive) && rt->alive)
opt->lifetime = htonl(rt->lifetime_set ? rt->lifetime : cf->route_lifetime);
else
opt->lifetime = 0;
/* Copy the relevant part of the prefix */
ip6_addr px_addr = ip6_hton(rt->n.prefix);
memcpy(opt->prefix, &px_addr, 8 * px_blocks);
return 0;
}
static int
radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend)
{
struct radv_rdnss_config *rcf = HEAD(*rdnss_list);
......@@ -252,7 +297,7 @@ radv_prepare_ra(struct radv_iface *ifa)
pkt->code = 0;
pkt->checksum = 0;
pkt->current_hop_limit = ic->current_hop_limit;
pkt->router_lifetime = (p->active || !ic->default_lifetime_sensitive) ?
pkt->router_lifetime = (p->valid && (p->active || !ic->default_lifetime_sensitive)) ?
htons(ic->default_lifetime) : 0;
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
(ic->other_config ? OPT_RA_OTHER_CFG : 0) |
......@@ -292,13 +337,23 @@ radv_prepare_ra(struct radv_iface *ifa)
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
goto done;
if (p->fib_up)
{
FIB_WALK(&p->routes, rt)
{
if (radv_prepare_route(ifa, (struct radv_route *) rt, &buf, bufend) < 0)
goto done;
}
FIB_WALK_END;
}
done:
ifa->plen = buf - bufstart;
}
void
radv_send_ra(struct radv_iface *ifa, int shutdown)
radv_send_ra(struct radv_iface *ifa)
{
struct radv_proto *p = ifa->ra;
......@@ -306,19 +361,6 @@ radv_send_ra(struct radv_iface *ifa, int shutdown)
if (!ifa->plen)
radv_prepare_ra(ifa);
if (shutdown)
{
/*
* Modify router lifetime to 0, it is not restored because we suppose that
* the iface will be removed. The preference value also has to be zeroed.
* (RFC 4191 2.2: If router lifetime is 0, the preference value must be 0.)
*/
struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf;
pkt->router_lifetime = 0;
pkt->flags &= ~RA_PREF_MASK;
}
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
}
......
......@@ -54,6 +54,10 @@ struct radv_config
ip_addr trigger_prefix; /* Prefix of a trigger route, if defined */
u8 trigger_pxlen; /* Pxlen of a trigger route, if defined */
u8 trigger_valid; /* Whether a trigger route is defined */
u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */
u32 route_lifetime; /* Lifetime for the RFC 4191 routes */
u32 route_lifetime_sensitive; /* Whether route_lifetime depends on trigger */
u32 route_linger_time; /* For how long we advertise dead routes with lifetime = 0 */
};
struct radv_iface_config
......@@ -117,12 +121,32 @@ struct radv_dnssl_config
char *domain; /* Domain for DNS search list, in processed form */
};
/*
* One more specific route as per RFC 4191.
*
* Note that it does *not* contain the next hop field. The next hop is always
* the router sending the advertisment and the more specific route only allows
* overriding the preference of the route.
*/
struct radv_route
{
struct fib_node n;
u32 lifetime; /* Lifetime from an attribute */
u8 lifetime_set; /* Is the lifetime set by an attribute? */
u8 preference; /* Preference of the route, RA_PREF_* */
u8 alive;
bird_clock_t expires; /* Time to remove when !alive */
};
struct radv_proto
{
struct proto p;
list iface_list; /* List of active ifaces */
u8 valid; /* Router is valid for forwarding, used for shutdown */
u8 active; /* Whether radv is active w.r.t. triggers */
u8 fib_up; /* FIB table (routes) is initialized */
struct fib routes; /* FIB table of specific routes (struct radv_route) */
bird_clock_t prune_time; /* Next time of route table pruning */
};
struct radv_prefix /* One prefix we advertise */
......@@ -147,7 +171,7 @@ struct radv_iface
struct ifa *addr; /* Link-local address of iface */
struct pool *pool; /* A pool for interface-specific things */
list prefixes; /* The prefixes we advertise (struct radv_prefix) */
bird_clock_t prefix_expires; /* When the soonest prefix expires (0 = none dead) */
bird_clock_t prune_time; /* Next time of prefix list pruning */
timer *timer;
struct object_lock *lock;
......@@ -161,7 +185,6 @@ struct radv_iface
#define RA_EV_INIT 1 /* Switch to initial mode */
#define RA_EV_CHANGE 2 /* Change of options or prefixes */
#define RA_EV_RS 3 /* Received RS */
#define RA_EV_GC 4 /* Internal garbage collection of prefixes */
/* Default Router Preferences (RFC 4191) */
#define RA_PREF_LOW 0x18
......@@ -169,6 +192,9 @@ struct radv_iface
#define RA_PREF_HIGH 0x08
#define RA_PREF_MASK 0x18
/* Attributes */
#define EA_RA_PREFERENCE EA_CODE(EAP_RADV, 0)
#define EA_RA_LIFETIME EA_CODE(EAP_RADV, 1)
#ifdef LOCAL_DEBUG
#define RADV_FORCE_DEBUG 1
......@@ -184,7 +210,7 @@ void radv_iface_notify(struct radv_iface *ifa, int event);
/* packets.c */
int radv_process_domain(struct radv_dnssl_config *cf);
void radv_send_ra(struct radv_iface *ifa, int shutdown);
void radv_send_ra(struct radv_iface *ifa);
int radv_sk_open(struct radv_iface *ifa);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment