Пример #1
0
/* Helper function for nl_dump_next(). */
static int
nl_dump_recv(struct nl_dump *dump)
{
    struct nlmsghdr *nlmsghdr;
    int retval;

    retval = nl_sock_recv__(dump->sock, &dump->buffer, true);
    if (retval) {
        return retval == EINTR ? EAGAIN : retval;
    }

    nlmsghdr = nl_msg_nlmsghdr(&dump->buffer);
    if (dump->seq != nlmsghdr->nlmsg_seq) {
        VLOG_DBG_RL(&rl, "ignoring seq %#"PRIx32" != expected %#"PRIx32,
                    nlmsghdr->nlmsg_seq, dump->seq);
        return EAGAIN;
    }

    if (nl_msg_nlmsgerr(&dump->buffer, &retval)) {
        VLOG_INFO_RL(&rl, "netlink dump request error (%s)",
                     ovs_strerror(retval));
        return retval && retval != EAGAIN ? retval : EPROTO;
    }

    return 0;
}
Пример #2
0
static void
lswitch_handshake(struct lswitch *sw)
{
    enum ofputil_protocol protocol;
    enum ofp_version version;

    send_features_request(sw);

	send_controller_id(sw);

    version = rconn_get_version(sw->rconn);
    protocol = ofputil_protocol_from_ofp_version(version);
    
    if (sw->default_flows) {
        struct ofpbuf *msg = NULL;
        int error = 0;
        size_t i;

        if (!(protocol & sw->usable_protocols)) {
            enum ofputil_protocol want = rightmost_1bit(sw->usable_protocols);
            while (!error) {
                msg = ofputil_encode_set_protocol(protocol, want, &protocol);
                if (!msg) {
                    break;
                }
                error = rconn_send(sw->rconn, msg, NULL);
            }
        }
        if (protocol & sw->usable_protocols) {
            for (i = 0; !error && i < sw->n_default_flows; i++) {
                msg = ofputil_encode_flow_mod(&sw->default_flows[i], protocol);
                error = rconn_send(sw->rconn, msg, NULL);
            }

            if (error) {
                VLOG_INFO_RL(&rl, "%s: failed to queue default flows (%s)",
                             rconn_get_name(sw->rconn), ovs_strerror(error));
            }
        } else {
            VLOG_INFO_RL(&rl, "%s: failed to set usable protocol",
                         rconn_get_name(sw->rconn));
        }
    }
    sw->protocol = protocol;
}
Пример #3
0
/* Extracts the mac, IPv4 and IPv6 addresses from the
 * "nbrec_logical_router_port" parameter 'lrp'.  Stores the IPv4 and
 * IPv6 addresses in the 'ipv4_addrs' and 'ipv6_addrs' fields of
 * 'laddrs', respectively.  In addition, a link local IPv6 address
 * based on the 'mac' member of 'lrp' is added to the 'ipv6_addrs'
 * field.
 *
 * Return true if a valid 'mac' address is found in 'lrp', false otherwise.
 *
 * The caller must call destroy_lport_addresses(). */
bool
extract_lrp_networks(const struct nbrec_logical_router_port *lrp,
                     struct lport_addresses *laddrs)
{
    memset(laddrs, 0, sizeof *laddrs);

