static void format_generic_odp_action(struct ds *ds, const struct nlattr *a) { size_t len = nl_attr_get_size(a); ds_put_format(ds, "action%"PRId16, nl_attr_type(a)); if (len) { const uint8_t *unspec; unsigned int i; unspec = nl_attr_get(a); for (i = 0; i < len; i++) { ds_put_char(ds, i ? ' ': '('); ds_put_format(ds, "%02x", unspec[i]); } ds_put_char(ds, ')'); } }
/* Tries to receive an openflow message from datapath 'dp_idx' on 'sock'. If * successful, stores the received message into '*msgp' and returns 0. The * caller is responsible for destroying the message with ofpbuf_delete(). On * failure, returns a positive errno value and stores a null pointer into * '*msgp'. * * Only Netlink messages with embedded OpenFlow messages are accepted. Other * Netlink messages provoke errors. * * If 'wait' is true, dpif_recv_openflow waits for a message to be ready; * otherwise, returns EAGAIN if the 'sock' receive buffer is empty. */ int dpif_recv_openflow(struct dpif *dp, int dp_idx, struct ofpbuf **bufferp, bool wait) { struct nlattr *attrs[ARRAY_SIZE(openflow_policy)]; struct ofpbuf *buffer; struct ofp_header *oh; uint16_t ofp_len; buffer = *bufferp = NULL; do { int retval; do { ofpbuf_delete(buffer); retval = nl_sock_recv(dp->sock, &buffer, wait); } while (retval == ENOBUFS || (!retval && (nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE || nl_msg_nlmsgerr(buffer, NULL)))); if (retval) { if (retval != EAGAIN) { VLOG_WARN_RL(&rl, "dpif_recv_openflow: %s", strerror(retval)); } return retval; } if (nl_msg_genlmsghdr(buffer) == NULL) { VLOG_DBG_RL(&rl, "received packet too short for Generic Netlink"); goto error; } if (nl_msg_nlmsghdr(buffer)->nlmsg_type != openflow_family) { VLOG_DBG_RL(&rl, "received type (%"PRIu16") != openflow family (%d)", nl_msg_nlmsghdr(buffer)->nlmsg_type, openflow_family); goto error; } if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, openflow_policy, attrs, ARRAY_SIZE(openflow_policy))) { goto error; } } while (nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]) != dp_idx); oh = buffer->data = (void *) nl_attr_get(attrs[DP_GENL_A_OPENFLOW]); buffer->size = nl_attr_get_size(attrs[DP_GENL_A_OPENFLOW]); ofp_len = ntohs(oh->length); if (ofp_len != buffer->size) { VLOG_WARN_RL(&rl, "ofp_header.length %"PRIu16" != attribute length %zu\n", ofp_len, buffer->size); buffer->size = MIN(ofp_len, buffer->size); } *bufferp = buffer; return 0; error: ofpbuf_delete(buffer); return EPROTO; }
return; } break; case OVS_SAMPLE_ATTR_ACTIONS: subactions = a; break; case OVS_SAMPLE_ATTR_UNSPEC: case __OVS_SAMPLE_ATTR_MAX: default: OVS_NOT_REACHED(); } } odp_execute_actions__(dp, &packet, 1, steal, md, nl_attr_get(subactions), nl_attr_get_size(subactions), dp_execute_action, more_actions); } static void odp_execute_actions__(void *dp, struct dpif_packet **packets, int cnt, bool steal, struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action, bool more_actions) { const struct nlattr *a; unsigned int left; int i;