コード例 #1
0
ファイル: test-odp.c プロジェクト: Danesca/openvswitch
int
main(void)
{
    struct ds in;

    ds_init(&in);
    while (!ds_get_line(&in, stdin)) {
        struct ofpbuf odp_key;
        struct flow flow;
        struct ds out;
        int error;
        char *s;

        /* Delete comments, skip blank lines. */
        s = ds_cstr(&in);
        if (*s == '#') {
            puts(s);
            continue;
        }
        if (strchr(s, '#')) {
            *strchr(s, '#') = '\0';
        }
        if (s[strspn(s, " ")] == '\0') {
            putchar('\n');
            continue;
        }

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        error = odp_flow_key_from_string(ds_cstr(&in), &odp_key);
        if (error) {
            printf("odp_flow_key_from_string: error\n");
            goto next;
        }

        /* Convert odp_key to flow. */
        error = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
        if (error) {
            printf("odp_flow_key_to_flow: error\n");
            goto next;
        }

        /* Convert cls_rule back to odp_key. */
        ofpbuf_uninit(&odp_key);
        ofpbuf_init(&odp_key, 0);
        odp_flow_key_from_flow(&odp_key, &flow);

        /* Convert odp_key to string. */
        ds_init(&out);
        odp_flow_key_format(odp_key.data, odp_key.size, &out);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
    }
    ds_destroy(&in);

    return 0;
}
コード例 #2
0
ファイル: route-table.c プロジェクト: AliJabar/ovs
static int
route_table_reset(void)
{
    struct nl_dump dump;
    struct rtgenmsg *rtmsg;
    uint64_t reply_stub[NL_DUMP_BUFSIZE / 8];
    struct ofpbuf request, reply, buf;

    route_map_clear();
    route_table_valid = true;
    rt_change_seq++;

    ofpbuf_init(&request, 0);

    nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETROUTE, NLM_F_REQUEST);

    rtmsg = ofpbuf_put_zeros(&request, sizeof *rtmsg);
    rtmsg->rtgen_family = AF_UNSPEC;

    nl_dump_start(&dump, NETLINK_ROUTE, &request);
    ofpbuf_uninit(&request);

    ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
    while (nl_dump_next(&dump, &reply, &buf)) {
        struct route_table_msg msg;

        if (route_table_parse(&reply, &msg)) {
            route_table_handle_msg(&msg);
        }
    }
    ofpbuf_uninit(&buf);

    return nl_dump_done(&dump);
}
コード例 #3
0
ファイル: ovs-brcompatd.c プロジェクト: Danesca/openvswitch
static int
lookup_brc_multicast_group(int *multicast_group)
{
    struct nl_sock *sock;
    struct ofpbuf request, *reply;
    struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)];
    int retval;

    retval = nl_sock_create(NETLINK_GENERIC, &sock);
    if (retval) {
        return retval;
    }
    ofpbuf_init(&request, 0);
    nl_msg_put_genlmsghdr(&request, 0, brc_family,
                          NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1);
    retval = nl_sock_transact(sock, &request, &reply);
    ofpbuf_uninit(&request);
    if (retval) {
        nl_sock_destroy(sock);
        return retval;
    }
    if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN,
                         brc_multicast_policy, attrs,
                         ARRAY_SIZE(brc_multicast_policy))) {
        nl_sock_destroy(sock);
        ofpbuf_delete(reply);
        return EPROTO;
    }
    *multicast_group = nl_attr_get_u32(attrs[BRC_GENL_A_MC_GROUP]);
    nl_sock_destroy(sock);
    ofpbuf_delete(reply);

    return 0;
}
コード例 #4
0
ファイル: test-odp.c プロジェクト: emaste/openvswitch
static int
parse_actions(void)
{
    struct ds in;

    ds_init(&in);
    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    while (!ds_get_test_line(&in, stdin)) {
        struct ofpbuf odp_actions;
        struct ds out;
        int error;

        /* Convert string to OVS DP actions. */
        ofpbuf_init(&odp_actions, 0);
        error = odp_actions_from_string(ds_cstr(&in), NULL, &odp_actions);
        if (error) {
            printf("odp_actions_from_string: error\n");
            goto next;
        }

        /* Convert odp_actions back to string. */
        ds_init(&out);
        format_odp_actions(&out, odp_actions.data, odp_actions.size);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_actions);
    }
    ds_destroy(&in);

    return 0;
}
コード例 #5
0
ファイル: ofp-parse.c プロジェクト: CPqD/of11softswitch
/* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
 * (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'.
 * '*cur_format' should initially contain the flow format currently configured
 * on the connection; this function will add a message to change the flow
 * format and update '*cur_format', if this is necessary to add the parsed
 * flow. */
void
parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
                       char *string, uint16_t command)
{
    bool is_del = command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT;
    enum nx_flow_format min_format, next_format;
    struct ofpbuf actions;
    struct ofpbuf *ofm;
    struct flow_mod fm;

    ofpbuf_init(&actions, 64);
    parse_ofp_str(&fm, NULL, is_del ? NULL : &actions, string);
    fm.command = command;

    min_format = ofputil_min_flow_format(&fm.cr, true, fm.cookie);
    next_format = MAX(*cur_format, min_format);
    if (next_format != *cur_format) {
        struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
        list_push_back(packets, &sff->list_node);
        *cur_format = next_format;
    }

    ofm = ofputil_encode_flow_mod(&fm, *cur_format);
    list_push_back(packets, &ofm->list_node);

    ofpbuf_uninit(&actions);
}
コード例 #6
0
ファイル: odp_target.c プロジェクト: blp/ovs-reviews
static int
parse_actions(const char *in)
{
    struct ofpbuf odp_actions;
    struct ds out;
    int error;

    /* Convert string to OVS DP actions. */
    ofpbuf_init(&odp_actions, 0);
    error = odp_actions_from_string(in, NULL, &odp_actions);
    if (error) {
        printf("odp_actions_from_string: error\n");
        goto next;
    }

    /* Convert odp_actions back to string. */
    ds_init(&out);
    format_odp_actions(&out, odp_actions.data, odp_actions.size, NULL);
    puts(ds_cstr(&out));
    ds_destroy(&out);

next:
    ofpbuf_uninit(&odp_actions);
    return 0;
}
コード例 #7
0
/* Sends the given 'command' to datapath 'dp', related to the local datapath
 * numbered 'dp_idx'.  If 'arg' is nonnull, adds it to the command as the
 * datapath or port name attribute depending on the requested operation.  
 * Returns 0 if successful, otherwise a positive errno value. */