    if (!eth_addr_from_string(lrp->mac, &laddrs->ea)) {
        laddrs->ea = eth_addr_zero;
        return false;
    }
    snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
             ETH_ADDR_ARGS(laddrs->ea));

    for (int i = 0; i < lrp->n_networks; i++) {
        ovs_be32 ip4;
        struct in6_addr ip6;
        unsigned int plen;
        char *error;

        error = ip_parse_cidr(lrp->networks[i], &ip4, &plen);
        if (!error) {
            if (!ip4 || plen == 32) {
                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
                VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
                continue;
            }

            add_ipv4_netaddr(laddrs, ip4, plen);
            continue;
        }
        free(error);

        error = ipv6_parse_cidr(lrp->networks[i], &ip6, &plen);
        if (!error) {
            if (plen == 128) {
                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
                VLOG_WARN_RL(&rl, "bad 'networks' %s", lrp->networks[i]);
                continue;
            }
            add_ipv6_netaddr(laddrs, ip6, plen);
        } else {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_INFO_RL(&rl, "invalid syntax '%s' in networks",
                         lrp->networks[i]);
            free(error);
        }
    }

    /* Always add the IPv6 link local address. */
    struct in6_addr lla;
    in6_generate_lla(laddrs->ea, &lla);
    add_ipv6_netaddr(laddrs, lla, 64);

    return true;
}
Пример #4
0
/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
 * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
 * 'ipv6_addrs' fields of 'laddrs'.
 *
 * Return true if at least 'MAC' is found in 'address', false otherwise.
 *
 * The caller must call destroy_lport_addresses(). */
bool
extract_lsp_addresses(const char *address, struct lport_addresses *laddrs)
{
    int ofs;
    bool success = extract_addresses(address, laddrs, &ofs);

    if (success && ofs < strlen(address)) {
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
        VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
    }

    return success;
}
Пример #5
0
/* Extracts the mac, IPv4 and IPv6 addresses from * 'address' which
 * should be of the format 'MAC [IP1 IP2 ..]" where IPn should be a
 * valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
 * 'ipv6_addrs' fields of 'laddrs'.
 *
 * Return true if at least 'MAC' is found in 'address', false otherwise.
 *
 * The caller must call destroy_lport_addresses(). */
bool
extract_lsp_addresses(const char *address, struct lport_addresses *laddrs)
{
    memset(laddrs, 0, sizeof *laddrs);

    const char *buf = address;
    int buf_index = 0;
    const char *buf_end = buf + strlen(address);
    if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
                      ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
        laddrs->ea = eth_addr_zero;
        return false;
    }

    snprintf(laddrs->ea_s, sizeof laddrs->ea_s, ETH_ADDR_FMT,
             ETH_ADDR_ARGS(laddrs->ea));

    ovs_be32 ip4;
    struct in6_addr ip6;
    unsigned int plen;
    char *error;

    /* Loop through the buffer and extract the IPv4/IPv6 addresses
     * and store in the 'laddrs'. Break the loop if invalid data is found.
     */
    buf += buf_index;
    while (buf < buf_end) {
        buf_index = 0;
        error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
        if (!error) {
            add_ipv4_netaddr(laddrs, ip4, plen);
            buf += buf_index;
            continue;
        }
        free(error);
        error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
        if (!error) {
            add_ipv6_netaddr(laddrs, ip6, plen);
        } else {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
            free(error);
            break;
        }
        buf += buf_index;
    }

    return true;
}
Пример #6
0
static void
queue_tx(struct lswitch *sw, struct ofpbuf *b)
{
    int retval = rconn_send_with_limit(sw->rconn, b, sw->queued, 10);
    if (retval && retval != ENOTCONN) {
        if (retval == EAGAIN) {
            VLOG_INFO_RL(&rl, "%016llx: %s: tx queue overflow",
                         sw->datapath_id, rconn_get_name(sw->rconn));
        } else {
            VLOG_WARN_RL(&rl, "%016llx: %s: send: %s",
                         sw->datapath_id, rconn_get_name(sw->rconn),
                         ovs_strerror(retval));
        }
    }
}
Пример #7
0
/* Schedules 'msg' to be sent on 'rpc' and returns 'rpc''s status (as with
 * jsonrpc_get_status()).
 *
 * If 'msg' cannot be sent immediately, it is appended to a buffer.  The caller
 * is responsible for ensuring that the amount of buffered data is somehow
 * limited.  (jsonrpc_get_backlog() returns the amount of data currently
 * buffered in 'rpc'.)
 *
 * Always takes ownership of 'msg', regardless of success. */
