1、近几天处理一个与协议栈相关的bug,首先对问题进行描述:两台支持LDP协议功能的路由设备之间建立LDP会话,路由协议采用OSPF,当采用脚本同时删除两端配置时,其中一台cpu处理能力弱的设备出现CPU利用率达到100%,造成设备最后卡死。基于VXworks系统的嵌入式设备,通过tt任务得到任务调用栈,可以看到LDP任务一直在执行SocketRead,说明接收到协议栈通知,有数据包可读。但其实此时设备已经不发送数据包。LDP协议依赖于两个传输层协议,UDP和TCP协议。
tt rcldp
0x00281950 vxTaskEntry +0x48 : 0x0194fc70 ()
0x0194fcfc ROS_TaskDelete+0x370:RcLdpMain ()
0x01547f8c RcLdpMain +0x3c : thread_call (0x8862b08)
0x01f96e84 thread_call +0x94 : ldpSocketRead()
0x01547090 ldpSocketRead+0x148: funcname_thread_add_read (0x884251c,&ldpSocketRead, 0x9216c84, 0x52, 0x29ea4ac, 0x29e9664, 0xba8)
0x01f951d4 funcname_thread_add_read+0xd8: ROS_SemP_ ()
value = 0 = 0x0
-> tt rcldp
0x00281950 vxTaskEntry +0x48 : 0x0194fc70 ()
0x0194fcfc ROS_TaskDelete+0x370:RcLdpMain ()
0x01547f8c RcLdpMain +0x3c : thread_call (0x8862b08)
0x01f96e84 thread_call +0x94 : ldpSocketRead()
0x015471b4 ldpSocketRead+0x26c: 0x01547bd0 (0x8862a04)
0x01547f38 ldpTimerEventProcess+0x590:ldp_event ()
0x015a1944 ldp_event +0x3b8: ldp_buf_process ()
0x015a22f0 ldp_buf_process+0x2b0:mpls_socket_udp_recvfrom ()
0x0167dab0mpls_socket_udp_recvfrom+0x144: recvmsg (0x52, 0x885d550, 0x80)
0x002686d4 recvmsg +0x118: 0x02136f74 (0x92a61d0, 0x885d550,0x80)
0x02136fe4 ipcom_spinlock_delete+0x1138:ipcom_recvmsg (0x11f, 0x885d550, 0x80)
0x001c04a4 ipcom_recvmsg+0x58 :ipcom_wv_event_2 ()
value = 0 = 0x0
-> tt rcldp
0x00281950 vxTaskEntry +0x48 : 0x0194fc70 ()
0x0194fcfc ROS_TaskDelete+0x370:RcLdpMain ()
0x01547f8c RcLdpMain +0x3c : thread_call (0x8862b08)
0x01f96e84 thread_call +0x94 : ldpSocketRead ()
0x015471b4 ldpSocketRead+0x26c:0x01547bd0 (0x8862a04)
0x01547f38 ldpTimerEventProcess+0x590:ldp_event ()
0x015a1684 ldp_event +0xf8 : memset ()
0x002994c4 memset +0x30 : gtfErrorLog (0x29f7970, 0,0x885ffd0, 0)
2、所以此时的疑问在于,为什么任务在一直循环读取Socket中报文?这里有个前提是,此路由设备当开启全局的LDP开关后,就会创建一个UDP Socket。
通过之前的show 命令信息得出,这个未被关闭的SOCKET一直在读包。
Socket control block info.
--------------------------------------------------------------------------------------------------------------.
SN SocketId SocketType TcpType State EntityInfo Local->Remote Thread.
--------------------------------------------------------------------------------------------------------------.
1 82 Udp -- Up -- 0.0.0.0-> -- 936424C
CreateTime:2018-1-18 14:37:23UpdateTimer:2018-1-18 14:46:53 ReadCount:269343
2 83 Tcp Listen Up -- 0.0.0.0-> -- 8866C9C
CreateTime:2018-1-18 14:37:23UpdateTimer:2018-1-18 14:37:44 ReadCount:2
node2(debug)#show mpls ldp socket
Socket control block info.
--------------------------------------------------------------------------------------------------------------.
SN SocketId SocketType TcpType State EntityInfo Local->Remote Thread.
--------------------------------------------------------------------------------------------------------------.
1 82 Udp -- Up -- 0.0.0.0-> -- 944483C
CreateTime:2018-1-18 14:37:23UpdateTimer:2018-1-18 14:46:55 ReadCount:272642
2 83 Tcp Listen Up -- 0.0.0.0-> -- 8866C9C
CreateTime:2018-1-18 14:37:23UpdateTimer:2018-1-18 14:37:44 ReadCount:2
node2(debug)#show mpls ldp socket
Socket control block info.
--------------------------------------------------------------------------------------------------------------.
SN SocketId SocketType TcpType State EntityInfo Local->Remote Thread.
--------------------------------------------------------------------------------------------------------------.
1 82 Udp -- Up -- 0.0.0.0-> -- 945EA24
CreateTime:2018-1-18 14:37:23UpdateTimer:2018-1-18 14:46:58 ReadCount:277612
2 83 Tcp Listen Up -- 0.0.0.0-> -- 8866C9C
3、协议栈在什么情况下会一直通知socket的使用者一直读取报文呢?当然一种情况下是真的存在数据包,另一种情况就是当socket出现错误,当socket使用者没有读取到这个错误,协议栈就一直给socket通知有数据包可读。对于不同的系统,实现的机制不同,但就目前出现的问题的系统来看。当用户在使用socket之前不检查socket的状态,很容易引起未知的错误。
4、现在来解释为什么会出现socket错误。删除配置过程中,有一条是删除子接口,子接口上配置有IP地址和LDP配置,删除子接口时,LDP模块的任务和协议栈的任务都去响应处理。LDP模块会将对应子接口的IP地址在UDP Socket中解除广播报文的属性,但由于是多进程,协议栈执行较快,此IP地址已经在协议栈任务中删掉,导致LDP执行设置socket选项失败。同时没有读取错误信息,使得LDP一直处在读取UDP Socket循环中。