X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fnetdev.c;h=150f8d851be362ee532bc383122c97c49bdbed25;hb=e175dc83c5772438466bafb23a17ceb2e052e1c2;hp=fb176260a29c6d7f805c683734e800014f8e9b75;hpb=2f9dd77fcd172e2870d737ede67970836db3eb14;p=cascardo%2Fovs.git diff --git a/lib/netdev.c b/lib/netdev.c index fb176260a..150f8d851 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ #include "coverage.h" #include "dpif.h" +#include "dp-packet.h" #include "dynamic-string.h" #include "fatal-signal.h" #include "hash.h" @@ -33,15 +34,17 @@ #include "netdev-dpdk.h" #include "netdev-provider.h" #include "netdev-vport.h" -#include "ofpbuf.h" +#include "odp-netlink.h" #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" +#include "seq.h" #include "shash.h" #include "smap.h" #include "sset.h" #include "svec.h" -#include "vlog.h" +#include "openvswitch/vlog.h" +#include "flow.h" VLOG_DEFINE_THIS_MODULE(netdev); @@ -52,7 +55,7 @@ COVERAGE_DEFINE(netdev_get_stats); struct netdev_saved_flags { struct netdev *netdev; - struct list node; /* In struct netdev's saved_flags_list. */ + struct ovs_list node; /* In struct netdev's saved_flags_list. */ enum netdev_flags saved_flags; enum netdev_flags saved_values; }; @@ -103,11 +106,19 @@ netdev_n_rxq(const struct netdev *netdev) return netdev->n_rxq; } +int +netdev_requested_n_rxq(const struct netdev *netdev) +{ + return netdev->requested_n_rxq; +} + bool netdev_is_pmd(const struct netdev *netdev) { return (!strcmp(netdev->netdev_class->type, "dpdk") || - !strcmp(netdev->netdev_class->type, "dpdkr")); + !strcmp(netdev->netdev_class->type, "dpdkr") || + !strcmp(netdev->netdev_class->type, "dpdkvhostcuse") || + !strcmp(netdev->netdev_class->type, "dpdkvhostuser")); } static void @@ -143,6 +154,11 @@ netdev_initialize(void) #if defined(__FreeBSD__) || defined(__NetBSD__) netdev_register_provider(&netdev_tap_class); netdev_register_provider(&netdev_bsd_class); +#endif +#ifdef _WIN32 + netdev_register_provider(&netdev_windows_class); + netdev_register_provider(&netdev_internal_class); + netdev_vport_tunnel_register(); #endif netdev_dpdk_register(); @@ -248,6 +264,8 @@ netdev_unregister_provider(const char *type) struct netdev_registered_class *rc; int error; + netdev_initialize(); + ovs_mutex_lock(&netdev_class_mutex); rc = netdev_lookup_class(type); if (!rc) { @@ -364,6 +382,7 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp) /* By default enable one tx and rx queue per netdev. */ netdev->n_txq = netdev->netdev_class->send ? 1 : 0; netdev->n_rxq = netdev->netdev_class->rxq_alloc ? 1 : 0; + netdev->requested_n_rxq = netdev->n_rxq; list_init(&netdev->saved_flags_list); @@ -620,28 +639,28 @@ netdev_rxq_close(struct netdev_rxq *rx) } } -/* Attempts to receive batch of packets from 'rx'. - * - * Returns EAGAIN immediately if no packet is ready to be received. +/* Attempts to receive a batch of packets from 'rx'. 'pkts' should point to + * the beginning of an array of MAX_RX_BATCH pointers to dp_packet. If + * successful, this function stores pointers to up to MAX_RX_BATCH dp_packets + * into the array, transferring ownership of the packets to the caller, stores + * the number of received packets into '*cnt', and returns 0. * - * Returns EMSGSIZE, and discards the packet, if the received packet is longer - * than 'ofpbuf_tailroom(buffer)'. + * The implementation does not necessarily initialize any non-data members of + * 'pkts'. That is, the caller must initialize layer pointers and metadata + * itself, if desired, e.g. with pkt_metadata_init() and miniflow_extract(). * - * It is advised that the tailroom of 'buffer' should be - * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an - * out-of-band VLAN header to be added to the packet. At the very least, - * 'buffer' must have at least ETH_TOTAL_MIN bytes of tailroom. - * - * This function may be set to null if it would always return EOPNOTSUPP - * anyhow. */ + * Returns EAGAIN immediately if no packet is ready to be received or another + * positive errno value if an error was encountered. */ int -netdev_rxq_recv(struct netdev_rxq *rx, struct dpif_packet **buffers, int *cnt) +netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet **pkts, int *cnt) { int retval; - retval = rx->netdev->netdev_class->rxq_recv(rx, buffers, cnt); + retval = rx->netdev->netdev_class->rxq_recv(rx, pkts, cnt); if (!retval) { COVERAGE_INC(netdev_received); + } else { + *cnt = 0; } return retval; } @@ -663,6 +682,43 @@ netdev_rxq_drain(struct netdev_rxq *rx) : 0); } +/* Configures the number of tx queues and rx queues of 'netdev'. + * Return 0 if successful, otherwise a positive errno value. + * + * 'n_rxq' specifies the maximum number of receive queues to create. + * The netdev provider might choose to create less (e.g. if the hardware + * supports only a smaller number). The caller can check how many have been + * actually created by calling 'netdev_n_rxq()' + * + * 'n_txq' specifies the exact number of transmission queues to create. + * If this function returns successfully, the caller can make 'n_txq' + * concurrent calls to netdev_send() (each one with a different 'qid' in the + * range [0..'n_txq'-1]). + * + * On error, the tx queue and rx queue configuration is indeterminant. + * Caller should make decision on whether to restore the previous or + * the default configuration. Also, caller must make sure there is no + * other thread accessing the queues at the same time. */ +int +netdev_set_multiq(struct netdev *netdev, unsigned int n_txq, + unsigned int n_rxq) +{ + int error; + + error = (netdev->netdev_class->set_multiq + ? netdev->netdev_class->set_multiq(netdev, + MAX(n_txq, 1), + MAX(n_rxq, 1)) + : EOPNOTSUPP); + + if (error && error != EOPNOTSUPP) { + VLOG_DBG_RL(&rl, "failed to set tx/rx queue for network device %s:" + "%s", netdev_get_name(netdev), ovs_strerror(error)); + } + + return error; +} + /* Sends 'buffers' on 'netdev'. Returns 0 if successful (for every packet), * otherwise a positive errno value. Returns EAGAIN without blocking if * at least one the packets cannot be queued immediately. Returns EMSGSIZE @@ -672,7 +728,9 @@ netdev_rxq_drain(struct netdev_rxq *rx) * If the function returns a non-zero value, some of the packets might have * been sent anyway. * - * To retain ownership of 'buffer' caller can set may_steal to false. + * If 'may_steal' is false, the caller retains ownership of all the packets. + * If 'may_steal' is true, the caller transfers ownership of all the packets + * to the network device, regardless of success. * * The network device is expected to maintain one or more packet * transmission queues, so that the caller does not ordinarily have to @@ -683,20 +741,76 @@ 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, int qid, struct dpif_packet **buffers, +netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers, int cnt, bool may_steal) { - int error; + if (!netdev->netdev_class->send) { + if (may_steal) { + for (int i = 0; i < cnt; i++) { + dp_packet_delete(buffers[i]); + } + } + return EOPNOTSUPP; + } - error = (netdev->netdev_class->send - ? netdev->netdev_class->send(netdev, qid, buffers, cnt, may_steal) - : EOPNOTSUPP); + int error = netdev->netdev_class->send(netdev, qid, buffers, cnt, + may_steal); if (!error) { COVERAGE_INC(netdev_sent); } return error; } +int +netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt) +{ + int i; + + if (!netdev->netdev_class->pop_header) { + return EOPNOTSUPP; + } + + for (i = 0; i < cnt; i++) { + int err; + + err = netdev->netdev_class->pop_header(buffers[i]); + if (err) { + dp_packet_clear(buffers[i]); + } + } + + return 0; +} + +int +netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, + const struct flow *tnl_flow) +{ + if (netdev->netdev_class->build_header) { + return netdev->netdev_class->build_header(netdev, data, tnl_flow); + } + return EOPNOTSUPP; +} + +int +netdev_push_header(const struct netdev *netdev, + struct dp_packet **buffers, int cnt, + const struct ovs_action_push_tnl *data) +{ + int i; + + if (!netdev->netdev_class->push_header) { + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + netdev->netdev_class->push_header(buffers[i], data); + pkt_metadata_init(&buffers[i]->md, u32_to_odp(data->out_port)); + } + + return 0; +} + /* Registers with the poll loop to wake up from the next call to poll_block() * when the packet transmission queue has sufficient room to transmit a packet * with netdev_send(). @@ -717,7 +831,7 @@ netdev_send_wait(struct netdev *netdev, int qid) /* Attempts to set 'netdev''s MAC address to 'mac'. Returns 0 if successful, * otherwise a positive errno value. */ int -netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN]) +netdev_set_etheraddr(struct netdev *netdev, const struct eth_addr mac) { return netdev->netdev_class->set_etheraddr(netdev, mac); } @@ -726,7 +840,7 @@ netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN]) * the MAC address into 'mac'. On failure, returns a positive errno value and * clears 'mac' to all-zeros. */ int -netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN]) +netdev_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac) { return netdev->netdev_class->get_etheraddr(netdev, mac); } @@ -1160,13 +1274,13 @@ netdev_restore_flags(struct netdev_saved_flags *sf) * ENXIO indicates that there is no ARP table entry for 'ip' on 'netdev'. */ int netdev_arp_lookup(const struct netdev *netdev, - ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN]) + ovs_be32 ip, struct eth_addr *mac) { int error = (netdev->netdev_class->arp_lookup ? netdev->netdev_class->arp_lookup(netdev, ip, mac) : EOPNOTSUPP); if (error) { - memset(mac, 0, ETH_ADDR_LEN); + *mac = eth_addr_zero; } return error; } @@ -1701,6 +1815,12 @@ netdev_rxq_get_name(const struct netdev_rxq *rx) return netdev_get_name(netdev_rxq_get_netdev(rx)); } +int +netdev_rxq_get_queue_id(const struct netdev_rxq *rx) +{ + return rx->queue_id; +} + static void restore_all_flags(void *aux OVS_UNUSED) {