static int
send_mgmt_command(struct dpif *dp, int dp_idx, int command, const char *arg)
{
    struct ofpbuf request, *reply;
    int retval;

    ofpbuf_init(&request, 0);
    nl_msg_put_genlmsghdr(&request, dp->sock, 32, openflow_family,
                          NLM_F_REQUEST | NLM_F_ACK, command, 1);
    if (dp_idx != -1) {
        nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, dp_idx);
    }
    if (arg) {
        if ((command == DP_GENL_C_ADD_DP) || (command == DP_GENL_C_DEL_DP)) {
            nl_msg_put_string(&request, DP_GENL_A_DP_NAME, arg);
        } else {
            nl_msg_put_string(&request, DP_GENL_A_PORTNAME, arg);
        }
    }
    retval = nl_sock_transact(dp->sock, &request, &reply);
    ofpbuf_uninit(&request);
    ofpbuf_delete(reply);

    return retval;
}
コード例 #8
0
ファイル: ofpbuf.c プロジェクト: andychenzy/dpdk-ovs
/* Frees memory that 'b' points to, as well as 'b' itself. */
void
ofpbuf_delete(struct ofpbuf *b)
{
    if (b) {
        ofpbuf_uninit(b);
        free(b);
    }
}
コード例 #9
0
ファイル: netlink-conntrack.c プロジェクト: Grim-lock/ovs
/* End a conntrack netlink dump. */
int
nl_ct_dump_done(struct nl_ct_dump_state *state)
{
    int error = nl_dump_done(&state->dump);

    ofpbuf_uninit(&state->buf);
    free(state);
    return error;
}
コード例 #10
0
/* Completes Netlink dump operation 'dump', which must have been initialized
 * with nl_dump_start().  Returns 0 if the dump operation was error-free,
 * otherwise a positive errno value describing the problem. */
int
nl_dump_done(struct nl_dump *dump)
{
    /* Drain any remaining messages that the client didn't read.  Otherwise the
     * kernel will continue to queue them up and waste buffer space.
     *
     * XXX We could just destroy and discard the socket in this case. */
    while (!dump->status) {
        struct ofpbuf reply;
        if (!nl_dump_next(dump, &reply)) {
            ovs_assert(dump->status);
        }
    }
    nl_pool_release(dump->sock);
    ofpbuf_uninit(&dump->buffer);
    return dump->status == EOF ? 0 : dump->status;
}
コード例 #11
0
ファイル: netlink-conntrack.c プロジェクト: Grim-lock/ovs
int
nl_ct_flush_zone(uint16_t flush_zone)
{
    /* Windows can flush a specific zone */
    struct ofpbuf buf;
    int err;

    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);

    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
                        IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
    nl_msg_put_be16(&buf, CTA_ZONE, flush_zone);

    err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
    ofpbuf_uninit(&buf);

    return err;
}
コード例 #12
0
ファイル: netlink-conntrack.c プロジェクト: Grim-lock/ovs
int
nl_ct_flush(void)
{
    struct ofpbuf buf;
    int err;

    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);

    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
                        IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);

    err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
    ofpbuf_uninit(&buf);

    /* Expectations are flushed automatically, because they do not
     * have a master connection anymore */

    return err;
}
コード例 #13
0
/* Looks up the Netlink multicast group and datapath index of a datapath
 * by either the datapath index or name.  If 'dp_idx' points to a value 
 * of '-1', then 'dp_name' is used to lookup the datapath.  If successful, 
 * stores the multicast group in '*multicast_group' and the index in
 * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */
static int
query_datapath(int *dp_idx, int *multicast_group, const char *dp_name)
{
    struct nl_sock *sock;
    struct ofpbuf request, *reply;
    struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)];
    int retval;

    retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock);
    if (retval) {
        return retval;
    }
    ofpbuf_init(&request, 0);
    nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST,
                          DP_GENL_C_QUERY_DP, 1);
    if (*dp_idx != -1) {
        nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx);
    }
    if (dp_name) {
        nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name);
    }
    retval = nl_sock_transact(sock, &request, &reply);
    ofpbuf_uninit(&request);
    if (retval) {
        nl_sock_destroy(sock);
        return retval;
    }
    if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN,
                         openflow_multicast_policy, attrs,
                         ARRAY_SIZE(openflow_multicast_policy))) {
        nl_sock_destroy(sock);
        ofpbuf_delete(reply);
        return EPROTO;
    }
    *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]);
    *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]);
    nl_sock_destroy(sock);
    ofpbuf_delete(reply);

    return 0;
}
コード例 #14
0
ファイル: fail-open.c プロジェクト: asteven/openvswitch
static void
send_bogus_packet_ins(struct fail_open *fo)
{
    struct ofputil_packet_in pin;
    uint8_t mac[ETH_ADDR_LEN];
    struct ofpbuf b;

    ofpbuf_init(&b, 128);
    eth_addr_nicira_random(mac);
    compose_rarp(&b, mac);

    memset(&pin, 0, sizeof pin);
    pin.packet = b.data;
    pin.packet_len = b.size;
    pin.reason = OFPR_NO_MATCH;
    pin.send_len = b.size;
    pin.fmd.in_port = OFPP_LOCAL;
    connmgr_send_packet_in(fo->connmgr, &pin);

    ofpbuf_uninit(&b);
}
コード例 #15
0
ファイル: netlink-conntrack.c プロジェクト: Grim-lock/ovs
/* Receive the next 'entry' from the conntrack netlink dump with 'state'.
 * Returns 'EOF' when no more entries are available, 0 otherwise.  'entry' may
 * be uninitilized memory on entry, and must be uninitialized with
 * ct_dpif_entry_uninit() afterwards by the caller.  In case the same 'entry' is
 * passed to this function again, the entry must also be uninitialized before
 * the next call. */
