和满哥抓包学NFSv3 (RFC1813)

Network File System(NFS)协议是SUN公司设计的,NFS就是网络上的文件系统。NFS自1984年面世以来,已经流行30年。理论上它适用于任何操作系统,不过因为种种原因,一般只在 Linux/UNIX 环境中存在。

无论SUN的命运如何多舛,NFS始终处乱不惊,这么多年来只出过3个版本,即1984年的NFSv2、1995年的NFSv3和2000年的NFSv4。目前,大多数NFS环境都还是NFSv3,本文介绍的也是这个版本。NFSv2还在极少数环境中运行(只在日本见到过),可以想象这些环境有多老了。而NFSv4因为深受CIFS影响,实施过程相对复杂,所以普及速度较慢。

如何深入学习NFS协议呢?其实所有权威资料都可以在RFC 1813中找到,不过这些文档读起来就像面对一张冷冰冰的面孔,令人望而却步。《鸟哥的Linux私房菜》中对NFS的介绍虽称得上友好,但美中不足的是不够深入,出了问题也不知道如何排查。

ps:不是所有问题都要抓包,如何定位问题的方法很多,本文仅介绍抓包方式。

抓包实践

NFS客户端和文件服务器的IP分别是10.32.106.159和10.32.106.62。在运行挂载命令(mount)时抓了包,然后用“portmap||mount||nfs”进行过滤。

# mount 10.32.106.62:/code /tmp/code

从上图中的Info一栏可以看到,Wireshark已经提供了详细的解析。

包号112和113:

客户端:“我想连接你的NFS进程,应该用哪个端口呀?”

服务器:“我的NFS端口是2049。”

包号123和124:

客户端:“那我试一下NFS进程能否连上。”

服务器:“收到了,能连上。”

包号128和129:

客户端:“我想连接你的mount服务,应该用哪个端口呀?”

服务器:“我的mount的端口号是1234。”

包号132和133:

客户端:“那我试一下mount进程能否连上。”

服务器:“收到了,能连上。”

包号134和135:

客户端:“我要挂载/code共享目录。”

服务器:“你的请求被批准了。以后请用file handle 0x2cc9be18 来访问本目录。”

包号140和141:

客户端:“我试一下NFS进程能否连上。”

服务器:“收到了,能连上。”

包号143和144:

客户端:“我想看看这个文件系统的属性。”

服务器:“给,都在这里。”

包号145和146:

客户端:“我想看看这个文件系统的属性。”

服务器:“给,都在这里。”

以上便是NFS挂载的全过程。细节之处很多,所以在没有Wireshark的情况下很难排错,经常不得不盲目地检查每一个环节,比如先用rpcinfo命令获得服务器上的端口列表,再用 Telnet命令逐个试探。即使这样也只能检查几个关键进程能否连上,排查范围非常有限。

看到portmap请求没有得到回复,可以考虑防火墙对111端口的拦截;如果发现mount请求被服务器拒绝了,就应该检查该共享目录的访问控制。

既然说到访问控制,我们就来看看NFS在安全方面的机制,包括对客户端的访问控制和对用户的权限控制。NFS对客户端的访问控制是通过IP地址实现的。创建共享目录时可以指定哪些IP允许读写,哪些IP只允许读,还有哪些IP连挂载都不允许。

问题1:客户端A上的用户admin在/code目录里新建一个文件,该文件的owner正常显示为admin。但是在客户端B上查看该文件时,owner却变成nasadmin。

上图的Credentials信息可知,用户在创建文件时并没有使用admin这个用户名,而是用了admin的UID501来代表自己的身份(用户名与UID的对应关系是由客户端的 /etc/passwd决定的)。也就是说NFS协议是只认UID不认用户名的。当admin通过客户端A创建了一个文件,其UID 501就会被写到文件里,成为owner信息。

而当客户端B上的用户查看该文件属性时,看到的其实也是“UID:501”。但是因为客户端B上的/etc/passwd文件和客户端A上的不一样,其UID501对应的用户名叫nasadmin,所以文件的owner就显示为nasadmin了。

为了防止这类问题,建议用户名和UID的关系在每台客户端上都保持一致。

问题2: NFS 是如何读写文件的?不同mount参数有什么作用?如何针对性地进行性能调优?

以读取文件abc.txt的过程为例

# cat /tmp/code/abc.txt

包号2和3:

客户端:“我可以进入0x2cc9be18(也就是/code的file handle)吗?”

服务器:“你的请求被接受了,进来吧。”

包号5和6:

