SDN功能实现(五)---修改OVS源码实现自定义openflow基本字段(延迟更新)

文章推荐:(提前了解背景)

Open vSwitch源码阅读笔记

SDNLAB技术分享(六):Open vSwitch匹配处理流程和拓展性

ovs流表

OpenvSwitch 流表转换

上面文章不需要全部看懂,了解即可!!

一:功能目的和扩展字段含义

(一)功能目的:实现openflow字段的延迟更新

参考hard_timeout字段:是为了使得openflow流表项在工作一段时间(即hard_timeout)后,自动失效!!!

而我所要实现的功能就是设置一个字段,可以实现微秒级别的,用来控制一条流表项的生效时间!!!

(二)扩展字段:effect_seceffect_usec含义

这两个字段来源于一个时间戳结构体:struct timeval; 该结构体可以精确时间到微秒级别

    struct timeval {
         time_t      tv_sec;   
         suseconds_t  tv_usec;
    };
#include <stdio.h>
#include <sys/time.h>
 
int main() {
    struct timeval tv;
    gettimeofday(&tv, NULL );

    printf("---%d---%d-\n",tv.tv_sec,tv.tv_usec);
    return 0;
}
结构体的使用,获取当前时间

(三)功能演示

1.启动mininet环境

sudo mn --topo=single,3 --switch=ovsk --controller=none

2.下发普通流表项

sh ovs-ofctl add-flow s1 in_port=1,actions=output:3,2
sh ovs-ofctl add-flow s1 in_port=2,actions=output:1

3.下发自定义字段的流表项

sh ovs-ofctl add-flow s1 in_port=3,effect_sec=1620909655,effect_usec=1811,actions=output:1

下发包含自定义基本字段的流表项之后,使用dpctl dump-flows查看流表项目:

发现我们下发的流表并没有被添加上去(因为还没有到生效时间),所以没有被添加。

此时使用ping命令,发现在没有达到生效时间时,无法ping通,当达到生效时间后,可以ping通!!!

并且查看流表项:发现我们之前添加的流表项也生效了

二:数据结构了解以及扩展数据

(一)ofputil_flow_mod结构体:整合所有版本的openflow消息结构体(不依赖某个版本)--- 解析下发的流表项字符串到ofputil_flow_mod结构体中

在文件openvswitch-2.11.4/include/openvswitch/ofp-flow.h中ofputil_flow_mod结构体添加自定义字段

struct ofputil_flow_mod {
    struct ovs_list list_node; /* For queuing flow_mods. */

    struct minimatch match;
    int priority;

    ovs_be64 cookie;         /* Cookie bits to match. */
    ovs_be64 cookie_mask;    /* 1-bit in each 'cookie' bit to match. */

    ovs_be64 new_cookie;     /* New cookie to install or UINT64_MAX. */
    bool modify_cookie;      /* Set cookie of existing flow to 'new_cookie'? */

    uint8_t table_id;
    uint16_t command;
    uint16_t idle_timeout;
    uint16_t hard_timeout;
    uint32_t buffer_id;
    ofp_port_t out_port;
    uint32_t out_group;
    enum ofputil_flow_mod_flags flags;
    uint16_t importance;     /* Eviction precedence. */
    struct ofpact *ofpacts;  /* Series of "struct ofpact"s. */
    size_t ofpacts_len;      /* Length of ofpacts, in bytes. */
    uint64_t ofpacts_tlv_bitmap; /* 1-bit for each present TLV in 'ofpacts'. */
    
    uint64_t effect_sec;     //----------------------------------修改-------------
    uint64_t effect_usec;     //----------------------------------修改-------------
};

(二)为所有需要的openflow协议体添加自定义基本字段---用于解析ofputil_flow_mod到对应的版本下的openflow协议

1.在文件openvswitch-2.11.4/include/openflow/openflow-1.1.h中为ofp11_flow_mod结构体添加自定义字段

/* Flow setup and teardown (controller -> datapath). */
struct ofp11_flow_mod {
    ovs_be64 cookie;             /* Opaque controller-issued identifier. */
    ovs_be64 cookie_mask;       
    /* Flow actions. */
    uint8_t table_id;            /* ID of the table to put the flow in */
    uint8_t command;             /* One of OFPFC_*. */
    ovs_be16 idle_timeout;       /* Idle time before discarding (seconds). */
    ovs_be16 hard_timeout;       /* Max time before discarding (seconds). */
    ovs_be16 priority;           /* Priority level of flow entry. */
    ovs_be32 buffer_id;          
    ovs_be32 out_port;          
    ovs_be32 out_group;         
    ovs_be16 flags;              /* One of OFPFF_*. */
    ovs_be16 importance;         
    ovs_be64 effect_sec;     /*---------------------------------修改-------------*/
    ovs_be64 effect_usec;     /*----------------------------------修改-------------*/
};
OFP_ASSERT(sizeof(struct ofp11_flow_mod) == 56);  /*-------必须是8的倍数-------*/

2.在文件openvswitch-2.11.4/include/openflow/openflow-1.0.h中为ofp10_flow_mod结构体添加自定义字段

/* Flow setup and teardown (controller -> datapath). */
struct ofp10_flow_mod {
    struct ofp10_match match;    /* Fields to match */
    ovs_be64 cookie;             /* Opaque controller-issued identifier. */

    ovs_be16 command;             /* One of OFPFC_*. */
    ovs_be16 idle_timeout;        /* Idle time before discarding (seconds). */
    ovs_be16 hard_timeout;        /* Max time before discarding (seconds). */
    ovs_be16 priority;            /* Priority level of flow entry. */
    ovs_be32 buffer_id;           
    ovs_be16 out_port;            
    ovs_be16 flags;               /* One of OFPFF_*. */

    ovs_be64 effect_sec;     /*---------------------------------修改-------------*/
    ovs_be64 effect_usec;     /*----------------------------------修改-------------*/
};
OFP_ASSERT(sizeof(struct ofp10_flow_mod) == 80);

(三)为所有需要的openflow stats协议体添加自定义基本字段,响应OFPST_FLOW请求---用于使用dump-flows命令后显示流表项信息

1.在文件openvswitch-2.11.4/include/openflow/nicira-ext.h中为nx_flow_stats结构体添加自定义字段

struct nx_flow_stats {
    ovs_be16 length;          /* Length of this entry. */
    uint8_t table_id;         /* ID of table flow came from. */
    uint8_t pad;
    ovs_be32 duration_sec;    /* Time flow has been alive in seconds. */
    ovs_be32 duration_nsec;   
    ovs_be16 priority;        /* Priority of the entry. */
    ovs_be16 idle_timeout;    /* Number of seconds idle before expiration. */
    ovs_be16 hard_timeout;    /* Number of seconds before expiration. */
    ovs_be16 match_len;       /* Length of nx_match. */
    ovs_be16 idle_age;        /* Seconds since last packet, plus one. */
    ovs_be16 hard_age;        /* Seconds since last modification, plus one. */
    ovs_be64 cookie;          /* Opaque controller-issued identifier. */
    ovs_be64 packet_count;    /* Number of packets, UINT64_MAX if unknown. */
    ovs_be64 byte_count;      /* Number of bytes, UINT64_MAX if unknown. */
ovs_be64 effect_sec; /*---------------------------------修改-------------*/ ovs_be64 effect_usec; /*----------------------------------修改-------------*/ }; OFP_ASSERT(sizeof(struct nx_flow_stats) == 64);

2.在文件openvswitch-2.11.4/include/openflow/openflow-1.0.h中为ofp10_flow_stats结构体添加自定义字段

/* Body of reply to OFPST_FLOW request. */
struct ofp10_flow_stats {
    ovs_be16 length;          /* Length of this entry. */
    uint8_t table_id;         /* ID of table flow came from. */
    uint8_t pad;
    struct ofp10_match match; /* Description of fields. */
    ovs_be32 duration_sec;    /* Time flow has been alive in seconds. */
    ovs_be32 duration_nsec;  
    ovs_be16 priority;      
    ovs_be16 idle_timeout;    /* Number of seconds idle before expiration. */
    ovs_be16 hard_timeout;    /* Number of seconds before expiration. */
    uint8_t pad2[6];          /* Align to 64 bits. */
    ovs_32aligned_be64 cookie;       /* Opaque controller-issued identifier. */
    ovs_32aligned_be64 packet_count; /* Number of packets in flow. */
    ovs_32aligned_be64 byte_count;   /* Number of bytes in flow. */
    ovs_be64 effect_sec;     /*---------------------------------修改-------------*/
    ovs_be64 effect_usec;     /*----------------------------------修改-------------*/
};
OFP_ASSERT(sizeof(struct ofp10_flow_stats) == 104);

3.在文件openvswitch-2.11.4/include/openflow/openflow-1.1.h中为ofp11_flow_stats结构体添加自定义字段

/* Body of reply to OFPST_FLOW request. */
struct ofp11_flow_stats {
    ovs_be16 length;           /* Length of this entry. */
    uint8_t table_id;          /* ID of table flow came from. */
    uint8_t pad;
    ovs_be32 duration_sec;     /* Time flow has been alive in seconds. */
    ovs_be32 duration_nsec;
    ovs_be16 priority;
    ovs_be16 idle_timeout;     /* Number of seconds idle before expiration. */
    ovs_be16 hard_timeout;     /* Number of seconds before expiration. */
    ovs_be16 flags;            /* OF 1.3: Set of OFPFF*. */
    ovs_be16 importance;       /* Eviction precedence (OF1.4+). */
    uint8_t  pad2[2];          /* Align to 64-bits. */
    ovs_be64 cookie;           /* Opaque controller-issued identifier. */
    ovs_be64 packet_count;     /* Number of packets in flow. */
    ovs_be64 byte_count;       /* Number of bytes in flow. */
    ovs_be64 effect_sec;     /*---------------------------------修改-------------*/
    ovs_be64 effect_usec;     /*----------------------------------修改-------------*/
};
OFP_ASSERT(sizeof(struct ofp11_flow_stats) == 64);

4.在文件openvswitch-2.11.4/include/openflow/ofp-flow.h中为ofputil_flow_stats结构体添加自定义字段---重点:这个结构体和前面1、2、3结构体的关系同(一)与(二)的关系

(1)通过ofctl_dump_flows--回调-->vconn_dump_flows(内部传参修改struct ofputil_flow_stats **fsesp)--调用--> ofputil_encode_flow_stats_request去解析各个版本下的openflow协议状态;最后将所有要显示的数据放入ofputil_flow_stats中

(2)再通过ofctl_dump_flows--调用-->ofputil_flow_stats_format(传参struct ofputil_flow_stats )--调用-->ds_put_format格式化要显示的流表项字符串信息

/* Flow stats reply, independent of protocol. */
struct ofputil_flow_stats {
    struct match match;
    ovs_be64 cookie;
    uint8_t table_id;
    uint16_t priority;
    uint16_t idle_timeout;
    uint16_t hard_timeout;
    uint32_t duration_sec;
    uint32_t duration_nsec;
    int idle_age;               /* Seconds since last packet, -1 if unknown. */
    int hard_age;               /* Seconds since last change, -1 if unknown. */
    uint64_t packet_count;      /* Packet count, UINT64_MAX if unknown. */
    uint64_t byte_count;        /* Byte count, UINT64_MAX if unknown. */
    const struct ofpact *ofpacts;
    size_t ofpacts_len;
    enum ofputil_flow_mod_flags flags;
    uint16_t importance;        /* Eviction precedence. */
    
    uint64_t effect_sec;     //----------------------------------修改-------------
    uint64_t effect_usec;     //----------------------------------修改-------------
};

(四)添加规则状态(未生效状态)和修改规则结构体---最后会将上面的openflow流表转换为规则插入datapath中进行缓存

在openvswitch/openvswitch-2.11.4/ofproto/ofproto-provider.h文件中

1.添加规则状态

enum OVS_PACKED_ENUM rule_state {
    RULE_INITIALIZED,
    RULE_INSERTED, 
    RULE_REMOVED,     
    RULE_EFFECTED,    /* ----------rule effect time------------*/
};

