+ /* Now handle the packets individually in order of arrival. In the common
+ * case each packet of a miss can share the same actions, but slow-pathed
+ * packets need to be translated individually:
+ *
+ * - For SLOW_CFM, SLOW_LACP, SLOW_STP, and SLOW_BFD, translation is what
+ * processes received packets for these protocols.
+ *
+ * - For SLOW_CONTROLLER, translation sends the packet to the OpenFlow
+ * controller.
+ *
+ * The loop fills 'ops' with an array of operations to execute in the
+ * datapath. */
+ n_ops = 0;
+ for (i = 0; i < n_upcalls; i++) {
+ struct upcall *upcall = &upcalls[i];
+ struct flow_miss *miss = upcall->flow_miss;
+ struct ofpbuf *packet = &upcall->dpif_upcall.packet;
+ struct dpif_op *op;
+ ovs_be16 flow_vlan_tci;
+
+ /* Save a copy of flow.vlan_tci in case it is changed to
+ * generate proper mega flow masks for VLAN splinter flows. */
+ flow_vlan_tci = miss->flow.vlan_tci;
+
+ if (miss->xout.slow) {
+ struct xlate_in xin;
+
+ xlate_in_init(&xin, miss->ofproto, &miss->flow, NULL, 0, packet);
+ xlate_actions_for_side_effects(&xin);
+ }
+
+ if (miss->flow.in_port.ofp_port
+ != vsp_realdev_to_vlandev(miss->ofproto,
+ miss->flow.in_port.ofp_port,
+ miss->flow.vlan_tci)) {
+ /* This packet was received on a VLAN splinter port. We
+ * added a VLAN to the packet to make the packet resemble
+ * the flow, but the actions were composed assuming that
+ * the packet contained no VLAN. So, we must remove the
+ * VLAN header from the packet before trying to execute the
+ * actions. */
+ if (ofpbuf_size(&miss->xout.odp_actions)) {
+ eth_pop_vlan(packet);
+ }
+
+ /* Remove the flow vlan tags inserted by vlan splinter logic
+ * to ensure megaflow masks generated match the data path flow. */
+ miss->flow.vlan_tci = 0;
+ }
+
+ /* Do not install a flow into the datapath if:
+ *
+ * - The datapath already has too many flows.
+ *
+ * - An earlier iteration of this loop already put the same flow.
+ *
+ * - We received this packet via some flow installed in the kernel
+ * already. */
+ if (may_put
+ && !miss->put
+ && upcall->dpif_upcall.type == DPIF_UC_MISS) {
+ struct ofpbuf mask;
+ bool megaflow;
+
+ miss->put = true;
+
+ atomic_read(&enable_megaflows, &megaflow);
+ ofpbuf_use_stack(&mask, &miss->mask_buf, sizeof miss->mask_buf);
+ if (megaflow) {
+ size_t max_mpls;
+
+ max_mpls = ofproto_dpif_get_max_mpls_depth(miss->ofproto);
+ odp_flow_key_from_mask(&mask, &miss->xout.wc.masks,
+ &miss->flow, UINT32_MAX, max_mpls);
+ }
+
+ op = &ops[n_ops++];
+ op->type = DPIF_OP_FLOW_PUT;
+ op->u.flow_put.flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
+ op->u.flow_put.key = miss->key;
+ op->u.flow_put.key_len = miss->key_len;
+ op->u.flow_put.mask = ofpbuf_data(&mask);
+ op->u.flow_put.mask_len = ofpbuf_size(&mask);
+ op->u.flow_put.stats = NULL;
+
+ if (!miss->xout.slow) {
+ op->u.flow_put.actions = ofpbuf_data(&miss->xout.odp_actions);
+ op->u.flow_put.actions_len = ofpbuf_size(&miss->xout.odp_actions);
+ } else {
+ struct ofpbuf buf;
+
+ ofpbuf_use_stack(&buf, miss->slow_path_buf,
+ sizeof miss->slow_path_buf);
+ compose_slow_path(udpif, &miss->xout, &miss->flow,
+ miss->odp_in_port, &buf);
+ op->u.flow_put.actions = ofpbuf_data(&buf);
+ op->u.flow_put.actions_len = ofpbuf_size(&buf);
+ }
+ }
+
+ /*
+ * The 'miss' may be shared by multiple upcalls. Restore
+ * the saved flow vlan_tci field before processing the next
+ * upcall. */
+ miss->flow.vlan_tci = flow_vlan_tci;
+
+ if (ofpbuf_size(&miss->xout.odp_actions)) {
+
+ op = &ops[n_ops++];
+ op->type = DPIF_OP_EXECUTE;
+ op->u.execute.packet = packet;
+ odp_key_to_pkt_metadata(miss->key, miss->key_len,
+ &op->u.execute.md);
+ op->u.execute.actions = ofpbuf_data(&miss->xout.odp_actions);
+ op->u.execute.actions_len = ofpbuf_size(&miss->xout.odp_actions);
+ op->u.execute.needs_help = (miss->xout.slow & SLOW_ACTION) != 0;
+ }
+ }
+
+ /* Special case for fail-open mode.
+ *
+ * If we are in fail-open mode, but we are connected to a controller too,
+ * then we should send the packet up to the controller in the hope that it
+ * will try to set up a flow and thereby allow us to exit fail-open.
+ *
+ * See the top-level comment in fail-open.c for more information.
+ *
+ * Copy packets before they are modified by execution. */
+ if (fail_open) {
+ for (i = 0; i < n_upcalls; i++) {
+ struct upcall *upcall = &upcalls[i];
+ struct flow_miss *miss = upcall->flow_miss;
+ struct ofpbuf *packet = &upcall->dpif_upcall.packet;
+ struct ofproto_packet_in *pin;
+
+ pin = xmalloc(sizeof *pin);
+ pin->up.packet = xmemdup(ofpbuf_data(packet), ofpbuf_size(packet));
+ pin->up.packet_len = ofpbuf_size(packet);
+ pin->up.reason = OFPR_NO_MATCH;
+ pin->up.table_id = 0;
+ pin->up.cookie = OVS_BE64_MAX;
+ flow_get_metadata(&miss->flow, &pin->up.fmd);
+ pin->send_len = 0; /* Not used for flow table misses. */
+ pin->miss_type = OFPROTO_PACKET_IN_NO_MISS;
+ ofproto_dpif_send_packet_in(miss->ofproto, pin);
+ }
+ }
+
+ /* Execute batch. */
+ for (i = 0; i < n_ops; i++) {
+ opsp[i] = &ops[i];
+ }
+ dpif_operate(udpif->dpif, opsp, n_ops);
+}
+
+/* Must be called with udpif->ukeys[hash % udpif->n_revalidators].mutex. */
+static struct udpif_key *
+ukey_lookup__(struct udpif *udpif, const struct nlattr *key, size_t key_len,
+ uint32_t hash)
+{
+ struct udpif_key *ukey;
+ struct hmap *hmap = &udpif->ukeys[hash % udpif->n_revalidators].hmap;
+
+ HMAP_FOR_EACH_WITH_HASH (ukey, hmap_node, hash, hmap) {
+ if (ukey->key_len == key_len && !memcmp(ukey->key, key, key_len)) {
+ return ukey;
+ }
+ }