#!/usr/bin/perl # # mkchbond.pl v0.9: Copyright (c) 2005-2007 Scalable Informatics # written by Joe Landman (landman@scalableinformatics.com) # # Changelog: # # v0.25 # Get the basic idea down and working. Add a little option parsing so as # to get the information back in the needed format # # v0.5 # more features, bug fixes, etc. # # v0.9 # ready to rock and roll ... sort of. # # v0.95 # SuSE support # this software is licensed under GPL2.0 only. See http://www.gnu.org/copyleft/gpl.html # for full license text. # mkchbond.pl comes with ABSOLUTELY NO WARRANTY # This is free software, and you are welcome # to redistribute it under certain conditions # NO WARRANTY # # BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO # WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN # OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE # PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND # FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST # OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. # # IN NO EVENT UNLESS REQUIRED # BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER # PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE # TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL # DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT # LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY # YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER # PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY # OF SUCH DAMAGES. use strict; use Getopt::Long; use IO::Handle; use File::Copy; use POSIX qw(strftime); use constant true => (1==1); use constant false => (1==0); # variables my $bond = "bond0"; my $modprobe = "/etc/modprobe.conf"; my (@eths,@eth_list); my $eth; my $rc; my $ipaddr; my $netmask; my $network; my $broadcast; my $write = false; my $ifcfg_net = "/etc/sysconfig/network-scripts/ifcfg-"; my $ifcfg; my $distro = "redhat"; my $time = strftime "%F_%T",localtime(); my $help = false; my $bits; my $mode = 6; my $dryrun = false; my $bonding_interfaces_count=1; if (-e '/etc/SuSE-release') { # looks like SuSE, re-adjust for that ... printf STDERR "SuSE detected ... \n"; $distro = "suse"; $ifcfg_net = "/etc/sysconfig/network/ifcfg-"; $modprobe = "/etc/modprobe.conf.local"; } ## banner printf "mkchbond.pl: v0.9 Create channel bonds easily\n"; printf "by Joe Landman (http://scalableinformatics.com)\n"; printf "This software is Copyright (c) 2005-2007 by Scalable Informatics\n"; printf "and licensed under GPL v2.0 only. You may freely distribute this\n"; printf "software under the terms and conditions of the GPL 2.0 license.\n"; printf "You may not alter, remove, or prevent printing of the copyright\n"; printf "notice and information.\n\n"; # start parsing command line arguments. All are of the form # --argument[=value(s)] # $rc = GetOptions ( "bond=s" => \$bond, "eth=s" => \@eth_list, "ip=s" => \$ipaddr, "modprobe=s" => \$modprobe, "netmask=s" => \$netmask, "network=s" => \$network, "broadcast=s" => \$broadcast, "ifcfg=s" => \$ifcfg_net, "write" => \$write, "dist=s" => \$distro, "help" => \$help, "mode=s" => \$mode ); # need to set up help ... ugh # fix ethernet specification, using --eth=ethA,ethB or --eth=ethA --eth=ethB to mean # the same thing foreach $eth (@eth_list) { map { push @eths,$_ } (split /[, :]/,$eth); } # modprobe $bits = sprintf "alias %s bonding\n",$bond; $bits .=sprintf "options bonding mode=%s miimon=100 downdelay=300 updelay=300 max_bonds=2\n",$mode; &append($write,$modprobe,$bits); # ifcfg-bond $ifcfg = sprintf "%s%s",$ifcfg_net,$bond; $bits = sprintf "DEVICE=%s\n",$bond; $bits .=sprintf "IPADDR=%s\n",$ipaddr; $bits .=sprintf "NETMASK=%s\n",$netmask; $bits .=sprintf "NETWORK=%s\n",$network; $bits .=sprintf "BROADCAST=%s\n",$broadcast; $bits .=sprintf "ONBOOT=yes\n"; $bits .=sprintf "BOOTPROTO=none\n"; $bits .=sprintf "USERCTL=no\n"; if ($distro eq "suse") { $bits .=sprintf "BONDING_MASTER=yes\n" ; foreach $eth (@eths) { $bits .=sprintf "BONDING_SLAVE%s=\'%s\'\n",$bonding_interfaces_count,$eth ; $bonding_interfaces_count++ } } &out($write,$ifcfg,$bits); # ifcfg-eth's foreach $eth (@eths) { if ($distro eq "redhat") { $ifcfg = sprintf "%s%s",$ifcfg_net,$eth; } else { # special case for SuSE, since they use an odd eth naming scheme my $hwaddr; $hwaddr = `ifconfig $eth | grep HWaddr`; if ($hwaddr =~ /(\S{2}:\S{2}:\S{2}:\S{2}:\S{2}:\S{2})/) { #printf STDERR "HWaddr for %s found to be %s\n",$eth,$1; $ifcfg = sprintf "%seth-id-%s",$ifcfg_net,lc($1); } } $bits = sprintf "DEVICE=%s\n",$eth; $bits .=sprintf "ONBOOT=yes\n"; $bits .=sprintf "BOOTPROTO=none\n"; $bits .=sprintf "USERCTL=no\n"; $bits .=sprintf "MASTER=%s\n",$bond; $bits .=sprintf "SLAVE=yes\n"; if ($distro eq "suse") { $bits .=sprintf "STARTMODE='off'\n" ; $bits .=sprintf "%s", `grep UNIQUE $ifcfg`; $bits .=sprintf "%s", `grep NAME $ifcfg`; $bits .=sprintf "%s", `grep _nm_name $ifcfg`; } &out($write,$ifcfg,$bits); } #&out($write,"stuff","things"); sub out { my $write = shift; my $file = shift; my $text = shift; my $ofh; my $backup_file_name = sprintf "%s.%s",$file,(strftime "%F_%T",localtime()); if ($write) { # first see if it exists, and if so, rename it with $time appended move ($file,$backup_file_name) if (-e $file); printf STDERR "opening file \'%s\' for writing\n",$file; open($ofh,">$file") or die "FATAL ERROR: unable to open file \'$file\' for writing\n"; } else { $ofh = new IO::Handle; $ofh->fdopen(fileno(STDOUT),"w"); printf "---- Would write the following to file \'%s\' up to EOM ----\n",$file; } printf $ofh "%s",$text; if ($write) { printf STDERR "closing file \'%s\' \n",$file; close($ofh) or die "FATAL ERROR: unable to close file \'$file\'\n"; } else { undef $ofh; printf "---- EOM ----\n\n"; } } sub append { my $write = shift; my $file = shift; my $text = shift; my $ofh; my $backup_file_name = sprintf "%s.%s",$file,(strftime "%F_%T",localtime()); if ($write) { # first see if it exists, and if so, make a copy of it with $time appended copy ($file,$backup_file_name) if (-e $file); printf STDERR "opening file \'%s\' for appending\n",$file; open($ofh,">>$file") or die "FATAL ERROR: unable to open file \'$file\' for appending\n"; } else { $ofh = new IO::Handle; $ofh->fdopen(fileno(STDOUT),"w"); printf "---- Would append the following to file \'%s\' up to EOM -----\n",$file; } printf $ofh "%s",$text; if ($write) { printf STDERR "closing file \'%s\' \n",$file; close($ofh) or die "FATAL ERROR: unable to close file \'$file\'\n"; } else { undef $ofh; printf "---- EOM -----\n\n"; } }