2.修改规则结构体

struct rule {
    struct ofproto *const ofproto; /* The ofproto that contains this rule. */
    const struct cls_rule cr;      /* In owning ofproto's classifier. */
    const uint8_t table_id;        /* Index in ofproto's 'tables' array. */

    enum rule_state state;
    ......
    /* Timeouts. */
    uint16_t hard_timeout OVS_GUARDED; /* In seconds from ->modified. */
    uint16_t idle_timeout OVS_GUARDED; /* In seconds from ->used. */

    /*------------------- effect time -------------------*/
    uint64_t effect_sec OVS_GUARDED;
    uint64_t effect_usec OVS_GUARDED;
    const struct ofproto_flow_mod* ofm; /*----------存储部分classifier_insert需要用到的参数---------*/
    ......
    const struct rule_actions * const actions;
    ...... 
    struct ovs_list expirable OVS_GUARDED_BY(ofproto_mutex);
    
    struct ovs_list effectable OVS_GUARDED_BY(ofproto_mutex);   /*-----effect time --------*/
    ......
};

3.修改struct ofproto_flow_mod结构体,因为需要保留请求中的数据

/* flow_mod with execution context. */
struct ofproto_flow_mod {
    /* Allocated by 'init' phase, may be freed after 'start' phase, as these
     * are not needed for 'revert' nor 'finish'.
     *
     * This structure owns a reference to 'temp_rule' (if it is nonnull) that
     * must be eventually be released with ofproto_rule_unref().  */
    struct rule *temp_rule;
    struct rule_criteria criteria;
    struct cls_conjunction *conjs;
    size_t n_conjs;

    /* Replicate needed fields from ofputil_flow_mod to not need it after the
     * flow has been created. */
    uint16_t command;
    bool modify_cookie;
    /* Fields derived from ofputil_flow_mod. */
    bool modify_may_add_flow;
    bool modify_keep_counts;
    enum nx_flow_update_event event;

    /* These are only used during commit execution.
     * ofproto_flow_mod_uninit() does NOT clean these up. */
    ovs_version_t version;              /* Version in which changes take
                                         * effect. */
    bool learn_adds_rule;               /* Learn execution adds a rule. */
    struct rule_collection old_rules;   /* Affected rules. */
    struct rule_collection new_rules;   /* Replacement rules. */

    /*--------------存储请求--------------------*/
    struct openflow_mod_requester * omr;
};

三:控制面实现,解析下发的流表项字符串到ofputil_flow_mod结构体中

流表下发一般是通过以下两种方式:

1.controller通过openflow协议下发FLOW_MOD命令给ovs的Userspace流表。
2.ovs-ofctl通过openflow协议下发FLOW_MOD给ovs的Userspace流表。

ovs-ofctl add-flow最终调用 ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);

(一)调用流程

ofctl_flow_mod--调用-->parse_ofp_flow_mod_str--调用-->parse_ofp_str--调用-->parse_ofp_str__实现解析字符串到ofputil_flow_mod结构体中

(二)修改parse_ofp_str__函数,使得解析字符串中的effect_sec和effect_usec字段

static char * OVS_WARN_UNUSED_RESULT
parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,     //----------------重点:1.字符串到ofputil_flow_mod
                const struct ofputil_port_map *port_map,
                const struct ofputil_table_map *table_map,
                enum ofputil_protocol *usable_protocols)
{
    VLOG_INFO("---------------parse_ofp_str__------------start--------\n");
    enum {
        F_OUT_PORT = 1 << 0,
        F_ACTIONS = 1 << 1,
        F_IMPORTANCE = 1 << 2,
        F_TIMEOUT = 1 << 3,
        F_PRIORITY = 1 << 4,
        F_FLAGS = 1 << 5,
    } fields;
    char *act_str = NULL;
    char *name, *value;

    *usable_protocols = OFPUTIL_P_ANY;

    if (command == -2) {
        size_t len;

        string += strspn(string, " \t\r\n");   /* Skip white space. */
        len = strcspn(string, ", \t\r\n"); /* Get length of the first token. */

        if (!strncmp(string, "add", len)) {
            command = OFPFC_ADD;
        } else if (!strncmp(string, "delete", len)) {
            command = OFPFC_DELETE;
        } else if (!strncmp(string, "delete_strict", len)) {
            command = OFPFC_DELETE_STRICT;
        } else if (!strncmp(string, "modify", len)) {
            command = OFPFC_MODIFY;
        } else if (!strncmp(string, "modify_strict", len)) {
            command = OFPFC_MODIFY_STRICT;
        } else {
            len = 0;
            command = OFPFC_ADD;
        }
        string += len;
    }

    switch (command) {
    case -1:
        fields = F_OUT_PORT;
        break;

    case OFPFC_ADD:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS | F_IMPORTANCE;
        break;

    case OFPFC_DELETE:
        fields = F_OUT_PORT;
        break;

    case OFPFC_DELETE_STRICT:
        fields = F_OUT_PORT | F_PRIORITY;
        break;

    case OFPFC_MODIFY:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
        break;

    case OFPFC_MODIFY_STRICT:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
        break;

    default:
        OVS_NOT_REACHED();
    }

    *fm = (struct ofputil_flow_mod) {
        .priority = OFP_DEFAULT_PRIORITY,
        .table_id = 0xff,
        .command = command,
        .buffer_id = UINT32_MAX,
        .out_port = OFPP_ANY,
        .out_group = OFPG_ANY,
        .effect_sec = 0,
        .effect_usec = 0,
    };
    VLOG_INFO("---------------parse_ofp_str__----flow_mod idle_timeout:%d--------start--------\n",fm->idle_timeout);
    VLOG_INFO("---------------parse_ofp_str__----flow_mod effect_time:%d %d--------start--------\n",fm->effect_sec,fm->effect_usec);

    /* For modify, by default, don't update the cookie. */
    if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) {
        fm->new_cookie = OVS_BE64_MAX;
    }

    if (fields & F_ACTIONS) {
        act_str = ofp_extract_actions(string);
        if (!act_str) {
            return xstrdup("must specify an action");
        }
    }

    struct match match = MATCH_CATCHALL_INITIALIZER;
    while (ofputil_parse_key_value(&string, &name, &value)) {
        const struct ofp_protocol *p;
        const struct mf_field *mf;
        char *error = NULL;

        if (ofp_parse_protocol(name, &p)) {
            match_set_dl_type(&match, htons(p->dl_type));
            if (p->nw_proto) {
                match_set_nw_proto(&match, p->nw_proto);
            }
            match_set_default_packet_type(&match);
        } else if (!strcmp(name, "eth")) {
            match_set_packet_type(&match, htonl(PT_ETH));
        } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
            fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
        } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
            fm->flags |= OFPUTIL_FF_CHECK_OVERLAP;
        } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
            fm->flags |= OFPUTIL_FF_RESET_COUNTS;
            *usable_protocols &= OFPUTIL_P_OF12_UP;
        } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
            fm->flags |= OFPUTIL_FF_NO_PKT_COUNTS;
            *usable_protocols &= OFPUTIL_P_OF13_UP;
        } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
            fm->flags |= OFPUTIL_FF_NO_BYT_COUNTS;
            *usable_protocols &= OFPUTIL_P_OF13_UP;
        } else if (!strcmp(name, "no_readonly_table")
                   || !strcmp(name, "allow_hidden_fields")) {
             /* ignore these fields. */
        } else if ((mf = mf_from_name(name)) != NULL) {
            error = ofp_parse_field(mf, value, port_map,
                                    &match, usable_protocols);
        } else if (strchr(name, '[')) {
            error = parse_subfield(name, value, &match, usable_protocols);
        } else {
            if (!*value) {
                return xasprintf("field %s missing value", name);
            }

            if (!strcmp(name, "table")) {
                if (!ofputil_table_from_string(value, table_map,
                                               &fm->table_id)) {
                    return xasprintf("unknown table \"%s\"", value);
                }
                if (fm->table_id != 0xff) {
                    *usable_protocols &= OFPUTIL_P_TID;
                }
            } else if (fields & F_OUT_PORT && !strcmp(name, "out_port")) {
                if (!ofputil_port_from_string(value, port_map,
                                              &fm->out_port)) {
                    error = xasprintf("%s is not a valid OpenFlow port",
                                      value);
                }
            } else if (fields & F_OUT_PORT && !strcmp(name, "out_group")) {
                *usable_protocols &= OFPUTIL_P_OF11_UP;
                if (!ofputil_group_from_string(value, &fm->out_group)) {
                    error = xasprintf("%s is not a valid OpenFlow group",
                                      value);
                }
            } else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
                uint16_t priority = 0;

                error = str_to_u16(value, name, &priority);
                fm->priority = priority;
            } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
                error = str_to_u16(value, name, &fm->idle_timeout);
            } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
                error = str_to_u16(value, name, &fm->hard_timeout);
            } else if (fields & F_IMPORTANCE && !strcmp(name, "importance")) {
                error = str_to_u16(value, name, &fm->importance);
            } else if(!strcmp(name, "effect_sec")){   //-------------------effect_sec---------------
                error = str_to_u64(value, &fm->effect_sec);
            } else if(!strcmp(name, "effect_usec")){   //-----------------effect_usec-----------------
                error = str_to_u64(value, &fm->effect_usec);
            } else if (!strcmp(name, "cookie")) {
                char *mask = strchr(value, '/');

                if (mask) {
                    /* A mask means we're searching for a cookie. */
                    if (command == OFPFC_ADD) {
                        return xstrdup("flow additions cannot use "
                                       "a cookie mask");
                    }
                    *mask = '\0';
                    error = str_to_be64(value, &fm->cookie);
                    if (error) {
                        return error;
                    }
                    error = str_to_be64(mask + 1, &fm->cookie_mask);

                    /* Matching of the cookie is only supported through NXM or
                     * OF1.1+. */
                    if (fm->cookie_mask != htonll(0)) {
                        *usable_protocols &= OFPUTIL_P_NXM_OF11_UP;
                    }
                } else {
                    /* No mask means that the cookie is being set. */
                    if (command != OFPFC_ADD && command != OFPFC_MODIFY
                        && command != OFPFC_MODIFY_STRICT) {
                        return xstrdup("cannot set cookie");
                    }
                    error = str_to_be64(value, &fm->new_cookie);
                    fm->modify_cookie = true;
                }
            } else if (!strcmp(name, "duration")
                       || !strcmp(name, "n_packets")
                       || !strcmp(name, "n_bytes")
                       || !strcmp(name, "idle_age")
                       || !strcmp(name, "hard_age")) {
                /* Ignore these, so that users can feed the output of
                 * "ovs-ofctl dump-flows" back into commands that parse
                 * flows. */
            } else {
                error = xasprintf("unknown keyword %s", name);
            }
        }

        if (error) {
            return error;
        }
    }
    VLOG_INFO("---------------parse_ofp_str__----flow_mod idle_timeout:%d--------start--------\n",fm->idle_timeout);
    VLOG_INFO("---------------parse_ofp_str__----flow_mod effect_sec:%d--effect_usec:%d------start--------\n",fm->effect_sec,fm->effect_usec);
    
    /* Copy ethertype to flow->dl_type for matches on packet_type
     * (OFPHTN_ETHERTYPE, ethertype). */
    if (match.wc.masks.packet_type == OVS_BE32_MAX &&
            pt_ns(match.flow.packet_type) == OFPHTN_ETHERTYPE) {
        match.flow.dl_type = pt_ns_type_be(match.flow.packet_type);
    }
    /* Check for usable protocol interdependencies between match fields. */
    if (match.flow.dl_type == htons(ETH_TYPE_IPV6)) {
        const struct flow_wildcards *wc = &match.wc;
        /* Only NXM and OXM support matching L3 and L4 fields within IPv6.
         *
         * (IPv6 specific fields as well as arp_sha, arp_tha, nw_frag, and
         *  nw_ttl are covered elsewhere so they don't need to be included in
         *  this test too.)
         */
        if (wc->masks.nw_proto || wc->masks.nw_tos
            || wc->masks.tp_src || wc->masks.tp_dst) {
            *usable_protocols &= OFPUTIL_P_NXM_OXM_ANY;
        }
    }
    if (!fm->cookie_mask && fm->new_cookie == OVS_BE64_MAX
        && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) {
        /* On modifies without a mask, we are supposed to add a flow if
         * one does not exist.  If a cookie wasn't been specified, use a
         * default of zero. */
        fm->new_cookie = htonll(0);
    }
    if (fields & F_ACTIONS) {
        enum ofputil_protocol action_usable_protocols;
        struct ofpbuf ofpacts;
        char *error;

        ofpbuf_init(&ofpacts, 32);
        struct ofpact_parse_params pp = {
            .port_map = port_map,
            .table_map = table_map,
            .ofpacts = &ofpacts,
            .usable_protocols = &action_usable_protocols
        };
        error = ofpacts_parse_instructions(act_str, &pp);
        *usable_protocols &= action_usable_protocols;
        if (!error) {
            enum ofperr err;

            struct ofpact_check_params cp = {
                .match = &match,
                .max_ports = OFPP_MAX,
                .table_id = fm->table_id,
                .n_tables = 255,
            };
            err = ofpacts_check(ofpacts.data, ofpacts.size, &cp);
            *usable_protocols &= cp.usable_protocols;
            if (!err && !*usable_protocols) {
                err = OFPERR_OFPBAC_MATCH_INCONSISTENT;
            }
            if (err) {
                error = xasprintf("actions are invalid with specified match "
                                  "(%s)", ofperr_to_string(err));
            }

        }
        if (error) {
            ofpbuf_uninit(&ofpacts);
            return error;
        }

        fm->ofpacts_len = ofpacts.size;
        fm->ofpacts = ofpbuf_steal_data(&ofpacts);
    } else {
        fm->ofpacts_len = 0;
        fm->ofpacts = NULL;
    }
    minimatch_init(&fm->match, &match);

    return NULL;
}
parse_ofp_str__
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,     //----------------重点:1.字符串到ofputil_flow_mod
                const struct ofputil_port_map *port_map,
                const struct ofputil_table_map *table_map,
                enum ofputil_protocol *usable_protocols)
{   
   ......
*fm = (struct ofputil_flow_mod) { .priority = OFP_DEFAULT_PRIORITY, .table_id = 0xff, .command = command, .buffer_id = UINT32_MAX, .out_port = OFPP_ANY, .out_group = OFPG_ANY, .effect_sec = 0,  //设置默认值 .effect_usec = 0, };
struct match match = MATCH_CATCHALL_INITIALIZER; while (ofputil_parse_key_value(&string, &name, &value)) { const struct ofp_protocol *p; const struct mf_field *mf; char *error = NULL; if (ofp_parse_protocol(name, &p)) { match_set_dl_type(&match, htons(p->dl_type)); if (p->nw_proto) { match_set_nw_proto(&match, p->nw_proto); } match_set_default_packet_type(&match); } else if (!strcmp(name, "eth")) { match_set_packet_type(&match, htonl(PT_ETH)); } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) { fm->flags |= OFPUTIL_FF_SEND_FLOW_REM; } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) { fm->flags |= OFPUTIL_FF_CHECK_OVERLAP; } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) { fm->flags |= OFPUTIL_FF_RESET_COUNTS; *usable_protocols &= OFPUTIL_P_OF12_UP; } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) { fm->flags |= OFPUTIL_FF_NO_PKT_COUNTS; *usable_protocols &= OFPUTIL_P_OF13_UP; } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) { fm->flags |= OFPUTIL_FF_NO_BYT_COUNTS; *usable_protocols &= OFPUTIL_P_OF13_UP; } else if (!strcmp(name, "no_readonly_table") || !strcmp(name, "allow_hidden_fields")) { /* ignore these fields. */ } else if ((mf = mf_from_name(name)) != NULL) { error = ofp_parse_field(mf, value, port_map, &match, usable_protocols); } else if (strchr(name, '[')) { error = parse_subfield(name, value, &match, usable_protocols); } else { if (!*value) { return xasprintf("field %s missing value", name); } if (!strcmp(name, "table")) { if (!ofputil_table_from_string(value, table_map, &fm->table_id)) { return xasprintf("unknown table \"%s\"", value); } if (fm->table_id != 0xff) { *usable_protocols &= OFPUTIL_P_TID; } } else if (fields & F_OUT_PORT && !strcmp(name, "out_port")) { if (!ofputil_port_from_string(value, port_map, &fm->out_port)) { error = xasprintf("%s is not a valid OpenFlow port", value); } } else if (fields & F_OUT_PORT && !strcmp(name, "out_group")) { *usable_protocols &= OFPUTIL_P_OF11_UP; if (!ofputil_group_from_string(value, &fm->out_group)) { error = xasprintf("%s is not a valid OpenFlow group", value); } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { uint16_t priority = 0; error = str_to_u16(value, name, &priority); fm->priority = priority; } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) { error = str_to_u16(value, name, &fm->idle_timeout); } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) { error = str_to_u16(value, name, &fm->hard_timeout); } else if (fields & F_IMPORTANCE && !strcmp(name, "importance")) { error = str_to_u16(value, name, &fm->importance); } else if(!strcmp(name, "effect_sec")){ //-------------------effect_sec--------------- error = str_to_u64(value, &fm->effect_sec); } else if(!strcmp(name, "effect_usec")){ //-----------------effect_usec----------------- error = str_to_u64(value, &fm->effect_usec); } else if (!strcmp(name, "cookie")) { ...... } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") || !strcmp(name, "n_bytes") || !strcmp(name, "idle_age") || !strcmp(name, "hard_age")) { } else { error = xasprintf("unknown keyword %s", name); } } if (error) { return error; } }
   ......
处理match和action
   ...... }