int
nl_ct_dump_next(struct nl_ct_dump_state *state, struct ct_dpif_entry *entry)
{
    struct ofpbuf buf;

    memset(entry, 0, sizeof *entry);
    for (;;) {
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
        enum nl_ct_event_type type;
        uint8_t nfgen_family;

        if (!nl_dump_next(&state->dump, &buf, &state->buf)) {
            return EOF;
        }

        if (!nl_ct_parse_header_policy(&buf, &type, &nfgen_family, attrs)) {
            continue;
        };

        if (state->filter_zone) {
            uint16_t entry_zone = attrs[CTA_ZONE]
                                  ? ntohs(nl_attr_get_be16(attrs[CTA_ZONE]))
                                  : 0;
            if (entry_zone != state->zone) {
                continue;
            }
        }

        if (nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) {
            break;
        }

        ct_dpif_entry_uninit(entry);
        memset(entry, 0, sizeof *entry);
        /* Ignore the failed entry and get the next one. */
    }

    ofpbuf_uninit(&buf);
    return 0;
}
コード例 #16
0
ファイル: ofp_print_target.c プロジェクト: blp/ovs-reviews
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
    if (size < sizeof(struct ofp_header)) {
        return 0;
    }

    static bool isInit = false;
    if (!isInit) {
        vlog_set_verbosity("off");
        isInit = true;
    }

    struct ofpbuf b;
    ofpbuf_use_const(&b, data, size);
    for (;;) {
        /* Check if ofpbuf contains ofp header. */
        struct ofp_header *oh = ofpbuf_at(&b, 0, sizeof *oh);
        if (!oh) {
            break;
        }

        /* Check if length is geq than lower bound. */
        size_t length = ntohs(oh->length);
        if (length < sizeof *oh) {
            break;
        }

        /* Check if ofpbuf contains payload. */
        size_t tail_len = length - sizeof *oh;
        void *tail = ofpbuf_at(&b, sizeof *oh, tail_len);
        if (!tail) {
            break;
        }

        ofp_print(stdout, ofpbuf_pull(&b, length), length, NULL, NULL, 2);
    }
    ofpbuf_uninit(&b);
    return 0;
}
コード例 #17
0
ファイル: netlink-socket.c プロジェクト: crazyideas21/swclone
/* Completes Netlink dump operation 'dump', which must have been initialized
 * with nl_dump_start().  Returns 0 if the dump operation was error-free,
 * otherwise a positive errno value describing the problem. */