int
jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg)
{
    struct ofpbuf *buf;
    struct json *json;
    size_t length;
    char *s;

    if (rpc->status) {
        jsonrpc_msg_destroy(msg);
        return rpc->status;
    }

    jsonrpc_log_msg(rpc, "send", msg);

    json = jsonrpc_msg_to_json(msg);
    s = json_to_string(json, 0);
    length = strlen(s);
    json_destroy(json);

    buf = xmalloc(sizeof *buf);
    ofpbuf_use(buf, s, length);
    buf->size = length;
    list_push_back(&rpc->output, &buf->list_node);
    rpc->output_count++;
    rpc->backlog += length;

    if (rpc->output_count >= 50) {
        VLOG_INFO_RL(&rl, "excessive sending backlog, jsonrpc: %s, num of"
                     " msgs: %"PRIuSIZE", backlog: %"PRIuSIZE".", rpc->name,
                     rpc->output_count, rpc->backlog);
    }

    if (rpc->backlog == length) {
        jsonrpc_run(rpc);
    }
    return rpc->status;
}
Пример #8
0
static int
do_ca_cert_bootstrap(struct stream *stream)
{
    struct ssl_stream *sslv = ssl_stream_cast(stream);
    STACK_OF(X509) *chain;
    X509 *cert;
    FILE *file;
    int error;
    int fd;

    chain = SSL_get_peer_cert_chain(sslv->ssl);
    if (!chain || !sk_X509_num(chain)) {
        VLOG_ERR("could not bootstrap CA cert: no certificate presented by "
                 "peer");
        return EPROTO;
    }
    cert = sk_X509_value(chain, sk_X509_num(chain) - 1);

    /* Check that 'cert' is self-signed.  Otherwise it is not a CA
     * certificate and we should not attempt to use it as one. */
    error = X509_check_issued(cert, cert);
    if (error) {
        VLOG_ERR("could not bootstrap CA cert: obtained certificate is "
                 "not self-signed (%s)",
                 X509_verify_cert_error_string(error));
        if (sk_X509_num(chain) < 2) {
            VLOG_ERR("only one certificate was received, so probably the peer "
                     "is not configured to send its CA certificate");
        }
        return EPROTO;
    }

    fd = open(ca_cert.file_name, O_CREAT | O_EXCL | O_WRONLY, 0444);
    if (fd < 0) {
        if (errno == EEXIST) {
            VLOG_INFO_RL(&rl, "reading CA cert %s created by another process",
                         ca_cert.file_name);
            stream_ssl_set_ca_cert_file__(ca_cert.file_name, true, true);
            return EPROTO;
        } else {
            VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s",
                     ca_cert.file_name, ovs_strerror(errno));
            return errno;
        }
    }

    file = fdopen(fd, "w");
    if (!file) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s",
                 ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    if (!PEM_write_X509(file, cert)) {
        VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: "
                 "%s", ca_cert.file_name,
                 ERR_error_string(ERR_get_error(), NULL));
        fclose(file);
        unlink(ca_cert.file_name);
        return EIO;
    }

    if (fclose(file)) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s",
                 ca_cert.file_name, ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert.file_name);
    log_ca_cert(ca_cert.file_name, cert);
    bootstrap_ca_cert = false;
    ca_cert.read = true;

    /* SSL_CTX_add_client_CA makes a copy of cert's relevant data. */
    SSL_CTX_add_client_CA(ctx, cert);

    SSL_CTX_set_cert_store(ctx, X509_STORE_new());
    if (SSL_CTX_load_verify_locations(ctx, ca_cert.file_name, NULL) != 1) {
        VLOG_ERR("SSL_CTX_load_verify_locations: %s",
                 ERR_error_string(ERR_get_error(), NULL));
        return EPROTO;
    }
    VLOG_INFO("killing successful connection to retry using CA cert");
    return EPROTO;
}
Пример #9
0
void
jsonrpc_session_run(struct jsonrpc_session *s)
{
    if (s->pstream) {
        struct stream *stream;
        int error;

        error = pstream_accept(s->pstream, &stream);
        if (!error) {
            if (s->rpc || s->stream) {
                VLOG_INFO_RL(&rl,
                             "%s: new connection replacing active connection",
                             reconnect_get_name(s->reconnect));
                jsonrpc_session_disconnect(s);
            }
            reconnect_connected(s->reconnect, time_msec());
            s->rpc = jsonrpc_open(stream);
        } else if (error != EAGAIN) {
            reconnect_listen_error(s->reconnect, time_msec(), error);
            pstream_close(s->pstream);
            s->pstream = NULL;
        }
    }

    if (s->rpc) {
        size_t backlog;
        int error;

        backlog = jsonrpc_get_backlog(s->rpc);
        jsonrpc_run(s->rpc);
        if (jsonrpc_get_backlog(s->rpc) < backlog) {
            /* Data previously caught in a queue was successfully sent (or
             * there's an error, which we'll catch below.)
             *
             * We don't count data that is successfully sent immediately as
             * activity, because there's a lot of queuing downstream from us,
             * which means that we can push a lot of data into a connection
             * that has stalled and won't ever recover.
             */
            reconnect_activity(s->reconnect, time_msec());
        }

        error = jsonrpc_get_status(s->rpc);
        if (error) {
            reconnect_disconnected(s->reconnect, time_msec(), error);
            jsonrpc_session_disconnect(s);
            s->last_error = error;
        }
    } else if (s->stream) {
        int error;

        stream_run(s->stream);
        error = stream_connect(s->stream);
        if (!error) {
            reconnect_connected(s->reconnect, time_msec());
            s->rpc = jsonrpc_open(s->stream);
            s->stream = NULL;
        } else if (error != EAGAIN) {
            reconnect_connect_failed(s->reconnect, time_msec(), error);
            stream_close(s->stream);
            s->stream = NULL;
            s->last_error = error;
        }
    }

    switch (reconnect_run(s->reconnect, time_msec())) {
    case RECONNECT_CONNECT:
        jsonrpc_session_connect(s);
        break;

    case RECONNECT_DISCONNECT:
        reconnect_disconnected(s->reconnect, time_msec(), 0);
        jsonrpc_session_disconnect(s);
        break;

    case RECONNECT_PROBE:
        if (s->rpc) {
            struct json *params;
            struct jsonrpc_msg *request;

            params = json_array_create_empty();
            request = jsonrpc_create_request("echo", params, NULL);
            json_destroy(request->id);
            request->id = json_string_create("echo");
            jsonrpc_send(s->rpc, request);
        }
        break;
    }
}
Пример #10
0
void
jsonrpc_session_run(struct jsonrpc_session *s)
{
    if (s->pstream) {
        struct stream *stream;
        int error;

        error = pstream_accept(s->pstream, &stream);
        if (!error) {
            if (s->rpc || s->stream) {
                VLOG_INFO_RL(&rl,
                             "%s: new connection replacing active connection",
                             reconnect_get_name(s->reconnect));
                jsonrpc_session_disconnect(s);
            }
            reconnect_connected(s->reconnect, time_msec());
            s->rpc = jsonrpc_open(stream);
        } else if (error != EAGAIN) {
            reconnect_listen_error(s->reconnect, time_msec(), error);
            pstream_close(s->pstream);
            s->pstream = NULL;
        }
    }

    if (s->rpc) {
        int error;

        jsonrpc_run(s->rpc);
        error = jsonrpc_get_status(s->rpc);
        if (error) {
            reconnect_disconnected(s->reconnect, time_msec(), error);
            jsonrpc_session_disconnect(s);
        }
    } else if (s->stream) {
        int error;

        stream_run(s->stream);
        error = stream_connect(s->stream);
        if (!error) {
            reconnect_connected(s->reconnect, time_msec());
            s->rpc = jsonrpc_open(s->stream);
            s->stream = NULL;
        } else if (error != EAGAIN) {
            reconnect_connect_failed(s->reconnect, time_msec(), error);
            stream_close(s->stream);
            s->stream = NULL;
        }
    }

    switch (reconnect_run(s->reconnect, time_msec())) {
    case RECONNECT_CONNECT:
        jsonrpc_session_connect(s);
        break;

    case RECONNECT_DISCONNECT:
        reconnect_disconnected(s->reconnect, time_msec(), 0);
        jsonrpc_session_disconnect(s);
        break;

    case RECONNECT_PROBE:
        if (s->rpc) {
            struct json *params;
            struct jsonrpc_msg *request;

            params = json_array_create_empty();
            request = jsonrpc_create_request("echo", params, NULL);
            json_destroy(request->id);
            request->id = json_string_create("echo");
            jsonrpc_send(s->rpc, request);
        }
        break;
    }
}
Пример #11
0
static int
ofputil_pull_queue_get_config_reply10(struct ofpbuf *msg,
                                      struct ofputil_queue_config *queue)
{
    const struct ofp_header *oh = msg->header;
    unsigned int opq_len;       /* Length of protocol-specific queue header. */
    unsigned int len;           /* Total length of queue + properties. */