四:控制面实现,转换由三获取ofputil_flow_mod结构体数据到对应的openflow版本中去

(一)调用流程

ofctl_flow_mod--调用-->ofctl_flow_mod__--调用-->ofputil_encode_flow_mod--返回-->struct ofpbuf *msg,其中msg中封装了各个版本的openflow协议信息

msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, version, tailroom);

最后在ofctl_flow_mod__中通过下面函数转发到对应的网桥中去(控制面和数据面交互)!!!https://www.cnblogs.com/liuhongru/p/11399046.html

transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));

ofctl_flow_mod__会打开一个指向ovs-vswitchd的socket,将ofputil_flow_mod变成openflow的协议,发出去transact_noreply

补充:vconn与OVS网桥的连接

connmgr即connect manager连接管理器,主要完成OVS网桥的连接管理。每一个网桥ofproto都有一个connmgr实体来管理连接。

(二)修改ofputil_encode_flow_mod函数,ofputil_flow_mod结构体数据到对应的openflow版本中去

struct ofpbuf *
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,  //---------------重点:从ofputil_flow_mod中解析ofp11_flow_mod
                        enum ofputil_protocol protocol)
{
    enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
    ovs_be16 raw_flags = ofputil_encode_flow_mod_flags(fm->flags, version);
    struct ofpbuf *msg;

    struct match match;
    minimatch_expand(&fm->match, &match);
    VLOG_INFO("--------------ofputil_encode_flow_mod-------------start--------------");

    switch (protocol) {
    case OFPUTIL_P_OF11_STD:
    case OFPUTIL_P_OF12_OXM:
    case OFPUTIL_P_OF13_OXM:
    case OFPUTIL_P_OF14_OXM:
    case OFPUTIL_P_OF15_OXM:
    case OFPUTIL_P_OF16_OXM: {
        struct ofp11_flow_mod *ofm; //---------------重点:从ofputil_flow_mod中解析ofp11_flow_mod
        int tailroom;
        VLOG_INFO("--------------ofputil_encode_flow_mod-------ofp11_flow_mod------start--------------");

        tailroom = ofputil_match_typical_len(protocol) + fm->ofpacts_len;
        msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, version, tailroom);
        ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
        if ((protocol == OFPUTIL_P_OF11_STD
             && (fm->command == OFPFC_MODIFY ||
                 fm->command == OFPFC_MODIFY_STRICT)
             && fm->cookie_mask == htonll(0))
            || fm->command == OFPFC_ADD) {
            ofm->cookie = fm->new_cookie;
        } else {
            ofm->cookie = fm->cookie & fm->cookie_mask;
        }
        ofm->cookie_mask = fm->cookie_mask;
        if (fm->table_id != OFPTT_ALL
            || (protocol != OFPUTIL_P_OF11_STD
                && (fm->command == OFPFC_DELETE ||
                    fm->command == OFPFC_DELETE_STRICT))) {
            ofm->table_id = fm->table_id;
        } else {
            ofm->table_id = 0;
        }
        ofm->command = fm->command;
        ofm->idle_timeout = htons(fm->idle_timeout);
        ofm->hard_timeout = htons(fm->hard_timeout);
        ofm->effect_sec = htonl(fm->effect_sec);
        ofm->effect_usec = htonl(fm->effect_usec);
        ofm->priority = htons(fm->priority);
        ofm->buffer_id = htonl(fm->buffer_id);
        ofm->out_port = ofputil_port_to_ofp11(fm->out_port);
        ofm->out_group = htonl(fm->out_group);
        ofm->flags = raw_flags;
        if (version >= OFP14_VERSION && fm->command == OFPFC_ADD) {
            ofm->importance = htons(fm->importance);
        } else {
            ofm->importance = 0;
        }
        ofputil_put_ofp11_match(msg, &match, protocol);
        ofpacts_put_openflow_instructions(fm->ofpacts, fm->ofpacts_len, msg,
                                          version);
        break;
    }

    case OFPUTIL_P_OF10_STD:
    case OFPUTIL_P_OF10_STD_TID: {
        struct ofp10_flow_mod *ofm;
        VLOG_INFO("--------------ofputil_encode_flow_mod-------ofp10_flow_mod------start--------------");

        msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
                           fm->ofpacts_len);
        ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
        ofputil_match_to_ofp10_match(&match, &ofm->match);
        ofm->cookie = fm->new_cookie;
        ofm->command = ofputil_tid_command(fm, protocol);
        ofm->idle_timeout = htons(fm->idle_timeout);
        ofm->hard_timeout = htons(fm->hard_timeout);
        ofm->effect_sec = htonl(fm->effect_sec);
        ofm->effect_usec = htonl(fm->effect_usec);
        ofm->priority = htons(fm->priority);
        ofm->buffer_id = htonl(fm->buffer_id);
        ofm->out_port = htons(ofp_to_u16(fm->out_port));
        ofm->flags = raw_flags;
        ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
                                     version);
        break;
    }

    case OFPUTIL_P_OF10_NXM:
    case OFPUTIL_P_OF10_NXM_TID: {
        struct nx_flow_mod *nfm;
        int match_len;
        VLOG_INFO("--------------ofputil_encode_flow_mod-------nx_flow_mod------start--------------");

        msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
                           NXM_TYPICAL_LEN + fm->ofpacts_len);
        nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
        nfm->command = ofputil_tid_command(fm, protocol);
        nfm->cookie = fm->new_cookie;
        match_len = nx_put_match(msg, &match, fm->cookie, fm->cookie_mask);
        nfm = msg->msg;
        nfm->idle_timeout = htons(fm->idle_timeout);
        nfm->hard_timeout = htons(fm->hard_timeout);
        nfm->priority = htons(fm->priority);
        nfm->buffer_id = htonl(fm->buffer_id);
        nfm->out_port = htons(ofp_to_u16(fm->out_port));
        nfm->flags = raw_flags;
        nfm->match_len = htons(match_len);
        ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
                                     version);
        break;
    }

    default:
        OVS_NOT_REACHED();
    }

    ofpmsg_update_length(msg);
    return msg;
}
ofputil_encode_flow_mod
struct ofpbuf *
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,  //---------------重点:从ofputil_flow_mod中解析ofp11_flow_mod
                        enum ofputil_protocol protocol)
{
    enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
    ovs_be16 raw_flags = ofputil_encode_flow_mod_flags(fm->flags, version);
    struct ofpbuf *msg;

