方案概述

使用类似于“物理旁挂,逻辑串联”的方式旁挂在 qrouter 旁。
根据用户的需求,是否使用PBR将流量引入FW,需要则在qrouter的namespace写入iptables策略,不需要则删掉策略。
拓扑如下图所示:

租户网络内部L3部署——旁挂引流回注

为了方便在qrouter上做引流策略,将fw启动在一个独立的subnet中。

该方式简单易行,只将 firewall 作为一个类似于feature 的实现,可以灵活的加载与卸载,当然切换中会有一定时间段的丢包。
开发则需要复用 neutron-server 的代码提供出自己的 API ,再写一个 plugin 调用 drive 向 namespace 写入和删除规则即可。

验证

【策略一】
(粗粒度,方便开发,下发策略)
根据流量进入口将非fw子网连接的 qr 接口全部使用pbr导入fw,fw根据自己的默认路由回注流量到 qrouter ,qrouter 再根据路由转发。
由于该pbr标记流量包含了ha 和 直接访问fw的流量,导致了 qrouter脑裂和fw面板无法访问的问题,但理论上来说不应该出现此问题,待跟进。
流量标记命令如下:

1
ip netns exec qrouter-xxx iptables -A PREROUTING ! -i qr-fw -j MARK --set-mark 100

【策略二】
(细粒度,测试主要以此种方式进行)

  1. 新建一个独立的路由表为PBR服务,下一跳指向fw

    1
    ip netns exec qrouter-xxx ip route add default via add-fw dev qr-fw table 100
  2. PBR策略(使用mangle表的mark进行着色)

    • egress流量
      以连接vm子网的 qr 口的进入流量为目标
      1
      ip netns exec qrouter-xxx iptables -A PREROUTING -t mangle -i qr-vm -j MARK --set-mark 100

    注意:
    neutron会将流量默认 mark 为 0x4000000/0xffff0000,将其余标记流量 drop 。所以需要删除非默认标记流量的drop规则,使流量可以流向fw:
    neutron过滤掉非默认标记流量
    附:问题现象记录
    观察iptables已成功将目标流量着色:
    PREROUTOING添加着色规则
    引流不成功,在 qr-fw 接口上无法抓到包:
    因neutron过滤掉非默认标记流量无法在qr-fw上抓到数据包的记录

    • ingress流量
      以 qr 口目标地址为vm子网的cidr的进入流量为目标
      存在以下问题:

      • 若使用 PREROUTING 链,此时还没有进行nat,目标地址应为floating ip(加细粒度)或 qg 口的地址,另外 mangle 之后是否会略过 nat 直接将流量引向 fw,还待验证,预估不会略过;
      • 若使用 FORWARD 或其它链,将会在路由选择之后,无法使用PBR。

      附上一张 iptables 的数据处理流程图:

      iptebles数据处理流程

      有待更正的示例:

      1
      ip netns exec qrouter-xxx iptables -A PREROUTING iptables -A PREROUTING -i qg-xxx -d add-fip -j MARK --set-mark 100
  3. 添加rule,将着色流量引入新建的独立table

    1
    ip netns exec qrouter-xxx ip rule add fwmark 100 table 100

    注意:
    关闭 neutron 的端口安全,使 fw 的 port 可以接受其它IP的流量(fw回注流量)。

    1
    neutron port-update --no-security-groups --port_security_enabled=False port-id-fw

    fw 的安全策略也要放开(在 fw 上配置),为方便测试打开了全部。
    360的firewall对转发流量全部放开
    在连接 fw 子网的 qr 接口上可以发现,存在 ttl=62 的包,说明流量顺利通过 br-int 回到了 qrouter 的 namespace :
    firewall引流回注egress流量从fw返回namespace证明

(更新一)
为了便于为 egress 流量引流定策略,同时避免着色流量行为及其后续需要采取的措施(如删除 neutron 过滤掉非默认标记流量的规则),现弃用mark标记流量的方式,直接基于流量应用rule。

  • egress流量

    1
    ip rule add dev qr-vm table 100
  • ingress流量

    1
    ip rule add dev qg-xxx to dst-address-cidr table 100

【目前无法解决的问题】

从外部主动发起的访问经过 firewall 可以顺利完成通信,但从内部主动发起的通信失败。
从下图的TTL可以看出,从外部主动访问内部完成了引流:

firewall引流回注ingress流量抵达目标并往返经过fw到达namespace的证明.png

从内部主动访问外部,在 qg 接口上无法抓到相应包,查看iptables发现流量没有顺利进行SNAT,反而匹配了下图中上面标红的规则,由该规则的out口策略确定流量从fw回注后进行路由时出现了错误:

firewall引流回注内部主动访问失败——查看iptables的nat表匹配

反复确认路由规则,并无问题,后面为了排除mark有效域等可能影响的因素,也同样使用PBR将流量强行导向 qg 口,然而iptables的匹配情况并无改善。图中匹配上SNAT的一条记录是删除上面那条标红规则匹配上的,但仍无法进行正确路由,未从根本上解决问题。

