Skip to content

Commit

Permalink
Improve CLAT IPv6 address auto-generation logic
Browse files Browse the repository at this point in the history
In the case of there being more than one EUI-64 based IPv6 address on
the PLAT device, clatd will now pick the one which share the longest
common prefix length with the PLAT prefix when deciding which one to
base the auto-generated CLAT IPv6 address on. This should avoid
accidentally ending up with a ULA-based CLAT IPv6 address when better
alternatives exist.

Resolves #1.
  • Loading branch information
toreanderson committed Mar 22, 2014
1 parent 0f5e885 commit 7e35aa5
Showing 1 changed file with 35 additions and 16 deletions.
51 changes: 35 additions & 16 deletions clatd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use strict;
use Net::IP;

my $VERSION = "1.0";
my $VERSION = "1.1";

#
# Populate the global config hash with the default values
Expand Down Expand Up @@ -436,6 +436,17 @@ sub get_clat_v6_addr {
if(!$plat_dev) {
err("get_clat_v6_addr(): No PLAT device to work with");
}

# In case there are more than one EUI-64-based addresses on the plat device,
# we'll need the plat prefix as an bigint in order to find which of those
# addresses share the longest common prefix. We'll prefer to use that one.
my $plat_prefix_int = Net::IP->new(cfg("plat-prefix"), 6)->intip();
if(!$plat_prefix_int) {
err("Failed to convert plat prefix to bigint");
}
my $ip; # will contain the best candidate ip in bigint format
my $best_score;

p("Attempting to derive a CLAT IPv6 address from a EUI-64 address on ",
"'$plat_dev'");
open(my $fd, '-|', cfg("cmd-ip"), qw(-6 address list scope global dev),
Expand All @@ -446,25 +457,33 @@ sub get_clat_v6_addr {
my $candidate = $1;
next unless(is_modified_eui64($candidate));
d2("Saw EUI-64 based address: $candidate");
my $ip = Net::IP->new($candidate, 6) or next;
$ip = $ip->intip();

# First clear the middle 0xfffe bits of the interface ID
my $mask = Net::IP->new("ffff:ffff:ffff:ffff:ffff:ff00:00ff:ffff");
$mask = $mask->intip();
$ip &= $mask;

# Next set them to the value 0xc1a7 and return
$mask = Net::IP->new("::c1:a700:0", 6) or next;
$mask = $mask->intip();
$ip |= $mask;

$ip = Net::IP->new(Net::IP::ip_bintoip(Net::IP::ip_inttobin($ip, 6), 6));
return $ip->short() if $ip;
my $candidate_int = Net::IP->new($candidate, 6)->intip();
if(!$candidate_int) {
err("Failed to convert plat prefix to bigint");
}
if(!$best_score or $best_score > ($plat_prefix_int ^ $candidate_int)) {
d2("$candidate has so far the longest common prefix with plat prefix");
$best_score = $plat_prefix_int ^ $candidate_int;
$ip = $candidate_int;
}
}
}
close($fd)
or err("'ip -6 address list scope global dev $plat_dev' failed");

# First clear the middle 0xfffe bits of the interface ID
my $mask = Net::IP->new("ffff:ffff:ffff:ffff:ffff:ff00:00ff:ffff");
$mask = $mask->intip();
$ip &= $mask;

# Next set them to the value 0xc1a7 and return
$mask = Net::IP->new("::c1:a700:0", 6) or err(Net::IP::Error());
$mask = $mask->intip();
$ip |= $mask;

$ip = Net::IP->new(Net::IP::ip_bintoip(Net::IP::ip_inttobin($ip, 6), 6));
return $ip->short() if $ip;

err("Failed to generate a CLAT IPv6 address (try setting 'clat-v6-addr')");
}

Expand Down

0 comments on commit 7e35aa5

Please sign in to comment.