    struct match match;
    minimatch_expand(&fm->match, &match);switch (protocol) {
    case OFPUTIL_P_OF11_STD:
    case OFPUTIL_P_OF12_OXM:
    case OFPUTIL_P_OF13_OXM:
    case OFPUTIL_P_OF14_OXM:
    case OFPUTIL_P_OF15_OXM:
    case OFPUTIL_P_OF16_OXM: {
        struct ofp11_flow_mod *ofm; //---------------重点:从ofputil_flow_mod中解析ofp11_flow_mod
        int tailroom;

        tailroom = ofputil_match_typical_len(protocol) + fm->ofpacts_len;
        msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, version, tailroom);
        ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
        if ((protocol == OFPUTIL_P_OF11_STD
             && (fm->command == OFPFC_MODIFY ||
                 fm->command == OFPFC_MODIFY_STRICT)
             && fm->cookie_mask == htonll(0))
            || fm->command == OFPFC_ADD) {
            ofm->cookie = fm->new_cookie;
        } else {
            ofm->cookie = fm->cookie & fm->cookie_mask;
        }
        ofm->cookie_mask = fm->cookie_mask;
        if (fm->table_id != OFPTT_ALL
            || (protocol != OFPUTIL_P_OF11_STD
                && (fm->command == OFPFC_DELETE ||
                    fm->command == OFPFC_DELETE_STRICT))) {
            ofm->table_id = fm->table_id;
        } else {
            ofm->table_id = 0;
        }
        ofm->command = fm->command;
        ofm->idle_timeout = htons(fm->idle_timeout);
        ofm->hard_timeout = htons(fm->hard_timeout);
        ofm->effect_sec = htonll(fm->effect_sec);
        ofm->effect_usec = htonll(fm->effect_usec);
        ofm->priority = htons(fm->priority);
        ofm->buffer_id = htonl(fm->buffer_id);
        ofm->out_port = ofputil_port_to_ofp11(fm->out_port);
        ofm->out_group = htonl(fm->out_group);
        ofm->flags = raw_flags;
        if (version >= OFP14_VERSION && fm->command == OFPFC_ADD) {
            ofm->importance = htons(fm->importance);
        } else {
            ofm->importance = 0;
        }
        ofputil_put_ofp11_match(msg, &match, protocol);
        ofpacts_put_openflow_instructions(fm->ofpacts, fm->ofpacts_len, msg,
                                          version);
        break;
    }

    case OFPUTIL_P_OF10_STD:
    case OFPUTIL_P_OF10_STD_TID: {
        struct ofp10_flow_mod *ofm;
        VLOG_INFO("--------------ofputil_encode_flow_mod-------ofp10_flow_mod------start--------------");

        msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
                           fm->ofpacts_len);
        ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
        ofputil_match_to_ofp10_match(&match, &ofm->match);
        ofm->cookie = fm->new_cookie;
        ofm->command = ofputil_tid_command(fm, protocol);
        ofm->idle_timeout = htons(fm->idle_timeout);
        ofm->hard_timeout = htons(fm->hard_timeout);
        ofm->effect_sec = htonll(fm->effect_sec);
        ofm->effect_usec = htonll(fm->effect_usec);
        ofm->priority = htons(fm->priority);
        ofm->buffer_id = htonl(fm->buffer_id);
        ofm->out_port = htons(ofp_to_u16(fm->out_port));
        ofm->flags = raw_flags;
        ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
                                     version);
        break;
    }

    case OFPUTIL_P_OF10_NXM:
    case OFPUTIL_P_OF10_NXM_TID: {
        struct nx_flow_mod *nfm;
        int match_len;
        VLOG_INFO("--------------ofputil_encode_flow_mod-------nx_flow_mod------start--------------");

        msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
                           NXM_TYPICAL_LEN + fm->ofpacts_len);
        nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
        nfm->command = ofputil_tid_command(fm, protocol);
        nfm->cookie = fm->new_cookie;
        match_len = nx_put_match(msg, &match, fm->cookie, fm->cookie_mask);
        nfm = msg->msg;
        nfm->idle_timeout = htons(fm->idle_timeout);
        nfm->hard_timeout = htons(fm->hard_timeout);
        nfm->priority = htons(fm->priority);
        nfm->buffer_id = htonl(fm->buffer_id);
        nfm->out_port = htons(ofp_to_u16(fm->out_port));
        nfm->flags = raw_flags;
        nfm->match_len = htons(match_len);
        ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
                                     version);
        break;
    }

    default:
        OVS_NOT_REACHED();
    }

    ofpmsg_update_length(msg);
    return msg;
}

五:控制面实现,dump-flows显示流表项

 (一)ofctl调用流程

ofctl_dump_flows --调用-->

static void
ofctl_dump_flows(struct ovs_cmdl_context *ctx)
{
    ....struct ofputil_flow_stats_request fsr;
        enum ofputil_protocol protocol;
        struct vconn *vconn;

        vconn = prepare_dump_flows(ctx->argc, ctx->argv, false,
                                   &fsr, &protocol);

        struct ofputil_flow_stats *fses;
        size_t n_fses;
        run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses),
            "dump flows");

        if (n_criteria) {
            qsort(fses, n_fses, sizeof *fses, compare_flows);
        }

        struct ds s = DS_EMPTY_INITIALIZER;
        for (size_t i = 0; i < n_fses; i++) {
            ds_clear(&s);
            ofputil_flow_stats_format(&s, &fses[i],
                                      ports_to_show(ctx->argv[1]),
                                      tables_to_show(ctx->argv[1]),
                                      show_stats);
            printf(" %s\n", ds_cstr(&s));  //打印输出结果字符串
        }
        ds_destroy(&s);

        for (size_t i = 0; i < n_fses; i++) {
            free(CONST_CAST(struct ofpact *, fses[i].ofpacts));
        }
        free(fses);

        vconn_close(vconn);
}

分支一:

--调用--> vconn_dump_flows --调用--> ofputil_encode_flow_stats_request获取协议版本对应的请求,然后根据请求去调用recv_flow_stats_reply --调用--> ofputil_decode_flow_stats_reply 获取统一的ofputil_flow_stats结构体,而不是某一个版本的结构体,详细参考二(三)中!!!

分支二:获取分支一之后的状态结构体之后,开始处理转换为字符串!!!

--调用--> ofputil_flow_stats_format转换ofputil_flow_stats结构体数据为字符串

(二)调用流程(二)handle_openflow,处理方法如(一)类似,甚至相同!!!

handle_openflow --调用--> handle_single_part_openflow --调用--> handle_flow_stats_request --调用-->

(1) ofputil_decode_flow_stats_request 获取协议版本对应的请求,然后根据请求去调用recv_flow_stats_reply 

(2) ofputil_append_flow_stats_reply 响应请求 获取统一的ofputil_flow_stats结构体

(3) ofconn_send_replies ----> ofconn_send_reply ----> ofconn_send ----> rconn_send ----> rconn_send__ ----> copy_to_monitor ----> vconn_send ----> do_send ----> ofp_to_string会打印出所要显示的字符串 ----> ofp_to_string__

----> ofp_print_flow_stats_reply ----> ofputil_decode_flow_stats_reply

(三)修改ofputil_flow_stats_format获取要显示的字符串

void
ofputil_flow_stats_format(struct ds *string,
                          const struct ofputil_flow_stats *fs,
                          const struct ofputil_port_map *port_map,
                          const struct ofputil_table_map *table_map,
                          bool show_stats)
{
    if (show_stats || fs->cookie) {
        ds_put_format(string, "%scookie=%s0x%"PRIx64", ",
                      colors.param, colors.end, ntohll(fs->cookie));
    }
    if (show_stats) {
        ds_put_format(string, "%sduration=%s", colors.param, colors.end);
        ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
        ds_put_cstr(string, ", ");
    }

    if (show_stats || fs->table_id
        || ofputil_table_map_get_name(table_map, fs->table_id) != NULL) {
        ds_put_format(string, "%stable=%s", colors.special, colors.end);
        ofputil_format_table(fs->table_id, table_map, string);
        ds_put_cstr(string, ", ");
    }
    if (show_stats) {
        print_flow_stat(string, "n_packets", fs->packet_count);
        print_flow_stat(string, "n_bytes", fs->byte_count);
    }
    if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
        ds_put_format(string, "%sidle_timeout=%s%"PRIu16", ",
                      colors.param, colors.end, fs->idle_timeout);
    }
    if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
        ds_put_format(string, "%shard_timeout=%s%"PRIu16", ",
                      colors.param, colors.end, fs->hard_timeout);
    }
    if (fs->effect_sec != 0) {
        ds_put_format(string, "%seffect_sec=%s%"PRIu64", ",
                      colors.param, colors.end, fs->effect_sec);
    }
    if (fs->effect_usec != 0) {
        ds_put_format(string, "%seffect_usec=%s%"PRIu64", ",
                      colors.param, colors.end, fs->effect_usec);
    }
    if (fs->flags) {
        ofputil_flow_mod_flags_format(string, fs->flags);
    }
    if (fs->importance != 0) {
        ds_put_format(string, "%simportance=%s%"PRIu16", ",
                      colors.param, colors.end, fs->importance);
    }
    if (show_stats && fs->idle_age >= 0) {
        ds_put_format(string, "%sidle_age=%s%d, ",
                      colors.param, colors.end, fs->idle_age);
    }
    if (show_stats && fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
        ds_put_format(string, "%shard_age=%s%d, ",
                      colors.param, colors.end, fs->hard_age);
    }

    /* Print the match, followed by a space (but omit the space if the match
     * was an empty string). */
    size_t length = string->length;
    match_format(&fs->match, port_map, string, fs->priority);
    if (string->length != length) {
        ds_put_char(string, ' ');
    }

    ds_put_format(string, "%sactions=%s", colors.actions, colors.end);
    struct ofpact_format_params fp = {
        .port_map = port_map,
        .table_map = table_map,
        .s = string,
    };
    ofpacts_format(fs->ofpacts, fs->ofpacts_len, &fp);
} 

(四)修改ofputil_decode_flow_stats_reply获取字符串 

int
ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,  //对比ofputil_decode_flow_mod函数,是将ofputil_flow_mod转openflow
                                struct ofpbuf *msg,
                                bool flow_age_extension,
                                struct ofpbuf *ofpacts)
{
    const struct ofp_header *oh;
    size_t instructions_len;
    enum ofperr error;
    enum ofpraw raw;

    error = (msg->header ? ofpraw_decode(&raw, msg->header)
             : ofpraw_pull(&raw, msg));
    if (error) {
        return error;
    }
    oh = msg->header;

