enum ovs_action_attr {/* ... *//** after #ifndef __KERNEL__ ... #endif.* the equals is thus ABSOLUTELY NECESSARY*/OVS_ACTION_ATTR_RMDUPQUEUE = 23, /* struct ovs_action_rmdupqueue. */__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted* from userspace. *//* ... */}
/** struct ovs_action_rmdupqueue - %OVS_ACTION_ATTR_RMDUPQUEUE action argument.* @queue_id: Algorithm used to choose queue number.* @max_len: basis used for setting queue[queue_id] size.*/
struct ovs_action_rmdupqueue{uint32_t queue_id;uint32_t max_len;
};
int nsh_hdr_from_nlattr(const struct nlattr *attr, struct nshhdr *nh,size_t size);//-------------------queue start---------------------
#define MAX_QUEUE_SIZE 1000 //最多可以为1000个流提供服务
#define MAX_QUEUE_LEN 1000 //----改进:动态自适应算法,自动选择队列大小 或者 滑动窗口协议PRP
typedef struct
{int *queue; //队列指针(动态分配队列空间)int NUM; //队列大小int TOP, REAR; //队首队尾标识int EmpFlag; //队列判空标识
}Queue;void InitQueue(Queue* q, int n); //初始化队列
int EmptyOrFullQueue(Queue q); //队列判空以及判断满
int QueueLength(Queue q); //获取队列大小int PushQueue(Queue* q,int ele); //入队操作
int PopQueue(Queue* q); //出队操作int RePushQueue(Queue* q, int ele); //当一个数据第二次到达时对数据进行匹配出队操作
int FindElePos(Queue q, int ele,int* n); //查找元素位置void ShowData(Queue q); //显示队列数据extern Queue Que[];
//-----------------queue end----------------------------
#endif /* flow_netlink.h */


//-------------------queue start---------------------
void InitQueue(Queue* q,int n)
{q->NUM = n;//空间回收if (q->queue != NULL){kfree(q->queue); //改进:设置一个新的action(---del-flows指令,不是action) 实现队列的释放,清除上一个actionq->queue = NULL;}if (q->NUM != 0){q->queue = (int *)kmalloc(sizeof(int)*n,GFP_KERNEL);memset(q->queue, 0, sizeof(int)*n);}q->TOP = q->REAR = 0;q->EmpFlag = 1; //空队列
}int EmptyOrFullQueue(Queue q)
{return q.EmpFlag;
}int QueueLength(Queue q)
{if (EmptyOrFullQueue(q) == 1)return 0;if (EmptyOrFullQueue(q) == 2)return q.NUM;if (q.TOP > q.REAR)return q.REAR + q.NUM - q.TOP;elsereturn q.REAR - q.TOP;
}int PushQueue(Queue* q, int ele)
{if (q->NUM <= 0)return 0; //队列空间已经释放 设置常量if (RePushQueue(q, ele) == 1) //重复插入,冗余数据---重点 改进:定义网络新协议,替换ip标识return 1;if (q->EmpFlag == 2) //队列满的情况入队PopQueue(q); //先出队队首,再入队q->queue[q->REAR] = ele;q->REAR = (q->REAR + 1) % q->NUM;if (q->TOP == q->REAR)q->EmpFlag = 2; //为满队列elseq->EmpFlag = 3;return 0;
}int PopQueue(Queue* q)
{if (q->NUM <= 0)return -2; //队列空间已经释放 改进:可以队列动态空间划分int temp = q->queue[q->TOP];if (q->EmpFlag == 1) //队列为空时,不允许出队return -1;q->TOP++;if (q->TOP == q->NUM)q->TOP = 0;if (q->TOP == q->REAR)q->EmpFlag = 1; //为空队列elseq->EmpFlag = 3;return temp;
}int RePushQueue(Queue* q, int ele)
{int n; //用于记录元素个数int pos = FindElePos(*q, ele, &n); if (pos == -1)return 0; //可以直接插入q->TOP = pos;if (QueueLength(*q) == 0)q->EmpFlag = 1;elseq->EmpFlag = 3;return 1; //队列有重复
}int FindElePos(Queue q, int ele,int* n)
{int i;for (i = 0; i < QueueLength(q); i++)if (q.queue[(i + q.TOP) % q.NUM] == ele){*n = i + 1; //返回队首到该元素,一共几个数据return (i + q.TOP + 1) % q.NUM; //返回该元素位置的下一个位置,新的队首}return -1;
}
//-----------------queue end----------------------------


static bool rmdup_queue(struct sk_buff *skb, struct sw_flow_key *key,const struct nlattr *attr)
{/* since we can't use rand() in the kernel */struct ovs_action_rmdupqueue* rdque_act = nla_data(attr);uint32_t queue_id = rdque_act->queue_id - 1; //can`t waste kernel space 改进:交换机返回设置后的队列号给控制器,用来进行记录调配https://www.cnblogs.com/ssyfj/p/11623514.htmluint32_t max_len = rdque_act->max_len;struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);unsigned int ident = (unsigned int)ip_header->id; //获取IP报文首部的id标识字段作为去重标准if(max_len == 0 && Que[queue_id].NUM == 0) //don`t need to remove the redundancy packetreturn false; //去重复,后面进行删除---false不进行去重复else if (max_len == 0 && Que[queue_id].NUM != 0){ //init queue infomationInitQueue(&Que[queue_id],max_len);return false; //去重复,后面进行删除---false不进行去重复} else if (max_len != 0 && max_len != Que[queue_id].NUM){ //reinit the queueInitQueue(&Que[queue_id],max_len);return PushQueue(&Que[queue_id],ident); //PushQueue返回1,表示有重复,返回0,表示没有重复}else{ //judge the packet, decide to remove this packetreturn PushQueue(&Que[queue_id],ident); //PushQueue返回1,表示有重复,返回0,表示没有重复}
}


/* Execute a list of actions against 'skb'. */
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,struct sw_flow_key *key,const struct nlattr *attr, int len)
{const struct nlattr *a;int rem;for (a = attr, rem = len; rem > 0;a = nla_next(a, &rem)) {int err = 0;switch (nla_type(a)) {case OVS_ACTION_ATTR_OUTPUT: ....break;case OVS_ACTION_ATTR_RMDUPQUEUE:if(rmdup_queue(skb, key, a)) //当我们的队列发现存在重复,则进行去重操作(删除当前数据包){while (rem) {a = nla_next(a, &rem);}}break;case OVS_ACTION_ATTR_PUSH_MPLS:err = push_mpls(skb, key, nla_data(a));break;

OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact, "goto_table") \OFPACT(RMDUPQUEUE, ofpact_rmdupqueue, ofpact, "rmdupqueue")

/* OFPACT_RMDUPQUEUE.** Used for OFPAT_RMDUPQUEUE */
struct ofpact_rmdupqueue {OFPACT_PADDED_MEMBERS(struct ofpact ofpact;uint32_t queue_id;uint32_t max_len; /* Uint probability, "covers" 0->1 range. */);uint8_t data[];
};


void
odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,const struct nlattr *actions, size_t actions_len,odp_execute_cb dp_execute_action)
{struct dp_packet *packet;......switch ((enum ovs_action_attr) type) {case OVS_ACTION_ATTR_UNSPEC:case OVS_ACTION_ATTR_RMDUPQUEUE:case __OVS_ACTION_ATTR_MAX:OVS_NOT_REACHED();}}dp_packet_delete_batch(batch, steal);
}


static void
dpif_execute_helper_cb( /* ... */ )
{/* ... */switch ((enum ovs_action_attr)type) {/* ... */ case OVS_ACTION_ATTR_RMDUPQUEUE:OVS_NOT_REACHED();}
}


void
dpif_ipfix_read_actions( /* ... */ )
{/* ... */switch (type) {/* ... */case OVS_ACTION_ATTR_RMDUPQUEUE:/* Again, ignore for now. Not needed. */break;}
}


void
dpif_sflow_read_actions( /* ... */ )
{switch (type) {/* ... */case OVS_ACTION_ATTR_RMDUPQUEUE:/* Ignore sFlow for now, unless needed. */break;}
}

static void
format_odp_rmdupqueue_action(struct ds *ds, const struct ovs_action_rmdupqueue *rdq_act)
{ds_put_format(ds, "rmdupqueue(queue_id=%"PRIu32",max_len=%"PRIu32")",rdq_act->queue_id,rdq_act->max_len);
}

static void
format_odp_action(struct ds *ds, const struct nlattr *a,const struct hmap *portno_names)
{int expected_len;enum ovs_action_attr type = nl_attr_type(a);switch (type) {case OVS_ACTION_ATTR_METER:ds_put_format(ds, "meter(%"PRIu32")", nl_attr_get_u32(a));break;......case OVS_ACTION_ATTR_RMDUPQUEUE: format_odp_rmdupqueue_action(ds, nl_attr_get(a));break; case OVS_ACTION_ATTR_UNSPEC:case __OVS_ACTION_ATTR_MAX:default:format_generic_odp_action(ds, a);break;}
}


static int
parse_odp_action(const char *s, const struct simap *port_names,struct ofpbuf *actions)
{{uint32_t port;int n;if (ovs_scan(s, "%"SCNi32"%n", &port, &n)) {nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, port);return n;}}...... {uint32_t queue_id,max_len;struct ovs_action_rmdupqueue rdque;int n;if (ovs_scan(s, "rmdupqueue(queue_id=%"SCNi32",max_len=%"SCNi32")%n", &queue_id, &max_len, &n)) {rdque.queue_id = queue_id;rdque.max_len = max_len;nl_msg_put_unspec(actions, OVS_ACTION_ATTR_RMDUPQUEUE,&rdque, sizeof rdque);return n;}}{if (!strncmp(s, "clone(", 6)) {..........


static int
odp_action_len(uint16_t type)
{if (type > OVS_ACTION_ATTR_MAX) {return -1;}switch ((enum ovs_action_attr) type) {case OVS_ACTION_ATTR_OUTPUT: return sizeof(uint32_t);......case OVS_ACTION_ATTR_RMDUPQUEUE: return sizeof(struct ovs_action_rmdupqueue);case OVS_ACTION_ATTR_UNSPEC:case __OVS_ACTION_ATTR_MAX:return ATTR_LEN_INVALID;}return ATTR_LEN_INVALID;
}
enum ofp_raw_action_type {/* ... *//* NX1.3+(47): struct nx_action_decap, ... */NXAST_RAW_DECAP,/* OF1.0+(30): struct ofp10_action_rmdupqueue. */OFPAT_RAW_RMDUPQUEUE,/* ... */
}
注释非常重要,说明了协议版本,序号,构造openflow消息所需参数 有些函数头是根据协议版本、您选择的代码和操作所需的参数类型自动生成的。 后面的序号是独一无二的,不能在同一协议版本中出现两个一样的序号
put_OFPAT_action构造openflow消息 put_OFPAT_RMDUPQUEUE: 根据 下面的消息结构体构造出openflow消息

struct ofp10_action_rmdupqueue {ovs_be16 type; /* OFPAT_VENDOR. */ovs_be16 len; /* At least 16. */ovs_be32 vendor; /* NX_VENDOR_ID. */ovs_be16 subtype; /* NXAST_OUTPUT_TRUNC. */uint8_t zeros[6];ovs_be32 queue_id;ovs_be32 max_len;
};
OFP_ASSERT(sizeof(struct ofp10_action_rmdupqueue) == 24); //必须是8字节的整数倍

(1)ofpact_decode---->decode_OFPAT_RAW_RMDUPQUEUE: 解openflow消息生成openvswitch action (2)ofpact_encode---->encode_RMDUPQUEUE: 从ofpact_type构造openflow消息 (3)ofpact_parse---->parse_RMDUPQUEUE: 从字符串解析构造openvswitch action (4)ofpact_format---->format_RMDUPQUEUE: 将openvswitch action转化为string (5)ofpact_check---->check_RMDUPQUEUE:校验openvswitch action
注意:
在我们添加流表项时,会先执行解析、检查、编码操作(从字符串解析OVS action,然后构造openflow消息)
在我们使用ovs-ofctl dump-flows 交换机,会先执行解码、格式化操作(将openflow消息转换为OVS action,然后根据OVS action中的参数去格式化为字符串显示)

/*use queue to achive remove packet duplicate*/
struct ofp10_action_rmdupqueue {ovs_be16 type; /* OFPAT_VENDOR. */ovs_be16 len; /* At least 16. */ovs_be32 vendor; /* NX_VENDOR_ID. */ovs_be16 subtype; /* NXAST_OUTPUT_TRUNC. */uint8_t zeros[6];ovs_be32 queue_id;ovs_be32 max_len;
};
OFP_ASSERT(sizeof(struct ofp10_action_rmdupqueue) == 24); //定义的消息体下实现编码、解码等即可/* Encoding the action packet to put on the wire. */
static void
encode_RMDUPQUEUE(const struct ofpact_rmdupqueue *rdque,enum ofp_version ofp_version OVS_UNUSED,struct ofpbuf *out)
{struct ofp10_action_rmdupqueue* of_rdque = put_OFPAT_RMDUPQUEUE(out);of_rdque->queue_id = rdque->queue_id;of_rdque->max_len = rdque->max_len;
}/* Reversing the process. */
static enum ofperr
decode_OFPAT_RAW_RMDUPQUEUE(const struct ofp10_action_rmdupqueue* of_rdque,enum ofp_version ofp_version OVS_UNUSED,struct ofpbuf *out)
{struct ofpact_rmdupqueue *rdque;rdque = ofpact_put_RMDUPQUEUE(out);rdque->queue_id = of_rdque->queue_id;rdque->max_len = of_rdque->max_len;return 0;
}/* Helper for below. */
static char * OVS_WARN_UNUSED_RESULT
parse_rdque(char *arg, struct ofpbuf *ofpacts)
{struct ofpact_rmdupqueue *rdque;char *key, *value;rdque = ofpact_put_RMDUPQUEUE(ofpacts);while (ofputil_parse_key_value(&arg, &key, &value)) {char *error = NULL;if (!strcmp(key, "queue_id")) {error = str_to_u32(value, &rdque->queue_id);} else if (!strcmp(key, "max_len")) {error = str_to_u32(value, &rdque->max_len);}if (error) return error;}return NULL;
}/* Go from string-formatted args into an action struct.
e.g. ovs-ofctl add-flow ... actions=rmdupqueue(queue_id=3,max_len=100),output:"s2-eth0"
*/
static char * OVS_WARN_UNUSED_RESULT
parse_RMDUPQUEUE(char *arg, const struct ofpact_parse_params *pp)
{return parse_rdque(arg, pp->ofpacts);
}/* Used when printing info to console. */
static void
format_RMDUPQUEUE(const struct ofpact_rmdupqueue *rdque,const struct ofpact_format_params *fp)
{/* Feel free to use e.g. colors.param,colors.end around parameter names */ds_put_format(fp->s, "rmdupqueue(queue_id=%"PRIu32, rdque->queue_id);ds_put_format(fp->s, ",max_len=%"PRIu32")", rdque->max_len);
}/* ... */static enum ofperr
check_RMDUPQUEUE(const struct ofpact_rmdupqueue *rdque OVS_UNUSED,const struct ofpact_check_params *cp OVS_UNUSED)
{/* My method needs no checking. Probably. */return 0;
}


struct ofpact *
ofpact_next_flattened(const struct ofpact *ofpact)
{switch (ofpact->type) {/* ... */case OFPACT_RMDUPQUEUE:return ofpact_next(ofpact);}/* ... */
}/* ... */enum ovs_instruction_type
ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
{switch (type) {/* ... */case OFPACT_RMDUPQUEUE:default:return OVSINST_OFPIT11_APPLY_ACTIONS;/* ... */}
}/* ... */static bool
ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
{switch (ofpact->type) {/* ... */case OFPACT_RMDUPQUEUE:default:return false;}
}


static enum action_set_class
action_set_classify(const struct ofpact a*)
{switch (a->type) {/* ... *//* NEVER *//* ... */case OFPACT_RMDUPQUEUE:return ACTION_SLOT_INVALID;/* ... */}
}

在某些情况下,守护程序和内核模块通过Netlink套接字相互通信。
守护程序在到达时将流操作向下发送到内核(用于数据包处理),并在到达时轮询来自内核的任何上行调用。
通常,当到达的数据包与任何已知条目都不匹配时(即必须将该数据包发送到控制器,或者需要具体实例化通配符规则),就会发生这种情况。

/* Put this with the other "compose" functions. */
static void
compose_rmdupqueue_action(struct xlate_ctx *ctx, struct ofpact_rmdupqueue *op) //可以看出是将用户态的消息体传入内核态中了
{struct { ovs_be32 queue_id;ovs_be32 max_len;} odp_pd_label;odp_pd_label.queue_id = op->queue_id;odp_pd_label.max_len = op->max_len;nl_msg_put_unspec(ctx->odp_actions, OVS_ACTION_ATTR_RMDUPQUEUE,&odp_pd_label, sizeof odp_pd_label);
}


static void
do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,struct xlate_ctx *ctx, bool is_last_action,bool group_bucket_action)
{struct flow_wildcards *wc = ctx->wc;......switch (a->type) {......case OFPACT_RMDUPQUEUE:compose_rmdupqueue_action(ctx, ofpact_get_RMDUPQUEUE(a));break;case OFPACT_CLONE:......}
}
/* No action can undo the packet drop: reflect this. */
static bool
reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len)
{const struct ofpact *a;OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {switch (a->type) {/*... */case OFPACT_RMDUPQUEUE:return false;}}return true;
}/* ... *//* RMDUPQUEUE likely doesn't require explicit thawing. */
static void
freeze_unroll_actions( /* ... */ )
{/* ... */switch (a->type) {case OFPACT_RMDUPQUEUE:/* These may not generate PACKET INs. */break;}
}/* ... *//* Naturally, don't need to recirculate since we don't change packets. */
static void
recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
{/* ... */switch (a->type) {case OFPACT_RMDUPQUEUE:default:break;}
}


static int __ovs_nla_copy_actions( /*...*/ )
{/* ... */static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {/* ... */[OVS_ACTION_ATTR_RMDUPQUEUE] = sizeof(struct ovs_action_rmdupqueue),};/* ... *//* Be careful here, your compiler may not catch this one* even with -Werror */switch (type) {/* ... */case OVS_ACTION_ATTR_RMDUPQUEUE:/* Finalest sanity checks in the kernel. */break;/* ... */}/* ... */
}
原文链接:https://www.cnblogs.com/ssyfj/p/13620781.html
(免费订阅,永久学习)学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂
下一篇:关于新颖的词语