Пример #1
0
/* Decodes the NXT_FLOW_MOD_TABLE_ID message at 'oh'.  Returns the message's
 * argument, that is, whether the flow_mod_table_id feature should be
 * enabled. */
bool
ofputil_decode_nx_flow_mod_table_id(const struct ofp_header *oh)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_FLOW_MOD_TABLE_ID);
    uint8_t *enable = ofpbuf_pull(&b, 8);
    return *enable != 0;
}
Пример #2
0
enum ofperr
ofputil_decode_bundle_add(const struct ofp_header *oh,
                          struct ofputil_bundle_add_msg *msg,
                          enum ofptype *typep)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));

    /* Pull the outer ofp_header. */
    enum ofpraw raw = ofpraw_pull_assert(&b);
    ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE
               || raw == OFPRAW_ONFT13_BUNDLE_ADD_MESSAGE);

    /* Pull the bundle_ctrl header. */
    const struct ofp14_bundle_ctrl_msg *m = ofpbuf_pull(&b, sizeof *m);
    msg->bundle_id = ntohl(m->bundle_id);
    msg->flags = ntohs(m->flags);

    /* Pull the inner ofp_header. */
    if (b.size < sizeof(struct ofp_header)) {
        return OFPERR_OFPBFC_MSG_BAD_LEN;
    }
    msg->msg = b.data;
    if (msg->msg->version != oh->version) {
        return OFPERR_OFPBFC_BAD_VERSION;
    }
    size_t inner_len = ntohs(msg->msg->length);
    if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) {
        return OFPERR_OFPBFC_MSG_BAD_LEN;
    }
    if (msg->msg->xid != oh->xid) {
        return OFPERR_OFPBFC_MSG_BAD_XID;
    }

    /* Reject unbundlable messages. */
    enum ofptype type;
    enum ofperr error = ofptype_decode(&type, msg->msg);
    if (error) {
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
        VLOG_WARN_RL(&rl, "OFPT14_BUNDLE_ADD_MESSAGE contained "
                     "message is unparsable (%s)", ofperr_get_name(error));
        return OFPERR_OFPBFC_MSG_UNSUP; /* 'error' would be confusing. */
    }

    if (!ofputil_is_bundlable(type)) {
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
        VLOG_WARN_RL(&rl, "%s message not allowed inside "
                     "OFPT14_BUNDLE_ADD_MESSAGE", ofptype_get_name(type));
        return OFPERR_OFPBFC_MSG_UNSUP;
    }
    if (typep) {
        *typep = type;
    }

    return 0;
}
Пример #3
0
static int
ofputil_pull_queue_get_config_reply14(struct ofpbuf *msg,
                                      struct ofputil_queue_config *queue)
{
    struct ofp14_queue_desc *oqd14 = ofpbuf_try_pull(msg, sizeof *oqd14);
    if (!oqd14) {
        return OFPERR_OFPBRC_BAD_LEN;
    }
    enum ofperr error = ofputil_port_from_ofp11(oqd14->port_no, &queue->port);
    if (error) {
        return error;
    }
    queue->queue = ntohl(oqd14->queue_id);

    /* Length check. */
    unsigned int len = ntohs(oqd14->len);
    if (len < sizeof *oqd14 || len > msg->size + sizeof *oqd14 || len % 8) {
        return OFPERR_OFPBRC_BAD_LEN;
    }
    len -= sizeof *oqd14;

    struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
                                                        len);
    while (properties.size > 0) {
        struct ofpbuf payload;
        uint64_t type;

        error = ofpprop_pull(&properties, &payload, &type);
        if (error) {
            return error;
        }

        switch (type) {
        case OFPQDPT14_MIN_RATE:
            error = ofpprop_parse_u16(&payload, &queue->min_rate);
            break;

        case OFPQDPT14_MAX_RATE:
            error = ofpprop_parse_u16(&payload, &queue->max_rate);
            break;

        default:
            error = OFPPROP_UNKNOWN(true, "queue desc", type);
            break;
        }

        if (error) {
            return error;
        }
    }

    return 0;
}
Пример #4
0
/* Tries to decode 'oh', which should be an OpenFlow OFPT_ERROR message.
 * Returns an OFPERR_* constant on success, 0 on failure.
 *
 * If 'payload' is nonnull, on success '*payload' is initialized with a copy of
 * the error's payload (copying is required because the payload is not properly
 * aligned).  The caller must free the payload (with ofpbuf_uninit()) when it
 * is no longer needed.  On failure, '*payload' is cleared. */