int
nl_dump_done(struct nl_dump *dump)
{
    /* Drain any remaining messages that the client didn't read.  Otherwise the
     * kernel will continue to queue them up and waste buffer space. */
    while (!dump->status) {
        struct ofpbuf reply;
        if (!nl_dump_next(dump, &reply)) {
            assert(dump->status);
        }
    }

    if (dump->sock) {
        if (dump->sock->dump) {
            dump->sock->dump = NULL;
        } else {
            nl_sock_destroy(dump->sock);
        }
    }
    ofpbuf_uninit(&dump->buffer);
    return dump->status == EOF ? 0 : dump->status;
}
コード例 #18
0
ファイル: fail-open.c プロジェクト: Altiscale/ovs
static void
send_bogus_packet_ins(struct fail_open *fo)
{
    struct ofproto_packet_in pin;
    uint8_t mac[ETH_ADDR_LEN];
    struct ofpbuf b;

    ofpbuf_init(&b, 128);
    eth_addr_nicira_random(mac);
    compose_rarp(&b, mac);

    memset(&pin, 0, sizeof pin);
    pin.up.packet = ofpbuf_data(&b);
    pin.up.packet_len = ofpbuf_size(&b);
    pin.up.reason = OFPR_NO_MATCH;
    pin.up.fmd.in_port = OFPP_LOCAL;
    pin.send_len = ofpbuf_size(&b);
    pin.miss_type = OFPROTO_PACKET_IN_NO_MISS;
    connmgr_send_packet_in(fo->connmgr, &pin);

    ofpbuf_uninit(&b);
}
コード例 #19
0
ファイル: ofpbuf.c プロジェクト: cho4036/MyProject
/* Frees memory that 'b' points to and allocates a new ofpbuf */
void
ofpbuf_reinit(struct ofpbuf *b, size_t size)
{
    ofpbuf_uninit(b);
    ofpbuf_init(b, size);
}
コード例 #20
0
ファイル: odp_target.c プロジェクト: blp/ovs-reviews
static int
parse_keys(bool wc_keys, const char *in)
{
    int exit_code = 0;

    enum odp_key_fitness fitness;
    struct ofpbuf odp_key;
    struct ofpbuf odp_mask;
    struct flow flow;
    struct ds out;
    int error;

    /* Convert string to OVS DP key. */
    ofpbuf_init(&odp_key, 0);
    ofpbuf_init(&odp_mask, 0);
    error = odp_flow_from_string(in, NULL,
                                 &odp_key, &odp_mask);
    if (error) {
        printf("odp_flow_from_string: error\n");
        goto next;
    }

    if (!wc_keys) {
        struct odp_flow_key_parms odp_parms = {
            .flow = &flow,
            .support = {
                .recirc = true,
                .ct_state = true,
                .ct_zone = true,
                .ct_mark = true,
                .ct_label = true,
                .max_vlan_headers = SIZE_MAX,
            },
        };

        /* Convert odp_key to flow. */
        fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
        switch (fitness) {
            case ODP_FIT_PERFECT:
                break;

            case ODP_FIT_TOO_LITTLE:
                printf("ODP_FIT_TOO_LITTLE: ");
                break;

            case ODP_FIT_TOO_MUCH:
                printf("ODP_FIT_TOO_MUCH: ");
                break;

            case ODP_FIT_ERROR:
                printf("odp_flow_key_to_flow: error\n");
                goto next;
        }
        /* Convert cls_rule back to odp_key. */
        ofpbuf_uninit(&odp_key);
        ofpbuf_init(&odp_key, 0);
        odp_flow_key_from_flow(&odp_parms, &odp_key);

        if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
            printf ("too long: %"PRIu32" > %d\n",
                    odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
            exit_code = 1;
        }
    }

    /* Convert odp_key to string. */
    ds_init(&out);
    if (wc_keys) {
        odp_flow_format(odp_key.data, odp_key.size,
                        odp_mask.data, odp_mask.size, NULL, &out, false);
    } else {
        odp_flow_key_format(odp_key.data, odp_key.size, &out);
    }
    puts(ds_cstr(&out));
    ds_destroy(&out);

next:
    ofpbuf_uninit(&odp_key);
    ofpbuf_uninit(&odp_mask);

    return exit_code;
}
コード例 #21
0
ファイル: netlink-conntrack.c プロジェクト: Grim-lock/ovs
int
nl_ct_flush_zone(uint16_t flush_zone)
{
    /* Apparently, there's no netlink interface to flush a specific zone.
     * This code dumps every connection, checks the zone and eventually
     * delete the entry.
     *
     * This is race-prone, but it is better than using shell scripts. */

    struct nl_dump dump;
    struct ofpbuf buf, reply, delete;

    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
    ofpbuf_init(&delete, NL_DUMP_BUFSIZE);

    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
                        IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
    nl_dump_start(&dump, NETLINK_NETFILTER, &buf);
    ofpbuf_clear(&buf);

    for (;;) {
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
        enum nl_ct_event_type event_type;
        uint8_t nfgen_family;
        uint16_t zone = 0;

        if (!nl_dump_next(&dump, &reply, &buf)) {
            break;
        }

        if (!nl_ct_parse_header_policy(&reply, &event_type, &nfgen_family,
                                       attrs)) {
            continue;
        };

        if (attrs[CTA_ZONE]) {
            zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE]));
        }

        if (zone != flush_zone) {
            /* The entry is not in the zone we're flushing. */
            continue;
        }
        nl_msg_put_nfgenmsg(&delete, 0, nfgen_family, NFNL_SUBSYS_CTNETLINK,
                            IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);

        nl_msg_put_be16(&delete, CTA_ZONE, htons(zone));
        nl_msg_put_unspec(&delete, CTA_TUPLE_ORIG, attrs[CTA_TUPLE_ORIG] + 1,
                          attrs[CTA_TUPLE_ORIG]->nla_len - NLA_HDRLEN);
        nl_msg_put_unspec(&delete, CTA_ID, attrs[CTA_ID] + 1,
                          attrs[CTA_ID]->nla_len - NLA_HDRLEN);
        nl_transact(NETLINK_NETFILTER, &delete, NULL);
        ofpbuf_clear(&delete);
    }

    nl_dump_done(&dump);

    ofpbuf_uninit(&delete);
    ofpbuf_uninit(&buf);

    /* Expectations are flushed automatically, because they do not
     * have a master connection anymore */
    return 0;
}
コード例 #22
0
ファイル: test-odp.c プロジェクト: emaste/openvswitch
static int
parse_keys(bool wc_keys)
{
    int exit_code = 0;
    struct ds in;

    ds_init(&in);
    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    while (!ds_get_test_line(&in, stdin)) {
        enum odp_key_fitness fitness;
        struct ofpbuf odp_key;
        struct ofpbuf odp_mask;
        struct flow flow;
        struct ds out;
        int error;

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        ofpbuf_init(&odp_mask, 0);
        error = odp_flow_from_string(ds_cstr(&in), NULL,
                                     &odp_key, &odp_mask);
        if (error) {
            printf("odp_flow_from_string: error\n");
            goto next;
        }

        if (!wc_keys) {
            /* Convert odp_key to flow. */
            fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
            switch (fitness) {
                case ODP_FIT_PERFECT:
                    break;

                case ODP_FIT_TOO_LITTLE:
                    printf("ODP_FIT_TOO_LITTLE: ");
                    break;

                case ODP_FIT_TOO_MUCH:
                    printf("ODP_FIT_TOO_MUCH: ");
                    break;

                case ODP_FIT_ERROR:
                    printf("odp_flow_key_to_flow: error\n");
                    goto next;
            }
            /* Convert cls_rule back to odp_key. */
            ofpbuf_uninit(&odp_key);
            ofpbuf_init(&odp_key, 0);
            odp_flow_key_from_flow(&odp_key, &flow, flow.in_port.odp_port);

            if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
                printf ("too long: %zu > %d\n",
                        odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
                exit_code = 1;
            }
        }

        /* Convert odp_key to string. */
        ds_init(&out);
        if (wc_keys) {
            odp_flow_format(odp_key.data, odp_key.size,
                            odp_mask.data, odp_mask.size, &out);
        } else {
            odp_flow_key_format(odp_key.data, odp_key.size, &out);
        }
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
    }
    ds_destroy(&in);

    return exit_code;
}
コード例 #23
0
ファイル: expr_parse_target.c プロジェクト: blp/ovs-reviews
static void
test_parse_actions(const char *input)
{
    struct shash symtab;
    struct hmap dhcp_opts;
    struct hmap dhcpv6_opts;
    struct hmap nd_ra_opts;
    struct simap ports;

    create_symtab(&symtab);
    create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts);

    /* Initialize group ids. */
    struct ovn_extend_table group_table;
    ovn_extend_table_init(&group_table);

    /* Initialize meter ids for QoS. */
    struct ovn_extend_table meter_table;
    ovn_extend_table_init(&meter_table);

    simap_init(&ports);
    simap_put(&ports, "eth0", 5);
    simap_put(&ports, "eth1", 6);
    simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL));

    struct ofpbuf ovnacts;
    struct expr *prereqs;
    char *error;

    puts(input);

    ofpbuf_init(&ovnacts, 0);

    const struct ovnact_parse_params pp = {
        .symtab = &symtab,
        .dhcp_opts = &dhcp_opts,
        .dhcpv6_opts = &dhcpv6_opts,
        .nd_ra_opts = &nd_ra_opts,
        .n_tables = 24,
        .cur_ltable = 10,
    };
    error = ovnacts_parse_string(input, &pp, &ovnacts, &prereqs);
    if (!error) {
        /* Convert the parsed representation back to a string and print it,
         * if it's different from the input. */
        struct ds ovnacts_s = DS_EMPTY_INITIALIZER;
        ovnacts_format(ovnacts.data, ovnacts.size, &ovnacts_s);
        if (strcmp(input, ds_cstr(&ovnacts_s))) {
            printf("    formats as %s\n", ds_cstr(&ovnacts_s));
        }

        /* Encode the actions into OpenFlow and print. */
        const struct ovnact_encode_params ep = {
            .lookup_port = lookup_port_cb,
            .aux = &ports,
            .is_switch = true,
            .group_table = &group_table,
            .meter_table = &meter_table,

            .pipeline = OVNACT_P_INGRESS,
            .ingress_ptable = 8,
            .egress_ptable = 40,
            .output_ptable = 64,
            .mac_bind_ptable = 65,
        };
        struct ofpbuf ofpacts;
        ofpbuf_init(&ofpacts, 0);
        ovnacts_encode(ovnacts.data, ovnacts.size, &ep, &ofpacts);
        struct ds ofpacts_s = DS_EMPTY_INITIALIZER;
        struct ofpact_format_params fp = { .s = &ofpacts_s };
        ofpacts_format(ofpacts.data, ofpacts.size, &fp);
        printf("    encodes as %s\n", ds_cstr(&ofpacts_s));
        ds_destroy(&ofpacts_s);
        ofpbuf_uninit(&ofpacts);

        /* Print prerequisites if any. */
        if (prereqs) {
            struct ds prereqs_s = DS_EMPTY_INITIALIZER;
            expr_format(prereqs, &prereqs_s);
            printf("    has prereqs %s\n", ds_cstr(&prereqs_s));
            ds_destroy(&prereqs_s);
        }

        /* Now re-parse and re-format the string to verify that it's
         * round-trippable. */
        struct ofpbuf ovnacts2;
        struct expr *prereqs2;
        ofpbuf_init(&ovnacts2, 0);
        error = ovnacts_parse_string(ds_cstr(&ovnacts_s), &pp, &ovnacts2,
                                     &prereqs2);
        if (!error) {
            struct ds ovnacts2_s = DS_EMPTY_INITIALIZER;
            ovnacts_format(ovnacts2.data, ovnacts2.size, &ovnacts2_s);
            if (strcmp(ds_cstr(&ovnacts_s), ds_cstr(&ovnacts2_s))) {
                printf("    bad reformat: %s\n", ds_cstr(&ovnacts2_s));
            }
            ds_destroy(&ovnacts2_s);
        } else {
            printf("    reparse error: %s\n", error);
            free(error);
        }
        expr_destroy(prereqs2);

        ovnacts_free(ovnacts2.data, ovnacts2.size);
        ofpbuf_uninit(&ovnacts2);
        ds_destroy(&ovnacts_s);
    } else {
        printf("    %s\n", error);
        free(error);
    }

    expr_destroy(prereqs);
    ovnacts_free(ovnacts.data, ovnacts.size);
    ofpbuf_uninit(&ovnacts);

    simap_destroy(&ports);
    expr_symtab_destroy(&symtab);
    shash_destroy(&symtab);
    dhcp_opts_destroy(&dhcp_opts);
    dhcp_opts_destroy(&dhcpv6_opts);
    nd_ra_opts_destroy(&nd_ra_opts);
    ovn_extend_table_destroy(&group_table);
    ovn_extend_table_destroy(&meter_table);
}

