2022-02-16 01:52:14

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 0/9] Add a tool for using the new sysfs files

From: Anna Schumaker <[email protected]>

These patches implement a tool that can be used to read and write the
sysfs files, with subcommands!

The following subcommands are implemented:
rpcctl client
rpcctl client show
rpcctl switch
rpcctl switch set
rpcctl switch show
rpcctl xprt
rpcctl xprt remove
rpcctl xprt set
rpcctl xprt show

So you can print out information about every switch with:
anna@client ~ % rpcctl switch
switch-0: xprts 1, active 1, queue 0
xprt-0: local, /var/run/gssproxy.sock [main]
switch-1: xprts 1, active 1, queue 0
xprt-1: local, /var/run/rpcbind.sock [main]
switch-2: xprts 1, active 1, queue 0
xprt-2: tcp, 192.168.111.1 [main]
switch-3: xprts 4, active 4, queue 0
xprt-3: tcp, 192.168.111.188 [main]
xprt-4: tcp, 192.168.111.188
xprt-5: tcp, 192.168.111.188
xprt-6: tcp, 192.168.111.188

And information about each xprt:
anna@client ~ % rpcctl xprt
xprt-0: local, /var/run/gssproxy.sock, port 0, state <CONNECTED,BOUND>, main
Source: (einval), port 0, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-1: local, /var/run/rpcbind.sock, port 0, state <CONNECTED,BOUND>, main
Source: (einval), port 0, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-2: tcp, 192.168.111.1, port 2049, state <CONNECTED,BOUND>, main
Source: 192.168.111.222, port 959, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-3: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>, main
Source: 192.168.111.222, port 921, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-4: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
Source: 192.168.111.222, port 726, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-5: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
Source: 192.168.111.222, port 671, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
xprt-6: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
Source: 192.168.111.222, port 934, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0

You can use the `set` subcommand to change the dstaddr of individual xprts:
anna@client ~ % sudo rpcctl xprt show xprt-4
xprt-4: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
Source: 192.168.111.222, port 726, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0

anna@client ~ % sudo rpcctl xprt set xprt-4 dstaddr server2.nowheycreamery.com
xprt-4: tcp, 192.168.111.186, port 2049, state <CONNECTED,BOUND>
Source: 192.168.111.222, port 726, Requests: 2
Congestion: cur 0, win 256, Slots: min 2, max 65536
Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0

Or for changing the dstaddr of all xprts attached to a switch:
anna@client % rpcctl switch show switch-3
switch-3: xprts 4, active 4, queue 0
xprt 3: tcp, 192.168.111.188 [main]
xprt 4: tcp, 192.168.111.188
xprt 5: tcp, 192.168.111.188
xprt 6: tcp, 192.168.111.188

anna@client % sudo rpcctl switch set switch-3 dstaddr server2.nowheycreamery.vm
switch-3: xprts 4, active 4, queue 0
xprt 2: tcp, 192.168.111.186 [main]
xprt 3: tcp, 192.168.111.186
xprt 5: tcp, 192.168.111.186
xprt 6: tcp, 192.168.111.186

Changes in v8:
- Improved exception handling when running commands
- Completely rework argument and command parsing to be more like ip-link
- Completely rewrite the man page to reflect the new argument scheme and
add examples
- Only call socket.gethostbyname() once when changing the dstaddr of an
RPC switch

Thoughts?
Anna


Anna Schumaker (9):
rpcctl: Add a rpcctl.py tool
rpcctl: Add a command for printing xprt switch information
rpcctl: Add a command for printing individual xprts
rpcctl: Add a command for printing rpc client information
rpcctl: Add a command for changing xprt dstaddr
rpcctl: Add a command for changing xprt switch dstaddrs
rpcctl: Add a command for changing xprt state
rpcctl: Add a man page
rpcctl: Add installation to the Makefile

