Is there any documentation for the ovs side geneve negotiation? Also one question below:
Thanks, Alex Wang, On Sun, Jul 19, 2015 at 3:45 PM, Ben Pfaff <b...@nicira.com> wrote: > This won't really get used until the next commit. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > ovn/controller/ofctrl.c | 470 > ++++++++++++++++++++++++++++------------ > ovn/controller/ofctrl.h | 5 +- > ovn/controller/ovn-controller.c | 6 +- > ovn/controller/physical.h | 7 + > 4 files changed, 348 insertions(+), 140 deletions(-) > > diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c > index b1c421c..d8a0573 100644 > --- a/ovn/controller/ofctrl.c > +++ b/ovn/controller/ofctrl.c > @@ -27,9 +27,10 @@ > #include "openflow/openflow.h" > #include "openvswitch/vlog.h" > #include "ovn-controller.h" > -#include "vswitch-idl.h" > +#include "physical.h" > #include "rconn.h" > #include "socket-util.h" > +#include "vswitch-idl.h" > > VLOG_DEFINE_THIS_MODULE(ofctrl); > > @@ -53,6 +54,9 @@ static char *ovn_flow_to_string(const struct ovn_flow *); > static void ovn_flow_log(const struct ovn_flow *, const char *action); > static void ovn_flow_destroy(struct ovn_flow *); > > +static ovs_be32 queue_msg(struct ofpbuf *); > +static void queue_flow_mod(struct ofputil_flow_mod *); > + > /* OpenFlow connection to the switch. */ > static struct rconn *swconn; > > @@ -60,6 +64,25 @@ static struct rconn *swconn; > * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */ > static unsigned int seqno; > > +/* Connection state machine. */ > +#define STATES \ > + STATE(S_NEW) \ > + STATE(S_GENEVE_TABLE_REQUESTED) \ > + STATE(S_GENEVE_TABLE_MOD_SENT) \ > + STATE(S_CLEAR_FLOWS) \ > + STATE(S_UPDATE_FLOWS) > +enum ofctrl_state { > +#define STATE(NAME) NAME, > + STATES > +#undef STATE > +}; > + > +/* Current state. */ > +static enum ofctrl_state state; > + > +/* Transaction IDs for messages in flight to the switch. */ > +static ovs_be32 xid, xid2; > + > /* Counter for in-flight OpenFlow messages on 'swconn'. We only send a > new > * round of flow table modifications to the switch when the counter falls > to > * zero, to avoid unbounded buffering. */ > @@ -69,11 +92,15 @@ static struct rconn_packet_counter *tx_counter; > * installed in the switch. */ > static struct hmap installed_flows; > > +/* MFF_* field ID for our Geneve option. In S_GENEVE_TABLE_MOD_SENT, > this is > + * the option we requested (we don't know whether we obtained it yet). In > + * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */ > +static enum mf_field_id mff_ovn_geneve; > + > static void ovn_flow_table_clear(struct hmap *flow_table); > static void ovn_flow_table_destroy(struct hmap *flow_table); > > -static void ofctrl_update_flows(struct hmap *desired_flows); > -static void ofctrl_recv(const struct ofpbuf *msg); > +static void ofctrl_recv(const struct ofp_header *, enum ofptype); > > void > ofctrl_init(void) > @@ -82,15 +109,244 @@ ofctrl_init(void) > tx_counter = rconn_packet_counter_create(); > hmap_init(&installed_flows); > } > + > +/* S_NEW, for a new connection. > + * > + * Sends NXT_GENEVE_TABLE_REQUEST and transitions to > + * S_GENEVE_TABLE_REQUESTED. */ > > -/* Attempts to update the OpenFlow flows in bridge 'br_int' to those in > - * 'flow_table'. Removes all of the flows from 'flow_table' and frees > them. > +static void > +run_S_NEW(void) > +{ > + struct ofpbuf *buf = ofpraw_alloc(OFPRAW_NXT_GENEVE_TABLE_REQUEST, > + rconn_get_version(swconn), 0); > + xid = queue_msg(buf); > + state = S_GENEVE_TABLE_REQUESTED; > +} > + > +static void > +recv_S_NEW(const struct ofp_header *oh OVS_UNUSED, > + enum ofptype type OVS_UNUSED) > +{ > + OVS_NOT_REACHED(); > +} > + > +/* S_GENEVE_TABLE_REQUESTED, when NXT_GENEVE_TABLE_REQUEST has been sent > + * and we're waiting for a reply. > * > - * The flow table will only be updated if we've got an OpenFlow > connection to > - * 'br_int' and it's not backlogged. Otherwise, it'll have to wait until > the > - * next iteration. */ > -void > -ofctrl_run(const struct ovsrec_bridge *br_int, struct hmap *flow_table) > + * If we receive an NXT_GENEVE_TABLE_REPLY: > + * > + * - If it contains our tunnel metadata option, assign its field ID to > + * mff_ovn_geneve and transition to S_CLEAR_FLOWS. > + * > + * - Otherwise, if there is an unused tunnel metadata field ID, send > + * NXT_GENEVE_TABLE_MOD and OFPT_BARRIER_REQUEST, and transition to > + * S_GENEVE_TABLE_MOD_SENT. > + * > + * - Otherwise, log an error, disable Geneve, and transition to > + * S_CLEAR_FLOWS. > + * > + * If we receive an OFPT_ERROR: > + * > + * - Log an error, disable Geneve, and transition to S_CLEAR_FLOWS. */ > + > +static void > +run_S_GENEVE_TABLE_REQUESTED(void) > +{ > +} > + > +static void > +recv_S_GENEVE_TABLE_REQUESTED(const struct ofp_header *oh, enum ofptype > type) > +{ > + if (oh->xid != xid) { > + ofctrl_recv(oh, type); > + } else if (type == OFPTYPE_NXT_GENEVE_TABLE_REPLY) { > + struct ofputil_geneve_table_reply reply; > + enum ofperr error = ofputil_decode_geneve_table_reply(oh, &reply); > + if (error) { > + VLOG_ERR("failed to decode Geneve table request (%s)", > + ofperr_to_string(error)); > + goto error; > + } > + > + const struct ofputil_geneve_map *map; > + uint64_t md_free = UINT64_MAX; > + BUILD_ASSERT(TUN_METADATA_NUM_OPTS == 64); > + > + LIST_FOR_EACH (map, list_node, &reply.mappings) { > + if (map->option_class == OVN_GENEVE_CLASS > + && map->option_type == OVN_GENEVE_TYPE > + && map->option_len == OVN_GENEVE_LEN) { > + if (map->index >= TUN_METADATA_NUM_OPTS) { > + VLOG_ERR("desired Geneve tunnel option 0x%"PRIx16"," > + "%"PRIu8",%"PRIu8" already in use with " > + "unsupported index %"PRIu16, > + map->option_class, map->option_type, > + map->option_len, map->index); > + goto error; > + } else { > + mff_ovn_geneve = MFF_TUN_METADATA0 + map->index; > + state = S_CLEAR_FLOWS; > + return; > + } > + } > + > + if (map->index < TUN_METADATA_NUM_OPTS) { > + md_free &= ~(UINT64_C(1) << map->index); > + } > + } > + > + VLOG_DBG("OVN Geneve option not found"); > + if (!md_free) { > + VLOG_ERR("no Geneve options free for use by OVN"); > + goto error; > + } > + > + unsigned int index = rightmost_1bit_idx(md_free); > + mff_ovn_geneve = MFF_TUN_METADATA0 + index; > + struct ofputil_geneve_map gm; > + gm.option_class = OVN_GENEVE_CLASS; > + gm.option_type = OVN_GENEVE_TYPE; > + gm.option_len = OVN_GENEVE_LEN; > + gm.index = index; > + > + struct ofputil_geneve_table_mod gtm; > + gtm.command = NXGTMC_ADD; > + list_init(>m.mappings); > + list_push_back(>m.mappings, &gm.list_node); > + > + xid = queue_msg(ofputil_encode_geneve_table_mod(OFP13_VERSION, > >m)); > + xid2 = queue_msg(ofputil_encode_barrier_request(OFP13_VERSION)); > + state = S_GENEVE_TABLE_MOD_SENT; > + } else if (type == OFPTYPE_ERROR) { > + VLOG_ERR("switch refused to allocate Geneve option (%s)", > + ofperr_to_string(ofperr_decode_msg(oh, NULL))); > + goto error; > + } else { > + char *s = ofp_to_string(oh, ntohs(oh->length), 1); > + VLOG_ERR("unexpected reply to Geneve table request (%s)", > + s); > + free(s); > + goto error; > + } > + return; > + > +error: > + mff_ovn_geneve = 0; > + state = S_CLEAR_FLOWS; > +} > + > +/* S_GENEVE_TABLE_MOD_SENT, when NXT_GENEVE_TABLE_MOD and > OFPT_BARRIER_REQUEST > + * have been sent and we're waiting for a reply to one or the other. > + * > + * If we receive an OFPT_ERROR: > + * > + * - If the error is NXGTMFC_ALREADY_MAPPED or NXGTMFC_DUP_ENTRY, we > + * raced with some other controller. Transition to S_NEW. > + * > + * - Otherwise, log an error, disable Geneve, and transition to > + * S_CLEAR_FLOWS. > + * > + * If we receive OFPT_BARRIER_REPLY: > + * > + * - Set the tunnel metadata field ID to the one that we requested. > + * Transition to S_CLEAR_FLOWS. > + */ > + > +static void > +run_S_GENEVE_TABLE_MOD_SENT(void) > +{ > +} > + > +static void > +recv_S_GENEVE_TABLE_MOD_SENT(const struct ofp_header *oh, enum ofptype > type) > +{ > + if (oh->xid != xid && oh->xid != xid2) { > + ofctrl_recv(oh, type); > + } else if (oh->xid == xid2 && type == OFPTYPE_BARRIER_REPLY) { > + state = S_CLEAR_FLOWS; > + } else if (oh->xid == xid && type == OFPTYPE_ERROR) { > + enum ofperr error = ofperr_decode_msg(oh, NULL); > + if (error == OFPERR_NXGTMFC_ALREADY_MAPPED || > + error == OFPERR_NXGTMFC_DUP_ENTRY) { > + VLOG_INFO("raced with another controller adding " > + "Geneve option (%s); trying again", > + ofperr_to_string(error)); > + state = S_NEW; > + } else { > + VLOG_ERR("error adding Geneve option (%s)", > + ofperr_to_string(error)); > + goto error; > + } > + } else { > + char *s = ofp_to_string(oh, ntohs(oh->length), 1); > + VLOG_ERR("unexpected reply to Geneve option allocation request > (%s)", > + s); > + free(s); > + goto error; > + } > + return; > + > +error: > + state = S_CLEAR_FLOWS; > +} > + > +/* S_CLEAR_FLOWS, after we've established a Geneve metadata field ID and > it's > + * time to set up some flows. > + * > + * Sends an OFPT_TABLE_MOD to clear all flows, then transitions to > + * S_UPDATE_FLOWS. */ > + > +static void > +run_S_CLEAR_FLOWS(void) > +{ > + /* Send a flow_mod to delete all flows. */ > + struct ofputil_flow_mod fm = { > + .match = MATCH_CATCHALL_INITIALIZER, > + .table_id = OFPTT_ALL, > + .command = OFPFC_DELETE, > + }; > + queue_flow_mod(&fm); > + VLOG_DBG("clearing all flows"); > + > + /* Clear installed_flows, to match the state of the switch. */ > + ovn_flow_table_clear(&installed_flows); > + > + state = S_UPDATE_FLOWS; > +} > + > +static void > +recv_S_CLEAR_FLOWS(const struct ofp_header *oh, enum ofptype type) > +{ > + ofctrl_recv(oh, type); > +} > + > +/* S_UPDATE_FLOWS, for maintaining the flow table over time. > + * > + * Compare the installed flows to the ones we want. Send OFPT_FLOW_MOD as > + * necessary. > + * > + * This is a terminal state. We only transition out of it if the > connection > + * drops. */ > + > +static void > +run_S_UPDATE_FLOWS(void) > +{ > +} > + > + > +static void > +recv_S_UPDATE_FLOWS(const struct ofp_header *oh, enum ofptype type) > +{ > + ofctrl_recv(oh, type); > +} > + > +/* Runs the OpenFlow state machine against 'br_int', which is local to the > + * hypervisor on which we are running. Attempts to negotiate a Geneve > option > + * field for class OVN_GENEVE_CLASS, type OVN_GENEVE_TYPE. If successful, > + * returns the MFF_* field ID for the option, otherwise returns 0. */ > +enum mf_field_id > +ofctrl_run(const struct ovsrec_bridge *br_int) > { > if (br_int) { > char *target; > @@ -107,24 +363,56 @@ ofctrl_run(const struct ovsrec_bridge *br_int, > struct hmap *flow_table) > rconn_run(swconn); > > if (!rconn_is_connected(swconn)) { > - goto exit; > + return 0; > } > - if (!rconn_packet_counter_n_packets(tx_counter)) { > - ofctrl_update_flows(flow_table); > + if (seqno != rconn_get_connection_seqno(swconn)) { > + seqno = rconn_get_connection_seqno(swconn); > + state = S_NEW; > } > > - for (int i = 0; i < 50; i++) { > + enum ofctrl_state old_state; > + do { > + old_state = state; > + switch (state) { > +#define STATE(NAME) case NAME: run_##NAME(); break; > + STATES > +#undef STATE > + default: > + OVS_NOT_REACHED(); > + } > + } while (state != old_state); > + > + for (int i = 0; state == old_state && i < 50; i++) { > struct ofpbuf *msg = rconn_recv(swconn); > if (!msg) { > break; > } > > - ofctrl_recv(msg); > + const struct ofp_header *oh = msg->data; > + enum ofptype type; > + enum ofperr error; > + > + error = ofptype_decode(&type, oh); > + if (!error) { > + switch (state) { > +#define STATE(NAME) case NAME: recv_##NAME(oh, type); break; > + STATES > +#undef STATE > + default: > + OVS_NOT_REACHED(); > + } > + } else { > + char *s = ofp_to_string(oh, ntohs(oh->length), 1); > + VLOG_WARN("could not decode OpenFlow message (%s): %s", > + ofperr_to_string(error), s); > + free(s); > + } > + > ofpbuf_delete(msg); > } > > -exit: > - ovn_flow_table_clear(flow_table); > + return (state == S_CLEAR_FLOWS || state == S_UPDATE_FLOWS > + ? mff_ovn_geneve : 0); > } > > void > @@ -142,109 +430,28 @@ ofctrl_destroy(void) > rconn_packet_counter_destroy(tx_counter); > } > > -static void > +static ovs_be32 > queue_msg(struct ofpbuf *msg) > { > + const struct ofp_header *oh = msg->data; > + ovs_be32 xid = oh->xid; > rconn_send(swconn, msg, tx_counter); > + return xid; > } > > static void > -ofctrl_recv(const struct ofpbuf *msg) > +ofctrl_recv(const struct ofp_header *oh, enum ofptype type) > { > - enum ofptype type; > - struct ofpbuf b; > - > - b = *msg; > - if (ofptype_pull(&type, &b)) { > - return; > - } > - > - switch (type) { > - case OFPTYPE_ECHO_REQUEST: > - queue_msg(make_echo_reply(msg->data)); > - break; > - > - case OFPTYPE_ECHO_REPLY: > - case OFPTYPE_PACKET_IN: > - case OFPTYPE_PORT_STATUS: > - case OFPTYPE_FLOW_REMOVED: > - /* Nothing to do. */ > - break; > - > - case OFPTYPE_HELLO: > - case OFPTYPE_ERROR: > - case OFPTYPE_FEATURES_REQUEST: > - case OFPTYPE_FEATURES_REPLY: > - case OFPTYPE_GET_CONFIG_REQUEST: > - case OFPTYPE_GET_CONFIG_REPLY: > - case OFPTYPE_SET_CONFIG: > - case OFPTYPE_PACKET_OUT: > - case OFPTYPE_FLOW_MOD: > - case OFPTYPE_GROUP_MOD: > - case OFPTYPE_PORT_MOD: > - case OFPTYPE_TABLE_MOD: > - case OFPTYPE_BARRIER_REQUEST: > - case OFPTYPE_BARRIER_REPLY: > - case OFPTYPE_QUEUE_GET_CONFIG_REQUEST: > - case OFPTYPE_QUEUE_GET_CONFIG_REPLY: > - case OFPTYPE_DESC_STATS_REQUEST: > - case OFPTYPE_DESC_STATS_REPLY: > - case OFPTYPE_FLOW_STATS_REQUEST: > - case OFPTYPE_FLOW_STATS_REPLY: > - case OFPTYPE_AGGREGATE_STATS_REQUEST: > - case OFPTYPE_AGGREGATE_STATS_REPLY: > - case OFPTYPE_TABLE_STATS_REQUEST: > - case OFPTYPE_TABLE_STATS_REPLY: > - case OFPTYPE_PORT_STATS_REQUEST: > - case OFPTYPE_PORT_STATS_REPLY: > - case OFPTYPE_QUEUE_STATS_REQUEST: > - case OFPTYPE_QUEUE_STATS_REPLY: > - case OFPTYPE_PORT_DESC_STATS_REQUEST: > - case OFPTYPE_PORT_DESC_STATS_REPLY: > - case OFPTYPE_ROLE_REQUEST: > - case OFPTYPE_ROLE_REPLY: > - case OFPTYPE_ROLE_STATUS: > - case OFPTYPE_SET_FLOW_FORMAT: > - case OFPTYPE_FLOW_MOD_TABLE_ID: > - case OFPTYPE_SET_PACKET_IN_FORMAT: > - case OFPTYPE_FLOW_AGE: > - case OFPTYPE_SET_CONTROLLER_ID: > - case OFPTYPE_FLOW_MONITOR_STATS_REQUEST: > - case OFPTYPE_FLOW_MONITOR_STATS_REPLY: > - case OFPTYPE_FLOW_MONITOR_CANCEL: > - case OFPTYPE_FLOW_MONITOR_PAUSED: > - case OFPTYPE_FLOW_MONITOR_RESUMED: > - case OFPTYPE_GET_ASYNC_REQUEST: > - case OFPTYPE_GET_ASYNC_REPLY: > - case OFPTYPE_SET_ASYNC_CONFIG: > - case OFPTYPE_METER_MOD: > - case OFPTYPE_GROUP_STATS_REQUEST: > - case OFPTYPE_GROUP_STATS_REPLY: > - case OFPTYPE_GROUP_DESC_STATS_REQUEST: > - case OFPTYPE_GROUP_DESC_STATS_REPLY: > - case OFPTYPE_GROUP_FEATURES_STATS_REQUEST: > - case OFPTYPE_GROUP_FEATURES_STATS_REPLY: > - case OFPTYPE_METER_STATS_REQUEST: > - case OFPTYPE_METER_STATS_REPLY: > - case OFPTYPE_METER_CONFIG_STATS_REQUEST: > - case OFPTYPE_METER_CONFIG_STATS_REPLY: > - case OFPTYPE_METER_FEATURES_STATS_REQUEST: > - case OFPTYPE_METER_FEATURES_STATS_REPLY: > - case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: > - case OFPTYPE_TABLE_FEATURES_STATS_REPLY: > - case OFPTYPE_TABLE_DESC_REQUEST: > - case OFPTYPE_TABLE_DESC_REPLY: > - case OFPTYPE_BUNDLE_CONTROL: > - case OFPTYPE_BUNDLE_ADD_MESSAGE: > - case OFPTYPE_NXT_GENEVE_TABLE_MOD: > - case OFPTYPE_NXT_GENEVE_TABLE_REQUEST: > - case OFPTYPE_NXT_GENEVE_TABLE_REPLY: > - default: > - /* Messages that are generally unexpected. */ > + if (type == OFPTYPE_ECHO_REQUEST) { > + queue_msg(make_echo_reply(oh)); > + } else if (type != OFPTYPE_ECHO_REPLY && > + type != OFPTYPE_PACKET_IN && > + type != OFPTYPE_PORT_STATUS && > + type != OFPTYPE_FLOW_REMOVED) { > if (VLOG_IS_DBG_ENABLED()) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, > 300); > > - char *s = ofp_to_string(msg->data, msg->size, 2); > + char *s = ofp_to_string(oh, ntohs(oh->length), 2); > VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s); > free(s); > } > @@ -272,6 +479,7 @@ ofctrl_add_flow(struct hmap *desired_flows, > f->match = *match; > f->ofpacts = xmemdup(actions->data, actions->size); > f->ofpacts_len = actions->size; > + f->hmap_node.hash = ovn_flow_hash(f); > > if (ovn_flow_lookup(desired_flows, f)) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); > @@ -285,7 +493,7 @@ ofctrl_add_flow(struct hmap *desired_flows, > return; > } > > - hmap_insert(desired_flows, &f->hmap_node, ovn_flow_hash(f)); > + hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash); > } > > /* ovn_flow. */ > @@ -359,6 +567,7 @@ ovn_flow_table_clear(struct hmap *flow_table) > ovn_flow_destroy(f); > } > } > + > static void > ovn_flow_table_destroy(struct hmap *flow_table) > { > @@ -377,26 +586,13 @@ queue_flow_mod(struct ofputil_flow_mod *fm) > queue_msg(ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM)); > } > > -static void > -ofctrl_update_flows(struct hmap *desired_flows) > +void > +ofctrl_put(struct hmap *flow_table) > { > - /* If we've (re)connected, don't make any assumptions about the flows > in > - * the switch: delete all of them. (We'll immediately repopulate it > - * below.) */ > - if (seqno != rconn_get_connection_seqno(swconn)) { > - seqno = rconn_get_connection_seqno(swconn); > - > - /* Send a flow_mod to delete all flows. */ > - struct ofputil_flow_mod fm = { > - .match = MATCH_CATCHALL_INITIALIZER, > - .table_id = OFPTT_ALL, > - .command = OFPFC_DELETE, > - }; > - queue_flow_mod(&fm); > - VLOG_DBG("clearing all flows"); > - > - /* Clear installed_flows, to match the state of the switch. */ > - ovn_flow_table_clear(&installed_flows); > + if (state != S_UPDATE_FLOWS > + || rconn_packet_counter_n_packets(tx_counter)) { > + ovn_flow_table_clear(flow_table); > + return; > } > > Should we use maybe a boolean to mark this case, so that ofctrl_wait could register a wake up event for re-updating the flows? Wonder if there could be a delayed flow update issue~ > /* Iterate through all of the installed flows. If any of them are no > @@ -404,7 +600,7 @@ ofctrl_update_flows(struct hmap *desired_flows) > * actions, update them. */ > struct ovn_flow *i, *next; > HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) { > - struct ovn_flow *d = ovn_flow_lookup(desired_flows, i); > + struct ovn_flow *d = ovn_flow_lookup(flow_table, i); > if (!d) { > /* Installed flow is no longer desirable. Delete it from the > * switch and from installed_flows. */ > @@ -442,16 +638,16 @@ ofctrl_update_flows(struct hmap *desired_flows) > d->ofpacts_len = 0; > } > > - hmap_remove(desired_flows, &d->hmap_node); > + hmap_remove(flow_table, &d->hmap_node); > ovn_flow_destroy(d); > } > } > > - /* The previous loop removed from 'desired_flows' all of the flows > that are > - * already installed. Thus, any flows remaining in 'desired_flows' > need to > + /* The previous loop removed from 'flow_table' all of the flows that > are > + * already installed. Thus, any flows remaining in 'flow_table' need > to > * be added to the flow table. */ > struct ovn_flow *d; > - HMAP_FOR_EACH_SAFE (d, next, hmap_node, desired_flows) { > + HMAP_FOR_EACH_SAFE (d, next, hmap_node, flow_table) { > /* Send flow_mod to add flow. */ > struct ofputil_flow_mod fm = { > .match = d->match, > @@ -464,8 +660,8 @@ ofctrl_update_flows(struct hmap *desired_flows) > queue_flow_mod(&fm); > ovn_flow_log(d, "adding"); > > - /* Move 'd' from 'desired_flows' to installed_flows. */ > - hmap_remove(desired_flows, &d->hmap_node); > + /* Move 'd' from 'flow_table' to installed_flows. */ > + hmap_remove(flow_table, &d->hmap_node); > hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash); > } > } > diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h > index fc07d51..b43527a 100644 > --- a/ovn/controller/ofctrl.h > +++ b/ovn/controller/ofctrl.h > @@ -19,6 +19,8 @@ > > #include <stdint.h> > > +#include "meta-flow.h" > + > struct controller_ctx; > struct hmap; > struct match; > @@ -27,7 +29,8 @@ struct ovsrec_bridge; > > /* Interface for OVN main loop. */ > void ofctrl_init(void); > -void ofctrl_run(const struct ovsrec_bridge *br_int, struct hmap > *flow_table); > +enum mf_field_id ofctrl_run(const struct ovsrec_bridge *br_int); > +void ofctrl_put(struct hmap *flows); > void ofctrl_wait(void); > void ofctrl_destroy(void); > > diff --git a/ovn/controller/ovn-controller.c > b/ovn/controller/ovn-controller.c > index 9d20245..488dce7 100644 > --- a/ovn/controller/ovn-controller.c > +++ b/ovn/controller/ovn-controller.c > @@ -265,12 +265,14 @@ main(int argc, char *argv[]) > } > > if (br_int) { > + enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int); > + > struct hmap flow_table = HMAP_INITIALIZER(&flow_table); > rule_run(&ctx, &flow_table); > - if (chassis_id) { > physical_run(&ctx, br_int, chassis_id, &flow_table); > + if (chassis_id && mff_ovn_geneve) { > } > - ofctrl_run(br_int, &flow_table); > + ofctrl_put(&flow_table); > hmap_destroy(&flow_table); > } > > diff --git a/ovn/controller/physical.h b/ovn/controller/physical.h > index 9de76de..82baa2f 100644 > --- a/ovn/controller/physical.h > +++ b/ovn/controller/physical.h > @@ -29,6 +29,13 @@ struct hmap; > struct ovsdb_idl; > struct ovsrec_bridge; > > +/* OVN Geneve option information. > + * > + * Keep these in sync with the documentation in ovn-architecture(7). */ > +#define OVN_GENEVE_CLASS 0xffff > +#define OVN_GENEVE_TYPE 0 > +#define OVN_GENEVE_LEN 4 > + > void physical_register_ovs_idl(struct ovsdb_idl *); > void physical_run(struct controller_ctx *, const struct ovsrec_bridge > *br_int, > const char *chassis_id, > -- > 2.1.3 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev