Just For Coding

Keep learning, keep living …

Open vSwitch上OpenFlow流表操作示例

Open vSwitch提供了OpenFlow命令行工具: ovs-ofctl, 用法及流表语法等细节参考: ovs-ofctl(8)。

本文将通过简单的PING实验来展示OVS上的OpenFlow操作,实验环境宿主机为CentOS7。

创建虚拟交换机:

1
ovs-vsctl add-br br-int

创建TAP设备:

1
2
ip tuntap add tap0 mode tap
ip tuntap add tap1 mode tap

将设备连接到虚拟交换机:

1
2
ovs-vsctl add-port br-int tap0
ovs-vsctl add-port br-int tap1

SDN和OpenFlow介绍

传统网络架构下,数据转发和转发决策逻辑都集中在网络设备内部,而各厂商的网络设备都有自己的配置方法, 运维和管理的复杂性很高。云计算等业务发展对网络调整的迅速响应需求越来越高,传统方式网络架构越来越不能满足灵活性要求。因而业界提出了SDN方案,将数据平面和控制平面分离,数据平面由网络设备完成,而决策逻辑交由独立的控制器来完成,从而控制器能够对整个网络进行全局管控。除此之外,控制器对上层应用程序提供API(称为北向API),上层的业务逻辑可以使用北向API处理流量和部署服务,网络控制逻辑可以直接通过编写程序来完成,网络调整的响应速度大为加快,灵活性大为提高。控制器与负责转发数据的网络设备之间通过标准协议交互转发策略,这之间协议称为南向协议或南向API。

整体架构如图:

OpenFlow是一种南向API协议,并且定义了交换机规范。实现OpenFlow规范的交换机称为OpenFlow交换机。

基于IPTABLES MARK机制实现策略路由

MARK是IPTABLES的一种规则目标,它用于给匹配了相应规则的数据包设置标签。它只能用于mangle表中。然而,标签并不是设置于数据包内容中,而是设置在内核中数据包的载体上。如果需要在数据包内容中设置标签,可以使用TOS规则目标,它可以修改IP数据包头的TOS值。

MARK是一个32位整数值, MARK目标可以使用3种方法来设置mark值:

  • --set-mark value: 直接设置mark值为value
  • --and-mark value: 将mark值与value做位与运算后设置为新mark值
  • --or-mark value: 将mark值与value做位或运算后设置为新mark值

比如,将从网络接口tun0进入的、目标端口为5222的TCP数据包设置mark值为1:

1
iptables -t mangle -A PREROUTING -j MARK --set-mark 1 -i tun0 -p tcp --dport 5222

OpenStack虚拟机实例关联多个浮动IP

许多场景下我们的OpenStack虚拟机实例需要关联多个浮动IP。Horizon Dashboard不支持这样的操作,但是我们可以通过命令行和API完成。

可以以两种形式关联:

  • 实例配置多个NIC,每个NIC关联一个浮动IP
  • 实例只配置一个NIC,NIC上配置多个fixed IP, 每个浮动IP关联一个fixed IP

首先看第一种形式:

列出所有网络,找到实例所在网络和子网:

1
2
3
4
5
6
7
8
9
[root@localhost ~(keystone_admin)]# neutron net-list
+--------------------------------------+---------+------------------------------------------------------+
| id                                   | name    | subnets                                              |
+--------------------------------------+---------+------------------------------------------------------+
| 1ced55ea-d30f-4c1d-ba97-6a7bbbd9ecca | private | f805a609-da7c-4a79-98a4-1aefb6aca2a2 10.0.0.0/24     |
| 467b92e0-540d-4cac-86a6-999354c6b6c8 | 1       | 216fa519-973f-493f-a8ef-1b5f9e30335f 10.0.1.0/24     |
| 65bdc2e1-d3ba-4b20-912c-6f0a29aef5de | public  | 189e9999-4295-45a4-b6b2-438225249654 172.24.4.224/28 |
| 73569655-f522-4e3d-b2f3-f1a1fd83cc5e | 2       | c9015487-e913-4a31-bc14-ef3cb549c895 10.0.2.0/24     |
+--------------------------------------+---------+------------------------------------------------------+

ARP协议介绍

ARP: Address Resolution Protocol, 地址解析协议,主要用于根据IP获取对应的物理地址,它封装在数据链路协议上,如以太网帧封装。