configure.ac | 1 +
tools/Makefile.am | 2 +-
tools/rpcctl/Makefile.am | 13 ++
tools/rpcctl/rpcctl.man | 67 ++++++++++
tools/rpcctl/rpcctl.py | 255 +++++++++++++++++++++++++++++++++++++++
5 files changed, 337 insertions(+), 1 deletion(-)
create mode 100644 tools/rpcctl/Makefile.am
create mode 100644 tools/rpcctl/rpcctl.man
create mode 100755 tools/rpcctl/rpcctl.py

--
2.35.1


2022-02-16 03:35:15

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 7/9] rpcctl: Add a command for changing xprt state

From: Anna Schumaker <[email protected]>

We can set it offline or online, or we can remove an xprt. The kernel
only supports removing offlined transports, so we make sure to set the
state to "offline" before sending the remove command.

Signed-off-by: Anna Schumaker <[email protected]>
---
tools/rpcctl/rpcctl.py | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/tools/rpcctl/rpcctl.py b/tools/rpcctl/rpcctl.py
index 0fbce99fff5b..b8df556b682c 100755
--- a/tools/rpcctl/rpcctl.py
+++ b/tools/rpcctl/rpcctl.py
@@ -48,9 +48,7 @@ class Xprt:
self.info = read_info_file(path / "xprt_info")
self.dstaddr = read_addr_file(path / "dstaddr")
self.srcaddr = read_addr_file(path / "srcaddr")
-
- with open(path / "xprt_state") as f:
- self.state = ','.join(f.readline().split()[1:])
+ self.read_state()

def __lt__(self, rhs):
return self.name < rhs.name
@@ -74,9 +72,16 @@ class Xprt:
f"backlog {self.info['backlog_q_len']}, tasks {self.info['tasks_queuelen']}"

def __str__(self):
+ if not self.path.exists():
+ return f"{self.name}: has been removed"
return "\n".join([self._xprt(), self._src_reqs(),
self._cong_slots(), self._queues() ])

+ def read_state(self):
+ if self.path.exists():
+ with open(self.path / "xprt_state") as f:
+ self.state = ','.join(f.readline().split()[1:])
+
def small_str(self):
main = " [main]" if self.info.get("main_xprt") else ""
return f"{self.name}: {self.type}, {self.dstaddr}{main}"
@@ -84,11 +89,21 @@ class Xprt:
def set_dstaddr(self, newaddr):
self.dstaddr = write_addr_file(self.path / "dstaddr", newaddr)

+ def set_state(self, state):
+ with open(self.path / "xprt_state", 'w') as f:
+ f.write(state)
+ self.read_state()
+
def add_command(subparser):
parser = subparser.add_parser("xprt", help="Commands for individual xprts")
parser.set_defaults(func=Xprt.show, xprt=None)
subparser = parser.add_subparsers()

+ remove = subparser.add_parser("remove", help="Remove an xprt")
+ remove.add_argument("xprt", metavar="XPRT", nargs=1,
+ help="Name of the xprt to remove")
+ remove.set_defaults(func=Xprt.set_property, property="remove")
+
show = subparser.add_parser("show", help="Show xprts")
show.add_argument("xprt", metavar="XPRT", nargs='?',
help="Name of a specific xprt to show")
@@ -98,6 +113,10 @@ class Xprt:
set.add_argument("xprt", metavar="XPRT", nargs=1,
help="Name of a specific xprt to modify")
subparser = set.add_subparsers(required=True)
+ online = subparser.add_parser("online", help="Set an xprt online")
+ online.set_defaults(func=Xprt.set_property, property="online")
+ offline = subparser.add_parser("offline", help="Set an xprt offline")
+ offline.set_defaults(func=Xprt.set_property, property="offline")
dstaddr = subparser.add_parser("dstaddr", help="Change an xprt's dstaddr")
dstaddr.add_argument("newaddr", metavar="NEWADDR", nargs=1,
help="The new address for the xprt")
@@ -119,6 +138,11 @@ class Xprt:
for xprt in Xprt.get_by_name(args.xprt[0]):
if args.property == "dstaddr":
xprt.set_dstaddr(socket.gethostbyname(args.newaddr[0]))
+ elif args.property == "remove":
+ xprt.set_state("offline")
+ xprt.set_state("remove")
+ else:
+ args.set_state(args.property)
print(xprt)


