Commit 7de150c4 authored by Leigh Stoller's avatar Leigh Stoller

Add IPV6 changes, contributed by Brecht and lightly modified by me.

To define, in the defs file:

	IPV6_ENABLED=1
	IPV6_SUBNET_PREFIX="2011:1948:0417:0004"

A /64 network is always assumed, don't do anything else. We generate
appropriate foward and reverse entries in the zone files, but
otherwise rely on the on the upstream router to provide the prefix
when asked for it by nodes when they wish to configure an IPV6
interface.

Important caveats:

1. The infrastructure is ipv4 only. We do not dupport dual stack or
   ipv6 only on any infrastructure.

2. We do not support ipv6 only on the control plane; ipv4 or dual stack.
parent 26d072dc
......@@ -658,6 +658,8 @@ TBOPSEMAIL_NOSLASH
TBOPSEMAIL
BROWSER_CONSOLE_ENABLE
EC2META_ENABLE
IPV6_ENABLED
IPV6_SUBNET_PREFIX
NOSITECHECKIN
SPEWFROMOPS
FIREWALL_OPS_LOCALRULETMPL
......@@ -5065,6 +5067,8 @@ SPEWFROMOPS=0
NOSITECHECKIN=0
EC2META_ENABLE=0
BROWSER_CONSOLE_ENABLE=0
IPV6_ENABLED=0
IPV6_SUBNET_PREFIX=""
#
# XXX You really don't want to change these!
......
......@@ -282,6 +282,8 @@ AC_SUBST(SPEWFROMOPS)
AC_SUBST(NOSITECHECKIN)
AC_SUBST(EC2META_ENABLE)
AC_SUBST(BROWSER_CONSOLE_ENABLE)
AC_SUBST(IPV6_ENABLED);
AC_SUBST(IPV6_SUBNET_PREFIX);
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -415,6 +417,8 @@ SPEWFROMOPS=0
NOSITECHECKIN=0
EC2META_ENABLE=0
BROWSER_CONSOLE_ENABLE=0
IPV6_ENABLED=0
IPV6_SUBNET_PREFIX=""
#
# XXX You really don't want to change these!
......
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -33,6 +33,8 @@ OURDOMAIN = @OURDOMAIN@
# This is silly. Needs to be done properly.
TESTBED_NETWORK = @TESTBED_NETWORK@
EXTERNAL_TESTBED_NETWORK = @EXTERNAL_TESTBED_NETWORK@
IPV6_ENABLED = @IPV6_ENABLED@
IPV6_SUBNET_PREFIX = @IPV6_SUBNET_PREFIX@
REVERSE_MAPNAME = \
$(shell echo @TESTBED_NETWORK@ | sed -e 's,.0$$,,')
......@@ -43,13 +45,20 @@ REVFILES = $(REVERSE_MAPNAME).db.head
ifneq ($(REVERSE_MAPNAME), $(EXTERNAL_REVERSE_MAPNAME))
REVFILES += $(EXTERNAL_REVERSE_MAPNAME).db.head
endif
ifeq ($(IPV6_ENABLED),1)
IPV6_MAPNAME = \
$(shell echo @IPV6_SUBNET_PREFIX@ | sed -e 's,\:,\.,g')
REVFILES += $(IPV6_MAPNAME).db.head
endif
BOSSTOKEN = $(shell echo @BOSSNODE@ | sed -e 's/\..*//')
USERTOKEN = $(shell echo @USERNODE@ | sed -e 's/\..*//')
NAMED_FILES = named.conf.template named_makeconf named_makerev reverse.head \
NAMED_FILES = named.conf.template named_makeconf named_makerev \
reverse.head \
resolv.conf localhost.rev forward.head named_makeforw \
$(REVFILES) $(OURDOMAIN).db.head $(OURDOMAIN).internal.db.head \
$(REVFILES) $(OURDOMAIN).db.head\
$(OURDOMAIN).internal.db.head \
named.conf resolv.conf.ops mail.access
include $(OBJDIR)/Makeconf
......
......@@ -44,6 +44,7 @@ view "internal" {
};
%internal_network_reverse_zones%
%internal_network_extra_stuff%
};
view "external" {
......@@ -67,5 +68,6 @@ view "external" {
};
%external_network_reverse_zones%
%external_network_extra_stuff%
};
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -61,10 +61,20 @@ my $NAMED_FORWARDERS = "@NAMED_FORWARDERS@";
my $VIRTNODE_NETWORK = "@VIRTNODE_NETWORK@";
my $VIRTNODE_NETMASK = "@VIRTNODE_NETMASK@";
my $NAMED_ALSONOTIFY = "@NAMED_ALSONOTIFY@";
my $IPV6_ENABLED = @IPV6_ENABLED@;
my $IPV6_SUBNET_PREFIX = "@IPV6_SUBNET_PREFIX@";
my $IPV6_MAPFILE = "";
if ($IPV6_ENABLED) {
$IPV6_MAPFILE = $IPV6_SUBNET_PREFIX . ".db";
# Switch : to dot since colon causes gmake to act strange.
$IPV6_MAPFILE =~ s/\:/./g;
}
# Protos
sub ReverseDottedIPV6($);
# Testbed libraries.
use lib "@prefix@/lib";
#use libdb;
# Simple is good. I stole this out of a google search.
my @NETMASKS =
......@@ -173,6 +183,14 @@ while (<IF>) {
}
}
elsif ($2 eq "internal_network_reverse_zones") {
if ($IPV6_ENABLED) {
my $dotted_reverse = ReverseDottedIPV6($IPV6_SUBNET_PREFIX);
print $1 . "zone \"${dotted_reverse}.ip6.arpa\" in {\n";
print $1 . "\ttype master;\n";
print $1 . "\tfile \"reverse/${IPV6_MAPFILE}\";\n";
print $1 . "};\n\n";
}
for (my $i = $ic; $i <= $ic + (255 - $imc); $i++) {
my $dotted = "${ia}.${ib}.${i}";
my $dotted_reverse = "${i}.${ib}.${ia}";
......@@ -193,6 +211,14 @@ while (<IF>) {
}
}
elsif ($2 eq "external_network_reverse_zones") {
if ($IPV6_ENABLED) {
my $dotted_reverse = ReverseDottedIPV6($IPV6_SUBNET_PREFIX);
print $1 . "zone \"${dotted_reverse}.ip6.arpa\" in {\n";
print $1 . "\ttype master;\n";
print $1 . "\tfile \"reverse/${IPV6_MAPFILE}\";\n";
print $1 . "};\n\n";
}
for (my $i = $ec; $i <= $ec + (255 - $emc); $i++) {
my $dotted = "${ea}.${eb}.${i}";
my $dotted_reverse = "${i}.${eb}.${ea}";
......@@ -203,6 +229,38 @@ while (<IF>) {
print $1 . "};\n";
}
}
elsif ($2 eq "internal_network_extra_stuff") {
if (-e "/etc/namedb/internal.named.conf") {
open(EXTRA, "/etc/namedb/internal.named.conf") or
die("*** $0:\n".
" Could not open internal.named.conf!\n");
print $1 . "#\n";
print $1 . "# Fragment included from internal.named.conf\n";
print $1 . "#\n";
while (<EXTRA>) {
print $1 . $_;
}
close(EXTRA);
print $1 .
"# End of fragment included from internal.named.conf\n";
}
}
elsif ($2 eq "external_network_extra_stuff") {
if (-e "/etc/namedb/external.named.conf") {
open(EXTRA, "/etc/namedb/external.named.conf") or
die("*** $0:\n".
" Could not open external.named.conf!\n");
print $1 . "#\n";
print $1 . "# Fragment included from external.named.conf\n";
print $1 . "#\n";
while (<EXTRA>) {
print $1 . $_;
}
close(EXTRA);
print $1 .
"# End of fragment included from external.named.conf\n";
}
}
else {
die("*** $0:\n".
" Unknown special tag in named template file!\n");
......@@ -215,3 +273,26 @@ while (<IF>) {
}
close(IF);
exit(0);
#
# Helper to form a dotted reverse for IPv6
#
sub ReverseDottedIPV6($)
{
my ($ipv6) = @_;
my @digits = ();
foreach my $nibblet (split(":", $ipv6)) {
if ($nibblet =~ /^(\w)(\w)(\w)(\w)$/) {
push(@digits, $1, $2, $3, $4);
}
else {
die("*** $0:\n".
" Bad format for ipv6 address: $IPV6_SUBNET_PREFIX!\n");
}
}
my $dotted = join(".", reverse(@digits));
return $dotted;
}
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -63,10 +63,11 @@ my $PUBLIC_NETMASK = "@PUBLIC_NETMASK@";
my $NAMED_FORWARDERS = "@NAMED_FORWARDERS@";
my $VIRTNODE_NETWORK = "@VIRTNODE_NETWORK@";
my $VIRTNODE_NETMASK = "@VIRTNODE_NETMASK@";
my $IPV6_ENABLED = @IPV6_ENABLED@;
my $IPV6_SUBNET_PREFIX = "@IPV6_SUBNET_PREFIX@";
# Testbed libraries.
use lib "@prefix@/lib";
#use libdb;
#
# This is for the dotted and reverse dotted notation needed for the
......@@ -166,6 +167,29 @@ for (my $i = $ic; $i <= $ic + (255 - $imc); $i++) {
close(REV);
}
if ($IPV6_ENABLED) {
my $revfile = ${IPV6_SUBNET_PREFIX} . ".db.head";
my @digits = ();
# Switch : to dot since it messes up gmake.
$revfile =~ s/\:/./g;
foreach my $nibblet (split(":", $IPV6_SUBNET_PREFIX)) {
if ($nibblet =~ /^(\w)(\w)(\w)(\w)$/) {
push(@digits, $1, $2, $3, $4);
}
else {
die("*** $0:\n".
" Bad format for ipv6 address: $IPV6_SUBNET_PREFIX!\n");
}
}
my $dotted = join(".", reverse(@digits));
print "Generating IPV6 reverse lookup file ...\n";
system("cp -f reverse.head $revfile") == 0 or
die("Unable to copy $infile to $revfile\n");
}
# No need is just one big IP space.
exit(0)
if ($TESTBED_NETWORK eq $EXTERNAL_TESTBED_NETWORK);
......
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -24,6 +24,7 @@
use English;
use Socket;
use strict;
use Net::IP;
#
# Suck out virtual names and create CNAME map entries.
......@@ -42,6 +43,7 @@ sub make_forward_zonefile($$$);
sub isroutable($);
sub IsJailIP($);
sub process_nodes($);
sub make_ipv6_reverse_zonefile($$);
#
# Configure variables
......@@ -53,7 +55,9 @@ my $DISABLED = "@DISABLE_NAMED_SETUP@";
my $OURDOMAIN = "@OURDOMAIN@";
my $VIRTNODE_NETWORK = "@VIRTNODE_NETWORK@";
my $VIRTNODE_NETMASK = "@VIRTNODE_NETMASK@";
my $IPV6_ENABLED = @IPV6_ENABLED@;
my $IPV6_SUBNET_PREFIX = "@IPV6_SUBNET_PREFIX@";
my $mapdir = "/etc/namedb";
my $mapfile = "${mapdir}/${OURDOMAIN}.db";
my $mapfiletail = "$mapfile.tail";
......@@ -63,6 +67,11 @@ my $mapfile_internal_tail = "$mapfile_internal.tail";
my $vnodesfile = "$mapdir/vnodes.${OURDOMAIN}.db";
my $vnodesback = "$mapdir/vnodes.${OURDOMAIN}.db.backup";
my $reversedir = "$mapdir/reverse";
my $reverse_ipv6 = "$reversedir/${IPV6_SUBNET_PREFIX}.db";
# Switch colon to dot since colon causes gmake to act strange.
$reverse_ipv6 =~ s/\:/./g;
my $reverse_ipv6_head = "${reverse_ipv6}.head";
my $reverse_ipv6_tail = "${reverse_ipv6}.tail";
my $restart_named = 1;
my $sortem = 0; # set to 1 to generated IP-sorted file
my $dbg = 0;
......@@ -119,11 +128,11 @@ if ((my $locked = TBScriptLock("named", 1)) != TBSCRIPTLOCK_OKAY()) {
#
my $db_result =
DBQueryFatal("select n.node_id, n.role, null, i.IP, i.role, ".
" r.inner_elab_role, i.IPaliases ".
" r.inner_elab_role, i.IPaliases, i.mac ".
" from nodes as n join interfaces as i ".
"left join reserved as r on r.node_id=n.node_id ".
"where (n.node_id=i.node_id and ".
" (n.role='testnode' or n.role='virtnode')) ".
" (n.role='powerctrl' or n.role='testnode' or n.role='virtnode')) ".
" and i.IP is not null ".
" and (i.role='" . TBDB_IFACEROLE_CONTROL() . "' or " .
" i.role='" . TBDB_IFACEROLE_MANAGEMENT() . "')");
......@@ -252,7 +261,6 @@ if (-e $mapfile_internal_head) {
assemble_zonefile($mapfile_internal);
}
#
# Look for reverse zone files that we may need to make
#
......@@ -289,7 +297,11 @@ while (my $dirent = readdir(DIR)) {
close MAP;
assemble_zonefile("$reversedir/$basename");
}
if ($IPV6_ENABLED) {
make_ipv6_reverse_zonefile($reverse_ipv6_tail,\%routable);
assemble_zonefile($reverse_ipv6);
}
closedir DIR;
......@@ -330,6 +342,7 @@ sub process_nodes($) {
my $irole = $row[4];
my $inner_elab_role = $row[5];
my $IPaliases = $row[6];
my $mac = $row[7];
#
# For most nodes, we get the IP address from the interfaces table;
......@@ -342,8 +355,8 @@ sub process_nodes($) {
warn "named_setup: No IP for node $node_id!\n";
next;
}
#
#
# Special treatment for gateway interfaces - we give act as if they
# are a separate node
#
......@@ -393,6 +406,34 @@ sub process_nodes($) {
};
}
}
if ($IPV6_ENABLED && $mac) {
# Calculate modified EUI-64 from MAC address
my $v = substr($mac, 1, 1);
$v = unpack("B4", pack("H1", $v));
if (substr($v, 2, 1) == '0') {
substr($v, 2, 1, '1');
}
else {
substr($v, 2, 1, '0');
}
$v = unpack("H1", pack("B4", $v));
my $IP6 = $IPV6_SUBNET_PREFIX . ':' . substr($mac,0,1) . $v .
substr($mac,2,2) . ':' . substr($mac,4,2) . 'ff:fe' .
substr($mac,6,2) . ':' . substr($mac,8,4);
# Make new node_rec with IP6 address in IP field
my $node_rec6 = {
IP => $IP6,
role => $nrole,
inner_elab_role => $inner_elab_role,
};
# Push it to the routable & unroutable stack, add prefix to create
# a different node_id key
$routable{"_V6_" . $node_id} = $node_rec6;
$unroutable{"_V6_" . $node_id} = $node_rec6;
}
#
# Put it into a map so we can generate the reverse zone file later
......@@ -517,6 +558,47 @@ sub byip {
$aa[3] <=> $bb[3];
}
#
# Make Reverse IPv6 zonefile
#
sub make_ipv6_reverse_zonefile($$) {
my ($filename, $addresses) = @_;
open(MAP, ">$filename") || fatal("Couldn't open $filename\n");
print MAP "\n";
print MAP ";\n";
print MAP "; DO NOT EDIT below this point. Auto generated map entries!\n";
print MAP ";\n";
print MAP "\n";
print MAP "\n";
print MAP ";\n";
print MAP "; Nodes\n";
print MAP ";\n";
print MAP "\n";
my @list = keys(%$addresses);
if ($sortem) {
$laddrs = $addresses;
@list = sort byip @list;
}
for my $node_id (@list) {
my $node_rec = $$addresses{$node_id};
if ($node_id =~ /^_V6_(.*)$/) {
$node_id = $1;
my $ipv6 = $node_rec->{IP};
$ipv6 =~ s/[\n|\r]//g;
my $convert_ip = new Net::IP ($ipv6)
or die (Net::IP::Error());
print MAP $convert_ip->reverse_ip() . "\tIN\tPTR\t" .
$node_id . "." . $OURDOMAIN . ".\n";
}
}
print MAP "\n";
close(MAP);
}
#
# Make a forward zone file, from the given map of addresses and CNAMEs
#
......@@ -552,8 +634,13 @@ sub make_forward_zonefile($$$) {
if (($node_rec->{role} eq "virtnode") && (!$cnames->{$node_id})) {
next;
}
print MAP "$node_id\tIN\tA\t$node_rec->{IP}\n";
if ($node_id =~ /^_V6_(.*)$/) {
$node_id = $1;
print MAP $node_id . "\tIN\tAAAA\t$node_rec->{IP}\n";
}
else {
print MAP "$node_id\tIN\tA\t$node_rec->{IP}\n";
}
if ($domx) {
if (defined($node_rec->{inner_elab_role}) &&
($node_rec->{inner_elab_role} eq "ops" ||
......@@ -583,7 +670,7 @@ sub make_forward_zonefile($$$) {
#
# Only print out CNAMEs for nodes that are actually going into this map
#
next unless ($addresses->{$pname});
next unless ($addresses->{$pname} || $addresses->{"_V6_" . $pname});
#
# Write out every CNAME for this pnode
......
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