diff --git a/dp-core/vr_flow.c b/dp-core/vr_flow.c index c8102f6f3..99e9348b9 100644 --- a/dp-core/vr_flow.c +++ b/dp-core/vr_flow.c @@ -775,7 +775,7 @@ vr_flow_action(struct vrouter *router, struct vr_flow_entry *fe, pkt_clone = vr_pclone(pkt); if (pkt_clone) { vr_preset(pkt_clone); - if (vr_pcow(pkt_clone, sizeof(struct vr_eth) + + if (vr_pcow(&pkt_clone, sizeof(struct vr_eth) + sizeof(struct agent_hdr))) { vr_pfree(pkt_clone, VP_DROP_PCOW_FAIL); } else { diff --git a/dp-core/vr_mirror.c b/dp-core/vr_mirror.c index 10d4de8be..7f539a050 100644 --- a/dp-core/vr_mirror.c +++ b/dp-core/vr_mirror.c @@ -437,7 +437,7 @@ vr_mirror(struct vrouter *router, uint8_t mirror_id, if (pkt_nh->nh_family == AF_INET) clone_len += pkt_nh->nh_encap_len; - if (vr_pcow(pkt, clone_len)) + if (vr_pcow(&pkt, clone_len)) goto fail; clone_len = 0; @@ -454,7 +454,7 @@ vr_mirror(struct vrouter *router, uint8_t mirror_id, vr_preset(pkt); if (clone_len) { - if (vr_pcow(pkt, clone_len)) + if (vr_pcow(&pkt, clone_len)) goto fail; } diff --git a/dp-core/vr_nexthop.c b/dp-core/vr_nexthop.c index 59d92adf8..f39d329a5 100644 --- a/dp-core/vr_nexthop.c +++ b/dp-core/vr_nexthop.c @@ -527,7 +527,7 @@ nh_mcast_clone(struct vr_packet *pkt, unsigned short head_room) } /* Increase the head space by the head_room */ - if (vr_pcow(clone_pkt, head_room)) { + if (vr_pcow(&clone_pkt, head_room)) { vr_pfree(clone_pkt, VP_DROP_PCOW_FAIL); return NULL; } diff --git a/dpdk/vr_dpdk_host.c b/dpdk/vr_dpdk_host.c index b42ef0d21..32d15803c 100644 --- a/dpdk/vr_dpdk_host.c +++ b/dpdk/vr_dpdk_host.c @@ -682,9 +682,31 @@ dpdk_pheader_pointer(struct vr_packet *pkt, unsigned short hdr_len, void *buf) /* VRouter callback */ static int -dpdk_pcow(struct vr_packet *pkt, unsigned short head_room) +dpdk_pcow(struct vr_packet **pktp, unsigned short head_room) { + struct vr_packet *pkt = *pktp; struct rte_mbuf *mbuf = vr_dpdk_pkt_to_mbuf(pkt); + struct rte_mbuf *m_copy; + struct vr_packet *p_copy; + + /* + * If this is an indirect mbuf, allocate a new mbuf and copy + * its data. Then free the original mbuf. + */ + if (RTE_MBUF_INDIRECT(mbuf)) { + m_copy = vr_dpdk_pktmbuf_copy(mbuf, mbuf->pool); + if (!m_copy) { + return -ENOMEM; + } + + p_copy = vr_dpdk_mbuf_to_pkt(m_copy); + *p_copy = *pkt; + p_copy->vp_head = m_copy->buf_addr; + + rte_pktmbuf_free(mbuf); + mbuf = m_copy; + *pktp = p_copy; + } if (head_room > rte_pktmbuf_headroom(mbuf)) { return -ENOMEM; diff --git a/freebsd/vrouter_mod.c b/freebsd/vrouter_mod.c index 0d0ad2b31..41b7a8b37 100644 --- a/freebsd/vrouter_mod.c +++ b/freebsd/vrouter_mod.c @@ -481,7 +481,7 @@ fh_pheader_pointer(struct vr_packet *pkt, unsigned short hdr_len, void *buf) } static int -fh_pcow(struct vr_packet *pkt, unsigned short head_room) +fh_pcow(struct vr_packet **pkt, unsigned short head_room) { vr_log(VR_ERR, "%s: not implemented\n", __func__); diff --git a/include/vrouter.h b/include/vrouter.h index 4df1d553c..75e8c8797 100644 --- a/include/vrouter.h +++ b/include/vrouter.h @@ -179,7 +179,7 @@ struct host_os { unsigned short, unsigned short *, int (*is_label_l2)(unsigned int, unsigned int, unsigned short *)); - int (*hos_pcow)(struct vr_packet *, unsigned short); + int (*hos_pcow)(struct vr_packet **, unsigned short); uint16_t (*hos_get_udp_src_port)(struct vr_packet *, struct vr_forwarding_md *, unsigned short); diff --git a/linux/vrouter_mod.c b/linux/vrouter_mod.c index 8ed1372f8..627eec3db 100644 --- a/linux/vrouter_mod.c +++ b/linux/vrouter_mod.c @@ -537,10 +537,11 @@ lh_put_defer_data(void *data) } static int -lh_pcow(struct vr_packet *pkt, unsigned short head_room) +lh_pcow(struct vr_packet **pktp, unsigned short head_room) { unsigned int old_off, new_off; int data_off = 0; + struct vr_packet *pkt = *pktp; struct sk_buff *skb = vp_os_packet(pkt);