--
2.35.1

2022-02-16 06:15:34

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 2/9] rpcctl: Add a command for printing xprt switch information

From: Anna Schumaker <[email protected]>

This combines the information found in xprt_switch_info with a subset of
the information found in each xprt subdirectory

Signed-off-by: Anna Schumaker <[email protected]>
---
v8: Handle Exceptions when running commands
---
tools/rpcctl/rpcctl.py | 80 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/tools/rpcctl/rpcctl.py b/tools/rpcctl/rpcctl.py
index 9737ac4a9740..1eb0454aaf58 100755
--- a/tools/rpcctl/rpcctl.py
+++ b/tools/rpcctl/rpcctl.py
@@ -1,5 +1,6 @@
#!/usr/bin/python3
import argparse
+import collections
import pathlib
import sys

@@ -14,6 +15,76 @@ if not sunrpc.is_dir():
print("ERROR: sysfs does not have sunrpc directory")
sys.exit(1)

+def read_addr_file(path):
+ try:
+ with open(path, 'r') as f:
+ return f.readline().strip()
+ except:
+ return "(enoent)"
+
+def read_info_file(path):
+ res = collections.defaultdict(int)
+ try:
+ with open(path) as info:
+ lines = [ l.split("=", 1) for l in info if "=" in l ]
+ res.update({ key:int(val.strip()) for (key, val) in lines })
+ finally:
+ return res
+
+
+class Xprt:
+ def __init__(self, path):
+ self.path = path
+ self.name = path.stem.rsplit("-", 1)[0]
+ self.type = path.stem.split("-")[2]
+ self.dstaddr = read_addr_file(path / "dstaddr")
+
+ def __lt__(self, rhs):
+ return self.name < rhs.name
+
+ def small_str(self):
+ return f"{self.name}: {self.type}, {self.dstaddr}"
+
+
+class XprtSwitch:
+ def __init__(self, path):
+ self.path = path
+ self.name = path.stem
+ self.info = read_info_file(path / "xprt_switch_info")
+ self.xprts = sorted([ Xprt(p) for p in self.path.iterdir() if p.is_dir() ])
+
+ def __lt__(self, rhs):
+ return self.name < rhs.name
+
+ def __str__(self):
+ switch = f"{self.name}: " \
+ f"xprts {self.info['num_xprts']}, " \
+ f"active {self.info['num_active']}, " \
+ f"queue {self.info['queue_len']}"
+ xprts = [ f" {x.small_str()}" for x in self.xprts ]
+ return "\n".join([ switch ] + xprts)
+
+ def add_command(subparser):
+ parser = subparser.add_parser("switch", help="Commands for xprt switches")
+ parser.set_defaults(func=XprtSwitch.show, switch=None)
+ subparser = parser.add_subparsers()
+
+ show = subparser.add_parser("show", help="Show xprt switches")
+ show.add_argument("switch", metavar="SWITCH", nargs='?',
+ help="Name of a specific switch to show")
+ show.set_defaults(func=XprtSwitch.show)
+
+ def get_by_name(name):
+ xprt_switches = sunrpc / "xprt-switches"
+ if name:
+ return [ XprtSwitch(xprt_switches / name) ]
+ return [ XprtSwitch(f) for f in sorted(xprt_switches.iterdir()) ]
+
+ def show(args):
+ for switch in XprtSwitch.get_by_name(args.switch):
+ print(switch)
+
+
parser = argparse.ArgumentParser()

def show_small_help(args):
@@ -21,5 +92,12 @@ def show_small_help(args):
print("sunrpc dir:", sunrpc)
parser.set_defaults(func=show_small_help)

+subparser = parser.add_subparsers(title="commands")
+XprtSwitch.add_command(subparser)
+
args = parser.parse_args()
-args.func(args)
+try:
+ args.func(args)
+except Exception as e:
+ print(str(e))
+ sys.exit(1)
--
2.35.1

2022-02-16 06:37:56

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 4/9] rpcctl: Add a command for printing rpc client information

From: Anna Schumaker <[email protected]>

