SDN控制器代码重构(一)---消息进来存的buffer和sw解耦

背景介绍

OpenFlow中的信息有很多种,以of13_msg_features_request为例,
原先在每个SW上起两个线程,一个接收,一个发送

1
2
3
//by:yhy 创建收发线程
pthread_create(&(sw->pid_recv), NULL, msg_recv_thread, (void *)&(sw->index));
pthread_create(&(sw->pid_proc), NULL, msg_proc_thread, (void *)&(sw->index));

这个是交换机中定义的结构体



typedef struct gn_switch
{
    UINT1 ofp_version;
    UINT1 state;						//标记Switch是否启用
    UINT1 pad[2];
    INT4 index;
    UINT8 dpid;							/* 数据通路唯一的 ID。低 48-bits 是 MAC 地址,高 16 位是开发者定义。 */
    UINT4 sw_ip;			
    UINT4 sw_port;
    UINT4 sock_fd;						//by:yhy 本交换机的socket连接句柄
    UINT4 n_buffers;					/*一次缓冲最大的数据包数。 	*/
    UINT4 n_tables;						/* 数据通路支持的表数量。 	*/
    UINT4 n_ports;						/* 交换机端口数量			*/
    UINT4 capabilities;					/* 位图的支持"ofp_capabilities". */
    switch_desc_t sw_desc;				//交换机的描述信息
    gn_port_t lo_port;					//by:yhy  Local openflow "port"
    gn_port_t ports[MAX_PORTS];
    neighbor_t *neighbor[MAX_PORTS];	//by:yhy 数组neighbor的索引与ports的索引匹配,neighbor[a]即为ports[a]的邻居节点
    mac_user_t **users;
    msg_driver_t msg_driver;
    buffer_list_t recv_buffer;			//by:yhy 接收缓存
    UINT4 send_len;
    UINT1 *send_buffer;					/*长度:g_sendbuf_len*/
    gn_flowmod_helper_t flowmod_helper;
    gn_flow_t *flow_entries;			//by:yhy 本交换机流表
    gn_meter_t *meter_entries;
	INT4 qos_type;
	gn_qos_t* qos_entries;
    gn_group_t* group_entries;
	gn_queue_t* queue_entries;
    pthread_mutex_t users_mutex;
    pthread_mutex_t send_buffer_mutex;
    pthread_mutex_t flow_entry_mutex;
    pthread_mutex_t meter_entry_mutex;
    pthread_mutex_t group_entry_mutex;
    pthread_t pid_recv;   				//by:yhy 接收线程pid
    pthread_t pid_proc;   				//by:yhy 处理线程pid
    UINT8 connected_since;
    UINT8 weight;         //sw_weight
    UINT1 sock_state;     //socket status  判断当前线程是否拥有操作的权利"0"有效
    pthread_mutex_t sock_state_mutex;
}gn_switch_t;

但是在每个包的处理过程中,会占用sw结构体中的buffer,并且每个包在存的时候都会加锁

1
2
3
4
5
6
7
8
static INT4 of13_msg_features_request(gn_switch_t *sw, UINT1 *fea_req)
{
	LOG_PROC("OF13", "of13_msg_features_request -- START");
    UINT2 total_len = sizeof(struct ofp_header);
    init_sendbuff(sw, OFP13_VERSION, OFPT13_FEATURES_REQUEST, total_len, 0);
	LOG_PROC("OF13", "of13_msg_features_request -- STOP");
    return send_of_msg(sw, total_len);
}

这个是init_sendbuff的函数,把header中的数据写到sw结构中的buffer中


//初始化发送缓存
UINT1 *init_sendbuff(gn_switch_t *sw, UINT1 of_version, UINT1 type, UINT2 buf_len, UINT4 transaction_id)
{
    UINT1 *b = NULL;
    struct ofp_header *h;

    pthread_mutex_lock(&sw->send_buffer_mutex);
    if(sw->send_len < g_sendbuf_len)
    {
        b = sw->send_buffer + sw->send_len;
    }
    else
    {
        printf("........\n");
        write(sw->sock_fd, sw->send_buffer, sw->send_len);
        memset(sw->send_buffer, 0, g_sendbuf_len);
        sw->send_len = 0;
        b = sw->send_buffer;
    }

    h = (struct ofp_header *)b;
    h->version = of_version;
    h->type    = type;
    h->length  = htons(buf_len);

    if (transaction_id)
    {
        h->xid = transaction_id;
    }
    else
    {
        h->xid = random_uint32();
    }

    return b;
}

这个是send_of_msg函数,把消息的total_len加上去,然后解锁,最后通过交换机的发送线程发送 //发送openflow消息(解锁switch的发送缓存,具体发送在发送线程中执行)

1
2
3
4
5
6
7
INT4 send_of_msg(gn_switch_t *sw, UINT4 total_len)
{
//    INT4 ret = 0;
    sw->send_len += total_len;
    pthread_mutex_unlock(&sw->send_buffer_mutex);
    return GN_OK;
}

重构后:

思路,把消息进来存的buffer和sw解耦,sw的buffer每次只能被一个消息所占用,很影响效率,改动后如下,每次给一个包分配一个msgbuf,等写完之后,全部扔给sw_buffer,从而提高性能

1
2
3
4
5
6
7
8
static INT4 of13_msg_features_request(gn_switch_t *sw, UINT1 *fea_req)
{
    Msg_Buf(struct ofp_header);
  
    UINT2 nLen = sizeof(struct ofp_header);
    init_header(pMsg,OFP13_VERSION,OFPT13_FEATURES_REQUEST,nLen,0);
    send_packet(sw, msgbuf, nLen);
}

重构init_header,把header中的数据封装


void init_header(struct ofp_header *p_header,UINT1 of_version, UINT1 type, UINT2 len, UINT4 transaction_id)
{
	p_header->version = of_version;
	p_header->type = type;
	p_header->length = htons(len);
    if (transaction_id)
    {
        p_header->xid = transaction_id;
    }
    else
    {
        p_header->xid = random_uint32();
    }
}

细节改动:

在common.h中加入
创建一个msgbuf给每个消息10K的大小的一个buffer,并初始化

1
2
3
4
5
6
#define MSG_MAX_LEN  10240
#define Msg_Buf(msgtype) \
    char msgbuf[MSG_MAX_LEN];\
    memset(msgbuf, 0, sizeof(msgbuf));\
    msgtype* pMsg = NULL;\
    pMsg = (msgtype*)msgbuf;

在conn-svr.h中加入


INT4 send_packet(gn_switch_t *sw, INT1* pBuf, UINT4 nLen);
void init_header(struct ofp_header *p_header,UINT1 of_version, UINT1 type, UINT2 len, UINT4 transaction_id);

在conn-svr.c中加入
直接将msgbuffer扔给sw_buffer处理

1
2
3
4
5
6
7
8
INT4 send_packet(gn_switch_t *sw, INT1* pBuf, UINT4 nLen)
{
    pthread_mutex_lock(&sw->send_buffer_mutex);
    memcpy(sw->send_buffer + sw->send_len, pBuf, nLen);
    sw->send_len += nLen;
    pthread_mutex_unlock(&sw->send_buffer_mutex);
}

蒋暕青

蒋暕青
Lots of mountains to climb,lots of enemies to defeat.

OpenStack cinder mutil-attach技术探秘

OpenStack cinder mutil-attach技术探秘 Continue reading

OpenStack octavia简介

Published on July 18, 2018

Openstack Cyborg项目介绍

Published on July 15, 2018