Open vSwitch源码解析之基于VxLAN实现NSH解析功能

有关SFC的某些基本概率就不在这里做过多阐述,相关内容可以参看其他小伙伴写的文章.SDNLAB技术分享(一):ODL的SFC入门和Demo

本文所有源码不是OVS主线版本,目前OVS主线版本还没有实现NSH解析功能。该版本的OVS为私有版本,github网址见下方:https://github.com/tfherbert/ovs_Pritesh_V8/tree/nsh-v8

1. NSH-SFC概述

当前SFC的实现方案主要分为两种:一种基于NSH(network service header)。数据封装时,在L2或者L3数据后添加NSH头,然后进行L3或L4的封装。转发时,根据nshheader去转发SFC中的数据,整个过程都是依据同一个SPI(service path id)和递减的SI(service index);另一种无NSH头,在转发过程中,SFF需要不停对新来的数据包进行判断,确定是否属于某个SFC。ODL的子项目SFC就是第一种的实现。

1.1 NSH-SFC组件简述

Classifier:分类器,根据controller来的policy来决策是否给数据进行nsh封装,并且把数据发送至相应的sff。
Service Function(SF):网络中的Middleware,常见的有loadbalance,firework,NAT等。值得注意的是,在NSH方案下,如果SF没有NSH解析功能,那么需要在SF和其对应的SFF之间增加一个proxy。该proxy用于解析NSH,并且帮助完成nshheader中SI的自减算法(如果SI不能成功自减,那么SFF会认为这个数据没有被forward到该SF,从而再次forward向该SF,最后的结果就是产生网络风暴)。

Service Function Forwarder(SFF):SFC中的数据中转站,负责数据的转发。当SI=1的时候,SFF负责把nsh头部去掉。

1.2 NSH-SFC(with VxLAN)工作流程

  • 控制层面定义SFC:
  • 用户利用SDN提供的北向应用,创建sfc1,controller会做相应的配置工作,产生对应的数据通道(sfc1本身是一个chain,可以和vxlan的tunnel完美匹配。那么,定义了sfc1,同时可以对应一个vxlan。所以,可以理解为sfc1同时绑定了vxlan和NSH中的path信息)。
  • 数据首先通过classifier,classifier为sfc1的数据打上nsh头信息,然后转交sff1。
  • sff1将数据发送至sf1,sf1将数据处理完后,为nshheader中的si执行自减操作,然后返回到sff1.
  • sff1将数据交到sff2,sff2重复sff的职责...
  • 对于没有nsh解析能力的sf2,proxy会帮其完成nsh相关工作.
  • 在si=0(有文档说si=1)的时候,sff会给数据包去nsh,那么整个sfc1流程就结束

1.3 VxLAN存在的意义

首先,NSH不一定需要依托于VxLAN,GRE + NSH、VXLAN-gpe + NSH、Ethernet + NSH都是可行的方案。其实,NSH只是一个封装技术,起了一个标签的作用,本身并不会影响传输。 在SFC中,很重要的一点是SFF能够尽快、准确地把带NSH头的数据包转发出去。那么,SFF需要做的工作实际根据nshheader去择路,而SFF中的路是controller通过流表已经创建好了的。所以,进一步说,SFF只需要把NSH头和某个流表统一起来即可。

每个openflow流表去匹配的时候,sw_key结构体是匹配的关键,该结构体包含了隧道信息。而nshheader本身的SPI就可以看成一种隧道信息,那么用vxlan便很轻易的统一起来了。

综合起来,VxLAN的tunnel信息和openflow流表就可以统一起来了。

上图其实也是sff去匹配流表的过程。

2. OVS源码解读。

首先是NSH和VxLAN的header结构体。

2.1NSHheader和VxLANheader结构体

NSH

很清楚的表明:包含base和ctx部分,其中base尤为重要,包含了路径信息;ctx用于sf之间传递metadata。

base的结构体

ctx结构体

协议图

VxLANheader

vni是重点

这部分代码说明了数据包封装过后的格式,如下图(请无视gpe)

2.2 VxLAN的创建和数据的监听和处理

首先介绍下linux内核中sock和socket还有skb。

socket和sock的区别和联系:大家都是socket通信中的socket,不过应用的网络层次有区别。socket主要作用于Linux系统中的BSD层(L6层),INET层很少应用, BSD和INET层分别对应ISO中的表示层和会话层,其结构体相对sock而言比较简单;而sock贯穿了硬件层和设备接口层和IP层INET层,贯穿了L2-L5层,而且是各层之间相互联系的重要纽带。

skb:sk_buff 是网络数据报在内核中的表现形式,数据包在内核协议栈中是通过skb的数据结构来实现的。

这部分代码是sk_buffer结构体中的联合体,很明显可以看出来skb贯穿了协议栈的各层。

下面是VxLAN的创建过程:
1、vport.c定义了实现了vport最基本的或者共有的一些功能, 如添加、删除等功能,还有数据的收发功能。