    if (!msg->size) {
        return EOF;
    } else if (raw == OFPRAW_OFPST15_FLOW_REPLY) {
        VLOG_INFO("------------ofputil_decode_flow_stats_reply------OFPRAW_OFPST15_FLOW_REPLY------");
        const struct ofp15_flow_desc *ofd;
        size_t length;
        uint16_t padded_match_len;
        uint16_t stat_len;
        uint8_t oxs_field_set;

        ofd = ofpbuf_try_pull(msg, sizeof *ofd);
        if (!ofd) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply has %" PRIu32
                         " leftover " "bytes at end", msg->size);
            return EINVAL;
        }

        length = ntohs(ofd->length);
        if (length < sizeof *ofd) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply claims invalid "
                         "length %" PRIuSIZE, length);
            return EINVAL;
        }

        if (ofputil_pull_ofp11_match(msg, NULL, NULL, &fs->match,
                                     &padded_match_len)) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply bad match");
            return EINVAL;
        }

        fs->priority = ntohs(ofd->priority);
        fs->table_id = ofd->table_id;
        fs->cookie = ofd->cookie;
        fs->idle_timeout = ntohs(ofd->idle_timeout);
        fs->hard_timeout = ntohs(ofd->hard_timeout);
        fs->importance = ntohs(ofd->importance);

        error = ofputil_decode_flow_mod_flags(ofd->flags, -1, oh->version,
                                                &fs->flags);
        if (error) {
            return error;
        }

        struct oxs_stats oxs;
        if (oxs_pull_stat(msg, &oxs, &stat_len, &oxs_field_set)) {
            VLOG_WARN_RL(&rl, "OXS OFPST_FLOW reply bad stats");
            return EINVAL;
        }
        fs->duration_sec = oxs.duration_sec;
        fs->duration_nsec = oxs.duration_nsec;
        fs->packet_count = oxs.packet_count;
        fs->byte_count = oxs.byte_count;
        fs->idle_age = oxs.idle_age == UINT32_MAX ? -1 : oxs.idle_age;
        fs->hard_age = -1;

        instructions_len = length - sizeof *ofd - padded_match_len - stat_len;
    } else if (raw == OFPRAW_OFPST11_FLOW_REPLY
               || raw == OFPRAW_OFPST13_FLOW_REPLY) {
        VLOG_INFO("------------ofputil_decode_flow_stats_reply------ofp11_flow_stats------");
        const struct ofp11_flow_stats *ofs;
        size_t length;
        uint16_t padded_match_len;

        ofs = ofpbuf_try_pull(msg, sizeof *ofs);
        if (!ofs) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply has %"PRIu32" leftover "
                         "bytes at end", msg->size);
            return OFPERR_OFPBRC_BAD_LEN;
        }

        length = ntohs(ofs->length);
        if (length < sizeof *ofs) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply claims invalid "
                         "length %"PRIuSIZE, length);
            return OFPERR_OFPBRC_BAD_LEN;
        }

        error = ofputil_pull_ofp11_match(msg, NULL, NULL, &fs->match,
                                         &padded_match_len);
        if (error) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply bad match");
            return error;
        }
        instructions_len = length - sizeof *ofs - padded_match_len;

        fs->priority = ntohs(ofs->priority);
        fs->table_id = ofs->table_id;
        fs->duration_sec = ntohl(ofs->duration_sec);
        fs->duration_nsec = ntohl(ofs->duration_nsec);
        fs->idle_timeout = ntohs(ofs->idle_timeout);
        fs->hard_timeout = ntohs(ofs->hard_timeout);

        fs->effect_sec = ntohll(ofs->effect_sec);    //处理------effect
        fs->effect_usec = ntohll(ofs->effect_usec);
        if (oh->version >= OFP14_VERSION) {
            fs->importance = ntohs(ofs->importance);
        } else {
            fs->importance = 0;
        }
        if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
            error = ofputil_decode_flow_mod_flags(ofs->flags, -1, oh->version,
                                                  &fs->flags);
            if (error) {
                return error;
            }
        } else {
            fs->flags = 0;
        }
        fs->idle_age = -1;
        fs->hard_age = -1;
        fs->cookie = ofs->cookie;
        fs->packet_count = ntohll(ofs->packet_count);
        fs->byte_count = ntohll(ofs->byte_count);
    } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
        const struct ofp10_flow_stats *ofs;
        size_t length;
        VLOG_INFO("------------ofputil_decode_flow_stats_reply------ofp10_flow_stats------");

        ofs = ofpbuf_try_pull(msg, sizeof *ofs);
        if (!ofs) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply has %"PRIu32" leftover "
                         "bytes at end", msg->size);
            return OFPERR_OFPBRC_BAD_LEN;
        }

        length = ntohs(ofs->length);
        if (length < sizeof *ofs) {
            VLOG_WARN_RL(&rl, "OFPST_FLOW reply claims invalid "
                         "length %"PRIuSIZE, length);
            return OFPERR_OFPBRC_BAD_LEN;
        }
        instructions_len = length - sizeof *ofs;

        fs->cookie = get_32aligned_be64(&ofs->cookie);
        ofputil_match_from_ofp10_match(&ofs->match, &fs->match);
        fs->priority = ntohs(ofs->priority);
        fs->table_id = ofs->table_id;
        fs->duration_sec = ntohl(ofs->duration_sec);
        fs->duration_nsec = ntohl(ofs->duration_nsec);
        fs->idle_timeout = ntohs(ofs->idle_timeout);
        fs->hard_timeout = ntohs(ofs->hard_timeout);
        fs->effect_sec = ntohll(ofs->effect_sec);    //处理------effect
        fs->effect_usec = ntohll(ofs->effect_usec);
        fs->importance = 0;
        fs->idle_age = -1;
        fs->hard_age = -1;
        fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count));
        fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
        fs->flags = 0;
    } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
        const struct nx_flow_stats *nfs;
        size_t match_len, length;
        VLOG_INFO("------------ofputil_decode_flow_stats_reply------nx_flow_stats------");

        nfs = ofpbuf_try_pull(msg, sizeof *nfs);
        if (!nfs) {
            VLOG_WARN_RL(&rl, "NXST_FLOW reply has %"PRIu32" leftover "
                         "bytes at end", msg->size);
            return OFPERR_OFPBRC_BAD_LEN;
        }

        length = ntohs(nfs->length);
        match_len = ntohs(nfs->match_len);
        if (length < sizeof *nfs + ROUND_UP(match_len, 8)) {
            VLOG_WARN_RL(&rl, "NXST_FLOW reply with match_len=%"PRIuSIZE" "
                         "claims invalid length %"PRIuSIZE, match_len, length);
            return OFPERR_OFPBRC_BAD_LEN;
        }
        error = nx_pull_match(msg, match_len, &fs->match, NULL, NULL, false,
                              NULL, NULL);
        if (error) {
            return error;
        }
        instructions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);

        fs->cookie = nfs->cookie;
        fs->table_id = nfs->table_id;
        fs->duration_sec = ntohl(nfs->duration_sec);
        fs->duration_nsec = ntohl(nfs->duration_nsec);
        fs->priority = ntohs(nfs->priority);
        fs->idle_timeout = ntohs(nfs->idle_timeout);
        fs->hard_timeout = ntohs(nfs->hard_timeout);
        fs->effect_sec = ntohl(nfs->effect_sec);    //处理------effect
        fs->effect_usec = ntohl(nfs->effect_usec);
        VLOG_INFO("-----tt----ofputil_decode_flow_stats_reply----%d %d------------",fs->effect_sec,fs->effect_usec);
        fs->importance = 0;
        fs->idle_age = -1;
        fs->hard_age = -1;
        if (flow_age_extension) {
            if (nfs->idle_age) {
                fs->idle_age = ntohs(nfs->idle_age) - 1;
            }
            if (nfs->hard_age) {
                fs->hard_age = ntohs(nfs->hard_age) - 1;
            }
        }
        fs->packet_count = ntohll(nfs->packet_count);
        fs->byte_count = ntohll(nfs->byte_count);
        fs->flags = 0;
    } else {
        OVS_NOT_REACHED();
    }

    error = ofpacts_pull_openflow_instructions(msg, instructions_len,
                                               oh->version, NULL, NULL,
                                               ofpacts);
    if (error) {
        VLOG_WARN_RL(&rl, "OFPST_FLOW reply bad instructions");
        return error;
    }
    fs->ofpacts = ofpacts->data;
    fs->ofpacts_len = ofpacts->size;

    return 0;
}

(五)修改ofputil_append_flow_stats_reply获取字符串

void
ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,    //----------对应ofputil_decode_flow_stats_reply函数,相反赋值
                                struct ovs_list *replies,
                                const struct tun_table *tun_table)
{
    struct ofputil_flow_stats *fs_ = CONST_CAST(struct ofputil_flow_stats *,
                                                fs);
    const struct tun_table *orig_tun_table;
    struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
    size_t start_ofs = reply->size;
    enum ofp_version version = ofpmp_version(replies);
    enum ofpraw raw = ofpmp_decode_raw(replies);

    orig_tun_table = fs->match.flow.tunnel.metadata.tab;
    fs_->match.flow.tunnel.metadata.tab = tun_table;
    VLOG_INFO("------------ofputil_append_flow_stats_reply-----start-----%d-----%d----",fs->effect_sec,fs->effect_usec);

    if (raw == OFPRAW_OFPST15_FLOW_REPLY) {
        VLOG_INFO("------------ofputil_append_flow_stats_reply-----OFPRAW_OFPST15_FLOW_REPLY----");
        struct ofp15_flow_desc *ofd;

        ofpbuf_put_uninit(reply, sizeof *ofd);
        oxm_put_match(reply, &fs->match, version);

        struct oxs_stats oxs = {
            .duration_sec = fs->duration_sec,
            .duration_nsec = fs->duration_nsec,
            .idle_age = fs->idle_age >= 0 ? fs->idle_age : UINT32_MAX,
            .packet_count = fs->packet_count,
            .byte_count = fs->byte_count,
            .flow_count = UINT32_MAX,
        };
        oxs_put_stats(reply, &oxs);

        ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
                                      version);

        ofd = ofpbuf_at_assert(reply, start_ofs, sizeof *ofd);
        ofd->length = htons(reply->size - start_ofs);
        ofd->table_id = fs->table_id;
        ofd->priority = htons(fs->priority);
        ofd->idle_timeout = htons(fs->idle_timeout);
        ofd->hard_timeout = htons(fs->hard_timeout);
        ofd->cookie = fs->cookie;
        memset(ofd->pad2, 0, sizeof ofd->pad2);
        ofd->pad = 0;
        ofd->importance = htons(fs->importance);
        ofd->flags = ofputil_encode_flow_mod_flags(fs->flags, version);
    } else if (raw == OFPRAW_OFPST11_FLOW_REPLY ||
               raw == OFPRAW_OFPST13_FLOW_REPLY) {  //处理------effect
        struct ofp11_flow_stats *ofs;
        VLOG_INFO("------------ofputil_append_flow_stats_reply-----OFPRAW_OFPST15_FLOW_REPLY----");

        ofpbuf_put_uninit(reply, sizeof *ofs);
        oxm_put_match(reply, &fs->match, version);
        ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
                                          version);

        ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
        ofs->length = htons(reply->size - start_ofs);
        ofs->table_id = fs->table_id;
        ofs->pad = 0;
        ofs->duration_sec = htonl(fs->duration_sec);
        ofs->duration_nsec = htonl(fs->duration_nsec);
        ofs->priority = htons(fs->priority);
        ofs->idle_timeout = htons(fs->idle_timeout);
        ofs->hard_timeout = htons(fs->hard_timeout);
        ofs->effect_sec = htonll(fs->effect_sec);    //处理------effect
        ofs->effect_usec = htonll(fs->effect_usec);
        if (version >= OFP14_VERSION) {
            ofs->importance = htons(fs->importance);
        } else {
            ofs->importance = 0;
        }
        if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
            ofs->flags = ofputil_encode_flow_mod_flags(fs->flags, version);
        } else {
            ofs->flags = 0;
        }
        memset(ofs->pad2, 0, sizeof ofs->pad2);
        ofs->cookie = fs->cookie;
        ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
        ofs->byte_count = htonll(unknown_to_zero(fs->byte_count));
    } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
        struct ofp10_flow_stats *ofs;
        VLOG_INFO("------------ofputil_append_flow_stats_reply-----OFPRAW_OFPST10_FLOW_REPLY----");

        ofpbuf_put_uninit(reply, sizeof *ofs);
        ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                     version);
        ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
        ofs->length = htons(reply->size - start_ofs);
        ofs->table_id = fs->table_id;
        ofs->pad = 0;
        ofputil_match_to_ofp10_match(&fs->match, &ofs->match);
        ofs->duration_sec = htonl(fs->duration_sec);
        ofs->duration_nsec = htonl(fs->duration_nsec);
        ofs->priority = htons(fs->priority);
        ofs->idle_timeout = htons(fs->idle_timeout);
        ofs->hard_timeout = htons(fs->hard_timeout);
        ofs->effect_sec = htonll(fs->effect_sec);
        ofs->effect_usec = htonll(fs->effect_usec);
        memset(ofs->pad2, 0, sizeof ofs->pad2);
        put_32aligned_be64(&ofs->cookie, fs->cookie);
        put_32aligned_be64(&ofs->packet_count,
                           htonll(unknown_to_zero(fs->packet_count)));
        put_32aligned_be64(&ofs->byte_count,
                           htonll(unknown_to_zero(fs->byte_count)));
    } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
        struct nx_flow_stats *nfs;
        int match_len;
        VLOG_INFO("------------ofputil_append_flow_stats_reply-----OFPRAW_NXST_FLOW_REPLY----");

        ofpbuf_put_uninit(reply, sizeof *nfs);
        match_len = nx_put_match(reply, &fs->match, 0, 0);
        ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                     version);
        nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
        nfs->length = htons(reply->size - start_ofs);
        nfs->table_id = fs->table_id;
        nfs->pad = 0;
        nfs->duration_sec = htonl(fs->duration_sec);
        nfs->duration_nsec = htonl(fs->duration_nsec);
        nfs->priority = htons(fs->priority);
        nfs->idle_timeout = htons(fs->idle_timeout);
        nfs->hard_timeout = htons(fs->hard_timeout);
        nfs->effect_sec = htonll(fs->effect_sec);
        nfs->effect_usec = htonll(fs->effect_usec);
        nfs->idle_age = htons(fs->idle_age < 0 ? 0
                              : fs->idle_age < UINT16_MAX ? fs->idle_age + 1
                              : UINT16_MAX);
        nfs->hard_age = htons(fs->hard_age < 0 ? 0
                              : fs->hard_age < UINT16_MAX ? fs->hard_age + 1
                              : UINT16_MAX);
        nfs->match_len = htons(match_len);
        nfs->cookie = fs->cookie;
        nfs->packet_count = htonll(fs->packet_count);
        nfs->byte_count = htonll(fs->byte_count);
    } else {
        VLOG_INFO("------------ofputil_append_flow_stats_reply-----OVS_NOT_REACHED----");
        OVS_NOT_REACHED();
    }

    ofpmp_postappend(replies, start_ofs);
    fs_->match.flow.tunnel.metadata.tab = orig_tun_table;
}