以太网中,交换机根据数据包中源MAC地址与对应的交换机端口建立映射关系。当以太网帧到达交换机,交换机根据包中目的MAC地址在映射表查找对应的交换机端口。若找到,则直接从该端口转发,否则向除接收端口外的所有其他端口广播数据包。

以太网内的主机要发送数据包时首先判断目标IP地址是否是同一子网。若发送给本地网络主机,则根据目的主机IP获取对应的MAC地址。若发送到其他网络,则通过路由获取目的IP(一般为网关IP),根据该IP获取对应的目的MAC地址。收到ARP响应之后,发送相应的数据包。

IPTABLES机制分析

iptables是Linux系统上的包过滤防火墙。它基于netfilter框架实现,分为内核模块和用户态程序。内核模块负责根据规则过滤数据包,用户态程序负责将规则写入内核模块。

iptables根据功能将过滤规则组织成表, 按处理时机组成链。每个表中含有多个链,每个链中包含一组规则。每条规则由数据包的匹配条件和匹配之后要执行的目标构成。iptables内核模块依次检查规则过滤数据包。

Linux路由分析

Linux默认情况下会丢掉不属于本机IP的数据包。将net.ipv4.ip_forward设置为1后,会开启路由功能,Linux会像路由器一样对不属于本机的IP数据包进行路由转发。

路由的基本流程为: 收到数据包之后,解析出目的IP,判断是否是本机IP。如果是本机IP,则交由上层传输层处理。如果不是本机IP,则通过查找路由表找到合适的网络接口将IP数据包转发出去。

Linux上通过路由规则和路由表配合来实现路由流程, 处理逻辑如下:

  • 按路由规则优先级, 根据规则匹配条件找到需要匹配的路由表
  • 根据路由表中条目进行匹配的结果进行转发
  • 若路由表中没有匹配到满足的路由条目,则处理下一路由规则

虚拟网络设备

OpenStack虚拟化网络实现中大量应用了多种虚拟网络设备,了解这些设备是理解OpenStack虚拟网络实现的基础,本文来简单介绍这些虚拟网络设备。

TUN/TAP设备

TUN/TAP设备是Linux内核中实现的虚拟网卡。物理网卡是从物理线路上收发数据包,而TUN/TAP设备是从用户态应用程序上收发以太网帧或IP包。用户态进程对/dev/net/tun文件调用open()获取一个文件描述符,并调用ioctl()挂接到该设备上,接着通过读写该文件描述符从TUN/TAP设备的收发数据包。收发的数据包由用户态进程构造好。TUN和TAP设备的区别在于TUN设备收发的是IP包,而TAP设备收发的是以太网帧。

在进程中创建及使用TUN/TAP设备可以参考官方文档: https://www.kernel.org/doc/Documentation/networking/tuntap.txt

可以使用iproute2工具包中的ip命令创建TUN/TAP设备, 如:

1
2
ip tuntap add dev tap0 mode tap
ip tuntap add dev tun0 mode tun

Lua代码加密

我们的程序很多业务逻辑由Lua实现,为了防止业务逻辑被曝光,需要对Lua代码进行加密。

我们有两种思路:

  • 自定义字节码: Lua库可以直接调用编译后生成的Lua字节码,因而我们可以将源码编译成字节码对外提供。但是因为Lua是开源的,可以通过工具将字节码反编译回源码。我们可以自定义字节码,加大反编译的难度。
  • 将Lua源码文件加密,在Lua编译字节码前,对源码文件进行解密

本文主要介绍第二种思路的实现。 我们的程序使用LuaJIT来执行Lua代码,因而以LuaJIT来说明。

XenServer编译内核模块

Citrix提供了DDK(Driver Development Kit)来支持在XenServer中要构建自定义的内核模块或硬件驱动。DDK是一个OVA格式的虚拟机镜像,包含了内核头文件和编译器等开发工具。

下面介绍使用DDK构建内核模块的步骤。

首先从官方下载相应版本DDK,这里选择6.5: http://downloadns.citrix.com.edgesuite.net/10106/XenServer-6.5.0-DDK.iso

将下载的ISO文件上传到XenServer宿主机上

挂载ISO

1
2
mkdir /mnt/tmp
mount <path_to_DDK>/ddk.iso /mnt/tmp -o loop