static void
test_parse_expr(const char *input)
{
    struct shash symtab;
    struct shash addr_sets;
    struct shash port_groups;
    struct simap ports;
    struct expr *expr;
    char *error;

    create_symtab(&symtab);
    create_addr_sets(&addr_sets);
    create_port_groups(&port_groups);

    simap_init(&ports);
    simap_put(&ports, "eth0", 5);
    simap_put(&ports, "eth1", 6);
    simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL));
    simap_put(&ports, "lsp1", 0x11);
    simap_put(&ports, "lsp2", 0x12);
    simap_put(&ports, "lsp3", 0x13);

    expr = expr_parse_string(input, &symtab, &addr_sets,
                             &port_groups, &error);
    if (!error) {
        expr = expr_annotate(expr, &symtab, &error);
    }
    if (!error) {
        expr = expr_simplify(expr, is_chassis_resident_cb, &ports);
        expr = expr_normalize(expr);
        ovs_assert(expr_is_normalized(expr));
    }
    if (!error) {
        struct hmap matches;

        expr_to_matches(expr, lookup_port_cb, &ports, &matches);
        expr_matches_print(&matches, stdout);
        expr_matches_destroy(&matches);
    } else {
        puts(error);
        free(error);
    }
    expr_destroy(expr);
    simap_destroy(&ports);
    expr_symtab_destroy(&symtab);
    shash_destroy(&symtab);
    expr_const_sets_destroy(&addr_sets);
    shash_destroy(&addr_sets);
    expr_const_sets_destroy(&port_groups);
    shash_destroy(&port_groups);
}