enum ofperr
ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload)
{
    const struct ofp_error_msg *oem;
    enum ofpraw raw;
    uint16_t type, code;
    uint32_t vendor;

    if (payload) {
        memset(payload, 0, sizeof *payload);
    }

    /* Pull off the error message. */
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    enum ofperr error = ofpraw_pull(&raw, &b);
    if (error) {
        return 0;
    }
    oem = ofpbuf_pull(&b, sizeof *oem);

    /* Get the error type and code. */
    vendor = 0;
    type = ntohs(oem->type);
    code = ntohs(oem->code);
    if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
        const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve);
        if (!nve) {
            return 0;
        }

        vendor = ntohl(nve->vendor);
        type = ntohs(nve->type);
        code = ntohs(nve->code);
    } else if (type == OFPET12_EXPERIMENTER) {
        const ovs_be32 *vendorp = ofpbuf_try_pull(&b, sizeof *vendorp);
        if (!vendorp) {
            return 0;
        }

        vendor = ntohl(*vendorp);
        type = code;
        code = 0;
    }

    /* Translate the error type and code into an ofperr. */
    error = ofperr_decode(oh->version, vendor, type, code);
    if (error && payload) {
        ofpbuf_init(payload, b.size);
        ofpbuf_push(payload, b.data, b.size);
    }
    return error;
}
Пример #5
0
/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
 * message 'oh'. */
size_t
ofputil_count_queue_stats(const struct ofp_header *oh)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    ofpraw_pull_assert(&b);

    for (size_t n = 0; ; n++) {
        struct ofputil_queue_stats qs;
        if (ofputil_decode_queue_stats(&qs, &b)) {
            return n;
        }
    }
}
Пример #6
0
enum ofperr
ofputil_queue_get_config_reply_format(struct ds *string,
                                      const struct ofp_header *oh,
                                      const struct ofputil_port_map *port_map)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));

    struct ofputil_queue_config *queues = NULL;
    size_t allocated_queues = 0;
    size_t n = 0;

    int retval = 0;
    for (;;) {
        if (n >= allocated_queues) {
            queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
        }
        retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
        if (retval) {
            break;
        }
        n++;
    }

    qsort(queues, n, sizeof *queues, compare_queues);

    ds_put_char(string, ' ');

    ofp_port_t port = 0;
    for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
        if (q->port != port) {
            port = q->port;

            ds_put_cstr(string, "port=");
            ofputil_format_port(port, port_map, string);
            ds_put_char(string, '\n');
        }

        ds_put_format(string, "queue %"PRIu32":", q->queue);
        print_queue_rate(string, "min_rate", q->min_rate);
        print_queue_rate(string, "max_rate", q->max_rate);
        ds_put_char(string, '\n');
    }

    ds_chomp(string, ' ');
    free(queues);

    return retval != EOF ? retval : 0;
}
Пример #7
0
enum ofperr
ofputil_decode_bundle_ctrl(const struct ofp_header *oh,
                           struct ofputil_bundle_ctrl_msg *msg)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    enum ofpraw raw = ofpraw_pull_assert(&b);
    ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_CONTROL
               || raw == OFPRAW_ONFT13_BUNDLE_CONTROL);

    const struct ofp14_bundle_ctrl_msg *m = b.msg;
    msg->bundle_id = ntohl(m->bundle_id);
    msg->type = ntohs(m->type);
    msg->flags = ntohs(m->flags);

    return 0;
}
Пример #8
0
static enum ofperr
process_switch_features(struct lswitch *sw, struct ofp_header *oh)
{
    struct ofputil_switch_features features;

    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    enum ofperr error = ofputil_pull_switch_features(&b, &features);
    if (error) {
        VLOG_ERR("received invalid switch feature reply (%s)",
                 ofperr_to_string(error));
        return error;
    }

    sw->datapath_id = features.datapath_id;

    return 0;
}
Пример #9
0
enum ofperr
ofputil_queue_stats_reply_format(struct ds *string,
                                 const struct ofp_header *oh,
                                 const struct ofputil_port_map *port_map,
                                 int verbosity)
{
    ds_put_format(string, " %"PRIuSIZE" queues\n",
                  ofputil_count_queue_stats(oh));
    if (verbosity < 1) {
        return 0;
    }

    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    for (;;) {
        struct ofputil_queue_stats qs;
        int retval;

        retval = ofputil_decode_queue_stats(&qs, &b);
        if (retval) {
            return retval != EOF ? retval : 0;
        }

        ds_put_cstr(string, "  port ");
        ofputil_format_port(qs.port_no, port_map, string);
        ds_put_cstr(string, " queue ");
        ofp_print_queue_name(string, qs.queue_id);
        ds_put_cstr(string, ": ");

        print_queue_stat(string, "bytes=", qs.tx_bytes, 1);
        print_queue_stat(string, "pkts=", qs.tx_packets, 1);
        print_queue_stat(string, "errors=", qs.tx_errors, 1);

        ds_put_cstr(string, "duration=");
        if (qs.duration_sec != UINT32_MAX) {
            ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
        } else {
            ds_put_char(string, '?');
        }
        ds_put_char(string, '\n');
    }
}
Пример #10
0
/* Returns the protocol specified in the NXT_SET_FLOW_FORMAT message at 'oh'
 * (either OFPUTIL_P_OF10_STD or OFPUTIL_P_OF10_NXM) or 0 if the message is
 * invalid. */
