Rewirte the proxydhcp.c with proxydhcp-xcat in perl; Added site.installnic to control the nics setting for windows; Added servicenode.proxydhcp and noderes.proxydhcp to control the starting of proxydhcp-xcat daemon and makedhcp againsts node for windows deployment

This commit is contained in:
daniceexi 2013-12-19 04:53:49 -05:00
parent 412f3b51c6
commit abea7eceee
5 changed files with 419 additions and 11 deletions

View File

@ -595,7 +595,7 @@ nodepos => {
},
},
noderes => {
cols => [qw(node servicenode netboot tftpserver tftpdir nfsserver monserver nfsdir installnic primarynic discoverynics cmdinterface xcatmaster current_osimage next_osimage nimserver routenames nameservers comments disable)],
cols => [qw(node servicenode netboot tftpserver tftpdir nfsserver monserver nfsdir installnic primarynic discoverynics cmdinterface xcatmaster current_osimage next_osimage nimserver routenames nameservers proxydhcp comments disable)],
keys => [qw(node)],
tablespace =>'XCATTBS16K',
table_desc => 'Resources and settings to use when installing nodes.',
@ -618,6 +618,7 @@ noderes => {
nimserver => 'Not used for now. The NIM server for this node (as known by this node).',
routenames => 'A comma separated list of route names that refer to rows in the routes table. These are the routes that should be defined on this node when it is deployed.',
nameservers => 'An optional node/group specific override for name server list. Most people want to stick to site or network defined nameserver configuration.',
proxydhcp => 'To specify whether the node supports proxydhcp protocol. Valid values: yes or 1, no or 0. Default value is yes.',
comments => 'Any user-written notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
},
@ -839,7 +840,7 @@ ppchcp => {
},
},
servicenode => {
cols => [qw(node nameserver dhcpserver tftpserver nfsserver conserver monserver ldapserver ntpserver ftpserver nimserver ipforward dhcpinterfaces comments disable)],
cols => [qw(node nameserver dhcpserver tftpserver nfsserver conserver monserver ldapserver ntpserver ftpserver nimserver ipforward dhcpinterfaces proxydhcp comments disable)],
keys => [qw(node)],
tablespace =>'XCATTBS16K',
table_desc => 'List of all Service Nodes and services that will be set up on the Service Node.',
@ -857,6 +858,7 @@ servicenode => {
nimserver => 'Not used. Do we set up a NIM server on this service node? Valid values:yes or 1, no or 0. If no or 0, it does not change the current state of the service.',
ipforward => 'Do we set up ip forwarding on this service node? Valid values:yes or 1, no or 0. If no or 0, it does not change the current state of the service.',
dhcpinterfaces => 'The network interfaces DHCP server should listen on for the target node. This attribute can be used for management node and service nodes. If defined, it will override the values defined in site.dhcpinterfaces. This is a comma separated list of device names. !remote! indicates a non-local network for relay DHCP. For example: !remote!,eth0,eth1',
proxydhcp => 'Do we set up proxydhcp service on this node? valid values: yes or 1, no or 0. If yes, the proxydhcp daemon will be enabled on this node.',
comments => 'Any user-written notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
@ -1081,9 +1083,10 @@ site => {
" xcatmaxbatchconnections: Number of concurrent xCAT connections allowed from the nodes.\n".
" Value must be less than xcatmaxconnections. Default is 50.\n".
" xcatdport: The port used by the xcatd daemon for client/server communication.\n\n".
" xcatiport: The port used by xcatd to receive install status updates from nodes.\n\n",
" xcatsslversion: The ssl version by xcatd. Default is SSLv3.\n\n",
" xcatsslciphers: The ssl cipher by xcatd. Default is 3DES.\n\n",
" xcatiport: The port used by xcatd to receive install status updates from nodes.\n\n".
" xcatsslversion: The ssl version by xcatd. Default is SSLv3.\n\n".
" xcatsslciphers: The ssl cipher by xcatd. Default is 3DES.\n\n".
" setinstallnic: Set the network configuration for installnic to be static.\n\n",
value => 'The value of the attribute specified in the "key" column.',
comments => 'Any user-written notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
@ -1660,6 +1663,11 @@ my @nodeattrs = (
tabentry => 'noderes.monserver',
access_tabentry => 'noderes.node=attr:node',
},
{attr_name => 'supportproxydhcp',
tabentry => 'noderes.proxydhcp',
access_tabentry => 'noderes.node=attr:node',
},
{attr_name => 'kernel',
tabentry => 'bootparams.kernel',
access_tabentry => 'bootparams.node=attr:node',
@ -1728,6 +1736,10 @@ my @nodeattrs = (
{attr_name => 'setupipforward',
tabentry => 'servicenode.ipforward',
access_tabentry => 'servicenode.node=attr:node',
},
{attr_name => 'setupproxydhcp',
tabentry => 'servicenode.proxydhcp',
access_tabentry => 'servicenode.node=attr:node',
},
# - moserver not used yet
# {attr_name => 'setupmonserver',

View File

@ -358,6 +358,28 @@ sub windows_net_cfg {
my $component_end = '</component>';
my $interfaces_cfg = '<Interfaces>';
# get the installnic
my $nrtab = xCAT::Table->new('noderes',-create=>0);
my $installnic;
if ($nrtab) {
my $nrent = $nrtab->getNodeAttribs($node,['installnic', 'primarynic']);
if ($nrent) {
if (defined ($nrent->{'installnic'})) {
$installnic = $nrent->{'installnic'};
} elsif (defined ($nrent->{'primarynic'})) {
$installnic = $nrent->{'primarynic'};
}
}
}
# get the site.setinstallnic
my @ents = xCAT::TableUtils->get_site_attribute("setinstallnic");
my $setinstallnic;
if ($ents[0] =~ /1|yes|y/i) {
$setinstallnic = 1;
}
my $nicstab = xCAT::Table->new('nics',-create=>0);
my $hasif;
if ($nicstab) {
@ -370,6 +392,15 @@ sub windows_net_cfg {
my ($nicname, $ips) = split(/!/, $_);
unless ($nicname) { next; }
if ($nicname =~ /^bmc/) { next; } # do nothing for bmc interface
my $dosetgw = 0;
if ($nicname eq $installnic) {
if ($setinstallnic) {
# set to static with gateway
$dosetgw = 1;
} else {# else: do nothing means using dhcp
next;
}
} # else: do not set gateway, since gateway only set for installnic
if ($ips) {
$interface_cfg .= '<Ipv4Settings><DhcpEnabled>false</DhcpEnabled></Ipv4Settings><Ipv6Settings><DhcpEnabled>false</DhcpEnabled></Ipv6Settings>';
$interface_cfg .= "<Identifier>$nicname</Identifier>";
@ -383,6 +414,9 @@ sub windows_net_cfg {
next;
}
if ($gw) { $gateway = $gw; }
if ($gateway eq '<xcatmaster>') {
$gateway = xCAT::NetworkUtils->my_ip_facing($ip);
}
$interface_cfg .= '<IpAddress wcm:action="add" wcm:keyValue="'.$num++.'">'.$ip."/$netmask".'</IpAddress>';
}
if ($num eq 1) {
@ -396,9 +430,10 @@ sub windows_net_cfg {
$interface_cfg .= '<Ipv4Settings><DhcpEnabled>true</DhcpEnabled></Ipv4Settings><Ipv6Settings><DhcpEnabled>true</DhcpEnabled></Ipv6Settings>';
$interface_cfg .= "<Identifier>$nicname</Identifier>";
}
# add the default gateway
if ($gateway) {
if ($gateway && $dosetgw) {
$interface_cfg .= '<Routes><Route wcm:action="add"><Identifier>1</Identifier><NextHopAddress>'.$gateway.'</NextHopAddress><Prefix>0/0</Prefix></Route></Routes>';
}
$interface_cfg .= '</Interface>';

View File

@ -128,7 +128,11 @@ sub init_plugin
}
}
if ($servicelist->{"proxydhcp"} == 1) {
&setup_proxydhcp(1);
} else {
&setup_proxydhcp(0);
}
} # end Linux only
#
# setup these services for AIX or Linux
@ -1455,5 +1459,26 @@ sub enable_TFTPhpa
return 0;
}
# enable or disable proxydhcp service
sub setup_proxydhcp {
my $flag = shift;
my $pid;
# read the pid of proxydhcp
if (open (PIDF, "</var/run/xcat/proxydhcp-xcat.pid")) {
$pid = <PIDF>;
}
close(PIDF);
# kill it first
if ($pid) {
kill 2, $pid;
}
# start the proxydhcp daemon if it's set to enable
if ($flag) {
system ("/opt/xcat/sbin/proxydhcp-xcat -d");
}
}
1;

View File

@ -102,9 +102,14 @@ sub check_uefi_support {
# check whether the proxydhcp has been enabled.
sub proxydhcp {
my @output = xCAT::Utils->runcmd("ps -C proxydhcp", -1);
my $nrent = shift;
if ($nrent && defined $nrent->{'proxydhcp'} && $nrent->{'proxydhcp'} =~ /0|no|n/i) {
return 0;
}
my @output = xCAT::Utils->runcmd("ps -C proxydhcp-xcat", -1);
if (@output) {
if (grep /proxydhcp/, @output) {
if (grep /proxydhcp-xcat/, @output) {
return 1;
}
}
@ -587,7 +592,7 @@ sub addnode
} else {
# If proxydhcp daemon is enabled for windows deployment, do vendor-class-identifier of "PXEClient" to bump it over to proxydhcp.c
if (($douefi == 2 and $chainent->{currstate} =~ /^install/) or $chainent->{currstate} =~ /^winshell/) {
if (proxydhcp()){ #proxy dhcp required in uefi invocation
if (proxydhcp($nrent)){ #proxy dhcp required in uefi invocation
$lstatements = 'if option client-architecture = 00:00 or option client-architecture = 00:07 or option client-architecture = 00:09 { filename = \"\"; option vendor-class-identifier \"PXEClient\"; } else { filename = \"\"; }'.$lstatements; #If proxydhcp daemon is enable, use it.
} else {
$lstatements = 'if option user-class-identifier = \"xNBA\" and option client-architecture = 00:00 { always-broadcast on; filename = \"http://'.$nxtsrv.'/tftpboot/xcat/xnba/nodes/'.$node.'\"; } else if option client-architecture = 00:07 or option client-architecture = 00:09 { filename = \"\"; option vendor-class-identifier \"PXEClient\"; } else if option client-architecture = 00:00 { filename = \"xcat/xnba.kpxe\"; } else { filename = \"\"; }'.$lstatements; #Only PXE compliant clients should ever receive xNBA
@ -1691,7 +1696,7 @@ sub process_request
} else {
$chainents = undef;
}
$nrhash = $nrtab->getNodesAttribs($req->{node}, ['tftpserver','netboot']);
$nrhash = $nrtab->getNodesAttribs($req->{node}, ['tftpserver','netboot','proxydhcp']);
my $nodetypetab;
$nodetypetab = xCAT::Table->new('nodetype',-create=>0);
if ($nodetypetab) {

331
xCAT-server/sbin/proxydhcp-xcat Executable file
View File

@ -0,0 +1,331 @@
#! /usr/bin/perl
# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html
# This program will start a proxydhcp daemon to handle 4011 request
use Sys::Syslog;
use IO::Socket::INET;
use IO::Select;
use Getopt::Long;
my $quit = 0;
my $doreload = 0;
my %nodecfg;
my $bootpmagic = pack("C*", 0x63, 0x82, 0x53, 0x63);
# set signal handler to set flag to reload configuration file
$SIG{USR1} = sub {
$doreload = 1;
};
$SIG{TERM} = $SIG{INT} = sub {
$quit = 1;
};
my $verbose;
my $tobedaemon;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
GetOptions(
'V' => \$verbose,
'd' => \$tobedaemon,
);
if ($tobedaemon) {
daemonize();
}
# open syslog
openlog("proxydhcp", "nofatal", "local4");
my $socket;
my $retry = 5;
while ($retry > 0) {
$socket = IO::Socket::INET->new(LocalPort => 4011,
Proto => 'udp',
Domain => AF_INET);
if ($socket) {
last;
} else {
sleep 1;
}
$retry--;
}
unless ($socket) {
syslog ("info", "Unable to open socket on port 4011.");
closelog();
exit;
}
# regist my pid to /var/run/xcat/proxydhcp.pid
if (open (PIDF, ">/var/run/xcat/proxydhcp-xcat.pid")) {
print PIDF $$;
close(PIDF);
} else {
syslog ("info", "Cannot open /var/run/xcat/proxydhcp.pid.");
closelog();
exit;
}
my $select = new IO::Select;
$select->add($socket);
load_cfg();
until ($quit) {
until ($select->can_read(5)) { #Wait for data
if ($doreload) {
load_cfg();
syslog ("info", "Reload configuration file in select.");
}
if ($quit) { last; };
yield;
}
if ($doreload) {
load_cfg();
syslog ("info", "Reload configuration file before recv.");
}
my $data;
my $caddr = $socket->recv($data,1500);
my ($cport, $cnip) = sockaddr_in($caddr);
my $snip = my_ip_facing($cnip);
unless ($snip) {
syslog ("info", "Cannot find the server ip of proxydhcp daemon");
next;
}
if (length ($data) < 320) {
next;
}
my @package = unpack("C*", $data);
my @replypkg;
if (pack("C*", $package[0xec], $package[0xed], $package[0xee], $package[0xef]) != $bootpmagic) {
next;
}
# get the node name of client
my $nodename = gethostbyaddr($cnip, AF_INET);
# get the winpepath
my $winpepath = "";
if ($nodename) {
if (defined $nodecfg{$nodename}) {
$winpepath = $nodecfg{$nodename};
if ($verbose) {syslog ("info", "Find configure for $nodename= $nodecfg{$nodename} in configuration file")};
} else {
$nodename =~ s/\..*//;
if (defined $nodecfg{$nodename}) {
$winpepath = $nodecfg{$nodename};
if ($verbose) {syslog ("info", "Find configure for $nodename= $nodecfg{$nodename} in configuration file")};
}
}
}
# get the Vendor class identifier
my $strp = 0xf0;
my $archp = 0;
while ($strp < $#package) {
if ($package[$strp] eq 60) {
$archp = $strp + 0x11;
last;
} else {
$strp += $package[$strp+1] + 2;
}
}
# get the winpe boot loader path
my $winboot = $winpepath."Boot/pxeboot.0";
if ($archp) {
my $clienttype = substr($data, $archp, 5);
if ($clienttype == "00000") {
#if ("$package[$archp]$package[$archp+1]$package[$archp+2]$package[$archp+3]$package[$archp+4]" == "00000") {
$winboot = $winpepath."Boot/pxeboot.0";
} elsif ($clienttype == "00007") {
$winboot = $winpepath."Boot/bootmgfw.efi";
}
}
syslog ("info", "The boot loader path for node $nodename is $winboot");
# set message type
$replypkg[0] = 2;
# set the hardware type
$replypkg[1] = $package[1];
# set the hardware address length
$replypkg[2] = $package[2];
# set the hops
$replypkg[3] = $package[3];
# set the transaction ID
@replypkg = (@replypkg, @package[4 .. 7]);
# set elapsed time
$replypkg[8] = 0;
$replypkg[9] = 0;
# set bootp flag
$replypkg[0xa] = 0;
$replypkg[0xb] = 0;
# set client ip
@replypkg = (@replypkg, @package[0xc .. 0xf]);
# set Your (client IP)
@replypkg = (@replypkg, 0, 0, 0, 0);
#set Next server IP (set my IP)
@replypkg = (@replypkg, unpack("C*", $snip));
# set dhcp relay agent ip
@replypkg = (@replypkg, 0, 0, 0, 0);
# set client hardware address
@replypkg = (@replypkg, @package[0x1c .. 0x2b]);
# set server host name
foreach (0x2c .. 0x6b) {
$replypkg[$_] = 0;
}
# set the boot file name
@replypkg = (@replypkg, unpack("C*", $winboot));
my $lenth = length ($winboot);
foreach (0x6c + $lenth .. 0xeb) {
$replypkg[$_] = 0;
}
# add magic cookie
#my @xx = unpack("C*", $bootpmagic);
#@replypkg = (@replypkg, @xx);
@replypkg = (@replypkg, unpack("C*", $bootpmagic));
# set dhcp msg type
$replypkg[0xf0] = 0x35; # option number
$replypkg[0xf1] = 0x1; # msg length
$replypkg[0xf2] = 0x5; # dhcp ack
# set dhcp server identifer
$replypkg[0xf3] = 0x36; # option number
$replypkg[0xf4] = 0x4; # msg length
@replypkg = (@replypkg, unpack("C*", $snip));
# set the bcd path
my $winbcd = $winpepath."Boot/BCD";
$replypkg[0xf9] = 0xfc; # option number
$replypkg[0xfa] = length($winbcd) + 1; # msg length
@replypkg = (@replypkg, unpack("C*", $winbcd));
$replypkg[0xfa + length($winbcd) + 1] = 0;
$replypkg[0xfa + length($winbcd) + 2] = 0xff;
$socket->send(pack("C*", @replypkg), 0, $caddr);
syslog ("info", "The BCD path for node $nodename is $winbcd");
# debug package detail
if (0) {
my $msg;
my $firstline = 1;
my $num = 0;
foreach (@replypkg) {
my $v = sprintf("%2x ", $_);
$msg .= $v;
if (($num - 5)%8 eq 0) {
$msg .= " ";
}
if (($num - 5)%16 eq 0) {
syslog ("info", $msg);
print $msg."\n";
$msg = "";
}
$num++;
}
print $msg."\n";
}
}
closelog();
# daemonize the service
sub daemonize
{
chdir('/');
umask 0022;
my $pid = fork;
if ($pid) {
exit;
}
open STDOUT, '>/dev/null';
open STDERR, '>/dev/null';
$0='proxydhcp-xcat';
$progname = \$0;
}
# load configuration from /var/lib/xcat/proxydhcp.cfg to %nodecfg
sub load_cfg
{
$doreload = 0;
if (! -r "/var/lib/xcat/proxydhcp.cfg") {
return;
}
if (! open (CFG, "</var/lib/xcat/proxydhcp.cfg")) {
syslog ("info", "Cannot open /var/lib/xcat/proxydhcp.cfg");
return;
}
my $mycfg;
while (<CFG>) {
$mycfg .= $_;
}
my $p = 0;
while (1) {
my $name = substr($mycfg, $p, 50);
$p += 50;
my $value = substr($mycfg, $p, 150);
$p += 150;
$name =~ s/\0//g;
$value =~ s/\0//g;
if ($name) {
$nodecfg{$name} = $value;
} else {
return;
}
}
close(CFG);
}
# get the ip in xCAT MN/SN which facing target ip
sub my_ip_facing
{
my $peer = shift;
unless ($peer) { return undef; }
my $noden = unpack("N", $peer);
my @nets = split /\n/, `/sbin/ip addr`;
foreach (@nets)
{
my @elems = split /\s+/;
unless (/^\s*inet\s/)
{
next;
}
(my $curnet, my $maskbits) = split /\//, $elems[2];
my $curmask = 2**$maskbits - 1 << (32 - $maskbits);
my $curn = unpack("N", inet_aton($curnet));
if (($noden & $curmask) == ($curn & $curmask))
{
return inet_aton($curnet);
}
}
return undef;
}