static bool
lookup_atoi_cb(const void *aux OVS_UNUSED, const char *port_name,
               unsigned int *portp)
{
    *portp = atoi(port_name);
    return true;
}

static void
test_expr_to_packets(const char *input)
{
    struct shash symtab;
    create_symtab(&symtab);

    struct flow uflow;
    char *error = expr_parse_microflow(input, &symtab, NULL, NULL,
                                       lookup_atoi_cb, NULL, &uflow);
    if (error) {
        puts(error);
        free(error);
        expr_symtab_destroy(&symtab);
        shash_destroy(&symtab);
        return;
    }

    uint64_t packet_stub[128 / 8];
    struct dp_packet packet;
    dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
    flow_compose(&packet, &uflow, NULL, 64);

    struct ds output = DS_EMPTY_INITIALIZER;
    const uint8_t *buf = dp_packet_data(&packet);
    for (int i = 0; i < dp_packet_size(&packet); i++) {
        uint8_t val = buf[i];
        ds_put_format(&output, "%02"PRIx8, val);
    }
    puts(ds_cstr(&output));
    ds_destroy(&output);
    dp_packet_uninit(&packet);
    expr_symtab_destroy(&symtab);
    shash_destroy(&symtab);
}

int
LLVMFuzzerTestOneInput(const uint8_t *input_, size_t size)
{
    /* Bail out if we cannot construct at least a 1 char string. */
    const char *input = (const char *) input_;
    if (size < 2 || input[size - 1] != '\0' || strchr(input, '\n') ||
        strlen(input) != size - 1) {
        return 0;
    }

    /* Disable logging to avoid write to disk. */
    static bool isInit = false;
    if (!isInit) {
        vlog_set_verbosity("off");
        isInit = true;
    }

    /* Parse, annotate, simplify, normalize expr and convert to flows. */
    test_parse_expr(input);

    /* Parse actions. */
    test_parse_actions(input);

    /* Test OVN lexer. */
    test_lex(input);

    /* Expr to packets. */
    test_expr_to_packets(input);

    return 0;
}
コード例 #24
0
ファイル: test-odp.c プロジェクト: sumgarg/ovs
static int
parse_keys(bool wc_keys)
{
    int exit_code = 0;
    struct ds in;

    ds_init(&in);
    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    while (!ds_get_test_line(&in, stdin)) {
        enum odp_key_fitness fitness;
        struct ofpbuf odp_key;
        struct ofpbuf odp_mask;
        struct flow flow;
        struct ds out;
        int error;

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        ofpbuf_init(&odp_mask, 0);
        error = odp_flow_from_string(ds_cstr(&in), NULL,
                                     &odp_key, &odp_mask);
        if (error) {
            printf("odp_flow_from_string: error\n");
            goto next;
        }

        if (!wc_keys) {
            struct odp_flow_key_parms odp_parms = {
                .flow = &flow,
                .recirc = true,
            };

            /* Convert odp_key to flow. */
            fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
            switch (fitness) {
                case ODP_FIT_PERFECT:
                    break;

                case ODP_FIT_TOO_LITTLE:
                    printf("ODP_FIT_TOO_LITTLE: ");
                    break;

                case ODP_FIT_TOO_MUCH:
                    printf("ODP_FIT_TOO_MUCH: ");
                    break;

                case ODP_FIT_ERROR:
                    printf("odp_flow_key_to_flow: error\n");
                    goto next;
            }
            /* Convert cls_rule back to odp_key. */
            ofpbuf_uninit(&odp_key);
            ofpbuf_init(&odp_key, 0);
            odp_parms.odp_in_port = flow.in_port.odp_port;
            odp_flow_key_from_flow(&odp_parms, &odp_key);

            if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
                printf ("too long: %"PRIu32" > %d\n",
                        odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
                exit_code = 1;
            }
        }

        /* Convert odp_key to string. */
        ds_init(&out);
        if (wc_keys) {
            odp_flow_format(odp_key.data, odp_key.size,
                            odp_mask.data, odp_mask.size, NULL, &out, false);
        } else {
            odp_flow_key_format(odp_key.data, odp_key.size, &out);
        }
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
    }
    ds_destroy(&in);

    return exit_code;
}