客户端:“我想看看这个目录里的文件及其file handle。”

服务器:“文件名及file handle的信息在这里。其中abc.txt的file handle是0x531352e1。”

包号8和9:

客户端:“0x531352e1(也就是abc.txt)的文件属性是什么?“

服务器:“权限、uid、gid, 文件大小等信息都给你。”

包号11和12:

客户端:“我可以打开0x531352e1(也就是abc.txt)吗?”

服务器:“你的请求被允许了。你有读、写、执行等权限。”

包号13、14、152、292:

客户端:“从0x531352e1的偏移量为0处(即从abc.txt的开头位置)读131072字节。”

客户端:“从0x531352e1的偏移量为131072处(即接着上一个请求读完的位置)再读131072字节。”

服务器:“给你131072字节。”

服务器:“再给你131072字节。”(继续读,直到读完整个文件。)

NFS完成了文件的读取过程。从最后几个包可见,Linux客户端读NFS共享文件时是多个 READ Call 连续发出去的(本例中是连续两个)。这个方式跟Windows XP读CIFS共享文件有所不同。Windows XP不会连续发READ Call,而是先发一个Call,等收到Reply后再发下一个。

除了读文件的方式,每个READ Call请求多少数据也会影响性能。这台Linux默认每次读131072字节,实验室里还有默认每次读32768字节的客户端。在高性能环境中,要手动指定一个比较大的值。我的Isilon实验室中,常常要调到512KB。这个值可以在mount时通过rsize参数来定义,比如 “mount -o  rsize=524288 10.32.106.62:/code/tmp/code”。

问题3:NFS 是如何写写文件的?不同mount参数有什么作用?如何针对性地进行性能调优?

# cp abc.txt code/abc.txt

包号1和2:

客户端:“我可以进入0x2cc9be18(即/code目录)吗?”

服务器:“你的请求被接受了,进来吧。”

包号4和5

客户端:“请问这里有叫abc.txt的文件么?”

服务器:“没有。”

包号6和7

客户端:“那我想创建一个叫abc.txt的文件。”

服务器:“没问题,这个文件的file handle是0x531352e1。”

包号69、104、130、190

客户端:“从0x531352e1的偏移量为0处(即 abc.txt的文件开头)写131072字节。”

服务器:“第/个131072字节写好了。”

客户端:“从0x531352e1的偏移量为131072处(即接着上一个写完的位置)再写131072字节。”

客户端:“从0x531352e1的偏移量为262144处(即接着上一个写完的位置)再写131072字节。”

(继续写,直到写完整个文件。)

包号306和307

客户端:“我刚才往0x531352e1(也就是abc.txt)写的数据都存盘了吗?”

服务器:“都存好了。”

包号308和309:

客户端:“那我看看0x531352e1(也就是abc.txt)的文件属性。”

服务器:“文件的权限、uid、gid、文件大小等信息都给你。”

这个例子的写操作也是多个WRITE Call连续发出去的,这是因为我们在挂载时没有指定任何参数,所以使用了默认的async写方式。和async相对应的是sync方式。假如mount时使用了sync参数(见图29),客户端会先发送一个WRITE Call,等收到Reply后再发下一个Call,也就是说WRITE Call和WRITE Reply是交替出现的。除此之外,还有什么办法在包里看出一个写操作是async还是sync呢?答案就是每个WRITE Call上的“UNSTABLE”和“FILE_SYNC”标志,前者表示async,后者表示sync。下图显示了用sync参数后的网络包。

从上图中不仅可以看到FILE_SYNC标志,还可以看到WRITE Call和WRITE Reply 是交替出现的(也就是说没有连续的 Call)。不难想象,每个 WRITE Call写多少数据也是影响写性能的重要因素,我们可以在mount时用wsize参数来指定每次应该写多少。不过在有些客户端上启用sync参数之后,无论wsize定义成多少都会被强制为 4KB,从而导致写性能非常差。那为什么还有人用 sync 方式呢?答案是有些特殊的应用要求服务器收到sync的写请求之后,一定要等到存盘才能回复 WRITE Reply,sync 操作正符合了这个需求。由此我们也可以推出COMMIT对于sync写操作是没有必要的。

非常值得一提的是,经常有人在mount时使用noac参数,然后发现读写性能都有问题。而根据RFC的说明,noac只是让客户端不缓存文件属性而已,为什么会影响性能呢?光看文档也许永远发现不了原因。抓个包吧,Wireshark会告诉我们答案。


本章读书笔记来自林沛满的《Wireshark网络分析就这么简单》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容