static int vr_do_flow_action(struct vrouter *router, struct vr_flow_entry *fe, unsigned int index, struct vr_packet *pkt, unsigned short proto, struct vr_forwarding_md *fmd) { uint32_t new_stats; new_stats = __sync_add_and_fetch(&fe->fe_stats.flow_bytes, pkt_len(pkt)); if (new_stats < pkt_len(pkt)) fe->fe_stats.flow_bytes_oflow++; new_stats = __sync_add_and_fetch(&fe->fe_stats.flow_packets, 1); if (!new_stats) fe->fe_stats.flow_packets_oflow++; if (fe->fe_action == VR_FLOW_ACTION_HOLD) { if (vr_flow_queue_is_empty(router, fe)) { vr_trap_flow(router, fe, pkt, index); return vr_enqueue_flow(fe, pkt, proto, fmd); } else { vr_pfree(pkt, VP_DROP_FLOW_UNUSABLE); return 0; } } return vr_flow_action(router, fe, index, pkt, proto, fmd); }
static int vr_enqueue_flow(struct vrouter *router, struct vr_flow_entry *fe, struct vr_packet *pkt, unsigned int index, struct vr_forwarding_md *fmd) { unsigned int i; unsigned short drop_reason = 0; struct vr_flow_queue *vfq = fe->fe_hold_list; struct vr_packet_node *pnode; if (!vfq) { drop_reason = VP_DROP_FLOW_UNUSABLE; goto drop; } i = __sync_fetch_and_add(&vfq->vfq_entries, 1); if (i >= VR_MAX_FLOW_QUEUE_ENTRIES) { drop_reason = VP_DROP_FLOW_QUEUE_LIMIT_EXCEEDED; goto drop; } pnode = &vfq->vfq_pnodes[i]; /* * we cannot cache nexthop here. to cache, we need to hold reference * to the nexthop. to hold a reference, we will have to hold a lock, * which we cannot. the only known case of misbehavior if we do not * cache is ECMP. when the packet comes from the fabric, the nexthop * actually points to a local composite, whereas a route lookup actually * returns a different nexthop, in which case the ecmp index will return * a bad nexthop. to avoid that, we will cache the label, and reuse it */ if (pkt->vp_nh && (pkt->vp_nh->nh_type == NH_VRF_TRANSLATE) && (pkt->vp_nh->nh_flags & NH_FLAG_VNID)) pnode->pl_flags |= PN_FLAG_LABEL_IS_VNID; pkt->vp_nh = NULL; pnode->pl_vif_idx = pkt->vp_if->vif_idx; if (fmd) { pnode->pl_outer_src_ip = fmd->fmd_outer_src_ip; pnode->pl_label = fmd->fmd_label; if (fmd->fmd_to_me) pnode->pl_flags |= PN_FLAG_TO_ME; } __sync_synchronize(); pnode->pl_packet = pkt; if (!i) vr_trap_flow(router, fe, pkt, index); return 0; drop: vr_pfree(pkt, drop_reason); return 0; }