2、vport-XXX.c是vport基于其他的一些个性化实现,如vport-vxlan.c实现了一些vxlan的功能:tunnel的创建、删除等。

2.2.1 OVS相关socket结构体

上面是VxLAN对应的socket,注意其中的struct socket   *sock; 他名字叫做sock,其实是socket结构体的实例。

接着看struct socket   *sock对应的结构体(linux内核中的函数)

注意struct sock *sk;  指向了sock。sock的结构体就不贴了,但是要注意的是sock中也有指向socket的指针,还有指向数据处理函数的指针。

综合起来,VxLAN中的几个socket联系如下:

2.2.2 VxLAN的创建过程,packet和流表的匹配

在用ovs-vsctl工具下命令创建VxLAN的时候,会去调用vport-vxlan.c中的ovs_vxlan_vport_ops.create命令,对应函数如下:

这个函数中比较重要的是vxlan_port = vxlan_vport(vport)和vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, false);

  • vxlan_port = vxlan_vport(vport)为该VxLAN的port申请私有数据区,该数据区可以存放任何数据。这也为逻辑端口vport和物理端口net_device提供绑定的空间。事实上,vport和net-device之间还隔着一个结构体netdev_vport,该数据区就可以用在存放vport对应的netdev_port。
  • vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, false)把vxlan_rcv数据处理函数注册到了vs中。

为了思路的连续性,我们先接着看主线vxlan_sock_add,最后回头再看数据处理部分。

  • vs->rcv = rcv;
  • sk = vs->sock->sk;
  • udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;

主线到这里就算结束了,最后的结果是创建了一个vxlan_sock和一个socket和一个sock,中间的socket只是一个索引,vxlan_sock->socket->sock。其中vxlan_sock和sock注册了各自的数据处理函数。 一个很重要的点是:在linux内核中,无论收发数据,都会被缓存到sock 结构中的缓冲队列中。

整理下主线结构:
创建vxlan的流程
ovs_vport_add->vport_ops_list[i].create->ovs_vxlan_vport_ops.create->
vxlan_tnl_create->vxlan_sock_add->vxlan_socket_create.

上面这个为sock注册过的处理函数,主要工作是一层层的剥开skb的封装(当然,里面会判断是否含有nshheader),提取udp,vxlan 和nshheader的头部信息。

  • sock在之前被强制转换成了udp的socket,该函数由linux内核中net/ipv4/udp.c回调.
  • if (udp->dest == htons(NSH_DST_PORT)) nsh的判断依据
  • si=0 的时候,sfc结束,drop packet
  • 核心调用 vs->rcv(vs, skb, vxh->vx_vni, nsp, c1, c2, c3, c3);

该函数最重要的一句无疑是ovs_vport_receive(vport, skb, &tun_info).

之前的工作实际是进一步整合传入的header信息,用ovs_flow_tun_info_init去初始化tun_info,然后调用vport中数据处理函数ovs_vport_receive进一步处理。

事实上,不论vxlan还是gre亦或lisp网络,最后的数据处理都会回到ovs_vport_receive,然后在ovs_vport_receive去调用ovs_dp_process_received_packet,回到datapath.c进行统一处理;在ovs_dp_process_received_packet进行流表查询,然后去查表执行对应的action。

在查询流表失败的时候,由ovs_dp_upcall发送upcall到用户空间(ovs-vswitchd),此后处理过程交给ovsd 处理。具体的流表匹配就不展开了。

以上数据监听到处理的流程解读实际上说明了OVS已经把VxLAN的tunnel信息和NSH信息整合起来了,流表和数据的对应关系如上图。

2.3 OVS作为classifier对数据进行的NSH封装

OVS作为classifier最重要的功能就是对数据的封装和发送。

linux内核中vxlan_xmit_skb函数的功能是对skb进行vxlan封装,在OVS中对该函数进行了重写,增加了NSH封装功能。
该函数在vxlan的send操作被调用,即在classifier发数据前进行了封装。另外,该版本OVS添加了NSH对应的action,主要是一些attribute动作,用于添加NSH信息。

3. 总结

  • OVS在SFC-NSH中,可以是Classifier,SFF和SF对应的proxy.
  • 该版本OVS添加了NSH对应的action,主要是attribute,用于添加NSH,这部分功能主要用于classifier去打NSHheader。
  • NSH只是一个封装技术,便于SFC中的数据传输。

作者简介: 张萌 2014.9-今在北邮计算机学院网络技术中心学习

--------------华丽的分割线------------------
本文系《SDNLAB原创文章奖励计划》投稿文章,该计划旨在鼓励广大从业人员在SDN/NFV/Cloud网络领域创新技术、开源项目、产业动态等方面进行经验和成果的文字传播、分享、交流。有意向投稿的同学请通过官方唯一指定投稿通道进行文章投递,投稿细则请参考《SDNLAB原创文章奖励计划》


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/16610.html
分享到:
相关文章
条评论

登录后才可以评论

小明头上一棵草 发表于16-04-22
2