diff --git a/ofproto/in-band.c b/ofproto/in-band.c index 9605b50f3..aebdb7e4b 100644 --- a/ofproto/in-band.c +++ b/ofproto/in-band.c @@ -235,6 +235,7 @@ struct in_band_remote { struct in_band { struct ofproto *ofproto; struct status_category *ss_cat; + int queue_id, prev_queue_id; /* Remote information. */ time_t next_remote_refresh; /* Refresh timer. */ @@ -585,13 +586,31 @@ drop_rules(struct in_band *ib) static void add_rule(struct in_band *ib, const struct cls_rule *rule) { - union ofp_action action; + struct { + struct nx_action_set_queue nxsq; + struct ofp_action_output oao; + } actions; - action.type = htons(OFPAT_OUTPUT); - action.output.len = htons(sizeof action); - action.output.port = htons(OFPP_NORMAL); - action.output.max_len = htons(0); - ofproto_add_flow(ib->ofproto, rule, &action, 1); + memset(&actions, 0, sizeof actions); + + actions.oao.type = htons(OFPAT_OUTPUT); + actions.oao.len = htons(sizeof actions.oao); + actions.oao.port = htons(OFPP_NORMAL); + actions.oao.max_len = htons(0); + + if (ib->queue_id < 0) { + ofproto_add_flow(ib->ofproto, rule, + (union ofp_action *) &actions.oao, 1); + } else { + actions.nxsq.type = htons(OFPAT_VENDOR); + actions.nxsq.len = htons(sizeof actions.nxsq); + actions.nxsq.vendor = htonl(NX_VENDOR_ID); + actions.nxsq.subtype = htons(NXAST_SET_QUEUE); + actions.nxsq.queue_id = htonl(ib->queue_id); + + ofproto_add_flow(ib->ofproto, rule, (union ofp_action *) &actions, + sizeof actions / sizeof(union ofp_action)); + } } /* Inserts flows into the flow table for the current state of 'ib'. */ @@ -626,15 +645,17 @@ compare_macs(const void *a, const void *b) void in_band_run(struct in_band *ib) { + bool local_change, remote_change, queue_id_change; struct in_band_remote *r; - bool local_change, remote_change; local_change = refresh_local(ib); remote_change = refresh_remotes(ib); - if (!local_change && !remote_change) { + queue_id_change = ib->queue_id != ib->prev_queue_id; + if (!local_change && !remote_change && !queue_id_change) { /* Nothing changed, nothing to do. */ return; } + ib->prev_queue_id = ib->queue_id; /* Drop old rules. */ drop_rules(ib); @@ -708,6 +729,7 @@ in_band_create(struct ofproto *ofproto, struct dpif *dpif, in_band->ofproto = ofproto; in_band->ss_cat = switch_status_register(ss, "in-band", in_band_status_cb, in_band); + in_band->queue_id = in_band->prev_queue_id = -1; in_band->next_remote_refresh = TIME_MIN; in_band->next_local_refresh = TIME_MIN; in_band->local_netdev = local_netdev; @@ -778,3 +800,13 @@ in_band_set_remotes(struct in_band *ib, /* Force refresh in next call to in_band_run(). */ ib->next_remote_refresh = TIME_MIN; } + +/* Sets the OpenFlow queue used by flows set up by 'ib' to 'queue_id'. If + * 'queue_id' is negative, 'ib' will not set any queue (which is also the + * default). */ +void +in_band_set_queue(struct in_band *ib, int queue_id) +{ + ib->queue_id = queue_id; +} + diff --git a/ofproto/in-band.h b/ofproto/in-band.h index 27a5fe51d..23a30cedb 100644 --- a/ofproto/in-band.h +++ b/ofproto/in-band.h @@ -31,6 +31,7 @@ int in_band_create(struct ofproto *, struct dpif *, struct switch_status *, struct in_band **); void in_band_destroy(struct in_band *); +void in_band_set_queue(struct in_band *, int queue_id); void in_band_set_remotes(struct in_band *, const struct sockaddr_in *, size_t n); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 4e49cb63c..897429f84 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -305,6 +305,7 @@ struct ofproto { long long int next_in_band_update; struct sockaddr_in *extra_in_band_remotes; size_t n_extra_remotes; + int in_band_queue; /* Flow table. */ struct classifier cls; @@ -405,11 +406,14 @@ ofproto_create(const char *datapath, const char *datapath_type, /* Initialize submodules. */ p->switch_status = switch_status_create(p); - p->in_band = NULL; p->fail_open = NULL; p->netflow = NULL; p->sflow = NULL; + /* Initialize in-band control. */ + p->in_band = NULL; + p->in_band_queue = -1; + /* Initialize flow table. */ classifier_init(&p->cls); p->next_expiration = time_msec() + 1000; @@ -600,6 +604,7 @@ update_in_band_remotes(struct ofproto *ofproto) if (ofproto->in_band) { in_band_set_remotes(ofproto->in_band, addrs, n_addrs); } + in_band_set_queue(ofproto->in_band, ofproto->in_band_queue); ofproto->next_in_band_update = time_msec() + 1000; } else { in_band_destroy(ofproto->in_band); @@ -776,6 +781,18 @@ ofproto_set_extra_in_band_remotes(struct ofproto *ofproto, update_in_band_remotes(ofproto); } +/* Sets the OpenFlow queue used by flows set up by in-band control on + * 'ofproto' to 'queue_id'. If 'queue_id' is negative, then in-band control + * flows will use the default queue. */ +void +ofproto_set_in_band_queue(struct ofproto *ofproto, int queue_id) +{ + if (queue_id != ofproto->in_band_queue) { + ofproto->in_band_queue = queue_id; + update_in_band_remotes(ofproto); + } +} + void ofproto_set_desc(struct ofproto *p, const char *mfr_desc, const char *hw_desc, diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index a3cc82556..fd089c5ef 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -106,6 +106,7 @@ void ofproto_set_fail_mode(struct ofproto *, enum ofproto_fail_mode fail_mode); void ofproto_reconnect_controllers(struct ofproto *); void ofproto_set_extra_in_band_remotes(struct ofproto *, const struct sockaddr_in *, size_t n); +void ofproto_set_in_band_queue(struct ofproto *, int queue_id); void ofproto_set_desc(struct ofproto *, const char *mfr_desc, const char *hw_desc, const char *sw_desc, const char *serial_desc, diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 9ddafe1ef..ff9ddfdf5 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1724,23 +1724,29 @@ bridge_reconfigure_remotes(struct bridge *br, const struct sockaddr_in *managers, size_t n_managers) { + const char *disable_ib_str, *queue_id_str; + bool disable_in_band = false; + int queue_id; + struct ovsrec_controller **controllers; size_t n_controllers; bool had_primary; - const char *disable_ib_str; - bool disable_in_band = false; struct ofproto_controller *ocs; size_t n_ocs; size_t i; - /* Check if we should disable in-band control on this bridge. */ disable_ib_str = bridge_get_other_config(br->cfg, "disable-in-band"); if (disable_ib_str && !strcmp(disable_ib_str, "true")) { disable_in_band = true; } + /* Set OpenFlow queue ID for in-band control. */ + queue_id_str = bridge_get_other_config(br->cfg, "in-band-queue"); + queue_id = queue_id_str ? strtol(queue_id_str, NULL, 10) : -1; + ofproto_set_in_band_queue(br->ofproto, queue_id); + if (disable_in_band) { ofproto_set_extra_in_band_remotes(br->ofproto, NULL, 0); } else { diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 2edb35e0d..7cfba180c 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -369,6 +369,14 @@ xx:xx:xx:xx:xx:xx to set the hardware address of the local port and influence the datapath ID. +
in-band-queue