static int nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, uint32_t nlmsg_seq, bool wait) { struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(msg); int error; nlmsg->nlmsg_len = ofpbuf_size(msg); nlmsg->nlmsg_seq = nlmsg_seq; nlmsg->nlmsg_pid = sock->pid; do { int retval; #ifdef _WIN32 bool result; DWORD last_error = 0; result = WriteFile(sock->handle, ofpbuf_data(msg), ofpbuf_size(msg), &retval, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { retval = -1; errno = EAGAIN; } #else retval = send(sock->fd, ofpbuf_data(msg), ofpbuf_size(msg), wait ? 0 : MSG_DONTWAIT); #endif error = retval < 0 ? errno : 0; } while (error == EINTR); log_nlmsg(__func__, error, ofpbuf_data(msg), ofpbuf_size(msg), sock->protocol); if (!error) { COVERAGE_INC(netlink_sent); } return error; }
/* Prefixes 'size' bytes to the head end of 'b', reallocating and copying its * data if necessary. Returns a pointer to the first byte of the data's * location in the ofpbuf. The new data is left uninitialized. */ void * ofpbuf_push_uninit(struct ofpbuf *b, size_t size) { ofpbuf_prealloc_headroom(b, size); ofpbuf_set_data(b, (char*)ofpbuf_data(b) - size); ofpbuf_set_size(b, ofpbuf_size(b) + size); return ofpbuf_data(b); }
/* Try connecting and sending a hello packet that has a bad version, which * should fail with EPROTO. */ static void test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); ((struct ofp_header *) ofpbuf_data(hello))->version = 0; test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO); ofpbuf_delete(hello); }
/* Shifts all of the data within the allocated space in 'b' by 'delta' bytes. * For example, a 'delta' of 1 would cause each byte of data to move one byte * forward (from address 'p' to 'p+1'), and a 'delta' of -1 would cause each * byte to move one byte backward (from 'p' to 'p-1'). */ void ofpbuf_shift(struct ofpbuf *b, int delta) { ovs_assert(delta > 0 ? delta <= ofpbuf_tailroom(b) : delta < 0 ? -delta <= ofpbuf_headroom(b) : true); if (delta != 0) { char *dst = (char *) ofpbuf_data(b) + delta; memmove(dst, ofpbuf_data(b), ofpbuf_size(b)); ofpbuf_set_data(b, dst); } }
/* Reallocates 'b' so that it has exactly 'new_headroom' and 'new_tailroom' * bytes of headroom and tailroom, respectively. */ static void ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom) { void *new_base, *new_data; size_t new_allocated; new_allocated = new_headroom + ofpbuf_size(b) + new_tailroom; switch (b->source) { case OFPBUF_DPDK: OVS_NOT_REACHED(); case OFPBUF_MALLOC: if (new_headroom == ofpbuf_headroom(b)) { new_base = xrealloc(ofpbuf_base(b), new_allocated); } else { new_base = xmalloc(new_allocated); ofpbuf_copy__(b, new_base, new_headroom, new_tailroom); free(ofpbuf_base(b)); } break; case OFPBUF_STACK: OVS_NOT_REACHED(); case OFPBUF_STUB: b->source = OFPBUF_MALLOC; new_base = xmalloc(new_allocated); ofpbuf_copy__(b, new_base, new_headroom, new_tailroom); break; default: OVS_NOT_REACHED(); } b->allocated = new_allocated; ofpbuf_set_base(b, new_base); new_data = (char *) new_base + new_headroom; if (ofpbuf_data(b) != new_data) { if (b->frame) { uintptr_t data_delta = (char *) new_data - (char *) ofpbuf_data(b); b->frame = (char *) b->frame + data_delta; } ofpbuf_set_data(b, new_data); } }
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, ofpbuf_data(&odp_actions), ofpbuf_size(&odp_actions)); puts(ds_cstr(&out)); ds_destroy(&out); next: ofpbuf_uninit(&odp_actions); } ds_destroy(&in); return 0; }
static int ssl_do_tx(struct stream *stream) { struct ssl_stream *sslv = ssl_stream_cast(stream); for (;;) { int old_state = SSL_get_state(sslv->ssl); int ret = SSL_write(sslv->ssl, ofpbuf_data(sslv->txbuf), ofpbuf_size(sslv->txbuf)); if (old_state != SSL_get_state(sslv->ssl)) { sslv->rx_want = SSL_NOTHING; } sslv->tx_want = SSL_NOTHING; if (ret > 0) { ofpbuf_pull(sslv->txbuf, ret); if (ofpbuf_size(sslv->txbuf) == 0) { return 0; } } else { int ssl_error = SSL_get_error(sslv->ssl, ret); if (ssl_error == SSL_ERROR_ZERO_RETURN) { VLOG_WARN_RL(&rl, "SSL_write: connection closed"); return EPIPE; } else { return interpret_ssl_error("SSL_write", ret, ssl_error, &sslv->tx_want); } } } }
static enum ofperr oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) { struct ofp11_match_header *omh = ofpbuf_data(b); uint8_t *p; uint16_t match_len; if (ofpbuf_size(b) < sizeof *omh) { return OFPERR_OFPBMC_BAD_LEN; } match_len = ntohs(omh->length); if (match_len < sizeof *omh) { return OFPERR_OFPBMC_BAD_LEN; } if (omh->type != htons(OFPMT_OXM)) { return OFPERR_OFPBMC_BAD_TYPE; } p = ofpbuf_try_pull(b, ROUND_UP(match_len, 8)); if (!p) { VLOG_DBG_RL(&rl, "oxm length %u, rounded up to a " "multiple of 8, is longer than space in message (max " "length %"PRIu32")", match_len, ofpbuf_size(b)); return OFPERR_OFPBMC_BAD_LEN; } return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh, strict, match, NULL, NULL); }
/* Performs periodic maintenance on 'rpc', such as flushing output buffers. */ void jsonrpc_run(struct jsonrpc *rpc) { if (rpc->status) { return; } stream_run(rpc->stream); while (!list_is_empty(&rpc->output)) { struct ofpbuf *buf = ofpbuf_from_list(rpc->output.next); int retval; retval = stream_send(rpc->stream, ofpbuf_data(buf), ofpbuf_size(buf)); if (retval >= 0) { rpc->backlog -= retval; ofpbuf_pull(buf, retval); if (!ofpbuf_size(buf)) { list_remove(&buf->list_node); rpc->output_count--; ofpbuf_delete(buf); } } else { if (retval != -EAGAIN) { VLOG_WARN_RL(&rl, "%s: send error: %s", rpc->name, ovs_strerror(-retval)); jsonrpc_error(rpc, -retval); } break; } } }
/* Reserves 'size' bytes of headroom so that they can be later allocated with * ofpbuf_push_uninit() without reallocating the ofpbuf. */ void ofpbuf_reserve(struct ofpbuf *b, size_t size) { ovs_assert(!ofpbuf_size(b)); ofpbuf_prealloc_tailroom(b, size); ofpbuf_set_data(b, (char*)ofpbuf_data(b) + size); }
/* Reserves 'headroom' bytes at the head and 'tailroom' at the end so that * they can be later allocated with ofpbuf_push_uninit() or * ofpbuf_put_uninit() without reallocating the ofpbuf. */ void ofpbuf_reserve_with_tailroom(struct ofpbuf *b, size_t headroom, size_t tailroom) { ovs_assert(!ofpbuf_size(b)); ofpbuf_prealloc_tailroom(b, headroom + tailroom); ofpbuf_set_data(b, (char*)ofpbuf_data(b) + headroom); }
/* Returns the data in 'b' as a block of malloc()'d memory and frees the buffer * within 'b'. (If 'b' itself was dynamically allocated, e.g. with * ofpbuf_new(), then it should still be freed with, e.g., ofpbuf_delete().) */ void * ofpbuf_steal_data(struct ofpbuf *b) { void *p; ovs_assert(b->source != OFPBUF_DPDK); if (b->source == OFPBUF_MALLOC && ofpbuf_data(b) == ofpbuf_base(b)) { p = ofpbuf_data(b); } else { p = xmemdup(ofpbuf_data(b), ofpbuf_size(b)); if (b->source == OFPBUF_MALLOC) { free(ofpbuf_base(b)); } } ofpbuf_set_base(b, NULL); ofpbuf_set_data(b, NULL); return p; }
/* 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; enum ofperr error; uint32_t vendor; struct ofpbuf b; if (payload) { memset(payload, 0, sizeof *payload); } /* Pull off the error message. */ ofpbuf_use_const(&b, oh, ntohs(oh->length)); 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, ofpbuf_size(&b)); ofpbuf_push(payload, ofpbuf_data(&b), ofpbuf_size(&b)); } return error; }
/* Try connecting and sending an echo request instead of a hello, which should * fail with EPROTO. */ static void test_send_echo_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *echo; echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, ofpbuf_data(echo), ofpbuf_size(echo), EPROTO); ofpbuf_delete(echo); }
/* Try connecting and sending a normal hello, which should succeed. */ static void test_send_plain_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); ofpbuf_delete(hello); }
/* Creates and returns a new ofpbuf whose data are copied from 'buffer'. The * returned ofpbuf will additionally have 'headroom' bytes of headroom. */ struct ofpbuf * ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom) { struct ofpbuf *new_buffer; new_buffer = ofpbuf_clone_data_with_headroom(ofpbuf_data(buffer), ofpbuf_size(buffer), headroom); if (buffer->frame) { uintptr_t data_delta = (char *)ofpbuf_data(new_buffer) - (char *)ofpbuf_data(buffer); new_buffer->frame = (char *) buffer->frame + data_delta; } new_buffer->l2_5_ofs = buffer->l2_5_ofs; new_buffer->l3_ofs = buffer->l3_ofs; new_buffer->l4_ofs = buffer->l4_ofs; return new_buffer; }
/* Returns a string that describes some of 'b''s metadata plus a hex dump of up * to 'maxbytes' from the start of the buffer. */ char * ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes) { struct ds s; ds_init(&s); ds_put_format(&s, "size=%"PRIu32", allocated=%"PRIu32", head=%"PRIuSIZE", tail=%"PRIuSIZE"\n", ofpbuf_size(b), b->allocated, ofpbuf_headroom(b), ofpbuf_tailroom(b)); ds_put_hex_dump(&s, ofpbuf_data(b), MIN(ofpbuf_size(b), maxbytes), 0, false); return ds_cstr(&s); }
/* Try connecting and sending an extra-long hello, which should succeed (since * the specification says that implementations must accept and ignore extra * data). */ static void test_send_long_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; enum { EXTRA_BYTES = 8 }; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), EXTRA_BYTES); ofpbuf_put_zeros(hello, EXTRA_BYTES); ofpmsg_update_length(hello); test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); ofpbuf_delete(hello); }
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); }
static int nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) { /* We can't accurately predict the size of the data to be received. The * caller is supposed to have allocated enough space in 'buf' to handle the * "typical" case. To handle exceptions, we make available enough space in * 'tail' to allow Netlink messages to be up to 64 kB long (a reasonable * figure since that's the maximum length of a Netlink attribute). */ struct nlmsghdr *nlmsghdr; #ifdef _WIN32 #define MAX_STACK_LENGTH 81920 uint8_t tail[MAX_STACK_LENGTH]; #else uint8_t tail[65536]; #endif struct iovec iov[2]; struct msghdr msg; ssize_t retval; int error; ovs_assert(buf->allocated >= sizeof *nlmsghdr); ofpbuf_clear(buf); iov[0].iov_base = ofpbuf_base(buf); iov[0].iov_len = buf->allocated; iov[1].iov_base = tail; iov[1].iov_len = sizeof tail; memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 2; /* Receive a Netlink message from the kernel. * * This works around a kernel bug in which the kernel returns an error code * as if it were the number of bytes read. It doesn't actually modify * anything in the receive buffer in that case, so we can initialize the * Netlink header with an impossible message length and then, upon success, * check whether it changed. */ nlmsghdr = ofpbuf_base(buf); do { nlmsghdr->nlmsg_len = UINT32_MAX; #ifdef _WIN32 boolean result = false; DWORD last_error = 0; result = ReadFile(sock->handle, tail, MAX_STACK_LENGTH, &retval, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { retval = -1; errno = EAGAIN; } else { ofpbuf_put(buf, tail, retval); } #else retval = recvmsg(sock->fd, &msg, wait ? 0 : MSG_DONTWAIT); #endif error = (retval < 0 ? errno : retval == 0 ? ECONNRESET /* not possible? */ : nlmsghdr->nlmsg_len != UINT32_MAX ? 0 : retval); } while (error == EINTR); if (error) { if (error == ENOBUFS) { /* Socket receive buffer overflow dropped one or more messages that * the kernel tried to send to us. */ COVERAGE_INC(netlink_overflow); } return error; } if (msg.msg_flags & MSG_TRUNC) { VLOG_ERR_RL(&rl, "truncated message (longer than %"PRIuSIZE" bytes)", sizeof tail); return E2BIG; } if (retval < sizeof *nlmsghdr || nlmsghdr->nlmsg_len < sizeof *nlmsghdr || nlmsghdr->nlmsg_len > retval) { VLOG_ERR_RL(&rl, "received invalid nlmsg (%"PRIuSIZE" bytes < %"PRIuSIZE")", retval, sizeof *nlmsghdr); return EPROTO; } #ifndef _WIN32 ofpbuf_set_size(buf, MIN(retval, buf->allocated)); if (retval > buf->allocated) { COVERAGE_INC(netlink_recv_jumbo); ofpbuf_put(buf, tail, retval - buf->allocated); } #endif log_nlmsg(__func__, 0, ofpbuf_data(buf), ofpbuf_size(buf), sock->protocol); COVERAGE_INC(netlink_received); return 0; }
static void test_netflow_main(int argc, char *argv[]) { struct unixctl_server *server; enum { MAX_RECV = 1500 }; const char *target; struct ofpbuf buf; bool exiting = false; int error; int sock; int n; proctitle_init(argc, argv); set_program_name(argv[0]); service_start(&argc, &argv); parse_options(argc, argv); if (argc - optind != 1) { ovs_fatal(0, "exactly one non-option argument required " "(use --help for help)"); } target = argv[optind]; sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true); if (sock < 0) { ovs_fatal(0, "%s: failed to open (%s)", argv[1], ovs_strerror(-sock)); } daemon_save_fd(STDOUT_FILENO); daemonize_start(); error = unixctl_server_create(NULL, &server); if (error) { ovs_fatal(error, "failed to create unixctl server"); } unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting); daemonize_complete(); ofpbuf_init(&buf, MAX_RECV); n = 0; for (;;) { int retval; unixctl_server_run(server); ofpbuf_clear(&buf); do { retval = recv(sock, ofpbuf_data(&buf), buf.allocated, 0); } while (retval < 0 && errno == EINTR); if (retval > 0) { ofpbuf_put_uninit(&buf, retval); if (n++ > 0) { putchar('\n'); } print_netflow(&buf); fflush(stdout); } if (exiting) { break; } poll_fd_wait(sock, POLLIN); unixctl_server_wait(server); poll_block(); } }
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 = strdup(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(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow); odp_flow_key_to_mask(ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), &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(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), 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 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 = ofpbuf_size(txn->request); nlmsg->nlmsg_seq = base_seq + i; nlmsg->nlmsg_pid = sock->pid; iovs[i].iov_base = ofpbuf_data(txn->request); iovs[i].iov_len = ofpbuf_size(txn->request); } memset(&msg, 0, sizeof msg); msg.msg_iov = iovs; msg.msg_iovlen = n; do { #ifdef _WIN32 DWORD last_error = 0; bool result = FALSE; for (i = 0; i < n; i++) { result = WriteFile((HANDLE)sock->handle, iovs[i].iov_base, iovs[i].iov_len, &error, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { error = EAGAIN; errno = EAGAIN; } else { error = 0; } } #else error = sendmsg(sock->fd, &msg, 0) < 0 ? errno : 0; #endif } while (error == EINTR); for (i = 0; i < n; i++) { struct nl_transaction *txn = transactions[i]; log_nlmsg(__func__, error, ofpbuf_data(txn->request), ofpbuf_size(txn->request), 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; }
/* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the * 'ofpacts' buffer. * * The caller has to actually execute 'fm'. */ void learn_execute(const struct ofpact_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts) { const struct ofpact_learn_spec *spec; match_init_catchall(&fm->match); fm->priority = learn->priority; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = learn->cookie; fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; fm->importance = 0; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { fm->flags |= OFPUTIL_FF_SEND_FLOW_REM; } fm->ofpacts = NULL; fm->ofpacts_len = 0; fm->delete_reason = OFPRR_DELETE; if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct ofpact_fin_timeout *oft; oft = ofpact_put_FIN_TIMEOUT(ofpacts); oft->fin_idle_timeout = learn->fin_idle_timeout; oft->fin_hard_timeout = learn->fin_hard_timeout; } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { struct ofpact_set_field *sf; union mf_subvalue value; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); } else { value = spec->src_imm; } switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); break; case NX_LEARN_DST_LOAD: sf = ofpact_put_reg_load(ofpacts); sf->field = spec->dst.field; bitwise_copy(&value, sizeof value, 0, &sf->value, spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); bitwise_one(&sf->mask, spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ovs_be16 *last_be16 = &value.be16[ARRAY_SIZE(value.be16) - 1]; ofp_port_t port = u16_to_ofp(ntohs(*last_be16)); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT || port == OFPP_FLOOD || port == OFPP_LOCAL || port == OFPP_ALL) { ofpact_put_OUTPUT(ofpacts)->port = port; } } break; } } ofpact_pad(ofpacts); fm->ofpacts = ofpbuf_data(ofpacts); fm->ofpacts_len = ofpbuf_size(ofpacts); }
/* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the * 'ofpacts' buffer. * * The caller has to actually execute 'fm'. */ void learn_execute(const struct ofpact_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts) { const struct ofpact_learn_spec *spec; match_init_catchall(&fm->match); fm->priority = learn->priority; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = htonll(learn->cookie); fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = learn->flags; fm->ofpacts = NULL; fm->ofpacts_len = 0; if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct ofpact_fin_timeout *oft; oft = ofpact_put_FIN_TIMEOUT(ofpacts); oft->fin_idle_timeout = learn->fin_idle_timeout; oft->fin_hard_timeout = learn->fin_hard_timeout; } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { union mf_subvalue value; int chunk, ofs; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); } else { value = spec->src_imm; } switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); break; case NX_LEARN_DST_LOAD: for (ofs = 0; ofs < spec->n_bits; ofs += chunk) { struct ofpact_reg_load *load; chunk = MIN(spec->n_bits - ofs, 64); load = ofpact_put_REG_LOAD(ofpacts); load->dst.field = spec->dst.field; load->dst.ofs = spec->dst.ofs + ofs; load->dst.n_bits = chunk; bitwise_copy(&value, sizeof value, ofs, &load->subvalue, sizeof load->subvalue, 0, chunk); } break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ofp_port_t port = u16_to_ofp(ntohs(value.be16[7])); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT || port == OFPP_FLOOD || port == OFPP_LOCAL || port == OFPP_ALL) { ofpact_put_OUTPUT(ofpacts)->port = port; } } break; } } ofpact_pad(ofpacts); fm->ofpacts = ofpbuf_data(ofpacts); fm->ofpacts_len = ofpbuf_size(ofpacts); }
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(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &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, NULL, flow.in_port.odp_port); if (ofpbuf_size(&odp_key) > ODPUTIL_FLOW_KEY_BYTES) { printf ("too long: %"PRIu32" > %d\n", ofpbuf_size(&odp_key), ODPUTIL_FLOW_KEY_BYTES); exit_code = 1; } } /* Convert odp_key to string. */ ds_init(&out); if (wc_keys) { odp_flow_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), NULL, &out, false); } else { odp_flow_key_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &out); } puts(ds_cstr(&out)); ds_destroy(&out); next: ofpbuf_uninit(&odp_key); } ds_destroy(&in); return exit_code; }