六:ovs-vswitchd的启动分析(见链接),是七的铺垫

其中run方法后面会用到的!!!

七:数据面处理来自控制面(由四转发而来)的openflow协议(重点

(一)调用流程

Ovs-vswitchd会监听socket,在ovs-vswitchd.c中

bridge_run --调用--> bridge_run__ --调用--> ofproto_run --调用--> connmgr_run(p->connmgr, handle_openflow); --调用--> ofconn_run(ofconn, handle_openflow) --调用--> handle_openflow(ofconn, &msgs);

当交换机有openflow调用的时候,handle_openflow会被调用去处理连接!!!!

handle_openflow--调用-->handle_flow_mod

分支(一):

--调用--> ofputil_decode_flow_mod解析各个版本的openflow协议到ofputil_flow_mod结构体中(包括基本字段、条件字段、action)

分支(二):调用分支一之后,所有信息都解析完成,存放在ofputil_flow_mod fm中,下面开始通过调用分支二下发到数据平面(datapath)

--调用--> handle_flow_mod__ --调用--> 

(1) ofproto_flow_mod_init将规则初始化赋值给了ofm中的temp_rule --调用--> add_flow_init --调用--> ofproto_rule_create创建并初始化规则 --回调--> rule_construct初始化struct rule_dpif(内部保护规则rule)

(2) ofproto_flow_mod_start --调用--> add_flow_start 开始添加流表项 --调用--> replace_rule_start 开始替换规则

(3) ofproto_flow_mod_finish --调用--> add_flow_finish --调用--> replace_rule_finish 替换规则完成

(4) ofmonitor_flush 通知底层内核更新流表项

(二)修改ofproto_rule_create创建并初始化规则,为规则添加我们自定义的字段 

1.handle_flow_mod__方法,保存后面需要的openflow_mod_requester请求数据到ofputil_flow_mod* fm中自定义字段中去

static enum ofperr
handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm,   //协议公共数据结构,前面handle_flow_mod方法就是为了获取他
                  const struct openflow_mod_requester *req)
    OVS_EXCLUDED(ofproto_mutex) //声明锁
{
    struct ofproto_flow_mod ofm;    //具有执行上下文的流模式
    enum ofperr error;

    error = ofproto_flow_mod_init(ofproto, &ofm, fm, NULL); //将规则赋值给了ofm中的temp_rules
    if (error) {
        return error;
    }

    ovs_mutex_lock(&ofproto_mutex);     //加锁----------加解锁中间才是重要的东西
    ofm.version = ofproto->tables_version + 1;
    ofm.omr = req;
    //将规则ofm中的temp_rules中,旧的放入old_rules;新的放入new_rules;中去
    error = ofproto_flow_mod_start(ofproto, &ofm);  //处理规则???----将规则加入ovs list
    if (!error) {
        VLOG_INFO("--------------------note ovs datapath----------start----");
        ofproto_bump_tables_version(ofproto);   //判断版本,不用管
        ofproto_flow_mod_finish(ofproto, &ofm, req);  //这里处理了
        //下面才是重點-----------
        ofmonitor_flush(ofproto->connmgr);  //ofproto->connmgr是OpenFlow交换机的连接管理器
        VLOG_INFO("--------------------note ovs datapath------------end--");
    }
    ovs_mutex_unlock(&ofproto_mutex);   //解锁

    return error;
}

1.add_flow_init方法,fm参数中已经在分支一中赋值了

static enum ofperr
add_flow_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
              const struct ofputil_flow_mod *fm)    //ofputil_flow_mod中还是包含了openflow协议的所有信息的
    OVS_EXCLUDED(ofproto_mutex)
{
    struct oftable *table;
    struct cls_rule cr;
    uint8_t table_id;
    enum ofperr error;

    if (!check_table_id(ofproto, fm->table_id)) {
        return OFPERR_OFPBRC_BAD_TABLE_ID;
    }

    /* Pick table. */
    //选择表id
    if (fm->table_id == 0xff) {
        if (ofproto->ofproto_class->rule_choose_table) {
            error = ofproto->ofproto_class->rule_choose_table(ofproto,
                                                              &fm->match,
                                                              &table_id);
            if (error) {
                return error;
            }
            ovs_assert(table_id < ofproto->n_tables);
        } else {
            table_id = 0;
        }
    } else if (fm->table_id < ofproto->n_tables) {
        table_id = fm->table_id;
    } else {
        return OFPERR_OFPBRC_BAD_TABLE_ID;
    }

    table = &ofproto->tables[table_id]; //------------选择对应的openflow表
    if (table->flags & OFTABLE_READONLY
        && !(fm->flags & OFPUTIL_FF_NO_READONLY)) { //只读表,不允许添加,返回错误
        return OFPERR_OFPBRC_EPERM;
    }

    if (!(fm->flags & OFPUTIL_FF_HIDDEN_FIELDS)
        && !minimatch_has_default_hidden_fields(&fm->match)) {
        VLOG_WARN_RL(&rl, "%s: (add_flow) only internal flows can set "
                     "non-default values to hidden fields", ofproto->name);
        return OFPERR_OFPBRC_EPERM;
    }

    if (!ofm->temp_rule) {  //如果上下文中没有临时规则(新添加),则下面进行初始化
        cls_rule_init_from_minimatch(&cr, &fm->match, fm->priority);    //初始化对象,增加match到rule中

        /* Allocate new rule.  Destroys 'cr'. */
        //分配新规则
        //返回指示“flow”中存在哪些隧道元数据字段的位图
        uint64_t map = miniflow_get_tun_metadata_present_map(fm->match.flow);
        error = ofproto_rule_create(ofproto, &cr, table - ofproto->tables,      //-----重点,将新规则结合到ofproto中去
                                    fm->new_cookie, fm->idle_timeout,           //回调rule_construct()初始化rule_dpif的参数
                                    fm->hard_timeout, fm->effect_sec,
                                    fm->effect_usec,fm->flags,
                                    fm->importance, fm->ofpacts,
                                    fm->ofpacts_len, map,
                                    fm->ofpacts_tlv_bitmap, &ofm->temp_rule);   //所有规则数据返回到&ofm->temp_rule中!!!-------重点!!!
        if (error) {
            return error;
        }

        get_conjunctions(fm, &ofm->conjs, &ofm->n_conjs);   //重點---------------?????
    }
    return 0;
}

2.ofproto_rule_create方法

static enum ofperr
ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr,
                    uint8_t table_id, ovs_be64 new_cookie,
                    uint16_t idle_timeout, uint16_t hard_timeout,
                    uint64_t effect_sec,uint64_t effect_usec,
                    enum ofputil_flow_mod_flags flags, uint16_t importance,
                    const struct ofpact *ofpacts, size_t ofpacts_len,
                    uint64_t match_tlv_bitmap, uint64_t ofpacts_tlv_bitmap,
                    struct rule **new_rule)
    OVS_NO_THREAD_SAFETY_ANALYSIS
{
    struct rule *rule;
    enum ofperr error;

    /* Allocate new rule. */
    rule = ofproto->ofproto_class->rule_alloc();    //回调函数rule_alloc()分配rule_dpif和rule对象 
    if (!rule) {
        cls_rule_destroy(cr);
        VLOG_WARN_RL(&rl, "%s: failed to allocate a rule.", ofproto->name);
        return OFPERR_OFPFMFC_UNKNOWN;
    }

    /* Initialize base state. */
    //接下来初始化rule对象中的相关参数……
    *CONST_CAST(struct ofproto **, &rule->ofproto) = ofproto;
    cls_rule_move(CONST_CAST(struct cls_rule *, &rule->cr), cr);
    ovs_refcount_init(&rule->ref_count);

    ovs_mutex_init(&rule->mutex);
    ovs_mutex_lock(&rule->mutex);
    *CONST_CAST(ovs_be64 *, &rule->flow_cookie) = new_cookie;
    rule->created = rule->modified = time_msec();
    rule->idle_timeout = idle_timeout;
    rule->hard_timeout = hard_timeout;
    rule->effect_sec = effect_sec;
    rule->effect_usec = effect_usec;
    *CONST_CAST(uint16_t *, &rule->importance) = importance;
    rule->removed_reason = OVS_OFPRR_NONE;

    *CONST_CAST(uint8_t *, &rule->table_id) = table_id;
    rule->flags = flags & OFPUTIL_FF_STATE;

    *CONST_CAST(const struct rule_actions **, &rule->actions)
        = rule_actions_create(ofpacts, ofpacts_len);
    //以上规则初始
    //下面处理ovs_list
    ovs_list_init(&rule->meter_list_node);
    rule->eviction_group = NULL;
    rule->monitor_flags = 0;
    rule->add_seqno = 0;
    rule->modify_seqno = 0;
    ovs_list_init(&rule->expirable);
    ovs_list_init(&rule->effectable);   //------修改effectable----------
    ovs_mutex_unlock(&rule->mutex);

    /* Construct rule, initializing derived state. */
    error = ofproto->ofproto_class->rule_construct(rule);   //回调rule_construct()初始化rule_dpif的参数
    if (error) {
        ofproto_rule_destroy__(rule);
        return error;
    }

    rule->state = RULE_INITIALIZED;
    rule->match_tlv_bitmap = match_tlv_bitmap;
    rule->ofpacts_tlv_bitmap = ofpacts_tlv_bitmap;
    mf_vl_mff_ref(&rule->ofproto->vl_mff_map, match_tlv_bitmap);
    mf_vl_mff_ref(&rule->ofproto->vl_mff_map, ofpacts_tlv_bitmap);

    *new_rule = rule;
    return 0;
}

其中的rule->effectable链中存放的是所有还没有生效的规则,会在后面run方法中遍历和检测,使之生效!!!

(三)修改replace_rule_start,开始替换规则

1.add_flow_start

