在H.323和SIP系统中如何实现RSVP协议
卢政 2003/08/19
摘要:
本文主要介绍了RSVP协议在IP网络通讯协议H.323和SIP中的运用,以及在语音/视频通讯数据的特殊性,然后详细叙述了Vocal系统中如何使用RAPI来实现RSVP的QoS管理,以及如何改善Vocal中RSVP的性能,并且论述了在主干网络使用DiffServ的时候如何修改RAPI中的数据结构,从而实现RSVP到DiffServ的映射。
前言:
RSVP(资源预留协议)是一种服务质量协议,也是一种商业的开放协议,当然它也是一种Internet上的大型协议,如果说它是网络上流动的一种钞票,这样的形容可以说是再合适不过了,利用RSVP消息,端点应用程序可以根据需求提出数据传送全程所必须网络带宽和缓冲大小以及延迟等等,同时也确定了沿途的路由器传输调度的策略,从而达到对每个数据流的QoS进行控制。
RSVP支持两种服务类型:受控载荷服务和保证服务,前者是在设定网络的载荷非常轻的情况下,所有的数据流都按照尽力的方式来处理且网络缓冲区为空,对于音频信号而言这种方法是正好合适的,而后者不是这样,不仅请求带宽,而且也要求最大传输延迟,那么所得到的结果就是在网络的负荷增加的时候不会让QoS有非常明显的减低。
如果从RSVP所支持的传输类型来区分QoS的服务,可以分成三种传输类型:最好性能(best-effort),速率敏感(rate-sensitive)与延迟敏感(delay-sensitive)。用来支持这些传输类型的数据流服务依赖保证QoS的协议实施。比如各种TCP/IP协议就是遵循最好性能传输的传输服务协议:TFTP,HTTP,SMTP,POP3等等;速率敏感传输放弃及时性,而确保传输速率。例如:速率敏感传输请求128 kbps带宽,如在扩展期实际发送256 kbps,路由器可能进行数据的队列缓冲,并且延迟传输;这类传输与采用电交换网络有关系,当然在internet主干网络和边沿网络也有这样的情况出现,RSVP服务支持速率敏感传输,称为位速率保证服务。延迟敏感传输要求传输及时,并因而改变其速率。例如:SIP或者H.323协议传输采用H.261协议压缩图象并且传输的时候流量可能达到384-768kbps,384Kbps可能对应一个静态的背景,而768kbps 可能是一个动态的图象。熟悉H.261协议的人都知道在H.261中存在I-frame和P-frame的两种压缩方式,前者是本地压缩,那么必然产生一个淬发的数据尖峰,而后者和平均带宽的要求和接近,以Microsoft NetMeeting 为例子每15个P-frame产生一个I-frame,由于单个帧要求在一帧时间内发送出去,或解码器速度跟不上,必须对I-frame的传输进行特定优先级别协调,RSVP服务支持延迟敏感传输,可以被看作控制延迟服务(非实时服务)与预报服务(实时服务)的混合。
上面详细的阐述了RSVP的服务类型和传输类型,这样我们可以看出在以H.323或者是SIP为基础的视频通讯系统中,QoS的保证是比较复杂的,即有延迟敏感传输的服务也有速率敏感传输的服务,RSVP目前对这两种服务都可以做到很好的支持,我在下面的文章中会阐述一下如何在H.323和SIP的协议栈中实现RSVP,重点介绍Vovida中Vocal的SIP的实现方式,但是这里之介绍点对点的情况,而不介绍多点互联和广播的情况。
RSVP资源预留协议的具体内容可以参看RFC 1633中对RSVP的具体定义,另外在draft-ietf-rsvp-rapi-01.txt中定义关于RSVP相关的基本API函数调用。
RSVP工作顺序描述如下图所示:
发送方发送PATH消息,消息中包含有数据业务特征,该消息沿所选的路径传送,沿途的路由器按照PATH准备路由资源,接收方接收到PATH消息以后,根据业务特征和所需要的QOS计算出所需要的资源,回送RESV消息,消息中包含的参数就包括请求预留的带宽,延PATH的原路途返回,沿途的路由器接收到RESV操作后才执行资源预留操作。发送方接收到RESV消息以后才发送用户数据。
简述在H.323协议中如何实现RSVP功能:
对于一个H.323或者是SIP的多媒体通讯系统而言,为了保证实时通讯的质量,一般来说采用了很多方面来保证QoS,对于H.323来说方式没有SIP那样灵活,在H.323v3版本采用了一些几种方式来增强QOS保证,另外这里暂时不对多播的情况考虑。
a. 增强的RAS过程,在ARQ中指明了是否具备资源预留能力;
b. 增强的能力交换过程,收发端点都具备RSVP功能,通过能力交换过程可以双方具备RSVP能力(RSVP属于能力集合的一个部分),在OpenLogicalChannel原语中定义了一个参数qOSCapability来表示;
c. 增强的逻辑信道能力在逻辑信道打开过程中包含Path和Resv两个过程。
下面我们用图来表示逻辑信道的打开过程和资源预留过程:
1. 发送端点向接受端点发送OpenLogicalChannel消息在qOSCapability中标明该信道的RSVP参数和综合业务类别。
2. 接收端点创建RSVP会话(调用Rapi_session API)向发送端点发送OpenLogicalChannel Ack。
3. 在OpenLogical Ack中包含FlowControl=0,抑制当前的媒体数据流。
4. 4和5表示发送端点和接收端点执行RSVP过程。
5. 接收端点接收到ResvConfirm以后知道预留成功。
6. FlowControl为最大的比特率,当前的媒体数据流为最大。
要注意的一点是由于通讯是双向的实际上述的过程发送和接收方需要对掉,特别在双方的能力集不相同的情况之下需要变换主叫和被叫的身份执行上述过程。
在SIP中实现RSVP功能:
以Vovida的Vocal为例子,在Vocal的SIP协议栈软件中提供了一个非常简便的实现RSVP的方式,当然按照这个方式实现RSVP是相当的不成熟的,很多参量在应用程序都没有反馈并且处理,仅仅是在路由器之间相互的汇报,不过这个简单的方式实现RSVP的构架,所以仍然有一定的使用价值。
在Vovida的SIP中实现RSVP的步骤如下:
在上图中实线的部分是SIP命令,虚线部分是RSVP消息
Vocal中的RSVP实现过程:
我们先看一下RSVP API中定义的流程:
我们先来看一下RSVP的API调用过程:
(点击放大)
首先通过rapi_session()打开一个Unix域的RAPI Socket,并创建一个RSVP的会话实例,如果成功则返回一个非零的数值用于表示建立的会话ID号。
例如在Vocal的SIP Stack中这样创建:
session_id = rapi_session(&(dest_addr),//会话对端的目的地址;
proto_id, //协议号 udp 17;
RAPI_USE_INTSERV,//这里表示采用IntServ定义(和Diffserv相对应)
(rapi_event_rtn_t)upcallHandler,//在RSVP错误发生时候的回调函数
0,//RSVP事件的过滤器
&rtn_code);//建立会话的错误返回值。
使用rapi_session创建会话是发送RSVP PATH或者是发送RSVP RESV都需要在调用相应的函数之前调用它,现在我们看下面具体的程序部分的调用过程:
1.首先是主叫部分发送INVITE命令,我们知道命令中包含有主叫的会话描述(这里我们称为Remote SDP);
2.被叫部分此时处于OpRing的状态中接收到主叫的INVITE消息以后,根据主叫的INVITE消息和主叫的SDP,得到主叫的地址和主叫的RSVP端口(主叫的RTP端口);被叫调用setupRsvp子程序发送包含有数据流标识和数据业务流特征的PATH消息到主叫,具体发送的业务流Tspec特征如下:
//Sender Tspec(数据流的话务描述特征)的定义:
rapi_tspec_t *tspec_ptr = &(snd_tspec);
qos_tspecx_t *qos_tspec = &(tspec_ptr->tspecbody_qosx);
qos_tspec->spec_type = QOS_TSPEC;//发送方业务流特征标示
qos_tspec->xtspec_r = 10000;//业务流量
qos_tspec->xtspec_b = 200;//标记存储桶宽度
qos_tspec->xtspec_p = 10000;//突发流量
qos_tspec->xtspec_m = 200;//本地缓冲最大保留量(漏桶参数)
qos_tspec->xtspec_M = 200;//SDU的最大值
tspec_ptr->len = sizeof(rapi_hdr_t) + sizeof(qos_tspecx_t);
// RAPI Sender
tspec_ptr->form = RAPI_TSPECTYPE_Simplified;
… …
我们先来看一下在RSVP API中定义的发送一个PATH消息的函数:
rtn_code = rapi_sender(session_id,//在rapi_session中创建的会话ID号。
0, //该标志暂时未被使用
&(src_addr), //源地址和源端口
NULL, //发送方的端口号和源地址,可以为空
&(snd_tspec), //发送方的数据流的话务描述特征
NULL, /* sender adsepc */ //Apspec的内容,可以为空
NULL, /* Policy */ //发送方策略值,一般为空
ttl); //消息的生存周期`````
这里似乎和RSVP的——呼叫方发送PATH消息的精神有一些违背,是被叫方发送PATH消息,其实二者没有什么不同,首先主叫方,没有收到被叫方的SDP所以不能确定被叫方接收RSVP消息的端口和IP地址,其次,媒体流是双向的,双方都必须在网路上通过PATH——Reserve的方式预流资源。
3.在完成了一系列SIP命令和状态的交换(RING,OK过程)以后,主叫方开始准备发送ACK消息了,也就是处于操作OpFarEndAnswered()的时候,调用rsvpFarEndAnswered发送Reserve消息,为什么要在这个时候发送Reserve消息呢?因为主叫在下一个过程(收到ACK消息后,打开RTP通道之前)的时候,已经保证了所有的主叫到被叫之间的路由器都已经收到了PATH预留消息,
4.第5,6两个消息是主叫端点向被叫端点之间的路由器发送PATH消息,并且接收对端的RESV消息的过程。和1,2,3的过程基本上一样,最后在双方的RTP通道打开之前,主叫/被叫之间的路由器实现稳定状态,也就是都收到主叫和被叫的资源预留的信息。
我们来看一下在主叫是如何定义RESV消息的:
//预留方式的选择:
//RAPI_RSTYLE_WILDCARD的方式适合于声音媒体传输,在多个请求的时候按最大的要求满足//Flowspec需要为空;
// RAPI_RSTYLE_FIXED的方式适合于声音媒体传输,对每个发送源进行单独的预留;
// RAPI_RSTYLE_SE表示预留数量应该为自该接口收到的所有预留请求的最大数值,这个方//式主要适合于视频媒体
style = RAPI_RSTYLE_FIXED; /* RAPI_RSTYLE_WILDCARD = 1
RAPI_RSTYLE_FIXED = 2
RAPI_RSTYLE_SE = 3 */
resv_flag = 0; /* RAPI_REQ_CONFIRM */
rapi_flowspec_t *flowspec_cl_ptr = &(flowspec_cl);
qos_flowspecx_t *qos_flowspec_cl = &flowspec_cl_ptr->specbody_qosx;
//数据流说明(Flowspec)中的Tspec项目,要和PATH中的业务特征相同
qos_flowspec_cl->spec_type = QOS_CNTR_LOAD;
qos_flowspec_cl->xspec_r = 10000;
qos_flowspec_cl->xspec_b = 200;
qos_flowspec_cl->xspec_p = 10000;
qos_flowspec_cl->xspec_m = 200;
qos_flowspec_cl->xspec_M = 200; /* 65535 */
flowspec_cl_ptr->form = RAPI_FLOWSTYPE_Simplified;
flowspec_cl_ptr->len = sizeof(rapi_flowspec_t);
//数据流说明中的Rspec项目,根据PATH的端到端延迟和指标和Adspec的参数计算出的,//在Vocal中直接采用估算的方法得出,Rspec是预留说明。
rapi_flowspec_t *flowspec_g_ptr = &(flowspec_g);
qos_flowspecx_t *qos_flowspec_g = &flowspec_g_ptr->specbody_qosx;
qos_flowspec_g->spec_type = QOS_GUARANTEEDX//类型为QoS保证,最为常用的设定;
qos_flowspec_g->xspec_R = 10000;//预流带宽
qos_flowspec_g->xspec_S = 0;//松弛项(relaxation),用于指示Qos富裕量
qos_flowspec_g->xspec_r = 10000;// 业务流量
qos_flowspec_g->xspec_b = 200;// 标记存储桶宽度
qos_flowspec_g->xspec_p = 10000; //突发流量
qos_flowspec_g->xspec_m = 200; //本地缓冲最大保留量(漏桶参数)
qos_flowspec_g->xspec_M = 200; //SDU的最大值
flowspec_g_ptr->form = RAPI_FLOWSTYPE_Simplified;
flowspec_g_ptr->len = sizeof(rapi_flowspec_t);
//筛选说明,用于表示对哪个或者那些发送方进行资源预留
filter_spec.form = RAPI_FILTERFORM_BASE;//表示包含发送方的套接字地址
//发送方的套接字地址
filter_spec.len = sizeof(rapi_hdr_t) + sizeof(rapi_filter_base_t);
filter_spec.rapi_filt4 = *(struct sockaddr_in *) & src_addr;
rtn_code = rapi_reserve(session_id,// 在rapi_session中创建的会话ID号。
resv_flag,//指示是否使用回吊函数(可以设置成0)
(struct sockaddr *) & rcv_sockaddr,//接收地址和端口
style,//预留方式(WF,FF,SF)
NULL,//扩展的预留类型列表,可以为空
NULL,//接收策略
1,// FilterNo值,为1表示不能忽略Filterspec_list
&(filter_spec), //筛选说明
1,//FlowspecNo值,为1表示不能忽略Flowspec_list
&(flowspec_cl)); //FlowSpec数据流说明结构。
5.在被叫端主要调用的函数:
a. void setupRsvp(SipSdp& localSdp, SipSdp& remoteSdp)
主要由被叫端调用,用于在收到主叫发送过来的INVITE消息以后根据主叫的SDP回送被叫资源预留PATH消息。
b. void rsvpFarEndAnswered(Sptr localSdp, Sptr remoteSdp)
主要由主叫端调用,用于在向被叫端发送ACK消息前向被叫发送RESV消息和开始主叫资源预留PATH消息。
c. void rsvpAckHandler(Sptr localSdp, Sptr remoteSdp)
主要由被叫端调用,用于在收到主叫发送过来的ACK消息以后根据主叫的SDP回送主叫资源预留RESV消息。
6. 如何实现的RSVP机制到Diffserv的映射:
对于目前在Vocal中对于RSVP的处理过程是非常简单的,在用户端都没有对AdSpec和Tspec做任何具体的运算,得出端到端的延迟指标,以及预留带宽,仅仅是通告路径上的路由器去预留资源,这样做如果是一个简单的没有太复杂的网络状态的区域网内部,采用这种方法当然是无可厚非的,不过如果是在有复杂网络状态的广域网上这样就可以说是不是很行得通了,一般来说在主干网络上会运行DiffServ(分类服务)的机制(所有的流都分组为多个服务类别的方式),这样在骨干网上的RSVP消息当然就会被忽略,所以我们的PATH和SESV消息都要实现对Diffserv的映射,换一句话来说,就地让骨干网看起来象RSVP的一个节点,一般来说我们把AdSpec中的DTOT最小路径延迟(或者说是子网络到主干网络的传播延迟 在RFC2205中有定义)改变成透过骨干网的传播延迟和平均排队延迟的值(这个是由主干网罗入口/出口路由器做的工作)这个近似的方式一般来说是有效的,因为骨干网络失效的机会毕竟比较小,如果主干网络是千兆路由器,那么每条PATH消息是可以在中继段上更新的。
返回RESV消息的时候,对于分类服务而言,并不是将每个相对应的RSVP操作定义一个单独的队列,对于骨干网络路由器是不现实的,只能相对服务等级接近的安排在最相近的队列中。
另外有几个情况是在如果主干网络使用DiffSev需要注意的:
a. 如果有一个流不符合Tspec时——而这个时候路由器已经为所有的入口和出口规划了每一条虚链路的时候,一个不符合Tspec的流就足以毁坏同一类别所有其他留所争取的服务质量,例如入口处归纳低质量的视频/音频流时候,出现了高质量的视频流。
b. 分散的/突发的流合并到平缓的流中时候。
不过一般来说每个路由器都具备检查流的Tspec的能力,特别是作为主干网络入口的路由器(例如一些大的网络(BGP/EBGP)的入/出口地方)。在运行视频会议或者是其他突发流很多的恶劣工作状况的时候。
7. 修改Vocal的SIP协议栈来更好的实现RSVP:
我们前面已经反复地阐述:在Vocal中只不过是实现了一个简单RSVP构架,最重要的一点就是它不能够实现软状态,也就是定期刷新消息的Tspec和Rspec,如果在传输视频信号的时候这样的情况出现得特别频繁,由于视频信号并不总是处于一种稳定的平缓的状态传输,另外当路由改变的时刻,RSVP消息需要能准确的沿着新的路由往复(这种情况是可能出现的,特别在大型网络中)。
解决上述问题的途径首先就是要在RSVP建立保证服务预定,也就是要根据接收端根据发送端的AdSpec消息计算预留的带宽(而在Vocal中基本上没有处理AdSpec),AdSpec中参加带宽运算的主要是两个参数:Dtot和Ctot,第一个参数是最小路径延迟,第二个是路径带宽,通过这两个参数根据公式D=(b(存储桶深度)+Ctot)/p + Dtot计算出端到端之间的延迟:
例如:
PATH流的初始特征:
Tspec(p=10mbps,L=2kbps,r=1mbps,b=32kbps) AdSpec(Ctot=0,Dtot=0)
经过第一个路由器:
Tspec(p=10mbps,L=2kbps,r=1mbps,b=32kbps) AdSpec(Ctot=11,Dtot=0.05s)
经过第二个路由器:
Tspec(p=10mbps,L=2kbps,r=1mbps,b=32kbps) AdSpec(Ctot=55,Dtot=0.1s)
现在我们来计算Resv中Rspec项目:
最长的延迟为0.1s的延迟,我们在Rspec中所计算的预留带宽必须符合这个要求,那么根据公式:
D=(b+Ctot)/p + Dtot
b:存储桶深度
计算出的D为0.185S我们在根据这个公式来计算预留带宽
R=((p-r)(L+Ctot)+(b-L)p)/((t-Dtot)(p-r)+b-L)
r:业务流量
t:所需要的延迟
注意:所需要的延迟在0.1-0.185之间变化,这样我们通过上述公式得出一个比较确切的R值R=1.66Mbps。所以Rspec为:R=1.66Mbps;松弛项(S):用于指示Qos的富裕量,如果所有的路由器按照R预留,那么整个路径上的端到端的延迟会比要求的时延要少5毫秒:这里可以选择0.05S,也就是说有一个比较宽余的带宽,可以实现其他的数据传输,或者是让当前的媒体数据实现尽力传输,具体的松弛项计算可以参看RFC2205定义。
上面我们解决了服务预定的问题,但是它只不过让我们的终端程序运行进一步合理化,可以正确的规划需要预留的带宽,但是中间还是有关键问题没有解决,也就是我们上面说的软状态——定期刷新Tspec和Rspec,以及探测/感知主干路由的变化
从程序上实现这些事实上并不困难,我们在打开媒体通讯的RTP信道以后,可以用一个进程定期的发送PATH和RESV消息,让流的接收者进行定期刷新,特别是在视频通讯阶段(采用H.263算法)出现帧间帧的时候,数据的流量必然会大大增加,这个时候,如果提前刷新预留的状态,那么我们可以在初期就避免网络出现阻塞的问题,当然,如果流量超过了路径所承受的标准,那么必然会依靠侵占S(松弛度)来发送数据包,如果超过了带宽许可,这个时候,必然通讯会出现一个比较明显的延迟,不过根据实验结果表明,这些还是可以接受的。
如果IP路由发生了变化,那么上述的解决办法同样的适用,定期传送RSVP的消息可以重新根据流的路径进行新的定义,所以他们也会沿着新的路径进行传输,所以沿着相反路径的RESV消息将试图沿着新的路由进行预定,旧的预定就会超时然后取消。
但是我们如果考虑到主干网络使用DiffServ就不会那么乐观了(当然主干网络的路由变化不会那么剧烈),主干网络上PATH项目中变化的部分就是AdSpec中的Dtot/Ctot,我们在上面已经说了如何定义Dtot的内容(子网络到主干网络的传播延迟的计算 在RFC2205中有定义)改变成透过骨干网的传播延迟和平均排队延迟的值,正如上面所说的,如果主干网络是功能强大的千兆路由器组成,那么PATH中的Dtot和Ctot可以在中继的时候得到更新,如果是ATM或者是MPLS网络的话,出入口也可以得到更新,这样的话你事实上完全不必操心。
8.一些其他的设想:
不过不管怎么说上述的数值如果是周期性计算并在RESV消息中更新的话,必然大大的加大路由器的运算开销,特别在跨洋多点视频会议的时候,这样用户接入服务供应商区域网入口路由器可能会发生“饿死”的情况(没有用户媒体数据时候反而被大量无用的RSVP消息所淹没),所以在使用主干网络的时候,我们考虑必须有一个机制探测主干网络的传播延迟并且通报给服务供应商区域网入口路由器,这个对于入口路由器并不使什么难事,最好是主干入口路由器本身就具备这样的功能,进一步简化主干网络为一个简单的RSVP节点,变成由主干网络的接入路由器通告服务供应商的路由器端对端的延迟 ,这样把计算的过程交给主干路由器,而服务供应商区域网入口路由器只负责更新AdSpec,对于用户来说,并不需要设定AdSpec,也就是可以让AdSpec为空,这样效率就可以得到大大的提高,代价就是增加了协议复杂性。
9.Vocal中采用策略服务器来管理QoS:
在H.323和SIP等大型的通讯协议中实现QoS的保证的确不是一个小的问题,和普通的传输服务协议所不同,H.323和SIP的传递数据都有着非常明显的延迟和速率敏感特性,在建立一个大型的视频会议/IP网络电话系统的时候需要有专门的设备来管理和保证QoS,在Vocal系统中实现这个的设备是PoS Server(Policy Server),它使用了OSP和COPS(Common Open Policy Service)协议。可以和路由器之间传递消息,PoS的工作流程非常简单,当代理服务器转递180 /183的振铃消息时(也就是被叫发送PATH消息前),发送一个COPS消息给PoS,同时被叫发送PATH消息到路由器上,路由器产生一个COPS-Request消息给PoS,以便确定用户的带宽申请授权,如果授权合法校验通过的话,PoS回送一个COPS-Decision到被叫端的路由器上,同样在主叫端的路由器回送RESV消息的时候也会向PoS进行同样操作。
本文地址:http://com.8s8s.com/it/it34545.htm