Monday, November 12, 2012

OpenvSwitch 代码分析(一)

本小节简要分析datapath模块。
datapath模块实现了最底层交换机机制的基本过程,该模块跟sdn其实并没有太大关系。
接收网包-->查表-->转发;如果表中没有,则通过upcall扔给ovsd。

datapath模块的代码主要包括如下几个关键子模块:主文件datapath.h/c,vport的实现vport-(generic/gre/capwap/netdev/internal/patch),genl子模块等。


action.c中定义了对网包执行操作的各个接口。
包括对vlan头的处理,对skb执行一系列给定的操作,发出网包,发skb给用户态(ovsd),采样,设置包头各个域的属性等。


flow模块包括flow.h和flow.c。
定义维护交换机本地流表相关的数据结构和操作,包括流表结构的创建、更新、删除,对每条流的管理等。


genl-exec.h中定义了对genl的相关操作,包括
typedef int (*genl_exec_func_t)(void *data);
int genl_exec(genl_exec_func_t func, void *data);
int genl_exec_init(void);
void genl_exec_exit(void);
genl_exec_family的定义为
static struct genl_family genl_exec_family = {
.id = GENL_ID_GENERATE, //channel number: will be assigned by the controller
.name = "ovs_genl_exec",
.version = 1,
};
genl_exec_ops[]的定义为
static struct genl_ops genl_exec_ops[] = {
{
.cmd = GENL_EXEC_RUN, //reference the operation
.doit = genl_exec_cmd, //the callback function
.flags = CAP_NET_ADMIN,
},
};


关键的逻辑实现在vport子模块中。在vport.h/c中定义了抽象的vport结构。对外的对vport进行操作的接口如下
int ovs_vport_init(void);
void ovs_vport_exit(void);

struct vport *ovs_vport_add(const struct vport_parms *);
void ovs_vport_del(struct vport *);

struct vport *ovs_vport_locate(struct net *net, const char *name);

int ovs_vport_set_addr(struct vport *, const unsigned char *);
void ovs_vport_set_stats(struct vport *, struct ovs_vport_stats *);
void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *);

int ovs_vport_set_options(struct vport *, struct nlattr *options);
int ovs_vport_get_options(const struct vport *, struct sk_buff *);

int ovs_vport_send(struct vport *, struct sk_buff *);
这些接口对外提供统一的用户操作界面。部分并没有立刻定义,即使定义的接口中,大部分依次或者单独调用某种类型的vport上绑定的vport_ops中提供的接口,对所有支持的vport进行操作。例如,初始化过程中,实际上是初始化了一个vport_ops_list[],依次初始化不同类型的vport,并放到该list中。再比如ovs_vport_add接口实际上先进行查找,找到给定的类型之后,进行对应的操作。
而具体到某个vport,其能进行操作的接口在vport_ops结构体中声明,为
struct vport_ops {
enum ovs_vport_type type;
u32 flags;

/* Called at module init and exit respectively. */
int (*init)(void);
void (*exit)(void);

/* Called with RTNL lock. */
struct vport *(*create)(const struct vport_parms *);
void (*destroy)(struct vport *);

int (*set_options)(struct vport *, struct nlattr *);
int (*get_options)(const struct vport *, struct sk_buff *);

int (*set_addr)(struct vport *, const unsigned char *);

/* Called with rcu_read_lock or RTNL lock. */
const char *(*get_name)(const struct vport *);
const unsigned char *(*get_addr)(const struct vport *);
void (*get_config)(const struct vport *, void *);
struct kobject *(*get_kobj)(const struct vport *);

unsigned (*get_dev_flags)(const struct vport *);
int (*is_running)(const struct vport *);
unsigned char (*get_operstate)(const struct vport *);

int (*get_ifindex)(const struct vport *);

int (*get_mtu)(const struct vport *);

int (*send)(struct vport *, struct sk_buff *);
};
目前,vport_ops支持5种类型,分别为
static const struct vport_ops *base_vport_ops_list[] = {
&ovs_netdev_vport_ops,
&ovs_internal_vport_ops,
&ovs_patch_vport_ops,
&ovs_gre_vport_ops,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
&ovs_capwap_vport_ops,
#endif
};
以ovs_netdev_vport_ops为例,定义了一系列的函数指针。
const struct vport_ops ovs_netdev_vport_ops = {
.type = OVS_VPORT_TYPE_NETDEV,
.flags          = VPORT_F_REQUIRED,
.init = netdev_init,
.exit = netdev_exit,
.create = netdev_create,
.destroy = netdev_destroy,
.set_addr = ovs_netdev_set_addr,
.get_name = ovs_netdev_get_name,
.get_addr = ovs_netdev_get_addr,
.get_kobj = ovs_netdev_get_kobj,
.get_dev_flags = ovs_netdev_get_dev_flags,
.is_running = ovs_netdev_is_running,
.get_operstate = ovs_netdev_get_operstate,
.get_ifindex = ovs_netdev_get_ifindex,
.get_mtu = ovs_netdev_get_mtu,
.send = netdev_send,
};



No comments:

Post a Comment