功能说明
防火墙部署过程中,需要使用代理提供较强的控制能力。而为了不影响用户网络,代理通常需要部署为透明代理。 L3层面的透明代理可以通过协议栈的支持来实现,可以结合haproxy的透明模式和linux协议栈的iptables以及策略路由实现。 有些场景,还需要实现L2的透明,主要是vlan+mac的透明,在协议栈的L3就不太容易实现。 因为网桥是符合L2透明的设备模型,因此在桥的基础上可以比较方便的实现二层透明代理。 下面主要利用Openvswitch流表解决二层透明代理的三个问题:
- 实现对代理业务报文和非业务报文的分流,非业务报文不代理。
- 实现业务报文上送到proxy,并且打上二层信息标签。
- 实现对proxy发出的报文进行正确的二层封装,透明转发到server或client。
实现方案
拓扑示意如图:
controller和proxy都是通过虚接口与ovs的datapath相连。
说明:
- 红色线为client->server报文经过的慢速路径,报文需要上送controller,再注入回datapath,经过proxy后到达server
- 蓝色线为server->client报文经过的慢速路径,报文需要上送controller,再注入回datapath,经过proxy后到达server
- 绿色线为client<->server双向通信的快速路径,报文经过流表规则上送proxy处理,但是不上送controller,客户端和服务器都不感知自己经过了proxy
实现流程
报文转发路径和流表规则
a. 引流设备同时刚部署进网络时,同时会收到业务报文和非业务报文。业务报文以(ip_proto_port)三元组标识。 添加一条normal规则,用于匹配非业务报文交换转发; 添加两条规则,用于匹配ctos和stoc两个方向的业务报文,使其上送controller,走慢速路径。
- match all, normal , 优先级0
- match 资产ip+port, to controller, 优先级1
b. client发出的第一个业务请求报文通过流表规则上送controller,走慢速路径,如图中的红色线所示。根据这个报文维护两张表(l2表和l3表),L2表是smac_dmac_vlan_inport表,根据报文的二层信息进行hash得到键值,同时根据该键值生成顺序数组的索引(使用bitmap); L3表是以sip_dip为键值的hash表,内容是前一张表计算生成的索引 值,注意只能填充ctos方向。这个报文同时触发生成4条流表规则。
- 生成proxy->client 改包转发的无标签匹配流表规则,封包规则是根据client请求反弹,即以dip_sip为键值查L3表,然后根据ctos方向的tag值查的L2信息封装后发出。优先级2
- 生成proxy->server 改包转发的无标签匹配流表规则,出接口根据接口对配置查得,封包规则以sip_dip为键值查L3表,然后根据ctos方向的tag值查的L2信息封装后发出。优先级2
- 生成proxy->server 改包转发的有标签匹配流表规则,出接口根据接口对配置查得,封包规则根据计算得到的标签匹配dmac,对报文进行封装。优先级3
- 生成client->proxy 快速路径的流表转发规则,该规则优先级高于a步骤中client->controller的优先级,封装方式为将tag值写入到smac,出接口为proxy所在接口。匹配项为资产信息+L2信息。优先级3
b1. controller 将b中收到的请求报文封装后上送proxy,封包处理方式同b中步骤4 。
c. server发出的第一个业务请求报文通过a步骤中所添加流表规则上送controller,走慢速路径,如图中蓝色线所示。 根据这个报文更新L2表和L3表,L2表根据根据二层信息hash得到一个新标签键值,L3表根据dip_sip信息填充stoc方向的二层信息索引键值。同时依据报文触发生成两条流表规则。
- 生成server->proxy快速路径的流表转发规则,该规则优先级高于a步骤中server->controller的优先级,封装方式为将tag值写入到smac,出接口为proxy所在接口。匹配项为资产信息+L2信息。优先级3
- 生成proxy-client 改包转发的有标签匹配流表规则,因为可能存在不对称的情况,需要根据server封装的源mac进行改包,而不是一直根据client报文反弹。封包规则是根据标签查得二层封装信息,对报文进行封装转发,优先级3
c1. controller 将c中收到的请求报文封装后上送proxy,封包处理方式同c中步骤1 。
出接口选择
交换机的出接口选择原理是学习转发,没学到时泛洪。而二层直通是直接根据接口对配置转发。二层直通方式不存在学习和和泛洪的问题。
表项结构与操作
L2表
C to S 方向
对所有业务报文的二层信息存入一张hash表ctos_l2_hash,如果是新插入的值,为该值生成反向查找标签,并将标签值作为hash value的一部分存储。
标签生成机制采用顺序生成方式,从0依次分配,有标签回收时整体搬移填空。维护一个标签反向查询数组,以标签为键值存储“指向二层信息表中entry的
的指针”。如果是python,以标签为键值直接存储二层地址信息ctos_l2_tag。例如: {l2_info: tag}tag is a index of [l2_info_pointer]
S to C 方向
对反向的业务报文二层信息维护另一张hash表stoc_l2_hash。生成新的标签值,维护S to C方向的标签反向查询数组stoc_l2_tag。
- 对所有上送业务报文,首先查hash表,如果查到,将对应的标签写到报文的smac中。如果查不到,生成标签,标签也写入对应mac中。
- 对proxy下发的报文,不论哪个方向,从smac中拿到标签,根据标签反向查询数组,查询得到要使用的二层信息,封装后发出。
- 如果是不对称的场景,需要将反向的标签值写入到报文smac中,上送协议栈,协议栈反向的标签值和正向的可能不同。
- 不对称的场景, c to s 方向要查询正向表, s to c 方向要查询反向表。可以开启学习以应对这种场景。
L3表
L3表的核心结构是(cip, sip)键值对,值为一对二层封装标签值(tag1, tag2)
在某些场景下L3表的键值可以用(cip_prefix, sip) 对为键值,替换掉 (cip, sip), 即将L3表对应的client聚合。
因为真实的场景下,client通常是经过路由器来访问server,因此是多个client ip对应一个client端的mac地址。
可以根据一个mac与多个client ip的对应关系,将表项的键值中的client ip聚合。达到缩减表项的目的,这个优化通常需要用户配置。
表老化
- L2表和L3表都存在老化问题,二层表时间可以设置稍长,比如2.5小时,ip表可以设置的时间稍短,比如20分钟。理论上不该存在TCP连接没断开而L2表老化了的情况。 可能存在MAC表没老化,而IP表老化了的情况,这种情况是知道如何封装和转发报文的。
- openflow的流表都有idle_timeout 和 hard_timeout两个选项,可以使用其中的idle_timeout控制流表的老化时间,流表老化时,根据数据平面上送的OFPT_FLOW_REMOVED消息通知控制器删除对应ip-mac表项。
不对称场景下的学习连接
在不对称的场景下,很少的情况下,回弹的报文不能正确返回到client,这个时候可能需要引流设备做一步对server二层地址的主动学习。 主动学习需要构造一条虚假的tcp连接,向server发起请求,依据这条虚假连接收到的server回复报文进行学习,获得stoc封装信息。 这条主动学习连接的构造方式,需要考虑协议的具体类型,很可能需要上层socket应用来构造包和维护收发报文的过程。