It's mostly the same information as with xprt-switches, except with
rpc-client id prepended to the first line.

Signed-off-by: Anna Schumaker <[email protected]>
---
v8: Better exception handling if an RpcClient isn't found
---
tools/rpcctl/rpcctl.py | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/tools/rpcctl/rpcctl.py b/tools/rpcctl/rpcctl.py
index 6b9627318949..2e710b5627f0 100755
--- a/tools/rpcctl/rpcctl.py
+++ b/tools/rpcctl/rpcctl.py
@@ -99,17 +99,18 @@ class Xprt:


class XprtSwitch:
- def __init__(self, path):
+ def __init__(self, path, sep=":"):
self.path = path
self.name = path.stem
self.info = read_info_file(path / "xprt_switch_info")
self.xprts = sorted([ Xprt(p) for p in self.path.iterdir() if p.is_dir() ])
+ self.sep = sep

def __lt__(self, rhs):
return self.name < rhs.name

def __str__(self):
- switch = f"{self.name}: " \
+ switch = f"{self.name}{self.sep} " \
f"xprts {self.info['num_xprts']}, " \
f"active {self.info['num_active']}, " \
f"queue {self.info['queue_len']}"
@@ -137,6 +138,39 @@ class XprtSwitch:
print(switch)


+class RpcClient:
+ def __init__(self, path):
+ self.path = path
+ self.name = path.stem
+ self.switch = XprtSwitch(path / (path / "switch").readlink(), sep=",")
+
+ def __lt__(self, rhs):
+ return self.name < rhs.name
+
+ def __str__(self):
+ return f"{self.name}: {self.switch}"
+
+ def add_command(subparser):
+ parser = subparser.add_parser("client", help="Commands for rpc clients")
+ parser.set_defaults(func=RpcClient.show, client=None)
+ subparser = parser.add_subparsers()
+
+ show = subparser.add_parser("show", help="Show rpc clients")
+ show.add_argument("client", metavar="CLIENT", nargs='?',
+ help="Name of a specific rpc client to show")
+ parser.set_defaults(func=RpcClient.show)
+
+ def get_by_name(name):
+ rpc_clients = sunrpc / "rpc-clients"
+ if name:
+ return [ RpcClient(rpc_clients / name) ]
+ return [ RpcClient(f) for f in sorted(rpc_clients.iterdir()) ]
+
+ def show(args):
+ for client in RpcClient.get_by_name(args.client):
+ print(client)
+
+
parser = argparse.ArgumentParser()

def show_small_help(args):
@@ -145,6 +179,7 @@ def show_small_help(args):
parser.set_defaults(func=show_small_help)

subparser = parser.add_subparsers(title="commands")
+RpcClient.add_command(subparser)
XprtSwitch.add_command(subparser)
Xprt.add_command(subparser)

--
2.35.1

2022-02-16 07:29:29

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 1/9] rpcctl: Add a rpcctl.py tool

From: Anna Schumaker <[email protected]>

This will be used to print and manipulate the sunrpc sysfs directory
files. Running without arguments prints both usage information and the
location of the sunrpc sysfs directory.

Signed-off-by: Anna Schumaker <[email protected]>
---
tools/rpcctl/rpcctl.py | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100755 tools/rpcctl/rpcctl.py

diff --git a/tools/rpcctl/rpcctl.py b/tools/rpcctl/rpcctl.py
new file mode 100755
index 000000000000..9737ac4a9740
--- /dev/null
+++ b/tools/rpcctl/rpcctl.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+import argparse
+import pathlib
+import sys
+
+with open("/proc/mounts", 'r') as f:
+ mount = [ line.split()[1] for line in f if "sysfs" in line ]
+ if len(mount) == 0:
+ print("ERROR: sysfs is not mounted")
+ sys.exit(1)
+
+sunrpc = pathlib.Path(mount[0]) / "kernel" / "sunrpc"
+if not sunrpc.is_dir():
+ print("ERROR: sysfs does not have sunrpc directory")
+ sys.exit(1)
+
+parser = argparse.ArgumentParser()
+
+def show_small_help(args):
+ parser.print_usage()
+ print("sunrpc dir:", sunrpc)
+parser.set_defaults(func=show_small_help)
+
+args = parser.parse_args()
+args.func(args)
--
2.35.1

