Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_init / nfsdump.pl
diff --git a/TBBT/trace_init/nfsdump.pl b/TBBT/trace_init/nfsdump.pl
new file mode 100755 (executable)
index 0000000..69eca84
--- /dev/null
@@ -0,0 +1,338 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: nfsdump.pl,v 1.5 2003/07/26 20:52:04 ellard Exp $\r
+#\r
+# Utility for dealing with raw nfsdump records.\r
+\r
+package nfsd;\r
+\r
+# If $AllowRisky is set, then allow some optimizations that might be\r
+# "risky" in bizarre situations (but have never been observed to\r
+# actually break anything).  By default, no riskiness is permitted.\r
+\r
+$AllowRisky    = 0;\r
+\r
+# nfsDumpParseLine -- initializes the global associative array\r
+# %nfsd'nfsDumpLine with information about a record from nfsdump. \r
+# Returns an empty list if anything goes wrong.  Otherwise, returns a\r
+# list of the protocol (eg R2, C2, R3, C3), the name of the operation,\r
+# and the xid, the client host ID, the time, and for responses, the\r
+# status (via nfsDumpParseLineHeader).  The reason for this particular\r
+# return list is that these are very frequently-accessed values, so it\r
+# can save time to avoid going through the associative array to access\r
+# them.\r
+#\r
+# All records begin with several fixed fields, and then are followed\r
+# by some number of name/value pairs, and finally some diagnostic\r
+# fields (which are mostly ignored by this routine-- the only\r
+# diagnostic this routine cares about is whether the packet as part of\r
+# a jumbo packet or not.  If so, then 'truncated' is set.)\r
+\r
+sub nfsDumpParseLine {\r
+       my ($line, $total) = @_;\r
+\r
+       my (@rl) = &nfsDumpParseLineHeader ($line);\r
+\r
+       if (@rl && $total) {\r
+               &nfsDumpParseLineBody ($line);\r
+       }\r
+\r
+       return @rl;\r
+}\r
+\r
+sub nfsDumpParseLineBody {\r
+       my ($line) = @_;\r
+       my $i;\r
+       my $client_id;\r
+       my $reseen;\r
+\r
+       undef %nfsDumpLine;\r
+\r
+       # If the line doesn't start with a digit, then it's certainly\r
+       # not properly formed, so bail out immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return undef;\r
+       }\r
+\r
+       my @l = split (' ', $line);\r
+       my $lineLen = @l;\r
+       if ($l[$lineLen - 1] eq 'LONGPKT') {\r
+               splice (@l, $lineLen - 1);\r
+               $nfsDumpLine{'truncated'} = 1;\r
+               $lineLen--;\r
+       }\r
+\r
+       $nfsDumpLine{'time'}    = $l[0];\r
+       $nfsDumpLine{'srchost'} = $l[1];\r
+       $nfsDumpLine{'deshost'} = $l[2];\r
+       $nfsDumpLine{'proto'}   = $l[4];\r
+       $nfsDumpLine{'xid'}     = $l[5];\r
+       $nfsDumpLine{'opcode'}  = $l[6];\r
+       $nfsDumpLine{'opname'}  = $l[7];\r
+\r
+       if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {\r
+               $nfsDumpLine{'status'}  = $l[8];\r
+\r
+               $client_id = $l[2];\r
+               $reseen = 0;\r
+               for ($i = 9; $i < $lineLen - 10; $i += 2) {\r
+                       if (defined $nfsDumpLine{$l[$i]}) {\r
+                               $reseen = 1;\r
+                               $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];\r
+                       }\r
+                       else {\r
+                               $nfsDumpLine{$l[$i]} = $l[$i + 1];\r
+                       }\r
+               }\r
+       }\r
+       else {\r
+               $client_id = $l[1];\r
+               $reseen = 0;\r
+               for ($i = 8; $i < $lineLen - 6; $i += 2) {\r
+                       if (defined $nfsDumpLine{$l[$i]}) {\r
+                               $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];\r
+                               $reseen = 1;\r
+                       }\r
+                       else {\r
+                               $nfsDumpLine{$l[$i]} = $l[$i + 1];\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+# Returns an empty list if anything goes wrong.  Otherwise, returns a\r
+# list of the protocol (eg R2, C2, R3, C3), the name of the operation,\r
+# and the xid, the client host ID, and time, and the response status. \r
+# (For call messages, the status is 'na'.)\r
+\r
+sub nfsDumpParseLineHeader {\r
+       my ($line) = @_;\r
+\r
+       # If the line doesn't start with a digit, then it's certainly\r
+       # not properly formed, so bail out immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return ();\r
+       }\r
+       else {\r
+               my $client_id;\r
+               my $status;\r
+\r
+               my @l = split (' ', $line, 10);\r
+\r
+\r
+               if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {\r
+                       $client_id = $l[2];\r
+                       $status = $l[8];\r
+               }\r
+               else {\r
+                       $client_id = $l[1];\r
+                       $status = 'na';\r
+               }\r
+\r
+               return ($l[4], $l[7], $l[5], $client_id, $l[0], $status);\r
+       }\r
+}\r
+\r
+# nfsDumpParseLineFields -- Just return a subset of the fields,\r
+# without parsing the entire line.\r
+\r
+sub nfsDumpParseLineFields {\r
+       my ($line, @fields) = @_;\r
+       my $i;\r
+\r
+       # If the line doesn't start with a digit, then\r
+       # it's certainly not properly formed, so bail out\r
+       # immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return ();\r
+       }\r
+\r
+       my $rest;\r
+       if ($AllowRisky) {\r
+               $rest = $line;\r
+       }\r
+       else {\r
+               my @foo = split (' ', $line, 9);\r
+               $rest = ' ' . $foo[8];\r
+       }\r
+\r
+       my $fl = @fields;\r
+       my @l = ();\r
+       for ($i = 0; $i < $fl; $i++) {\r
+               my $field = $fields[$i];\r
+\r
+               $rest =~ /\ $field\ +([^\ ]+)/;\r
+               $l[$i] = $1;\r
+       }\r
+\r
+       return (@l);\r
+}\r
+\r
+# nfsDumpParseLineField -- Just return ONE of the fields,\r
+# without parsing the entire line.\r
+\r
+sub nfsDumpParseLineField {\r
+       my ($line, $field) = @_;\r
+\r
+       # If the line doesn't start with a digit, then\r
+       # it's certainly not properly formed, so bail out\r
+       # immediately.\r
+\r
+       if (! ($line =~ /^[0-9]/)) {\r
+               return undef;\r
+       }\r
+\r
+       my $rest;\r
+       if ($AllowRisky) {\r
+               $rest = $line;\r
+       }\r
+       else {\r
+               my @foo = split (' ', $line, 9);\r
+               $rest = ' ' . $foo[8];\r
+       }\r
+\r
+       $rest =~ /\ $field\ +([^\ ]+)/;\r
+       return $1;\r
+}\r
+\r
+# Returns a new file handle that has all the "useful" information as\r
+# the original, but requires less storage space.  File handles\r
+# typically contain quite a bit of redundancy or unused bytes.\r
+#\r
+# This routine only knows about the advfs and netapp formats.  If\r
+# you're using anything else, just use anything else as the mode, and\r
+# the original file handle will be returned.\r
+#\r
+# If you extend this to handle more file handles, please send the new\r
+# code to me (ellard@eecs.harvard.edu) so I can add it to the\r
+# distribution.\r
+\r
+sub nfsDumpCompressFH {\r
+       my ($mode, $fh) = @_;\r
+\r
+       if ($mode eq 'advfs') {\r
+\r
+               # The fh is a long hex string:\r
+               # 8 chars: file system ID\r
+               # 8 chars: apparently unused.\r
+               # 8 chars: unused.\r
+               # 8 chars: inode\r
+               # 8 chars: generation\r
+               # rest of string: mount point (not interesting).\r
+               # So all we do is pluck out the fsid, inode,\r
+               # and generation number, and throw the rest away.\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$1-$4-$5");\r
+       }\r
+       elsif ($mode eq 'netapp') {\r
+\r
+               # Here's the netapp format (from Shane Owara):\r
+               #\r
+               # 4 bytes     mount point file inode number\r
+               # 4 bytes     mount point file generation number\r
+               # \r
+               # 2 bytes     flags\r
+               # 1 byte      snapshot id\r
+               # 1 byte      unused\r
+               #\r
+               # 4 bytes     file inode number\r
+               # 4 bytes     file generation number\r
+               # 4 bytes     volume identifier\r
+               #\r
+               # 4 bytes     export point fileid\r
+               # 1 byte      export point snapshot id\r
+               # 3 bytes     export point snapshot generation number\r
+               #\r
+               # The only parts of this that are interesting are\r
+               # inode, generation, and volume identifier (and probably\r
+               # a lot of the bits of the volume identifier could be\r
+               # tossed, since we don't have many volumes...).\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$4-$5-$6-$1");\r
+       }\r
+       elsif ($mode eq 'RFSNN') {\r
+\r
+               # Here's the netapp format (from Shane Owara):\r
+               #\r
+               # 4 bytes     mount point file inode number\r
+               # 4 bytes     mount point file generation number\r
+               # \r
+               # 2 bytes     flags\r
+               # 1 byte      snapshot id\r
+               # 1 byte      unused\r
+               #\r
+               # 4 bytes     file inode number\r
+               # 4 bytes     file generation number\r
+               # 4 bytes     volume identifier\r
+               #\r
+               # 4 bytes     export point fileid\r
+               # 1 byte      export point snapshot id\r
+               # 3 bytes     export point snapshot generation number\r
+               #\r
+               # The only parts of this that are interesting are\r
+               # inode, generation, and volume identifier (and probably\r
+               # a lot of the bits of the volume identifier could be\r
+               # tossed, since we don't have many volumes...).\r
+               \r
+               # 61890100575701002000000  0009ac710e9ea381  0d24400006189010057570100\r
+               # 61890100575701002000000  0009ac70ed2ea381  0d24400006189010057570100\r
+               # 61890100575701002000000  000479a1e008d782  0d24400006189010057570100\r
+               # Ningning need only 24-39 (or 12-19 bytes)\r
+\r
+               $fh =~ /^(........)(........)(........)(........)(........)(........)/;\r
+\r
+               return ("$4$5");\r
+       }else {\r
+\r
+               return ($fh);\r
+       }\r
+}\r
+\r
+sub testMain {\r
+       $lineNum = 0;\r
+\r
+       while (<STDIN>) {\r
+               $line = $_;\r
+               $lineNum++;\r
+\r
+               &nfsDumpParseLine ($line);\r
+       }\r
+}\r
+\r
+1;\r
+\r
+# end of nfsdump.pl\r