static int
parse_actions(void)
{
    struct ds in;

    ds_init(&in);
    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    while (!ds_get_test_line(&in, stdin)) {
        struct ofpbuf odp_actions;
        struct ds out;
        int error;

        /* Convert string to OVS DP actions. */
        ofpbuf_init(&odp_actions, 0);
        error = odp_actions_from_string(ds_cstr(&in), NULL, &odp_actions);
        if (error) {
            printf("odp_actions_from_string: error\n");
            goto next;
        }

        /* Convert odp_actions back to string. */
        ds_init(&out);
        format_odp_actions(&out, odp_actions.data, odp_actions.size);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_actions);
    }
    ds_destroy(&in);

    return 0;
}

static int
parse_filter(char *filter_parse)
{
    struct ds in;
    struct flow flow_filter;
    struct flow_wildcards wc_filter;
    char *error, *filter = NULL;

    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    if (filter_parse && !strncmp(filter_parse, "filter=", 7)) {
        filter = xstrdup(filter_parse + 7);
        memset(&flow_filter, 0, sizeof(flow_filter));
        memset(&wc_filter, 0, sizeof(wc_filter));

        error = parse_ofp_exact_flow(&flow_filter, &wc_filter.masks, filter,
                                     NULL);
        if (error) {
            ovs_fatal(0, "Failed to parse filter (%s)", error);
        }
    } else {
        ovs_fatal(0, "No filter to parse.");
    }

    ds_init(&in);
    while (!ds_get_test_line(&in, stdin)) {
        struct ofpbuf odp_key;
        struct ofpbuf odp_mask;
        struct ds out;
        int error;

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        ofpbuf_init(&odp_mask, 0);
        error = odp_flow_from_string(ds_cstr(&in), NULL,
                                     &odp_key, &odp_mask);
        if (error) {
            printf("odp_flow_from_string: error\n");
            goto next;
        }

        if (filter) {
            struct flow flow;
            struct flow_wildcards wc;
            struct match match, match_filter;
            struct minimatch minimatch;

            odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
            odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc.masks,
                                 &flow);
            match_init(&match, &flow, &wc);

            match_init(&match_filter, &flow_filter, &wc);
            match_init(&match_filter, &match_filter.flow, &wc_filter);
            minimatch_init(&minimatch, &match_filter);

            if (!minimatch_matches_flow(&minimatch, &match.flow)) {
                minimatch_destroy(&minimatch);
                goto next;
            }
            minimatch_destroy(&minimatch);
        }
        /* Convert odp_key to string. */
        ds_init(&out);
        odp_flow_format(odp_key.data, odp_key.size,
                        odp_mask.data, odp_mask.size, NULL, &out, false);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
        ofpbuf_uninit(&odp_mask);
    }
    ds_destroy(&in);

    free(filter);
    return 0;
}