2022-02-16 07:34:54

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v8 5/9] rpcctl: Add a command for changing xprt dstaddr

From: Anna Schumaker <[email protected]>

Using the socket module for dns resolution

Signed-off-by: Anna Schumaker <[email protected]>
---
tools/rpcctl/rpcctl.py | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/tools/rpcctl/rpcctl.py b/tools/rpcctl/rpcctl.py
index 2e710b5627f0..98e1f680ed72 100755
--- a/tools/rpcctl/rpcctl.py
+++ b/tools/rpcctl/rpcctl.py
@@ -4,6 +4,7 @@ import collections
import errno
import os
import pathlib
+import socket
import sys

with open("/proc/mounts", 'r') as f:
@@ -24,6 +25,11 @@ def read_addr_file(path):
except:
return "(enoent)"

+def write_addr_file(path, newaddr):
+ with open(path, 'w') as f:
+ f.write(newaddr)
+ return read_addr_file(path)
+
def read_info_file(path):
res = collections.defaultdict(int)
try:
@@ -75,6 +81,10 @@ class Xprt:
main = " [main]" if self.info.get("main_xprt") else ""
return f"{self.name}: {self.type}, {self.dstaddr}{main}"

+ def set_dstaddr(self, newaddr):
+ resolved = socket.gethostbyname(newaddr)
+ self.dstaddr = write_addr_file(self.path / "dstaddr", newaddr)
+
def add_command(subparser):
parser = subparser.add_parser("xprt", help="Commands for individual xprts")
parser.set_defaults(func=Xprt.show, xprt=None)
@@ -85,6 +95,15 @@ class Xprt:
help="Name of a specific xprt to show")
show.set_defaults(func=Xprt.show)

+ set = subparser.add_parser("set", help="Change an xprt property")
+ set.add_argument("xprt", metavar="XPRT", nargs=1,
+ help="Name of a specific xprt to modify")
+ subparser = set.add_subparsers(required=True)
+ dstaddr = subparser.add_parser("dstaddr", help="Change an xprt's dstaddr")
+ dstaddr.add_argument("newaddr", metavar="NEWADDR", nargs=1,
+ help="The new address for the xprt")
+ dstaddr.set_defaults(func=Xprt.set_property, property="dstaddr")
+
def get_by_name(name):
glob = f"**/{name}-*" if name else "**/xprt-*"
res = [ Xprt(x) for x in (sunrpc / "xprt-switches").glob(glob) ]
@@ -97,6 +116,12 @@ class Xprt:
for xprt in Xprt.get_by_name(args.xprt):
print(xprt)

+ def set_property(args):
+ for xprt in Xprt.get_by_name(args.xprt[0]):
+ if args.property == "dstaddr":
+ xprt.set_dstaddr(socket.gethostbyname(args.newaddr[0]))
+ print(xprt)
+

class XprtSwitch:
def __init__(self, path, sep=":"):
--
2.35.1

2022-02-24 01:28:24

by Steve Dickson

[permalink] [raw]
Subject: Re: [PATCH v8 0/9] Add a tool for using the new sysfs files