enum ofputil_protocol
ofputil_decode_nx_set_flow_format(const struct ofp_header *oh)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_SET_FLOW_FORMAT);

    ovs_be32 *flow_formatp = ofpbuf_pull(&b, sizeof *flow_formatp);
    uint32_t flow_format = ntohl(*flow_formatp);
    switch (flow_format) {
    case NXFF_OPENFLOW10:
        return OFPUTIL_P_OF10_STD;

    case NXFF_NXM:
        return OFPUTIL_P_OF10_NXM;

    default:
        VLOG_WARN_RL(&rl, "NXT_SET_FLOW_FORMAT message specified invalid "
                     "flow format %"PRIu32, flow_format);
        return 0;
    }
}
Пример #11
0
/* Decodes 'oh', which must be an OFPT_GET_CONFIG_REPLY or OFPT_SET_CONFIG
 * message, into 'config'.  Returns false if 'oh' contained any flags that
 * aren't specified in its version of OpenFlow, true otherwise. */
static bool
ofputil_decode_switch_config(const struct ofp_header *oh,
                             struct ofputil_switch_config *config)
{
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    ofpraw_pull_assert(&b);

    const struct ofp_switch_config *osc = ofpbuf_pull(&b, sizeof *osc);
    config->frag = ntohs(osc->flags) & OFPC_FRAG_MASK;
    config->miss_send_len = ntohs(osc->miss_send_len);

    ovs_be16 valid_mask = htons(OFPC_FRAG_MASK);
    if (oh->version < OFP13_VERSION) {
        const ovs_be16 ttl_bit = htons(OFPC_INVALID_TTL_TO_CONTROLLER);
        valid_mask |= ttl_bit;
        config->invalid_ttl_to_controller = (osc->flags & ttl_bit) != 0;
    } else {
        config->invalid_ttl_to_controller = -1;
    }

    return !(osc->flags & ~valid_mask);
}
Пример #12
0
/* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified by the
 * request into '*port'.  Returns 0 if successful, otherwise an OpenFlow error
 * code. */
enum ofperr
ofputil_decode_queue_get_config_request(const struct ofp_header *oh,
                                        ofp_port_t *port, uint32_t *queue)
{
    const struct ofp10_queue_get_config_request *qgcr10;
    const struct ofp11_queue_get_config_request *qgcr11;
    const struct ofp14_queue_desc_request *qdr14;
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
    enum ofpraw raw = ofpraw_pull_assert(&b);

    switch ((int) raw) {
    case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
        qgcr10 = b.data;
        *port = u16_to_ofp(ntohs(qgcr10->port));
        *queue = OFPQ_ALL;
        break;

    case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
        qgcr11 = b.data;
        *queue = OFPQ_ALL;
        enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port);
        if (error || *port == OFPP_ANY) {
            return error;
        }
        break;

    case OFPRAW_OFPST14_QUEUE_DESC_REQUEST:
        qdr14 = b.data;
        *queue = ntohl(qdr14->queue);
        return ofputil_port_from_ofp11(qdr14->port, port);

    default:
        OVS_NOT_REACHED();
    }

    return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX)
            ? 0
            : OFPERR_OFPQOFC_BAD_PORT);
}
Пример #13
0
static int
netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
                                  struct ofpbuf *buf)
{
    static const struct nl_policy ovs_netdev_policy[] = {
        [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 },
        [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 },
        [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
        [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) },
        [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 },
        [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
    };

    netdev_windows_info_init(info);

    struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
    struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
    struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);

    struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
    if (!nlmsg || !genl || !ovs_header
        || nlmsg->nlmsg_type != ovs_win_netdev_family
        || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
                            ARRAY_SIZE(ovs_netdev_policy))) {
        return EINVAL;
    }

    info->cmd = genl->cmd;
    info->dp_ifindex = ovs_header->dp_ifindex;
    info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);