Blame SOURCES/rxe_cfg

26a767
#!/usr/bin/perl
26a767
26a767
# * Copyright (c) 2009-2011 Mellanox Technologies Ltd. All rights reserved.
26a767
# * Copyright (c) 2009-2011 System Fabric Works, Inc. All rights reserved.
26a767
# *
26a767
# * This software is available to you under a choice of one of two
26a767
# * licenses.  You may choose to be licensed under the terms of the GNU
26a767
# * General Public License (GPL) Version 2, available from the file
26a767
# * COPYING in the main directory of this source tree, or the
26a767
# * OpenIB.org BSD license below:
26a767
# *
26a767
# *     Redistribution and use in source and binary forms, with or
26a767
# *     without modification, are permitted provided that the following
26a767
# *     conditions are met:
26a767
# *
26a767
# *	- Redistributions of source code must retain the above
26a767
# *	  copyright notice, this list of conditions and the following
26a767
# *	  disclaimer.
26a767
# *
26a767
# *	- Redistributions in binary form must reproduce the above
26a767
# *	  copyright notice, this list of conditions and the following
26a767
# *	  disclaimer in the documentation and/or other materials
26a767
# *	  provided with the distribution.
26a767
# *
26a767
# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26a767
# * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26a767
# * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26a767
# * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26a767
# * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26a767
# * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26a767
# * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26a767
# * SOFTWARE.
26a767
#
26a767
26a767
use warnings;
26a767
use strict;
26a767
26a767
use File::Basename;
26a767
use File::Path qw(make_path);
26a767
use Getopt::Long;
26a767
26a767
my $help = 0;
26a767
my $no_persist = 0;
26a767
my $debug = 0;
26a767
my $force = 0;
26a767
my $linkonly = 0;
26a767
my $parms = "/sys/module/rdma_rxe/parameters";
26a767
my $modprobe_opt = "";
26a767
my $modprobe_checked = "0";
26a767
my $persistence_path = "/var/lib/rxe";
26a767
my $persistence_file = "${persistence_path}/rxe";
26a767
my $num_persistent = 0;
26a767
my $sys = "/sys/module/rdma_rxe/parameters";
26a767
my %rxe_names;
26a767
my @rxe_array;
26a767
my %eth_names;
26a767
my @eth_list;
26a767
my %eth_driver;
26a767
my %link_state;
26a767
my %link_speed;
26a767
my %eth_mtu;
26a767
my %ipv4_addr;
26a767
my %rxe_mtu;
26a767
my @persistence_array;
26a767
my %persistence_hash;
26a767
my @mlx4_port;
26a767
my @mlx4_ether;
26a767
my @roce_list;
26a767
26a767
# Read a file and return its contents as a string.
26a767
sub read_file {
26a767
    my $filename = shift;
26a767
    my $result = "";
26a767
26a767
    if (open(FILE, $filename)) {
26a767
	$result = <FILE>;
26a767
	close FILE;
26a767
    }
26a767
    return $result;
26a767
}
26a767
26a767
#get mapping between rxe and eth devices
26a767
sub get_names {
26a767
    my $i = 0;
26a767
    
26a767
    foreach my $rxe (glob("/sys/class/infiniband/rxe*")) {
26a767
	$rxe = basename($rxe);
26a767
	my $eth = read_file("/sys/class/infiniband/$rxe/parent");
26a767
	chomp($eth);
26a767
	
26a767
	if (($eth =~ /[\w]+[\d]/)
26a767
	    && ($rxe =~ /rxe[0123456789]/)) {
26a767
	    
26a767
	    # hash ethername to rxename
26a767
	    $rxe_names{$eth} = $rxe;
26a767
	    $rxe_array[$i++] = $rxe;
26a767
	    
26a767
	    # hash rxename to ethername
26a767
	    $eth_names{$rxe} = $eth;
26a767
	}
26a767
    }
26a767
}
26a767
26a767
# get list of Mellanox RoCE ports
26a767
sub get_mlx4_list {
26a767
    my $i = 0;
26a767
26a767
    foreach my $mlx4 (glob("/sys/class/infiniband/mlx4_*")) {
26a767
	$mlx4 = basename($mlx4);
26a767
	foreach my $port (glob("/sys/class/infiniband/$mlx4/ports/*")) {
26a767
	    $port = basename($port);
26a767
	    my $link = read_file("$port/link_layer");
26a767
	    chomp($link);
26a767
26a767
	    if ($link =~ "Ethernet") {
26a767
		$roce_list[$i++] = "$mlx4:$port";
26a767
	    }
26a767
	}
26a767
    }
26a767
}
26a767
26a767
#collect per device information
26a767
sub get_dev_info {
26a767
    my @list;
26a767
    my @fields;
26a767
    my @lines;
26a767
    my $line;
26a767
    my $eth;
26a767
    my $drv;
26a767
    my $np;
26a767
    my $i = 0;
26a767
    my $j = 0;
26a767
26a767
    get_mlx4_list();
26a767
26a767
    my @my_eth_list = ();
26a767
    foreach my $my_eth_dev (glob("/sys/class/net/*")) {
26a767
       $my_eth_dev = basename($my_eth_dev);
26a767
          if ($my_eth_dev ne "bonding_masters"){
26a767
             my $my_dev_type = read_file("/sys/class/net/${my_eth_dev}/type");
26a767
             chomp($my_dev_type);
26a767
             if ($my_dev_type == "1") {
26a767
                push(@my_eth_list, "$my_eth_dev");
26a767
             }
26a767
          }
26a767
    }
26a767
26a767
    @list = @my_eth_list;
26a767
    foreach $eth (@list) {
26a767
	chomp($eth);
26a767
26a767
	$eth_list[$i++] = $eth;
26a767
26a767
	@lines = `ethtool -i $eth`;
26a767
	foreach $line (@lines) {
26a767
	    chomp($line);
26a767
26a767
	    @fields = split(/\s+/, $line);
26a767
	    chomp($fields[0]);
26a767
26a767
	    if ($fields[0] =~ /driver:/) {
26a767
		$drv = $fields[1];
26a767
		$eth_driver{$eth} = $drv;
26a767
26a767
		if ($drv =~ /mlx4_en/ && scalar(@roce_list) > 0 ) {
26a767
		    $eth_names{$roce_list[$j++]} = $eth;
26a767
		}
26a767
	    }
26a767
	}
26a767
26a767
	# get link status
26a767
	$link_state{$eth} = "";
26a767
	$link_speed{$eth} = "";
26a767
26a767
	@lines = `ethtool $eth`;
26a767
	foreach $line (@lines) {
26a767
	    chomp($line);
26a767
26a767
	    @fields = split(/:/, $line);
26a767
	    if (defined($fields[1])) {
26a767
		    $fields[1] =~ s/^\s+//g;
26a767
		    if ($fields[0] =~ "Link detected") {
26a767
			$link_state{$eth} = $fields[1];
26a767
		    }
26a767
	    }
26a767
	    elsif ($line =~ "10000baseT") {
26a767
		$link_speed{$eth} = "10GigE";
26a767
	    }
26a767
	}
26a767
26a767
	$ipv4_addr{$eth} = "            ";
26a767
	$eth_mtu{$eth} = "";
26a767
26a767
	@lines = `ip addr show $eth`;
26a767
	foreach $line (@lines) {
26a767
		# get IP address
26a767
		if ($line =~ /inet /) {
26a767
			$line =~ s/^\s+inet ([0-9.]+)\//$1 /g;
26a767
			@fields = split(/\s+/, $line);
26a767
			$ipv4_addr{$eth} = $fields[0];
26a767
		}
26a767
26a767
		# get ethernet mtu
26a767
		if ($line =~ /mtu /) {
26a767
			$line =~ s/^.*mtu //g;
26a767
			@fields = split(/\s+/, $line);
26a767
			$eth_mtu{$eth} = $fields[0];
26a767
		}
26a767
    }
26a767
    }
26a767
26a767
    # get rxe mtu
26a767
    foreach my $rxe (@rxe_array) {
26a767
	
26a767
	@lines = `ibv_devinfo -d $rxe`;
26a767
	foreach $line (@lines) {
26a767
	    if ($line =~ "active_mtu") {
26a767
		$line =~ s/^\s+active_mtu:\s+//g;
26a767
		chomp($line);
26a767
26a767
		$rxe_mtu{$rxe} = $line;
26a767
	    }
26a767
	}
26a767
	$rxe_mtu{$rxe} = "(?)" if (!$rxe_mtu{$rxe});
26a767
    }
26a767
}
26a767
26a767
# return string or the string "###" if string is all whitespace
26a767
sub set_field {
26a767
    my $fld = $_[0];
26a767
26a767
    if (defined($fld) && $fld =~ /\S/) {
26a767
        return $fld;
26a767
    } else {
26a767
        return "###";
26a767
    }
26a767
}
26a767
26a767
# format status output into fixed width columns
26a767
sub status_print {
26a767
    my @fields;
26a767
    my $field;
26a767
    my @flen = ();
26a767
    my $num_fields = 0;
26a767
    my $i;
26a767
    my $pad;
26a767
    my $line;
26a767
26a767
    # one pass to size the columns
26a767
    foreach $line (@_) {
26a767
	@fields = split(/\s+/, $line);
26a767
	$i = 0;
26a767
	foreach $field (@fields) {
26a767
	    if (!defined($flen[$i])) {
26a767
		$flen[$i] = length($field);
26a767
	    }
26a767
	    else {
26a767
		$flen[$i] = max($flen[$i], length($field));
26a767
	    }
26a767
	    $i++;
26a767
	}
26a767
26a767
	if ($i > $num_fields) {
26a767
	    $num_fields = $i;
26a767
	}
26a767
    }
26a767
26a767
    # one pass to print
26a767
    foreach $line (@_) {
26a767
	print "  ";
26a767
	@fields = split(/\s+/, $line);
26a767
	for ($i = 0; $i < $num_fields; $i++) {
26a767
	    if (defined($fields[$i])) {
26a767
	        $pad = $flen[$i] - length($fields[$i]) + 2;
26a767
	    }
26a767
	    else {
26a767
	        $pad = $flen[$i] + 2;
26a767
	    }
26a767
	    if (defined($fields[$i]) && ($fields[$i] ne "###")) {
26a767
		print "$fields[$i]";
26a767
	    }
26a767
	    else {
26a767
		print "   ";
26a767
	    }
26a767
	    printf("%*s", $pad, "");
26a767
	}
26a767
	print "\n";
26a767
    }
26a767
}
26a767
26a767
# check driver load status
26a767
sub check_module_status {
26a767
    if (-e $sys) {
26a767
	return 0;
26a767
    } else {
26a767
	return 1;
26a767
    }
26a767
}
26a767
26a767
# print driver load status and ethertype for rdma_rxe and rdma_rxe_net
26a767
sub show_module_status {
26a767
    print "rdma_rxe module not loaded\n" if (!(-e $sys));
26a767
}
26a767
26a767
# print rxe status
26a767
sub do_status {
26a767
    my $instance = $_[0];
26a767
    my $ln = 0;
26a767
    my @outp;
26a767
    my $rxe;
26a767
    my $rmtu;
26a767
26a767
    get_names();
26a767
    get_dev_info();
26a767
    show_module_status();
26a767
26a767
    $outp[$ln++] = "Name\tLink\tDriver\t\tSpeed\tNMTU\tIPv4_addr\tRDEV\tRMTU";
26a767
26a767
    foreach my $eth (@eth_list) {
26a767
26a767
	# handle case where rxe_drivers are not loaded
26a767
	if (defined($rxe_names{$eth})) {
26a767
		$rxe = $rxe_names{$eth};
26a767
		$rmtu = $rxe_mtu{$rxe};
26a767
	}
26a767
	else {
26a767
		$rxe = "";
26a767
		$rmtu = "";
26a767
	}
26a767
26a767
	if ((!defined($instance) 
26a767
	     && (($linkonly == 0) || ($link_state{$eth} =~ "yes")))
26a767
	    || (defined($instance) && ($rxe =~ "$instance"))) {
26a767
	    $outp[$ln] =  set_field("$eth");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$link_state{$eth}");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field(exists($eth_driver{$eth}) ? $eth_driver{$eth} : "");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$link_speed{$eth}");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$eth_mtu{$eth}");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$ipv4_addr{$eth}");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$rxe");
26a767
	    $outp[$ln] .= "\t";
26a767
	    $outp[$ln] .= set_field("$rmtu");
26a767
	    $ln++;
26a767
	}