/* ofm->temp_rule is consumed only in the successful case. */
//开始使用规则了!!!
static enum ofperr
add_flow_start(struct ofproto *ofproto, struct ofproto_flow_mod *ofm)
    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *old_rule = NULL;
    struct rule *new_rule = ofm->temp_rule; //------------使用
    const struct rule_actions *actions = rule_get_actions(new_rule);    //获取规则actions,返回一个rule_actions指针
    struct oftable *table = &ofproto->tables[new_rule->table_id];   //获取对应的table
    enum ofperr error;

    /* Must check actions while holding ofproto_mutex to avoid a race. */
    error = ofproto_check_ofpacts(ofproto, actions->ofpacts,    //检查锁,避免竞争
                                  actions->ofpacts_len);
    if (error) {
        return error;
    }

    /* Check for the existence of an identical rule.
     * This will not return rules earlier marked for removal. */
    //检查是否存在相同的规则(旧的)
    old_rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
                                                               &new_rule->cr,
                                                               ofm->version));
    if (!old_rule) {
        /* Check for overlap, if requested. 检查重叠*/ 
        if (new_rule->flags & OFPUTIL_FF_CHECK_OVERLAP
            && classifier_rule_overlaps(&table->cls, &new_rule->cr,
                                        ofm->version)) {
            return OFPERR_OFPFMFC_OVERLAP;
        }

        /* If necessary, evict an existing rule to clear out space. */
        //如果流表项太多,就删除表中的部分流表项
        if (table->n_flows >= table->max_flows) {
            if (!choose_rule_to_evict(table, &old_rule)) {
                return OFPERR_OFPFMFC_TABLE_FULL;
            }
            eviction_group_remove_rule(old_rule);
            /* Marks 'old_rule' as an evicted rule rather than replaced rule.
             */
            old_rule->removed_reason = OFPRR_EVICTION;
        }
    } else {
        ofm->modify_cookie = true;
    }

    if (old_rule) { //----------这里检测出来是否有旧的流表项了
        rule_collection_add(&ofm->old_rules, old_rule);
    }/* Take ownership of the temp_rule. */
    //将去重处理后的新new_rule放入ofm->new_rules,并且清空ofm->temp_rule-------------重点!!!!
    rule_collection_add(&ofm->new_rules, new_rule);
    ofm->temp_rule = NULL;
    //开始真正插入操作!!!-----重点---------------开始将规则
    /*
    replace_rule_start主要操作就是新的流表替换旧的流表的操作,如果存在旧流表,则调用ofproto_rule_remove__删除,
    然后调用ofproto_rule_insert__和classifier_insert添加流表。其中classifier_insert主要是将rule->cr添加到table->cls中
    */
    replace_rule_start(ofproto, ofm, old_rule, new_rule);
    return 0;
}

2.replace_rule_start 处理包含自定义字段的流表项,放入effectable链中,不直接插入datapath。

static void
replace_rule_start(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,   //---------插入cls
                   struct rule *old_rule, struct rule *new_rule)
{
    struct oftable *table = &ofproto->tables[new_rule->table_id];   //获取表
    /* 'old_rule' may be either an evicted rule or replaced rule. */
    //“旧规则”可以是逐出规则或替换规则。
    if (old_rule) {/* Copy values from old rule for modify semantics. */
        if (old_rule->removed_reason != OFPRR_EVICTION) {   //非驱逐--替换(用旧的替换新的部分信息)
            bool change_cookie = (ofm->modify_cookie
                                  && new_rule->flow_cookie != OVS_BE64_MAX
                                  && new_rule->flow_cookie != old_rule->flow_cookie);

            ovs_mutex_lock(&new_rule->mutex);
            ovs_mutex_lock(&old_rule->mutex);
            if (ofm->command != OFPFC_ADD) {
                new_rule->idle_timeout = old_rule->idle_timeout;
                new_rule->hard_timeout = old_rule->hard_timeout;
                *CONST_CAST(uint16_t *, &new_rule->importance) = old_rule->importance;
                new_rule->flags = old_rule->flags;
                new_rule->created = old_rule->created;
            }
            if (!change_cookie) {
                *CONST_CAST(ovs_be64 *, &new_rule->flow_cookie)
                    = old_rule->flow_cookie;
            }
            ovs_mutex_unlock(&old_rule->mutex);
            ovs_mutex_unlock(&new_rule->mutex);
        }

        /* Remove the old rule from data structures. */
        if(new_rule->effect_sec || new_rule->effect_usec){//把ofm中的old_rule剔除----------
          rule_collection_remove(&ofm->old_rules, old_rule);
        }else{/* Mark the old rule for removal in the next version. */
          //标记旧规则,以便后面删除
          cls_rule_make_invisible_in_version(&old_rule->cr, ofm->version);
          ofproto_rule_remove__(ofproto, old_rule); 
        }
    } else {
        table->n_flows++;
    }
    /* Insert flow to ofproto data structures, so that later flow_mods may
     * relate to it.  This is reversible, in case later errors require this to
     * be reverted. */
    //将流插入到原始数据结构中,以便以后的流与之相关。这是可逆的,以防以后的错误需要恢复。

    //先判断是否应该插入,effectable
    if(new_rule->effect_sec || new_rule->effect_usec){
      if(new_rule->state == RULE_EFFECTED || new_rule->state == RULE_INSERTED)
        return;

      struct ofproto_flow_mod* tofm = (struct ofproto_flow_mod*)xmalloc(sizeof(*ofm));  //用来一直存放
      memcpy(tofm,ofm,sizeof(*ofm));
      tofm->omr = (struct openflow_mod_requester*)xmalloc(sizeof(struct openflow_mod_requester));
      memcpy(tofm->omr,ofm->omr,sizeof(struct openflow_mod_requester));

      tofm->conjs = (struct cls_conjunction *)xmalloc(ofm->n_conjs*sizeof(struct cls_conjunction));
      memcpy(tofm->conjs,ofm->conjs,ofm->n_conjs*sizeof(struct cls_conjunction));
      rule_collection_add(&tofm->old_rules, old_rule);

      new_rule->ofm = tofm;

ofproto_rule_effect__(ofproto,new_rule); //进行插入操作 return; }
ofproto_rule_insert__(ofproto, new_rule); /* Make the new rule visible for classifier lookups only from the next * version. */ classifier_insert(&table->cls, &new_rule->cr, ofm->version, ofm->conjs, ofm->n_conjs); }

分析代码1:

    //先判断是否应该插入,effectable
    if(new_rule->effect_sec || new_rule->effect_usec){  //如果我们设置了自定义字段的值的话!!!,开始将这条规则通过ofproto_rule_effect__方法插入effectable链中,并且改变该规则的状态
      if(new_rule->state == RULE_EFFECTED || new_rule->state == RULE_INSERTED)  
        return;

      struct ofproto_flow_mod* tofm = (struct ofproto_flow_mod*)xmalloc(sizeof(*ofm));  //我们需要将ofproto_flow_mod ofm存放到规则中的自定义字段中,因为规则生效时,进行插入datapath过程中需要使用到这些数据
      memcpy(tofm,ofm,sizeof(*ofm));  //ofm在开始时是存放在栈中,不是堆中,生存周期没有办法达到我们需要的长度,所以我们变为堆中存放,并且把需要的数据拷贝过来
      tofm->omr = (struct openflow_mod_requester*)xmalloc(sizeof(struct openflow_mod_requester));  //把请求数据一块保存,后面插入也是需要这个数据的
      memcpy(tofm->omr,ofm->omr,sizeof(struct openflow_mod_requester));  //ofm->omr在handle_flow_mod__方法中被赋值了,所以我们这里可以直接获取openflow_mod_requester的数据

      tofm->conjs = (struct cls_conjunction *)xmalloc(ofm->n_conjs*sizeof(struct cls_conjunction));
      memcpy(tofm->conjs,ofm->conjs,ofm->n_conjs*sizeof(struct cls_conjunction));
      rule_collection_add(&tofm->old_rules, old_rule);  //把旧流表项添加到链中,当新的流表项生效时,再去把旧的流表项移除!!!!,注意我们后面分析的代码2

      new_rule->ofm = tofm;  

      ofproto_rule_effect__(ofproto,new_rule);    //调用自定义方法ofproto_rule_effect__进行插入操作,插入自定义的effectable链中去,并且修改流表规则的状态

      return;
    }

分析代码2:

        if(new_rule->effect_sec || new_rule->effect_usec){//把ofm中的old_rule剔除----------原本old_rule中是存在这个旧的规则,但是我们因为新规则还没有生效,所以不能把旧规则删除了,所以我们把这个规则先移除来,不被删除掉
          rule_collection_remove(&ofm->old_rules, old_rule);  //如果effect字段被使用了,我们后面会添加到effectable链中单独处理,对于当前正在运行的旧的流表项(相互冲突的),我们在新流表项生效之前,始终运行!!!,所以我们不能去移除他
        }else{  //对于没有使用自定义字段的规则,如果存在冲突的旧规则,则直接移除
          //标记旧规则,以便后面删除
          cls_rule_make_invisible_in_version(&old_rule->cr, ofm->version);
          ofproto_rule_remove__(ofproto, old_rule); 
        }

3.自定义方法ofproto_rule_effect__,添加规则到链表中去

static void
ofproto_rule_effect__(struct ofproto *ofproto, struct rule *rule)
    OVS_REQUIRES(ofproto_mutex)
{
    /* A rule may not be reinserted. */
    ovs_assert(rule->state != RULE_EFFECTED);   //生效系列操作

    if(rule->effect_sec || rule->effect_usec){
        VLOG_INFO("------!!!---------ofproto_rule_effect__-------effectable----start---%d-----%d",rule->ofm->version,rule->ofm->n_conjs);
        ovs_list_insert(&ofproto->effectable, &rule->effectable); //effectable入链
    }

    rule->state = RULE_EFFECTED;    //规则已经插入
}

(四)分析ofproto_flow_mod_finish方法(未修改)

1.add_flow_finish方法

static void
add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
                const struct openflow_mod_requester *req)
    OVS_REQUIRES(ofproto_mutex)
{struct rule *old_rule = rule_collection_n(&ofm->old_rules)
        ? rule_collection_rules(&ofm->old_rules)[0] : NULL;struct rule *new_rule = rule_collection_rules(&ofm->new_rules)[0];struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);//下面代替才是重点-----------------!!!
    replace_rule_finish(ofproto, ofm, req, old_rule, new_rule, &dead_cookies);
    learned_cookies_flush(ofproto, &dead_cookies);if (old_rule) {
        ovsrcu_postpone(remove_rule_rcu, old_rule);
    } else {
        ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
                         req ? req->ofconn : NULL,
                         req ? req->request->xid : 0, NULL);/* Send Vacancy Events for OF1.4+. */
        send_table_status(ofproto, new_rule->table_id);
    }
}

2.replace_rule_finish方法

/* Adds the 'new_rule', replacing the 'old_rule'. */
static void
replace_rule_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
                    const struct openflow_mod_requester *req,
                    struct rule *old_rule, struct rule *new_rule,
                    struct ovs_list *dead_cookies)
    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *replaced_rule;
    replaced_rule = (old_rule && old_rule->removed_reason != OFPRR_EVICTION)
        ? old_rule : NULL;

    ofproto->ofproto_class->rule_insert(new_rule, replaced_rule,    //流表变化标识设置
                                        ofm->modify_keep_counts);
    learned_cookies_inc(ofproto, rule_get_actions(new_rule));if (old_rule) {const struct rule_actions *old_actions = rule_get_actions(old_rule);
        const struct rule_actions *new_actions = rule_get_actions(new_rule);

        learned_cookies_dec(ofproto, old_actions, dead_cookies);if (replaced_rule) {
            enum nx_flow_update_event event = ofm->command == OFPFC_ADD
                ? NXFME_ADDED : NXFME_MODIFIED;

            bool changed_cookie = (new_rule->flow_cookie
                                   != old_rule->flow_cookie);

            bool changed_actions = !ofpacts_equal(new_actions->ofpacts,
                                                  new_actions->ofpacts_len,
                                                  old_actions->ofpacts,
                                                  old_actions->ofpacts_len);if (event != NXFME_MODIFIED || changed_actions
                || changed_cookie) {
                //-------------------填充ofconn->updates用于消息发送
                ofmonitor_report(ofproto->connmgr, new_rule, event, 0,
                                 req ? req->ofconn : NULL,
                                 req ? req->request->xid : 0,
                                 changed_actions ? old_actions : NULL);
            }
        } else {
            /* XXX: This is slight duplication with delete_flows_finish__() */
            ofmonitor_report(ofproto->connmgr, old_rule, NXFME_DELETED,
                             OFPRR_EVICTION,
                             req ? req->ofconn : NULL,
                             req ? req->request->xid : 0, NULL);
        }
    }
}

