diff --git a/lib/automake.mk b/lib/automake.mk index dc2ca0eb8..3f984d9bd 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -165,6 +165,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/ovsdb-parser.h \ lib/ovsdb-types.c \ lib/ovsdb-types.h \ + lib/packet-dpif.c \ + lib/packet-dpif.h \ lib/packets.c \ lib/packets.h \ lib/pcap-file.c \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 6c281fee6..32ef9698e 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -52,6 +52,7 @@ #include "ofp-print.h" #include "ofpbuf.h" #include "ovs-rcu.h" +#include "packet-dpif.h" #include "packets.h" #include "poll-loop.h" #include "random.h" @@ -337,11 +338,12 @@ static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *, const struct nlattr *userdata); static void dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *, - struct ofpbuf *, bool may_steal, + struct dpif_packet *, bool may_steal, struct pkt_metadata *, const struct nlattr *actions, size_t actions_len); -static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, +static void dp_netdev_port_input(struct dp_netdev *dp, + struct dpif_packet *packet, struct pkt_metadata *); static void dp_netdev_set_pmd_threads(struct dp_netdev *, int n); @@ -1522,6 +1524,7 @@ static int dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) { struct dp_netdev *dp = get_dp_netdev(dpif); + struct dpif_packet packet; struct pkt_metadata *md = &execute->md; struct { struct miniflow flow; @@ -1537,9 +1540,16 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) miniflow_initialize(&key.flow, key.buf); miniflow_extract(execute->packet, md, &key.flow); - dp_netdev_execute_actions(dp, &key.flow, execute->packet, false, md, + packet.ofpbuf = *execute->packet; + + dp_netdev_execute_actions(dp, &key.flow, &packet, false, md, execute->actions, execute->actions_len); + /* Even though may_steal is set to false, some actions could modify or + * reallocate the ofpbuf memory. We need to pass those changes to the + * caller */ + *execute->packet = packet.ofpbuf; + return 0; } @@ -1751,7 +1761,7 @@ dp_netdev_process_rxq_port(struct dp_netdev *dp, struct dp_netdev_port *port, struct netdev_rxq *rxq) { - struct ofpbuf *packet[NETDEV_MAX_RX_BATCH]; + struct dpif_packet *packet[NETDEV_MAX_RX_BATCH]; int error, c; error = netdev_rxq_recv(rxq, packet, &c); @@ -1993,27 +2003,28 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type) } static void -dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet, +dp_netdev_input(struct dp_netdev *dp, struct dpif_packet *packet, struct pkt_metadata *md) { struct dp_netdev_flow *netdev_flow; + struct ofpbuf *buf = &packet->ofpbuf; struct { struct miniflow flow; uint32_t buf[FLOW_U32S]; } key; - if (ofpbuf_size(packet) < ETH_HEADER_LEN) { - ofpbuf_delete(packet); + if (ofpbuf_size(buf) < ETH_HEADER_LEN) { + dpif_packet_delete(packet); return; } miniflow_initialize(&key.flow, key.buf); - miniflow_extract(packet, md, &key.flow); + miniflow_extract(buf, md, &key.flow); netdev_flow = dp_netdev_lookup_flow(dp, &key.flow); if (netdev_flow) { struct dp_netdev_actions *actions; - dp_netdev_flow_used(netdev_flow, packet, &key.flow); + dp_netdev_flow_used(netdev_flow, buf, &key.flow); actions = dp_netdev_flow_get_actions(netdev_flow); dp_netdev_execute_actions(dp, &key.flow, packet, true, md, @@ -2021,15 +2032,14 @@ dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet, dp_netdev_count_packet(dp, DP_STAT_HIT); } else if (dp->handler_queues) { dp_netdev_count_packet(dp, DP_STAT_MISS); - dp_netdev_output_userspace(dp, packet, - miniflow_hash_5tuple(&key.flow, 0) + dp_netdev_output_userspace(dp, buf, miniflow_hash_5tuple(&key.flow, 0) % dp->n_handlers, DPIF_UC_MISS, &key.flow, NULL); } } static void -dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, +dp_netdev_port_input(struct dp_netdev *dp, struct dpif_packet *packet, struct pkt_metadata *md) { uint32_t *recirc_depth = recirc_depth_get(); @@ -2099,7 +2109,7 @@ struct dp_netdev_execute_aux { }; static void -dp_execute_cb(void *aux_, struct ofpbuf *packet, +dp_execute_cb(void *aux_, struct dpif_packet *packet, struct pkt_metadata *md, const struct nlattr *a, bool may_steal) OVS_NO_THREAD_SAFETY_ANALYSIS @@ -2122,7 +2132,9 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, const struct nlattr *userdata; userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); - userspace_packet = may_steal ? packet : ofpbuf_clone(packet); + userspace_packet = may_steal + ? &packet->ofpbuf + : ofpbuf_clone(&packet->ofpbuf); dp_netdev_output_userspace(aux->dp, userspace_packet, miniflow_hash_5tuple(aux->key, 0) @@ -2157,9 +2169,9 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, case OVS_ACTION_ATTR_RECIRC: if (*depth < MAX_RECIRC_DEPTH) { struct pkt_metadata recirc_md = *md; - struct ofpbuf *recirc_packet; + struct dpif_packet *recirc_packet; - recirc_packet = may_steal ? packet : ofpbuf_clone(packet); + recirc_packet = may_steal ? packet : dpif_packet_clone(packet); recirc_md.recirc_id = nl_attr_get_u32(a); (*depth)++; @@ -2186,7 +2198,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, static void dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *key, - struct ofpbuf *packet, bool may_steal, + struct dpif_packet *packet, bool may_steal, struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len) { diff --git a/lib/dpif.c b/lib/dpif.c index cace47b0e..99d5a5263 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -34,6 +34,7 @@ #include "ofp-print.h" #include "ofp-util.h" #include "ofpbuf.h" +#include "packet-dpif.h" #include "packets.h" #include "poll-loop.h" #include "shash.h" @@ -1060,7 +1061,7 @@ struct dpif_execute_helper_aux { /* This is called for actions that need the context of the datapath to be * meaningful. */ static void -dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet, +dpif_execute_helper_cb(void *aux_, struct dpif_packet *packet, struct pkt_metadata *md, const struct nlattr *action, bool may_steal OVS_UNUSED) { @@ -1074,7 +1075,7 @@ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet, case OVS_ACTION_ATTR_RECIRC: execute.actions = action; execute.actions_len = NLA_ALIGN(action->nla_len); - execute.packet = packet; + execute.packet = &packet->ofpbuf; execute.md = *md; execute.needs_help = false; aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute); @@ -1102,12 +1103,20 @@ static int dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute) { struct dpif_execute_helper_aux aux = {dpif, 0}; + struct dpif_packet packet; COVERAGE_INC(dpif_execute_with_help); - odp_execute_actions(&aux, execute->packet, false, &execute->md, - execute->actions, execute->actions_len, - dpif_execute_helper_cb); + packet.ofpbuf = *execute->packet; + + odp_execute_actions(&aux, &packet, false, &execute->md, execute->actions, + execute->actions_len, dpif_execute_helper_cb); + + /* Even though may_steal is set to false, some actions could modify or + * reallocate the ofpbuf memory. We need to pass those changes to the + * caller */ + *execute->packet = packet.ofpbuf; + return aux.error; } diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index 35a8da4da..92838a5c1 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -54,6 +54,7 @@ #include "ofpbuf.h" #include "openflow/openflow.h" #include "ovs-thread.h" +#include "packet-dpif.h" #include "packets.h" #include "poll-loop.h" #include "shash.h" @@ -620,10 +621,12 @@ netdev_rxq_bsd_recv_tap(struct netdev_rxq_bsd *rxq, struct ofpbuf *buffer) } static int -netdev_bsd_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) +netdev_bsd_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **packets, + int *c) { struct netdev_rxq_bsd *rxq = netdev_rxq_bsd_cast(rxq_); struct netdev *netdev = rxq->up.netdev; + struct dpif_packet *packet; struct ofpbuf *buffer; ssize_t retval; int mtu; @@ -632,17 +635,19 @@ netdev_bsd_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) mtu = ETH_PAYLOAD_MAX; } - buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM); + packet = dpif_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, + DP_NETDEV_HEADROOM); + buffer = &packet->ofpbuf; retval = (rxq->pcap_handle ? netdev_rxq_bsd_recv_pcap(rxq, buffer) : netdev_rxq_bsd_recv_tap(rxq, buffer)); if (retval) { - ofpbuf_delete(buffer); + dpif_packet_delete(packet); } else { dp_packet_pad(buffer); - packet[0] = buffer; + packets[0] = packet; *c = 1; } return retval; @@ -681,12 +686,13 @@ netdev_bsd_rxq_drain(struct netdev_rxq *rxq_) * system or a tap device. */ static int -netdev_bsd_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal) +netdev_bsd_send(struct netdev *netdev_, struct dpif_packet *pkt, + bool may_steal) { struct netdev_bsd *dev = netdev_bsd_cast(netdev_); const char *name = netdev_get_name(netdev_); - const void *data = ofpbuf_data(pkt); - size_t size = ofpbuf_size(pkt); + const void *data = ofpbuf_data(&pkt->ofpbuf); + size_t size = ofpbuf_size(&pkt->ofpbuf); int error; ovs_mutex_lock(&dev->mutex); @@ -724,7 +730,7 @@ netdev_bsd_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal) ovs_mutex_unlock(&dev->mutex); if (may_steal) { - ofpbuf_delete(pkt); + dpif_packet_delete(pkt); } return error; diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index fb8d953b7..83b018e60 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -38,6 +38,7 @@ #include "ofpbuf.h" #include "ovs-thread.h" #include "ovs-rcu.h" +#include "packet-dpif.h" #include "packets.h" #include "shash.h" #include "sset.h" @@ -203,8 +204,9 @@ dpdk_rte_mzalloc(size_t sz) } void -free_dpdk_buf(struct ofpbuf *b) +free_dpdk_buf(struct dpif_packet *p) { + struct ofpbuf *b = &p->ofpbuf; struct rte_mbuf *pkt = (struct rte_mbuf *) b->dpdk_buf; rte_mempool_put(pkt->pool, pkt); @@ -217,16 +219,16 @@ __rte_pktmbuf_init(struct rte_mempool *mp, unsigned i OVS_UNUSED) { struct rte_mbuf *m = _m; - uint32_t buf_len = mp->elt_size - sizeof(struct ofpbuf); + uint32_t buf_len = mp->elt_size - sizeof(struct dpif_packet); - RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct ofpbuf)); + RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct dpif_packet)); memset(m, 0, mp->elt_size); /* start of buffer is just after mbuf structure */ - m->buf_addr = (char *)m + sizeof(struct ofpbuf); + m->buf_addr = (char *)m + sizeof(struct dpif_packet); m->buf_physaddr = rte_mempool_virt2phy(mp, m) + - sizeof(struct ofpbuf); + sizeof(struct dpif_packet); m->buf_len = (uint16_t)buf_len; /* keep some headroom between start of buffer and data */ @@ -586,7 +588,8 @@ dpdk_queue_flush(struct netdev_dpdk *dev, int qid) } static int -netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packets, int *c) +netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **packets, + int *c) { struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq_); struct netdev *netdev = rx->up.netdev; @@ -672,9 +675,10 @@ dpdk_do_tx_copy(struct netdev *netdev, char *buf, int size) static int netdev_dpdk_send(struct netdev *netdev, - struct ofpbuf *ofpbuf, bool may_steal) + struct dpif_packet *packet, bool may_steal) { struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + struct ofpbuf *ofpbuf = &packet->ofpbuf; int ret; if (ofpbuf_size(ofpbuf) > dev->max_packet_len) { @@ -693,7 +697,7 @@ netdev_dpdk_send(struct netdev *netdev, dpdk_do_tx_copy(netdev, (char *) ofpbuf_data(ofpbuf), ofpbuf_size(ofpbuf)); if (may_steal) { - ofpbuf_delete(ofpbuf); + dpif_packet_delete(packet); } } else { int qid; diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h index 280731076..f443a218b 100644 --- a/lib/netdev-dpdk.h +++ b/lib/netdev-dpdk.h @@ -4,6 +4,8 @@ #include #include "ofpbuf.h" +struct dpif_packet; + #ifdef DPDK_NETDEV #include @@ -20,7 +22,7 @@ int dpdk_init(int argc, char **argv); void netdev_dpdk_register(void); -void free_dpdk_buf(struct ofpbuf *); +void free_dpdk_buf(struct dpif_packet *); int pmd_thread_setaffinity_cpu(int cpu); #else @@ -38,7 +40,7 @@ netdev_dpdk_register(void) } static inline void -free_dpdk_buf(struct ofpbuf *buf OVS_UNUSED) +free_dpdk_buf(struct dpif_packet *buf OVS_UNUSED) { /* Nothing */ } diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index b087ed168..1a51533e8 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -29,6 +29,7 @@ #include "odp-util.h" #include "ofp-print.h" #include "ofpbuf.h" +#include "packet-dpif.h" #include "packets.h" #include "pcap-file.h" #include "poll-loop.h" @@ -779,7 +780,8 @@ netdev_dummy_rxq_dealloc(struct netdev_rxq *rxq_) } static int -netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **arr, int *c) +netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **arr, + int *c) { struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_); struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev); @@ -803,7 +805,10 @@ netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **arr, int *c) ovs_mutex_unlock(&netdev->mutex); dp_packet_pad(packet); - arr[0] = packet; + + /* This performs a (sometimes unnecessary) copy */ + arr[0] = dpif_packet_clone_from_ofpbuf(packet); + ofpbuf_delete(packet); *c = 1; return 0; } @@ -841,11 +846,12 @@ netdev_dummy_rxq_drain(struct netdev_rxq *rxq_) } static int -netdev_dummy_send(struct netdev *netdev, struct ofpbuf *pkt, bool may_steal) +netdev_dummy_send(struct netdev *netdev, struct dpif_packet *pkt, + bool may_steal) { struct netdev_dummy *dev = netdev_dummy_cast(netdev); - const void *buffer = ofpbuf_data(pkt); - size_t size = ofpbuf_size(pkt); + const void *buffer = ofpbuf_data(&pkt->ofpbuf); + size_t size = ofpbuf_size(&pkt->ofpbuf); if (size < ETH_HEADER_LEN) { return EMSGSIZE; @@ -881,7 +887,7 @@ netdev_dummy_send(struct netdev *netdev, struct ofpbuf *pkt, bool may_steal) ovs_mutex_unlock(&dev->mutex); if (may_steal) { - ofpbuf_delete(pkt); + dpif_packet_delete(pkt); } return 0; diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 840022d77..77a0299ec 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -62,6 +62,7 @@ #include "ofpbuf.h" #include "openflow/openflow.h" #include "ovs-atomic.h" +#include "packet-dpif.h" #include "packets.h" #include "poll-loop.h" #include "rtnetlink-link.h" @@ -984,10 +985,12 @@ netdev_linux_rxq_recv_tap(int fd, struct ofpbuf *buffer) } static int -netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) +netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **packets, + int *c) { struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_); struct netdev *netdev = rx->up.netdev; + struct dpif_packet *packet; struct ofpbuf *buffer; ssize_t retval; int mtu; @@ -996,7 +999,9 @@ netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) mtu = ETH_PAYLOAD_MAX; } - buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM); + packet = dpif_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, + DP_NETDEV_HEADROOM); + buffer = &packet->ofpbuf; retval = (rx->is_tap ? netdev_linux_rxq_recv_tap(rx->fd, buffer) @@ -1010,7 +1015,7 @@ netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) ofpbuf_delete(buffer); } else { dp_packet_pad(buffer); - packet[0] = buffer; + packets[0] = packet; *c = 1; } @@ -1052,10 +1057,11 @@ netdev_linux_rxq_drain(struct netdev_rxq *rxq_) * The kernel maintains a packet transmission queue, so the caller is not * expected to do additional queuing of packets. */ static int -netdev_linux_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal) +netdev_linux_send(struct netdev *netdev_, struct dpif_packet *pkt, + bool may_steal) { - const void *data = ofpbuf_data(pkt); - size_t size = ofpbuf_size(pkt); + const void *data = ofpbuf_data(&pkt->ofpbuf); + size_t size = ofpbuf_size(&pkt->ofpbuf); for (;;) { ssize_t retval; @@ -1108,7 +1114,7 @@ netdev_linux_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal) } if (may_steal) { - ofpbuf_delete(pkt); + dpif_packet_delete(pkt); } if (retval < 0) { diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 37b9da398..17109f75a 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -268,7 +268,8 @@ struct netdev_class { * network device from being usefully used by the netdev-based "userspace * datapath". It will also prevent the OVS implementation of bonding from * working properly over 'netdev'.) */ - int (*send)(struct netdev *netdev, struct ofpbuf *buffer, bool may_steal); + int (*send)(struct netdev *netdev, struct dpif_packet *buffer, + bool may_steal); /* Registers with the poll loop to wake up from the next call to * poll_block() when the packet transmission queue for 'netdev' has @@ -661,8 +662,8 @@ struct netdev_class { void (*rxq_destruct)(struct netdev_rxq *); void (*rxq_dealloc)(struct netdev_rxq *); - /* Attempts to receive batch of packets from 'rx' and place array of pointers - * into '*pkt'. netdev is responsible for allocating buffers. + /* Attempts to receive batch of packets from 'rx' and place array of + * pointers into '*pkts'. netdev is responsible for allocating buffers. * '*cnt' points to packet count for given batch. Once packets are returned * to caller, netdev should give up ownership of ofpbuf data. * @@ -672,7 +673,8 @@ struct netdev_class { * Caller is expected to pass array of size MAX_RX_BATCH. * This function may be set to null if it would always return EOPNOTSUPP * anyhow. */ - int (*rxq_recv)(struct netdev_rxq *rx, struct ofpbuf **pkt, int *cnt); + int (*rxq_recv)(struct netdev_rxq *rx, struct dpif_packet **pkts, + int *cnt); /* Registers with the poll loop to wake up from the next call to * poll_block() when a packet is ready to be received with netdev_rxq_recv() diff --git a/lib/netdev.c b/lib/netdev.c index 07cda42e5..aaafb1180 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -622,7 +622,7 @@ netdev_rxq_close(struct netdev_rxq *rx) * This function may be set to null if it would always return EOPNOTSUPP * anyhow. */ int -netdev_rxq_recv(struct netdev_rxq *rx, struct ofpbuf **buffers, int *cnt) +netdev_rxq_recv(struct netdev_rxq *rx, struct dpif_packet **buffers, int *cnt) { int retval; @@ -663,7 +663,7 @@ netdev_rxq_drain(struct netdev_rxq *rx) * Some network devices may not implement support for this function. In such * cases this function will always return EOPNOTSUPP. */ int -netdev_send(struct netdev *netdev, struct ofpbuf *buffer, bool may_steal) +netdev_send(struct netdev *netdev, struct dpif_packet *buffer, bool may_steal) { int error; diff --git a/lib/netdev.h b/lib/netdev.h index a4bd01a12..3a0b0d978 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -59,6 +59,7 @@ extern "C" { * netdev and access each of those from a different thread.) */ +struct dpif_packet; struct netdev; struct netdev_class; struct netdev_rxq; @@ -166,12 +167,13 @@ void netdev_rxq_close(struct netdev_rxq *); const char *netdev_rxq_get_name(const struct netdev_rxq *); -int netdev_rxq_recv(struct netdev_rxq *rx, struct ofpbuf **buffers, int *cnt); +int netdev_rxq_recv(struct netdev_rxq *rx, struct dpif_packet **buffers, + int *cnt); void netdev_rxq_wait(struct netdev_rxq *); int netdev_rxq_drain(struct netdev_rxq *); /* Packet transmission. */ -int netdev_send(struct netdev *, struct ofpbuf *, bool may_steal); +int netdev_send(struct netdev *, struct dpif_packet *, bool may_steal); void netdev_send_wait(struct netdev *); /* Hardware address. */ diff --git a/lib/odp-execute.c b/lib/odp-execute.c index cc185368c..4be799492 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -25,6 +25,7 @@ #include "netlink.h" #include "ofpbuf.h" #include "odp-util.h" +#include "packet-dpif.h" #include "packets.h" #include "flow.h" #include "unaligned.h" @@ -64,7 +65,7 @@ set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key) } static void -odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, +odp_execute_set_action(struct dpif_packet *packet, const struct nlattr *a, struct pkt_metadata *md) { enum ovs_key_attr type = nl_attr_type(a); @@ -88,44 +89,50 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, break; case OVS_KEY_ATTR_ETHERNET: - odp_eth_set_addrs(packet, + odp_eth_set_addrs(&packet->ofpbuf, nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); break; case OVS_KEY_ATTR_IPV4: ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); - packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst, - ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl); + packet_set_ipv4(&packet->ofpbuf, ipv4_key->ipv4_src, + ipv4_key->ipv4_dst, ipv4_key->ipv4_tos, + ipv4_key->ipv4_ttl); break; case OVS_KEY_ATTR_IPV6: ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6)); - packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src, - ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass, - ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit); + packet_set_ipv6(&packet->ofpbuf, ipv6_key->ipv6_proto, + ipv6_key->ipv6_src, ipv6_key->ipv6_dst, + ipv6_key->ipv6_tclass, ipv6_key->ipv6_label, + ipv6_key->ipv6_hlimit); break; case OVS_KEY_ATTR_TCP: tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp)); - packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst); + packet_set_tcp_port(&packet->ofpbuf, tcp_key->tcp_src, + tcp_key->tcp_dst); break; case OVS_KEY_ATTR_UDP: udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)); - packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst); + packet_set_udp_port(&packet->ofpbuf, udp_key->udp_src, + udp_key->udp_dst); break; case OVS_KEY_ATTR_SCTP: sctp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_sctp)); - packet_set_sctp_port(packet, sctp_key->sctp_src, sctp_key->sctp_dst); + packet_set_sctp_port(&packet->ofpbuf, sctp_key->sctp_src, + sctp_key->sctp_dst); break; case OVS_KEY_ATTR_MPLS: - set_mpls_lse(packet, nl_attr_get_be32(a)); + set_mpls_lse(&packet->ofpbuf, nl_attr_get_be32(a)); break; case OVS_KEY_ATTR_ARP: - set_arp(packet, nl_attr_get_unspec(a, sizeof(struct ovs_key_arp))); + set_arp(&packet->ofpbuf, + nl_attr_get_unspec(a, sizeof(struct ovs_key_arp))); break; case OVS_KEY_ATTR_DP_HASH: @@ -152,13 +159,13 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, } static void -odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, +odp_execute_actions__(void *dp, struct dpif_packet *packet, bool steal, struct pkt_metadata *, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action, bool more_actions); static void -odp_execute_sample(void *dp, struct ofpbuf *packet, bool steal, +odp_execute_sample(void *dp, struct dpif_packet *packet, bool steal, struct pkt_metadata *md, const struct nlattr *action, odp_execute_cb dp_execute_action, bool more_actions) { @@ -193,7 +200,7 @@ odp_execute_sample(void *dp, struct ofpbuf *packet, bool steal, } static void -odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, +odp_execute_actions__(void *dp, struct dpif_packet *packet, bool steal, struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action, bool more_actions) @@ -230,7 +237,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, struct flow flow; uint32_t hash; - flow_extract(packet, md, &flow); + flow_extract(&packet->ofpbuf, md, &flow); hash = flow_hash_5tuple(&flow, hash_act->hash_basis); md->dp_hash = hash ? hash : 1; } else { @@ -242,22 +249,24 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, case OVS_ACTION_ATTR_PUSH_VLAN: { const struct ovs_action_push_vlan *vlan = nl_attr_get(a); - eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci); + eth_push_vlan(&packet->ofpbuf, + htons(ETH_TYPE_VLAN), vlan->vlan_tci); break; } case OVS_ACTION_ATTR_POP_VLAN: - eth_pop_vlan(packet); + eth_pop_vlan(&packet->ofpbuf); break; case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nl_attr_get(a); - push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse); + push_mpls(&packet->ofpbuf, + mpls->mpls_ethertype, mpls->mpls_lse); break; } case OVS_ACTION_ATTR_POP_MPLS: - pop_mpls(packet, nl_attr_get_be16(a)); + pop_mpls(&packet->ofpbuf, nl_attr_get_be16(a)); break; case OVS_ACTION_ATTR_SET: @@ -277,7 +286,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, } void -odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, +odp_execute_actions(void *dp, struct dpif_packet *packet, bool steal, struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action) @@ -287,6 +296,6 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, if (!actions_len && steal) { /* Drop action. */ - ofpbuf_delete(packet); + dpif_packet_delete(packet); } } diff --git a/lib/odp-execute.h b/lib/odp-execute.h index 91f0c5183..1f836d51f 100644 --- a/lib/odp-execute.h +++ b/lib/odp-execute.h @@ -24,10 +24,10 @@ #include "openvswitch/types.h" struct nlattr; -struct ofpbuf; +struct dpif_packet; struct pkt_metadata; -typedef void (*odp_execute_cb)(void *dp, struct ofpbuf *packet, +typedef void (*odp_execute_cb)(void *dp, struct dpif_packet *packet, struct pkt_metadata *, const struct nlattr *action, bool may_steal); @@ -35,8 +35,8 @@ typedef void (*odp_execute_cb)(void *dp, struct ofpbuf *packet, * to 'dp_execute_action', if non-NULL. Currently this is called only for * actions OVS_ACTION_ATTR_OUTPUT and OVS_ACTION_ATTR_USERSPACE so * 'dp_execute_action' needs to handle only these. */ -void odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, - struct pkt_metadata *, - const struct nlattr *actions, size_t actions_len, - odp_execute_cb dp_execute_action); +void odp_execute_actions(void *dp, struct dpif_packet *packet, bool steal, + struct pkt_metadata *, + const struct nlattr *actions, size_t actions_len, + odp_execute_cb dp_execute_action); #endif diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c index 446593dfb..cc0d741da 100644 --- a/lib/ofpbuf.c +++ b/lib/ofpbuf.c @@ -140,7 +140,9 @@ ofpbuf_uninit(struct ofpbuf *b) } else if (b->source == OFPBUF_DPDK) { #ifdef DPDK_NETDEV ovs_assert(b != b->dpdk_buf); - free_dpdk_buf(b); + /* If this ofpbuf was allocated by DPDK it must have been + * created as a dpif_packet */ + free_dpdk_buf((struct dpif_packet*) b); #else ovs_assert(b->source != OFPBUF_DPDK); #endif diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h index 13a3e9de5..eed5ca8a9 100644 --- a/lib/ofpbuf.h +++ b/lib/ofpbuf.h @@ -176,7 +176,9 @@ static inline void ofpbuf_delete(struct ofpbuf *b) { if (b) { if (b->source == OFPBUF_DPDK) { - free_dpdk_buf(b); + /* If this ofpbuf was allocated by DPDK it must have been + * created as a dpif_packet */ + free_dpdk_buf((struct dpif_packet*) b); return; } diff --git a/lib/packet-dpif.c b/lib/packet-dpif.c new file mode 100644 index 000000000..cb871d8b3 --- /dev/null +++ b/lib/packet-dpif.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "packet-dpif.h" + +#include "ofpbuf.h" + +struct dpif_packet * +dpif_packet_new_with_headroom(size_t size, size_t headroom) +{ + struct dpif_packet *p = xmalloc(sizeof *p); + struct ofpbuf *b = &p->ofpbuf; + + ofpbuf_init(b, size + headroom); + ofpbuf_reserve(b, headroom); + + return p; +} + +struct dpif_packet * +dpif_packet_clone_from_ofpbuf(const struct ofpbuf *b) +{ + struct dpif_packet *p = xmalloc(sizeof *p); + size_t headroom = ofpbuf_headroom(b); + + ofpbuf_init(&p->ofpbuf, ofpbuf_size(b) + headroom); + ofpbuf_reserve(&p->ofpbuf, headroom); + + ofpbuf_put(&p->ofpbuf, ofpbuf_data(b), ofpbuf_size(b)); + + if (b->frame) { + uintptr_t data_delta + = (char *)ofpbuf_data(&p->ofpbuf) - (char *)ofpbuf_data(b); + + p->ofpbuf.frame = (char *) b->frame + data_delta; + } + p->ofpbuf.l2_5_ofs = b->l2_5_ofs; + p->ofpbuf.l3_ofs = b->l3_ofs; + p->ofpbuf.l4_ofs = b->l4_ofs; + + return p; +} + +struct dpif_packet * +dpif_packet_clone(struct dpif_packet *p) +{ + struct dpif_packet *newp; + + newp = dpif_packet_clone_from_ofpbuf(&p->ofpbuf); + + return newp; +} diff --git a/lib/packet-dpif.h b/lib/packet-dpif.h new file mode 100644 index 000000000..bb98c275c --- /dev/null +++ b/lib/packet-dpif.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PACKET_DPIF_H +#define PACKET_DPIF_H 1 + +#include "ofpbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* A packet received from a netdev and passed to a dpif. */ + +struct dpif_packet { + struct ofpbuf ofpbuf; /* Packet data. */ +}; + +struct dpif_packet *dpif_packet_new_with_headroom(size_t size, + size_t headroom); + +struct dpif_packet *dpif_packet_clone_from_ofpbuf(const struct ofpbuf *b); + +struct dpif_packet *dpif_packet_clone(struct dpif_packet *p); + +static inline void dpif_packet_delete(struct dpif_packet *p) +{ + struct ofpbuf *ofp = &p->ofpbuf; + + ofpbuf_delete(ofp); +} + +#ifdef __cplusplus +} +#endif + +#endif /* packet-dpif.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 71eaad156..a59173834 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -46,6 +46,7 @@ #include "ofproto/ofproto-dpif-sflow.h" #include "ofproto/ofproto-dpif.h" #include "ofproto/ofproto-provider.h" +#include "packet-dpif.h" #include "tunnel.h" #include "vlog.h" @@ -2643,7 +2644,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, uint16_t controller_id) { struct ofproto_packet_in *pin; - struct ofpbuf *packet; + struct dpif_packet *packet; struct pkt_metadata md = PKT_METADATA_INITIALIZER(0); ctx->xout->slow |= SLOW_CONTROLLER; @@ -2651,7 +2652,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, return; } - packet = ofpbuf_clone(ctx->xin->packet); + packet = dpif_packet_clone_from_ofpbuf(ctx->xin->packet); ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, @@ -2662,8 +2663,8 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ofpbuf_size(&ctx->xout->odp_actions), NULL); pin = xmalloc(sizeof *pin); - pin->up.packet_len = ofpbuf_size(packet); - pin->up.packet = ofpbuf_steal_data(packet); + pin->up.packet_len = ofpbuf_size(&packet->ofpbuf); + pin->up.packet = ofpbuf_steal_data(&packet->ofpbuf); pin->up.reason = reason; pin->up.table_id = ctx->table_id; pin->up.cookie = (ctx->rule @@ -2691,7 +2692,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, } } ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin); - ofpbuf_delete(packet); + dpif_packet_delete(packet); } static void