26a767
    }
26a767
26a767
    status_print(@outp);
26a767
}
26a767
26a767
# read file containing list of ethernet devices into a list
26a767
sub populate_persistence {
26a767
    my $i = 0;
26a767
    
26a767
    open FILE, $persistence_file;
26a767
    while(<FILE>) {
26a767
	my $line = $_;
26a767
	chomp($line);
26a767
	$line =~ s/^\s+//g;
26a767
	if ($line =~ /[\w]+[\d]/) {
26a767
	    # in case we add fields later
26a767
	    my ($eth, $cruft) = split(/\s+/, $line, 2);
26a767
	    if ($eth =~ /^[\w]+[\d]/) {
26a767
		$persistence_array[$i] = $eth;
26a767
		$persistence_hash{$eth} = $i++;
26a767
	    }
26a767
	}
26a767
    }
26a767
    close FILE;
26a767
26a767
    $num_persistent = $i;
26a767
}
26a767
26a767
# print out list of ethernet devices to file
26a767
sub commit_persistent {
26a767
    my $i;
26a767
    my $eth;
26a767
26a767
    open(PF, ">$persistence_file");
26a767
    
26a767
    for ($i = 0; $i < $num_persistent; $i++) {
26a767
	$eth = $persistence_array[$i];
26a767
	if ($eth =~ /[\w]+[\d]/) {
26a767
	    print(PF "$persistence_array[$i]\n");
26a767
	}
26a767
    }
26a767
26a767
    close(PF);
26a767
}
26a767
26a767
sub delete_persistent {
26a767
    my $eth = $_[0];
26a767
    
26a767
    if (defined($persistence_hash{$eth})) {
26a767
	$persistence_array[$persistence_hash{$eth}] = "";
26a767
    }
26a767
}
26a767
26a767
sub add_persistent {
26a767
    my $eth = $_[0];
26a767
26a767
    # Is this one already in the persistence list?
26a767
    if (!defined($persistence_hash{$eth})) {
26a767
	$persistence_array[$num_persistent] = $eth;
26a767
	$persistence_hash{$eth} = $num_persistent;
26a767
	$num_persistent++;
26a767
    }
26a767
}
26a767
26a767
# add new rxe device to eth if not already up
26a767
sub rxe_add {
26a767
    my $eth = $_[0];
26a767
26a767
    if (!($eth =~ /[\w]+[\d]/)) {
26a767
	print "eth_name ($eth) looks bogus\n";
26a767
	return;
26a767
    }
26a767
26a767
    if (!defined($rxe_names{$eth})) {
26a767
	system("echo '$eth' > $parms/add");
26a767
    }
26a767
    if (!$no_persist) {
26a767
	add_persistent($eth);
26a767
	commit_persistent();
26a767
    }
26a767
}
26a767
26a767
sub rxe_remove {
26a767
    my $arg2 = $_[0];
26a767
    my $rxe;
26a767
    my $eth;
26a767
26a767
    print "remove $arg2\n"  if ($debug > 0);
26a767
26a767
    if ($arg2 =~ /[\w]+[\d]/) {
26a767
	$eth = $arg2;
26a767
	$rxe = $rxe_names{$eth};
26a767
    }
26a767
    elsif ($arg2 =~ /rxe[0123456789]/) {
26a767
	$rxe = $arg2;
26a767
	$eth = $eth_names{$rxe};
26a767
    }
26a767
    elsif ($arg2 eq "all") {
26a767
	$rxe = "all";
26a767
    }
26a767
26a767
    if (($rxe eq "all") || ($rxe =~ /^rxe[0123456789]/)) {
26a767
	my $cmd = "echo '$rxe' > $parms/remove";
26a767
	#print "$cmd\n";
26a767
	system($cmd);
26a767
	if (!$no_persist) {
26a767
	    if ($rxe eq "all") {
26a767
		unlink($persistence_file);
26a767
	    }
26a767
	    elsif ($eth =~/[\w]+[\d]/) {
26a767
		delete_persistent($eth);
26a767
		commit_persistent();
26a767
	    }
26a767
	    else {
26a767
		print "Warning: Unable to resolve ethname; "
26a767
		    . "instance may persist on restart\n";
26a767
	    }
26a767
	}
26a767
    }
26a767
    else {
26a767
	print "rxe instance $rxe not found\n";
26a767
    }
26a767
}
26a767
26a767
sub get_devinfo {
26a767
    my $rxe = $_[0];
26a767
26a767
    my $cmd = "ibv_devinfo -d $rxe";
26a767
    return `$cmd`;
26a767
}
26a767
26a767
# allow unsupported modules to load in SLES11 if allowed
26a767
sub modprobe {
26a767
    my $module = $_[0];
26a767
    my $opts = $_[1];
26a767
    my @lines;
26a767
    my $line;
26a767
26a767
    if ($modprobe_checked == "0") {
26a767
	@lines = `modprobe -c`;
26a767
	foreach $line (@lines) {
26a767
	    if ($line =~ /^allow_unsupported_modules  *0/) {
26a767
		$modprobe_opt = " --allow-unsupported-modules ";
26a767
		last;
26a767
	    }
26a767
	}
26a767
	$modprobe_checked = "1";
26a767
    }
26a767
26a767
    if (!defined($opts)) {
26a767
	$opts = "";
26a767
    }
26a767
26a767
    system("modprobe $modprobe_opt $module $opts");
26a767
}
26a767
26a767
# bring up rxe
26a767
sub do_start {
26a767
    my $proto_str = "";
26a767
26a767
    system("mkdir -p $persistence_path");
26a767
    system("touch $persistence_file");
26a767
26a767
    modprobe("ib_core");
26a767
    modprobe("ib_uverbs");
26a767
    modprobe("rdma_ucm");
26a767
    modprobe("rdma_rxe");
26a767
26a767
    populate_persistence();
26a767
    system("udevadm control --reload");
26a767
26a767
    foreach my $eth (@persistence_array) {
26a767
	rxe_add($eth);
26a767
    }
26a767
26a767
    get_names();
26a767
26a767
    foreach my $rxe (@rxe_array) {
26a767
	my $stat = get_devinfo($rxe);
26a767
	if ($stat =~ "PORT_DOWN") {
26a767
		my $cmd = "ip link set $eth_names{$rxe} up";
26a767
		system($cmd);
26a767
	}
26a767
    }
26a767
26a767
}
26a767
26a767
# check if argument is an integer
26a767
sub is_integer {
26a767
    defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
26a767
}
26a767
26a767
# remove all rxe devices and unload drivers
26a767
sub do_stop {
26a767
    my $rxe;
26a767
26a767
    foreach $rxe (@rxe_array) {
26a767
	system("echo '$rxe' > $sys/remove");
26a767
    }
26a767
26a767
    if (-e $sys) {
26a767
	system("rmmod rdma_rxe");
26a767
    }
26a767
26a767
    if (-e $sys) {
26a767
	print "unable to unload drivers, reboot required\n";
26a767
    }
26a767
}
26a767
26a767
sub do_debug {
26a767
    my $arg2 = $_[0];
26a767
    my $debugfile = "$parms/debug";
26a767
    chomp($arg2);
26a767
26a767
    if (!(-e "$debugfile")) {
26a767
	print "Error: debug is compiled out of this rxe driver\n";
26a767
	return;
26a767
    }
26a767
26a767
    if    ($arg2 eq "on")  { system("echo '31' > $debugfile"); }
26a767
    elsif ($arg2 eq "off") { system("echo '0'  > $debugfile"); }
26a767
    elsif ($arg2 eq "0")   { system("echo '0'  > $debugfile"); }
26a767
    elsif ($arg2 eq "")    { }
26a767
	elsif ($arg2 ge "0" && $arg2 le "31") {
26a767
	    system("echo '$arg2' > $debugfile");
26a767
	}
26a767
	else {
26a767
	    print "unrecognized debug cmd ($arg2)\n";
26a767
	}
26a767
26a767
    my $current = read_file($debugfile);
26a767
    chomp($current);
26a767
    if ($current > 0) {
26a767
	print "Debug is ON ($current)\n";
26a767
    }
26a767
    elsif ($current == 0) {
26a767
	print "Debug is OFF\n";
26a767
    }
26a767
    else {
26a767
	print "Unrecognized debug value\n";
26a767
    }
26a767
}
26a767
26a767
sub max {
26a767
    my $a = $_[0];
26a767
    my $b = $_[1];
26a767
    return $a if ($a > $b);
26a767
    return $b;
26a767
}
26a767
26a767
# show usage for rxe_cfg
26a767
sub usage {
26a767
    print "  Usage:\n";
26a767
    print "    rxe_cfg [options] start|stop|status|persistent\n";
26a767
    print "    rxe_cfg debug on|off|<num>\n";
26a767
    print "    rxe_cfg [-n] add <ndev>\n";
26a767
    print "    rxe_cfg [-n] remove <ndev>|<rdev>\n";
26a767
    print "\n";
26a767
    print "    <ndev> = network device e.g. eth3\n";
26a767
    print "    <rdev> = rdma device e.g. rxe1\n";
26a767
    print "\n";
26a767
    print "  Options:\n";
26a767
    print "    -h: print this usage information\n";
26a767
    print "    -n: do not make the configuration action persistent\n";
26a767
    print "    -v: print additional debug output\n";
26a767
    print "    -l: show status for interfaces with link up\n";
26a767
    print "    -p <num>: (start command only) - set ethertype\n";
26a767
}
26a767
26a767
sub main {
26a767
    GetOptions(
26a767
	   "-h"          => \$help,
26a767
	   "--help"      => \$help,
26a767
	   "-n"          => \$no_persist,
26a767
	   "-v:+"        => \$debug,
26a767
	   "-f"          => \$force,
26a767
	   "-l"          => \$linkonly,
26a767
	   );
26a767
26a767
    my $arg1 = $ARGV[0];
26a767
    my $arg2 = $ARGV[1];
26a767
    my $arg3 = $ARGV[2];
26a767
26a767
    # status is the default
26a767
    if (!defined($arg1) || ($arg1 =~ /status/)) {
26a767
        do_status($arg2);
26a767
        exit;
26a767
    }
26a767
26a767
    if ($help) {
26a767
        usage();
26a767
        exit;
26a767
    }
26a767
26a767
    # stuff that does not require modules to be loaded
26a767
    if    ($arg1 eq "help")       { usage(); exit; }
26a767
    elsif ($arg1 eq "start")      { do_start(); do_status(); exit; }
26a767
    elsif ($arg1 eq "persistent") { system("cat $persistence_file"); exit; }
26a767
26a767
26a767
    # can't do much else, bail if modules aren't loaded
26a767
    if (check_module_status()) {
26a767
	exit;
26a767
    }
26a767
26a767
    # create persistence file if necessary
26a767
    make_path($persistence_path);
26a767
    if (!(-e $persistence_file)) {
26a767
        `touch $persistence_file`;
26a767
    }
26a767
26a767
    # Get full context of the configuration
26a767
    populate_persistence();
26a767
    get_names();
26a767
    get_dev_info();
26a767
26a767
    # Stuff that requires the rdma_rxe module to be loaded
26a767
    if    ($arg1 eq "stop")   { do_stop(); 	   exit; }
26a767
    elsif ($arg1 eq "debug")  { do_debug($arg2);   exit; }
26a767
    elsif ($arg1 eq "add")    { rxe_add($arg2);    exit; }
26a767
    elsif ($arg1 eq "remove") { rxe_remove($arg2); exit; }
26a767
    elsif ($arg1 eq "help")   { usage();	   exit; }
26a767
}
26a767
26a767
main();
26a767
26a767
exit;