static void
test_odp_main(int argc, char *argv[])
{
    int exit_code = 0;

    set_program_name(argv[0]);
    if (argc == 2 &&!strcmp(argv[1], "parse-keys")) {
        exit_code =parse_keys(false);
    } else if (argc == 2 &&!strcmp(argv[1], "parse-wc-keys")) {
        exit_code =parse_keys(true);
    } else if (argc == 2 && !strcmp(argv[1], "parse-actions")) {
        exit_code = parse_actions();
    } else if (argc == 3 && !strcmp(argv[1], "parse-filter")) {
        exit_code =parse_filter(argv[2]);
    } else {
        ovs_fatal(0, "usage: %s parse-keys | parse-wc-keys | parse-actions", argv[0]);
    }

    exit(exit_code);
}
コード例 #25
0
ファイル: test-odp.c プロジェクト: JScheurich/ovs
static int
parse_filter(char *filter_parse)
{
    struct ds in;
    struct flow flow_filter;
    struct flow_wildcards wc_filter;
    char *error, *filter = NULL;

    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    if (filter_parse && !strncmp(filter_parse, "filter=", 7)) {
        filter = xstrdup(filter_parse + 7);
        memset(&flow_filter, 0, sizeof(flow_filter));
        memset(&wc_filter, 0, sizeof(wc_filter));

        error = parse_ofp_exact_flow(&flow_filter, &wc_filter, NULL, filter,
                                     NULL);
        if (error) {
            ovs_fatal(0, "Failed to parse filter (%s)", error);
        }
    } else {
        ovs_fatal(0, "No filter to parse.");
    }

    ds_init(&in);
    while (!ds_get_test_line(&in, stdin)) {
        struct ofpbuf odp_key;
        struct ofpbuf odp_mask;
        struct ds out;

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        ofpbuf_init(&odp_mask, 0);
        if (odp_flow_from_string(ds_cstr(&in), NULL, &odp_key, &odp_mask)) {
            printf("odp_flow_from_string: error\n");
            goto next;
        }

        if (filter) {
            struct flow flow;
            struct flow_wildcards wc;
            struct match match, match_filter;
            struct minimatch minimatch;

            odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
            odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc, &flow);
            match_init(&match, &flow, &wc);

            match_init(&match_filter, &flow_filter, &wc);
            match_init(&match_filter, &match_filter.flow, &wc_filter);
            minimatch_init(&minimatch, &match_filter);

            if (!minimatch_matches_flow(&minimatch, &match.flow)) {
                minimatch_destroy(&minimatch);
                goto next;
            }
            minimatch_destroy(&minimatch);
        }
        /* Convert odp_key to string. */
        ds_init(&out);
        odp_flow_format(odp_key.data, odp_key.size,
                        odp_mask.data, odp_mask.size, NULL, &out, false);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
        ofpbuf_uninit(&odp_mask);
    }
    ds_destroy(&in);

    free(filter);
    return 0;
}
コード例 #26
0
ファイル: test-odp.c プロジェクト: crazyideas21/swclone
int
main(void)
{
    int exit_code = 0;
    struct ds in;

    ds_init(&in);
    vlog_set_levels_from_string("odp_util:console:dbg");
    while (!ds_get_line(&in, stdin)) {
        enum odp_key_fitness fitness;
        struct ofpbuf odp_key;
        struct flow flow;
        struct ds out;
        int error;
        char *s;

        /* Delete comments, skip blank lines. */
        s = ds_cstr(&in);
        if (*s == '#') {
            puts(s);
            continue;
        }
        if (strchr(s, '#')) {
            *strchr(s, '#') = '\0';
        }
        if (s[strspn(s, " ")] == '\0') {
            putchar('\n');
            continue;
        }

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        error = odp_flow_key_from_string(ds_cstr(&in), NULL, &odp_key);
        if (error) {
            printf("odp_flow_key_from_string: error\n");
            goto next;
        }

        /* Convert odp_key to flow. */
        fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
        switch (fitness) {
        case ODP_FIT_PERFECT:
            break;

        case ODP_FIT_TOO_LITTLE:
            printf("ODP_FIT_TOO_LITTLE: ");
            break;

        case ODP_FIT_TOO_MUCH:
            printf("ODP_FIT_TOO_MUCH: ");
            break;

        case ODP_FIT_ERROR:
            printf("odp_flow_key_to_flow: error\n");
            goto next;
        }

        /* Convert cls_rule back to odp_key. */
        ofpbuf_uninit(&odp_key);
        ofpbuf_init(&odp_key, 0);
        odp_flow_key_from_flow(&odp_key, &flow);

        if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
            printf ("too long: %zu > %d\n",
                    odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
            exit_code = 1;
        }

        /* Convert odp_key to string. */
        ds_init(&out);
        odp_flow_key_format(odp_key.data, odp_key.size, &out);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
    }
    ds_destroy(&in);

    return exit_code;
}
コード例 #27
0
static int
nl_sock_transact_multiple__(struct nl_sock *sock,
                            struct nl_transaction **transactions, size_t n,
                            size_t *done)
{
    uint64_t tmp_reply_stub[1024 / 8];
    struct nl_transaction tmp_txn;
    struct ofpbuf tmp_reply;

    uint32_t base_seq;
    struct iovec iovs[MAX_IOVS];
    struct msghdr msg;
    int error;
    int i;

    base_seq = nl_sock_allocate_seq(sock, n);
    *done = 0;
    for (i = 0; i < n; i++) {
        struct nl_transaction *txn = transactions[i];
        struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(txn->request);

        nlmsg->nlmsg_len = txn->request->size;
        nlmsg->nlmsg_seq = base_seq + i;
        nlmsg->nlmsg_pid = sock->pid;

        iovs[i].iov_base = txn->request->data;
        iovs[i].iov_len = txn->request->size;
    }

    memset(&msg, 0, sizeof msg);
    msg.msg_iov = iovs;
    msg.msg_iovlen = n;
    do {
        error = sendmsg(sock->fd, &msg, 0) < 0 ? errno : 0;
    } while (error == EINTR);

    for (i = 0; i < n; i++) {
        struct nl_transaction *txn = transactions[i];

        log_nlmsg(__func__, error, txn->request->data, txn->request->size,
                  sock->protocol);
    }
    if (!error) {
        COVERAGE_ADD(netlink_sent, n);
    }

    if (error) {
        return error;
    }

    ofpbuf_use_stub(&tmp_reply, tmp_reply_stub, sizeof tmp_reply_stub);
    tmp_txn.request = NULL;
    tmp_txn.reply = &tmp_reply;
    tmp_txn.error = 0;
    while (n > 0) {
        struct nl_transaction *buf_txn, *txn;
        uint32_t seq;

        /* Find a transaction whose buffer we can use for receiving a reply.
         * If no such transaction is left, use tmp_txn. */
        buf_txn = &tmp_txn;
        for (i = 0; i < n; i++) {
            if (transactions[i]->reply) {
                buf_txn = transactions[i];
                break;
            }
        }

        /* Receive a reply. */
        error = nl_sock_recv__(sock, buf_txn->reply, false);
        if (error) {
            if (error == EAGAIN) {
                nl_sock_record_errors__(transactions, n, 0);
                *done += n;
                error = 0;
            }
            break;
        }

        /* Match the reply up with a transaction. */
        seq = nl_msg_nlmsghdr(buf_txn->reply)->nlmsg_seq;
        if (seq < base_seq || seq >= base_seq + n) {
            VLOG_DBG_RL(&rl, "ignoring unexpected seq %#"PRIx32, seq);
            continue;
        }
        i = seq - base_seq;
        txn = transactions[i];

        /* Fill in the results for 'txn'. */
        if (nl_msg_nlmsgerr(buf_txn->reply, &txn->error)) {
            if (txn->reply) {
                ofpbuf_clear(txn->reply);
            }
            if (txn->error) {
                VLOG_DBG_RL(&rl, "received NAK error=%d (%s)",
                            error, ovs_strerror(txn->error));
            }
        } else {
            txn->error = 0;
            if (txn->reply && txn != buf_txn) {
                /* Swap buffers. */
                struct ofpbuf *reply = buf_txn->reply;
                buf_txn->reply = txn->reply;
                txn->reply = reply;
            }
        }

        /* Fill in the results for transactions before 'txn'.  (We have to do
         * this after the results for 'txn' itself because of the buffer swap
         * above.) */
        nl_sock_record_errors__(transactions, i, 0);

        /* Advance. */
        *done += i + 1;
        transactions += i + 1;
        n -= i + 1;
        base_seq += i + 1;
    }
    ofpbuf_uninit(&tmp_reply);

    return error;
}