Commit 3646ba98 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Merge remote-tracking branch 'remotes/theo/tobast/v6tethered-reimplem' into v4viav6

parents f82a10e9 a4aebc71
......@@ -22,6 +22,7 @@ This file lists people who have contributed to babeld (in alphabetical order):
Matthieu Boutier <boutier at irif dot fr>
Sawssen Hadded <saw dot hadded at gmail dot com>
Stephane Glondu <steph at glondu dot net>
Théophile Bastian <theophile dot bastian at ens dot fr>
Thomas Petazzoni <thomas dot petazzoni at free-electrons dot com>
Toke Høiland-Jørgensen <toke at toke dot dk>
Vincent Gross <dermiste at screwball-coders dot net>
......
......@@ -63,6 +63,7 @@ int debug = 0;
int link_detect = 0;
int all_wireless = 0;
int has_ipv6_subtrees = 0;
int has_v4ov6 = 0;
int default_wireless_hello_interval = -1;
int default_wired_hello_interval = -1;
int resend_delay = -1;
......@@ -151,6 +152,7 @@ main(int argc, char **argv)
protocol_port = 6696;
change_smoothing_half_life(4);
has_ipv6_subtrees = kernel_has_ipv6_subtrees();
has_v4ov6 = kernel_has_v4ov6();
while(1) {
opt = getopt(argc, argv,
......
......@@ -92,6 +92,7 @@ extern const char *logfile, *pidfile, *state_file;
extern int link_detect;
extern int all_wireless;
extern int has_ipv6_subtrees;
extern int has_v4ov6;
extern unsigned char myid[8];
extern int have_id;
......
......@@ -200,6 +200,11 @@ This specifies whether to use native source-specific IPv6 forwarding
rather than multiple routing tables. The default is chosen automatically
depending on the kernel version.
.TP
.BR v4-over-v6 " {" true | false }
This specifies whether to use v4-over-v6 routes (IPv4 routes with an IPv6
next-hop). This should not be enabled unless your kernel supports it. The
default is chosen automatically depending on the kernel version.
.TP
.BI debug " level"
This specifies the debugging level, and is equivalent to the command-line
option
......
......@@ -1029,6 +1029,7 @@ parse_option(int c, gnc_t gnc, void *closure, char *token)
strcmp(token, "daemonise") == 0 ||
strcmp(token, "skip-kernel-setup") == 0 ||
strcmp(token, "ipv6-subtrees") == 0 ||
strcmp(token, "v4-over-v6") == 0 ||
strcmp(token, "reflect-kernel-metric") == 0) {
int b;
c = getbool(c, &b, gnc, closure);
......@@ -1045,6 +1046,8 @@ parse_option(int c, gnc_t gnc, void *closure, char *token)
skip_kernel_setup = b;
else if(strcmp(token, "ipv6-subtrees") == 0)
has_ipv6_subtrees = b;
else if(strcmp(token, "v4-over-v6") == 0)
has_v4ov6 = b;
else if(strcmp(token, "reflect-kernel-metric") == 0)
reflect_kernel_metric = b;
else
......
......@@ -95,3 +95,10 @@ int gettime(struct timeval *tv);
int read_random_bytes(void *buf, int len);
int kernel_older_than(const char *sysname, int version, int sub_version);
int kernel_has_ipv6_subtrees(void);
int kernel_has_v4ov6(void);
int add_rule(int prio, const unsigned char *src_prefix, int src_plen,
int table);
int flush_rule(int prio, int family);
int change_rule(int new_prio, int old_prio, const unsigned char *src, int plen,
int table);
......@@ -943,6 +943,14 @@ kernel_has_ipv6_subtrees(void)
return (kernel_older_than("Linux", 3, 11) == 0);
}
int
kernel_has_v4ov6(void)
{
/* v4-over-v6 was introduced in Linux by commit
d15662682db232da77136cd348f4c9df312ca6f9 first released as 5.2 */
return (kernel_older_than("Linux", 5, 2) == 0);
}
int
kernel_route(int operation, int table,
const unsigned char *dest, unsigned short plen,
......@@ -956,7 +964,7 @@ kernel_route(int operation, int table,
struct rtmsg *rtm;
struct rtattr *rta;
int len = sizeof(buf.raw);
int rc, ipv4, use_src = 0;
int rc, ipv4, is_v4_over_v6, use_src = 0;
if(!nl_setup) {
fprintf(stderr,"kernel_route: netlink not initialized.\n");
......@@ -978,8 +986,7 @@ kernel_route(int operation, int table,
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(dest)) {
if(!v4mapped(gate) ||
!v4mapped(src)) {
if(!v4mapped(src)) {
errno = EINVAL;
return -1;
}
......@@ -1018,7 +1025,8 @@ kernel_route(int operation, int table,
}
ipv4 = v4mapped(gate);
ipv4 = v4mapped(dest);
is_v4_over_v6 = ipv4 && !v4mapped(gate);
use_src = !is_default(src, src_plen);
if(use_src) {
if(ipv4 || !has_ipv6_subtrees) {
......@@ -1095,22 +1103,31 @@ kernel_route(int operation, int table,
*(int*)RTA_DATA(rta) = ifindex;
#define ADD_IPARG(type, addr) \
do if(ipv4) { \
do { \
rta = RTA_NEXT(rta, len); \
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); \
rta->rta_type = type; \
if(v4mapped(addr)) { \
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); \
memcpy(RTA_DATA(rta), addr + 12, sizeof(struct in_addr)); \
} else { \
rta = RTA_NEXT(rta, len); \
if(type == RTA_VIA) { \
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr) + 2); \
*((sa_family_t*) RTA_DATA(rta)) = AF_INET6; \
memcpy(RTA_DATA(rta) + 2, addr, sizeof(struct in6_addr)); \
} else { \
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); \
rta->rta_type = type; \
memcpy(RTA_DATA(rta), addr, sizeof(struct in6_addr)); \
} \
} \
} while (0)
if(is_v4_over_v6)
ADD_IPARG(RTA_VIA, gate);
else
ADD_IPARG(RTA_GATEWAY, gate);
if(pref_src)
ADD_IPARG(RTA_PREFSRC, pref_src);
#undef ADD_IPARG
} else {
*(int*)RTA_DATA(rta) = -1;
......
......@@ -395,6 +395,12 @@ kernel_has_ipv6_subtrees(void)
return 0;
}
int
kernel_has_v4ov6(void)
{
return 0;
}
int
kernel_route(int operation, int table,
const unsigned char *dest, unsigned short plen,
......
......@@ -56,7 +56,7 @@ struct timeval seqno_time = {0, 0};
static int
known_ae(int ae)
{
return ae <= 3;
return ae <= AE_IPV6_LOCAL || ae == AE_V4OV6;
}
/* Parse a network prefix, encoded in the somewhat baroque compressed
......@@ -83,10 +83,11 @@ network_prefix(int ae, int plen, unsigned int omitted,
memset(prefix, 0, 16);
switch(ae) {
case 0:
case AE_WILDCARD:
ret = 0;
break;
case 1:
case AE_IPV4:
case AE_V4OV6:
if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
return -1;
memcpy(prefix, v4prefix, 12);
......@@ -97,7 +98,7 @@ network_prefix(int ae, int plen, unsigned int omitted,
if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted);
ret = pb - omitted;
break;
case 2:
case AE_IPV6:
if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1;
if(omitted) {
if(dp == NULL || v4mapped(dp)) return -1;
......@@ -106,7 +107,7 @@ network_prefix(int ae, int plen, unsigned int omitted,
if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
ret = pb - omitted;
break;
case 3:
case AE_IPV6_LOCAL:
if(pb > 8 && len < pb - 8) return -1;
prefix[0] = 0xfe;
prefix[1] = 0x80;
......@@ -117,7 +118,8 @@ network_prefix(int ae, int plen, unsigned int omitted,
return -1;
}
normalize_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen);
normalize_prefix(p_r, prefix,
plen < 0 ? 128 : ae_is_v4(ae) ? plen + 96 : plen);
return ret;
}
......@@ -175,7 +177,7 @@ parse_update_subtlv(struct interface *ifp, int metric, int ae,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
if(ae_is_v4(ae))
*src_plen = a[i + 2] + 96;
else
*src_plen = a[i + 2];
......@@ -341,7 +343,7 @@ parse_request_subtlv(int ae, const unsigned char *a, int alen,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
if(ae_is_v4(ae))
*src_plen = a[i + 2] + 96;
else
*src_plen = a[i + 2];
......@@ -392,7 +394,7 @@ parse_seqno_request_subtlv(int ae, const unsigned char *a, int alen,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
if(ae_is_v4(ae))
(*src_plen) += 96;
} else {
debugf("Received unknown%s Route Request sub-TLV %d.\n",
......@@ -591,9 +593,10 @@ parse_packet(const unsigned char *from, struct interface *ifp,
int bodylen;
struct neighbour *neigh = NULL;
int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0,
have_v4ov6_prefix = 0,
have_v4_nh = 0, have_v6_nh = 0;
unsigned char router_id[8], v4_prefix[16], v6_prefix[16],
v4_nh[16], v6_nh[16];
v4ov6_prefix[16], v4_nh[16], v6_nh[16];
int have_hello_rtt = 0;
/* Content of the RTT sub-TLV on IHU messages. */
unsigned int hello_send_us = 0, hello_rtt_receive_time = 0;
......@@ -745,7 +748,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
txcost, interval,
format_address(from), ifp->name,
format_address(address));
if(message[2] == 0 || interface_ll_address(ifp, address)) {
if(message[2] == AE_WILDCARD ||
interface_ll_address(ifp, address)) {
int changed;
rc = parse_ihu_subtlv(message + 8 + rc, len - 6 - rc,
&hello_send_us, &hello_rtt_receive_time,
......@@ -800,12 +804,21 @@ parse_packet(const unsigned char *from, struct interface *ifp,
debugf("Received nh %s (%d) from %s on %s.\n",
format_address(nh), message[2],
format_address(from), ifp->name);
if(message[2] == 1) {
switch(message[2]) {
case AE_IPV4:
memcpy(v4_nh, nh, 16);
have_v4_nh = 1;
} else {
break;
case AE_IPV6:
case AE_IPV6_LOCAL:
memcpy(v6_nh, nh, 16);
have_v6_nh = 1;
break;
case AE_V4OV6:
goto done;
default:
/* We should have guards against this before this point. */
goto fail;
}
rc = parse_other_subtlv(message + 4 + rc, len - 2 - rc);
if(rc < 0)
......@@ -819,7 +832,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
int rc, parsed_len, is_ss;
if(len < 10) {
if(len < 2 || message[3] & 0x80)
have_v4_prefix = have_v6_prefix = 0;
have_v4_prefix = have_v6_prefix = have_v4ov6_prefix = 0;
goto fail;
}
if(!known_ae(message[2])) {
......@@ -827,18 +840,31 @@ parse_packet(const unsigned char *from, struct interface *ifp,
message[2]);
goto done;
}
if(message[2] == AE_V4OV6 && !has_v4ov6) {
/* We can safely ignore the prefix update that might come
alongside with this TLV, since we ignore every v4-over-v6
TLVs */
debugf("Ignoring v4-over-v6 route (unsupported).\n");
goto done;
}
DO_NTOHS(interval, message + 6);
DO_NTOHS(seqno, message + 8);
DO_NTOHS(metric, message + 10);
if(message[5] == 0 ||
(message[2] == 1 ? have_v4_prefix : have_v6_prefix))
(message[2] == AE_IPV4 ? have_v4_prefix :
message[2] == AE_IPV6 ? have_v6_prefix :
message[2] == AE_V4OV6 ? have_v4ov6_prefix :
0))
rc = network_prefix(message[2], message[4], message[5],
message + 12,
message[2] == 1 ? v4_prefix : v6_prefix,
(message[2] == AE_IPV4 ? v4_prefix :
message[2] == AE_IPV6 ? v6_prefix :
message[2] == AE_V4OV6 ? v4ov6_prefix :
NULL),
len - 10, prefix);
else
rc = -1;
if(message[2] == 1) {
if(ae_is_v4(message[2])) {
v4tov6(src_prefix, zeroes);
src_plen = 96;
} else {
......@@ -847,24 +873,36 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
if(rc < 0) {
if(message[3] & 0x80)
have_v4_prefix = have_v6_prefix = 0;
have_v4_prefix = have_v6_prefix = have_v4ov6_prefix = 0;
goto fail;
}
parsed_len = 10 + rc;
plen = message[4] + (message[2] == 1 ? 96 : 0);
plen = message[4] + (ae_is_v4(message[2]) ? 96 : 0);
if(message[3] & 0x80) {
if(message[2] == 1) {
switch(message[2]) {
case AE_IPV4:
memcpy(v4_prefix, prefix, 16);
have_v4_prefix = 1;
} else {
break;
case AE_IPV6:
memcpy(v6_prefix, prefix, 16);
have_v6_prefix = 1;
break;
case AE_V4OV6:
memcpy(v4ov6_prefix, prefix, 16);
have_v4ov6_prefix = 1;
break;
default:
debugf("Received default prefix update with invalid "
"AE %d.\n",
message[2]);
break;
}
}
if(message[3] & 0x40) {
if(message[2] == 1) {
if(ae_is_v4(message[2])) {
memset(router_id, 0, 4);
memcpy(router_id + 4, prefix + 12, 4);
} else {
......@@ -872,7 +910,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
have_router_id = 1;
}
if(metric < INFINITY && !have_router_id && message[2] != 0) {
if(metric < INFINITY &&
!have_router_id &&
message[2] != AE_WILDCARD) {
fprintf(stderr, "Received prefix with no router id.\n");
goto fail;
}
......@@ -881,7 +921,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
(message[3] & 0x40) ? "/id" : "",
format_prefix(prefix, plen),
format_address(from), ifp->name);
if(message[2] == 1) {
if(message[2] == AE_IPV4) {
if(have_v4_nh) {
nh = v4_nh;
} else {
......@@ -902,7 +942,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(rc < 0)
goto done;
if(message[2] == 0) {
if(message[2] == AE_WILDCARD) {
if(metric < 0xFFFF) {
fprintf(stderr,
"Received wildcard update with finite metric.\n");
......@@ -926,7 +966,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
is_ss ? format_prefix(src_prefix, src_plen) : "",
format_address(from), ifp->name);
if(message[2] == 1) {
if(message[2] == AE_IPV4) {
if(!ifp->ipv4)
goto done;
}
......@@ -947,8 +987,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
rc = network_prefix(message[2], message[3], 0,
message + 4, NULL, len - 2, prefix);
if(rc < 0) goto fail;
plen = message[3] + (message[2] == 1 ? 96 : 0);
if(message[2] == 1) {
plen = message[3] + (ae_is_v4(message[2]) ? 96 : 0);
if(ae_is_v4(message[2])) {
v4tov6(src_prefix, zeroes);
src_plen = 96;
} else {
......@@ -960,7 +1000,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(rc < 0)
goto done;
is_ss = !is_default(src_prefix, src_plen);
if(message[2] == 0) {
if(message[2] == AE_WILDCARD) {
if(is_ss) {
/* Wildcard requests don't carry a source prefix. */
fprintf(stderr,
......@@ -982,7 +1022,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
} else {
debugf("Received request for dst %s%s%s from %s on %s.\n",
message[2] == 0 ? "" : format_prefix(prefix, plen),
message[2] == AE_WILDCARD ?
"" : format_prefix(prefix, plen),
is_ss ? " src " : "",
is_ss ? format_prefix(src_prefix, src_plen) : "",
format_address(from), ifp->name);
......@@ -1002,7 +1043,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
rc = network_prefix(message[2], message[3], 0,
message + 16, NULL, len - 14, prefix);
if(rc < 0) goto fail;
if(message[2] == 1) {
if(ae_is_v4(message[2])) {
v4tov6(src_prefix, zeroes);
src_plen = 96;
} else {
......@@ -1015,7 +1056,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(rc < 0)
goto done;
is_ss = !is_default(src_prefix, src_plen);
plen = message[3] + (message[2] == 1 ? 96 : 0);
plen = message[3] + (ae_is_v4(message[2]) ? 96 : 0);
debugf("Received request (%d) for dst %s%s%s from %s on "
"%s (%s, %d).\n",
message[6],
......@@ -1400,7 +1441,7 @@ really_buffer_update(struct buffered *buf, struct interface *ifp,
unsigned char *channels, int channels_len)
{
int add_metric, v4, real_plen, real_src_plen;
int omit, spb, channels_size, len;
int ae, omit, spb, channels_size, len;
const unsigned char *real_prefix, *real_src_prefix;
unsigned short flags = 0;
int is_ss = !is_default(src_prefix, src_plen);
......@@ -1424,24 +1465,28 @@ really_buffer_update(struct buffered *buf, struct interface *ifp,
v4 = plen >= 96 && v4mapped(prefix);
if(v4) {
if(!ifp->ipv4)
return;
omit = 0;
if(!ifp->ipv4) {
ae = AE_V4OV6;
} else {
ae = AE_IPV4;
if(!buf->have_nh ||
memcmp(buf->nh, ifp->ipv4, 4) != 0) {
start_message(buf, ifp, MESSAGE_NH, 6);
accumulate_byte(buf, 1);
accumulate_byte(buf, AE_IPV4);
accumulate_byte(buf, 0);
accumulate_bytes(buf, ifp->ipv4, 4);
end_message(buf, MESSAGE_NH, 6);
memcpy(&buf->nh, ifp->ipv4, 4);
buf->have_nh = 1;
}
}
omit = 0;
real_prefix = prefix + 12;
real_plen = plen - 96;
real_src_prefix = src_prefix + 12;
real_src_plen = src_plen - 96;
} else {
ae = AE_IPV6;
omit = 0;
if(buf->have_prefix) {
while(omit < plen / 8 &&
......@@ -1477,7 +1522,7 @@ really_buffer_update(struct buffered *buf, struct interface *ifp,
len += 3 + spb;
start_message(buf, ifp, MESSAGE_UPDATE, len);
accumulate_byte(buf, v4 ? 1 : 2);
accumulate_byte(buf, ae);
accumulate_byte(buf, flags);
accumulate_byte(buf, real_plen);
accumulate_byte(buf, omit);
......@@ -1856,7 +1901,7 @@ void
buffer_wildcard_retraction(struct buffered *buf, struct interface *ifp)
{
start_message(buf, ifp, MESSAGE_UPDATE, 10);
accumulate_byte(buf, 0);
accumulate_byte(buf, AE_WILDCARD);
accumulate_byte(buf, 0);
accumulate_byte(buf, 0);
accumulate_byte(buf, 0);
......@@ -1941,7 +1986,7 @@ buffer_ihu(struct buffered *buf, struct interface *ifp, unsigned short rxcost,
msglen = (ll ? 14 : 22) + (rtt_data ? 10 : 0);
start_message(buf, ifp, MESSAGE_IHU, msglen);
accumulate_byte(buf, ll ? 3 : 2);
accumulate_byte(buf, ll ? AE_IPV6_LOCAL : AE_IPV6);
accumulate_byte(buf, 0);
accumulate_short(buf, rxcost);
accumulate_short(buf, interval);
......@@ -2061,7 +2106,7 @@ send_request(struct buffered *buf, struct interface *ifp,
assert(!src_prefix);
debugf("sending request for any.\n");
start_message(buf, ifp, MESSAGE_REQUEST, 2);
accumulate_byte(buf, 0);
accumulate_byte(buf, AE_WILDCARD);
accumulate_byte(buf, 0);
end_message(buf, MESSAGE_REQUEST, 2);
return;
......@@ -2077,7 +2122,7 @@ send_request(struct buffered *buf, struct interface *ifp,
len = 2 + pb + (is_ss ? 3 + spb : 0);
start_message(buf, ifp, MESSAGE_REQUEST, len);
accumulate_byte(buf, v4 ? 1 : 2);
accumulate_byte(buf, v4 ? AE_IPV4 : AE_IPV6);
accumulate_byte(buf, v4 ? plen - 96 : plen);
if(v4)
accumulate_bytes(buf, prefix + 12, pb);
......@@ -2164,7 +2209,7 @@ send_multihop_request(struct buffered *buf, struct interface *ifp,
len = 6 + 8 + pb + (is_ss ? 3 + spb : 0);
start_message(buf, ifp, MESSAGE_MH_REQUEST, len);
accumulate_byte(buf, v4 ? 1 : 2);
accumulate_byte(buf, v4 ? AE_IPV4 : AE_IPV6);
accumulate_byte(buf, v4 ? plen - 96 : plen);
accumulate_short(buf, seqno);
accumulate_byte(buf, hop_count);
......
......@@ -47,6 +47,13 @@ THE SOFTWARE.
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
#define SUBTLV_SOURCE_PREFIX 128 /* Source-specific routing. */
/* Address encodings */
#define AE_WILDCARD 0
#define AE_IPV4 1
#define AE_IPV6 2
#define AE_IPV6_LOCAL 3
#define AE_V4OV6 4
extern unsigned short myseqno;
extern struct timeval seqno_time;
......
......@@ -502,6 +502,12 @@ v4tov6(unsigned char *dst, const unsigned char *src)
memcpy(dst + 12, src, 4);
}
int
ae_is_v4(int ae)
{
return ae == 1 || ae == 4;
}
int
daemonise()
{
......
......@@ -100,6 +100,7 @@ int wait_for_fd(int direction, int fd, int msecs);
int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure));
int linklocal(const unsigned char *address) ATTRIBUTE ((pure));
int v4mapped(const unsigned char *address) ATTRIBUTE ((pure));
int ae_is_v4(int ae) ATTRIBUTE ((pure));
void v4tov6(unsigned char *dst, const unsigned char *src);
int daemonise(void);
int set_src_prefix(unsigned char *src_addr, unsigned char *src_plen);
......
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