从外部发起的连接,匹配DNAT,Linux会有CT模块(connection_tracker)跟踪连接,该数据流就只有第一个包进行匹配,其余跟随装换。同理,回去的数据包并没有匹配SNAT规则,直接进行了转换。
但CT模块应该不可能略过路由,这就说明路由并没有问题,这和昨天研究的从内部发起连接的流量由于路由导致匹配规则出现问题的结论相悖。

(更新二)

从内部主动访问外部 iptables 匹配错误并不是由于路由造成的,那个匹配中的数据包是数据第一次进入 namespace 匹配上的,而由于 iptables 的 connection track 机制导致从 firewall 回流的数据与该数据认为是同一个数据流,不再另行匹配 iptables 规则,导致通信失败。

为解决该问题使用 raw 表解除该流量的 CT :

1
ip netns exec qrouter-xxx iptables -t raw -A PREROUTING -i qr-vm -j NOTRACK

验证发现从内部访问外部已经正常,引流也没有出现问题,但从外部访问内部又出现了问题。

在连接虚机所在子网的 qr 接口上抓包发现数据报文被修改了源地址,由外部IP修改成了 qg 桥用来做端口复用的的IP:
neutron将从非qg桥进来的dnat流量进行了snat现象

查看iptables规则,发现在 nat 表存在这样一条规则:
neutron将从非qg桥进来的dnat流量进行了snat

暂不考虑次生问题,先把这条规则干掉,再次在连接虚机所在子网的 qr 接口上抓包,与预期一致,但还是通信失败。
接着排查发现回复的数据包进了firewall,却没有吐回来:
firewall没有回吐流量证明

以icmp流量进行分析,是因为返回报文的 identifier 字段不一致导致 firewall 无法建立session:
icmp验证字段不一致1
icmp验证字段不一致2

根据环境推测,造成 identifier 字段不一样的原因是报文经过路由后为了保持该字段与下一跳一致会进行改变,取消 connection track 后这样的修改就没有进行。
预估就算 firewall 把流量吐回来,由于回复流量也被取消了ct,可能会出现其他问题,比如不能基于 ct 直接进行 snat 出去,需要自行匹配 snat 规则,tcp 会话是否能成功建立也有待验证。

该问题暂时无解,尝试取消从连接 firewall 子网的 qr 接口进来的流量的 ct,发现从双向发起的通信都无法完成,分析如下:

  • 会话由外部发起
    由于从 firewall 回注入 namespace ct记录的缺失,从vm 返回 namespace 的流量直接根据 ct 进行了snat,在连接firewall子网的qr 接口上抓包可见现象如下:
    由于ct缺失导致错误进行了snat
  • 会话由内部发起
    egress方向上从qg接口上出去时,由于使用raw表取消的ct,同时导致略过了snat:
    raw表取消ct导致略过了snat

(更新三)
在 namespace 连接 firewall 所在子网的接口上,取消目的 IP 为 client 所在子网的 CIDR 的流量的 CT

1
ip netns exec qrouter-xxx iptables -t raw -A PREROUTING -i qr-fw -d cidr-vm -j NOTRACK

顺利完成测试。

另外进行补充两点:

  • 只进行单向引流,回注回 namespace 的流量会被直接 drop ,这是由于未做返回流量的引流前,关于流量的路由结果逃出接口前后不相符,从而导致直接丢包。
  • 新加的这条取消 CT 的操作,将使流量直接略过更新二中所提到的有影响的 snat 规则,则现在不需要特别对其进行删除了。

总结 · 环境快速搭建指北

环境准备

  • client 虚机
    启动一台虚机,用于测试引流后,和外部的通信情况。(之后可以在启动第二台,用于验证租户内部通信情况)
  • 360_fw 镜像实例
    在不改变流量报文的情况下将流量引过来,提供安全服务。

    • 关闭该实例的 neutron 端口的端口安全和安全组,使 fw 的 port 可以接受其它IP的流量(fw回注流量)。

      1
      neutron port-update --no-security-groups --port_security_enabled=False port-id-fw
    • firewall 镜像实例的各种相关安全策略也要放开(在 fw 上配置),为方便测试打开了全部。
      360的firewall对转发流量全部放开

引流策略

  • 在 qrouter 的 namespace 中新建一个独立的路由表为PBR服务,下一跳指向fw

    1
    ip netns exec qrouter-xxx ip route add default via add-fw dev qr-fw table 100
  • egress引流

    1
    ip netns exec qrouter-xxx ip rule add dev qr-vm table 100
  • ingrees引流

    1
    ip netns exec qrouter-xxx ip rule add dev qg-xxx to dst-address-cidr table 100
  • 在 namespace 连接 client 所在子网的接口上取消 CT 记录

    1
    ip netns exec qrouter-xxx iptables -t raw -A PREROUTING -i qr-vm -j NOTRACK
  • 在 namespace 连接 firewall 所在子网的接口上,取消目的 IP 为 client 所在子网的 CIDR 的流量的 CT

    1
    ip netns exec qrouter-xxx iptables -t raw -A PREROUTING -i qr-fw -d cidr-vm -j NOTRACK