(五)修改run方法,位于main的while循环中,循环处理effectable流表链!!!

在文件openvswitch-2.11.4/ofproto/ofproto-dpif.c中:

1.修改run方法,处理达到生效时间的流表规则,使之生效

#include <time.h>

static
int run(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); uint64_t new_seq, new_dump_seq; struct timeval tv; //---------------获取当前时间--------------- if (mbridge_need_revalidate(ofproto->mbridge)) { ofproto->backer->need_revalidate = REV_RECONFIGURE; ovs_rwlock_wrlock(&ofproto->ml->rwlock); mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); mcast_snooping_mdb_flush(ofproto->ms); } /* Always updates the ofproto->ams_seqno to avoid frequent wakeup during * flow restore. Even though nothing is processed during flow restore, * all queued 'ams' will be handled immediately when flow restore * completes. */ ofproto->ams_seqno = seq_read(ofproto->ams_seq); /* Do not perform any periodic activity required by 'ofproto' while * waiting for flow restore to complete. */ if (!ofproto_get_flow_restore_wait()) { struct ofproto_async_msg *am; struct ovs_list ams; guarded_list_pop_all(&ofproto->ams, &ams); LIST_FOR_EACH_POP (am, list_node, &ams) { connmgr_send_async_msg(ofproto->up.connmgr, am); ofproto_async_msg_free(am); } } if (ofproto->netflow) { netflow_run(ofproto->netflow); } if (ofproto->sflow) { dpif_sflow_run(ofproto->sflow); } if (ofproto->ipfix) { dpif_ipfix_run (ofproto->ipfix); } new_seq = seq_read(connectivity_seq_get()); if (ofproto->change_seq != new_seq) { struct ofport_dpif *ofport; HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) { port_run(ofport); } ofproto->change_seq = new_seq; } if (ofproto->lacp_enabled || ofproto->has_bonded_bundles) { struct ofbundle *bundle; HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { bundle_run(bundle); } } stp_run(ofproto); rstp_run(ofproto); ovs_rwlock_wrlock(&ofproto->ml->rwlock); if (mac_learning_run(ofproto->ml)) { ofproto->backer->need_revalidate = REV_MAC_LEARNING; } ovs_rwlock_unlock(&ofproto->ml->rwlock); if (mcast_snooping_run(ofproto->ms)) { ofproto->backer->need_revalidate = REV_MCAST_SNOOPING; } new_dump_seq = seq_read(udpif_dump_seq(ofproto->backer->udpif)); if (ofproto->dump_seq != new_dump_seq) { struct rule *rule, *next_rule; ovs_mutex_lock(&ofproto_mutex); LIST_FOR_EACH_SAFE (rule, next_rule, effectable, &ofproto->up.effectable) { //对于小于effect生效时间的,不进行处理 if(rule->effect_sec!=0 || rule->effect_usec!=0){ gettimeofday(&tv, NULL); //获取当前时间 if(!((tv.tv_sec < rule->effect_sec)||(tv.tv_sec == rule->effect_sec && tv.tv_usec < rule->effect_usec))){ //先对比秒,当前时刻小于生效时间,则return VLOG_INFO("-----------run--local_time--%d--%d->>>>>>-effect_time--%d--%d--",tv.tv_sec,tv.tv_usec,rule->effect_sec,rule->effect_usec); rule->effect_sec = 0; //归0 rule->effect_usec = 0; replace_rule_effect(&ofproto->up,rule); //进行插入 ------- 没有主动去调用handle_flow_mod函数,导致更新不及时!!!,不能进行处理 ovs_list_remove(&rule->effectable); //出链操作 } } } ovs_mutex_unlock(&ofproto_mutex); } if (ofproto->dump_seq != new_dump_seq) {  //这里是用来遍历expirable链表,用来检测hard_timeout和idle_timeout是否到期的;effectable链就是模仿他实现的 struct rule *rule, *next_rule; long long now = time_msec(); /* We know stats are relatively fresh, so now is a good time to do some * periodic work. */ ofproto->dump_seq = new_dump_seq; /* Expire OpenFlow flows whose idle_timeout or hard_timeout * has passed. */ /* #define LIST_FOR_EACH_SAFE(ITER, NEXT, MEMBER, LIST) \ for (INIT_CONTAINER(ITER, (LIST)->next, MEMBER); \ (&(ITER)->MEMBER != (LIST) \ ? INIT_CONTAINER(NEXT, (ITER)->MEMBER.next, MEMBER), 1 \ : 0); \ (ITER) = (NEXT)) */ ovs_mutex_lock(&ofproto_mutex); LIST_FOR_EACH_SAFE (rule, next_rule, expirable, &ofproto->up.expirable) { rule_expire(rule_dpif_cast(rule), now); //-------这里校验是否超时 } ovs_mutex_unlock(&ofproto_mutex); /* All outstanding data in existing flows has been accounted, so it's a * good time to do bond rebalancing. */ if (ofproto->has_bonded_bundles) { struct ofbundle *bundle; HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { if (bundle->bond) { bond_rebalance(bundle->bond); } } } } return 0; }

代码分析1:

    if (ofproto->dump_seq != new_dump_seq) {
        struct rule *rule, *next_rule;

        ovs_mutex_lock(&ofproto_mutex);
        LIST_FOR_EACH_SAFE (rule, next_rule, effectable,
                            &ofproto->up.effectable) {  //遍历交换机的effectable链表
            //对于小于effect生效时间的,不进行处理
            if(rule->effect_sec!=0 || rule->effect_usec!=0){  //其实这里的规则的effect_sec或者effect_usec都是有值的
                gettimeofday(&tv, NULL);    //获取当前时间

                if(!((tv.tv_sec < rule->effect_sec)||(tv.tv_sec == rule->effect_sec && tv.tv_usec < rule->effect_usec))){ //先对比秒和微秒,当前时刻大于生效时间,则当前流表项可以开始工作了,可以插入交换机进行生效处理!!!
                    rule->effect_sec = 0;   //归0,对于处理后的我们把值置为0,其实这里也可以不置为0,置为0之后后面不会在dump-flows中显示设置的生效时间了
                    rule->effect_usec = 0;
                    
                    replace_rule_effect(&ofproto->up,rule); //调用自定义replace_rule_effect方法进行插入,在内部主动去调用ofmonitor_flush函数,使得datapath及时更新!!!否則的话,可能更新不及时,不能进行按照新的流表项处理   
                    ovs_list_remove(&rule->effectable); //出链操作,后面就不会再重复处理了!!!
                }
            }
        }
        ovs_mutex_unlock(&ofproto_mutex);
    }

2.调用自定义方法replace_rule_effect,使得流表添加,并且被datapath及时处理(下面全部添加)

void replace_rule_effect(struct ofproto *ofproto,struct rule *new_rule){
    ovs_assert(new_rule->state != RULE_INSERTED);  //判断是否生效---是否是没有添加过的流表项const struct rule_actions *actions = rule_get_actions(new_rule);    //获取规则actions,返回一个rule_actions指针  rule结构体中有action
    struct oftable *table = &ofproto->tables[new_rule->table_id];   //获取表
    struct ofproto_flow_mod* ofm = new_rule->ofm;  //获取对应规则的ofproto_flow_mod数据
    struct rule* old_rule = NULL;
    enum ofperr error;

    /* Check for the existence of an identical rule.
     * This will not return rules earlier marked for removal. */
    //检查是否存在相同的规则(旧的)

    /* Must check actions while holding ofproto_mutex to avoid a race. */
    error = ofproto_check_ofpacts(ofproto, actions->ofpacts,    //检查锁,避免竞争-----------------出错!!!!
                                  actions->ofpacts_len);
    if (error) {return ;
    }
    old_rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,  //去流表中查找旧的规则(于新规则有冲突的表项)
                                                               &new_rule->cr,
                                                               ofm->version));
    if (!old_rule) {/* Check for overlap, if requested. 检查重叠*/ 
        if (new_rule->flags & OFPUTIL_FF_CHECK_OVERLAP
            && classifier_rule_overlaps(&table->cls, &new_rule->cr,
                                        ofm->version)) {return ;
        }

        /* If necessary, evict an existing rule to clear out space. */
        //如果流表项太多,就删除表中的部分流表项
        if (table->n_flows >= table->max_flows) {
            if (!choose_rule_to_evict(table, &old_rule)) {return ;
            }
            eviction_group_remove_rule(old_rule);
            /* Marks 'old_rule' as an evicted rule rather than replaced rule.
             */
            old_rule->removed_reason = OFPRR_EVICTION;
        }
    } else {
        ofm->modify_cookie = true;
    }

    if (old_rule) {  //如果存在旧规则,就放入ofm的old_rules链中
        rule_collection_add(&ofm->old_rules, old_rule);
    }
    /* Take ownership of the temp_rule. */
    //将去重处理后的新new_rule放入ofm->new_rules,并且清空ofm->temp_rule-------------重点!!!!//开始真正插入操作!!!-----重点---------------开始将规则
    //“旧规则”可以是逐出规则或替换规则。
    if (old_rule) {  //开始删除旧的规则/* Copy values from old rule for modify semantics. */
        if (old_rule->removed_reason != OFPRR_EVICTION) {   //非驱逐--替换(用旧的替换新的部分信息)
            bool change_cookie = (ofm->modify_cookie
                                  && new_rule->flow_cookie != OVS_BE64_MAX
                                  && new_rule->flow_cookie != old_rule->flow_cookie);

            ovs_mutex_lock(&new_rule->mutex);
            ovs_mutex_lock(&old_rule->mutex);
            if (ofm->command != OFPFC_ADD) {
                new_rule->idle_timeout = old_rule->idle_timeout;
                new_rule->hard_timeout = old_rule->hard_timeout;
                *CONST_CAST(uint16_t *, &new_rule->importance) = old_rule->importance;
                new_rule->flags = old_rule->flags;
                new_rule->created = old_rule->created;
            }
            if (!change_cookie) {*CONST_CAST(ovs_be64 *, &new_rule->flow_cookie)
                    = old_rule->flow_cookie;
            }
            ovs_mutex_unlock(&old_rule->mutex);
            ovs_mutex_unlock(&new_rule->mutex);
        }/* Mark the old rule for removal in the next version. */
        //标记旧规则,以便后面删除
        cls_rule_make_invisible_in_version(&old_rule->cr, ofm->version);/* Remove the old rule from data structures. */
        ofproto_rule_remove__(ofproto, old_rule);  //移除旧的规则!!!!
    } else {
        table->n_flows++;
    }

    ofproto_rule_insert__(ofproto, new_rule);  //插入新的规则(就是我们设置的生效时间下的流表项)
    /* Make the new rule visible for classifier lookups only from the next
     * version. */
    classifier_insert(&table->cls, &new_rule->cr, new_rule->ofm->version, new_rule->ofm->conjs,
                      new_rule->ofm->n_conjs);

    new_rule->state = RULE_INSERTED;  //修改规则状态为已安装状态!!!//-----------更新完成之后进行通知-
    ofproto_bump_tables_version(ofproto);   //判断版本,不用管//ofproto_flow_mod_finish(ofproto, new_rule->ofm, new_rule->ofm->omr);  //------------------這裏開始出錯!-------------------::::注釋之後可以正常開始了:::::://下面才是重點
    ofmonitor_flush(ofproto->connmgr);  //ofproto->connmgr是OpenFlow交换机的连接管理器-------------通知内核,及时修改流表
}

目前第一个较为稳定的版本已经实现完成!!!

对于修改源码后,编译程序的方法见:

openvswitch2.11.0修改源码后重新编译(2)

 

posted @ 2022-05-04 22:42  山上有风景  阅读(947)  评论(0编辑  收藏  举报