我们知道当packet到达交换机之后会提取出flow key->查询流表,如果匹配成功就执行对应的action,否则构造netlink attribute发送到用户空间对应的进程,这里vswitchd会调用handle_upcalls(ofproto/ofproto-dpif.c)来处理。主要流程图是:
结构体 dpif_upcall 表征的是从datapath传到userspace的一个packet(lib/dpif.h)。
(如果key或者action非空的话,那么其指向的数据从属于这个packet,所以不能单独被释放;)
struct dpif_upcall {
/* All types. */
enum dpif_upcall_type type;
struct ofpbuf *packet; /* Packet data. 是全部数据包,还是根据of协议 ??
struct nlattr *key; /* Flow key. */
size_t key_len; /* Length of 'key' in bytes. */
/* DPIF_UC_ACTION only. */
uint64_t userdata; /* Argument to OVS_ACTION_ATTR_USERSPACE. */
};
struct dpif_upcall {
/* All types. */
enum dpif_upcall_type type;
struct ofpbuf *packet; /* Packet data. 是全部数据包,还是根据of协议 ??
struct nlattr *key; /* Flow key. */
size_t key_len; /* Length of 'key' in bytes. */
/* DPIF_UC_ACTION only. */
uint64_t userdata; /* Argument to OVS_ACTION_ATTR_USERSPACE. */
};
upcall的类型有:
enum dpif_upcall_type {
DPIF_UC_MISS, /* Miss in flow table. */
DPIF_UC_ACTION, /* OVS_ACTION_ATTR_USERSPACE action. */
DPIF_N_UC_TYPES
};
DPIF_UC_MISS, /* Miss in flow table. */
DPIF_UC_ACTION, /* OVS_ACTION_ATTR_USERSPACE action. */
DPIF_N_UC_TYPES
};
static int handle_upcalls(struct ofproto_dpif *ofproto, unsigned int max_batch) {
struct dpif_upcall misses[FLOW_MISS_MAX_BATCH];
struct ofpbuf miss_bufs[FLOW_MISS_MAX_BATCH];
uint64_t miss_buf_stubs[FLOW_MISS_MAX_BATCH][4096 / 8];
int n_processed;
int n_misses;
int i;
assert(max_batch <= FLOW_MISS_MAX_BATCH);
n_misses = 0;
for (n_processed = 0; n_processed < max_batch; n_processed++) {
struct dpif_upcall *upcall = &misses[n_misses];
struct ofpbuf *buf = &miss_bufs[n_misses];
int error;
ofpbuf_use_stub(buf, miss_buf_stubs[n_misses], sizeof miss_buf_stubs[n_misses]);
struct dpif_upcall misses[FLOW_MISS_MAX_BATCH];
struct ofpbuf miss_bufs[FLOW_MISS_MAX_BATCH];
uint64_t miss_buf_stubs[FLOW_MISS_MAX_BATCH][4096 / 8];
int n_processed;
int n_misses;
int i;
assert(max_batch <= FLOW_MISS_MAX_BATCH);
n_misses = 0;
for (n_processed = 0; n_processed < max_batch; n_processed++) {
struct dpif_upcall *upcall = &misses[n_misses];
struct ofpbuf *buf = &miss_bufs[n_misses];
int error;
ofpbuf_use_stub(buf, miss_buf_stubs[n_misses], sizeof miss_buf_stubs[n_misses]);
//这个函数的作用是初始化从某个基址开始,一定大小的ofbuf缓冲区,并且base应该指向一个栈的缓冲区并且要对齐;
//使用uint32_t,uint64_t类型可以确保合适的对齐;一个ofbuf缓冲区操作如果需要重新分配数据的话需要将STUB上的
//数据拷贝到malloc缓冲区中,由于这个buf可能扩展到堆上,所以最后应该调用ofpbuf_uninit来释放相应的内存。(??)
error = dpif_recv(ofproto->dpif, upcall, buf);
//通过具体的datapath类型,调用其中的recv方法(这里的dpif class 是dpif_linux_class,表示本机);
//dpif_linux_class表示的是通过netlink和本地的datapath通信,而dpif_netdev_class通过网络协议和远程的datapath通信;
switch (classify_upcall(upcall)) {
case MISS_UPCALL:
n_misses++; /* Handle it later. */
break;
case SFLOW_UPCALL:
if (ofproto->sflow) {
handle_sflow_upcall(ofproto, upcall);
case MISS_UPCALL:
n_misses++; /* Handle it later. */
break;
case SFLOW_UPCALL:
if (ofproto->sflow) {
handle_sflow_upcall(ofproto, upcall);
//对于SFLOW_UPCALL 和 BAD_UPCALL,进行对应处理后释放存有 upcall 消息的 buf,而对于
//MISS_UPCALL 类型,则调用 handle_miss_upcalls 进行后续的处理。
//MISS_UPCALL 类型,则调用 handle_miss_upcalls 进行后续的处理。