static void ind_ovs_handle_packet_miss(struct ind_ovs_upcall_thread *thread, struct ind_ovs_port *port, struct nl_msg *msg, struct nlattr **attrs) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = (void *)(nlh + 1); struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY]; struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET]; assert(key && packet); struct ind_ovs_parsed_key pkey; ind_ovs_parse_key(key, &pkey); /* Lookup the flow in the userspace flowtable. */ struct ind_ovs_flow *flow; if (ind_ovs_lookup_flow(&pkey, &flow) != 0) { ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key, OF_PACKET_IN_REASON_NO_MATCH); return; } /* Reuse the incoming message for the packet execute */ gnlh->cmd = OVS_PACKET_CMD_EXECUTE; ind_ovs_translate_actions(&pkey, flow->of_list_action, msg, OVS_PACKET_ATTR_ACTIONS); __sync_fetch_and_add(&flow->packets, 1); __sync_fetch_and_add(&flow->bytes, nla_len(packet)); /* Reuse the translated actions for adding the kflow. */ struct nlattr *actions = nlmsg_find_attr(nlmsg_hdr(msg), sizeof(struct genlmsghdr) + sizeof(struct ovs_header), OVS_PACKET_ATTR_ACTIONS); /* Don't send the packet back out if it would be dropped. */ if (nla_len(actions) > 0) { nlh->nlmsg_pid = 0; nlh->nlmsg_seq = 0; nlh->nlmsg_flags = NLM_F_REQUEST; struct iovec *iovec = &thread->tx_queue[thread->tx_queue_len++]; iovec->iov_base = nlh; iovec->iov_len = nlh->nlmsg_len; if (thread->log_upcalls) { LOG_VERBOSE("Sending upcall reply:"); ind_ovs_dump_msg(nlh); } } /* See the comment for ind_ovs_upcall_seen_key. */ if (ind_ovs_upcall_seen_key(thread, key)) { /* Create a kflow with the given key and actions. */ ind_ovs_bh_request_kflow(key, actions); } }
static void ind_ovs_handle_packet_miss(struct ind_ovs_upcall_thread *thread, struct ind_ovs_port *port, struct nl_msg *msg, struct nlattr **attrs) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = (void *)(nlh + 1); struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY]; struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET]; assert(key && packet); struct ind_ovs_parsed_key pkey; ind_ovs_parse_key(key, &pkey); struct pipeline_result *result = &thread->result; pipeline_result_reset(result); indigo_error_t err = pipeline_process(&pkey, result); if (err < 0) { return; } struct ind_ovs_flow_stats **stats_ptrs = xbuf_data(&result->stats); int num_stats_ptrs = xbuf_length(&result->stats) / sizeof(void *); int i; for (i = 0; i < num_stats_ptrs; i++) { struct ind_ovs_flow_stats *stats = stats_ptrs[i]; __sync_fetch_and_add(&stats->packets, 1); __sync_fetch_and_add(&stats->bytes, nla_len(packet)); } /* Check for a single controller action */ { uint32_t actions_length = xbuf_length(&result->actions); struct nlattr *first_action = xbuf_data(&result->actions); if (actions_length >= NLA_HDRLEN && actions_length == NLA_ALIGN(first_action->nla_len) && first_action->nla_type == IND_OVS_ACTION_CONTROLLER) { /* * The only action is sending the packet to the controller. * It's wasteful to send it all the way through the kernel * to be received as another upcall, so request a pktin * directly here. */ uint64_t userdata = *XBUF_PAYLOAD(first_action, uint64_t); ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key, IVS_PKTIN_REASON(userdata), IVS_PKTIN_METADATA(userdata)); return; } } /* Reuse the incoming message for the packet execute */ gnlh->cmd = OVS_PACKET_CMD_EXECUTE; struct nlattr *actions = nla_nest_start(msg, OVS_PACKET_ATTR_ACTIONS); ind_ovs_translate_actions(&pkey, &result->actions, msg); ind_ovs_nla_nest_end(msg, actions); /* Don't send the packet back out if it would be dropped. */ if (nla_len(actions) > 0) { nlh->nlmsg_pid = 0; nlh->nlmsg_seq = 0; nlh->nlmsg_flags = NLM_F_REQUEST; struct iovec *iovec = &thread->tx_queue[thread->tx_queue_len++]; iovec->iov_base = nlh; iovec->iov_len = nlh->nlmsg_len; if (thread->log_upcalls) { LOG_VERBOSE("Sending upcall reply:"); ind_ovs_dump_msg(nlh); } } /* See the comment for ind_ovs_upcall_seen_key. */ if (!ind_ovs_disable_kflows && ind_ovs_upcall_seen_key(thread, key)) { /* Create a kflow with the given key and actions. */ ind_ovs_bh_request_kflow(key); } }