    /* Obtain the port number from the message header. */
    if (oh->version == OFP10_VERSION) {
        const struct ofp10_queue_get_config_reply *oqgcr10 = msg->msg;
        queue->port = u16_to_ofp(ntohs(oqgcr10->port));
    } else {
        const struct ofp11_queue_get_config_reply *oqgcr11 = msg->msg;
        enum ofperr error = ofputil_port_from_ofp11(oqgcr11->port,
                                                    &queue->port);
        if (error) {
            return error;
        }
    }

    /* Pull off the queue header and get the queue number and length. */
    if (oh->version < OFP12_VERSION) {
        const struct ofp10_packet_queue *opq10;
        opq10 = ofpbuf_try_pull(msg, sizeof *opq10);
        if (!opq10) {
            return OFPERR_OFPBRC_BAD_LEN;
        }
        queue->queue = ntohl(opq10->queue_id);
        len = ntohs(opq10->len);
        opq_len = sizeof *opq10;
    } else {
        const struct ofp12_packet_queue *opq12;
        opq12 = ofpbuf_try_pull(msg, sizeof *opq12);
        if (!opq12) {
            return OFPERR_OFPBRC_BAD_LEN;
        }
        queue->queue = ntohl(opq12->queue_id);
        len = ntohs(opq12->len);
        opq_len = sizeof *opq12;
    }

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

    /* Pull properties.  The format of these properties differs from used in
     * OF1.4+ so we can't use the common property functions. */
    while (len > 0) {
        const struct ofp10_queue_prop_header *hdr;
        unsigned int property;
        unsigned int prop_len;
        enum ofperr error = 0;

        hdr = ofpbuf_at_assert(msg, 0, sizeof *hdr);
        prop_len = ntohs(hdr->len);
        if (prop_len < sizeof *hdr || prop_len > len || prop_len % 8) {
            return OFPERR_OFPBRC_BAD_LEN;
        }

        property = ntohs(hdr->property);
        switch (property) {
        case OFPQT10_MIN_RATE:
            error = parse_ofp10_queue_rate(hdr, &queue->min_rate);
            break;

        case OFPQT11_MAX_RATE:
            error = parse_ofp10_queue_rate(hdr, &queue->max_rate);
            break;

        default:
            VLOG_INFO_RL(&rl, "unknown queue property %u", property);
            break;
        }
        if (error) {
            return error;
        }

        ofpbuf_pull(msg, prop_len);
        len -= prop_len;
    }
    return 0;
}