On 2/15/22 2:21 PM, [email protected] wrote:
> From: Anna Schumaker <[email protected]>
>
> These patches implement a tool that can be used to read and write the
> sysfs files, with subcommands!
>
> The following subcommands are implemented:
> rpcctl client
> rpcctl client show
> rpcctl switch
> rpcctl switch set
> rpcctl switch show
> rpcctl xprt
> rpcctl xprt remove
> rpcctl xprt set
> rpcctl xprt show
>
> So you can print out information about every switch with:
> anna@client ~ % rpcctl switch
> switch-0: xprts 1, active 1, queue 0
> xprt-0: local, /var/run/gssproxy.sock [main]
> switch-1: xprts 1, active 1, queue 0
> xprt-1: local, /var/run/rpcbind.sock [main]
> switch-2: xprts 1, active 1, queue 0
> xprt-2: tcp, 192.168.111.1 [main]
> switch-3: xprts 4, active 4, queue 0
> xprt-3: tcp, 192.168.111.188 [main]
> xprt-4: tcp, 192.168.111.188
> xprt-5: tcp, 192.168.111.188
> xprt-6: tcp, 192.168.111.188
>
> And information about each xprt:
> anna@client ~ % rpcctl xprt
> xprt-0: local, /var/run/gssproxy.sock, port 0, state <CONNECTED,BOUND>, main
> Source: (einval), port 0, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-1: local, /var/run/rpcbind.sock, port 0, state <CONNECTED,BOUND>, main
> Source: (einval), port 0, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-2: tcp, 192.168.111.1, port 2049, state <CONNECTED,BOUND>, main
> Source: 192.168.111.222, port 959, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-3: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>, main
> Source: 192.168.111.222, port 921, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-4: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
> Source: 192.168.111.222, port 726, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-5: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
> Source: 192.168.111.222, port 671, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
> xprt-6: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
> Source: 192.168.111.222, port 934, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
>
> You can use the `set` subcommand to change the dstaddr of individual xprts:
> anna@client ~ % sudo rpcctl xprt show xprt-4
> xprt-4: tcp, 192.168.111.188, port 2049, state <CONNECTED,BOUND>
> Source: 192.168.111.222, port 726, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
>
> anna@client ~ % sudo rpcctl xprt set xprt-4 dstaddr server2.nowheycreamery.com
> xprt-4: tcp, 192.168.111.186, port 2049, state <CONNECTED,BOUND>
> Source: 192.168.111.222, port 726, Requests: 2
> Congestion: cur 0, win 256, Slots: min 2, max 65536
> Queues: binding 0, sending 0, pending 0, backlog 0, tasks 0
>
> Or for changing the dstaddr of all xprts attached to a switch:
> anna@client % rpcctl switch show switch-3
> switch-3: xprts 4, active 4, queue 0
> xprt 3: tcp, 192.168.111.188 [main]
> xprt 4: tcp, 192.168.111.188
> xprt 5: tcp, 192.168.111.188
> xprt 6: tcp, 192.168.111.188
>
> anna@client % sudo rpcctl switch set switch-3 dstaddr server2.nowheycreamery.vm
> switch-3: xprts 4, active 4, queue 0
> xprt 2: tcp, 192.168.111.186 [main]
> xprt 3: tcp, 192.168.111.186
> xprt 5: tcp, 192.168.111.186
> xprt 6: tcp, 192.168.111.186
>
> Changes in v8:
> - Improved exception handling when running commands
> - Completely rework argument and command parsing to be more like ip-link
> - Completely rewrite the man page to reflect the new argument scheme and
> add examples
> - Only call socket.gethostbyname() once when changing the dstaddr of an
> RPC switch
>
> Thoughts?
> Anna
>
>
> Anna Schumaker (9):
> rpcctl: Add a rpcctl.py tool
> rpcctl: Add a command for printing xprt switch information
> rpcctl: Add a command for printing individual xprts
> rpcctl: Add a command for printing rpc client information
> rpcctl: Add a command for changing xprt dstaddr
> rpcctl: Add a command for changing xprt switch dstaddrs
> rpcctl: Add a command for changing xprt state
> rpcctl: Add a man page
> rpcctl: Add installation to the Makefile
>
> configure.ac | 1 +
> tools/Makefile.am | 2 +-
> tools/rpcctl/Makefile.am | 13 ++
> tools/rpcctl/rpcctl.man | 67 ++++++++++
> tools/rpcctl/rpcctl.py | 255 +++++++++++++++++++++++++++++++++++++++
> 5 files changed, 337 insertions(+), 1 deletion(-)
> create mode 100644 tools/rpcctl/Makefile.am
> create mode 100644 tools/rpcctl/rpcctl.man
> create mode 100755 tools/rpcctl/rpcctl.py
>
Committed... (tag: nfs-utils-2-6-2-rc2)

steved.