X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Flearning-switch.c;h=23d26e7bfc18ee117d0961d8bc5d7a8b58c86a89;hb=4530afbaf4e5fbf8f9b3e2832fb9c89f618225e5;hp=435acb96c24bca013b70b616809d49786db4b025;hpb=80d5aefd65b9dd953d873f9995b949bc8b8d19d5;p=sliver-openvswitch.git diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 435acb96c..23d26e7bf 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -77,8 +77,8 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300); static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *); static void send_features_request(struct lswitch *, struct rconn *); -static void process_switch_features(struct lswitch *, - struct ofp_switch_features *); +static enum ofperr process_switch_features(struct lswitch *, + struct ofp_switch_features *); static void process_packet_in(struct lswitch *, struct rconn *, const struct ofp_packet_in *); static void process_echo_request(struct lswitch *, struct rconn *, @@ -139,18 +139,46 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg) send_features_request(sw, rconn); if (cfg->default_flows) { - const struct ofpbuf *b; - - LIST_FOR_EACH (b, list_node, cfg->default_flows) { - struct ofpbuf *copy = ofpbuf_clone(b); - int error = rconn_send(rconn, copy, NULL); - if (error) { - VLOG_INFO_RL(&rl, "%s: failed to queue default flows (%s)", - rconn_get_name(rconn), strerror(error)); - ofpbuf_delete(copy); - break; + enum ofputil_protocol usable_protocols; + enum ofputil_protocol protocol; + struct ofpbuf *msg = NULL; + int ofp_version; + int error = 0; + size_t i; + + /* Figure out the initial protocol on the connection. */ + ofp_version = rconn_get_version(rconn); + protocol = ofputil_protocol_from_ofp_version(ofp_version); + + /* If the initial protocol isn't good enough for default_flows, then + * pick one that will work and encode messages to set up that + * protocol. + * + * This could be improved by actually negotiating a mutually acceptable + * flow format with the switch, but that would require an asynchronous + * state machine. This version ought to work fine in practice. */ + usable_protocols = ofputil_flow_mod_usable_protocols( + cfg->default_flows, cfg->n_default_flows); + if (!(protocol & usable_protocols)) { + enum ofputil_protocol want = rightmost_1bit(usable_protocols); + while (!error) { + msg = ofputil_encode_set_protocol(protocol, want, &protocol); + if (!msg) { + break; + } + error = rconn_send(rconn, msg, NULL); } } + + for (i = 0; !error && i < cfg->n_default_flows; i++) { + msg = ofputil_encode_flow_mod(&cfg->default_flows[i], protocol); + error = rconn_send(rconn, msg, NULL); + } + + if (error) { + VLOG_INFO_RL(&rl, "%s: failed to queue default flows (%s)", + rconn_get_name(rconn), strerror(error)); + } } return sw; @@ -266,6 +294,7 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn, case OFPUTIL_NXT_FLOW_REMOVED: case OFPUTIL_NXT_FLOW_AGE: case OFPUTIL_NXT_SET_ASYNC_CONFIG: + case OFPUTIL_NXT_SET_CONTROLLER_ID: case OFPUTIL_NXST_FLOW_REQUEST: case OFPUTIL_NXST_AGGREGATE_REQUEST: case OFPUTIL_NXST_FLOW_REPLY: @@ -317,27 +346,32 @@ queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *b) } } -static void +static enum ofperr process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf) { - size_t n_ports; - size_t i; - - sw->datapath_id = ntohll(osf->datapath_id); + struct ofputil_switch_features features; + struct ofputil_phy_port port; + enum ofperr error; + struct ofpbuf b; + + error = ofputil_decode_switch_features(osf, &features, &b); + if (error) { + VLOG_ERR("received invalid switch feature reply (%s)", + ofperr_to_string(error)); + return error; + } - n_ports = (ntohs(osf->header.length) - sizeof *osf) / sizeof *osf->ports; - for (i = 0; i < n_ports; i++) { - struct ofp_phy_port *opp = &osf->ports[i]; - struct lswitch_port *lp; + sw->datapath_id = features.datapath_id; - opp->name[OFP_MAX_PORT_NAME_LEN - 1] = '\0'; - lp = shash_find_data(&sw->queue_names, opp->name); + while (!ofputil_pull_switch_features_port(&b, &port)) { + struct lswitch_port *lp = shash_find_data(&sw->queue_names, port.name); if (lp && hmap_node_is_null(&lp->hmap_node)) { - lp->port_no = ntohs(opp->port_no); + lp->port_no = port.port_no; hmap_insert(&sw->queue_numbers, &lp->hmap_node, hash_int(lp->port_no, 0)); } } + return 0; } static uint16_t @@ -441,7 +475,7 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, struct ofp_action_output oao; memset(&oao, 0, sizeof oao); - oao.type = htons(OFPAT_OUTPUT); + oao.type = htons(OFPAT10_OUTPUT); oao.len = htons(sizeof oao); oao.port = htons(out_port); @@ -451,7 +485,7 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, struct ofp_action_enqueue oae; memset(&oae, 0, sizeof oae); - oae.type = htons(OFPAT_ENQUEUE); + oae.type = htons(OFPAT10_ENQUEUE); oae.len = htons(sizeof oae); oae.port = htons(out_port); oae.queue_id = htonl(queue_id);