Just For Coding

Keep learning, keep living …

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

Lua源码分析: 2. Math标准库实现

Lua通过标准库实现了核心之外的功能,如math库,I/O库等。本文来分析math标准库的实现, 代码位于lmathlib.c

math库提供了一组标准的数学函数,如绝对值函数, 三角函数,随机数函数等。调用方式为:

1
a = math.abs(-1)

标准库由C语言函数实现,提供给Lua程序使用。Lua程序与C函数通过虚拟栈交互。Lua将参数压入栈中,C函数从栈中获取参数,并将结果压入栈中,C函数返回入栈的结果数量。C函数无需在压入结果前清空栈,Lua会在函数执行完成后从栈中获取结果并自动清空结果下的内容。

Lua调用的C函数的格式是固定的,定义在lua.h中:

1
typedef int (*lua_CFunction) (lua_State *L);

Lua源码分析: 1. Lua命令行程序实现

默认情况下,Lua源码编译后会生成三个文件:

  • lua: Lua解释器的命令行程序,在命令行下执行Lua脚本文件
  • luac: Lua编译器,将Lua程序编译成Lua的字节码
  • liblua.a: Lua语言的功能实现库,通过该库的API调用可以将Lua嵌入其他语言

Lua 是一种解释型语言,执行方式如图:

首先将Lua源码编译成Lua字节码,然后由虚拟机来执行Lua字节码。

Thrift介绍

Thrift(https://thrift.apache.org/)是一个轻量级、语言无关的RPC框架。它定义了一套简单直观的IDL(Interface Definition Language)用于描述服务接口规范。 通过代码生成引擎将IDL描述的接口规范生成各种目标语言(如C++ ,JAVA等)的源码文件。应用开发者基于这些源码构建服务端和客户端。通过这种方式,Thrift屏蔽了不同语言间的数据序列化/反序列化、数据传输、网络通信等与业务逻辑不相关的部分,使开发者只需关心业务逻辑实现。