LCOV - code coverage report
Current view: top level - lib - netdev-linux.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 871 2187 39.8 %
Date: 2016-09-14 01:02:56 Functions: 118 235 50.2 %
Branches: 307 1096 28.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : 
      19                 :            : #include "netdev-linux.h"
      20                 :            : 
      21                 :            : #include <errno.h>
      22                 :            : #include <fcntl.h>
      23                 :            : #include <arpa/inet.h>
      24                 :            : #include <inttypes.h>
      25                 :            : #include <linux/filter.h>
      26                 :            : #include <linux/gen_stats.h>
      27                 :            : #include <linux/if_ether.h>
      28                 :            : #include <linux/if_tun.h>
      29                 :            : #include <linux/types.h>
      30                 :            : #include <linux/ethtool.h>
      31                 :            : #include <linux/mii.h>
      32                 :            : #include <linux/pkt_cls.h>
      33                 :            : #include <linux/pkt_sched.h>
      34                 :            : #include <linux/rtnetlink.h>
      35                 :            : #include <linux/sockios.h>
      36                 :            : #include <sys/types.h>
      37                 :            : #include <sys/ioctl.h>
      38                 :            : #include <sys/socket.h>
      39                 :            : #include <sys/utsname.h>
      40                 :            : #include <netpacket/packet.h>
      41                 :            : #include <net/if.h>
      42                 :            : #include <net/if_arp.h>
      43                 :            : #include <net/if_packet.h>
      44                 :            : #include <net/route.h>
      45                 :            : #include <netinet/in.h>
      46                 :            : #include <poll.h>
      47                 :            : #include <stdlib.h>
      48                 :            : #include <string.h>
      49                 :            : #include <unistd.h>
      50                 :            : 
      51                 :            : #include "coverage.h"
      52                 :            : #include "dp-packet.h"
      53                 :            : #include "dpif-netlink.h"
      54                 :            : #include "dpif-netdev.h"
      55                 :            : #include "openvswitch/dynamic-string.h"
      56                 :            : #include "fatal-signal.h"
      57                 :            : #include "hash.h"
      58                 :            : #include "openvswitch/hmap.h"
      59                 :            : #include "netdev-provider.h"
      60                 :            : #include "netdev-vport.h"
      61                 :            : #include "netlink-notifier.h"
      62                 :            : #include "netlink-socket.h"
      63                 :            : #include "netlink.h"
      64                 :            : #include "openvswitch/ofpbuf.h"
      65                 :            : #include "openflow/openflow.h"
      66                 :            : #include "ovs-atomic.h"
      67                 :            : #include "packets.h"
      68                 :            : #include "poll-loop.h"
      69                 :            : #include "rtnetlink.h"
      70                 :            : #include "openvswitch/shash.h"
      71                 :            : #include "socket-util.h"
      72                 :            : #include "sset.h"
      73                 :            : #include "timer.h"
      74                 :            : #include "unaligned.h"
      75                 :            : #include "openvswitch/vlog.h"
      76                 :            : #include "util.h"
      77                 :            : 
      78                 :      20190 : VLOG_DEFINE_THIS_MODULE(netdev_linux);
      79                 :            : 
      80                 :      98358 : COVERAGE_DEFINE(netdev_set_policing);
      81                 :      92814 : COVERAGE_DEFINE(netdev_arp_lookup);
      82                 :      94890 : COVERAGE_DEFINE(netdev_get_ifindex);
      83                 :     109716 : COVERAGE_DEFINE(netdev_get_hwaddr);
      84                 :      93468 : COVERAGE_DEFINE(netdev_set_hwaddr);
      85                 :      99984 : COVERAGE_DEFINE(netdev_get_ethtool);
      86                 :      93720 : COVERAGE_DEFINE(netdev_set_ethtool);
      87                 :            : 
      88                 :            : 
      89                 :            : /* These were introduced in Linux 2.6.14, so they might be missing if we have
      90                 :            :  * old headers. */
      91                 :            : #ifndef ADVERTISED_Pause
      92                 :            : #define ADVERTISED_Pause                (1 << 13)
      93                 :            : #endif
      94                 :            : #ifndef ADVERTISED_Asym_Pause
      95                 :            : #define ADVERTISED_Asym_Pause           (1 << 14)
      96                 :            : #endif
      97                 :            : 
      98                 :            : /* These were introduced in Linux 2.6.24, so they might be missing if we
      99                 :            :  * have old headers. */
     100                 :            : #ifndef ETHTOOL_GFLAGS
     101                 :            : #define ETHTOOL_GFLAGS       0x00000025 /* Get flags bitmap(ethtool_value) */
     102                 :            : #endif
     103                 :            : #ifndef ETHTOOL_SFLAGS
     104                 :            : #define ETHTOOL_SFLAGS       0x00000026 /* Set flags bitmap(ethtool_value) */
     105                 :            : #endif
     106                 :            : 
     107                 :            : /* This was introduced in Linux 2.6.25, so it might be missing if we have old
     108                 :            :  * headers. */
     109                 :            : #ifndef TC_RTAB_SIZE
     110                 :            : #define TC_RTAB_SIZE 1024
     111                 :            : #endif
     112                 :            : 
     113                 :            : /* Linux 2.6.21 introduced struct tpacket_auxdata.
     114                 :            :  * Linux 2.6.27 added the tp_vlan_tci member.
     115                 :            :  * Linux 3.0 defined TP_STATUS_VLAN_VALID.
     116                 :            :  * Linux 3.13 repurposed a padding member for tp_vlan_tpid and defined
     117                 :            :  * TP_STATUS_VLAN_TPID_VALID.
     118                 :            :  *
     119                 :            :  * With all this churn it's easiest to unconditionally define a replacement
     120                 :            :  * structure that has everything we want.
     121                 :            :  */
     122                 :            : #ifndef PACKET_AUXDATA
     123                 :            : #define PACKET_AUXDATA                  8
     124                 :            : #endif
     125                 :            : #ifndef TP_STATUS_VLAN_VALID
     126                 :            : #define TP_STATUS_VLAN_VALID            (1 << 4)
     127                 :            : #endif
     128                 :            : #ifndef TP_STATUS_VLAN_TPID_VALID
     129                 :            : #define TP_STATUS_VLAN_TPID_VALID       (1 << 6)
     130                 :            : #endif
     131                 :            : #undef tpacket_auxdata
     132                 :            : #define tpacket_auxdata rpl_tpacket_auxdata
     133                 :            : struct tpacket_auxdata {
     134                 :            :     uint32_t tp_status;
     135                 :            :     uint32_t tp_len;
     136                 :            :     uint32_t tp_snaplen;
     137                 :            :     uint16_t tp_mac;
     138                 :            :     uint16_t tp_net;
     139                 :            :     uint16_t tp_vlan_tci;
     140                 :            :     uint16_t tp_vlan_tpid;
     141                 :            : };
     142                 :            : 
     143                 :            : /* Linux 2.6.27 introduced ethtool_cmd_speed
     144                 :            :  *
     145                 :            :  * To avoid revisiting problems reported with using configure to detect
     146                 :            :  * compatibility (see report at
     147                 :            :  * http://openvswitch.org/pipermail/dev/2014-October/047978.html)
     148                 :            :  * unconditionally replace ethtool_cmd_speed. */
     149                 :            : #define ethtool_cmd_speed rpl_ethtool_cmd_speed
     150                 :        776 : static inline uint32_t rpl_ethtool_cmd_speed(const struct ethtool_cmd *ep)
     151                 :            : {
     152                 :        776 :         return ep->speed | (ep->speed_hi << 16);
     153                 :            : }
     154                 :            : 
     155                 :            : /* Linux 2.6.30 introduced supported and advertised flags for
     156                 :            :  * 1G base KX, and 10G base KX4, KR and R. */
     157                 :            : #ifndef SUPPORTED_1000baseKX_Full
     158                 :            : #define SUPPORTED_1000baseKX_Full      (1 << 17)
     159                 :            : #define SUPPORTED_10000baseKX4_Full    (1 << 18)
     160                 :            : #define SUPPORTED_10000baseKR_Full     (1 << 19)
     161                 :            : #define SUPPORTED_10000baseR_FEC       (1 << 20)
     162                 :            : #define ADVERTISED_1000baseKX_Full     (1 << 17)
     163                 :            : #define ADVERTISED_10000baseKX4_Full   (1 << 18)
     164                 :            : #define ADVERTISED_10000baseKR_Full    (1 << 19)
     165                 :            : #define ADVERTISED_10000baseR_FEC      (1 << 20)
     166                 :            : #endif
     167                 :            : 
     168                 :            : /* Linux 3.5 introduced supported and advertised flags for
     169                 :            :  * 40G base KR4, CR4, SR4 and LR4. */
     170                 :            : #ifndef SUPPORTED_40000baseKR4_Full
     171                 :            : #define SUPPORTED_40000baseKR4_Full    (1 << 23)
     172                 :            : #define SUPPORTED_40000baseCR4_Full    (1 << 24)
     173                 :            : #define SUPPORTED_40000baseSR4_Full    (1 << 25)
     174                 :            : #define SUPPORTED_40000baseLR4_Full    (1 << 26)
     175                 :            : #define ADVERTISED_40000baseKR4_Full   (1 << 23)
     176                 :            : #define ADVERTISED_40000baseCR4_Full   (1 << 24)
     177                 :            : #define ADVERTISED_40000baseSR4_Full   (1 << 25)
     178                 :            : #define ADVERTISED_40000baseLR4_Full   (1 << 26)
     179                 :            : #endif
     180                 :            : 
     181                 :            : /* Linux 2.6.35 introduced IFLA_STATS64 and rtnl_link_stats64.
     182                 :            :  *
     183                 :            :  * Tests for rtnl_link_stats64 don't seem to consistently work, e.g. on
     184                 :            :  * 2.6.32-431.29.2.el6.x86_64 (see report at
     185                 :            :  * http://openvswitch.org/pipermail/dev/2014-October/047978.html).  Maybe
     186                 :            :  * if_link.h is not self-contained on those kernels.  It is easiest to
     187                 :            :  * unconditionally define a replacement. */
     188                 :            : #ifndef IFLA_STATS64
     189                 :            : #define IFLA_STATS64 23
     190                 :            : #endif
     191                 :            : #define rtnl_link_stats64 rpl_rtnl_link_stats64
     192                 :            : struct rtnl_link_stats64 {
     193                 :            :     uint64_t rx_packets;
     194                 :            :     uint64_t tx_packets;
     195                 :            :     uint64_t rx_bytes;
     196                 :            :     uint64_t tx_bytes;
     197                 :            :     uint64_t rx_errors;
     198                 :            :     uint64_t tx_errors;
     199                 :            :     uint64_t rx_dropped;
     200                 :            :     uint64_t tx_dropped;
     201                 :            :     uint64_t multicast;
     202                 :            :     uint64_t collisions;
     203                 :            : 
     204                 :            :     uint64_t rx_length_errors;
     205                 :            :     uint64_t rx_over_errors;
     206                 :            :     uint64_t rx_crc_errors;
     207                 :            :     uint64_t rx_frame_errors;
     208                 :            :     uint64_t rx_fifo_errors;
     209                 :            :     uint64_t rx_missed_errors;
     210                 :            : 
     211                 :            :     uint64_t tx_aborted_errors;
     212                 :            :     uint64_t tx_carrier_errors;
     213                 :            :     uint64_t tx_fifo_errors;
     214                 :            :     uint64_t tx_heartbeat_errors;
     215                 :            :     uint64_t tx_window_errors;
     216                 :            : 
     217                 :            :     uint64_t rx_compressed;
     218                 :            :     uint64_t tx_compressed;
     219                 :            : };
     220                 :            : 
     221                 :            : enum {
     222                 :            :     VALID_IFINDEX           = 1 << 0,
     223                 :            :     VALID_ETHERADDR         = 1 << 1,
     224                 :            :     VALID_IN                = 1 << 2,
     225                 :            :     VALID_MTU               = 1 << 3,
     226                 :            :     VALID_POLICING          = 1 << 4,
     227                 :            :     VALID_VPORT_STAT_ERROR  = 1 << 5,
     228                 :            :     VALID_DRVINFO           = 1 << 6,
     229                 :            :     VALID_FEATURES          = 1 << 7,
     230                 :            : };
     231                 :            : 
     232                 :            : /* Traffic control. */
     233                 :            : 
     234                 :            : /* An instance of a traffic control class.  Always associated with a particular
     235                 :            :  * network device.
     236                 :            :  *
     237                 :            :  * Each TC implementation subclasses this with whatever additional data it
     238                 :            :  * needs. */
     239                 :            : struct tc {
     240                 :            :     const struct tc_ops *ops;
     241                 :            :     struct hmap queues;         /* Contains "struct tc_queue"s.
     242                 :            :                                  * Read by generic TC layer.
     243                 :            :                                  * Written only by TC implementation. */
     244                 :            : };
     245                 :            : 
     246                 :            : #define TC_INITIALIZER(TC, OPS) { OPS, HMAP_INITIALIZER(&(TC)->queues) }
     247                 :            : 
     248                 :            : /* One traffic control queue.
     249                 :            :  *
     250                 :            :  * Each TC implementation subclasses this with whatever additional data it
     251                 :            :  * needs. */
     252                 :            : struct tc_queue {
     253                 :            :     struct hmap_node hmap_node; /* In struct tc's "queues" hmap. */
     254                 :            :     unsigned int queue_id;      /* OpenFlow queue ID. */
     255                 :            :     long long int created;      /* Time queue was created, in msecs. */
     256                 :            : };
     257                 :            : 
     258                 :            : /* A particular kind of traffic control.  Each implementation generally maps to
     259                 :            :  * one particular Linux qdisc class.
     260                 :            :  *
     261                 :            :  * The functions below return 0 if successful or a positive errno value on
     262                 :            :  * failure, except where otherwise noted.  All of them must be provided, except
     263                 :            :  * where otherwise noted. */
     264                 :            : struct tc_ops {
     265                 :            :     /* Name used by kernel in the TCA_KIND attribute of tcmsg, e.g. "htb".
     266                 :            :      * This is null for tc_ops_default and tc_ops_other, for which there are no
     267                 :            :      * appropriate values. */
     268                 :            :     const char *linux_name;
     269                 :            : 
     270                 :            :     /* Name used in OVS database, e.g. "linux-htb".  Must be nonnull. */
     271                 :            :     const char *ovs_name;
     272                 :            : 
     273                 :            :     /* Number of supported OpenFlow queues, 0 for qdiscs that have no
     274                 :            :      * queues.  The queues are numbered 0 through n_queues - 1. */
     275                 :            :     unsigned int n_queues;
     276                 :            : 
     277                 :            :     /* Called to install this TC class on 'netdev'.  The implementation should
     278                 :            :      * make the Netlink calls required to set up 'netdev' with the right qdisc
     279                 :            :      * and configure it according to 'details'.  The implementation may assume
     280                 :            :      * that the current qdisc is the default; that is, there is no need for it
     281                 :            :      * to delete the current qdisc before installing itself.
     282                 :            :      *
     283                 :            :      * The contents of 'details' should be documented as valid for 'ovs_name'
     284                 :            :      * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
     285                 :            :      * (which is built as ovs-vswitchd.conf.db(8)).
     286                 :            :      *
     287                 :            :      * This function must return 0 if and only if it sets 'netdev->tc' to an
     288                 :            :      * initialized 'struct tc'.
     289                 :            :      *
     290                 :            :      * (This function is null for tc_ops_other, which cannot be installed.  For
     291                 :            :      * other TC classes it should always be nonnull.) */
     292                 :            :     int (*tc_install)(struct netdev *netdev, const struct smap *details);
     293                 :            : 
     294                 :            :     /* Called when the netdev code determines (through a Netlink query) that
     295                 :            :      * this TC class's qdisc is installed on 'netdev', but we didn't install
     296                 :            :      * it ourselves and so don't know any of the details.
     297                 :            :      *
     298                 :            :      * 'nlmsg' is the kernel reply to a RTM_GETQDISC Netlink message for
     299                 :            :      * 'netdev'.  The TCA_KIND attribute of 'nlmsg' is 'linux_name'.  The
     300                 :            :      * implementation should parse the other attributes of 'nlmsg' as
     301                 :            :      * necessary to determine its configuration.  If necessary it should also
     302                 :            :      * use Netlink queries to determine the configuration of queues on
     303                 :            :      * 'netdev'.
     304                 :            :      *
     305                 :            :      * This function must return 0 if and only if it sets 'netdev->tc' to an
     306                 :            :      * initialized 'struct tc'. */
     307                 :            :     int (*tc_load)(struct netdev *netdev, struct ofpbuf *nlmsg);
     308                 :            : 
     309                 :            :     /* Destroys the data structures allocated by the implementation as part of
     310                 :            :      * 'tc'.  (This includes destroying 'tc->queues' by calling
     311                 :            :      * tc_destroy(tc).
     312                 :            :      *
     313                 :            :      * The implementation should not need to perform any Netlink calls.  If
     314                 :            :      * desirable, the caller is responsible for deconfiguring the kernel qdisc.
     315                 :            :      * (But it may not be desirable.)
     316                 :            :      *
     317                 :            :      * This function may be null if 'tc' is trivial. */
     318                 :            :     void (*tc_destroy)(struct tc *tc);
     319                 :            : 
     320                 :            :     /* Retrieves details of 'netdev->tc' configuration into 'details'.
     321                 :            :      *
     322                 :            :      * The implementation should not need to perform any Netlink calls, because
     323                 :            :      * the 'tc_install' or 'tc_load' that instantiated 'netdev->tc' should have
     324                 :            :      * cached the configuration.
     325                 :            :      *
     326                 :            :      * The contents of 'details' should be documented as valid for 'ovs_name'
     327                 :            :      * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
     328                 :            :      * (which is built as ovs-vswitchd.conf.db(8)).
     329                 :            :      *
     330                 :            :      * This function may be null if 'tc' is not configurable.
     331                 :            :      */
     332                 :            :     int (*qdisc_get)(const struct netdev *netdev, struct smap *details);
     333                 :            : 
     334                 :            :     /* Reconfigures 'netdev->tc' according to 'details', performing any
     335                 :            :      * required Netlink calls to complete the reconfiguration.
     336                 :            :      *
     337                 :            :      * The contents of 'details' should be documented as valid for 'ovs_name'
     338                 :            :      * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
     339                 :            :      * (which is built as ovs-vswitchd.conf.db(8)).
     340                 :            :      *
     341                 :            :      * This function may be null if 'tc' is not configurable.
     342                 :            :      */
     343                 :            :     int (*qdisc_set)(struct netdev *, const struct smap *details);
     344                 :            : 
     345                 :            :     /* Retrieves details of 'queue' on 'netdev->tc' into 'details'.  'queue' is
     346                 :            :      * one of the 'struct tc_queue's within 'netdev->tc->queues'.
     347                 :            :      *
     348                 :            :      * The contents of 'details' should be documented as valid for 'ovs_name'
     349                 :            :      * in the "other_config" column in the "Queue" table in
     350                 :            :      * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
     351                 :            :      *
     352                 :            :      * The implementation should not need to perform any Netlink calls, because
     353                 :            :      * the 'tc_install' or 'tc_load' that instantiated 'netdev->tc' should have
     354                 :            :      * cached the queue configuration.
     355                 :            :      *
     356                 :            :      * This function may be null if 'tc' does not have queues ('n_queues' is
     357                 :            :      * 0). */
     358                 :            :     int (*class_get)(const struct netdev *netdev, const struct tc_queue *queue,
     359                 :            :                      struct smap *details);
     360                 :            : 
     361                 :            :     /* Configures or reconfigures 'queue_id' on 'netdev->tc' according to
     362                 :            :      * 'details', perfoming any required Netlink calls to complete the
     363                 :            :      * reconfiguration.  The caller ensures that 'queue_id' is less than
     364                 :            :      * 'n_queues'.
     365                 :            :      *
     366                 :            :      * The contents of 'details' should be documented as valid for 'ovs_name'
     367                 :            :      * in the "other_config" column in the "Queue" table in
     368                 :            :      * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
     369                 :            :      *
     370                 :            :      * This function may be null if 'tc' does not have queues or its queues are
     371                 :            :      * not configurable. */
     372                 :            :     int (*class_set)(struct netdev *, unsigned int queue_id,
     373                 :            :                      const struct smap *details);
     374                 :            : 
     375                 :            :     /* Deletes 'queue' from 'netdev->tc'.  'queue' is one of the 'struct
     376                 :            :      * tc_queue's within 'netdev->tc->queues'.
     377                 :            :      *
     378                 :            :      * This function may be null if 'tc' does not have queues or its queues
     379                 :            :      * cannot be deleted. */
     380                 :            :     int (*class_delete)(struct netdev *, struct tc_queue *queue);
     381                 :            : 
     382                 :            :     /* Obtains stats for 'queue' from 'netdev->tc'.  'queue' is one of the
     383                 :            :      * 'struct tc_queue's within 'netdev->tc->queues'.
     384                 :            :      *
     385                 :            :      * On success, initializes '*stats'.
     386                 :            :      *
     387                 :            :      * This function may be null if 'tc' does not have queues or if it cannot
     388                 :            :      * report queue statistics. */
     389                 :            :     int (*class_get_stats)(const struct netdev *netdev,
     390                 :            :                            const struct tc_queue *queue,
     391                 :            :                            struct netdev_queue_stats *stats);
     392                 :            : 
     393                 :            :     /* Extracts queue stats from 'nlmsg', which is a response to a
     394                 :            :      * RTM_GETTCLASS message, and passes them to 'cb' along with 'aux'.
     395                 :            :      *
     396                 :            :      * This function may be null if 'tc' does not have queues or if it cannot
     397                 :            :      * report queue statistics. */
     398                 :            :     int (*class_dump_stats)(const struct netdev *netdev,
     399                 :            :                             const struct ofpbuf *nlmsg,
     400                 :            :                             netdev_dump_queue_stats_cb *cb, void *aux);
     401                 :            : };
     402                 :            : 
     403                 :            : static void
     404                 :        233 : tc_init(struct tc *tc, const struct tc_ops *ops)
     405                 :            : {
     406                 :        233 :     tc->ops = ops;
     407                 :        233 :     hmap_init(&tc->queues);
     408                 :        233 : }
     409                 :            : 
     410                 :            : static void
     411                 :        233 : tc_destroy(struct tc *tc)
     412                 :            : {
     413                 :        233 :     hmap_destroy(&tc->queues);
     414                 :        233 : }
     415                 :            : 
     416                 :            : static const struct tc_ops tc_ops_htb;
     417                 :            : static const struct tc_ops tc_ops_hfsc;
     418                 :            : static const struct tc_ops tc_ops_codel;
     419                 :            : static const struct tc_ops tc_ops_fqcodel;
     420                 :            : static const struct tc_ops tc_ops_sfq;
     421                 :            : static const struct tc_ops tc_ops_default;
     422                 :            : static const struct tc_ops tc_ops_noop;
     423                 :            : static const struct tc_ops tc_ops_other;
     424                 :            : 
     425                 :            : static const struct tc_ops *const tcs[] = {
     426                 :            :     &tc_ops_htb,                /* Hierarchy token bucket (see tc-htb(8)). */
     427                 :            :     &tc_ops_hfsc,               /* Hierarchical fair service curve. */
     428                 :            :     &tc_ops_codel,              /* Controlled delay */
     429                 :            :     &tc_ops_fqcodel,            /* Fair queue controlled delay */
     430                 :            :     &tc_ops_sfq,                /* Stochastic fair queueing */
     431                 :            :     &tc_ops_noop,               /* Non operating qos type. */
     432                 :            :     &tc_ops_default,            /* Default qdisc (see tc-pfifo_fast(8)). */
     433                 :            :     &tc_ops_other,              /* Some other qdisc. */
     434                 :            :     NULL
     435                 :            : };
     436                 :            : 
     437                 :            : static unsigned int tc_make_handle(unsigned int major, unsigned int minor);
     438                 :            : static unsigned int tc_get_major(unsigned int handle);
     439                 :            : static unsigned int tc_get_minor(unsigned int handle);
     440                 :            : 
     441                 :            : static unsigned int tc_ticks_to_bytes(unsigned int rate, unsigned int ticks);
     442                 :            : static unsigned int tc_bytes_to_ticks(unsigned int rate, unsigned int size);
     443                 :            : static unsigned int tc_buffer_per_jiffy(unsigned int rate);
     444                 :            : 
     445                 :            : static struct tcmsg *tc_make_request(const struct netdev *, int type,
     446                 :            :                                      unsigned int flags, struct ofpbuf *);
     447                 :            : static int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp);
     448                 :            : static int tc_add_del_ingress_qdisc(struct netdev *netdev, bool add);
     449                 :            : static int tc_add_policer(struct netdev *,
     450                 :            :                           uint32_t kbits_rate, uint32_t kbits_burst);
     451                 :            : 
     452                 :            : static int tc_parse_qdisc(const struct ofpbuf *, const char **kind,
     453                 :            :                           struct nlattr **options);
     454                 :            : static int tc_parse_class(const struct ofpbuf *, unsigned int *queue_id,
     455                 :            :                           struct nlattr **options,
     456                 :            :                           struct netdev_queue_stats *);
     457                 :            : static int tc_query_class(const struct netdev *,
     458                 :            :                           unsigned int handle, unsigned int parent,
     459                 :            :                           struct ofpbuf **replyp);
     460                 :            : static int tc_delete_class(const struct netdev *, unsigned int handle);
     461                 :            : 
     462                 :            : static int tc_del_qdisc(struct netdev *netdev);
     463                 :            : static int tc_query_qdisc(const struct netdev *netdev);
     464                 :            : 
     465                 :            : static int tc_calc_cell_log(unsigned int mtu);
     466                 :            : static void tc_fill_rate(struct tc_ratespec *rate, uint64_t bps, int mtu);
     467                 :            : static void tc_put_rtab(struct ofpbuf *, uint16_t type,
     468                 :            :                         const struct tc_ratespec *rate);
     469                 :            : static int tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes);
     470                 :            : 
     471                 :            : struct netdev_linux {
     472                 :            :     struct netdev up;
     473                 :            : 
     474                 :            :     /* Protects all members below. */
     475                 :            :     struct ovs_mutex mutex;
     476                 :            : 
     477                 :            :     unsigned int cache_valid;
     478                 :            : 
     479                 :            :     bool miimon;                    /* Link status of last poll. */
     480                 :            :     long long int miimon_interval;  /* Miimon Poll rate. Disabled if <= 0. */
     481                 :            :     struct timer miimon_timer;
     482                 :            : 
     483                 :            :     /* The following are figured out "on demand" only.  They are only valid
     484                 :            :      * when the corresponding VALID_* bit in 'cache_valid' is set. */
     485                 :            :     int ifindex;
     486                 :            :     struct eth_addr etheraddr;
     487                 :            :     int mtu;
     488                 :            :     unsigned int ifi_flags;
     489                 :            :     long long int carrier_resets;
     490                 :            :     uint32_t kbits_rate;        /* Policing data. */
     491                 :            :     uint32_t kbits_burst;
     492                 :            :     int vport_stats_error;      /* Cached error code from vport_get_stats().
     493                 :            :                                    0 or an errno value. */
     494                 :            :     int netdev_mtu_error;       /* Cached error code from SIOCGIFMTU or SIOCSIFMTU. */
     495                 :            :     int ether_addr_error;       /* Cached error code from set/get etheraddr. */
     496                 :            :     int netdev_policing_error;  /* Cached error code from set policing. */
     497                 :            :     int get_features_error;     /* Cached error code from ETHTOOL_GSET. */
     498                 :            :     int get_ifindex_error;      /* Cached error code from SIOCGIFINDEX. */
     499                 :            : 
     500                 :            :     enum netdev_features current;    /* Cached from ETHTOOL_GSET. */
     501                 :            :     enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */
     502                 :            :     enum netdev_features supported;  /* Cached from ETHTOOL_GSET. */
     503                 :            : 
     504                 :            :     struct ethtool_drvinfo drvinfo;  /* Cached from ETHTOOL_GDRVINFO. */
     505                 :            :     struct tc *tc;
     506                 :            : 
     507                 :            :     /* For devices of class netdev_tap_class only. */
     508                 :            :     int tap_fd;
     509                 :            : };
     510                 :            : 
     511                 :            : struct netdev_rxq_linux {
     512                 :            :     struct netdev_rxq up;
     513                 :            :     bool is_tap;
     514                 :            :     int fd;
     515                 :            : };
     516                 :            : 
     517                 :            : /* This is set pretty low because we probably won't learn anything from the
     518                 :            :  * additional log messages. */
     519                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
     520                 :            : 
     521                 :            : /* Polling miimon status for all ports causes performance degradation when
     522                 :            :  * handling a large number of ports. If there are no devices using miimon, then
     523                 :            :  * we skip netdev_linux_miimon_run() and netdev_linux_miimon_wait().
     524                 :            :  *
     525                 :            :  * Readers do not depend on this variable synchronizing with the related
     526                 :            :  * changes in the device miimon status, so we can use atomic_count. */
     527                 :            : static atomic_count miimon_cnt = ATOMIC_COUNT_INIT(0);
     528                 :            : 
     529                 :            : static void netdev_linux_run(const struct netdev_class *);
     530                 :            : 
     531                 :            : static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
     532                 :            :                                    int cmd, const char *cmd_name);
     533                 :            : static int get_flags(const struct netdev *, unsigned int *flags);
     534                 :            : static int set_flags(const char *, unsigned int flags);
     535                 :            : static int update_flags(struct netdev_linux *netdev, enum netdev_flags off,
     536                 :            :                         enum netdev_flags on, enum netdev_flags *old_flagsp)
     537                 :            :     OVS_REQUIRES(netdev->mutex);
     538                 :            : static int do_get_ifindex(const char *netdev_name);
     539                 :            : static int get_ifindex(const struct netdev *, int *ifindexp);
     540                 :            : static int do_set_addr(struct netdev *netdev,
     541                 :            :                        int ioctl_nr, const char *ioctl_name,
     542                 :            :                        struct in_addr addr);
     543                 :            : static int get_etheraddr(const char *netdev_name, struct eth_addr *ea);
     544                 :            : static int set_etheraddr(const char *netdev_name, const struct eth_addr);
     545                 :            : static int get_stats_via_netlink(const struct netdev *, struct netdev_stats *);
     546                 :            : static int af_packet_sock(void);
     547                 :            : static bool netdev_linux_miimon_enabled(void);
     548                 :            : static void netdev_linux_miimon_run(void);
     549                 :            : static void netdev_linux_miimon_wait(void);
     550                 :            : static int netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup);
     551                 :            : 
     552                 :            : static bool
     553                 :     285309 : is_netdev_linux_class(const struct netdev_class *netdev_class)
     554                 :            : {
     555                 :     285309 :     return netdev_class->run == netdev_linux_run;
     556                 :            : }
     557                 :            : 
     558                 :            : static bool
     559                 :       1548 : is_tap_netdev(const struct netdev *netdev)
     560                 :            : {
     561                 :       1548 :     return netdev_get_class(netdev) == &netdev_tap_class;
     562                 :            : }
     563                 :            : 
     564                 :            : static struct netdev_linux *
     565                 :     247830 : netdev_linux_cast(const struct netdev *netdev)
     566                 :            : {
     567         [ -  + ]:     247830 :     ovs_assert(is_netdev_linux_class(netdev_get_class(netdev)));
     568                 :            : 
     569                 :     247830 :     return CONTAINER_OF(netdev, struct netdev_linux, up);
     570                 :            : }
     571                 :            : 
     572                 :            : static struct netdev_rxq_linux *
     573                 :      35928 : netdev_rxq_linux_cast(const struct netdev_rxq *rx)
     574                 :            : {
     575         [ -  + ]:      35928 :     ovs_assert(is_netdev_linux_class(netdev_get_class(rx->netdev)));
     576                 :      35928 :     return CONTAINER_OF(rx, struct netdev_rxq_linux, up);
     577                 :            : }
     578                 :            : 
     579                 :            : static void netdev_linux_update(struct netdev_linux *netdev,
     580                 :            :                                 const struct rtnetlink_change *)
     581                 :            :     OVS_REQUIRES(netdev->mutex);
     582                 :            : static void netdev_linux_changed(struct netdev_linux *netdev,
     583                 :            :                                  unsigned int ifi_flags, unsigned int mask)
     584                 :            :     OVS_REQUIRES(netdev->mutex);
     585                 :            : 
     586                 :            : /* Returns a NETLINK_ROUTE socket listening for RTNLGRP_LINK,
     587                 :            :  * RTNLGRP_IPV4_IFADDR and RTNLGRP_IPV6_IFADDR changes, or NULL
     588                 :            :  * if no such socket could be created. */
     589                 :            : static struct nl_sock *
     590                 :     563416 : netdev_linux_notify_sock(void)
     591                 :            : {
     592                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     593                 :            :     static struct nl_sock *sock;
     594                 :     563416 :     unsigned int mcgroups[] = {RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR,
     595                 :            :                                 RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_IFINFO};
     596                 :            : 
     597         [ +  + ]:     563416 :     if (ovsthread_once_start(&once)) {
     598                 :            :         int error;
     599                 :            : 
     600                 :        616 :         error = nl_sock_create(NETLINK_ROUTE, &sock);
     601         [ +  - ]:        616 :         if (!error) {
     602                 :            :             size_t i;
     603                 :            : 
     604         [ +  + ]:       3080 :             for (i = 0; i < ARRAY_SIZE(mcgroups); i++) {
     605                 :       2464 :                 error = nl_sock_join_mcgroup(sock, mcgroups[i]);
     606         [ -  + ]:       2464 :                 if (error) {
     607                 :          0 :                     nl_sock_destroy(sock);
     608                 :          0 :                     sock = NULL;
     609                 :          0 :                     break;
     610                 :            :                 }
     611                 :            :             }
     612                 :            :         }
     613                 :        616 :         ovsthread_once_done(&once);
     614                 :            :     }
     615                 :            : 
     616                 :     563416 :     return sock;
     617                 :            : }
     618                 :            : 
     619                 :            : static bool
     620                 :     563416 : netdev_linux_miimon_enabled(void)
     621                 :            : {
     622                 :     563416 :     return atomic_count_get(&miimon_cnt) > 0;
     623                 :            : }
     624                 :            : 
     625                 :            : static void
     626                 :     281708 : netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED)
     627                 :            : {
     628                 :            :     struct nl_sock *sock;
     629                 :            :     int error;
     630                 :            : 
     631         [ -  + ]:     281708 :     if (netdev_linux_miimon_enabled()) {
     632                 :          0 :         netdev_linux_miimon_run();
     633                 :            :     }
     634                 :            : 
     635                 :     281708 :     sock = netdev_linux_notify_sock();
     636         [ -  + ]:     281708 :     if (!sock) {
     637                 :          0 :         return;
     638                 :            :     }
     639                 :            : 
     640                 :            :     do {
     641                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     642                 :            :         uint64_t buf_stub[4096 / 8];
     643                 :            :         struct ofpbuf buf;
     644                 :            : 
     645                 :     284383 :         ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
     646                 :     284383 :         error = nl_sock_recv(sock, &buf, false);
     647         [ +  + ]:     284383 :         if (!error) {
     648                 :            :             struct rtnetlink_change change;
     649                 :            : 
     650         [ +  - ]:       2675 :             if (rtnetlink_parse(&buf, &change)) {
     651                 :       2675 :                 struct netdev *netdev_ = NULL;
     652                 :            :                 char dev_name[IFNAMSIZ];
     653                 :            : 
     654         [ +  + ]:       2675 :                 if (!change.ifname) {
     655                 :        190 :                      change.ifname = if_indextoname(change.if_index, dev_name);
     656                 :            :                 }
     657                 :            : 
     658         [ +  - ]:       2675 :                 if (change.ifname) {
     659                 :       2675 :                     netdev_ = netdev_from_name(change.ifname);
     660                 :            :                 }
     661 [ +  + ][ +  - ]:       2675 :                 if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
     662                 :       1551 :                     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     663                 :            : 
     664                 :       1551 :                     ovs_mutex_lock(&netdev->mutex);
     665                 :       1551 :                     netdev_linux_update(netdev, &change);
     666                 :       1551 :                     ovs_mutex_unlock(&netdev->mutex);
     667                 :            :                 }
     668                 :       2675 :                 netdev_close(netdev_);
     669                 :            :             }
     670         [ -  + ]:     281708 :         } else if (error == ENOBUFS) {
     671                 :            :             struct shash device_shash;
     672                 :            :             struct shash_node *node;
     673                 :            : 
     674                 :          0 :             nl_sock_drain(sock);
     675                 :            : 
     676                 :          0 :             shash_init(&device_shash);
     677                 :          0 :             netdev_get_devices(&netdev_linux_class, &device_shash);
     678 [ #  # ][ #  # ]:          0 :             SHASH_FOR_EACH (node, &device_shash) {
     679                 :          0 :                 struct netdev *netdev_ = node->data;
     680                 :          0 :                 struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     681                 :            :                 unsigned int flags;
     682                 :            : 
     683                 :          0 :                 ovs_mutex_lock(&netdev->mutex);
     684                 :          0 :                 get_flags(netdev_, &flags);
     685                 :          0 :                 netdev_linux_changed(netdev, flags, 0);
     686                 :          0 :                 ovs_mutex_unlock(&netdev->mutex);
     687                 :            : 
     688                 :          0 :                 netdev_close(netdev_);
     689                 :            :             }
     690                 :          0 :             shash_destroy(&device_shash);
     691         [ -  + ]:     281708 :         } else if (error != EAGAIN) {
     692         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)",
     693                 :            :                          ovs_strerror(error));
     694                 :            :         }
     695                 :     284383 :         ofpbuf_uninit(&buf);
     696         [ +  + ]:     284383 :     } while (!error);
     697                 :            : }
     698                 :            : 
     699                 :            : static void
     700                 :     281708 : netdev_linux_wait(const struct netdev_class *netdev_class OVS_UNUSED)
     701                 :            : {
     702                 :            :     struct nl_sock *sock;
     703                 :            : 
     704         [ -  + ]:     281708 :     if (netdev_linux_miimon_enabled()) {
     705                 :          0 :         netdev_linux_miimon_wait();
     706                 :            :     }
     707                 :     281708 :     sock = netdev_linux_notify_sock();
     708         [ +  - ]:     281708 :     if (sock) {
     709                 :     281708 :         nl_sock_wait(sock, POLLIN);
     710                 :            :     }
     711                 :     281708 : }
     712                 :            : 
     713                 :            : static void
     714                 :       1551 : netdev_linux_changed(struct netdev_linux *dev,
     715                 :            :                      unsigned int ifi_flags, unsigned int mask)
     716                 :            :     OVS_REQUIRES(dev->mutex)
     717                 :            : {
     718                 :       1551 :     netdev_change_seq_changed(&dev->up);
     719                 :            : 
     720         [ +  + ]:       1551 :     if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) {
     721                 :        105 :         dev->carrier_resets++;
     722                 :            :     }
     723                 :       1551 :     dev->ifi_flags = ifi_flags;
     724                 :            : 
     725                 :       1551 :     dev->cache_valid &= mask;
     726         [ +  + ]:       1551 :     if (!(mask & VALID_IN)) {
     727                 :        210 :         netdev_get_addrs_list_flush();
     728                 :            :     }
     729                 :       1551 : }
     730                 :            : 
     731                 :            : static void
     732                 :       1551 : netdev_linux_update(struct netdev_linux *dev,
     733                 :            :                     const struct rtnetlink_change *change)
     734                 :            :     OVS_REQUIRES(dev->mutex)
     735                 :            : {
     736         [ +  + ]:       1551 :     if (rtnetlink_type_is_rtnlgrp_link(change->nlmsg_type)){
     737         [ +  + ]:       1343 :         if (change->nlmsg_type == RTM_NEWLINK) {
     738                 :            :             /* Keep drv-info, and ip addresses. */
     739                 :       1341 :             netdev_linux_changed(dev, change->ifi_flags,
     740                 :            :                                  VALID_DRVINFO | VALID_IN);
     741                 :            : 
     742                 :            :             /* Update netdev from rtnl-change msg. */
     743         [ +  - ]:       1341 :             if (change->mtu) {
     744                 :       1341 :                 dev->mtu = change->mtu;
     745                 :       1341 :                 dev->cache_valid |= VALID_MTU;
     746                 :       1341 :                 dev->netdev_mtu_error = 0;
     747                 :            :             }
     748                 :            : 
     749         [ +  - ]:       1341 :             if (!eth_addr_is_zero(change->mac)) {
     750                 :       1341 :                 dev->etheraddr = change->mac;
     751                 :       1341 :                 dev->cache_valid |= VALID_ETHERADDR;
     752                 :       1341 :                 dev->ether_addr_error = 0;
     753                 :            :             }
     754                 :            : 
     755                 :       1341 :             dev->ifindex = change->if_index;
     756                 :       1341 :             dev->cache_valid |= VALID_IFINDEX;
     757                 :       1341 :             dev->get_ifindex_error = 0;
     758                 :            :         } else {
     759                 :       1343 :             netdev_linux_changed(dev, change->ifi_flags, 0);
     760                 :            :         }
     761         [ +  - ]:        208 :     } else if (rtnetlink_type_is_rtnlgrp_addr(change->nlmsg_type)) {
     762                 :            :         /* Invalidates in4, in6. */
     763                 :        208 :         netdev_linux_changed(dev, dev->ifi_flags, ~VALID_IN);
     764                 :            :     } else {
     765                 :          0 :         OVS_NOT_REACHED();
     766                 :            :     }
     767                 :       1551 : }
     768                 :            : 
     769                 :            : static struct netdev *
     770                 :      25396 : netdev_linux_alloc(void)
     771                 :            : {
     772                 :      25396 :     struct netdev_linux *netdev = xzalloc(sizeof *netdev);
     773                 :      25396 :     return &netdev->up;
     774                 :            : }
     775                 :            : 
     776                 :            : static void
     777                 :      25396 : netdev_linux_common_construct(struct netdev_linux *netdev)
     778                 :            : {
     779                 :      25396 :     ovs_mutex_init(&netdev->mutex);
     780                 :      25396 : }
     781                 :            : 
     782                 :            : /* Creates system and internal devices. */
     783                 :            : static int
     784                 :      25330 : netdev_linux_construct(struct netdev *netdev_)
     785                 :            : {
     786                 :      25330 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     787                 :            :     int error;
     788                 :            : 
     789                 :      25330 :     netdev_linux_common_construct(netdev);
     790                 :            : 
     791                 :      25330 :     error = get_flags(&netdev->up, &netdev->ifi_flags);
     792         [ +  + ]:      25330 :     if (error == ENODEV) {
     793         [ -  + ]:         76 :         if (netdev->up.netdev_class != &netdev_internal_class) {
     794                 :            :             /* The device does not exist, so don't allow it to be opened. */
     795                 :          0 :             return ENODEV;
     796                 :            :         } else {
     797                 :            :             /* "Internal" netdevs have to be created as netdev objects before
     798                 :            :              * they exist in the kernel, because creating them in the kernel
     799                 :            :              * happens by passing a netdev object to dpif_port_add().
     800                 :            :              * Therefore, ignore the error. */
     801                 :            :         }
     802                 :            :     }
     803                 :            : 
     804                 :      25330 :     return 0;
     805                 :            : }
     806                 :            : 
     807                 :            : /* For most types of netdevs we open the device for each call of
     808                 :            :  * netdev_open().  However, this is not the case with tap devices,
     809                 :            :  * since it is only possible to open the device once.  In this
     810                 :            :  * situation we share a single file descriptor, and consequently
     811                 :            :  * buffers, across all readers.  Therefore once data is read it will
     812                 :            :  * be unavailable to other reads for tap devices. */
     813                 :            : static int
     814                 :         66 : netdev_linux_construct_tap(struct netdev *netdev_)
     815                 :            : {
     816                 :         66 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     817                 :            :     static const char tap_dev[] = "/dev/net/tun";
     818                 :         66 :     const char *name = netdev_->name;
     819                 :            :     struct ifreq ifr;
     820                 :            :     int error;
     821                 :            : 
     822                 :         66 :     netdev_linux_common_construct(netdev);
     823                 :            : 
     824                 :            :     /* Open tap device. */
     825                 :         66 :     netdev->tap_fd = open(tap_dev, O_RDWR);
     826         [ -  + ]:         66 :     if (netdev->tap_fd < 0) {
     827                 :          0 :         error = errno;
     828         [ #  # ]:          0 :         VLOG_WARN("opening \"%s\" failed: %s", tap_dev, ovs_strerror(error));
     829                 :          0 :         return error;
     830                 :            :     }
     831                 :            : 
     832                 :            :     /* Create tap device. */
     833                 :         66 :     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
     834                 :         66 :     ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
     835         [ -  + ]:         66 :     if (ioctl(netdev->tap_fd, TUNSETIFF, &ifr) == -1) {
     836         [ #  # ]:          0 :         VLOG_WARN("%s: creating tap device failed: %s", name,
     837                 :            :                   ovs_strerror(errno));
     838                 :          0 :         error = errno;
     839                 :          0 :         goto error_close;
     840                 :            :     }
     841                 :            : 
     842                 :            :     /* Make non-blocking. */
     843                 :         66 :     error = set_nonblocking(netdev->tap_fd);
     844         [ -  + ]:         66 :     if (error) {
     845                 :          0 :         goto error_close;
     846                 :            :     }
     847                 :            : 
     848                 :         66 :     return 0;
     849                 :            : 
     850                 :            : error_close:
     851                 :          0 :     close(netdev->tap_fd);
     852                 :         66 :     return error;
     853                 :            : }
     854                 :            : 
     855                 :            : static void
     856                 :      24457 : netdev_linux_destruct(struct netdev *netdev_)
     857                 :            : {
     858                 :      24457 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     859                 :            : 
     860 [ +  + ][ -  + ]:      24457 :     if (netdev->tc && netdev->tc->ops->tc_destroy) {
     861                 :          0 :         netdev->tc->ops->tc_destroy(netdev->tc);
     862                 :            :     }
     863                 :            : 
     864         [ -  + ]:      24457 :     if (netdev_get_class(netdev_) == &netdev_tap_class
     865         [ #  # ]:          0 :         && netdev->tap_fd >= 0)
     866                 :            :     {
     867                 :          0 :         close(netdev->tap_fd);
     868                 :            :     }
     869                 :            : 
     870         [ -  + ]:      24457 :     if (netdev->miimon_interval > 0) {
     871                 :          0 :         atomic_count_dec(&miimon_cnt);
     872                 :            :     }
     873                 :            : 
     874                 :      24457 :     ovs_mutex_destroy(&netdev->mutex);
     875                 :      24457 : }
     876                 :            : 
     877                 :            : static void
     878                 :      24457 : netdev_linux_dealloc(struct netdev *netdev_)
     879                 :            : {
     880                 :      24457 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     881                 :      24457 :     free(netdev);
     882                 :      24457 : }
     883                 :            : 
     884                 :            : static struct netdev_rxq *
     885                 :        148 : netdev_linux_rxq_alloc(void)
     886                 :            : {
     887                 :        148 :     struct netdev_rxq_linux *rx = xzalloc(sizeof *rx);
     888                 :        148 :     return &rx->up;
     889                 :            : }
     890                 :            : 
     891                 :            : static int
     892                 :        148 : netdev_linux_rxq_construct(struct netdev_rxq *rxq_)
     893                 :            : {
     894                 :        148 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
     895                 :        148 :     struct netdev *netdev_ = rx->up.netdev;
     896                 :        148 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     897                 :            :     int error;
     898                 :            : 
     899                 :        148 :     ovs_mutex_lock(&netdev->mutex);
     900                 :        148 :     rx->is_tap = is_tap_netdev(netdev_);
     901         [ +  + ]:        148 :     if (rx->is_tap) {
     902                 :         66 :         rx->fd = netdev->tap_fd;
     903                 :            :     } else {
     904                 :            :         struct sockaddr_ll sll;
     905                 :            :         int ifindex, val;
     906                 :            :         /* Result of tcpdump -dd inbound */
     907                 :            :         static const struct sock_filter filt[] = {
     908                 :            :             { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */
     909                 :            :             { 0x15, 0, 1, 0x00000004 }, /* jeq #4     jt 2  jf 3 */
     910                 :            :             { 0x6, 0, 0, 0x00000000 },  /* ret #0 */
     911                 :            :             { 0x6, 0, 0, 0x0000ffff }   /* ret #65535 */
     912                 :            :         };
     913                 :            :         static const struct sock_fprog fprog = {
     914                 :            :             ARRAY_SIZE(filt), (struct sock_filter *) filt
     915                 :            :         };
     916                 :            : 
     917                 :            :         /* Create file descriptor. */
     918                 :         82 :         rx->fd = socket(PF_PACKET, SOCK_RAW, 0);
     919         [ -  + ]:         82 :         if (rx->fd < 0) {
     920                 :          0 :             error = errno;
     921         [ #  # ]:          0 :             VLOG_ERR("failed to create raw socket (%s)", ovs_strerror(error));
     922                 :          0 :             goto error;
     923                 :            :         }
     924                 :            : 
     925                 :         82 :         val = 1;
     926         [ -  + ]:         82 :         if (setsockopt(rx->fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof val)) {
     927                 :          0 :             error = errno;
     928         [ #  # ]:          0 :             VLOG_ERR("%s: failed to mark socket for auxdata (%s)",
     929                 :            :                      netdev_get_name(netdev_), ovs_strerror(error));
     930                 :          0 :             goto error;
     931                 :            :         }
     932                 :            : 
     933                 :            :         /* Set non-blocking mode. */
     934                 :         82 :         error = set_nonblocking(rx->fd);
     935         [ -  + ]:         82 :         if (error) {
     936                 :          0 :             goto error;
     937                 :            :         }
     938                 :            : 
     939                 :            :         /* Get ethernet device index. */
     940                 :         82 :         error = get_ifindex(&netdev->up, &ifindex);
     941         [ -  + ]:         82 :         if (error) {
     942                 :          0 :             goto error;
     943                 :            :         }
     944                 :            : 
     945                 :            :         /* Bind to specific ethernet device. */
     946                 :         82 :         memset(&sll, 0, sizeof sll);
     947                 :         82 :         sll.sll_family = AF_PACKET;
     948                 :         82 :         sll.sll_ifindex = ifindex;
     949                 :         82 :         sll.sll_protocol = htons(ETH_P_ALL);
     950         [ -  + ]:         82 :         if (bind(rx->fd, (struct sockaddr *) &sll, sizeof sll) < 0) {
     951                 :          0 :             error = errno;
     952         [ #  # ]:          0 :             VLOG_ERR("%s: failed to bind raw socket (%s)",
     953                 :            :                      netdev_get_name(netdev_), ovs_strerror(error));
     954                 :          0 :             goto error;
     955                 :            :         }
     956                 :            : 
     957                 :            :         /* Filter for only inbound packets. */
     958                 :         82 :         error = setsockopt(rx->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog,
     959                 :            :                            sizeof fprog);
     960         [ -  + ]:         82 :         if (error) {
     961                 :          0 :             error = errno;
     962         [ #  # ]:          0 :             VLOG_ERR("%s: failed to attach filter (%s)",
     963                 :            :                      netdev_get_name(netdev_), ovs_strerror(error));
     964                 :         82 :             goto error;
     965                 :            :         }
     966                 :            :     }
     967                 :        148 :     ovs_mutex_unlock(&netdev->mutex);
     968                 :            : 
     969                 :        148 :     return 0;
     970                 :            : 
     971                 :            : error:
     972         [ #  # ]:          0 :     if (rx->fd >= 0) {
     973                 :          0 :         close(rx->fd);
     974                 :            :     }
     975                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
     976                 :          0 :     return error;
     977                 :            : }
     978                 :            : 
     979                 :            : static void
     980                 :          0 : netdev_linux_rxq_destruct(struct netdev_rxq *rxq_)
     981                 :            : {
     982                 :          0 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
     983                 :            : 
     984         [ #  # ]:          0 :     if (!rx->is_tap) {
     985                 :          0 :         close(rx->fd);
     986                 :            :     }
     987                 :          0 : }
     988                 :            : 
     989                 :            : static void
     990                 :          0 : netdev_linux_rxq_dealloc(struct netdev_rxq *rxq_)
     991                 :            : {
     992                 :          0 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
     993                 :            : 
     994                 :          0 :     free(rx);
     995                 :          0 : }
     996                 :            : 
     997                 :            : static ovs_be16
     998                 :        108 : auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux)
     999                 :            : {
    1000         [ +  - ]:        108 :     if (aux->tp_status & TP_STATUS_VLAN_TPID_VALID) {
    1001                 :        108 :         return htons(aux->tp_vlan_tpid);
    1002                 :            :     } else {
    1003                 :          0 :         return htons(ETH_TYPE_VLAN);
    1004                 :            :     }
    1005                 :            : }
    1006                 :            : 
    1007                 :            : static bool
    1008                 :       1338 : auxdata_has_vlan_tci(const struct tpacket_auxdata *aux)
    1009                 :            : {
    1010 [ +  + ][ -  + ]:       1338 :     return aux->tp_vlan_tci || aux->tp_status & TP_STATUS_VLAN_VALID;
    1011                 :            : }
    1012                 :            : 
    1013                 :            : static int
    1014                 :       9153 : netdev_linux_rxq_recv_sock(int fd, struct dp_packet *buffer)
    1015                 :            : {
    1016                 :            :     size_t size;
    1017                 :            :     ssize_t retval;
    1018                 :            :     struct iovec iov;
    1019                 :            :     struct cmsghdr *cmsg;
    1020                 :            :     union {
    1021                 :            :         struct cmsghdr cmsg;
    1022                 :            :         char buffer[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
    1023                 :            :     } cmsg_buffer;
    1024                 :            :     struct msghdr msgh;
    1025                 :            : 
    1026                 :            :     /* Reserve headroom for a single VLAN tag */
    1027                 :       9153 :     dp_packet_reserve(buffer, VLAN_HEADER_LEN);
    1028                 :       9153 :     size = dp_packet_tailroom(buffer);
    1029                 :            : 
    1030                 :       9153 :     iov.iov_base = dp_packet_data(buffer);
    1031                 :       9153 :     iov.iov_len = size;
    1032                 :       9153 :     msgh.msg_name = NULL;
    1033                 :       9153 :     msgh.msg_namelen = 0;
    1034                 :       9153 :     msgh.msg_iov = &iov;
    1035                 :       9153 :     msgh.msg_iovlen = 1;
    1036                 :       9153 :     msgh.msg_control = &cmsg_buffer;
    1037                 :       9153 :     msgh.msg_controllen = sizeof cmsg_buffer;
    1038                 :       9153 :     msgh.msg_flags = 0;
    1039                 :            : 
    1040                 :            :     do {
    1041                 :       9153 :         retval = recvmsg(fd, &msgh, MSG_TRUNC);
    1042 [ +  + ][ -  + ]:       9153 :     } while (retval < 0 && errno == EINTR);
    1043                 :            : 
    1044         [ +  + ]:       9153 :     if (retval < 0) {
    1045                 :       7815 :         return errno;
    1046         [ -  + ]:       1338 :     } else if (retval > size) {
    1047                 :          0 :         return EMSGSIZE;
    1048                 :            :     }
    1049                 :            : 
    1050                 :       1338 :     dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
    1051                 :            : 
    1052 [ +  - ][ +  + ]:       2568 :     for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
    1053                 :            :         const struct tpacket_auxdata *aux;
    1054                 :            : 
    1055         [ +  - ]:       1338 :         if (cmsg->cmsg_level != SOL_PACKET
    1056         [ +  - ]:       1338 :             || cmsg->cmsg_type != PACKET_AUXDATA
    1057         [ -  + ]:       1338 :             || cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata))) {
    1058                 :          0 :             continue;
    1059                 :            :         }
    1060                 :            : 
    1061                 :       1338 :         aux = ALIGNED_CAST(struct tpacket_auxdata *, CMSG_DATA(cmsg));
    1062         [ +  + ]:       1338 :         if (auxdata_has_vlan_tci(aux)) {
    1063         [ -  + ]:        108 :             if (retval < ETH_HEADER_LEN) {
    1064                 :          0 :                 return EINVAL;
    1065                 :            :             }
    1066                 :            : 
    1067                 :        108 :             eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux),
    1068                 :        108 :                           htons(aux->tp_vlan_tci));
    1069                 :        108 :             break;
    1070                 :            :         }
    1071                 :            :     }
    1072                 :            : 
    1073                 :       9153 :     return 0;
    1074                 :            : }
    1075                 :            : 
    1076                 :            : static int
    1077                 :       9760 : netdev_linux_rxq_recv_tap(int fd, struct dp_packet *buffer)
    1078                 :            : {
    1079                 :            :     ssize_t retval;
    1080                 :       9760 :     size_t size = dp_packet_tailroom(buffer);
    1081                 :            : 
    1082                 :            :     do {
    1083                 :       9760 :         retval = read(fd, dp_packet_data(buffer), size);
    1084 [ +  + ][ -  + ]:       9760 :     } while (retval < 0 && errno == EINTR);
    1085                 :            : 
    1086         [ +  + ]:       9760 :     if (retval < 0) {
    1087                 :       9684 :         return errno;
    1088                 :            :     }
    1089                 :            : 
    1090                 :         76 :     dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
    1091                 :         76 :     return 0;
    1092                 :            : }
    1093                 :            : 
    1094                 :            : static int
    1095                 :      18913 : netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
    1096                 :            : {
    1097                 :      18913 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
    1098                 :      18913 :     struct netdev *netdev = rx->up.netdev;
    1099                 :            :     struct dp_packet *buffer;
    1100                 :            :     ssize_t retval;
    1101                 :            :     int mtu;
    1102                 :            : 
    1103         [ -  + ]:      18913 :     if (netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu)) {
    1104                 :          0 :         mtu = ETH_PAYLOAD_MAX;
    1105                 :            :     }
    1106                 :            : 
    1107                 :      18913 :     buffer = dp_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu,
    1108                 :            :                                            DP_NETDEV_HEADROOM);
    1109         [ +  + ]:      37826 :     retval = (rx->is_tap
    1110                 :       9760 :               ? netdev_linux_rxq_recv_tap(rx->fd, buffer)
    1111                 :       9153 :               : netdev_linux_rxq_recv_sock(rx->fd, buffer));
    1112                 :            : 
    1113         [ +  + ]:      18913 :     if (retval) {
    1114 [ -  + ][ #  # ]:      17499 :         if (retval != EAGAIN && retval != EMSGSIZE) {
    1115         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
    1116                 :            :                          netdev_rxq_get_name(rxq_), ovs_strerror(errno));
    1117                 :            :         }
    1118                 :      17499 :         dp_packet_delete(buffer);
    1119                 :            :     } else {
    1120                 :       1414 :         batch->packets[0] = buffer;
    1121                 :       1414 :         batch->count = 1;
    1122                 :            :     }
    1123                 :            : 
    1124                 :      18913 :     return retval;
    1125                 :            : }
    1126                 :            : 
    1127                 :            : static void
    1128                 :      16867 : netdev_linux_rxq_wait(struct netdev_rxq *rxq_)
    1129                 :            : {
    1130                 :      16867 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
    1131                 :      16867 :     poll_fd_wait(rx->fd, POLLIN);
    1132                 :      16867 : }
    1133                 :            : 
    1134                 :            : static int
    1135                 :          0 : netdev_linux_rxq_drain(struct netdev_rxq *rxq_)
    1136                 :            : {
    1137                 :          0 :     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
    1138         [ #  # ]:          0 :     if (rx->is_tap) {
    1139                 :            :         struct ifreq ifr;
    1140                 :          0 :         int error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr,
    1141                 :            :                                         SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
    1142         [ #  # ]:          0 :         if (error) {
    1143                 :          0 :             return error;
    1144                 :            :         }
    1145                 :          0 :         drain_fd(rx->fd, ifr.ifr_qlen);
    1146                 :          0 :         return 0;
    1147                 :            :     } else {
    1148                 :          0 :         return drain_rcvbuf(rx->fd);
    1149                 :            :     }
    1150                 :            : }
    1151                 :            : 
    1152                 :            : /* Sends 'buffer' on 'netdev'.  Returns 0 if successful, otherwise a positive
    1153                 :            :  * errno value.  Returns EAGAIN without blocking if the packet cannot be queued
    1154                 :            :  * immediately.  Returns EMSGSIZE if a partial packet was transmitted or if
    1155                 :            :  * the packet is too big or too small to transmit on the device.
    1156                 :            :  *
    1157                 :            :  * The caller retains ownership of 'buffer' in all cases.
    1158                 :            :  *
    1159                 :            :  * The kernel maintains a packet transmission queue, so the caller is not
    1160                 :            :  * expected to do additional queuing of packets. */
    1161                 :            : static int
    1162                 :       1182 : netdev_linux_send(struct netdev *netdev_, int qid OVS_UNUSED,
    1163                 :            :                   struct dp_packet_batch *batch, bool may_steal,
    1164                 :            :                   bool concurrent_txq OVS_UNUSED)
    1165                 :            : {
    1166                 :            :     int i;
    1167                 :       1182 :     int error = 0;
    1168                 :            : 
    1169                 :            :     /* 'i' is incremented only if there's no error */
    1170         [ +  + ]:       2364 :     for (i = 0; i < batch->count;) {
    1171                 :       1182 :         const void *data = dp_packet_data(batch->packets[i]);
    1172                 :       1182 :         size_t size = dp_packet_size(batch->packets[i]);
    1173                 :            :         ssize_t retval;
    1174                 :            : 
    1175                 :            :         /* Truncate the packet if it is configured. */
    1176                 :       1182 :         size -= dp_packet_get_cutlen(batch->packets[i]);
    1177                 :            : 
    1178         [ +  + ]:       1182 :         if (!is_tap_netdev(netdev_)) {
    1179                 :            :             /* Use our AF_PACKET socket to send to this device. */
    1180                 :            :             struct sockaddr_ll sll;
    1181                 :            :             struct msghdr msg;
    1182                 :            :             struct iovec iov;
    1183                 :            :             int ifindex;
    1184                 :            :             int sock;
    1185                 :            : 
    1186                 :        930 :             sock = af_packet_sock();
    1187         [ -  + ]:        930 :             if (sock < 0) {
    1188                 :          0 :                 return -sock;
    1189                 :            :             }
    1190                 :            : 
    1191                 :        930 :             ifindex = netdev_get_ifindex(netdev_);
    1192         [ -  + ]:        930 :             if (ifindex < 0) {
    1193                 :          0 :                 return -ifindex;
    1194                 :            :             }
    1195                 :            : 
    1196                 :            :             /* We don't bother setting most fields in sockaddr_ll because the
    1197                 :            :              * kernel ignores them for SOCK_RAW. */
    1198                 :        930 :             memset(&sll, 0, sizeof sll);
    1199                 :        930 :             sll.sll_family = AF_PACKET;
    1200                 :        930 :             sll.sll_ifindex = ifindex;
    1201                 :            : 
    1202                 :        930 :             iov.iov_base = CONST_CAST(void *, data);
    1203                 :        930 :             iov.iov_len = size;
    1204                 :            : 
    1205                 :        930 :             msg.msg_name = &sll;
    1206                 :        930 :             msg.msg_namelen = sizeof sll;
    1207                 :        930 :             msg.msg_iov = &iov;
    1208                 :        930 :             msg.msg_iovlen = 1;
    1209                 :        930 :             msg.msg_control = NULL;
    1210                 :        930 :             msg.msg_controllen = 0;
    1211                 :        930 :             msg.msg_flags = 0;
    1212                 :            : 
    1213                 :        930 :             retval = sendmsg(sock, &msg, 0);
    1214                 :            :         } else {
    1215                 :            :             /* Use the tap fd to send to this device.  This is essential for
    1216                 :            :              * tap devices, because packets sent to a tap device with an
    1217                 :            :              * AF_PACKET socket will loop back to be *received* again on the
    1218                 :            :              * tap device.  This doesn't occur on other interface types
    1219                 :            :              * because we attach a socket filter to the rx socket. */
    1220                 :        252 :             struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1221                 :            : 
    1222                 :        252 :             retval = write(netdev->tap_fd, data, size);
    1223                 :            :         }
    1224                 :            : 
    1225         [ -  + ]:       1182 :         if (retval < 0) {
    1226         [ #  # ]:          0 :             if (errno == EINTR) {
    1227                 :            :                 /* The send was interrupted by a signal.  Retry the packet by
    1228                 :            :                  * continuing without incrementing 'i'.*/
    1229                 :          0 :                 continue;
    1230 [ #  # ][ #  # ]:          0 :             } else if (errno == EIO && is_tap_netdev(netdev_)) {
    1231                 :            :                 /* The Linux tap driver returns EIO if the device is not up.
    1232                 :            :                  * From the OVS side this is not an error, so ignore it. */
    1233                 :            :             } else {
    1234                 :            :                 /* The Linux AF_PACKET implementation never blocks waiting for
    1235                 :            :                  * room for packets, instead returning ENOBUFS.  Translate this
    1236                 :            :                  * into EAGAIN for the caller. */
    1237         [ #  # ]:          0 :                 error = errno == ENOBUFS ? EAGAIN : errno;
    1238                 :          0 :                 break;
    1239                 :            :             }
    1240         [ -  + ]:       1182 :         } else if (retval != size) {
    1241         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRIuSIZE" bytes"
    1242                 :            :                               " of %"PRIuSIZE") on %s", retval, size,
    1243                 :            :                          netdev_get_name(netdev_));
    1244                 :          0 :             error = EMSGSIZE;
    1245                 :          0 :             break;
    1246                 :            :         }
    1247                 :            : 
    1248                 :            :         /* Process the next packet in the batch */
    1249                 :       1182 :         i++;
    1250                 :            :     }
    1251                 :            : 
    1252                 :       1182 :     dp_packet_delete_batch(batch, may_steal);
    1253                 :            : 
    1254 [ -  + ][ #  # ]:       1182 :     if (error && error != EAGAIN) {
    1255         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
    1256                 :            :                          netdev_get_name(netdev_), ovs_strerror(error));
    1257                 :            :     }
    1258                 :            : 
    1259                 :       1182 :     return error;
    1260                 :            : 
    1261                 :            : }
    1262                 :            : 
    1263                 :            : /* Registers with the poll loop to wake up from the next call to poll_block()
    1264                 :            :  * when the packet transmission queue has sufficient room to transmit a packet
    1265                 :            :  * with netdev_send().
    1266                 :            :  *
    1267                 :            :  * The kernel maintains a packet transmission queue, so the client is not
    1268                 :            :  * expected to do additional queuing of packets.  Thus, this function is
    1269                 :            :  * unlikely to ever be used.  It is included for completeness. */
    1270                 :            : static void
    1271                 :          0 : netdev_linux_send_wait(struct netdev *netdev, int qid OVS_UNUSED)
    1272                 :            : {
    1273         [ #  # ]:          0 :     if (is_tap_netdev(netdev)) {
    1274                 :            :         /* TAP device always accepts packets.*/
    1275                 :          0 :         poll_immediate_wake();
    1276                 :            :     }
    1277                 :          0 : }
    1278                 :            : 
    1279                 :            : /* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
    1280                 :            :  * otherwise a positive errno value. */
    1281                 :            : static int
    1282                 :       2072 : netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
    1283                 :            : {
    1284                 :       2072 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1285                 :       2072 :     enum netdev_flags old_flags = 0;
    1286                 :            :     int error;
    1287                 :            : 
    1288                 :       2072 :     ovs_mutex_lock(&netdev->mutex);
    1289                 :            : 
    1290         [ +  - ]:       2072 :     if (netdev->cache_valid & VALID_ETHERADDR) {
    1291                 :       2072 :         error = netdev->ether_addr_error;
    1292 [ +  - ][ +  + ]:       2072 :         if (error || eth_addr_equals(netdev->etheraddr, mac)) {
    1293                 :            :             goto exit;
    1294                 :            :         }
    1295                 :        109 :         netdev->cache_valid &= ~VALID_ETHERADDR;
    1296                 :            :     }
    1297                 :            : 
    1298                 :            :     /* Tap devices must be brought down before setting the address. */
    1299         [ +  + ]:        109 :     if (is_tap_netdev(netdev_)) {
    1300                 :         35 :         update_flags(netdev, NETDEV_UP, 0, &old_flags);
    1301                 :            :     }
    1302                 :        109 :     error = set_etheraddr(netdev_get_name(netdev_), mac);
    1303 [ -  + ][ #  # ]:        109 :     if (!error || error == ENODEV) {
    1304                 :        109 :         netdev->ether_addr_error = error;
    1305                 :        109 :         netdev->cache_valid |= VALID_ETHERADDR;
    1306         [ +  - ]:        109 :         if (!error) {
    1307                 :        109 :             netdev->etheraddr = mac;
    1308                 :            :         }
    1309                 :            :     }
    1310                 :            : 
    1311 [ +  + ][ -  + ]:        109 :     if (is_tap_netdev(netdev_) && old_flags & NETDEV_UP) {
    1312                 :          0 :         update_flags(netdev, 0, NETDEV_UP, &old_flags);
    1313                 :            :     }
    1314                 :            : 
    1315                 :            : exit:
    1316                 :       2072 :     ovs_mutex_unlock(&netdev->mutex);
    1317                 :       2072 :     return error;
    1318                 :            : }
    1319                 :            : 
    1320                 :            : /* Copies 'netdev''s MAC address to 'mac' which is passed as param. */
    1321                 :            : static int
    1322                 :      12232 : netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
    1323                 :            : {
    1324                 :      12232 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1325                 :            :     int error;
    1326                 :            : 
    1327                 :      12232 :     ovs_mutex_lock(&netdev->mutex);
    1328         [ +  + ]:      12232 :     if (!(netdev->cache_valid & VALID_ETHERADDR)) {
    1329                 :       2817 :         netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_),
    1330                 :            :                                                  &netdev->etheraddr);
    1331                 :       2817 :         netdev->cache_valid |= VALID_ETHERADDR;
    1332                 :            :     }
    1333                 :            : 
    1334                 :      12232 :     error = netdev->ether_addr_error;
    1335         [ +  + ]:      12232 :     if (!error) {
    1336                 :      12222 :         *mac = netdev->etheraddr;
    1337                 :            :     }
    1338                 :      12232 :     ovs_mutex_unlock(&netdev->mutex);
    1339                 :            : 
    1340                 :      12232 :     return error;
    1341                 :            : }
    1342                 :            : 
    1343                 :            : static int
    1344                 :      26133 : netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup)
    1345                 :            : {
    1346                 :            :     int error;
    1347                 :            : 
    1348         [ +  + ]:      26133 :     if (!(netdev->cache_valid & VALID_MTU)) {
    1349                 :            :         struct ifreq ifr;
    1350                 :            : 
    1351                 :        377 :         netdev->netdev_mtu_error = af_inet_ifreq_ioctl(
    1352                 :        377 :             netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU");
    1353                 :        377 :         netdev->mtu = ifr.ifr_mtu;
    1354                 :        377 :         netdev->cache_valid |= VALID_MTU;
    1355                 :            :     }
    1356                 :            : 
    1357                 :      26133 :     error = netdev->netdev_mtu_error;
    1358         [ +  + ]:      26133 :     if (!error) {
    1359                 :      26128 :         *mtup = netdev->mtu;
    1360                 :            :     }
    1361                 :            : 
    1362                 :      26133 :     return error;
    1363                 :            : }
    1364                 :            : 
    1365                 :            : /* Returns the maximum size of transmitted (and received) packets on 'netdev',
    1366                 :            :  * in bytes, not including the hardware header; thus, this is typically 1500
    1367                 :            :  * bytes for Ethernet devices. */
    1368                 :            : static int
    1369                 :       7220 : netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
    1370                 :            : {
    1371                 :       7220 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1372                 :            :     int error;
    1373                 :            : 
    1374                 :       7220 :     ovs_mutex_lock(&netdev->mutex);
    1375                 :       7220 :     error = netdev_linux_get_mtu__(netdev, mtup);
    1376                 :       7220 :     ovs_mutex_unlock(&netdev->mutex);
    1377                 :            : 
    1378                 :       7220 :     return error;
    1379                 :            : }
    1380                 :            : 
    1381                 :            : /* Sets the maximum size of transmitted (MTU) for given device using linux
    1382                 :            :  * networking ioctl interface.
    1383                 :            :  */
    1384                 :            : static int
    1385                 :         97 : netdev_linux_set_mtu(struct netdev *netdev_, int mtu)
    1386                 :            : {
    1387                 :         97 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1388                 :            :     struct ifreq ifr;
    1389                 :            :     int error;
    1390                 :            : 
    1391                 :         97 :     ovs_mutex_lock(&netdev->mutex);
    1392         [ +  - ]:         97 :     if (netdev->cache_valid & VALID_MTU) {
    1393                 :         97 :         error = netdev->netdev_mtu_error;
    1394 [ +  - ][ +  + ]:         97 :         if (error || netdev->mtu == mtu) {
    1395                 :            :             goto exit;
    1396                 :            :         }
    1397                 :          2 :         netdev->cache_valid &= ~VALID_MTU;
    1398                 :            :     }
    1399                 :          2 :     ifr.ifr_mtu = mtu;
    1400                 :          2 :     error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
    1401                 :            :                                 SIOCSIFMTU, "SIOCSIFMTU");
    1402 [ -  + ][ #  # ]:          2 :     if (!error || error == ENODEV) {
    1403                 :          2 :         netdev->netdev_mtu_error = error;
    1404                 :          2 :         netdev->mtu = ifr.ifr_mtu;
    1405                 :          2 :         netdev->cache_valid |= VALID_MTU;
    1406                 :            :     }
    1407                 :            : exit:
    1408                 :         97 :     ovs_mutex_unlock(&netdev->mutex);
    1409                 :         97 :     return error;
    1410                 :            : }
    1411                 :            : 
    1412                 :            : /* Returns the ifindex of 'netdev', if successful, as a positive number.
    1413                 :            :  * On failure, returns a negative errno value. */
    1414                 :            : static int
    1415                 :       5166 : netdev_linux_get_ifindex(const struct netdev *netdev_)
    1416                 :            : {
    1417                 :       5166 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1418                 :            :     int ifindex, error;
    1419                 :            : 
    1420                 :       5166 :     ovs_mutex_lock(&netdev->mutex);
    1421                 :       5166 :     error = get_ifindex(netdev_, &ifindex);
    1422                 :       5166 :     ovs_mutex_unlock(&netdev->mutex);
    1423                 :            : 
    1424         [ +  + ]:       5166 :     return error ? -error : ifindex;
    1425                 :            : }
    1426                 :            : 
    1427                 :            : static int
    1428                 :       7942 : netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier)
    1429                 :            : {
    1430                 :       7942 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1431                 :            : 
    1432                 :       7942 :     ovs_mutex_lock(&netdev->mutex);
    1433         [ -  + ]:       7942 :     if (netdev->miimon_interval > 0) {
    1434                 :          0 :         *carrier = netdev->miimon;
    1435                 :            :     } else {
    1436                 :       7942 :         *carrier = (netdev->ifi_flags & IFF_RUNNING) != 0;
    1437                 :            :     }
    1438                 :       7942 :     ovs_mutex_unlock(&netdev->mutex);
    1439                 :            : 
    1440                 :       7942 :     return 0;
    1441                 :            : }
    1442                 :            : 
    1443                 :            : static long long int
    1444                 :      11021 : netdev_linux_get_carrier_resets(const struct netdev *netdev_)
    1445                 :            : {
    1446                 :      11021 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1447                 :            :     long long int carrier_resets;
    1448                 :            : 
    1449                 :      11021 :     ovs_mutex_lock(&netdev->mutex);
    1450                 :      11021 :     carrier_resets = netdev->carrier_resets;
    1451                 :      11021 :     ovs_mutex_unlock(&netdev->mutex);
    1452                 :            : 
    1453                 :      11021 :     return carrier_resets;
    1454                 :            : }
    1455                 :            : 
    1456                 :            : static int
    1457                 :          0 : netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name,
    1458                 :            :                        struct mii_ioctl_data *data)
    1459                 :            : {
    1460                 :            :     struct ifreq ifr;
    1461                 :            :     int error;
    1462                 :            : 
    1463                 :          0 :     memset(&ifr, 0, sizeof ifr);
    1464                 :          0 :     memcpy(&ifr.ifr_data, data, sizeof *data);
    1465                 :          0 :     error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name);
    1466                 :          0 :     memcpy(data, &ifr.ifr_data, sizeof *data);
    1467                 :            : 
    1468                 :          0 :     return error;
    1469                 :            : }
    1470                 :            : 
    1471                 :            : static int
    1472                 :          0 : netdev_linux_get_miimon(const char *name, bool *miimon)
    1473                 :            : {
    1474                 :            :     struct mii_ioctl_data data;
    1475                 :            :     int error;
    1476                 :            : 
    1477                 :          0 :     *miimon = false;
    1478                 :            : 
    1479                 :          0 :     memset(&data, 0, sizeof data);
    1480                 :          0 :     error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data);
    1481         [ #  # ]:          0 :     if (!error) {
    1482                 :            :         /* data.phy_id is filled out by previous SIOCGMIIPHY miimon call. */
    1483                 :          0 :         data.reg_num = MII_BMSR;
    1484                 :          0 :         error = netdev_linux_do_miimon(name, SIOCGMIIREG, "SIOCGMIIREG",
    1485                 :            :                                        &data);
    1486                 :            : 
    1487         [ #  # ]:          0 :         if (!error) {
    1488                 :          0 :             *miimon = !!(data.val_out & BMSR_LSTATUS);
    1489                 :            :         } else {
    1490         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: failed to query MII", name);
    1491                 :            :         }
    1492                 :            :     } else {
    1493                 :            :         struct ethtool_cmd ecmd;
    1494                 :            : 
    1495         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "%s: failed to query MII, falling back to ethtool",
    1496                 :            :                     name);
    1497                 :            : 
    1498                 :          0 :         COVERAGE_INC(netdev_get_ethtool);
    1499                 :          0 :         memset(&ecmd, 0, sizeof ecmd);
    1500                 :          0 :         error = netdev_linux_do_ethtool(name, &ecmd, ETHTOOL_GLINK,
    1501                 :            :                                         "ETHTOOL_GLINK");
    1502         [ #  # ]:          0 :         if (!error) {
    1503                 :            :             struct ethtool_value eval;
    1504                 :            : 
    1505                 :          0 :             memcpy(&eval, &ecmd, sizeof eval);
    1506                 :          0 :             *miimon = !!eval.data;
    1507                 :            :         } else {
    1508         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: ethtool link status failed", name);
    1509                 :            :         }
    1510                 :            :     }
    1511                 :            : 
    1512                 :          0 :     return error;
    1513                 :            : }
    1514                 :            : 
    1515                 :            : static int
    1516                 :       4175 : netdev_linux_set_miimon_interval(struct netdev *netdev_,
    1517                 :            :                                  long long int interval)
    1518                 :            : {
    1519                 :       4175 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1520                 :            : 
    1521                 :       4175 :     ovs_mutex_lock(&netdev->mutex);
    1522         [ -  + ]:       4175 :     interval = interval > 0 ? MAX(interval, 100) : 0;
    1523         [ -  + ]:       4175 :     if (netdev->miimon_interval != interval) {
    1524 [ #  # ][ #  # ]:          0 :         if (interval && !netdev->miimon_interval) {
    1525                 :          0 :             atomic_count_inc(&miimon_cnt);
    1526 [ #  # ][ #  # ]:          0 :         } else if (!interval && netdev->miimon_interval) {
    1527                 :          0 :             atomic_count_dec(&miimon_cnt);
    1528                 :            :         }
    1529                 :            : 
    1530                 :          0 :         netdev->miimon_interval = interval;
    1531                 :          0 :         timer_set_expired(&netdev->miimon_timer);
    1532                 :            :     }
    1533                 :       4175 :     ovs_mutex_unlock(&netdev->mutex);
    1534                 :            : 
    1535                 :       4175 :     return 0;
    1536                 :            : }
    1537                 :            : 
    1538                 :            : static void
    1539                 :          0 : netdev_linux_miimon_run(void)
    1540                 :            : {
    1541                 :            :     struct shash device_shash;
    1542                 :            :     struct shash_node *node;
    1543                 :            : 
    1544                 :          0 :     shash_init(&device_shash);
    1545                 :          0 :     netdev_get_devices(&netdev_linux_class, &device_shash);
    1546 [ #  # ][ #  # ]:          0 :     SHASH_FOR_EACH (node, &device_shash) {
    1547                 :          0 :         struct netdev *netdev = node->data;
    1548                 :          0 :         struct netdev_linux *dev = netdev_linux_cast(netdev);
    1549                 :            :         bool miimon;
    1550                 :            : 
    1551                 :          0 :         ovs_mutex_lock(&dev->mutex);
    1552 [ #  # ][ #  # ]:          0 :         if (dev->miimon_interval > 0 && timer_expired(&dev->miimon_timer)) {
    1553                 :          0 :             netdev_linux_get_miimon(dev->up.name, &miimon);
    1554         [ #  # ]:          0 :             if (miimon != dev->miimon) {
    1555                 :          0 :                 dev->miimon = miimon;
    1556                 :          0 :                 netdev_linux_changed(dev, dev->ifi_flags, 0);
    1557                 :            :             }
    1558                 :            : 
    1559                 :          0 :             timer_set_duration(&dev->miimon_timer, dev->miimon_interval);
    1560                 :            :         }
    1561                 :          0 :         ovs_mutex_unlock(&dev->mutex);
    1562                 :          0 :         netdev_close(netdev);
    1563                 :            :     }
    1564                 :            : 
    1565                 :          0 :     shash_destroy(&device_shash);
    1566                 :          0 : }
    1567                 :            : 
    1568                 :            : static void
    1569                 :          0 : netdev_linux_miimon_wait(void)
    1570                 :            : {
    1571                 :            :     struct shash device_shash;
    1572                 :            :     struct shash_node *node;
    1573                 :            : 
    1574                 :          0 :     shash_init(&device_shash);
    1575                 :          0 :     netdev_get_devices(&netdev_linux_class, &device_shash);
    1576 [ #  # ][ #  # ]:          0 :     SHASH_FOR_EACH (node, &device_shash) {
    1577                 :          0 :         struct netdev *netdev = node->data;
    1578                 :          0 :         struct netdev_linux *dev = netdev_linux_cast(netdev);
    1579                 :            : 
    1580                 :          0 :         ovs_mutex_lock(&dev->mutex);
    1581         [ #  # ]:          0 :         if (dev->miimon_interval > 0) {
    1582                 :          0 :             timer_wait(&dev->miimon_timer);
    1583                 :            :         }
    1584                 :          0 :         ovs_mutex_unlock(&dev->mutex);
    1585                 :          0 :         netdev_close(netdev);
    1586                 :            :     }
    1587                 :          0 :     shash_destroy(&device_shash);
    1588                 :          0 : }
    1589                 :            : 
    1590                 :            : static void
    1591                 :        220 : swap_uint64(uint64_t *a, uint64_t *b)
    1592                 :            : {
    1593                 :        220 :     uint64_t tmp = *a;
    1594                 :        220 :     *a = *b;
    1595                 :        220 :     *b = tmp;
    1596                 :        220 : }
    1597                 :            : 
    1598                 :            : /* Copies 'src' into 'dst', performing format conversion in the process.
    1599                 :            :  *
    1600                 :            :  * 'src' is allowed to be misaligned. */
    1601                 :            : static void
    1602                 :        335 : netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst,
    1603                 :            :                                   const struct ovs_vport_stats *src)
    1604                 :            : {
    1605                 :        335 :     dst->rx_packets = get_32aligned_u64(&src->rx_packets);
    1606                 :        335 :     dst->tx_packets = get_32aligned_u64(&src->tx_packets);
    1607                 :        335 :     dst->rx_bytes = get_32aligned_u64(&src->rx_bytes);
    1608                 :        335 :     dst->tx_bytes = get_32aligned_u64(&src->tx_bytes);
    1609                 :        335 :     dst->rx_errors = get_32aligned_u64(&src->rx_errors);
    1610                 :        335 :     dst->tx_errors = get_32aligned_u64(&src->tx_errors);
    1611                 :        335 :     dst->rx_dropped = get_32aligned_u64(&src->rx_dropped);
    1612                 :        335 :     dst->tx_dropped = get_32aligned_u64(&src->tx_dropped);
    1613                 :        335 :     dst->multicast = 0;
    1614                 :        335 :     dst->collisions = 0;
    1615                 :        335 :     dst->rx_length_errors = 0;
    1616                 :        335 :     dst->rx_over_errors = 0;
    1617                 :        335 :     dst->rx_crc_errors = 0;
    1618                 :        335 :     dst->rx_frame_errors = 0;
    1619                 :        335 :     dst->rx_fifo_errors = 0;
    1620                 :        335 :     dst->rx_missed_errors = 0;
    1621                 :        335 :     dst->tx_aborted_errors = 0;
    1622                 :        335 :     dst->tx_carrier_errors = 0;
    1623                 :        335 :     dst->tx_fifo_errors = 0;
    1624                 :        335 :     dst->tx_heartbeat_errors = 0;
    1625                 :        335 :     dst->tx_window_errors = 0;
    1626                 :        335 : }
    1627                 :            : 
    1628                 :            : static int
    1629                 :        501 : get_stats_via_vport__(const struct netdev *netdev, struct netdev_stats *stats)
    1630                 :            : {
    1631                 :            :     struct dpif_netlink_vport reply;
    1632                 :            :     struct ofpbuf *buf;
    1633                 :            :     int error;
    1634                 :            : 
    1635                 :        501 :     error = dpif_netlink_vport_get(netdev_get_name(netdev), &reply, &buf);
    1636         [ +  + ]:        501 :     if (error) {
    1637                 :        166 :         return error;
    1638         [ -  + ]:        335 :     } else if (!reply.stats) {
    1639                 :          0 :         ofpbuf_delete(buf);
    1640                 :          0 :         return EOPNOTSUPP;
    1641                 :            :     }
    1642                 :            : 
    1643                 :        335 :     netdev_stats_from_ovs_vport_stats(stats, reply.stats);
    1644                 :            : 
    1645                 :        335 :     ofpbuf_delete(buf);
    1646                 :            : 
    1647                 :        501 :     return 0;
    1648                 :            : }
    1649                 :            : 
    1650                 :            : static void
    1651                 :        531 : get_stats_via_vport(const struct netdev *netdev_,
    1652                 :            :                     struct netdev_stats *stats)
    1653                 :            : {
    1654                 :        531 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1655                 :            : 
    1656 [ +  + ][ +  + ]:        531 :     if (!netdev->vport_stats_error ||
    1657                 :         79 :         !(netdev->cache_valid & VALID_VPORT_STAT_ERROR)) {
    1658                 :            :         int error;
    1659                 :            : 
    1660                 :        501 :         error = get_stats_via_vport__(netdev_, stats);
    1661 [ +  + ][ -  + ]:        501 :         if (error && error != ENOENT && error != ENODEV) {
                 [ #  # ]
    1662         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed "
    1663                 :            :                          "(%s)",
    1664                 :            :                          netdev_get_name(netdev_), ovs_strerror(error));
    1665                 :            :         }
    1666                 :        501 :         netdev->vport_stats_error = error;
    1667                 :        501 :         netdev->cache_valid |= VALID_VPORT_STAT_ERROR;
    1668                 :            :     }
    1669                 :        531 : }
    1670                 :            : 
    1671                 :            : /* Retrieves current device stats for 'netdev-linux'. */
    1672                 :            : static int
    1673                 :        370 : netdev_linux_get_stats(const struct netdev *netdev_,
    1674                 :            :                        struct netdev_stats *stats)
    1675                 :            : {
    1676                 :        370 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1677                 :            :     struct netdev_stats dev_stats;
    1678                 :            :     int error;
    1679                 :            : 
    1680                 :        370 :     ovs_mutex_lock(&netdev->mutex);
    1681                 :        370 :     get_stats_via_vport(netdev_, stats);
    1682                 :        370 :     error = get_stats_via_netlink(netdev_, &dev_stats);
    1683         [ -  + ]:        370 :     if (error) {
    1684         [ #  # ]:          0 :         if (!netdev->vport_stats_error) {
    1685                 :          0 :             error = 0;
    1686                 :            :         }
    1687         [ +  + ]:        370 :     } else if (netdev->vport_stats_error) {
    1688                 :            :         /* stats not available from OVS then use netdev stats. */
    1689                 :        141 :         *stats = dev_stats;
    1690                 :            :     } else {
    1691                 :            :         /* Use kernel netdev's packet and byte counts since vport's counters
    1692                 :            :          * do not reflect packet counts on the wire when GSO, TSO or GRO are
    1693                 :            :          * enabled. */
    1694                 :        229 :         stats->rx_packets = dev_stats.rx_packets;
    1695                 :        229 :         stats->rx_bytes = dev_stats.rx_bytes;
    1696                 :        229 :         stats->tx_packets = dev_stats.tx_packets;
    1697                 :        229 :         stats->tx_bytes = dev_stats.tx_bytes;
    1698                 :            : 
    1699                 :        229 :         stats->rx_errors           += dev_stats.rx_errors;
    1700                 :        229 :         stats->tx_errors           += dev_stats.tx_errors;
    1701                 :        229 :         stats->rx_dropped          += dev_stats.rx_dropped;
    1702                 :        229 :         stats->tx_dropped          += dev_stats.tx_dropped;
    1703                 :        229 :         stats->multicast           += dev_stats.multicast;
    1704                 :        229 :         stats->collisions          += dev_stats.collisions;
    1705                 :        229 :         stats->rx_length_errors    += dev_stats.rx_length_errors;
    1706                 :        229 :         stats->rx_over_errors      += dev_stats.rx_over_errors;
    1707                 :        229 :         stats->rx_crc_errors       += dev_stats.rx_crc_errors;
    1708                 :        229 :         stats->rx_frame_errors     += dev_stats.rx_frame_errors;
    1709                 :        229 :         stats->rx_fifo_errors      += dev_stats.rx_fifo_errors;
    1710                 :        229 :         stats->rx_missed_errors    += dev_stats.rx_missed_errors;
    1711                 :        229 :         stats->tx_aborted_errors   += dev_stats.tx_aborted_errors;
    1712                 :        229 :         stats->tx_carrier_errors   += dev_stats.tx_carrier_errors;
    1713                 :        229 :         stats->tx_fifo_errors      += dev_stats.tx_fifo_errors;
    1714                 :        229 :         stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors;
    1715                 :        229 :         stats->tx_window_errors    += dev_stats.tx_window_errors;
    1716                 :            :     }
    1717                 :        370 :     ovs_mutex_unlock(&netdev->mutex);
    1718                 :            : 
    1719                 :        370 :     return error;
    1720                 :            : }
    1721                 :            : 
    1722                 :            : /* Retrieves current device stats for 'netdev-tap' netdev or
    1723                 :            :  * netdev-internal. */
    1724                 :            : static int
    1725                 :         55 : netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
    1726                 :            : {
    1727                 :         55 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1728                 :            :     struct netdev_stats dev_stats;
    1729                 :            :     int error;
    1730                 :            : 
    1731                 :         55 :     ovs_mutex_lock(&netdev->mutex);
    1732                 :         55 :     get_stats_via_vport(netdev_, stats);
    1733                 :         55 :     error = get_stats_via_netlink(netdev_, &dev_stats);
    1734         [ -  + ]:         55 :     if (error) {
    1735         [ #  # ]:          0 :         if (!netdev->vport_stats_error) {
    1736                 :          0 :             error = 0;
    1737                 :            :         }
    1738         [ +  - ]:         55 :     } else if (netdev->vport_stats_error) {
    1739                 :            :         /* Transmit and receive stats will appear to be swapped relative to the
    1740                 :            :          * other ports since we are the one sending the data, not a remote
    1741                 :            :          * computer.  For consistency, we swap them back here. This does not
    1742                 :            :          * apply if we are getting stats from the vport layer because it always
    1743                 :            :          * tracks stats from the perspective of the switch. */
    1744                 :            : 
    1745                 :         55 :         *stats = dev_stats;
    1746                 :         55 :         swap_uint64(&stats->rx_packets, &stats->tx_packets);
    1747                 :         55 :         swap_uint64(&stats->rx_bytes, &stats->tx_bytes);
    1748                 :         55 :         swap_uint64(&stats->rx_errors, &stats->tx_errors);
    1749                 :         55 :         swap_uint64(&stats->rx_dropped, &stats->tx_dropped);
    1750                 :         55 :         stats->rx_length_errors = 0;
    1751                 :         55 :         stats->rx_over_errors = 0;
    1752                 :         55 :         stats->rx_crc_errors = 0;
    1753                 :         55 :         stats->rx_frame_errors = 0;
    1754                 :         55 :         stats->rx_fifo_errors = 0;
    1755                 :         55 :         stats->rx_missed_errors = 0;
    1756                 :         55 :         stats->tx_aborted_errors = 0;
    1757                 :         55 :         stats->tx_carrier_errors = 0;
    1758                 :         55 :         stats->tx_fifo_errors = 0;
    1759                 :         55 :         stats->tx_heartbeat_errors = 0;
    1760                 :         55 :         stats->tx_window_errors = 0;
    1761                 :            :     } else {
    1762                 :            :         /* Use kernel netdev's packet and byte counts since vport counters
    1763                 :            :          * do not reflect packet counts on the wire when GSO, TSO or GRO
    1764                 :            :          * are enabled. */
    1765                 :          0 :         stats->rx_packets = dev_stats.tx_packets;
    1766                 :          0 :         stats->rx_bytes = dev_stats.tx_bytes;
    1767                 :          0 :         stats->tx_packets = dev_stats.rx_packets;
    1768                 :          0 :         stats->tx_bytes = dev_stats.rx_bytes;
    1769                 :            : 
    1770                 :          0 :         stats->rx_dropped          += dev_stats.tx_dropped;
    1771                 :          0 :         stats->tx_dropped          += dev_stats.rx_dropped;
    1772                 :            : 
    1773                 :          0 :         stats->rx_errors           += dev_stats.tx_errors;
    1774                 :          0 :         stats->tx_errors           += dev_stats.rx_errors;
    1775                 :            : 
    1776                 :          0 :         stats->multicast           += dev_stats.multicast;
    1777                 :          0 :         stats->collisions          += dev_stats.collisions;
    1778                 :            :     }
    1779                 :         55 :     ovs_mutex_unlock(&netdev->mutex);
    1780                 :            : 
    1781                 :         55 :     return error;
    1782                 :            : }
    1783                 :            : 
    1784                 :            : static int
    1785                 :        106 : netdev_internal_get_stats(const struct netdev *netdev_,
    1786                 :            :                           struct netdev_stats *stats)
    1787                 :            : {
    1788                 :        106 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1789                 :            :     int error;
    1790                 :            : 
    1791                 :        106 :     ovs_mutex_lock(&netdev->mutex);
    1792                 :        106 :     get_stats_via_vport(netdev_, stats);
    1793                 :        106 :     error = netdev->vport_stats_error;
    1794                 :        106 :     ovs_mutex_unlock(&netdev->mutex);
    1795                 :            : 
    1796                 :        106 :     return error;
    1797                 :            : }
    1798                 :            : 
    1799                 :            : static void
    1800                 :       3955 : netdev_linux_read_features(struct netdev_linux *netdev)
    1801                 :            : {
    1802                 :            :     struct ethtool_cmd ecmd;
    1803                 :            :     uint32_t speed;
    1804                 :            :     int error;
    1805                 :            : 
    1806         [ +  + ]:       3955 :     if (netdev->cache_valid & VALID_FEATURES) {
    1807                 :       3179 :         return;
    1808                 :            :     }
    1809                 :            : 
    1810                 :        776 :     COVERAGE_INC(netdev_get_ethtool);
    1811                 :        776 :     memset(&ecmd, 0, sizeof ecmd);
    1812                 :        776 :     error = netdev_linux_do_ethtool(netdev->up.name, &ecmd,
    1813                 :            :                                     ETHTOOL_GSET, "ETHTOOL_GSET");
    1814         [ -  + ]:        776 :     if (error) {
    1815                 :          0 :         goto out;
    1816                 :            :     }
    1817                 :            : 
    1818                 :            :     /* Supported features. */
    1819                 :        776 :     netdev->supported = 0;
    1820         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_10baseT_Half) {
    1821                 :          0 :         netdev->supported |= NETDEV_F_10MB_HD;
    1822                 :            :     }
    1823         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_10baseT_Full) {
    1824                 :          0 :         netdev->supported |= NETDEV_F_10MB_FD;
    1825                 :            :     }
    1826         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_100baseT_Half)  {
    1827                 :          0 :         netdev->supported |= NETDEV_F_100MB_HD;
    1828                 :            :     }
    1829         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_100baseT_Full) {
    1830                 :          0 :         netdev->supported |= NETDEV_F_100MB_FD;
    1831                 :            :     }
    1832         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_1000baseT_Half) {
    1833                 :          0 :         netdev->supported |= NETDEV_F_1GB_HD;
    1834                 :            :     }
    1835 [ +  - ][ -  + ]:        776 :     if ((ecmd.supported & SUPPORTED_1000baseT_Full) ||
    1836                 :        776 :         (ecmd.supported & SUPPORTED_1000baseKX_Full)) {
    1837                 :          0 :         netdev->supported |= NETDEV_F_1GB_FD;
    1838                 :            :     }
    1839 [ +  - ][ +  - ]:        776 :     if ((ecmd.supported & SUPPORTED_10000baseT_Full) ||
    1840         [ +  - ]:        776 :         (ecmd.supported & SUPPORTED_10000baseKX4_Full) ||
    1841         [ -  + ]:        776 :         (ecmd.supported & SUPPORTED_10000baseKR_Full) ||
    1842                 :        776 :         (ecmd.supported & SUPPORTED_10000baseR_FEC)) {
    1843                 :          0 :         netdev->supported |= NETDEV_F_10GB_FD;
    1844                 :            :     }
    1845 [ +  - ][ +  - ]:        776 :     if ((ecmd.supported & SUPPORTED_40000baseKR4_Full) ||
    1846         [ +  - ]:        776 :         (ecmd.supported & SUPPORTED_40000baseCR4_Full) ||
    1847         [ -  + ]:        776 :         (ecmd.supported & SUPPORTED_40000baseSR4_Full) ||
    1848                 :        776 :         (ecmd.supported & SUPPORTED_40000baseLR4_Full)) {
    1849                 :          0 :         netdev->supported |= NETDEV_F_40GB_FD;
    1850                 :            :     }
    1851         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_TP) {
    1852                 :          0 :         netdev->supported |= NETDEV_F_COPPER;
    1853                 :            :     }
    1854         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_FIBRE) {
    1855                 :          0 :         netdev->supported |= NETDEV_F_FIBER;
    1856                 :            :     }
    1857         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_Autoneg) {
    1858                 :          0 :         netdev->supported |= NETDEV_F_AUTONEG;
    1859                 :            :     }
    1860         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_Pause) {
    1861                 :          0 :         netdev->supported |= NETDEV_F_PAUSE;
    1862                 :            :     }
    1863         [ -  + ]:        776 :     if (ecmd.supported & SUPPORTED_Asym_Pause) {
    1864                 :          0 :         netdev->supported |= NETDEV_F_PAUSE_ASYM;
    1865                 :            :     }
    1866                 :            : 
    1867                 :            :     /* Advertised features. */
    1868                 :        776 :     netdev->advertised = 0;
    1869         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_10baseT_Half) {
    1870                 :          0 :         netdev->advertised |= NETDEV_F_10MB_HD;
    1871                 :            :     }
    1872         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_10baseT_Full) {
    1873                 :          0 :         netdev->advertised |= NETDEV_F_10MB_FD;
    1874                 :            :     }
    1875         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_100baseT_Half) {
    1876                 :          0 :         netdev->advertised |= NETDEV_F_100MB_HD;
    1877                 :            :     }
    1878         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_100baseT_Full) {
    1879                 :          0 :         netdev->advertised |= NETDEV_F_100MB_FD;
    1880                 :            :     }
    1881         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_1000baseT_Half) {
    1882                 :          0 :         netdev->advertised |= NETDEV_F_1GB_HD;
    1883                 :            :     }
    1884 [ +  - ][ -  + ]:        776 :     if ((ecmd.advertising & ADVERTISED_1000baseT_Full) ||
    1885                 :        776 :         (ecmd.advertising & ADVERTISED_1000baseKX_Full)) {
    1886                 :          0 :         netdev->advertised |= NETDEV_F_1GB_FD;
    1887                 :            :     }
    1888 [ +  - ][ +  - ]:        776 :     if ((ecmd.advertising & ADVERTISED_10000baseT_Full) ||
    1889         [ +  - ]:        776 :         (ecmd.advertising & ADVERTISED_10000baseKX4_Full) ||
    1890         [ -  + ]:        776 :         (ecmd.advertising & ADVERTISED_10000baseKR_Full) ||
    1891                 :        776 :         (ecmd.advertising & ADVERTISED_10000baseR_FEC)) {
    1892                 :          0 :         netdev->advertised |= NETDEV_F_10GB_FD;
    1893                 :            :     }
    1894 [ +  - ][ +  - ]:        776 :     if ((ecmd.advertising & ADVERTISED_40000baseKR4_Full) ||
    1895         [ +  - ]:        776 :         (ecmd.advertising & ADVERTISED_40000baseCR4_Full) ||
    1896         [ -  + ]:        776 :         (ecmd.advertising & ADVERTISED_40000baseSR4_Full) ||
    1897                 :        776 :         (ecmd.advertising & ADVERTISED_40000baseLR4_Full)) {
    1898                 :          0 :         netdev->advertised |= NETDEV_F_40GB_FD;
    1899                 :            :     }
    1900         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_TP) {
    1901                 :          0 :         netdev->advertised |= NETDEV_F_COPPER;
    1902                 :            :     }
    1903         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_FIBRE) {
    1904                 :          0 :         netdev->advertised |= NETDEV_F_FIBER;
    1905                 :            :     }
    1906         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_Autoneg) {
    1907                 :          0 :         netdev->advertised |= NETDEV_F_AUTONEG;
    1908                 :            :     }
    1909         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_Pause) {
    1910                 :          0 :         netdev->advertised |= NETDEV_F_PAUSE;
    1911                 :            :     }
    1912         [ -  + ]:        776 :     if (ecmd.advertising & ADVERTISED_Asym_Pause) {
    1913                 :          0 :         netdev->advertised |= NETDEV_F_PAUSE_ASYM;
    1914                 :            :     }
    1915                 :            : 
    1916                 :            :     /* Current settings. */
    1917                 :        776 :     speed = ethtool_cmd_speed(&ecmd);
    1918         [ +  + ]:        776 :     if (speed == SPEED_10) {
    1919         [ +  - ]:         80 :         netdev->current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD;
    1920         [ -  + ]:        696 :     } else if (speed == SPEED_100) {
    1921         [ #  # ]:          0 :         netdev->current = ecmd.duplex ? NETDEV_F_100MB_FD : NETDEV_F_100MB_HD;
    1922         [ -  + ]:        696 :     } else if (speed == SPEED_1000) {
    1923         [ #  # ]:          0 :         netdev->current = ecmd.duplex ? NETDEV_F_1GB_FD : NETDEV_F_1GB_HD;
    1924         [ +  - ]:        696 :     } else if (speed == SPEED_10000) {
    1925                 :        696 :         netdev->current = NETDEV_F_10GB_FD;
    1926         [ #  # ]:          0 :     } else if (speed == 40000) {
    1927                 :          0 :         netdev->current = NETDEV_F_40GB_FD;
    1928         [ #  # ]:          0 :     } else if (speed == 100000) {
    1929                 :          0 :         netdev->current = NETDEV_F_100GB_FD;
    1930         [ #  # ]:          0 :     } else if (speed == 1000000) {
    1931                 :          0 :         netdev->current = NETDEV_F_1TB_FD;
    1932                 :            :     } else {
    1933                 :          0 :         netdev->current = 0;
    1934                 :            :     }
    1935                 :            : 
    1936         [ +  - ]:        776 :     if (ecmd.port == PORT_TP) {
    1937                 :        776 :         netdev->current |= NETDEV_F_COPPER;
    1938         [ #  # ]:          0 :     } else if (ecmd.port == PORT_FIBRE) {
    1939                 :          0 :         netdev->current |= NETDEV_F_FIBER;
    1940                 :            :     }
    1941                 :            : 
    1942         [ -  + ]:        776 :     if (ecmd.autoneg) {
    1943                 :          0 :         netdev->current |= NETDEV_F_AUTONEG;
    1944                 :            :     }
    1945                 :            : 
    1946                 :            : out:
    1947                 :        776 :     netdev->cache_valid |= VALID_FEATURES;
    1948                 :        776 :     netdev->get_features_error = error;
    1949                 :            : }
    1950                 :            : 
    1951                 :            : /* Stores the features supported by 'netdev' into of '*current', '*advertised',
    1952                 :            :  * '*supported', and '*peer'.  Each value is a bitmap of NETDEV_* bits.
    1953                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
    1954                 :            : static int
    1955                 :       3955 : netdev_linux_get_features(const struct netdev *netdev_,
    1956                 :            :                           enum netdev_features *current,
    1957                 :            :                           enum netdev_features *advertised,
    1958                 :            :                           enum netdev_features *supported,
    1959                 :            :                           enum netdev_features *peer)
    1960                 :            : {
    1961                 :       3955 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1962                 :            :     int error;
    1963                 :            : 
    1964                 :       3955 :     ovs_mutex_lock(&netdev->mutex);
    1965                 :       3955 :     netdev_linux_read_features(netdev);
    1966         [ +  - ]:       3955 :     if (!netdev->get_features_error) {
    1967                 :       3955 :         *current = netdev->current;
    1968                 :       3955 :         *advertised = netdev->advertised;
    1969                 :       3955 :         *supported = netdev->supported;
    1970                 :       3955 :         *peer = 0;              /* XXX */
    1971                 :            :     }
    1972                 :       3955 :     error = netdev->get_features_error;
    1973                 :       3955 :     ovs_mutex_unlock(&netdev->mutex);
    1974                 :            : 
    1975                 :       3955 :     return error;
    1976                 :            : }
    1977                 :            : 
    1978                 :            : /* Set the features advertised by 'netdev' to 'advertise'. */
    1979                 :            : static int
    1980                 :          0 : netdev_linux_set_advertisements(struct netdev *netdev_,
    1981                 :            :                                 enum netdev_features advertise)
    1982                 :            : {
    1983                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    1984                 :            :     struct ethtool_cmd ecmd;
    1985                 :            :     int error;
    1986                 :            : 
    1987                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    1988                 :            : 
    1989                 :          0 :     COVERAGE_INC(netdev_get_ethtool);
    1990                 :          0 :     memset(&ecmd, 0, sizeof ecmd);
    1991                 :          0 :     error = netdev_linux_do_ethtool(netdev_get_name(netdev_), &ecmd,
    1992                 :            :                                     ETHTOOL_GSET, "ETHTOOL_GSET");
    1993         [ #  # ]:          0 :     if (error) {
    1994                 :          0 :         goto exit;
    1995                 :            :     }
    1996                 :            : 
    1997                 :          0 :     ecmd.advertising = 0;
    1998         [ #  # ]:          0 :     if (advertise & NETDEV_F_10MB_HD) {
    1999                 :          0 :         ecmd.advertising |= ADVERTISED_10baseT_Half;
    2000                 :            :     }
    2001         [ #  # ]:          0 :     if (advertise & NETDEV_F_10MB_FD) {
    2002                 :          0 :         ecmd.advertising |= ADVERTISED_10baseT_Full;
    2003                 :            :     }
    2004         [ #  # ]:          0 :     if (advertise & NETDEV_F_100MB_HD) {
    2005                 :          0 :         ecmd.advertising |= ADVERTISED_100baseT_Half;
    2006                 :            :     }
    2007         [ #  # ]:          0 :     if (advertise & NETDEV_F_100MB_FD) {
    2008                 :          0 :         ecmd.advertising |= ADVERTISED_100baseT_Full;
    2009                 :            :     }
    2010         [ #  # ]:          0 :     if (advertise & NETDEV_F_1GB_HD) {
    2011                 :          0 :         ecmd.advertising |= ADVERTISED_1000baseT_Half;
    2012                 :            :     }
    2013         [ #  # ]:          0 :     if (advertise & NETDEV_F_1GB_FD) {
    2014                 :          0 :         ecmd.advertising |= ADVERTISED_1000baseT_Full;
    2015                 :            :     }
    2016         [ #  # ]:          0 :     if (advertise & NETDEV_F_10GB_FD) {
    2017                 :          0 :         ecmd.advertising |= ADVERTISED_10000baseT_Full;
    2018                 :            :     }
    2019         [ #  # ]:          0 :     if (advertise & NETDEV_F_COPPER) {
    2020                 :          0 :         ecmd.advertising |= ADVERTISED_TP;
    2021                 :            :     }
    2022         [ #  # ]:          0 :     if (advertise & NETDEV_F_FIBER) {
    2023                 :          0 :         ecmd.advertising |= ADVERTISED_FIBRE;
    2024                 :            :     }
    2025         [ #  # ]:          0 :     if (advertise & NETDEV_F_AUTONEG) {
    2026                 :          0 :         ecmd.advertising |= ADVERTISED_Autoneg;
    2027                 :            :     }
    2028         [ #  # ]:          0 :     if (advertise & NETDEV_F_PAUSE) {
    2029                 :          0 :         ecmd.advertising |= ADVERTISED_Pause;
    2030                 :            :     }
    2031         [ #  # ]:          0 :     if (advertise & NETDEV_F_PAUSE_ASYM) {
    2032                 :          0 :         ecmd.advertising |= ADVERTISED_Asym_Pause;
    2033                 :            :     }
    2034                 :          0 :     COVERAGE_INC(netdev_set_ethtool);
    2035                 :          0 :     error = netdev_linux_do_ethtool(netdev_get_name(netdev_), &ecmd,
    2036                 :            :                                     ETHTOOL_SSET, "ETHTOOL_SSET");
    2037                 :            : 
    2038                 :            : exit:
    2039                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2040                 :          0 :     return error;
    2041                 :            : }
    2042                 :            : 
    2043                 :            : /* Attempts to set input rate limiting (policing) policy.  Returns 0 if
    2044                 :            :  * successful, otherwise a positive errno value. */
    2045                 :            : static int
    2046                 :       4175 : netdev_linux_set_policing(struct netdev *netdev_,
    2047                 :            :                           uint32_t kbits_rate, uint32_t kbits_burst)
    2048                 :            : {
    2049                 :       4175 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2050                 :       4175 :     const char *netdev_name = netdev_get_name(netdev_);
    2051                 :            :     int error;
    2052                 :            : 
    2053                 :       4175 :     kbits_burst = (!kbits_rate ? 0       /* Force to 0 if no rate specified. */
    2054         [ -  + ]:       4175 :                    : !kbits_burst ? 8000 /* Default to 8000 kbits if 0. */
    2055         [ #  # ]:          0 :                    : kbits_burst);       /* Stick with user-specified value. */
    2056                 :            : 
    2057                 :       4175 :     ovs_mutex_lock(&netdev->mutex);
    2058         [ +  + ]:       4175 :     if (netdev->cache_valid & VALID_POLICING) {
    2059                 :       3251 :         error = netdev->netdev_policing_error;
    2060 [ +  + ][ +  - ]:       3251 :         if (error || (netdev->kbits_rate == kbits_rate &&
                 [ -  + ]
    2061                 :       3248 :                       netdev->kbits_burst == kbits_burst)) {
    2062                 :            :             /* Assume that settings haven't changed since we last set them. */
    2063                 :            :             goto out;
    2064                 :            :         }
    2065                 :          0 :         netdev->cache_valid &= ~VALID_POLICING;
    2066                 :            :     }
    2067                 :            : 
    2068                 :        924 :     COVERAGE_INC(netdev_set_policing);
    2069                 :            :     /* Remove any existing ingress qdisc. */
    2070                 :        924 :     error = tc_add_del_ingress_qdisc(netdev_, false);
    2071         [ +  + ]:        924 :     if (error) {
    2072         [ +  - ]:          2 :         VLOG_WARN_RL(&rl, "%s: removing policing failed: %s",
    2073                 :            :                      netdev_name, ovs_strerror(error));
    2074                 :          2 :         goto out;
    2075                 :            :     }
    2076                 :            : 
    2077         [ -  + ]:        922 :     if (kbits_rate) {
    2078                 :          0 :         error = tc_add_del_ingress_qdisc(netdev_, true);
    2079         [ #  # ]:          0 :         if (error) {
    2080         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: adding policing qdisc failed: %s",
    2081                 :            :                          netdev_name, ovs_strerror(error));
    2082                 :          0 :             goto out;
    2083                 :            :         }
    2084                 :            : 
    2085                 :          0 :         error = tc_add_policer(netdev_, kbits_rate, kbits_burst);
    2086         [ #  # ]:          0 :         if (error){
    2087         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: adding policing action failed: %s",
    2088                 :            :                     netdev_name, ovs_strerror(error));
    2089                 :          0 :             goto out;
    2090                 :            :         }
    2091                 :            :     }
    2092                 :            : 
    2093                 :        922 :     netdev->kbits_rate = kbits_rate;
    2094                 :        922 :     netdev->kbits_burst = kbits_burst;
    2095                 :            : 
    2096                 :            : out:
    2097 [ +  + ][ +  - ]:       4175 :     if (!error || error == ENODEV) {
    2098                 :       4175 :         netdev->netdev_policing_error = error;
    2099                 :       4175 :         netdev->cache_valid |= VALID_POLICING;
    2100                 :            :     }
    2101                 :       4175 :     ovs_mutex_unlock(&netdev->mutex);
    2102                 :       4175 :     return error;
    2103                 :            : }
    2104                 :            : 
    2105                 :            : static int
    2106                 :          0 : netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED,
    2107                 :            :                            struct sset *types)
    2108                 :            : {
    2109                 :            :     const struct tc_ops *const *opsp;
    2110         [ #  # ]:          0 :     for (opsp = tcs; *opsp != NULL; opsp++) {
    2111                 :          0 :         const struct tc_ops *ops = *opsp;
    2112 [ #  # ][ #  # ]:          0 :         if (ops->tc_install && ops->ovs_name[0] != '\0') {
    2113                 :          0 :             sset_add(types, ops->ovs_name);
    2114                 :            :         }
    2115                 :            :     }
    2116                 :          0 :     return 0;
    2117                 :            : }
    2118                 :            : 
    2119                 :            : static const struct tc_ops *
    2120                 :       4175 : tc_lookup_ovs_name(const char *name)
    2121                 :            : {
    2122                 :            :     const struct tc_ops *const *opsp;
    2123                 :            : 
    2124         [ +  - ]:      29225 :     for (opsp = tcs; *opsp != NULL; opsp++) {
    2125                 :      29225 :         const struct tc_ops *ops = *opsp;
    2126         [ +  + ]:      29225 :         if (!strcmp(name, ops->ovs_name)) {
    2127                 :       4175 :             return ops;
    2128                 :            :         }
    2129                 :            :     }
    2130                 :          0 :     return NULL;
    2131                 :            : }
    2132                 :            : 
    2133                 :            : static const struct tc_ops *
    2134                 :        233 : tc_lookup_linux_name(const char *name)
    2135                 :            : {
    2136                 :            :     const struct tc_ops *const *opsp;
    2137                 :            : 
    2138         [ +  - ]:        932 :     for (opsp = tcs; *opsp != NULL; opsp++) {
    2139                 :        932 :         const struct tc_ops *ops = *opsp;
    2140 [ +  - ][ +  + ]:        932 :         if (ops->linux_name && !strcmp(name, ops->linux_name)) {
    2141                 :        233 :             return ops;
    2142                 :            :         }
    2143                 :            :     }
    2144                 :          0 :     return NULL;
    2145                 :            : }
    2146                 :            : 
    2147                 :            : static struct tc_queue *
    2148                 :          0 : tc_find_queue__(const struct netdev *netdev_, unsigned int queue_id,
    2149                 :            :                 size_t hash)
    2150                 :            : {
    2151                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2152                 :            :     struct tc_queue *queue;
    2153                 :            : 
    2154 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH_IN_BUCKET (queue, hmap_node, hash, &netdev->tc->queues) {
    2155         [ #  # ]:          0 :         if (queue->queue_id == queue_id) {
    2156                 :          0 :             return queue;
    2157                 :            :         }
    2158                 :            :     }
    2159                 :          0 :     return NULL;
    2160                 :            : }
    2161                 :            : 
    2162                 :            : static struct tc_queue *
    2163                 :          0 : tc_find_queue(const struct netdev *netdev, unsigned int queue_id)
    2164                 :            : {
    2165                 :          0 :     return tc_find_queue__(netdev, queue_id, hash_int(queue_id, 0));
    2166                 :            : }
    2167                 :            : 
    2168                 :            : static int
    2169                 :          0 : netdev_linux_get_qos_capabilities(const struct netdev *netdev OVS_UNUSED,
    2170                 :            :                                   const char *type,
    2171                 :            :                                   struct netdev_qos_capabilities *caps)
    2172                 :            : {
    2173                 :          0 :     const struct tc_ops *ops = tc_lookup_ovs_name(type);
    2174         [ #  # ]:          0 :     if (!ops) {
    2175                 :          0 :         return EOPNOTSUPP;
    2176                 :            :     }
    2177                 :          0 :     caps->n_queues = ops->n_queues;
    2178                 :          0 :     return 0;
    2179                 :            : }
    2180                 :            : 
    2181                 :            : static int
    2182                 :          0 : netdev_linux_get_qos(const struct netdev *netdev_,
    2183                 :            :                      const char **typep, struct smap *details)
    2184                 :            : {
    2185                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2186                 :            :     int error;
    2187                 :            : 
    2188                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2189                 :          0 :     error = tc_query_qdisc(netdev_);
    2190         [ #  # ]:          0 :     if (!error) {
    2191                 :          0 :         *typep = netdev->tc->ops->ovs_name;
    2192                 :          0 :         error = (netdev->tc->ops->qdisc_get
    2193                 :          0 :                  ? netdev->tc->ops->qdisc_get(netdev_, details)
    2194         [ #  # ]:          0 :                  : 0);
    2195                 :            :     }
    2196                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2197                 :            : 
    2198                 :          0 :     return error;
    2199                 :            : }
    2200                 :            : 
    2201                 :            : static int
    2202                 :       4175 : netdev_linux_set_qos(struct netdev *netdev_,
    2203                 :            :                      const char *type, const struct smap *details)
    2204                 :            : {
    2205                 :       4175 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2206                 :            :     const struct tc_ops *new_ops;
    2207                 :            :     int error;
    2208                 :            : 
    2209                 :       4175 :     new_ops = tc_lookup_ovs_name(type);
    2210 [ +  - ][ -  + ]:       4175 :     if (!new_ops || !new_ops->tc_install) {
    2211                 :          0 :         return EOPNOTSUPP;
    2212                 :            :     }
    2213                 :            : 
    2214         [ -  + ]:       4175 :     if (new_ops == &tc_ops_noop) {
    2215                 :          0 :         return new_ops->tc_install(netdev_, details);
    2216                 :            :     }
    2217                 :            : 
    2218                 :       4175 :     ovs_mutex_lock(&netdev->mutex);
    2219                 :       4175 :     error = tc_query_qdisc(netdev_);
    2220         [ -  + ]:       4175 :     if (error) {
    2221                 :          0 :         goto exit;
    2222                 :            :     }
    2223                 :            : 
    2224         [ +  + ]:       4175 :     if (new_ops == netdev->tc->ops) {
    2225         [ -  + ]:       3942 :         error = new_ops->qdisc_set ? new_ops->qdisc_set(netdev_, details) : 0;
    2226                 :            :     } else {
    2227                 :            :         /* Delete existing qdisc. */
    2228                 :        233 :         error = tc_del_qdisc(netdev_);
    2229         [ -  + ]:        233 :         if (error) {
    2230                 :          0 :             goto exit;
    2231                 :            :         }
    2232         [ -  + ]:        233 :         ovs_assert(netdev->tc == NULL);
    2233                 :            : 
    2234                 :            :         /* Install new qdisc. */
    2235                 :        233 :         error = new_ops->tc_install(netdev_, details);
    2236         [ -  + ]:        233 :         ovs_assert((error == 0) == (netdev->tc != NULL));
    2237                 :            :     }
    2238                 :            : 
    2239                 :            : exit:
    2240                 :       4175 :     ovs_mutex_unlock(&netdev->mutex);
    2241                 :       4175 :     return error;
    2242                 :            : }
    2243                 :            : 
    2244                 :            : static int
    2245                 :          0 : netdev_linux_get_queue(const struct netdev *netdev_,
    2246                 :            :                        unsigned int queue_id, struct smap *details)
    2247                 :            : {
    2248                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2249                 :            :     int error;
    2250                 :            : 
    2251                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2252                 :          0 :     error = tc_query_qdisc(netdev_);
    2253         [ #  # ]:          0 :     if (!error) {
    2254                 :          0 :         struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
    2255                 :          0 :         error = (queue
    2256                 :          0 :                 ? netdev->tc->ops->class_get(netdev_, queue, details)
    2257         [ #  # ]:          0 :                 : ENOENT);
    2258                 :            :     }
    2259                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2260                 :            : 
    2261                 :          0 :     return error;
    2262                 :            : }
    2263                 :            : 
    2264                 :            : static int
    2265                 :          0 : netdev_linux_set_queue(struct netdev *netdev_,
    2266                 :            :                        unsigned int queue_id, const struct smap *details)
    2267                 :            : {
    2268                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2269                 :            :     int error;
    2270                 :            : 
    2271                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2272                 :          0 :     error = tc_query_qdisc(netdev_);
    2273         [ #  # ]:          0 :     if (!error) {
    2274                 :          0 :         error = (queue_id < netdev->tc->ops->n_queues
    2275         [ #  # ]:          0 :                  && netdev->tc->ops->class_set
    2276                 :          0 :                  ? netdev->tc->ops->class_set(netdev_, queue_id, details)
    2277         [ #  # ]:          0 :                  : EINVAL);
    2278                 :            :     }
    2279                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2280                 :            : 
    2281                 :          0 :     return error;
    2282                 :            : }
    2283                 :            : 
    2284                 :            : static int
    2285                 :          0 : netdev_linux_delete_queue(struct netdev *netdev_, unsigned int queue_id)
    2286                 :            : {
    2287                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2288                 :            :     int error;
    2289                 :            : 
    2290                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2291                 :          0 :     error = tc_query_qdisc(netdev_);
    2292         [ #  # ]:          0 :     if (!error) {
    2293         [ #  # ]:          0 :         if (netdev->tc->ops->class_delete) {
    2294                 :          0 :             struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
    2295                 :          0 :             error = (queue
    2296                 :          0 :                      ? netdev->tc->ops->class_delete(netdev_, queue)
    2297         [ #  # ]:          0 :                      : ENOENT);
    2298                 :            :         } else {
    2299                 :          0 :             error = EINVAL;
    2300                 :            :         }
    2301                 :            :     }
    2302                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2303                 :            : 
    2304                 :          0 :     return error;
    2305                 :            : }
    2306                 :            : 
    2307                 :            : static int
    2308                 :          0 : netdev_linux_get_queue_stats(const struct netdev *netdev_,
    2309                 :            :                              unsigned int queue_id,
    2310                 :            :                              struct netdev_queue_stats *stats)
    2311                 :            : {
    2312                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2313                 :            :     int error;
    2314                 :            : 
    2315                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2316                 :          0 :     error = tc_query_qdisc(netdev_);
    2317         [ #  # ]:          0 :     if (!error) {
    2318         [ #  # ]:          0 :         if (netdev->tc->ops->class_get_stats) {
    2319                 :          0 :             const struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
    2320         [ #  # ]:          0 :             if (queue) {
    2321                 :          0 :                 stats->created = queue->created;
    2322                 :          0 :                 error = netdev->tc->ops->class_get_stats(netdev_, queue,
    2323                 :            :                                                          stats);
    2324                 :            :             } else {
    2325                 :          0 :                 error = ENOENT;
    2326                 :            :             }
    2327                 :            :         } else {
    2328                 :          0 :             error = EOPNOTSUPP;
    2329                 :            :         }
    2330                 :            :     }
    2331                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2332                 :            : 
    2333                 :          0 :     return error;
    2334                 :            : }
    2335                 :            : 
    2336                 :            : struct queue_dump_state {
    2337                 :            :     struct nl_dump dump;
    2338                 :            :     struct ofpbuf buf;
    2339                 :            : };
    2340                 :            : 
    2341                 :            : static bool
    2342                 :          0 : start_queue_dump(const struct netdev *netdev, struct queue_dump_state *state)
    2343                 :            : {
    2344                 :            :     struct ofpbuf request;
    2345                 :            :     struct tcmsg *tcmsg;
    2346                 :            : 
    2347                 :          0 :     tcmsg = tc_make_request(netdev, RTM_GETTCLASS, 0, &request);
    2348         [ #  # ]:          0 :     if (!tcmsg) {
    2349                 :          0 :         return false;
    2350                 :            :     }
    2351                 :          0 :     tcmsg->tcm_parent = 0;
    2352                 :          0 :     nl_dump_start(&state->dump, NETLINK_ROUTE, &request);
    2353                 :          0 :     ofpbuf_uninit(&request);
    2354                 :            : 
    2355                 :          0 :     ofpbuf_init(&state->buf, NL_DUMP_BUFSIZE);
    2356                 :          0 :     return true;
    2357                 :            : }
    2358                 :            : 
    2359                 :            : static int
    2360                 :          0 : finish_queue_dump(struct queue_dump_state *state)
    2361                 :            : {
    2362                 :          0 :     ofpbuf_uninit(&state->buf);
    2363                 :          0 :     return nl_dump_done(&state->dump);
    2364                 :            : }
    2365                 :            : 
    2366                 :            : struct netdev_linux_queue_state {
    2367                 :            :     unsigned int *queues;
    2368                 :            :     size_t cur_queue;
    2369                 :            :     size_t n_queues;
    2370                 :            : };
    2371                 :            : 
    2372                 :            : static int
    2373                 :          0 : netdev_linux_queue_dump_start(const struct netdev *netdev_, void **statep)
    2374                 :            : {
    2375                 :          0 :     const struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2376                 :            :     int error;
    2377                 :            : 
    2378                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2379                 :          0 :     error = tc_query_qdisc(netdev_);
    2380         [ #  # ]:          0 :     if (!error) {
    2381         [ #  # ]:          0 :         if (netdev->tc->ops->class_get) {
    2382                 :            :             struct netdev_linux_queue_state *state;
    2383                 :            :             struct tc_queue *queue;
    2384                 :            :             size_t i;
    2385                 :            : 
    2386                 :          0 :             *statep = state = xmalloc(sizeof *state);
    2387                 :          0 :             state->n_queues = hmap_count(&netdev->tc->queues);
    2388                 :          0 :             state->cur_queue = 0;
    2389                 :          0 :             state->queues = xmalloc(state->n_queues * sizeof *state->queues);
    2390                 :            : 
    2391                 :          0 :             i = 0;
    2392 [ #  # ][ #  # ]:          0 :             HMAP_FOR_EACH (queue, hmap_node, &netdev->tc->queues) {
    2393                 :          0 :                 state->queues[i++] = queue->queue_id;
    2394                 :            :             }
    2395                 :            :         } else {
    2396                 :          0 :             error = EOPNOTSUPP;
    2397                 :            :         }
    2398                 :            :     }
    2399                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2400                 :            : 
    2401                 :          0 :     return error;
    2402                 :            : }
    2403                 :            : 
    2404                 :            : static int
    2405                 :          0 : netdev_linux_queue_dump_next(const struct netdev *netdev_, void *state_,
    2406                 :            :                              unsigned int *queue_idp, struct smap *details)
    2407                 :            : {
    2408                 :          0 :     const struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2409                 :          0 :     struct netdev_linux_queue_state *state = state_;
    2410                 :          0 :     int error = EOF;
    2411                 :            : 
    2412                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2413         [ #  # ]:          0 :     while (state->cur_queue < state->n_queues) {
    2414                 :          0 :         unsigned int queue_id = state->queues[state->cur_queue++];
    2415                 :          0 :         struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
    2416                 :            : 
    2417         [ #  # ]:          0 :         if (queue) {
    2418                 :          0 :             *queue_idp = queue_id;
    2419                 :          0 :             error = netdev->tc->ops->class_get(netdev_, queue, details);
    2420                 :          0 :             break;
    2421                 :            :         }
    2422                 :            :     }
    2423                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2424                 :            : 
    2425                 :          0 :     return error;
    2426                 :            : }
    2427                 :            : 
    2428                 :            : static int
    2429                 :          0 : netdev_linux_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
    2430                 :            :                              void *state_)
    2431                 :            : {
    2432                 :          0 :     struct netdev_linux_queue_state *state = state_;
    2433                 :            : 
    2434                 :          0 :     free(state->queues);
    2435                 :          0 :     free(state);
    2436                 :          0 :     return 0;
    2437                 :            : }
    2438                 :            : 
    2439                 :            : static int
    2440                 :          0 : netdev_linux_dump_queue_stats(const struct netdev *netdev_,
    2441                 :            :                               netdev_dump_queue_stats_cb *cb, void *aux)
    2442                 :            : {
    2443                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2444                 :            :     int error;
    2445                 :            : 
    2446                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2447                 :          0 :     error = tc_query_qdisc(netdev_);
    2448         [ #  # ]:          0 :     if (!error) {
    2449                 :            :         struct queue_dump_state state;
    2450                 :            : 
    2451         [ #  # ]:          0 :         if (!netdev->tc->ops->class_dump_stats) {
    2452                 :          0 :             error = EOPNOTSUPP;
    2453         [ #  # ]:          0 :         } else if (!start_queue_dump(netdev_, &state)) {
    2454                 :          0 :             error = ENODEV;
    2455                 :            :         } else {
    2456                 :            :             struct ofpbuf msg;
    2457                 :            :             int retval;
    2458                 :            : 
    2459         [ #  # ]:          0 :             while (nl_dump_next(&state.dump, &msg, &state.buf)) {
    2460                 :          0 :                 retval = netdev->tc->ops->class_dump_stats(netdev_, &msg,
    2461                 :            :                                                            cb, aux);
    2462         [ #  # ]:          0 :                 if (retval) {
    2463                 :          0 :                     error = retval;
    2464                 :            :                 }
    2465                 :            :             }
    2466                 :            : 
    2467                 :          0 :             retval = finish_queue_dump(&state);
    2468         [ #  # ]:          0 :             if (retval) {
    2469                 :          0 :                 error = retval;
    2470                 :            :             }
    2471                 :            :         }
    2472                 :            :     }
    2473                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2474                 :            : 
    2475                 :          0 :     return error;
    2476                 :            : }
    2477                 :            : 
    2478                 :            : static int
    2479                 :          0 : netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
    2480                 :            :                      struct in_addr netmask)
    2481                 :            : {
    2482                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2483                 :            :     int error;
    2484                 :            : 
    2485                 :          0 :     ovs_mutex_lock(&netdev->mutex);
    2486                 :          0 :     error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address);
    2487         [ #  # ]:          0 :     if (!error) {
    2488         [ #  # ]:          0 :         if (address.s_addr != INADDR_ANY) {
    2489                 :          0 :             error = do_set_addr(netdev_, SIOCSIFNETMASK,
    2490                 :            :                                 "SIOCSIFNETMASK", netmask);
    2491                 :            :         }
    2492                 :            :     }
    2493                 :            : 
    2494                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
    2495                 :            : 
    2496                 :          0 :     return error;
    2497                 :            : }
    2498                 :            : 
    2499                 :            : /* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
    2500                 :            :  * Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
    2501                 :            :  * error. */
    2502                 :            : static int
    2503                 :      41940 : netdev_linux_get_addr_list(const struct netdev *netdev_,
    2504                 :            :                           struct in6_addr **addr, struct in6_addr **mask, int *n_cnt)
    2505                 :            : {
    2506                 :      41940 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2507                 :            :     int error;
    2508                 :            : 
    2509                 :      41940 :     ovs_mutex_lock(&netdev->mutex);
    2510                 :      41940 :     error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
    2511                 :      41940 :     ovs_mutex_unlock(&netdev->mutex);
    2512                 :            : 
    2513                 :      41940 :     return error;
    2514                 :            : }
    2515                 :            : 
    2516                 :            : static void
    2517                 :          0 : make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr)
    2518                 :            : {
    2519                 :            :     struct sockaddr_in sin;
    2520                 :          0 :     memset(&sin, 0, sizeof sin);
    2521                 :          0 :     sin.sin_family = AF_INET;
    2522                 :          0 :     sin.sin_addr = addr;
    2523                 :          0 :     sin.sin_port = 0;
    2524                 :            : 
    2525                 :          0 :     memset(sa, 0, sizeof *sa);
    2526                 :          0 :     memcpy(sa, &sin, sizeof sin);
    2527                 :          0 : }
    2528                 :            : 
    2529                 :            : static int
    2530                 :          0 : do_set_addr(struct netdev *netdev,
    2531                 :            :             int ioctl_nr, const char *ioctl_name, struct in_addr addr)
    2532                 :            : {
    2533                 :            :     struct ifreq ifr;
    2534                 :            : 
    2535                 :          0 :     make_in4_sockaddr(&ifr.ifr_addr, addr);
    2536                 :          0 :     return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
    2537                 :            :                                ioctl_name);
    2538                 :            : }
    2539                 :            : 
    2540                 :            : /* Adds 'router' as a default IP gateway. */
    2541                 :            : static int
    2542                 :          0 : netdev_linux_add_router(struct netdev *netdev OVS_UNUSED, struct in_addr router)
    2543                 :            : {
    2544                 :          0 :     struct in_addr any = { INADDR_ANY };
    2545                 :            :     struct rtentry rt;
    2546                 :            :     int error;
    2547                 :            : 
    2548                 :          0 :     memset(&rt, 0, sizeof rt);
    2549                 :          0 :     make_in4_sockaddr(&rt.rt_dst, any);
    2550                 :          0 :     make_in4_sockaddr(&rt.rt_gateway, router);
    2551                 :          0 :     make_in4_sockaddr(&rt.rt_genmask, any);
    2552                 :          0 :     rt.rt_flags = RTF_UP | RTF_GATEWAY;
    2553                 :          0 :     error = af_inet_ioctl(SIOCADDRT, &rt);
    2554         [ #  # ]:          0 :     if (error) {
    2555         [ #  # ]:          0 :         VLOG_WARN("ioctl(SIOCADDRT): %s", ovs_strerror(error));
    2556                 :            :     }
    2557                 :          0 :     return error;
    2558                 :            : }
    2559                 :            : 
    2560                 :            : static int
    2561                 :          0 : netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop,
    2562                 :            :                           char **netdev_name)
    2563                 :            : {
    2564                 :            :     static const char fn[] = "/proc/net/route";
    2565                 :            :     FILE *stream;
    2566                 :            :     char line[256];
    2567                 :            :     int ln;
    2568                 :            : 
    2569                 :          0 :     *netdev_name = NULL;
    2570                 :          0 :     stream = fopen(fn, "r");
    2571         [ #  # ]:          0 :     if (stream == NULL) {
    2572         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "%s: open failed: %s", fn, ovs_strerror(errno));
    2573                 :          0 :         return errno;
    2574                 :            :     }
    2575                 :            : 
    2576                 :          0 :     ln = 0;
    2577         [ #  # ]:          0 :     while (fgets(line, sizeof line, stream)) {
    2578         [ #  # ]:          0 :         if (++ln >= 2) {
    2579                 :            :             char iface[17];
    2580                 :            :             ovs_be32 dest, gateway, mask;
    2581                 :            :             int refcnt, metric, mtu;
    2582                 :            :             unsigned int flags, use, window, irtt;
    2583                 :            : 
    2584         [ #  # ]:          0 :             if (!ovs_scan(line,
    2585                 :            :                           "%16s %"SCNx32" %"SCNx32" %04X %d %u %d %"SCNx32
    2586                 :            :                           " %d %u %u\n",
    2587                 :            :                           iface, &dest, &gateway, &flags, &refcnt,
    2588                 :            :                           &use, &metric, &mask, &mtu, &window, &irtt)) {
    2589         [ #  # ]:          0 :                 VLOG_WARN_RL(&rl, "%s: could not parse line %d: %s",
    2590                 :            :                         fn, ln, line);
    2591                 :          0 :                 continue;
    2592                 :            :             }
    2593         [ #  # ]:          0 :             if (!(flags & RTF_UP)) {
    2594                 :            :                 /* Skip routes that aren't up. */
    2595                 :          0 :                 continue;
    2596                 :            :             }
    2597                 :            : 
    2598                 :            :             /* The output of 'dest', 'mask', and 'gateway' were given in
    2599                 :            :              * network byte order, so we don't need need any endian
    2600                 :            :              * conversions here. */
    2601         [ #  # ]:          0 :             if ((dest & mask) == (host->s_addr & mask)) {
    2602         [ #  # ]:          0 :                 if (!gateway) {
    2603                 :            :                     /* The host is directly reachable. */
    2604                 :          0 :                     next_hop->s_addr = 0;
    2605                 :            :                 } else {
    2606                 :            :                     /* To reach the host, we must go through a gateway. */
    2607                 :          0 :                     next_hop->s_addr = gateway;
    2608                 :            :                 }
    2609                 :          0 :                 *netdev_name = xstrdup(iface);
    2610                 :          0 :                 fclose(stream);
    2611                 :          0 :                 return 0;
    2612                 :            :             }
    2613                 :            :         }
    2614                 :            :     }
    2615                 :            : 
    2616                 :          0 :     fclose(stream);
    2617                 :          0 :     return ENXIO;
    2618                 :            : }
    2619                 :            : 
    2620                 :            : static int
    2621                 :       2998 : netdev_linux_get_status(const struct netdev *netdev_, struct smap *smap)
    2622                 :            : {
    2623                 :       2998 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2624                 :       2998 :     int error = 0;
    2625                 :            : 
    2626                 :       2998 :     ovs_mutex_lock(&netdev->mutex);
    2627         [ +  + ]:       2998 :     if (!(netdev->cache_valid & VALID_DRVINFO)) {
    2628                 :        268 :         struct ethtool_cmd *cmd = (struct ethtool_cmd *) &netdev->drvinfo;
    2629                 :            : 
    2630                 :        268 :         COVERAGE_INC(netdev_get_ethtool);
    2631                 :        268 :         memset(&netdev->drvinfo, 0, sizeof netdev->drvinfo);
    2632                 :        268 :         error = netdev_linux_do_ethtool(netdev->up.name,
    2633                 :            :                                         cmd,
    2634                 :            :                                         ETHTOOL_GDRVINFO,
    2635                 :            :                                         "ETHTOOL_GDRVINFO");
    2636         [ +  - ]:        268 :         if (!error) {
    2637                 :        268 :             netdev->cache_valid |= VALID_DRVINFO;
    2638                 :            :         }
    2639                 :            :     }
    2640                 :            : 
    2641         [ +  - ]:       2998 :     if (!error) {
    2642                 :       2998 :         smap_add(smap, "driver_name", netdev->drvinfo.driver);
    2643                 :       2998 :         smap_add(smap, "driver_version", netdev->drvinfo.version);
    2644                 :       2998 :         smap_add(smap, "firmware_version", netdev->drvinfo.fw_version);
    2645                 :            :     }
    2646                 :       2998 :     ovs_mutex_unlock(&netdev->mutex);
    2647                 :            : 
    2648                 :       2998 :     return error;
    2649                 :            : }
    2650                 :            : 
    2651                 :            : static int
    2652                 :       1238 : netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED,
    2653                 :            :                            struct smap *smap)
    2654                 :            : {
    2655                 :       1238 :     smap_add(smap, "driver_name", "openvswitch");
    2656                 :       1238 :     return 0;
    2657                 :            : }
    2658                 :            : 
    2659                 :            : /* Looks up the ARP table entry for 'ip' on 'netdev'.  If one exists and can be
    2660                 :            :  * successfully retrieved, it stores the corresponding MAC address in 'mac' and
    2661                 :            :  * returns 0.  Otherwise, it returns a positive errno value; in particular,
    2662                 :            :  * ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
    2663                 :            : static int
    2664                 :          0 : netdev_linux_arp_lookup(const struct netdev *netdev,
    2665                 :            :                         ovs_be32 ip, struct eth_addr *mac)
    2666                 :            : {
    2667                 :            :     struct arpreq r;
    2668                 :            :     struct sockaddr_in sin;
    2669                 :            :     int retval;
    2670                 :            : 
    2671                 :          0 :     memset(&r, 0, sizeof r);
    2672                 :          0 :     memset(&sin, 0, sizeof sin);
    2673                 :          0 :     sin.sin_family = AF_INET;
    2674                 :          0 :     sin.sin_addr.s_addr = ip;
    2675                 :          0 :     sin.sin_port = 0;
    2676                 :          0 :     memcpy(&r.arp_pa, &sin, sizeof sin);
    2677                 :          0 :     r.arp_ha.sa_family = ARPHRD_ETHER;
    2678                 :          0 :     r.arp_flags = 0;
    2679                 :          0 :     ovs_strzcpy(r.arp_dev, netdev_get_name(netdev), sizeof r.arp_dev);
    2680                 :          0 :     COVERAGE_INC(netdev_arp_lookup);
    2681                 :          0 :     retval = af_inet_ioctl(SIOCGARP, &r);
    2682         [ #  # ]:          0 :     if (!retval) {
    2683                 :          0 :         memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN);
    2684         [ #  # ]:          0 :     } else if (retval != ENXIO) {
    2685         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "%s: could not look up ARP entry for "IP_FMT": %s",
    2686                 :            :                      netdev_get_name(netdev), IP_ARGS(ip),
    2687                 :            :                      ovs_strerror(retval));
    2688                 :            :     }
    2689                 :          0 :     return retval;
    2690                 :            : }
    2691                 :            : 
    2692                 :            : static int
    2693                 :      65454 : nd_to_iff_flags(enum netdev_flags nd)
    2694                 :            : {
    2695                 :      65454 :     int iff = 0;
    2696         [ +  + ]:      65454 :     if (nd & NETDEV_UP) {
    2697                 :         35 :         iff |= IFF_UP;
    2698                 :            :     }
    2699         [ +  + ]:      65454 :     if (nd & NETDEV_PROMISC) {
    2700                 :        179 :         iff |= IFF_PROMISC;
    2701                 :            :     }
    2702         [ -  + ]:      65454 :     if (nd & NETDEV_LOOPBACK) {
    2703                 :          0 :         iff |= IFF_LOOPBACK;
    2704                 :            :     }
    2705                 :      65454 :     return iff;
    2706                 :            : }
    2707                 :            : 
    2708                 :            : static int
    2709                 :      32727 : iff_to_nd_flags(int iff)
    2710                 :            : {
    2711                 :      32727 :     enum netdev_flags nd = 0;
    2712         [ +  + ]:      32727 :     if (iff & IFF_UP) {
    2713                 :      25674 :         nd |= NETDEV_UP;
    2714                 :            :     }
    2715         [ +  + ]:      32727 :     if (iff & IFF_PROMISC) {
    2716                 :       7385 :         nd |= NETDEV_PROMISC;
    2717                 :            :     }
    2718         [ +  + ]:      32727 :     if (iff & IFF_LOOPBACK) {
    2719                 :      10038 :         nd |= NETDEV_LOOPBACK;
    2720                 :            :     }
    2721                 :      32727 :     return nd;
    2722                 :            : }
    2723                 :            : 
    2724                 :            : static int
    2725                 :      32727 : update_flags(struct netdev_linux *netdev, enum netdev_flags off,
    2726                 :            :              enum netdev_flags on, enum netdev_flags *old_flagsp)
    2727                 :            :     OVS_REQUIRES(netdev->mutex)
    2728                 :            : {
    2729                 :            :     int old_flags, new_flags;
    2730                 :      32727 :     int error = 0;
    2731                 :            : 
    2732                 :      32727 :     old_flags = netdev->ifi_flags;
    2733                 :      32727 :     *old_flagsp = iff_to_nd_flags(old_flags);
    2734                 :      32727 :     new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
    2735         [ +  + ]:      32727 :     if (new_flags != old_flags) {
    2736                 :        179 :         error = set_flags(netdev_get_name(&netdev->up), new_flags);
    2737                 :        179 :         get_flags(&netdev->up, &netdev->ifi_flags);
    2738                 :            :     }
    2739                 :            : 
    2740                 :      32727 :     return error;
    2741                 :            : }
    2742                 :            : 
    2743                 :            : static int
    2744                 :      32692 : netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
    2745                 :            :                           enum netdev_flags on, enum netdev_flags *old_flagsp)
    2746                 :            : {
    2747                 :      32692 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2748                 :            :     int error;
    2749                 :            : 
    2750                 :      32692 :     ovs_mutex_lock(&netdev->mutex);
    2751                 :      32692 :     error = update_flags(netdev, off, on, old_flagsp);
    2752                 :      32692 :     ovs_mutex_unlock(&netdev->mutex);
    2753                 :            : 
    2754                 :      32692 :     return error;
    2755                 :            : }
    2756                 :            : 
    2757                 :            : #define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS,          \
    2758                 :            :                            GET_FEATURES, GET_STATUS)            \
    2759                 :            : {                                                               \
    2760                 :            :     NAME,                                                       \
    2761                 :            :     false,                      /* is_pmd */                    \
    2762                 :            :                                                                 \
    2763                 :            :     NULL,                                                       \
    2764                 :            :     netdev_linux_run,                                           \
    2765                 :            :     netdev_linux_wait,                                          \
    2766                 :            :                                                                 \
    2767                 :            :     netdev_linux_alloc,                                         \
    2768                 :            :     CONSTRUCT,                                                  \
    2769                 :            :     netdev_linux_destruct,                                      \
    2770                 :            :     netdev_linux_dealloc,                                       \
    2771                 :            :     NULL,                       /* get_config */                \
    2772                 :            :     NULL,                       /* set_config */                \
    2773                 :            :     NULL,                       /* get_tunnel_config */         \
    2774                 :            :     NULL,                       /* build header */              \
    2775                 :            :     NULL,                       /* push header */               \
    2776                 :            :     NULL,                       /* pop header */                \
    2777                 :            :     NULL,                       /* get_numa_id */               \
    2778                 :            :     NULL,                       /* set_tx_multiq */             \
    2779                 :            :                                                                 \
    2780                 :            :     netdev_linux_send,                                          \
    2781                 :            :     netdev_linux_send_wait,                                     \
    2782                 :            :                                                                 \
    2783                 :            :     netdev_linux_set_etheraddr,                                 \
    2784                 :            :     netdev_linux_get_etheraddr,                                 \
    2785                 :            :     netdev_linux_get_mtu,                                       \
    2786                 :            :     netdev_linux_set_mtu,                                       \
    2787                 :            :     netdev_linux_get_ifindex,                                   \
    2788                 :            :     netdev_linux_get_carrier,                                   \
    2789                 :            :     netdev_linux_get_carrier_resets,                            \
    2790                 :            :     netdev_linux_set_miimon_interval,                           \
    2791                 :            :     GET_STATS,                                                  \
    2792                 :            :                                                                 \
    2793                 :            :     GET_FEATURES,                                               \
    2794                 :            :     netdev_linux_set_advertisements,                            \
    2795                 :            :                                                                 \
    2796                 :            :     netdev_linux_set_policing,                                  \
    2797                 :            :     netdev_linux_get_qos_types,                                 \
    2798                 :            :     netdev_linux_get_qos_capabilities,                          \
    2799                 :            :     netdev_linux_get_qos,                                       \
    2800                 :            :     netdev_linux_set_qos,                                       \
    2801                 :            :     netdev_linux_get_queue,                                     \
    2802                 :            :     netdev_linux_set_queue,                                     \
    2803                 :            :     netdev_linux_delete_queue,                                  \
    2804                 :            :     netdev_linux_get_queue_stats,                               \
    2805                 :            :     netdev_linux_queue_dump_start,                              \
    2806                 :            :     netdev_linux_queue_dump_next,                               \
    2807                 :            :     netdev_linux_queue_dump_done,                               \
    2808                 :            :     netdev_linux_dump_queue_stats,                              \
    2809                 :            :                                                                 \
    2810                 :            :     netdev_linux_set_in4,                                       \
    2811                 :            :     netdev_linux_get_addr_list,                                 \
    2812                 :            :     netdev_linux_add_router,                                    \
    2813                 :            :     netdev_linux_get_next_hop,                                  \
    2814                 :            :     GET_STATUS,                                                 \
    2815                 :            :     netdev_linux_arp_lookup,                                    \
    2816                 :            :                                                                 \
    2817                 :            :     netdev_linux_update_flags,                                  \
    2818                 :            :     NULL,                       /* reconfigure */               \
    2819                 :            :                                                                 \
    2820                 :            :     netdev_linux_rxq_alloc,                                     \
    2821                 :            :     netdev_linux_rxq_construct,                                 \
    2822                 :            :     netdev_linux_rxq_destruct,                                  \
    2823                 :            :     netdev_linux_rxq_dealloc,                                   \
    2824                 :            :     netdev_linux_rxq_recv,                                      \
    2825                 :            :     netdev_linux_rxq_wait,                                      \
    2826                 :            :     netdev_linux_rxq_drain,                                     \
    2827                 :            : }
    2828                 :            : 
    2829                 :            : const struct netdev_class netdev_linux_class =
    2830                 :            :     NETDEV_LINUX_CLASS(
    2831                 :            :         "system",
    2832                 :            :         netdev_linux_construct,
    2833                 :            :         netdev_linux_get_stats,
    2834                 :            :         netdev_linux_get_features,
    2835                 :            :         netdev_linux_get_status);
    2836                 :            : 
    2837                 :            : const struct netdev_class netdev_tap_class =
    2838                 :            :     NETDEV_LINUX_CLASS(
    2839                 :            :         "tap",
    2840                 :            :         netdev_linux_construct_tap,
    2841                 :            :         netdev_tap_get_stats,
    2842                 :            :         netdev_linux_get_features,
    2843                 :            :         netdev_linux_get_status);
    2844                 :            : 
    2845                 :            : const struct netdev_class netdev_internal_class =
    2846                 :            :     NETDEV_LINUX_CLASS(
    2847                 :            :         "internal",
    2848                 :            :         netdev_linux_construct,
    2849                 :            :         netdev_internal_get_stats,
    2850                 :            :         NULL,                  /* get_features */
    2851                 :            :         netdev_internal_get_status);
    2852                 :            : 
    2853                 :            : 
    2854                 :            : #define CODEL_N_QUEUES 0x0000
    2855                 :            : 
    2856                 :            : /* In sufficiently new kernel headers these are defined as enums in
    2857                 :            :  * <linux/pkt_sched.h>.  Define them here as macros to help out with older
    2858                 :            :  * kernels.  (This overrides any enum definition in the header file but that's
    2859                 :            :  * harmless.) */
    2860                 :            : #define TCA_CODEL_TARGET   1
    2861                 :            : #define TCA_CODEL_LIMIT    2
    2862                 :            : #define TCA_CODEL_INTERVAL 3
    2863                 :            : 
    2864                 :            : struct codel {
    2865                 :            :     struct tc tc;
    2866                 :            :     uint32_t target;
    2867                 :            :     uint32_t limit;
    2868                 :            :     uint32_t interval;
    2869                 :            : };
    2870                 :            : 
    2871                 :            : static struct codel *
    2872                 :          0 : codel_get__(const struct netdev *netdev_)
    2873                 :            : {
    2874                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2875                 :          0 :     return CONTAINER_OF(netdev->tc, struct codel, tc);
    2876                 :            : }
    2877                 :            : 
    2878                 :            : static void
    2879                 :          0 : codel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit,
    2880                 :            :                 uint32_t interval)
    2881                 :            : {
    2882                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    2883                 :            :     struct codel *codel;
    2884                 :            : 
    2885                 :          0 :     codel = xmalloc(sizeof *codel);
    2886                 :          0 :     tc_init(&codel->tc, &tc_ops_codel);
    2887                 :          0 :     codel->target = target;
    2888                 :          0 :     codel->limit = limit;
    2889                 :          0 :     codel->interval = interval;
    2890                 :            : 
    2891                 :          0 :     netdev->tc = &codel->tc;
    2892                 :          0 : }
    2893                 :            : 
    2894                 :            : static int
    2895                 :          0 : codel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit,
    2896                 :            :                     uint32_t interval)
    2897                 :            : {
    2898                 :            :     size_t opt_offset;
    2899                 :            :     struct ofpbuf request;
    2900                 :            :     struct tcmsg *tcmsg;
    2901                 :            :     uint32_t otarget, olimit, ointerval;
    2902                 :            :     int error;
    2903                 :            : 
    2904                 :          0 :     tc_del_qdisc(netdev);
    2905                 :            : 
    2906                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
    2907                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    2908         [ #  # ]:          0 :     if (!tcmsg) {
    2909                 :          0 :         return ENODEV;
    2910                 :            :     }
    2911                 :          0 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    2912                 :          0 :     tcmsg->tcm_parent = TC_H_ROOT;
    2913                 :            : 
    2914         [ #  # ]:          0 :     otarget = target ? target : 5000;
    2915         [ #  # ]:          0 :     olimit = limit ? limit : 10240;
    2916         [ #  # ]:          0 :     ointerval = interval ? interval : 100000;
    2917                 :            : 
    2918                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "codel");
    2919                 :          0 :     opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    2920                 :          0 :     nl_msg_put_u32(&request, TCA_CODEL_TARGET, otarget);
    2921                 :          0 :     nl_msg_put_u32(&request, TCA_CODEL_LIMIT, olimit);
    2922                 :          0 :     nl_msg_put_u32(&request, TCA_CODEL_INTERVAL, ointerval);
    2923                 :          0 :     nl_msg_end_nested(&request, opt_offset);
    2924                 :            : 
    2925                 :          0 :     error = tc_transact(&request, NULL);
    2926         [ #  # ]:          0 :     if (error) {
    2927         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
    2928                 :            :         "target %u, limit %u, interval %u error %d(%s)",
    2929                 :            :         netdev_get_name(netdev),
    2930                 :            :         otarget, olimit, ointerval,
    2931                 :            :         error, ovs_strerror(error));
    2932                 :            :     }
    2933                 :          0 :     return error;
    2934                 :            : }
    2935                 :            : 
    2936                 :            : static void
    2937                 :          0 : codel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED,
    2938                 :            :                             const struct smap *details, struct codel *codel)
    2939                 :            : {
    2940                 :          0 :     codel->target = smap_get_ullong(details, "target", 0);
    2941                 :          0 :     codel->limit = smap_get_ullong(details, "limit", 0);
    2942                 :          0 :     codel->interval = smap_get_ullong(details, "interval", 0);
    2943                 :            : 
    2944         [ #  # ]:          0 :     if (!codel->target) {
    2945                 :          0 :         codel->target = 5000;
    2946                 :            :     }
    2947         [ #  # ]:          0 :     if (!codel->limit) {
    2948                 :          0 :         codel->limit = 10240;
    2949                 :            :     }
    2950         [ #  # ]:          0 :     if (!codel->interval) {
    2951                 :          0 :         codel->interval = 100000;
    2952                 :            :     }
    2953                 :          0 : }
    2954                 :            : 
    2955                 :            : static int
    2956                 :          0 : codel_tc_install(struct netdev *netdev, const struct smap *details)
    2957                 :            : {
    2958                 :            :     int error;
    2959                 :            :     struct codel codel;
    2960                 :            : 
    2961                 :          0 :     codel_parse_qdisc_details__(netdev, details, &codel);
    2962                 :          0 :     error = codel_setup_qdisc__(netdev, codel.target, codel.limit,
    2963                 :            :                                 codel.interval);
    2964         [ #  # ]:          0 :     if (!error) {
    2965                 :          0 :         codel_install__(netdev, codel.target, codel.limit, codel.interval);
    2966                 :            :     }
    2967                 :          0 :     return error;
    2968                 :            : }
    2969                 :            : 
    2970                 :            : static int
    2971                 :          0 : codel_parse_tca_options__(struct nlattr *nl_options, struct codel *codel)
    2972                 :            : {
    2973                 :            :     static const struct nl_policy tca_codel_policy[] = {
    2974                 :            :         [TCA_CODEL_TARGET] = { .type = NL_A_U32 },
    2975                 :            :         [TCA_CODEL_LIMIT] = { .type = NL_A_U32 },
    2976                 :            :         [TCA_CODEL_INTERVAL] = { .type = NL_A_U32 }
    2977                 :            :     };
    2978                 :            : 
    2979                 :            :     struct nlattr *attrs[ARRAY_SIZE(tca_codel_policy)];
    2980                 :            : 
    2981         [ #  # ]:          0 :     if (!nl_parse_nested(nl_options, tca_codel_policy,
    2982                 :            :                          attrs, ARRAY_SIZE(tca_codel_policy))) {
    2983         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse CoDel class options");
    2984                 :          0 :         return EPROTO;
    2985                 :            :     }
    2986                 :            : 
    2987                 :          0 :     codel->target = nl_attr_get_u32(attrs[TCA_CODEL_TARGET]);
    2988                 :          0 :     codel->limit = nl_attr_get_u32(attrs[TCA_CODEL_LIMIT]);
    2989                 :          0 :     codel->interval = nl_attr_get_u32(attrs[TCA_CODEL_INTERVAL]);
    2990                 :          0 :     return 0;
    2991                 :            : }
    2992                 :            : 
    2993                 :            : static int
    2994                 :          0 : codel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
    2995                 :            : {
    2996                 :            :     struct nlattr *nlattr;
    2997                 :            :     const char * kind;
    2998                 :            :     int error;
    2999                 :            :     struct codel codel;
    3000                 :            : 
    3001                 :          0 :     error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
    3002         [ #  # ]:          0 :     if (error != 0) {
    3003                 :          0 :         return error;
    3004                 :            :     }
    3005                 :            : 
    3006                 :          0 :     error = codel_parse_tca_options__(nlattr, &codel);
    3007         [ #  # ]:          0 :     if (error != 0) {
    3008                 :          0 :         return error;
    3009                 :            :     }
    3010                 :            : 
    3011                 :          0 :     codel_install__(netdev, codel.target, codel.limit, codel.interval);
    3012                 :          0 :     return 0;
    3013                 :            : }
    3014                 :            : 
    3015                 :            : 
    3016                 :            : static void
    3017                 :          0 : codel_tc_destroy(struct tc *tc)
    3018                 :            : {
    3019                 :          0 :     struct codel *codel = CONTAINER_OF(tc, struct codel, tc);
    3020                 :          0 :     tc_destroy(tc);
    3021                 :          0 :     free(codel);
    3022                 :          0 : }
    3023                 :            : 
    3024                 :            : static int
    3025                 :          0 : codel_qdisc_get(const struct netdev *netdev, struct smap *details)
    3026                 :            : {
    3027                 :          0 :     const struct codel *codel = codel_get__(netdev);
    3028                 :          0 :     smap_add_format(details, "target", "%u", codel->target);
    3029                 :          0 :     smap_add_format(details, "limit", "%u", codel->limit);
    3030                 :          0 :     smap_add_format(details, "interval", "%u", codel->interval);
    3031                 :          0 :     return 0;
    3032                 :            : }
    3033                 :            : 
    3034                 :            : static int
    3035                 :          0 : codel_qdisc_set(struct netdev *netdev, const struct smap *details)
    3036                 :            : {
    3037                 :            :     struct codel codel;
    3038                 :            : 
    3039                 :          0 :     codel_parse_qdisc_details__(netdev, details, &codel);
    3040                 :          0 :     codel_install__(netdev, codel.target, codel.limit, codel.interval);
    3041                 :          0 :     codel_get__(netdev)->target = codel.target;
    3042                 :          0 :     codel_get__(netdev)->limit = codel.limit;
    3043                 :          0 :     codel_get__(netdev)->interval = codel.interval;
    3044                 :          0 :     return 0;
    3045                 :            : }
    3046                 :            : 
    3047                 :            : static const struct tc_ops tc_ops_codel = {
    3048                 :            :     "codel",                      /* linux_name */
    3049                 :            :     "linux-codel",                /* ovs_name */
    3050                 :            :     CODEL_N_QUEUES,               /* n_queues */
    3051                 :            :     codel_tc_install,
    3052                 :            :     codel_tc_load,
    3053                 :            :     codel_tc_destroy,
    3054                 :            :     codel_qdisc_get,
    3055                 :            :     codel_qdisc_set,
    3056                 :            :     NULL,
    3057                 :            :     NULL,
    3058                 :            :     NULL,
    3059                 :            :     NULL,
    3060                 :            :     NULL
    3061                 :            : };
    3062                 :            : 
    3063                 :            : /* FQ-CoDel traffic control class. */
    3064                 :            : 
    3065                 :            : #define FQCODEL_N_QUEUES 0x0000
    3066                 :            : 
    3067                 :            : /* In sufficiently new kernel headers these are defined as enums in
    3068                 :            :  * <linux/pkt_sched.h>.  Define them here as macros to help out with older
    3069                 :            :  * kernels.  (This overrides any enum definition in the header file but that's
    3070                 :            :  * harmless.) */
    3071                 :            : #define TCA_FQ_CODEL_TARGET     1
    3072                 :            : #define TCA_FQ_CODEL_LIMIT      2
    3073                 :            : #define TCA_FQ_CODEL_INTERVAL   3
    3074                 :            : #define TCA_FQ_CODEL_ECN        4
    3075                 :            : #define TCA_FQ_CODEL_FLOWS      5
    3076                 :            : #define TCA_FQ_CODEL_QUANTUM    6
    3077                 :            : 
    3078                 :            : struct fqcodel {
    3079                 :            :     struct tc tc;
    3080                 :            :     uint32_t target;
    3081                 :            :     uint32_t limit;
    3082                 :            :     uint32_t interval;
    3083                 :            :     uint32_t flows;
    3084                 :            :     uint32_t quantum;
    3085                 :            : };
    3086                 :            : 
    3087                 :            : static struct fqcodel *
    3088                 :          0 : fqcodel_get__(const struct netdev *netdev_)
    3089                 :            : {
    3090                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3091                 :          0 :     return CONTAINER_OF(netdev->tc, struct fqcodel, tc);
    3092                 :            : }
    3093                 :            : 
    3094                 :            : static void
    3095                 :        233 : fqcodel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit,
    3096                 :            :                   uint32_t interval, uint32_t flows, uint32_t quantum)
    3097                 :            : {
    3098                 :        233 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3099                 :            :     struct fqcodel *fqcodel;
    3100                 :            : 
    3101                 :        233 :     fqcodel = xmalloc(sizeof *fqcodel);
    3102                 :        233 :     tc_init(&fqcodel->tc, &tc_ops_fqcodel);
    3103                 :        233 :     fqcodel->target = target;
    3104                 :        233 :     fqcodel->limit = limit;
    3105                 :        233 :     fqcodel->interval = interval;
    3106                 :        233 :     fqcodel->flows = flows;
    3107                 :        233 :     fqcodel->quantum = quantum;
    3108                 :            : 
    3109                 :        233 :     netdev->tc = &fqcodel->tc;
    3110                 :        233 : }
    3111                 :            : 
    3112                 :            : static int
    3113                 :          0 : fqcodel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit,
    3114                 :            :                       uint32_t interval, uint32_t flows, uint32_t quantum)
    3115                 :            : {
    3116                 :            :     size_t opt_offset;
    3117                 :            :     struct ofpbuf request;
    3118                 :            :     struct tcmsg *tcmsg;
    3119                 :            :     uint32_t otarget, olimit, ointerval, oflows,  oquantum;
    3120                 :            :     int error;
    3121                 :            : 
    3122                 :          0 :     tc_del_qdisc(netdev);
    3123                 :            : 
    3124                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
    3125                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    3126         [ #  # ]:          0 :     if (!tcmsg) {
    3127                 :          0 :         return ENODEV;
    3128                 :            :     }
    3129                 :          0 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    3130                 :          0 :     tcmsg->tcm_parent = TC_H_ROOT;
    3131                 :            : 
    3132         [ #  # ]:          0 :     otarget = target ? target : 5000;
    3133         [ #  # ]:          0 :     olimit = limit ? limit : 10240;
    3134         [ #  # ]:          0 :     ointerval = interval ? interval : 100000;
    3135         [ #  # ]:          0 :     oflows = flows ? flows : 1024;
    3136         [ #  # ]:          0 :     oquantum = quantum ? quantum : 1514; /* fq_codel default quantum is 1514
    3137                 :            :                                             not mtu */
    3138                 :            : 
    3139                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "fq_codel");
    3140                 :          0 :     opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    3141                 :          0 :     nl_msg_put_u32(&request, TCA_FQ_CODEL_TARGET, otarget);
    3142                 :          0 :     nl_msg_put_u32(&request, TCA_FQ_CODEL_LIMIT, olimit);
    3143                 :          0 :     nl_msg_put_u32(&request, TCA_FQ_CODEL_INTERVAL, ointerval);
    3144                 :          0 :     nl_msg_put_u32(&request, TCA_FQ_CODEL_FLOWS, oflows);
    3145                 :          0 :     nl_msg_put_u32(&request, TCA_FQ_CODEL_QUANTUM, oquantum);
    3146                 :          0 :     nl_msg_end_nested(&request, opt_offset);
    3147                 :            : 
    3148                 :          0 :     error = tc_transact(&request, NULL);
    3149         [ #  # ]:          0 :     if (error) {
    3150         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
    3151                 :            :         "target %u, limit %u, interval %u, flows %u, quantum %u error %d(%s)",
    3152                 :            :         netdev_get_name(netdev),
    3153                 :            :         otarget, olimit, ointerval, oflows, oquantum,
    3154                 :            :         error, ovs_strerror(error));
    3155                 :            :     }
    3156                 :          0 :     return error;
    3157                 :            : }
    3158                 :            : 
    3159                 :            : static void
    3160                 :          0 : fqcodel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED,
    3161                 :            :                           const struct smap *details, struct fqcodel *fqcodel)
    3162                 :            : {
    3163                 :          0 :     fqcodel->target = smap_get_ullong(details, "target", 0);
    3164                 :          0 :     fqcodel->limit = smap_get_ullong(details, "limit", 0);
    3165                 :          0 :     fqcodel->interval = smap_get_ullong(details, "interval", 0);
    3166                 :          0 :     fqcodel->flows = smap_get_ullong(details, "flows", 0);
    3167                 :          0 :     fqcodel->quantum = smap_get_ullong(details, "quantum", 0);
    3168                 :            : 
    3169         [ #  # ]:          0 :     if (!fqcodel->target) {
    3170                 :          0 :         fqcodel->target = 5000;
    3171                 :            :     }
    3172         [ #  # ]:          0 :     if (!fqcodel->limit) {
    3173                 :          0 :         fqcodel->limit = 10240;
    3174                 :            :     }
    3175         [ #  # ]:          0 :     if (!fqcodel->interval) {
    3176                 :          0 :         fqcodel->interval = 1000000;
    3177                 :            :     }
    3178         [ #  # ]:          0 :     if (!fqcodel->flows) {
    3179                 :          0 :         fqcodel->flows = 1024;
    3180                 :            :     }
    3181         [ #  # ]:          0 :     if (!fqcodel->quantum) {
    3182                 :          0 :         fqcodel->quantum = 1514;
    3183                 :            :     }
    3184                 :          0 : }
    3185                 :            : 
    3186                 :            : static int
    3187                 :          0 : fqcodel_tc_install(struct netdev *netdev, const struct smap *details)
    3188                 :            : {
    3189                 :            :     int error;
    3190                 :            :     struct fqcodel fqcodel;
    3191                 :            : 
    3192                 :          0 :     fqcodel_parse_qdisc_details__(netdev, details, &fqcodel);
    3193                 :          0 :     error = fqcodel_setup_qdisc__(netdev, fqcodel.target, fqcodel.limit,
    3194                 :            :                                   fqcodel.interval, fqcodel.flows,
    3195                 :            :                                   fqcodel.quantum);
    3196         [ #  # ]:          0 :     if (!error) {
    3197                 :          0 :         fqcodel_install__(netdev, fqcodel.target, fqcodel.limit,
    3198                 :            :                           fqcodel.interval, fqcodel.flows, fqcodel.quantum);
    3199                 :            :     }
    3200                 :          0 :     return error;
    3201                 :            : }
    3202                 :            : 
    3203                 :            : static int
    3204                 :        233 : fqcodel_parse_tca_options__(struct nlattr *nl_options, struct fqcodel *fqcodel)
    3205                 :            : {
    3206                 :            :     static const struct nl_policy tca_fqcodel_policy[] = {
    3207                 :            :         [TCA_FQ_CODEL_TARGET] = { .type = NL_A_U32 },
    3208                 :            :         [TCA_FQ_CODEL_LIMIT] = { .type = NL_A_U32 },
    3209                 :            :         [TCA_FQ_CODEL_INTERVAL] = { .type = NL_A_U32 },
    3210                 :            :         [TCA_FQ_CODEL_FLOWS] = { .type = NL_A_U32 },
    3211                 :            :         [TCA_FQ_CODEL_QUANTUM] = { .type = NL_A_U32 }
    3212                 :            :     };
    3213                 :            : 
    3214                 :            :     struct nlattr *attrs[ARRAY_SIZE(tca_fqcodel_policy)];
    3215                 :            : 
    3216         [ -  + ]:        233 :     if (!nl_parse_nested(nl_options, tca_fqcodel_policy,
    3217                 :            :                          attrs, ARRAY_SIZE(tca_fqcodel_policy))) {
    3218         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse FQ_CoDel class options");
    3219                 :          0 :         return EPROTO;
    3220                 :            :     }
    3221                 :            : 
    3222                 :        233 :     fqcodel->target = nl_attr_get_u32(attrs[TCA_FQ_CODEL_TARGET]);
    3223                 :        233 :     fqcodel->limit = nl_attr_get_u32(attrs[TCA_FQ_CODEL_LIMIT]);
    3224                 :        233 :     fqcodel->interval =nl_attr_get_u32(attrs[TCA_FQ_CODEL_INTERVAL]);
    3225                 :        233 :     fqcodel->flows = nl_attr_get_u32(attrs[TCA_FQ_CODEL_FLOWS]);
    3226                 :        233 :     fqcodel->quantum = nl_attr_get_u32(attrs[TCA_FQ_CODEL_QUANTUM]);
    3227                 :        233 :     return 0;
    3228                 :            : }
    3229                 :            : 
    3230                 :            : static int
    3231                 :        233 : fqcodel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
    3232                 :            : {
    3233                 :            :     struct nlattr *nlattr;
    3234                 :            :     const char * kind;
    3235                 :            :     int error;
    3236                 :            :     struct fqcodel fqcodel;
    3237                 :            : 
    3238                 :        233 :     error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
    3239         [ -  + ]:        233 :     if (error != 0) {
    3240                 :          0 :         return error;
    3241                 :            :     }
    3242                 :            : 
    3243                 :        233 :     error = fqcodel_parse_tca_options__(nlattr, &fqcodel);
    3244         [ -  + ]:        233 :     if (error != 0) {
    3245                 :          0 :         return error;
    3246                 :            :     }
    3247                 :            : 
    3248                 :        233 :     fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval,
    3249                 :            :                       fqcodel.flows, fqcodel.quantum);
    3250                 :        233 :     return 0;
    3251                 :            : }
    3252                 :            : 
    3253                 :            : static void
    3254                 :        233 : fqcodel_tc_destroy(struct tc *tc)
    3255                 :            : {
    3256                 :        233 :     struct fqcodel *fqcodel = CONTAINER_OF(tc, struct fqcodel, tc);
    3257                 :        233 :     tc_destroy(tc);
    3258                 :        233 :     free(fqcodel);
    3259                 :        233 : }
    3260                 :            : 
    3261                 :            : static int
    3262                 :          0 : fqcodel_qdisc_get(const struct netdev *netdev, struct smap *details)
    3263                 :            : {
    3264                 :          0 :     const struct fqcodel *fqcodel = fqcodel_get__(netdev);
    3265                 :          0 :     smap_add_format(details, "target", "%u", fqcodel->target);
    3266                 :          0 :     smap_add_format(details, "limit", "%u", fqcodel->limit);
    3267                 :          0 :     smap_add_format(details, "interval", "%u", fqcodel->interval);
    3268                 :          0 :     smap_add_format(details, "flows", "%u", fqcodel->flows);
    3269                 :          0 :     smap_add_format(details, "quantum", "%u", fqcodel->quantum);
    3270                 :          0 :     return 0;
    3271                 :            : }
    3272                 :            : 
    3273                 :            : static int
    3274                 :          0 : fqcodel_qdisc_set(struct netdev *netdev, const struct smap *details)
    3275                 :            : {
    3276                 :            :     struct fqcodel fqcodel;
    3277                 :            : 
    3278                 :          0 :     fqcodel_parse_qdisc_details__(netdev, details, &fqcodel);
    3279                 :          0 :     fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval,
    3280                 :            :                       fqcodel.flows, fqcodel.quantum);
    3281                 :          0 :     fqcodel_get__(netdev)->target = fqcodel.target;
    3282                 :          0 :     fqcodel_get__(netdev)->limit = fqcodel.limit;
    3283                 :          0 :     fqcodel_get__(netdev)->interval = fqcodel.interval;
    3284                 :          0 :     fqcodel_get__(netdev)->flows = fqcodel.flows;
    3285                 :          0 :     fqcodel_get__(netdev)->quantum = fqcodel.quantum;
    3286                 :          0 :     return 0;
    3287                 :            : }
    3288                 :            : 
    3289                 :            : static const struct tc_ops tc_ops_fqcodel = {
    3290                 :            :     "fq_codel",                      /* linux_name */
    3291                 :            :     "linux-fq_codel",                /* ovs_name */
    3292                 :            :     FQCODEL_N_QUEUES,                /* n_queues */
    3293                 :            :     fqcodel_tc_install,
    3294                 :            :     fqcodel_tc_load,
    3295                 :            :     fqcodel_tc_destroy,
    3296                 :            :     fqcodel_qdisc_get,
    3297                 :            :     fqcodel_qdisc_set,
    3298                 :            :     NULL,
    3299                 :            :     NULL,
    3300                 :            :     NULL,
    3301                 :            :     NULL,
    3302                 :            :     NULL
    3303                 :            : };
    3304                 :            : 
    3305                 :            : /* SFQ traffic control class. */
    3306                 :            : 
    3307                 :            : #define SFQ_N_QUEUES 0x0000
    3308                 :            : 
    3309                 :            : struct sfq {
    3310                 :            :     struct tc tc;
    3311                 :            :     uint32_t quantum;
    3312                 :            :     uint32_t perturb;
    3313                 :            : };
    3314                 :            : 
    3315                 :            : static struct sfq *
    3316                 :          0 : sfq_get__(const struct netdev *netdev_)
    3317                 :            : {
    3318                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3319                 :          0 :     return CONTAINER_OF(netdev->tc, struct sfq, tc);
    3320                 :            : }
    3321                 :            : 
    3322                 :            : static void
    3323                 :          0 : sfq_install__(struct netdev *netdev_, uint32_t quantum, uint32_t perturb)
    3324                 :            : {
    3325                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3326                 :            :     struct sfq *sfq;
    3327                 :            : 
    3328                 :          0 :     sfq = xmalloc(sizeof *sfq);
    3329                 :          0 :     tc_init(&sfq->tc, &tc_ops_sfq);
    3330                 :          0 :     sfq->perturb = perturb;
    3331                 :          0 :     sfq->quantum = quantum;
    3332                 :            : 
    3333                 :          0 :     netdev->tc = &sfq->tc;
    3334                 :          0 : }
    3335                 :            : 
    3336                 :            : static int
    3337                 :          0 : sfq_setup_qdisc__(struct netdev *netdev, uint32_t quantum, uint32_t perturb)
    3338                 :            : {
    3339                 :            :     struct tc_sfq_qopt opt;
    3340                 :            :     struct ofpbuf request;
    3341                 :            :     struct tcmsg *tcmsg;
    3342                 :            :     int mtu;
    3343                 :            :     int mtu_error, error;
    3344                 :          0 :     mtu_error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
    3345                 :            : 
    3346                 :          0 :     tc_del_qdisc(netdev);
    3347                 :            : 
    3348                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
    3349                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    3350         [ #  # ]:          0 :     if (!tcmsg) {
    3351                 :          0 :         return ENODEV;
    3352                 :            :     }
    3353                 :          0 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    3354                 :          0 :     tcmsg->tcm_parent = TC_H_ROOT;
    3355                 :            : 
    3356                 :          0 :     memset(&opt, 0, sizeof opt);
    3357         [ #  # ]:          0 :     if (!quantum) {
    3358         [ #  # ]:          0 :         if (!mtu_error) {
    3359                 :          0 :             opt.quantum = mtu; /* if we cannot find mtu, use default */
    3360                 :            :         }
    3361                 :            :     } else {
    3362                 :          0 :         opt.quantum = quantum;
    3363                 :            :     }
    3364                 :            : 
    3365         [ #  # ]:          0 :     if (!perturb) {
    3366                 :          0 :         opt.perturb_period = 10;
    3367                 :            :     } else {
    3368                 :          0 :         opt.perturb_period = perturb;
    3369                 :            :     }
    3370                 :            : 
    3371                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "sfq");
    3372                 :          0 :     nl_msg_put_unspec(&request, TCA_OPTIONS, &opt, sizeof opt);
    3373                 :            : 
    3374                 :          0 :     error = tc_transact(&request, NULL);
    3375         [ #  # ]:          0 :     if (error) {
    3376         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
    3377                 :            :                      "quantum %u, perturb %u error %d(%s)",
    3378                 :            :                      netdev_get_name(netdev),
    3379                 :            :                      opt.quantum, opt.perturb_period,
    3380                 :            :                      error, ovs_strerror(error));
    3381                 :            :     }
    3382                 :          0 :     return error;
    3383                 :            : }
    3384                 :            : 
    3385                 :            : static void
    3386                 :          0 : sfq_parse_qdisc_details__(struct netdev *netdev,
    3387                 :            :                           const struct smap *details, struct sfq *sfq)
    3388                 :            : {
    3389                 :          0 :     sfq->perturb = smap_get_ullong(details, "perturb", 0);
    3390                 :          0 :     sfq->quantum = smap_get_ullong(details, "quantum", 0);
    3391                 :            : 
    3392         [ #  # ]:          0 :     if (!sfq->perturb) {
    3393                 :          0 :         sfq->perturb = 10;
    3394                 :            :     }
    3395                 :            : 
    3396         [ #  # ]:          0 :     if (!sfq->quantum) {
    3397                 :            :         int mtu;
    3398         [ #  # ]:          0 :         if (!netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu)) {
    3399                 :          0 :             sfq->quantum = mtu;
    3400                 :            :         } else {
    3401         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "when using SFQ, you must specify quantum on a "
    3402                 :            :                          "device without mtu");
    3403                 :            :         }
    3404                 :            :     }
    3405                 :          0 : }
    3406                 :            : 
    3407                 :            : static int
    3408                 :          0 : sfq_tc_install(struct netdev *netdev, const struct smap *details)
    3409                 :            : {
    3410                 :            :     int error;
    3411                 :            :     struct sfq sfq;
    3412                 :            : 
    3413                 :          0 :     sfq_parse_qdisc_details__(netdev, details, &sfq);
    3414                 :          0 :     error = sfq_setup_qdisc__(netdev, sfq.quantum, sfq.perturb);
    3415         [ #  # ]:          0 :     if (!error) {
    3416                 :          0 :         sfq_install__(netdev, sfq.quantum, sfq.perturb);
    3417                 :            :     }
    3418                 :          0 :     return error;
    3419                 :            : }
    3420                 :            : 
    3421                 :            : static int
    3422                 :          0 : sfq_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
    3423                 :            : {
    3424                 :            :     const struct tc_sfq_qopt *sfq;
    3425                 :            :     struct nlattr *nlattr;
    3426                 :            :     const char * kind;
    3427                 :            :     int error;
    3428                 :            : 
    3429                 :          0 :     error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
    3430         [ #  # ]:          0 :     if (error == 0) {
    3431                 :          0 :         sfq = nl_attr_get(nlattr);
    3432                 :          0 :         sfq_install__(netdev, sfq->perturb_period, sfq->quantum);
    3433                 :          0 :         return 0;
    3434                 :            :     }
    3435                 :            : 
    3436                 :          0 :     return error;
    3437                 :            : }
    3438                 :            : 
    3439                 :            : static void
    3440                 :          0 : sfq_tc_destroy(struct tc *tc)
    3441                 :            : {
    3442                 :          0 :     struct sfq *sfq = CONTAINER_OF(tc, struct sfq, tc);
    3443                 :          0 :     tc_destroy(tc);
    3444                 :          0 :     free(sfq);
    3445                 :          0 : }
    3446                 :            : 
    3447                 :            : static int
    3448                 :          0 : sfq_qdisc_get(const struct netdev *netdev, struct smap *details)
    3449                 :            : {
    3450                 :          0 :     const struct sfq *sfq = sfq_get__(netdev);
    3451                 :          0 :     smap_add_format(details, "quantum", "%u", sfq->quantum);
    3452                 :          0 :     smap_add_format(details, "perturb", "%u", sfq->perturb);
    3453                 :          0 :     return 0;
    3454                 :            : }
    3455                 :            : 
    3456                 :            : static int
    3457                 :          0 : sfq_qdisc_set(struct netdev *netdev, const struct smap *details)
    3458                 :            : {
    3459                 :            :     struct sfq sfq;
    3460                 :            : 
    3461                 :          0 :     sfq_parse_qdisc_details__(netdev, details, &sfq);
    3462                 :          0 :     sfq_install__(netdev, sfq.quantum, sfq.perturb);
    3463                 :          0 :     sfq_get__(netdev)->quantum = sfq.quantum;
    3464                 :          0 :     sfq_get__(netdev)->perturb = sfq.perturb;
    3465                 :          0 :     return 0;
    3466                 :            : }
    3467                 :            : 
    3468                 :            : static const struct tc_ops tc_ops_sfq = {
    3469                 :            :     "sfq",                      /* linux_name */
    3470                 :            :     "linux-sfq",                /* ovs_name */
    3471                 :            :     SFQ_N_QUEUES,               /* n_queues */
    3472                 :            :     sfq_tc_install,
    3473                 :            :     sfq_tc_load,
    3474                 :            :     sfq_tc_destroy,
    3475                 :            :     sfq_qdisc_get,
    3476                 :            :     sfq_qdisc_set,
    3477                 :            :     NULL,
    3478                 :            :     NULL,
    3479                 :            :     NULL,
    3480                 :            :     NULL,
    3481                 :            :     NULL
    3482                 :            : };
    3483                 :            : 
    3484                 :            : /* HTB traffic control class. */
    3485                 :            : 
    3486                 :            : #define HTB_N_QUEUES 0xf000
    3487                 :            : #define HTB_RATE2QUANTUM 10
    3488                 :            : 
    3489                 :            : struct htb {
    3490                 :            :     struct tc tc;
    3491                 :            :     unsigned int max_rate;      /* In bytes/s. */
    3492                 :            : };
    3493                 :            : 
    3494                 :            : struct htb_class {
    3495                 :            :     struct tc_queue tc_queue;
    3496                 :            :     unsigned int min_rate;      /* In bytes/s. */
    3497                 :            :     unsigned int max_rate;      /* In bytes/s. */
    3498                 :            :     unsigned int burst;         /* In bytes. */
    3499                 :            :     unsigned int priority;      /* Lower values are higher priorities. */
    3500                 :            : };
    3501                 :            : 
    3502                 :            : static struct htb *
    3503                 :          0 : htb_get__(const struct netdev *netdev_)
    3504                 :            : {
    3505                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3506                 :          0 :     return CONTAINER_OF(netdev->tc, struct htb, tc);
    3507                 :            : }
    3508                 :            : 
    3509                 :            : static void
    3510                 :          0 : htb_install__(struct netdev *netdev_, uint64_t max_rate)
    3511                 :            : {
    3512                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3513                 :            :     struct htb *htb;
    3514                 :            : 
    3515                 :          0 :     htb = xmalloc(sizeof *htb);
    3516                 :          0 :     tc_init(&htb->tc, &tc_ops_htb);
    3517                 :          0 :     htb->max_rate = max_rate;
    3518                 :            : 
    3519                 :          0 :     netdev->tc = &htb->tc;
    3520                 :          0 : }
    3521                 :            : 
    3522                 :            : /* Create an HTB qdisc.
    3523                 :            :  *
    3524                 :            :  * Equivalent to "tc qdisc add dev <dev> root handle 1: htb default 1". */
    3525                 :            : static int
    3526                 :          0 : htb_setup_qdisc__(struct netdev *netdev)
    3527                 :            : {
    3528                 :            :     size_t opt_offset;
    3529                 :            :     struct tc_htb_glob opt;
    3530                 :            :     struct ofpbuf request;
    3531                 :            :     struct tcmsg *tcmsg;
    3532                 :            : 
    3533                 :          0 :     tc_del_qdisc(netdev);
    3534                 :            : 
    3535                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
    3536                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    3537         [ #  # ]:          0 :     if (!tcmsg) {
    3538                 :          0 :         return ENODEV;
    3539                 :            :     }
    3540                 :          0 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    3541                 :          0 :     tcmsg->tcm_parent = TC_H_ROOT;
    3542                 :            : 
    3543                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "htb");
    3544                 :            : 
    3545                 :          0 :     memset(&opt, 0, sizeof opt);
    3546                 :          0 :     opt.rate2quantum = HTB_RATE2QUANTUM;
    3547                 :          0 :     opt.version = 3;
    3548                 :          0 :     opt.defcls = 1;
    3549                 :            : 
    3550                 :          0 :     opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    3551                 :          0 :     nl_msg_put_unspec(&request, TCA_HTB_INIT, &opt, sizeof opt);
    3552                 :          0 :     nl_msg_end_nested(&request, opt_offset);
    3553                 :            : 
    3554                 :          0 :     return tc_transact(&request, NULL);
    3555                 :            : }
    3556                 :            : 
    3557                 :            : /* Equivalent to "tc class replace <dev> classid <handle> parent <parent> htb
    3558                 :            :  * rate <min_rate>bps ceil <max_rate>bps burst <burst>b prio <priority>". */
    3559                 :            : static int
    3560                 :          0 : htb_setup_class__(struct netdev *netdev, unsigned int handle,
    3561                 :            :                   unsigned int parent, struct htb_class *class)
    3562                 :            : {
    3563                 :            :     size_t opt_offset;
    3564                 :            :     struct tc_htb_opt opt;
    3565                 :            :     struct ofpbuf request;
    3566                 :            :     struct tcmsg *tcmsg;
    3567                 :            :     int error;
    3568                 :            :     int mtu;
    3569                 :            : 
    3570                 :          0 :     error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
    3571         [ #  # ]:          0 :     if (error) {
    3572         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "cannot set up HTB on device %s that lacks MTU",
    3573                 :            :                      netdev_get_name(netdev));
    3574                 :          0 :         return error;
    3575                 :            :     }
    3576                 :            : 
    3577                 :          0 :     memset(&opt, 0, sizeof opt);
    3578                 :          0 :     tc_fill_rate(&opt.rate, class->min_rate, mtu);
    3579                 :          0 :     tc_fill_rate(&opt.ceil, class->max_rate, mtu);
    3580                 :            :     /* Makes sure the quantum is at least MTU.  Setting quantum will
    3581                 :            :      * make htb ignore the r2q for this class. */
    3582         [ #  # ]:          0 :     if ((class->min_rate / HTB_RATE2QUANTUM) < mtu) {
    3583                 :          0 :         opt.quantum = mtu;
    3584                 :            :     }
    3585                 :          0 :     opt.buffer = tc_calc_buffer(opt.rate.rate, mtu, class->burst);
    3586                 :          0 :     opt.cbuffer = tc_calc_buffer(opt.ceil.rate, mtu, class->burst);
    3587                 :          0 :     opt.prio = class->priority;
    3588                 :            : 
    3589                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWTCLASS, NLM_F_CREATE, &request);
    3590         [ #  # ]:          0 :     if (!tcmsg) {
    3591                 :          0 :         return ENODEV;
    3592                 :            :     }
    3593                 :          0 :     tcmsg->tcm_handle = handle;
    3594                 :          0 :     tcmsg->tcm_parent = parent;
    3595                 :            : 
    3596                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "htb");
    3597                 :          0 :     opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    3598                 :          0 :     nl_msg_put_unspec(&request, TCA_HTB_PARMS, &opt, sizeof opt);
    3599                 :          0 :     tc_put_rtab(&request, TCA_HTB_RTAB, &opt.rate);
    3600                 :          0 :     tc_put_rtab(&request, TCA_HTB_CTAB, &opt.ceil);
    3601                 :          0 :     nl_msg_end_nested(&request, opt_offset);
    3602                 :            : 
    3603                 :          0 :     error = tc_transact(&request, NULL);
    3604         [ #  # ]:          0 :     if (error) {
    3605         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to replace %s class %u:%u, parent %u:%u, "
    3606                 :            :                      "min_rate=%u max_rate=%u burst=%u prio=%u (%s)",
    3607                 :            :                      netdev_get_name(netdev),
    3608                 :            :                      tc_get_major(handle), tc_get_minor(handle),
    3609                 :            :                      tc_get_major(parent), tc_get_minor(parent),
    3610                 :            :                      class->min_rate, class->max_rate,
    3611                 :            :                      class->burst, class->priority, ovs_strerror(error));
    3612                 :            :     }
    3613                 :          0 :     return error;
    3614                 :            : }
    3615                 :            : 
    3616                 :            : /* Parses Netlink attributes in 'options' for HTB parameters and stores a
    3617                 :            :  * description of them into 'details'.  The description complies with the
    3618                 :            :  * specification given in the vswitch database documentation for linux-htb
    3619                 :            :  * queue details. */
    3620                 :            : static int
    3621                 :          0 : htb_parse_tca_options__(struct nlattr *nl_options, struct htb_class *class)
    3622                 :            : {
    3623                 :            :     static const struct nl_policy tca_htb_policy[] = {
    3624                 :            :         [TCA_HTB_PARMS] = { .type = NL_A_UNSPEC, .optional = false,
    3625                 :            :                             .min_len = sizeof(struct tc_htb_opt) },
    3626                 :            :     };
    3627                 :            : 
    3628                 :            :     struct nlattr *attrs[ARRAY_SIZE(tca_htb_policy)];
    3629                 :            :     const struct tc_htb_opt *htb;
    3630                 :            : 
    3631         [ #  # ]:          0 :     if (!nl_parse_nested(nl_options, tca_htb_policy,
    3632                 :            :                          attrs, ARRAY_SIZE(tca_htb_policy))) {
    3633         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse HTB class options");
    3634                 :          0 :         return EPROTO;
    3635                 :            :     }
    3636                 :            : 
    3637                 :          0 :     htb = nl_attr_get(attrs[TCA_HTB_PARMS]);
    3638                 :          0 :     class->min_rate = htb->rate.rate;
    3639                 :          0 :     class->max_rate = htb->ceil.rate;
    3640                 :          0 :     class->burst = tc_ticks_to_bytes(htb->rate.rate, htb->buffer);
    3641                 :          0 :     class->priority = htb->prio;
    3642                 :          0 :     return 0;
    3643                 :            : }
    3644                 :            : 
    3645                 :            : static int
    3646                 :          0 : htb_parse_tcmsg__(struct ofpbuf *tcmsg, unsigned int *queue_id,
    3647                 :            :                   struct htb_class *options,
    3648                 :            :                   struct netdev_queue_stats *stats)
    3649                 :            : {
    3650                 :            :     struct nlattr *nl_options;
    3651                 :            :     unsigned int handle;
    3652                 :            :     int error;
    3653                 :            : 
    3654                 :          0 :     error = tc_parse_class(tcmsg, &handle, &nl_options, stats);
    3655 [ #  # ][ #  # ]:          0 :     if (!error && queue_id) {
    3656                 :          0 :         unsigned int major = tc_get_major(handle);
    3657                 :          0 :         unsigned int minor = tc_get_minor(handle);
    3658 [ #  # ][ #  # ]:          0 :         if (major == 1 && minor > 0 && minor <= HTB_N_QUEUES) {
                 [ #  # ]
    3659                 :          0 :             *queue_id = minor - 1;
    3660                 :            :         } else {
    3661                 :          0 :             error = EPROTO;
    3662                 :            :         }
    3663                 :            :     }
    3664 [ #  # ][ #  # ]:          0 :     if (!error && options) {
    3665                 :          0 :         error = htb_parse_tca_options__(nl_options, options);
    3666                 :            :     }
    3667                 :          0 :     return error;
    3668                 :            : }
    3669                 :            : 
    3670                 :            : static void
    3671                 :          0 : htb_parse_qdisc_details__(struct netdev *netdev_,
    3672                 :            :                           const struct smap *details, struct htb_class *hc)
    3673                 :            : {
    3674                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3675                 :            : 
    3676                 :          0 :     hc->max_rate = smap_get_ullong(details, "max-rate", 0) / 8;
    3677         [ #  # ]:          0 :     if (!hc->max_rate) {
    3678                 :            :         enum netdev_features current;
    3679                 :            : 
    3680                 :          0 :         netdev_linux_read_features(netdev);
    3681         [ #  # ]:          0 :         current = !netdev->get_features_error ? netdev->current : 0;
    3682                 :          0 :         hc->max_rate = netdev_features_to_bps(current, 100 * 1000 * 1000) / 8;
    3683                 :            :     }
    3684                 :          0 :     hc->min_rate = hc->max_rate;
    3685                 :          0 :     hc->burst = 0;
    3686                 :          0 :     hc->priority = 0;
    3687                 :          0 : }
    3688                 :            : 
    3689                 :            : static int
    3690                 :          0 : htb_parse_class_details__(struct netdev *netdev,
    3691                 :            :                           const struct smap *details, struct htb_class *hc)
    3692                 :            : {
    3693                 :          0 :     const struct htb *htb = htb_get__(netdev);
    3694                 :            :     int mtu, error;
    3695                 :            : 
    3696                 :          0 :     error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
    3697         [ #  # ]:          0 :     if (error) {
    3698         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "cannot parse HTB class on device %s that lacks MTU",
    3699                 :            :                      netdev_get_name(netdev));
    3700                 :          0 :         return error;
    3701                 :            :     }
    3702                 :            : 
    3703                 :            :     /* HTB requires at least an mtu sized min-rate to send any traffic even
    3704                 :            :      * on uncongested links. */
    3705                 :          0 :     hc->min_rate = smap_get_ullong(details, "min-rate", 0) / 8;
    3706                 :          0 :     hc->min_rate = MAX(hc->min_rate, mtu);
    3707                 :          0 :     hc->min_rate = MIN(hc->min_rate, htb->max_rate);
    3708                 :            : 
    3709                 :            :     /* max-rate */
    3710                 :          0 :     hc->max_rate = smap_get_ullong(details, "max-rate", 0) / 8;
    3711         [ #  # ]:          0 :     if (!hc->max_rate) {
    3712                 :          0 :         hc->max_rate = htb->max_rate;
    3713                 :            :     }
    3714                 :          0 :     hc->max_rate = MAX(hc->max_rate, hc->min_rate);
    3715                 :          0 :     hc->max_rate = MIN(hc->max_rate, htb->max_rate);
    3716                 :            : 
    3717                 :            :     /* burst
    3718                 :            :      *
    3719                 :            :      * According to hints in the documentation that I've read, it is important
    3720                 :            :      * that 'burst' be at least as big as the largest frame that might be
    3721                 :            :      * transmitted.  Also, making 'burst' a bit bigger than necessary is OK,
    3722                 :            :      * but having it a bit too small is a problem.  Since netdev_get_mtu()
    3723                 :            :      * doesn't include the Ethernet header, we need to add at least 14 (18?) to
    3724                 :            :      * the MTU.  We actually add 64, instead of 14, as a guard against
    3725                 :            :      * additional headers get tacked on somewhere that we're not aware of. */
    3726                 :          0 :     hc->burst = smap_get_ullong(details, "burst", 0) / 8;
    3727                 :          0 :     hc->burst = MAX(hc->burst, mtu + 64);
    3728                 :            : 
    3729                 :            :     /* priority */
    3730                 :          0 :     hc->priority = smap_get_ullong(details, "priority", 0);
    3731                 :            : 
    3732                 :          0 :     return 0;
    3733                 :            : }
    3734                 :            : 
    3735                 :            : static int
    3736                 :          0 : htb_query_class__(const struct netdev *netdev, unsigned int handle,
    3737                 :            :                   unsigned int parent, struct htb_class *options,
    3738                 :            :                   struct netdev_queue_stats *stats)
    3739                 :            : {
    3740                 :            :     struct ofpbuf *reply;
    3741                 :            :     int error;
    3742                 :            : 
    3743                 :          0 :     error = tc_query_class(netdev, handle, parent, &reply);
    3744         [ #  # ]:          0 :     if (!error) {
    3745                 :          0 :         error = htb_parse_tcmsg__(reply, NULL, options, stats);
    3746                 :          0 :         ofpbuf_delete(reply);
    3747                 :            :     }
    3748                 :          0 :     return error;
    3749                 :            : }
    3750                 :            : 
    3751                 :            : static int
    3752                 :          0 : htb_tc_install(struct netdev *netdev, const struct smap *details)
    3753                 :            : {
    3754                 :            :     int error;
    3755                 :            : 
    3756                 :          0 :     error = htb_setup_qdisc__(netdev);
    3757         [ #  # ]:          0 :     if (!error) {
    3758                 :            :         struct htb_class hc;
    3759                 :            : 
    3760                 :          0 :         htb_parse_qdisc_details__(netdev, details, &hc);
    3761                 :          0 :         error = htb_setup_class__(netdev, tc_make_handle(1, 0xfffe),
    3762                 :            :                                   tc_make_handle(1, 0), &hc);
    3763         [ #  # ]:          0 :         if (!error) {
    3764                 :          0 :             htb_install__(netdev, hc.max_rate);
    3765                 :            :         }
    3766                 :            :     }
    3767                 :          0 :     return error;
    3768                 :            : }
    3769                 :            : 
    3770                 :            : static struct htb_class *
    3771                 :          0 : htb_class_cast__(const struct tc_queue *queue)
    3772                 :            : {
    3773                 :          0 :     return CONTAINER_OF(queue, struct htb_class, tc_queue);
    3774                 :            : }
    3775                 :            : 
    3776                 :            : static void
    3777                 :          0 : htb_update_queue__(struct netdev *netdev, unsigned int queue_id,
    3778                 :            :                    const struct htb_class *hc)
    3779                 :            : {
    3780                 :          0 :     struct htb *htb = htb_get__(netdev);
    3781                 :          0 :     size_t hash = hash_int(queue_id, 0);
    3782                 :            :     struct tc_queue *queue;
    3783                 :            :     struct htb_class *hcp;
    3784                 :            : 
    3785                 :          0 :     queue = tc_find_queue__(netdev, queue_id, hash);
    3786         [ #  # ]:          0 :     if (queue) {
    3787                 :          0 :         hcp = htb_class_cast__(queue);
    3788                 :            :     } else {
    3789                 :          0 :         hcp = xmalloc(sizeof *hcp);
    3790                 :          0 :         queue = &hcp->tc_queue;
    3791                 :          0 :         queue->queue_id = queue_id;
    3792                 :          0 :         queue->created = time_msec();
    3793                 :          0 :         hmap_insert(&htb->tc.queues, &queue->hmap_node, hash);
    3794                 :            :     }
    3795                 :            : 
    3796                 :          0 :     hcp->min_rate = hc->min_rate;
    3797                 :          0 :     hcp->max_rate = hc->max_rate;
    3798                 :          0 :     hcp->burst = hc->burst;
    3799                 :          0 :     hcp->priority = hc->priority;
    3800                 :          0 : }
    3801                 :            : 
    3802                 :            : static int
    3803                 :          0 : htb_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
    3804                 :            : {
    3805                 :            :     struct ofpbuf msg;
    3806                 :            :     struct queue_dump_state state;
    3807                 :            :     struct htb_class hc;
    3808                 :            : 
    3809                 :            :     /* Get qdisc options. */
    3810                 :          0 :     hc.max_rate = 0;
    3811                 :          0 :     htb_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL);
    3812                 :          0 :     htb_install__(netdev, hc.max_rate);
    3813                 :            : 
    3814                 :            :     /* Get queues. */
    3815         [ #  # ]:          0 :     if (!start_queue_dump(netdev, &state)) {
    3816                 :          0 :         return ENODEV;
    3817                 :            :     }
    3818         [ #  # ]:          0 :     while (nl_dump_next(&state.dump, &msg, &state.buf)) {
    3819                 :            :         unsigned int queue_id;
    3820                 :            : 
    3821         [ #  # ]:          0 :         if (!htb_parse_tcmsg__(&msg, &queue_id, &hc, NULL)) {
    3822                 :          0 :             htb_update_queue__(netdev, queue_id, &hc);
    3823                 :            :         }
    3824                 :            :     }
    3825                 :          0 :     finish_queue_dump(&state);
    3826                 :            : 
    3827                 :          0 :     return 0;
    3828                 :            : }
    3829                 :            : 
    3830                 :            : static void
    3831                 :          0 : htb_tc_destroy(struct tc *tc)
    3832                 :            : {
    3833                 :          0 :     struct htb *htb = CONTAINER_OF(tc, struct htb, tc);
    3834                 :            :     struct htb_class *hc;
    3835                 :            : 
    3836 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH_POP (hc, tc_queue.hmap_node, &htb->tc.queues) {
                 [ #  # ]
    3837                 :          0 :         free(hc);
    3838                 :            :     }
    3839                 :          0 :     tc_destroy(tc);
    3840                 :          0 :     free(htb);
    3841                 :          0 : }
    3842                 :            : 
    3843                 :            : static int
    3844                 :          0 : htb_qdisc_get(const struct netdev *netdev, struct smap *details)
    3845                 :            : {
    3846                 :          0 :     const struct htb *htb = htb_get__(netdev);
    3847                 :          0 :     smap_add_format(details, "max-rate", "%llu", 8ULL * htb->max_rate);
    3848                 :          0 :     return 0;
    3849                 :            : }
    3850                 :            : 
    3851                 :            : static int
    3852                 :          0 : htb_qdisc_set(struct netdev *netdev, const struct smap *details)
    3853                 :            : {
    3854                 :            :     struct htb_class hc;
    3855                 :            :     int error;
    3856                 :            : 
    3857                 :          0 :     htb_parse_qdisc_details__(netdev, details, &hc);
    3858                 :          0 :     error = htb_setup_class__(netdev, tc_make_handle(1, 0xfffe),
    3859                 :            :                               tc_make_handle(1, 0), &hc);
    3860         [ #  # ]:          0 :     if (!error) {
    3861                 :          0 :         htb_get__(netdev)->max_rate = hc.max_rate;
    3862                 :            :     }
    3863                 :          0 :     return error;
    3864                 :            : }
    3865                 :            : 
    3866                 :            : static int
    3867                 :          0 : htb_class_get(const struct netdev *netdev OVS_UNUSED,
    3868                 :            :               const struct tc_queue *queue, struct smap *details)
    3869                 :            : {
    3870                 :          0 :     const struct htb_class *hc = htb_class_cast__(queue);
    3871                 :            : 
    3872                 :          0 :     smap_add_format(details, "min-rate", "%llu", 8ULL * hc->min_rate);
    3873         [ #  # ]:          0 :     if (hc->min_rate != hc->max_rate) {
    3874                 :          0 :         smap_add_format(details, "max-rate", "%llu", 8ULL * hc->max_rate);
    3875                 :            :     }
    3876                 :          0 :     smap_add_format(details, "burst", "%llu", 8ULL * hc->burst);
    3877         [ #  # ]:          0 :     if (hc->priority) {
    3878                 :          0 :         smap_add_format(details, "priority", "%u", hc->priority);
    3879                 :            :     }
    3880                 :          0 :     return 0;
    3881                 :            : }
    3882                 :            : 
    3883                 :            : static int
    3884                 :          0 : htb_class_set(struct netdev *netdev, unsigned int queue_id,
    3885                 :            :               const struct smap *details)
    3886                 :            : {
    3887                 :            :     struct htb_class hc;
    3888                 :            :     int error;
    3889                 :            : 
    3890                 :          0 :     error = htb_parse_class_details__(netdev, details, &hc);
    3891         [ #  # ]:          0 :     if (error) {
    3892                 :          0 :         return error;
    3893                 :            :     }
    3894                 :            : 
    3895                 :          0 :     error = htb_setup_class__(netdev, tc_make_handle(1, queue_id + 1),
    3896                 :            :                               tc_make_handle(1, 0xfffe), &hc);
    3897         [ #  # ]:          0 :     if (error) {
    3898                 :          0 :         return error;
    3899                 :            :     }
    3900                 :            : 
    3901                 :          0 :     htb_update_queue__(netdev, queue_id, &hc);
    3902                 :          0 :     return 0;
    3903                 :            : }
    3904                 :            : 
    3905                 :            : static int
    3906                 :          0 : htb_class_delete(struct netdev *netdev, struct tc_queue *queue)
    3907                 :            : {
    3908                 :          0 :     struct htb_class *hc = htb_class_cast__(queue);
    3909                 :          0 :     struct htb *htb = htb_get__(netdev);
    3910                 :            :     int error;
    3911                 :            : 
    3912                 :          0 :     error = tc_delete_class(netdev, tc_make_handle(1, queue->queue_id + 1));
    3913         [ #  # ]:          0 :     if (!error) {
    3914                 :          0 :         hmap_remove(&htb->tc.queues, &hc->tc_queue.hmap_node);
    3915                 :          0 :         free(hc);
    3916                 :            :     }
    3917                 :          0 :     return error;
    3918                 :            : }
    3919                 :            : 
    3920                 :            : static int
    3921                 :          0 : htb_class_get_stats(const struct netdev *netdev, const struct tc_queue *queue,
    3922                 :            :                     struct netdev_queue_stats *stats)
    3923                 :            : {
    3924                 :          0 :     return htb_query_class__(netdev, tc_make_handle(1, queue->queue_id + 1),
    3925                 :            :                              tc_make_handle(1, 0xfffe), NULL, stats);
    3926                 :            : }
    3927                 :            : 
    3928                 :            : static int
    3929                 :          0 : htb_class_dump_stats(const struct netdev *netdev OVS_UNUSED,
    3930                 :            :                      const struct ofpbuf *nlmsg,
    3931                 :            :                      netdev_dump_queue_stats_cb *cb, void *aux)
    3932                 :            : {
    3933                 :            :     struct netdev_queue_stats stats;
    3934                 :            :     unsigned int handle, major, minor;
    3935                 :            :     int error;
    3936                 :            : 
    3937                 :          0 :     error = tc_parse_class(nlmsg, &handle, NULL, &stats);
    3938         [ #  # ]:          0 :     if (error) {
    3939                 :          0 :         return error;
    3940                 :            :     }
    3941                 :            : 
    3942                 :          0 :     major = tc_get_major(handle);
    3943                 :          0 :     minor = tc_get_minor(handle);
    3944 [ #  # ][ #  # ]:          0 :     if (major == 1 && minor > 0 && minor <= HTB_N_QUEUES) {
                 [ #  # ]
    3945                 :          0 :         (*cb)(minor - 1, &stats, aux);
    3946                 :            :     }
    3947                 :          0 :     return 0;
    3948                 :            : }
    3949                 :            : 
    3950                 :            : static const struct tc_ops tc_ops_htb = {
    3951                 :            :     "htb",                      /* linux_name */
    3952                 :            :     "linux-htb",                /* ovs_name */
    3953                 :            :     HTB_N_QUEUES,               /* n_queues */
    3954                 :            :     htb_tc_install,
    3955                 :            :     htb_tc_load,
    3956                 :            :     htb_tc_destroy,
    3957                 :            :     htb_qdisc_get,
    3958                 :            :     htb_qdisc_set,
    3959                 :            :     htb_class_get,
    3960                 :            :     htb_class_set,
    3961                 :            :     htb_class_delete,
    3962                 :            :     htb_class_get_stats,
    3963                 :            :     htb_class_dump_stats
    3964                 :            : };
    3965                 :            : 
    3966                 :            : /* "linux-hfsc" traffic control class. */
    3967                 :            : 
    3968                 :            : #define HFSC_N_QUEUES 0xf000
    3969                 :            : 
    3970                 :            : struct hfsc {
    3971                 :            :     struct tc tc;
    3972                 :            :     uint32_t max_rate;
    3973                 :            : };
    3974                 :            : 
    3975                 :            : struct hfsc_class {
    3976                 :            :     struct tc_queue tc_queue;
    3977                 :            :     uint32_t min_rate;
    3978                 :            :     uint32_t max_rate;
    3979                 :            : };
    3980                 :            : 
    3981                 :            : static struct hfsc *
    3982                 :          0 : hfsc_get__(const struct netdev *netdev_)
    3983                 :            : {
    3984                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3985                 :          0 :     return CONTAINER_OF(netdev->tc, struct hfsc, tc);
    3986                 :            : }
    3987                 :            : 
    3988                 :            : static struct hfsc_class *
    3989                 :          0 : hfsc_class_cast__(const struct tc_queue *queue)
    3990                 :            : {
    3991                 :          0 :     return CONTAINER_OF(queue, struct hfsc_class, tc_queue);
    3992                 :            : }
    3993                 :            : 
    3994                 :            : static void
    3995                 :          0 : hfsc_install__(struct netdev *netdev_, uint32_t max_rate)
    3996                 :            : {
    3997                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    3998                 :            :     struct hfsc *hfsc;
    3999                 :            : 
    4000                 :          0 :     hfsc = xmalloc(sizeof *hfsc);
    4001                 :          0 :     tc_init(&hfsc->tc, &tc_ops_hfsc);
    4002                 :          0 :     hfsc->max_rate = max_rate;
    4003                 :          0 :     netdev->tc = &hfsc->tc;
    4004                 :          0 : }
    4005                 :            : 
    4006                 :            : static void
    4007                 :          0 : hfsc_update_queue__(struct netdev *netdev, unsigned int queue_id,
    4008                 :            :                     const struct hfsc_class *hc)
    4009                 :            : {
    4010                 :            :     size_t hash;
    4011                 :            :     struct hfsc *hfsc;
    4012                 :            :     struct hfsc_class *hcp;
    4013                 :            :     struct tc_queue *queue;
    4014                 :            : 
    4015                 :          0 :     hfsc = hfsc_get__(netdev);
    4016                 :          0 :     hash = hash_int(queue_id, 0);
    4017                 :            : 
    4018                 :          0 :     queue = tc_find_queue__(netdev, queue_id, hash);
    4019         [ #  # ]:          0 :     if (queue) {
    4020                 :          0 :         hcp = hfsc_class_cast__(queue);
    4021                 :            :     } else {
    4022                 :          0 :         hcp             = xmalloc(sizeof *hcp);
    4023                 :          0 :         queue           = &hcp->tc_queue;
    4024                 :          0 :         queue->queue_id = queue_id;
    4025                 :          0 :         queue->created  = time_msec();
    4026                 :          0 :         hmap_insert(&hfsc->tc.queues, &queue->hmap_node, hash);
    4027                 :            :     }
    4028                 :            : 
    4029                 :          0 :     hcp->min_rate = hc->min_rate;
    4030                 :          0 :     hcp->max_rate = hc->max_rate;
    4031                 :          0 : }
    4032                 :            : 
    4033                 :            : static int
    4034                 :          0 : hfsc_parse_tca_options__(struct nlattr *nl_options, struct hfsc_class *class)
    4035                 :            : {
    4036                 :            :     const struct tc_service_curve *rsc, *fsc, *usc;
    4037                 :            :     static const struct nl_policy tca_hfsc_policy[] = {
    4038                 :            :         [TCA_HFSC_RSC] = {
    4039                 :            :             .type      = NL_A_UNSPEC,
    4040                 :            :             .optional  = false,
    4041                 :            :             .min_len   = sizeof(struct tc_service_curve),
    4042                 :            :         },
    4043                 :            :         [TCA_HFSC_FSC] = {
    4044                 :            :             .type      = NL_A_UNSPEC,
    4045                 :            :             .optional  = false,
    4046                 :            :             .min_len   = sizeof(struct tc_service_curve),
    4047                 :            :         },
    4048                 :            :         [TCA_HFSC_USC] = {
    4049                 :            :             .type      = NL_A_UNSPEC,
    4050                 :            :             .optional  = false,
    4051                 :            :             .min_len   = sizeof(struct tc_service_curve),
    4052                 :            :         },
    4053                 :            :     };
    4054                 :            :     struct nlattr *attrs[ARRAY_SIZE(tca_hfsc_policy)];
    4055                 :            : 
    4056         [ #  # ]:          0 :     if (!nl_parse_nested(nl_options, tca_hfsc_policy,
    4057                 :            :                          attrs, ARRAY_SIZE(tca_hfsc_policy))) {
    4058         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse HFSC class options");
    4059                 :          0 :         return EPROTO;
    4060                 :            :     }
    4061                 :            : 
    4062                 :          0 :     rsc = nl_attr_get(attrs[TCA_HFSC_RSC]);
    4063                 :          0 :     fsc = nl_attr_get(attrs[TCA_HFSC_FSC]);
    4064                 :          0 :     usc = nl_attr_get(attrs[TCA_HFSC_USC]);
    4065                 :            : 
    4066 [ #  # ][ #  # ]:          0 :     if (rsc->m1 != 0 || rsc->d != 0 ||
                 [ #  # ]
    4067 [ #  # ][ #  # ]:          0 :         fsc->m1 != 0 || fsc->d != 0 ||
    4068         [ #  # ]:          0 :         usc->m1 != 0 || usc->d != 0) {
    4069         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse HFSC class options. "
    4070                 :            :                      "Non-linear service curves are not supported.");
    4071                 :          0 :         return EPROTO;
    4072                 :            :     }
    4073                 :            : 
    4074         [ #  # ]:          0 :     if (rsc->m2 != fsc->m2) {
    4075         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse HFSC class options. "
    4076                 :            :                      "Real-time service curves are not supported ");
    4077                 :          0 :         return EPROTO;
    4078                 :            :     }
    4079                 :            : 
    4080         [ #  # ]:          0 :     if (rsc->m2 > usc->m2) {
    4081         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse HFSC class options. "
    4082                 :            :                      "Min-rate service curve is greater than "
    4083                 :            :                      "the max-rate service curve.");
    4084                 :          0 :         return EPROTO;
    4085                 :            :     }
    4086                 :            : 
    4087                 :          0 :     class->min_rate = fsc->m2;
    4088                 :          0 :     class->max_rate = usc->m2;
    4089                 :          0 :     return 0;
    4090                 :            : }
    4091                 :            : 
    4092                 :            : static int
    4093                 :          0 : hfsc_parse_tcmsg__(struct ofpbuf *tcmsg, unsigned int *queue_id,
    4094                 :            :                    struct hfsc_class *options,
    4095                 :            :                    struct netdev_queue_stats *stats)
    4096                 :            : {
    4097                 :            :     int error;
    4098                 :            :     unsigned int handle;
    4099                 :            :     struct nlattr *nl_options;
    4100                 :            : 
    4101                 :          0 :     error = tc_parse_class(tcmsg, &handle, &nl_options, stats);
    4102         [ #  # ]:          0 :     if (error) {
    4103                 :          0 :         return error;
    4104                 :            :     }
    4105                 :            : 
    4106         [ #  # ]:          0 :     if (queue_id) {
    4107                 :            :         unsigned int major, minor;
    4108                 :            : 
    4109                 :          0 :         major = tc_get_major(handle);
    4110                 :          0 :         minor = tc_get_minor(handle);
    4111 [ #  # ][ #  # ]:          0 :         if (major == 1 && minor > 0 && minor <= HFSC_N_QUEUES) {
                 [ #  # ]
    4112                 :          0 :             *queue_id = minor - 1;
    4113                 :            :         } else {
    4114                 :          0 :             return EPROTO;
    4115                 :            :         }
    4116                 :            :     }
    4117                 :            : 
    4118         [ #  # ]:          0 :     if (options) {
    4119                 :          0 :         error = hfsc_parse_tca_options__(nl_options, options);
    4120                 :            :     }
    4121                 :            : 
    4122                 :          0 :     return error;
    4123                 :            : }
    4124                 :            : 
    4125                 :            : static int
    4126                 :          0 : hfsc_query_class__(const struct netdev *netdev, unsigned int handle,
    4127                 :            :                    unsigned int parent, struct hfsc_class *options,
    4128                 :            :                    struct netdev_queue_stats *stats)
    4129                 :            : {
    4130                 :            :     int error;
    4131                 :            :     struct ofpbuf *reply;
    4132                 :            : 
    4133                 :          0 :     error = tc_query_class(netdev, handle, parent, &reply);
    4134         [ #  # ]:          0 :     if (error) {
    4135                 :          0 :         return error;
    4136                 :            :     }
    4137                 :            : 
    4138                 :          0 :     error = hfsc_parse_tcmsg__(reply, NULL, options, stats);
    4139                 :          0 :     ofpbuf_delete(reply);
    4140                 :          0 :     return error;
    4141                 :            : }
    4142                 :            : 
    4143                 :            : static void
    4144                 :          0 : hfsc_parse_qdisc_details__(struct netdev *netdev_, const struct smap *details,
    4145                 :            :                            struct hfsc_class *class)
    4146                 :            : {
    4147                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    4148                 :            : 
    4149                 :          0 :     uint32_t max_rate = smap_get_ullong(details, "max-rate", 0) / 8;
    4150         [ #  # ]:          0 :     if (!max_rate) {
    4151                 :            :         enum netdev_features current;
    4152                 :            : 
    4153                 :          0 :         netdev_linux_read_features(netdev);
    4154         [ #  # ]:          0 :         current = !netdev->get_features_error ? netdev->current : 0;
    4155                 :          0 :         max_rate = netdev_features_to_bps(current, 100 * 1000 * 1000) / 8;
    4156                 :            :     }
    4157                 :            : 
    4158                 :          0 :     class->min_rate = max_rate;
    4159                 :          0 :     class->max_rate = max_rate;
    4160                 :          0 : }
    4161                 :            : 
    4162                 :            : static int
    4163                 :          0 : hfsc_parse_class_details__(struct netdev *netdev,
    4164                 :            :                            const struct smap *details,
    4165                 :            :                            struct hfsc_class * class)
    4166                 :            : {
    4167                 :            :     const struct hfsc *hfsc;
    4168                 :            :     uint32_t min_rate, max_rate;
    4169                 :            : 
    4170                 :          0 :     hfsc       = hfsc_get__(netdev);
    4171                 :            : 
    4172                 :          0 :     min_rate = smap_get_ullong(details, "min-rate", 0) / 8;
    4173                 :          0 :     min_rate = MAX(min_rate, 1);
    4174                 :          0 :     min_rate = MIN(min_rate, hfsc->max_rate);
    4175                 :            : 
    4176                 :          0 :     max_rate = smap_get_ullong(details, "max-rate", hfsc->max_rate * 8) / 8;
    4177                 :          0 :     max_rate = MAX(max_rate, min_rate);
    4178                 :          0 :     max_rate = MIN(max_rate, hfsc->max_rate);
    4179                 :            : 
    4180                 :          0 :     class->min_rate = min_rate;
    4181                 :          0 :     class->max_rate = max_rate;
    4182                 :            : 
    4183                 :          0 :     return 0;
    4184                 :            : }
    4185                 :            : 
    4186                 :            : /* Create an HFSC qdisc.
    4187                 :            :  *
    4188                 :            :  * Equivalent to "tc qdisc add dev <dev> root handle 1: hfsc default 1". */
    4189                 :            : static int
    4190                 :          0 : hfsc_setup_qdisc__(struct netdev * netdev)
    4191                 :            : {
    4192                 :            :     struct tcmsg *tcmsg;
    4193                 :            :     struct ofpbuf request;
    4194                 :            :     struct tc_hfsc_qopt opt;
    4195                 :            : 
    4196                 :          0 :     tc_del_qdisc(netdev);
    4197                 :            : 
    4198                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
    4199                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    4200                 :            : 
    4201         [ #  # ]:          0 :     if (!tcmsg) {
    4202                 :          0 :         return ENODEV;
    4203                 :            :     }
    4204                 :            : 
    4205                 :          0 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    4206                 :          0 :     tcmsg->tcm_parent = TC_H_ROOT;
    4207                 :            : 
    4208                 :          0 :     memset(&opt, 0, sizeof opt);
    4209                 :          0 :     opt.defcls = 1;
    4210                 :            : 
    4211                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "hfsc");
    4212                 :          0 :     nl_msg_put_unspec(&request, TCA_OPTIONS, &opt, sizeof opt);
    4213                 :            : 
    4214                 :          0 :     return tc_transact(&request, NULL);
    4215                 :            : }
    4216                 :            : 
    4217                 :            : /* Create an HFSC class.
    4218                 :            :  *
    4219                 :            :  * Equivalent to "tc class add <dev> parent <parent> classid <handle> hfsc
    4220                 :            :  * sc rate <min_rate> ul rate <max_rate>" */
    4221                 :            : static int
    4222                 :          0 : hfsc_setup_class__(struct netdev *netdev, unsigned int handle,
    4223                 :            :                    unsigned int parent, struct hfsc_class *class)
    4224                 :            : {
    4225                 :            :     int error;
    4226                 :            :     size_t opt_offset;
    4227                 :            :     struct tcmsg *tcmsg;
    4228                 :            :     struct ofpbuf request;
    4229                 :            :     struct tc_service_curve min, max;
    4230                 :            : 
    4231                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWTCLASS, NLM_F_CREATE, &request);
    4232                 :            : 
    4233         [ #  # ]:          0 :     if (!tcmsg) {
    4234                 :          0 :         return ENODEV;
    4235                 :            :     }
    4236                 :            : 
    4237                 :          0 :     tcmsg->tcm_handle = handle;
    4238                 :          0 :     tcmsg->tcm_parent = parent;
    4239                 :            : 
    4240                 :          0 :     min.m1 = 0;
    4241                 :          0 :     min.d  = 0;
    4242                 :          0 :     min.m2 = class->min_rate;
    4243                 :            : 
    4244                 :          0 :     max.m1 = 0;
    4245                 :          0 :     max.d  = 0;
    4246                 :          0 :     max.m2 = class->max_rate;
    4247                 :            : 
    4248                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "hfsc");
    4249                 :          0 :     opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    4250                 :          0 :     nl_msg_put_unspec(&request, TCA_HFSC_RSC, &min, sizeof min);
    4251                 :          0 :     nl_msg_put_unspec(&request, TCA_HFSC_FSC, &min, sizeof min);
    4252                 :          0 :     nl_msg_put_unspec(&request, TCA_HFSC_USC, &max, sizeof max);
    4253                 :          0 :     nl_msg_end_nested(&request, opt_offset);
    4254                 :            : 
    4255                 :          0 :     error = tc_transact(&request, NULL);
    4256         [ #  # ]:          0 :     if (error) {
    4257         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to replace %s class %u:%u, parent %u:%u, "
    4258                 :            :                      "min-rate %ubps, max-rate %ubps (%s)",
    4259                 :            :                      netdev_get_name(netdev),
    4260                 :            :                      tc_get_major(handle), tc_get_minor(handle),
    4261                 :            :                      tc_get_major(parent), tc_get_minor(parent),
    4262                 :            :                      class->min_rate, class->max_rate, ovs_strerror(error));
    4263                 :            :     }
    4264                 :            : 
    4265                 :          0 :     return error;
    4266                 :            : }
    4267                 :            : 
    4268                 :            : static int
    4269                 :          0 : hfsc_tc_install(struct netdev *netdev, const struct smap *details)
    4270                 :            : {
    4271                 :            :     int error;
    4272                 :            :     struct hfsc_class class;
    4273                 :            : 
    4274                 :          0 :     error = hfsc_setup_qdisc__(netdev);
    4275                 :            : 
    4276         [ #  # ]:          0 :     if (error) {
    4277                 :          0 :         return error;
    4278                 :            :     }
    4279                 :            : 
    4280                 :          0 :     hfsc_parse_qdisc_details__(netdev, details, &class);
    4281                 :          0 :     error = hfsc_setup_class__(netdev, tc_make_handle(1, 0xfffe),
    4282                 :            :                                tc_make_handle(1, 0), &class);
    4283                 :            : 
    4284         [ #  # ]:          0 :     if (error) {
    4285                 :          0 :         return error;
    4286                 :            :     }
    4287                 :            : 
    4288                 :          0 :     hfsc_install__(netdev, class.max_rate);
    4289                 :          0 :     return 0;
    4290                 :            : }
    4291                 :            : 
    4292                 :            : static int
    4293                 :          0 : hfsc_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
    4294                 :            : {
    4295                 :            :     struct ofpbuf msg;
    4296                 :            :     struct queue_dump_state state;
    4297                 :            :     struct hfsc_class hc;
    4298                 :            : 
    4299                 :          0 :     hc.max_rate = 0;
    4300                 :          0 :     hfsc_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL);
    4301                 :          0 :     hfsc_install__(netdev, hc.max_rate);
    4302                 :            : 
    4303         [ #  # ]:          0 :     if (!start_queue_dump(netdev, &state)) {
    4304                 :          0 :         return ENODEV;
    4305                 :            :     }
    4306                 :            : 
    4307         [ #  # ]:          0 :     while (nl_dump_next(&state.dump, &msg, &state.buf)) {
    4308                 :            :         unsigned int queue_id;
    4309                 :            : 
    4310         [ #  # ]:          0 :         if (!hfsc_parse_tcmsg__(&msg, &queue_id, &hc, NULL)) {
    4311                 :          0 :             hfsc_update_queue__(netdev, queue_id, &hc);
    4312                 :            :         }
    4313                 :            :     }
    4314                 :            : 
    4315                 :          0 :     finish_queue_dump(&state);
    4316                 :          0 :     return 0;
    4317                 :            : }
    4318                 :            : 
    4319                 :            : static void
    4320                 :          0 : hfsc_tc_destroy(struct tc *tc)
    4321                 :            : {
    4322                 :            :     struct hfsc *hfsc;
    4323                 :            :     struct hfsc_class *hc, *next;
    4324                 :            : 
    4325                 :          0 :     hfsc = CONTAINER_OF(tc, struct hfsc, tc);
    4326                 :            : 
    4327 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH_SAFE (hc, next, tc_queue.hmap_node, &hfsc->tc.queues) {
                 [ #  # ]
    4328                 :          0 :         hmap_remove(&hfsc->tc.queues, &hc->tc_queue.hmap_node);
    4329                 :          0 :         free(hc);
    4330                 :            :     }
    4331                 :            : 
    4332                 :          0 :     tc_destroy(tc);
    4333                 :          0 :     free(hfsc);
    4334                 :          0 : }
    4335                 :            : 
    4336                 :            : static int
    4337                 :          0 : hfsc_qdisc_get(const struct netdev *netdev, struct smap *details)
    4338                 :            : {
    4339                 :            :     const struct hfsc *hfsc;
    4340                 :          0 :     hfsc = hfsc_get__(netdev);
    4341                 :          0 :     smap_add_format(details, "max-rate", "%llu", 8ULL * hfsc->max_rate);
    4342                 :          0 :     return 0;
    4343                 :            : }
    4344                 :            : 
    4345                 :            : static int
    4346                 :          0 : hfsc_qdisc_set(struct netdev *netdev, const struct smap *details)
    4347                 :            : {
    4348                 :            :     int error;
    4349                 :            :     struct hfsc_class class;
    4350                 :            : 
    4351                 :          0 :     hfsc_parse_qdisc_details__(netdev, details, &class);
    4352                 :          0 :     error = hfsc_setup_class__(netdev, tc_make_handle(1, 0xfffe),
    4353                 :            :                                tc_make_handle(1, 0), &class);
    4354                 :            : 
    4355         [ #  # ]:          0 :     if (!error) {
    4356                 :          0 :         hfsc_get__(netdev)->max_rate = class.max_rate;
    4357                 :            :     }
    4358                 :            : 
    4359                 :          0 :     return error;
    4360                 :            : }
    4361                 :            : 
    4362                 :            : static int
    4363                 :          0 : hfsc_class_get(const struct netdev *netdev OVS_UNUSED,
    4364                 :            :               const struct tc_queue *queue, struct smap *details)
    4365                 :            : {
    4366                 :            :     const struct hfsc_class *hc;
    4367                 :            : 
    4368                 :          0 :     hc = hfsc_class_cast__(queue);
    4369                 :          0 :     smap_add_format(details, "min-rate", "%llu", 8ULL * hc->min_rate);
    4370         [ #  # ]:          0 :     if (hc->min_rate != hc->max_rate) {
    4371                 :          0 :         smap_add_format(details, "max-rate", "%llu", 8ULL * hc->max_rate);
    4372                 :            :     }
    4373                 :          0 :     return 0;
    4374                 :            : }
    4375                 :            : 
    4376                 :            : static int
    4377                 :          0 : hfsc_class_set(struct netdev *netdev, unsigned int queue_id,
    4378                 :            :                const struct smap *details)
    4379                 :            : {
    4380                 :            :     int error;
    4381                 :            :     struct hfsc_class class;
    4382                 :            : 
    4383                 :          0 :     error = hfsc_parse_class_details__(netdev, details, &class);
    4384         [ #  # ]:          0 :     if (error) {
    4385                 :          0 :         return error;
    4386                 :            :     }
    4387                 :            : 
    4388                 :          0 :     error = hfsc_setup_class__(netdev, tc_make_handle(1, queue_id + 1),
    4389                 :            :                                tc_make_handle(1, 0xfffe), &class);
    4390         [ #  # ]:          0 :     if (error) {
    4391                 :          0 :         return error;
    4392                 :            :     }
    4393                 :            : 
    4394                 :          0 :     hfsc_update_queue__(netdev, queue_id, &class);
    4395                 :          0 :     return 0;
    4396                 :            : }
    4397                 :            : 
    4398                 :            : static int
    4399                 :          0 : hfsc_class_delete(struct netdev *netdev, struct tc_queue *queue)
    4400                 :            : {
    4401                 :            :     int error;
    4402                 :            :     struct hfsc *hfsc;
    4403                 :            :     struct hfsc_class *hc;
    4404                 :            : 
    4405                 :          0 :     hc   = hfsc_class_cast__(queue);
    4406                 :          0 :     hfsc = hfsc_get__(netdev);
    4407                 :            : 
    4408                 :          0 :     error = tc_delete_class(netdev, tc_make_handle(1, queue->queue_id + 1));
    4409         [ #  # ]:          0 :     if (!error) {
    4410                 :          0 :         hmap_remove(&hfsc->tc.queues, &hc->tc_queue.hmap_node);
    4411                 :          0 :         free(hc);
    4412                 :            :     }
    4413                 :          0 :     return error;
    4414                 :            : }
    4415                 :            : 
    4416                 :            : static int
    4417                 :          0 : hfsc_class_get_stats(const struct netdev *netdev, const struct tc_queue *queue,
    4418                 :            :                      struct netdev_queue_stats *stats)
    4419                 :            : {
    4420                 :          0 :     return hfsc_query_class__(netdev, tc_make_handle(1, queue->queue_id + 1),
    4421                 :            :                              tc_make_handle(1, 0xfffe), NULL, stats);
    4422                 :            : }
    4423                 :            : 
    4424                 :            : static int
    4425                 :          0 : hfsc_class_dump_stats(const struct netdev *netdev OVS_UNUSED,
    4426                 :            :                       const struct ofpbuf *nlmsg,
    4427                 :            :                       netdev_dump_queue_stats_cb *cb, void *aux)
    4428                 :            : {
    4429                 :            :     struct netdev_queue_stats stats;
    4430                 :            :     unsigned int handle, major, minor;
    4431                 :            :     int error;
    4432                 :            : 
    4433                 :          0 :     error = tc_parse_class(nlmsg, &handle, NULL, &stats);
    4434         [ #  # ]:          0 :     if (error) {
    4435                 :          0 :         return error;
    4436                 :            :     }
    4437                 :            : 
    4438                 :          0 :     major = tc_get_major(handle);
    4439                 :          0 :     minor = tc_get_minor(handle);
    4440 [ #  # ][ #  # ]:          0 :     if (major == 1 && minor > 0 && minor <= HFSC_N_QUEUES) {
                 [ #  # ]
    4441                 :          0 :         (*cb)(minor - 1, &stats, aux);
    4442                 :            :     }
    4443                 :          0 :     return 0;
    4444                 :            : }
    4445                 :            : 
    4446                 :            : static const struct tc_ops tc_ops_hfsc = {
    4447                 :            :     "hfsc",                     /* linux_name */
    4448                 :            :     "linux-hfsc",               /* ovs_name */
    4449                 :            :     HFSC_N_QUEUES,              /* n_queues */
    4450                 :            :     hfsc_tc_install,            /* tc_install */
    4451                 :            :     hfsc_tc_load,               /* tc_load */
    4452                 :            :     hfsc_tc_destroy,            /* tc_destroy */
    4453                 :            :     hfsc_qdisc_get,             /* qdisc_get */
    4454                 :            :     hfsc_qdisc_set,             /* qdisc_set */
    4455                 :            :     hfsc_class_get,             /* class_get */
    4456                 :            :     hfsc_class_set,             /* class_set */
    4457                 :            :     hfsc_class_delete,          /* class_delete */
    4458                 :            :     hfsc_class_get_stats,       /* class_get_stats */
    4459                 :            :     hfsc_class_dump_stats       /* class_dump_stats */
    4460                 :            : };
    4461                 :            : 
    4462                 :            : /* "linux-noop" traffic control class. */
    4463                 :            : 
    4464                 :            : static void
    4465                 :          0 : noop_install__(struct netdev *netdev_)
    4466                 :            : {
    4467                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    4468                 :            :     static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_default);
    4469                 :            : 
    4470                 :          0 :     netdev->tc = CONST_CAST(struct tc *, &tc);
    4471                 :          0 : }
    4472                 :            : 
    4473                 :            : static int
    4474                 :          0 : noop_tc_install(struct netdev *netdev,
    4475                 :            :                    const struct smap *details OVS_UNUSED)
    4476                 :            : {
    4477                 :          0 :     noop_install__(netdev);
    4478                 :          0 :     return 0;
    4479                 :            : }
    4480                 :            : 
    4481                 :            : static int
    4482                 :          0 : noop_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
    4483                 :            : {
    4484                 :          0 :     noop_install__(netdev);
    4485                 :          0 :     return 0;
    4486                 :            : }
    4487                 :            : 
    4488                 :            : static const struct tc_ops tc_ops_noop = {
    4489                 :            :     NULL,                       /* linux_name */
    4490                 :            :     "linux-noop",               /* ovs_name */
    4491                 :            :     0,                          /* n_queues */
    4492                 :            :     noop_tc_install,
    4493                 :            :     noop_tc_load,
    4494                 :            :     NULL,                       /* tc_destroy */
    4495                 :            :     NULL,                       /* qdisc_get */
    4496                 :            :     NULL,                       /* qdisc_set */
    4497                 :            :     NULL,                       /* class_get */
    4498                 :            :     NULL,                       /* class_set */
    4499                 :            :     NULL,                       /* class_delete */
    4500                 :            :     NULL,                       /* class_get_stats */
    4501                 :            :     NULL                        /* class_dump_stats */
    4502                 :            : };
    4503                 :            : 
    4504                 :            : /* "linux-default" traffic control class.
    4505                 :            :  *
    4506                 :            :  * This class represents the default, unnamed Linux qdisc.  It corresponds to
    4507                 :            :  * the "" (empty string) QoS type in the OVS database. */
    4508                 :            : 
    4509                 :            : static void
    4510                 :        344 : default_install__(struct netdev *netdev_)
    4511                 :            : {
    4512                 :        344 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    4513                 :            :     static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_default);
    4514                 :            : 
    4515                 :            :     /* Nothing but a tc class implementation is allowed to write to a tc.  This
    4516                 :            :      * class never does that, so we can legitimately use a const tc object. */
    4517                 :        344 :     netdev->tc = CONST_CAST(struct tc *, &tc);
    4518                 :        344 : }
    4519                 :            : 
    4520                 :            : static int
    4521                 :        233 : default_tc_install(struct netdev *netdev,
    4522                 :            :                    const struct smap *details OVS_UNUSED)
    4523                 :            : {
    4524                 :        233 :     default_install__(netdev);
    4525                 :        233 :     return 0;
    4526                 :            : }
    4527                 :            : 
    4528                 :            : static int
    4529                 :        111 : default_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
    4530                 :            : {
    4531                 :        111 :     default_install__(netdev);
    4532                 :        111 :     return 0;
    4533                 :            : }
    4534                 :            : 
    4535                 :            : static const struct tc_ops tc_ops_default = {
    4536                 :            :     NULL,                       /* linux_name */
    4537                 :            :     "",                         /* ovs_name */
    4538                 :            :     0,                          /* n_queues */
    4539                 :            :     default_tc_install,
    4540                 :            :     default_tc_load,
    4541                 :            :     NULL,                       /* tc_destroy */
    4542                 :            :     NULL,                       /* qdisc_get */
    4543                 :            :     NULL,                       /* qdisc_set */
    4544                 :            :     NULL,                       /* class_get */
    4545                 :            :     NULL,                       /* class_set */
    4546                 :            :     NULL,                       /* class_delete */
    4547                 :            :     NULL,                       /* class_get_stats */
    4548                 :            :     NULL                        /* class_dump_stats */
    4549                 :            : };
    4550                 :            : 
    4551                 :            : /* "linux-other" traffic control class.
    4552                 :            :  *
    4553                 :            :  * */
    4554                 :            : 
    4555                 :            : static int
    4556                 :          0 : other_tc_load(struct netdev *netdev_, struct ofpbuf *nlmsg OVS_UNUSED)
    4557                 :            : {
    4558                 :          0 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    4559                 :            :     static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_other);
    4560                 :            : 
    4561                 :            :     /* Nothing but a tc class implementation is allowed to write to a tc.  This
    4562                 :            :      * class never does that, so we can legitimately use a const tc object. */
    4563                 :          0 :     netdev->tc = CONST_CAST(struct tc *, &tc);
    4564                 :          0 :     return 0;
    4565                 :            : }
    4566                 :            : 
    4567                 :            : static const struct tc_ops tc_ops_other = {
    4568                 :            :     NULL,                       /* linux_name */
    4569                 :            :     "linux-other",              /* ovs_name */
    4570                 :            :     0,                          /* n_queues */
    4571                 :            :     NULL,                       /* tc_install */
    4572                 :            :     other_tc_load,
    4573                 :            :     NULL,                       /* tc_destroy */
    4574                 :            :     NULL,                       /* qdisc_get */
    4575                 :            :     NULL,                       /* qdisc_set */
    4576                 :            :     NULL,                       /* class_get */
    4577                 :            :     NULL,                       /* class_set */
    4578                 :            :     NULL,                       /* class_delete */
    4579                 :            :     NULL,                       /* class_get_stats */
    4580                 :            :     NULL                        /* class_dump_stats */
    4581                 :            : };
    4582                 :            : 
    4583                 :            : /* Traffic control. */
    4584                 :            : 
    4585                 :            : /* Number of kernel "tc" ticks per second. */
    4586                 :            : static double ticks_per_s;
    4587                 :            : 
    4588                 :            : /* Number of kernel "jiffies" per second.  This is used for the purpose of
    4589                 :            :  * computing buffer sizes.  Generally kernel qdiscs need to be able to buffer
    4590                 :            :  * one jiffy's worth of data.
    4591                 :            :  *
    4592                 :            :  * There are two possibilities here:
    4593                 :            :  *
    4594                 :            :  *    - 'buffer_hz' is the kernel's real timer tick rate, a small number in the
    4595                 :            :  *      approximate range of 100 to 1024.  That means that we really need to
    4596                 :            :  *      make sure that the qdisc can buffer that much data.
    4597                 :            :  *
    4598                 :            :  *    - 'buffer_hz' is an absurdly large number.  That means that the kernel
    4599                 :            :  *      has finely granular timers and there's no need to fudge additional room
    4600                 :            :  *      for buffers.  (There's no extra effort needed to implement that: the
    4601                 :            :  *      large 'buffer_hz' is used as a divisor, so practically any number will
    4602                 :            :  *      come out as 0 in the division.  Small integer results in the case of
    4603                 :            :  *      really high dividends won't have any real effect anyhow.)
    4604                 :            :  */
    4605                 :            : static unsigned int buffer_hz;
    4606                 :            : 
    4607                 :            : /* Returns tc handle 'major':'minor'. */
    4608                 :            : static unsigned int
    4609                 :       1499 : tc_make_handle(unsigned int major, unsigned int minor)
    4610                 :            : {
    4611                 :       1499 :     return TC_H_MAKE(major << 16, minor);
    4612                 :            : }
    4613                 :            : 
    4614                 :            : /* Returns the major number from 'handle'. */
    4615                 :            : static unsigned int
    4616                 :          0 : tc_get_major(unsigned int handle)
    4617                 :            : {
    4618                 :          0 :     return TC_H_MAJ(handle) >> 16;
    4619                 :            : }
    4620                 :            : 
    4621                 :            : /* Returns the minor number from 'handle'. */
    4622                 :            : static unsigned int
    4623                 :          0 : tc_get_minor(unsigned int handle)
    4624                 :            : {
    4625                 :          0 :     return TC_H_MIN(handle);
    4626                 :            : }
    4627                 :            : 
    4628                 :            : static struct tcmsg *
    4629                 :       1501 : tc_make_request(const struct netdev *netdev, int type, unsigned int flags,
    4630                 :            :                 struct ofpbuf *request)
    4631                 :            : {
    4632                 :            :     struct tcmsg *tcmsg;
    4633                 :            :     int ifindex;
    4634                 :            :     int error;
    4635                 :            : 
    4636                 :       1501 :     error = get_ifindex(netdev, &ifindex);
    4637         [ +  + ]:       1501 :     if (error) {
    4638                 :          2 :         return NULL;
    4639                 :            :     }
    4640                 :            : 
    4641                 :       1499 :     ofpbuf_init(request, 512);
    4642                 :       1499 :     nl_msg_put_nlmsghdr(request, sizeof *tcmsg, type, NLM_F_REQUEST | flags);
    4643                 :       1499 :     tcmsg = ofpbuf_put_zeros(request, sizeof *tcmsg);
    4644                 :       1499 :     tcmsg->tcm_family = AF_UNSPEC;
    4645                 :       1499 :     tcmsg->tcm_ifindex = ifindex;
    4646                 :            :     /* Caller should fill in tcmsg->tcm_handle. */
    4647                 :            :     /* Caller should fill in tcmsg->tcm_parent. */
    4648                 :            : 
    4649                 :       1501 :     return tcmsg;
    4650                 :            : }
    4651                 :            : 
    4652                 :            : static int
    4653                 :       1499 : tc_transact(struct ofpbuf *request, struct ofpbuf **replyp)
    4654                 :            : {
    4655                 :       1499 :     int error = nl_transact(NETLINK_ROUTE, request, replyp);
    4656                 :       1499 :     ofpbuf_uninit(request);
    4657                 :       1499 :     return error;
    4658                 :            : }
    4659                 :            : 
    4660                 :            : /* Adds or deletes a root ingress qdisc on 'netdev'.  We use this for
    4661                 :            :  * policing configuration.
    4662                 :            :  *
    4663                 :            :  * This function is equivalent to running the following when 'add' is true:
    4664                 :            :  *     /sbin/tc qdisc add dev <devname> handle ffff: ingress
    4665                 :            :  *
    4666                 :            :  * This function is equivalent to running the following when 'add' is false:
    4667                 :            :  *     /sbin/tc qdisc del dev <devname> handle ffff: ingress
    4668                 :            :  *
    4669                 :            :  * The configuration and stats may be seen with the following command:
    4670                 :            :  *     /sbin/tc -s qdisc show dev <devname>
    4671                 :            :  *
    4672                 :            :  * Returns 0 if successful, otherwise a positive errno value.
    4673                 :            :  */
    4674                 :            : static int
    4675                 :        924 : tc_add_del_ingress_qdisc(struct netdev *netdev, bool add)
    4676                 :            : {
    4677                 :            :     struct ofpbuf request;
    4678                 :            :     struct tcmsg *tcmsg;
    4679                 :            :     int error;
    4680         [ -  + ]:        924 :     int type = add ? RTM_NEWQDISC : RTM_DELQDISC;
    4681         [ -  + ]:        924 :     int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0;
    4682                 :            : 
    4683                 :        924 :     tcmsg = tc_make_request(netdev, type, flags, &request);
    4684         [ +  + ]:        924 :     if (!tcmsg) {
    4685                 :          2 :         return ENODEV;
    4686                 :            :     }
    4687                 :        922 :     tcmsg->tcm_handle = tc_make_handle(0xffff, 0);
    4688                 :        922 :     tcmsg->tcm_parent = TC_H_INGRESS;
    4689                 :        922 :     nl_msg_put_string(&request, TCA_KIND, "ingress");
    4690                 :        922 :     nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0);
    4691                 :            : 
    4692                 :        922 :     error = tc_transact(&request, NULL);
    4693         [ +  - ]:        922 :     if (error) {
    4694                 :            :         /* If we're deleting the qdisc, don't worry about some of the
    4695                 :            :          * error conditions. */
    4696 [ +  - ][ -  + ]:        922 :         if (!add && (error == ENOENT || error == EINVAL)) {
                 [ #  # ]
    4697                 :        922 :             return 0;
    4698                 :            :         }
    4699                 :          0 :         return error;
    4700                 :            :     }
    4701                 :            : 
    4702                 :        924 :     return 0;
    4703                 :            : }
    4704                 :            : 
    4705                 :            : /* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
    4706                 :            :  * of 'kbits_burst'.
    4707                 :            :  *
    4708                 :            :  * This function is equivalent to running:
    4709                 :            :  *     /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
    4710                 :            :  *              basic police rate <kbits_rate>kbit burst <kbits_burst>k
    4711                 :            :  *              mtu 65535 drop
    4712                 :            :  *
    4713                 :            :  * The configuration and stats may be seen with the following command:
    4714                 :            :  *     /sbin/tc -s filter show dev <devname> parent ffff:
    4715                 :            :  *
    4716                 :            :  * Returns 0 if successful, otherwise a positive errno value.
    4717                 :            :  */
    4718                 :            : static int
    4719                 :          0 : tc_add_policer(struct netdev *netdev,
    4720                 :            :                uint32_t kbits_rate, uint32_t kbits_burst)
    4721                 :            : {
    4722                 :            :     struct tc_police tc_police;
    4723                 :            :     struct ofpbuf request;
    4724                 :            :     struct tcmsg *tcmsg;
    4725                 :            :     size_t basic_offset;
    4726                 :            :     size_t police_offset;
    4727                 :            :     int error;
    4728                 :          0 :     int mtu = 65535;
    4729                 :            : 
    4730                 :          0 :     memset(&tc_police, 0, sizeof tc_police);
    4731                 :          0 :     tc_police.action = TC_POLICE_SHOT;
    4732                 :          0 :     tc_police.mtu = mtu;
    4733                 :          0 :     tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu);
    4734                 :            : 
    4735                 :            :     /* The following appears wrong in one way: In networking a kilobit is
    4736                 :            :      * usually 1000 bits but this uses 1024 bits.
    4737                 :            :      *
    4738                 :            :      * However if you "fix" those problems then "tc filter show ..." shows
    4739                 :            :      * "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit ==
    4740                 :            :      * 1,000,000 bits, whereas this actually ends up doing the right thing from
    4741                 :            :      * tc's point of view.  Whatever. */
    4742                 :          0 :     tc_police.burst = tc_bytes_to_ticks(
    4743                 :          0 :         tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024 / 8);
    4744                 :            : 
    4745                 :          0 :     tcmsg = tc_make_request(netdev, RTM_NEWTFILTER,
    4746                 :            :                             NLM_F_EXCL | NLM_F_CREATE, &request);
    4747         [ #  # ]:          0 :     if (!tcmsg) {
    4748                 :          0 :         return ENODEV;
    4749                 :            :     }
    4750                 :          0 :     tcmsg->tcm_parent = tc_make_handle(0xffff, 0);
    4751                 :          0 :     tcmsg->tcm_info = tc_make_handle(49,
    4752                 :          0 :                                      (OVS_FORCE uint16_t) htons(ETH_P_ALL));
    4753                 :            : 
    4754                 :          0 :     nl_msg_put_string(&request, TCA_KIND, "basic");
    4755                 :          0 :     basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
    4756                 :          0 :     police_offset = nl_msg_start_nested(&request, TCA_BASIC_POLICE);
    4757                 :          0 :     nl_msg_put_unspec(&request, TCA_POLICE_TBF, &tc_police, sizeof tc_police);
    4758                 :          0 :     tc_put_rtab(&request, TCA_POLICE_RATE, &tc_police.rate);
    4759                 :          0 :     nl_msg_end_nested(&request, police_offset);
    4760                 :          0 :     nl_msg_end_nested(&request, basic_offset);
    4761                 :            : 
    4762                 :          0 :     error = tc_transact(&request, NULL);
    4763         [ #  # ]:          0 :     if (error) {
    4764                 :          0 :         return error;
    4765                 :            :     }
    4766                 :            : 
    4767                 :          0 :     return 0;
    4768                 :            : }
    4769                 :            : 
    4770                 :            : static void
    4771                 :          0 : read_psched(void)
    4772                 :            : {
    4773                 :            :     /* The values in psched are not individually very meaningful, but they are
    4774                 :            :      * important.  The tables below show some values seen in the wild.
    4775                 :            :      *
    4776                 :            :      * Some notes:
    4777                 :            :      *
    4778                 :            :      *   - "c" has always been a constant 1000000 since at least Linux 2.4.14.
    4779                 :            :      *     (Before that, there are hints that it was 1000000000.)
    4780                 :            :      *
    4781                 :            :      *   - "d" can be unrealistically large, see the comment on 'buffer_hz'
    4782                 :            :      *     above.
    4783                 :            :      *
    4784                 :            :      *                        /proc/net/psched
    4785                 :            :      *     -----------------------------------
    4786                 :            :      * [1] 000c8000 000f4240 000f4240 00000064
    4787                 :            :      * [2] 000003e8 00000400 000f4240 3b9aca00
    4788                 :            :      * [3] 000003e8 00000400 000f4240 3b9aca00
    4789                 :            :      * [4] 000003e8 00000400 000f4240 00000064
    4790                 :            :      * [5] 000003e8 00000040 000f4240 3b9aca00
    4791                 :            :      * [6] 000003e8 00000040 000f4240 000000f9
    4792                 :            :      *
    4793                 :            :      *           a         b          c             d ticks_per_s     buffer_hz
    4794                 :            :      *     ------- --------- ---------- ------------- ----------- -------------
    4795                 :            :      * [1] 819,200 1,000,000  1,000,000           100     819,200           100
    4796                 :            :      * [2]   1,000     1,024  1,000,000 1,000,000,000     976,562 1,000,000,000
    4797                 :            :      * [3]   1,000     1,024  1,000,000 1,000,000,000     976,562 1,000,000,000
    4798                 :            :      * [4]   1,000     1,024  1,000,000           100     976,562           100
    4799                 :            :      * [5]   1,000        64  1,000,000 1,000,000,000  15,625,000 1,000,000,000
    4800                 :            :      * [6]   1,000        64  1,000,000           249  15,625,000           249
    4801                 :            :      *
    4802                 :            :      * [1] 2.6.18-128.1.6.el5.xs5.5.0.505.1024xen from XenServer 5.5.0-24648p
    4803                 :            :      * [2] 2.6.26-1-686-bigmem from Debian lenny
    4804                 :            :      * [3] 2.6.26-2-sparc64 from Debian lenny
    4805                 :            :      * [4] 2.6.27.42-0.1.1.xs5.6.810.44.111163xen from XenServer 5.6.810-31078p
    4806                 :            :      * [5] 2.6.32.21.22 (approx.) from Ubuntu 10.04 on VMware Fusion
    4807                 :            :      * [6] 2.6.34 from kernel.org on KVM
    4808                 :            :      */
    4809                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
    4810                 :            :     static const char fn[] = "/proc/net/psched";
    4811                 :            :     unsigned int a, b, c, d;
    4812                 :            :     FILE *stream;
    4813                 :            : 
    4814         [ #  # ]:          0 :     if (!ovsthread_once_start(&once)) {
    4815                 :          0 :         return;
    4816                 :            :     }
    4817                 :            : 
    4818                 :          0 :     ticks_per_s = 1.0;
    4819                 :          0 :     buffer_hz = 100;
    4820                 :            : 
    4821                 :          0 :     stream = fopen(fn, "r");
    4822         [ #  # ]:          0 :     if (!stream) {
    4823         [ #  # ]:          0 :         VLOG_WARN("%s: open failed: %s", fn, ovs_strerror(errno));
    4824                 :          0 :         goto exit;
    4825                 :            :     }
    4826                 :            : 
    4827         [ #  # ]:          0 :     if (fscanf(stream, "%x %x %x %x", &a, &b, &c, &d) != 4) {
    4828         [ #  # ]:          0 :         VLOG_WARN("%s: read failed", fn);
    4829                 :          0 :         fclose(stream);
    4830                 :          0 :         goto exit;
    4831                 :            :     }
    4832         [ #  # ]:          0 :     VLOG_DBG("%s: psched parameters are: %u %u %u %u", fn, a, b, c, d);
    4833                 :          0 :     fclose(stream);
    4834                 :            : 
    4835 [ #  # ][ #  # ]:          0 :     if (!a || !c) {
    4836         [ #  # ]:          0 :         VLOG_WARN("%s: invalid scheduler parameters", fn);
    4837                 :          0 :         goto exit;
    4838                 :            :     }
    4839                 :            : 
    4840                 :          0 :     ticks_per_s = (double) a * c / b;
    4841         [ #  # ]:          0 :     if (c == 1000000) {
    4842                 :          0 :         buffer_hz = d;
    4843                 :            :     } else {
    4844         [ #  # ]:          0 :         VLOG_WARN("%s: unexpected psched parameters: %u %u %u %u",
    4845                 :            :                   fn, a, b, c, d);
    4846                 :            :     }
    4847         [ #  # ]:          0 :     VLOG_DBG("%s: ticks_per_s=%f buffer_hz=%u", fn, ticks_per_s, buffer_hz);
    4848                 :            : 
    4849                 :            : exit:
    4850                 :          0 :     ovsthread_once_done(&once);
    4851                 :            : }
    4852                 :            : 
    4853                 :            : /* Returns the number of bytes that can be transmitted in 'ticks' ticks at a
    4854                 :            :  * rate of 'rate' bytes per second. */
    4855                 :            : static unsigned int
    4856                 :          0 : tc_ticks_to_bytes(unsigned int rate, unsigned int ticks)
    4857                 :            : {
    4858                 :          0 :     read_psched();
    4859                 :          0 :     return (rate * ticks) / ticks_per_s;
    4860                 :            : }
    4861                 :            : 
    4862                 :            : /* Returns the number of ticks that it would take to transmit 'size' bytes at a
    4863                 :            :  * rate of 'rate' bytes per second. */
    4864                 :            : static unsigned int
    4865                 :          0 : tc_bytes_to_ticks(unsigned int rate, unsigned int size)
    4866                 :            : {
    4867                 :          0 :     read_psched();
    4868         [ #  # ]:          0 :     return rate ? ((unsigned long long int) ticks_per_s * size) / rate : 0;
    4869                 :            : }
    4870                 :            : 
    4871                 :            : /* Returns the number of bytes that need to be reserved for qdisc buffering at
    4872                 :            :  * a transmission rate of 'rate' bytes per second. */
    4873                 :            : static unsigned int
    4874                 :          0 : tc_buffer_per_jiffy(unsigned int rate)
    4875                 :            : {
    4876                 :          0 :     read_psched();
    4877                 :          0 :     return rate / buffer_hz;
    4878                 :            : }
    4879                 :            : 
    4880                 :            : /* Given Netlink 'msg' that describes a qdisc, extracts the name of the qdisc,
    4881                 :            :  * e.g. "htb", into '*kind' (if it is nonnull).  If 'options' is nonnull,
    4882                 :            :  * extracts 'msg''s TCA_OPTIONS attributes into '*options' if it is present or
    4883                 :            :  * stores NULL into it if it is absent.
    4884                 :            :  *
    4885                 :            :  * '*kind' and '*options' point into 'msg', so they are owned by whoever owns
    4886                 :            :  * 'msg'.
    4887                 :            :  *
    4888                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
    4889                 :            : static int
    4890                 :        466 : tc_parse_qdisc(const struct ofpbuf *msg, const char **kind,
    4891                 :            :                struct nlattr **options)
    4892                 :            : {
    4893                 :            :     static const struct nl_policy tca_policy[] = {
    4894                 :            :         [TCA_KIND] = { .type = NL_A_STRING, .optional = false },
    4895                 :            :         [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = true },
    4896                 :            :     };
    4897                 :            :     struct nlattr *ta[ARRAY_SIZE(tca_policy)];
    4898                 :            : 
    4899         [ -  + ]:        466 :     if (!nl_policy_parse(msg, NLMSG_HDRLEN + sizeof(struct tcmsg),
    4900                 :            :                          tca_policy, ta, ARRAY_SIZE(ta))) {
    4901         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse qdisc message");
    4902                 :          0 :         goto error;
    4903                 :            :     }
    4904                 :            : 
    4905         [ +  - ]:        466 :     if (kind) {
    4906                 :        466 :         *kind = nl_attr_get_string(ta[TCA_KIND]);
    4907                 :            :     }
    4908                 :            : 
    4909         [ +  + ]:        466 :     if (options) {
    4910                 :        233 :         *options = ta[TCA_OPTIONS];
    4911                 :            :     }
    4912                 :            : 
    4913                 :        466 :     return 0;
    4914                 :            : 
    4915                 :            : error:
    4916         [ #  # ]:          0 :     if (kind) {
    4917                 :          0 :         *kind = NULL;
    4918                 :            :     }
    4919         [ #  # ]:          0 :     if (options) {
    4920                 :          0 :         *options = NULL;
    4921                 :            :     }
    4922                 :        466 :     return EPROTO;
    4923                 :            : }
    4924                 :            : 
    4925                 :            : /* Given Netlink 'msg' that describes a class, extracts the queue ID (e.g. the
    4926                 :            :  * minor number of its class ID) into '*queue_id', its TCA_OPTIONS attribute
    4927                 :            :  * into '*options', and its queue statistics into '*stats'.  Any of the output
    4928                 :            :  * arguments may be null.
    4929                 :            :  *
    4930                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
    4931                 :            : static int
    4932                 :          0 : tc_parse_class(const struct ofpbuf *msg, unsigned int *handlep,
    4933                 :            :                struct nlattr **options, struct netdev_queue_stats *stats)
    4934                 :            : {
    4935                 :            :     static const struct nl_policy tca_policy[] = {
    4936                 :            :         [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false },
    4937                 :            :         [TCA_STATS2] = { .type = NL_A_NESTED, .optional = false },
    4938                 :            :     };
    4939                 :            :     struct nlattr *ta[ARRAY_SIZE(tca_policy)];
    4940                 :            : 
    4941         [ #  # ]:          0 :     if (!nl_policy_parse(msg, NLMSG_HDRLEN + sizeof(struct tcmsg),
    4942                 :            :                          tca_policy, ta, ARRAY_SIZE(ta))) {
    4943         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse class message");
    4944                 :          0 :         goto error;
    4945                 :            :     }
    4946                 :            : 
    4947         [ #  # ]:          0 :     if (handlep) {
    4948                 :          0 :         struct tcmsg *tc = ofpbuf_at_assert(msg, NLMSG_HDRLEN, sizeof *tc);
    4949                 :          0 :         *handlep = tc->tcm_handle;
    4950                 :            :     }
    4951                 :            : 
    4952         [ #  # ]:          0 :     if (options) {
    4953                 :          0 :         *options = ta[TCA_OPTIONS];
    4954                 :            :     }
    4955                 :            : 
    4956         [ #  # ]:          0 :     if (stats) {
    4957                 :            :         const struct gnet_stats_queue *gsq;
    4958                 :            :         struct gnet_stats_basic gsb;
    4959                 :            : 
    4960                 :            :         static const struct nl_policy stats_policy[] = {
    4961                 :            :             [TCA_STATS_BASIC] = { .type = NL_A_UNSPEC, .optional = false,
    4962                 :            :                                   .min_len = sizeof gsb },
    4963                 :            :             [TCA_STATS_QUEUE] = { .type = NL_A_UNSPEC, .optional = false,
    4964                 :            :                                   .min_len = sizeof *gsq },
    4965                 :            :         };
    4966                 :            :         struct nlattr *sa[ARRAY_SIZE(stats_policy)];
    4967                 :            : 
    4968         [ #  # ]:          0 :         if (!nl_parse_nested(ta[TCA_STATS2], stats_policy,
    4969                 :            :                              sa, ARRAY_SIZE(sa))) {
    4970         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "failed to parse class stats");
    4971                 :          0 :             goto error;
    4972                 :            :         }
    4973                 :            : 
    4974                 :            :         /* Alignment issues screw up the length of struct gnet_stats_basic on
    4975                 :            :          * some arch/bitsize combinations.  Newer versions of Linux have a
    4976                 :            :          * struct gnet_stats_basic_packed, but we can't depend on that.  The
    4977                 :            :          * easiest thing to do is just to make a copy. */
    4978                 :          0 :         memset(&gsb, 0, sizeof gsb);
    4979         [ #  # ]:          0 :         memcpy(&gsb, nl_attr_get(sa[TCA_STATS_BASIC]),
    4980                 :          0 :                MIN(nl_attr_get_size(sa[TCA_STATS_BASIC]), sizeof gsb));
    4981                 :          0 :         stats->tx_bytes = gsb.bytes;
    4982                 :          0 :         stats->tx_packets = gsb.packets;
    4983                 :            : 
    4984                 :          0 :         gsq = nl_attr_get(sa[TCA_STATS_QUEUE]);
    4985                 :          0 :         stats->tx_errors = gsq->drops;
    4986                 :            :     }
    4987                 :            : 
    4988                 :          0 :     return 0;
    4989                 :            : 
    4990                 :            : error:
    4991         [ #  # ]:          0 :     if (options) {
    4992                 :          0 :         *options = NULL;
    4993                 :            :     }
    4994         [ #  # ]:          0 :     if (stats) {
    4995                 :          0 :         memset(stats, 0, sizeof *stats);
    4996                 :            :     }
    4997                 :          0 :     return EPROTO;
    4998                 :            : }
    4999                 :            : 
    5000                 :            : /* Queries the kernel for class with identifier 'handle' and parent 'parent'
    5001                 :            :  * on 'netdev'. */
    5002                 :            : static int
    5003                 :          0 : tc_query_class(const struct netdev *netdev,
    5004                 :            :                unsigned int handle, unsigned int parent,
    5005                 :            :                struct ofpbuf **replyp)
    5006                 :            : {
    5007                 :            :     struct ofpbuf request;
    5008                 :            :     struct tcmsg *tcmsg;
    5009                 :            :     int error;
    5010                 :            : 
    5011                 :          0 :     tcmsg = tc_make_request(netdev, RTM_GETTCLASS, NLM_F_ECHO, &request);
    5012         [ #  # ]:          0 :     if (!tcmsg) {
    5013                 :          0 :         return ENODEV;
    5014                 :            :     }
    5015                 :          0 :     tcmsg->tcm_handle = handle;
    5016                 :          0 :     tcmsg->tcm_parent = parent;
    5017                 :            : 
    5018                 :          0 :     error = tc_transact(&request, replyp);
    5019         [ #  # ]:          0 :     if (error) {
    5020         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "query %s class %u:%u (parent %u:%u) failed (%s)",
    5021                 :            :                      netdev_get_name(netdev),
    5022                 :            :                      tc_get_major(handle), tc_get_minor(handle),
    5023                 :            :                      tc_get_major(parent), tc_get_minor(parent),
    5024                 :            :                      ovs_strerror(error));
    5025                 :            :     }
    5026                 :          0 :     return error;
    5027                 :            : }
    5028                 :            : 
    5029                 :            : /* Equivalent to "tc class del dev <name> handle <handle>". */
    5030                 :            : static int
    5031                 :          0 : tc_delete_class(const struct netdev *netdev, unsigned int handle)
    5032                 :            : {
    5033                 :            :     struct ofpbuf request;
    5034                 :            :     struct tcmsg *tcmsg;
    5035                 :            :     int error;
    5036                 :            : 
    5037                 :          0 :     tcmsg = tc_make_request(netdev, RTM_DELTCLASS, 0, &request);
    5038         [ #  # ]:          0 :     if (!tcmsg) {
    5039                 :          0 :         return ENODEV;
    5040                 :            :     }
    5041                 :          0 :     tcmsg->tcm_handle = handle;
    5042                 :          0 :     tcmsg->tcm_parent = 0;
    5043                 :            : 
    5044                 :          0 :     error = tc_transact(&request, NULL);
    5045         [ #  # ]:          0 :     if (error) {
    5046         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "delete %s class %u:%u failed (%s)",
    5047                 :            :                      netdev_get_name(netdev),
    5048                 :            :                      tc_get_major(handle), tc_get_minor(handle),
    5049                 :            :                      ovs_strerror(error));
    5050                 :            :     }
    5051                 :          0 :     return error;
    5052                 :            : }
    5053                 :            : 
    5054                 :            : /* Equivalent to "tc qdisc del dev <name> root". */
    5055                 :            : static int
    5056                 :        233 : tc_del_qdisc(struct netdev *netdev_)
    5057                 :            : {
    5058                 :        233 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    5059                 :            :     struct ofpbuf request;
    5060                 :            :     struct tcmsg *tcmsg;
    5061                 :            :     int error;
    5062                 :            : 
    5063                 :        233 :     tcmsg = tc_make_request(netdev_, RTM_DELQDISC, 0, &request);
    5064         [ -  + ]:        233 :     if (!tcmsg) {
    5065                 :          0 :         return ENODEV;
    5066                 :            :     }
    5067                 :        233 :     tcmsg->tcm_handle = tc_make_handle(1, 0);
    5068                 :        233 :     tcmsg->tcm_parent = TC_H_ROOT;
    5069                 :            : 
    5070                 :        233 :     error = tc_transact(&request, NULL);
    5071         [ +  - ]:        233 :     if (error == EINVAL) {
    5072                 :            :         /* EINVAL probably means that the default qdisc was in use, in which
    5073                 :            :          * case we've accomplished our purpose. */
    5074                 :        233 :         error = 0;
    5075                 :            :     }
    5076 [ +  - ][ +  - ]:        233 :     if (!error && netdev->tc) {
    5077         [ +  - ]:        233 :         if (netdev->tc->ops->tc_destroy) {
    5078                 :        233 :             netdev->tc->ops->tc_destroy(netdev->tc);
    5079                 :            :         }
    5080                 :        233 :         netdev->tc = NULL;
    5081                 :            :     }
    5082                 :        233 :     return error;
    5083                 :            : }
    5084                 :            : 
    5085                 :            : static bool
    5086                 :        688 : getqdisc_is_safe(void)
    5087                 :            : {
    5088                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
    5089                 :            :     static bool safe = false;
    5090                 :            : 
    5091         [ +  + ]:        688 :     if (ovsthread_once_start(&once)) {
    5092                 :            :         struct utsname utsname;
    5093                 :            :         int major, minor;
    5094                 :            : 
    5095         [ -  + ]:         94 :         if (uname(&utsname) == -1) {
    5096         [ #  # ]:          0 :             VLOG_WARN("uname failed (%s)", ovs_strerror(errno));
    5097         [ -  + ]:         94 :         } else if (!ovs_scan(utsname.release, "%d.%d", &major, &minor)) {
    5098         [ #  # ]:          0 :             VLOG_WARN("uname reported bad OS release (%s)", utsname.release);
    5099 [ +  - ][ -  + ]:         94 :         } else if (major < 2 || (major == 2 && minor < 35)) {
                 [ #  # ]
    5100         [ #  # ]:          0 :             VLOG_INFO("disabling unsafe RTM_GETQDISC in Linux kernel %s",
    5101                 :            :                       utsname.release);
    5102                 :            :         } else {
    5103                 :         94 :             safe = true;
    5104                 :            :         }
    5105                 :         94 :         ovsthread_once_done(&once);
    5106                 :            :     }
    5107                 :        688 :     return safe;
    5108                 :            : }
    5109                 :            : 
    5110                 :            : /* If 'netdev''s qdisc type and parameters are not yet known, queries the
    5111                 :            :  * kernel to determine what they are.  Returns 0 if successful, otherwise a
    5112                 :            :  * positive errno value. */
    5113                 :            : static int
    5114                 :       4175 : tc_query_qdisc(const struct netdev *netdev_)
    5115                 :            : {
    5116                 :       4175 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    5117                 :            :     struct ofpbuf request, *qdisc;
    5118                 :            :     const struct tc_ops *ops;
    5119                 :            :     struct tcmsg *tcmsg;
    5120                 :            :     int load_error;
    5121                 :            :     int error;
    5122                 :            : 
    5123         [ +  + ]:       4175 :     if (netdev->tc) {
    5124                 :       3831 :         return 0;
    5125                 :            :     }
    5126                 :            : 
    5127                 :            :     /* This RTM_GETQDISC is crafted to avoid OOPSing kernels that do not have
    5128                 :            :      * commit 53b0f08 "net_sched: Fix qdisc_notify()", which is anything before
    5129                 :            :      * 2.6.35 without that fix backported to it.
    5130                 :            :      *
    5131                 :            :      * To avoid the OOPS, we must not make a request that would attempt to dump
    5132                 :            :      * a "built-in" qdisc, that is, the default pfifo_fast qdisc or one of a
    5133                 :            :      * few others.  There are a few ways that I can see to do this, but most of
    5134                 :            :      * them seem to be racy (and if you lose the race the kernel OOPSes).  The
    5135                 :            :      * technique chosen here is to assume that any non-default qdisc that we
    5136                 :            :      * create will have a class with handle 1:0.  The built-in qdiscs only have
    5137                 :            :      * a class with handle 0:0.
    5138                 :            :      *
    5139                 :            :      * On Linux 2.6.35+ we use the straightforward method because it allows us
    5140                 :            :      * to handle non-builtin qdiscs without handle 1:0 (e.g. codel).  However,
    5141                 :            :      * in such a case we get no response at all from the kernel (!) if a
    5142                 :            :      * builtin qdisc is in use (which is later caught by "!error &&
    5143                 :            :      * !qdisc->size"). */
    5144                 :        344 :     tcmsg = tc_make_request(netdev_, RTM_GETQDISC, NLM_F_ECHO, &request);
    5145         [ -  + ]:        344 :     if (!tcmsg) {
    5146                 :          0 :         return ENODEV;
    5147                 :            :     }
    5148         [ +  - ]:        344 :     tcmsg->tcm_handle = tc_make_handle(getqdisc_is_safe() ? 0 : 1, 0);
    5149         [ +  - ]:        344 :     tcmsg->tcm_parent = getqdisc_is_safe() ? TC_H_ROOT : 0;
    5150                 :            : 
    5151                 :            :     /* Figure out what tc class to instantiate. */
    5152                 :        344 :     error = tc_transact(&request, &qdisc);
    5153 [ +  - ][ +  + ]:        577 :     if (!error && qdisc->size) {
    5154                 :            :         const char *kind;
    5155                 :            : 
    5156                 :        233 :         error = tc_parse_qdisc(qdisc, &kind, NULL);
    5157         [ -  + ]:        233 :         if (error) {
    5158                 :          0 :             ops = &tc_ops_other;
    5159                 :            :         } else {
    5160                 :        233 :             ops = tc_lookup_linux_name(kind);
    5161         [ -  + ]:        233 :             if (!ops) {
    5162                 :            :                 static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 1);
    5163         [ #  # ]:          0 :                 VLOG_DBG_RL(&rl2, "unknown qdisc \"%s\"", kind);
    5164                 :            : 
    5165                 :          0 :                 ops = &tc_ops_other;
    5166                 :            :             }
    5167                 :            :         }
    5168 [ +  - ][ -  + ]:        111 :     } else if ((!error && !qdisc->size) || error == ENOENT) {
                 [ #  # ]
    5169                 :            :         /* Either it's a built-in qdisc, or (on Linux pre-2.6.35) it's a qdisc
    5170                 :            :          * set up by some other entity that doesn't have a handle 1:0.  We will
    5171                 :            :          * assume that it's the system default qdisc. */
    5172                 :        111 :         ops = &tc_ops_default;
    5173                 :        111 :         error = 0;
    5174                 :            :     } else {
    5175                 :            :         /* Who knows?  Maybe the device got deleted. */
    5176         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "query %s qdisc failed (%s)",
    5177                 :            :                      netdev_get_name(netdev_), ovs_strerror(error));
    5178                 :          0 :         ops = &tc_ops_other;
    5179                 :            :     }
    5180                 :            : 
    5181                 :            :     /* Instantiate it. */
    5182                 :        344 :     load_error = ops->tc_load(CONST_CAST(struct netdev *, netdev_), qdisc);
    5183         [ -  + ]:        344 :     ovs_assert((load_error == 0) == (netdev->tc != NULL));
    5184                 :        344 :     ofpbuf_delete(qdisc);
    5185                 :            : 
    5186         [ -  + ]:       4175 :     return error ? error : load_error;
    5187                 :            : }
    5188                 :            : 
    5189                 :            : /* Linux traffic control uses tables with 256 entries ("rtab" tables) to
    5190                 :            :    approximate the time to transmit packets of various lengths.  For an MTU of
    5191                 :            :    256 or less, each entry is exact; for an MTU of 257 through 512, each entry
    5192                 :            :    represents two possible packet lengths; for a MTU of 513 through 1024, four
    5193                 :            :    possible lengths; and so on.
    5194                 :            : 
    5195                 :            :    Returns, for the specified 'mtu', the number of bits that packet lengths
    5196                 :            :    need to be shifted right to fit within such a 256-entry table. */
    5197                 :            : static int
    5198                 :          0 : tc_calc_cell_log(unsigned int mtu)
    5199                 :            : {
    5200                 :            :     int cell_log;
    5201                 :            : 
    5202         [ #  # ]:          0 :     if (!mtu) {
    5203                 :          0 :         mtu = ETH_PAYLOAD_MAX;
    5204                 :            :     }
    5205                 :          0 :     mtu += ETH_HEADER_LEN + VLAN_HEADER_LEN;
    5206                 :            : 
    5207         [ #  # ]:          0 :     for (cell_log = 0; mtu >= 256; cell_log++) {
    5208                 :          0 :         mtu >>= 1;
    5209                 :            :     }
    5210                 :            : 
    5211                 :          0 :     return cell_log;
    5212                 :            : }
    5213                 :            : 
    5214                 :            : /* Initializes 'rate' properly for a rate of 'Bps' bytes per second with an MTU
    5215                 :            :  * of 'mtu'. */
    5216                 :            : static void
    5217                 :          0 : tc_fill_rate(struct tc_ratespec *rate, uint64_t Bps, int mtu)
    5218                 :            : {
    5219                 :          0 :     memset(rate, 0, sizeof *rate);
    5220                 :          0 :     rate->cell_log = tc_calc_cell_log(mtu);
    5221                 :            :     /* rate->overhead = 0; */           /* New in 2.6.24, not yet in some */
    5222                 :            :     /* rate->cell_align = 0; */         /* distro headers. */
    5223                 :          0 :     rate->mpu = ETH_TOTAL_MIN;
    5224                 :          0 :     rate->rate = Bps;
    5225                 :          0 : }
    5226                 :            : 
    5227                 :            : /* Appends to 'msg' an "rtab" table for the specified 'rate' as a Netlink
    5228                 :            :  * attribute of the specified "type".
    5229                 :            :  *
    5230                 :            :  * See tc_calc_cell_log() above for a description of "rtab"s. */
    5231                 :            : static void
    5232                 :          0 : tc_put_rtab(struct ofpbuf *msg, uint16_t type, const struct tc_ratespec *rate)
    5233                 :            : {
    5234                 :            :     uint32_t *rtab;
    5235                 :            :     unsigned int i;
    5236                 :            : 
    5237                 :          0 :     rtab = nl_msg_put_unspec_uninit(msg, type, TC_RTAB_SIZE);
    5238         [ #  # ]:          0 :     for (i = 0; i < TC_RTAB_SIZE / sizeof *rtab; i++) {
    5239                 :          0 :         unsigned packet_size = (i + 1) << rate->cell_log;
    5240         [ #  # ]:          0 :         if (packet_size < rate->mpu) {
    5241                 :          0 :             packet_size = rate->mpu;
    5242                 :            :         }
    5243                 :          0 :         rtab[i] = tc_bytes_to_ticks(rate->rate, packet_size);
    5244                 :            :     }
    5245                 :          0 : }
    5246                 :            : 
    5247                 :            : /* Calculates the proper value of 'buffer' or 'cbuffer' in HTB options given a
    5248                 :            :  * rate of 'Bps' bytes per second, the specified 'mtu', and a user-requested
    5249                 :            :  * burst size of 'burst_bytes'.  (If no value was requested, a 'burst_bytes' of
    5250                 :            :  * 0 is fine.) */
    5251                 :            : static int
    5252                 :          0 : tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes)
    5253                 :            : {
    5254                 :          0 :     unsigned int min_burst = tc_buffer_per_jiffy(Bps) + mtu;
    5255                 :          0 :     return tc_bytes_to_ticks(Bps, MAX(burst_bytes, min_burst));
    5256                 :            : }
    5257                 :            : 
    5258                 :            : /* Linux-only functions declared in netdev-linux.h  */
    5259                 :            : 
    5260                 :            : /* Modifies the 'flag' bit in ethtool's flags field for 'netdev'.  If
    5261                 :            :  * 'enable' is true, the bit is set.  Otherwise, it is cleared. */
    5262                 :            : int
    5263                 :        151 : netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag,
    5264                 :            :                               const char *flag_name, bool enable)
    5265                 :            : {
    5266                 :        151 :     const char *netdev_name = netdev_get_name(netdev);
    5267                 :            :     struct ethtool_value evalue;
    5268                 :            :     uint32_t new_flags;
    5269                 :            :     int error;
    5270                 :            : 
    5271                 :        151 :     COVERAGE_INC(netdev_get_ethtool);
    5272                 :        151 :     memset(&evalue, 0, sizeof evalue);
    5273                 :        151 :     error = netdev_linux_do_ethtool(netdev_name,
    5274                 :            :                                     (struct ethtool_cmd *)&evalue,
    5275                 :            :                                     ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS");
    5276         [ -  + ]:        151 :     if (error) {
    5277                 :          0 :         return error;
    5278                 :            :     }
    5279                 :            : 
    5280                 :        151 :     COVERAGE_INC(netdev_set_ethtool);
    5281         [ -  + ]:        151 :     new_flags = (evalue.data & ~flag) | (enable ? flag : 0);
    5282         [ +  - ]:        151 :     if (new_flags == evalue.data) {
    5283                 :        151 :         return 0;
    5284                 :            :     }
    5285                 :          0 :     evalue.data = new_flags;
    5286                 :          0 :     error = netdev_linux_do_ethtool(netdev_name,
    5287                 :            :                                     (struct ethtool_cmd *)&evalue,
    5288                 :            :                                     ETHTOOL_SFLAGS, "ETHTOOL_SFLAGS");
    5289         [ #  # ]:          0 :     if (error) {
    5290                 :          0 :         return error;
    5291                 :            :     }
    5292                 :            : 
    5293                 :          0 :     COVERAGE_INC(netdev_get_ethtool);
    5294                 :          0 :     memset(&evalue, 0, sizeof evalue);
    5295                 :          0 :     error = netdev_linux_do_ethtool(netdev_name,
    5296                 :            :                                     (struct ethtool_cmd *)&evalue,
    5297                 :            :                                     ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS");
    5298         [ #  # ]:          0 :     if (error) {
    5299                 :          0 :         return error;
    5300                 :            :     }
    5301                 :            : 
    5302         [ #  # ]:          0 :     if (new_flags != evalue.data) {
    5303 [ #  # ][ #  # ]:          0 :         VLOG_WARN_RL(&rl, "attempt to %s ethtool %s flag on network "
    5304                 :            :                      "device %s failed", enable ? "enable" : "disable",
    5305                 :            :                      flag_name, netdev_name);
    5306                 :          0 :         return EOPNOTSUPP;
    5307                 :            :     }
    5308                 :            : 
    5309                 :        151 :     return 0;
    5310                 :            : }
    5311                 :            : 
    5312                 :            : /* Utility functions. */
    5313                 :            : 
    5314                 :            : /* Copies 'src' into 'dst', performing format conversion in the process. */
    5315                 :            : static void
    5316                 :          0 : netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst,
    5317                 :            :                                   const struct rtnl_link_stats *src)
    5318                 :            : {
    5319                 :          0 :     dst->rx_packets = src->rx_packets;
    5320                 :          0 :     dst->tx_packets = src->tx_packets;
    5321                 :          0 :     dst->rx_bytes = src->rx_bytes;
    5322                 :          0 :     dst->tx_bytes = src->tx_bytes;
    5323                 :          0 :     dst->rx_errors = src->rx_errors;
    5324                 :          0 :     dst->tx_errors = src->tx_errors;
    5325                 :          0 :     dst->rx_dropped = src->rx_dropped;
    5326                 :          0 :     dst->tx_dropped = src->tx_dropped;
    5327                 :          0 :     dst->multicast = src->multicast;
    5328                 :          0 :     dst->collisions = src->collisions;
    5329                 :          0 :     dst->rx_length_errors = src->rx_length_errors;
    5330                 :          0 :     dst->rx_over_errors = src->rx_over_errors;
    5331                 :          0 :     dst->rx_crc_errors = src->rx_crc_errors;
    5332                 :          0 :     dst->rx_frame_errors = src->rx_frame_errors;
    5333                 :          0 :     dst->rx_fifo_errors = src->rx_fifo_errors;
    5334                 :          0 :     dst->rx_missed_errors = src->rx_missed_errors;
    5335                 :          0 :     dst->tx_aborted_errors = src->tx_aborted_errors;
    5336                 :          0 :     dst->tx_carrier_errors = src->tx_carrier_errors;
    5337                 :          0 :     dst->tx_fifo_errors = src->tx_fifo_errors;
    5338                 :          0 :     dst->tx_heartbeat_errors = src->tx_heartbeat_errors;
    5339                 :          0 :     dst->tx_window_errors = src->tx_window_errors;
    5340                 :          0 : }
    5341                 :            : 
    5342                 :            : /* Copies 'src' into 'dst', performing format conversion in the process. */
    5343                 :            : static void
    5344                 :        425 : netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst,
    5345                 :            :                                     const struct rtnl_link_stats64 *src)
    5346                 :            : {
    5347                 :        425 :     dst->rx_packets = src->rx_packets;
    5348                 :        425 :     dst->tx_packets = src->tx_packets;
    5349                 :        425 :     dst->rx_bytes = src->rx_bytes;
    5350                 :        425 :     dst->tx_bytes = src->tx_bytes;
    5351                 :        425 :     dst->rx_errors = src->rx_errors;
    5352                 :        425 :     dst->tx_errors = src->tx_errors;
    5353                 :        425 :     dst->rx_dropped = src->rx_dropped;
    5354                 :        425 :     dst->tx_dropped = src->tx_dropped;
    5355                 :        425 :     dst->multicast = src->multicast;
    5356                 :        425 :     dst->collisions = src->collisions;
    5357                 :        425 :     dst->rx_length_errors = src->rx_length_errors;
    5358                 :        425 :     dst->rx_over_errors = src->rx_over_errors;
    5359                 :        425 :     dst->rx_crc_errors = src->rx_crc_errors;
    5360                 :        425 :     dst->rx_frame_errors = src->rx_frame_errors;
    5361                 :        425 :     dst->rx_fifo_errors = src->rx_fifo_errors;
    5362                 :        425 :     dst->rx_missed_errors = src->rx_missed_errors;
    5363                 :        425 :     dst->tx_aborted_errors = src->tx_aborted_errors;
    5364                 :        425 :     dst->tx_carrier_errors = src->tx_carrier_errors;
    5365                 :        425 :     dst->tx_fifo_errors = src->tx_fifo_errors;
    5366                 :        425 :     dst->tx_heartbeat_errors = src->tx_heartbeat_errors;
    5367                 :        425 :     dst->tx_window_errors = src->tx_window_errors;
    5368                 :        425 : }
    5369                 :            : 
    5370                 :            : static int
    5371                 :        425 : get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats)
    5372                 :            : {
    5373                 :            :     struct ofpbuf request;
    5374                 :            :     struct ofpbuf *reply;
    5375                 :            :     int error;
    5376                 :            : 
    5377                 :            :     /* Filtering all counters by default */
    5378                 :        425 :     memset(stats, 0xFF, sizeof(struct netdev_stats));
    5379                 :            : 
    5380                 :        425 :     ofpbuf_init(&request, 0);
    5381                 :        425 :     nl_msg_put_nlmsghdr(&request,
    5382                 :            :                         sizeof(struct ifinfomsg) + NL_ATTR_SIZE(IFNAMSIZ),
    5383                 :            :                         RTM_GETLINK, NLM_F_REQUEST);
    5384                 :        425 :     ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
    5385                 :        425 :     nl_msg_put_string(&request, IFLA_IFNAME, netdev_get_name(netdev_));
    5386                 :        425 :     error = nl_transact(NETLINK_ROUTE, &request, &reply);
    5387                 :        425 :     ofpbuf_uninit(&request);
    5388         [ -  + ]:        425 :     if (error) {
    5389                 :          0 :         return error;
    5390                 :            :     }
    5391                 :            : 
    5392         [ +  - ]:        425 :     if (ofpbuf_try_pull(reply, NLMSG_HDRLEN + sizeof(struct ifinfomsg))) {
    5393                 :        425 :         const struct nlattr *a = nl_attr_find(reply, 0, IFLA_STATS64);
    5394 [ +  - ][ +  - ]:        425 :         if (a && nl_attr_get_size(a) >= sizeof(struct rtnl_link_stats64)) {
    5395                 :        425 :             netdev_stats_from_rtnl_link_stats64(stats, nl_attr_get(a));
    5396                 :        425 :             error = 0;
    5397                 :            :         } else {
    5398                 :          0 :             const struct nlattr *a = nl_attr_find(reply, 0, IFLA_STATS);
    5399 [ #  # ][ #  # ]:          0 :             if (a && nl_attr_get_size(a) >= sizeof(struct rtnl_link_stats)) {
    5400                 :          0 :                 netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(a));
    5401                 :          0 :                 error = 0;
    5402                 :            :             } else {
    5403         [ #  # ]:          0 :                 VLOG_WARN_RL(&rl, "RTM_GETLINK reply lacks stats");
    5404                 :        425 :                 error = EPROTO;
    5405                 :            :             }
    5406                 :            :         }
    5407                 :            :     } else {
    5408         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "short RTM_GETLINK reply");
    5409                 :          0 :         error = EPROTO;
    5410                 :            :     }
    5411                 :            : 
    5412                 :            : 
    5413                 :        425 :     ofpbuf_delete(reply);
    5414                 :        425 :     return error;
    5415                 :            : }
    5416                 :            : 
    5417                 :            : static int
    5418                 :      25509 : get_flags(const struct netdev *dev, unsigned int *flags)
    5419                 :            : {
    5420                 :            :     struct ifreq ifr;
    5421                 :            :     int error;
    5422                 :            : 
    5423                 :      25509 :     *flags = 0;
    5424                 :      25509 :     error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS");
    5425         [ +  + ]:      25509 :     if (!error) {
    5426                 :      25433 :         *flags = ifr.ifr_flags;
    5427                 :            :     }
    5428                 :      25509 :     return error;
    5429                 :            : }
    5430                 :            : 
    5431                 :            : static int
    5432                 :        179 : set_flags(const char *name, unsigned int flags)
    5433                 :            : {
    5434                 :            :     struct ifreq ifr;
    5435                 :            : 
    5436                 :        179 :     ifr.ifr_flags = flags;
    5437                 :        179 :     return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
    5438                 :            : }
    5439                 :            : 
    5440                 :            : static int
    5441                 :        346 : do_get_ifindex(const char *netdev_name)
    5442                 :            : {
    5443                 :            :     struct ifreq ifr;
    5444                 :            :     int error;
    5445                 :            : 
    5446                 :        346 :     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
    5447                 :        346 :     COVERAGE_INC(netdev_get_ifindex);
    5448                 :            : 
    5449                 :        346 :     error = af_inet_ioctl(SIOCGIFINDEX, &ifr);
    5450         [ +  + ]:        346 :     if (error) {
    5451         [ +  - ]:          2 :         VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s",
    5452                 :            :                      netdev_name, ovs_strerror(error));
    5453                 :          2 :         return -error;
    5454                 :            :     }
    5455                 :        346 :     return ifr.ifr_ifindex;
    5456                 :            : }
    5457                 :            : 
    5458                 :            : static int
    5459                 :       6749 : get_ifindex(const struct netdev *netdev_, int *ifindexp)
    5460                 :            : {
    5461                 :       6749 :     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
    5462                 :            : 
    5463         [ +  + ]:       6749 :     if (!(netdev->cache_valid & VALID_IFINDEX)) {
    5464                 :        346 :         int ifindex = do_get_ifindex(netdev_get_name(netdev_));
    5465                 :            : 
    5466         [ +  + ]:        346 :         if (ifindex < 0) {
    5467                 :          2 :             netdev->get_ifindex_error = -ifindex;
    5468                 :          2 :             netdev->ifindex = 0;
    5469                 :            :         } else {
    5470                 :        344 :             netdev->get_ifindex_error = 0;
    5471                 :        344 :             netdev->ifindex = ifindex;
    5472                 :            :         }
    5473                 :        346 :         netdev->cache_valid |= VALID_IFINDEX;
    5474                 :            :     }
    5475                 :            : 
    5476                 :       6749 :     *ifindexp = netdev->ifindex;
    5477                 :       6749 :     return netdev->get_ifindex_error;
    5478                 :            : }
    5479                 :            : 
    5480                 :            : static int
    5481                 :       2817 : get_etheraddr(const char *netdev_name, struct eth_addr *ea)
    5482                 :            : {
    5483                 :            :     struct ifreq ifr;
    5484                 :            :     int hwaddr_family;
    5485                 :            :     int error;
    5486                 :            : 
    5487                 :       2817 :     memset(&ifr, 0, sizeof ifr);
    5488                 :       2817 :     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
    5489                 :       2817 :     COVERAGE_INC(netdev_get_hwaddr);
    5490                 :       2817 :     error = af_inet_ioctl(SIOCGIFHWADDR, &ifr);
    5491         [ +  + ]:       2817 :     if (error) {
    5492                 :            :         /* ENODEV probably means that a vif disappeared asynchronously and
    5493                 :            :          * hasn't been removed from the database yet, so reduce the log level
    5494                 :            :          * to INFO for that case. */
    5495 [ +  - ][ +  - ]:          2 :         VLOG(error == ENODEV ? VLL_INFO : VLL_ERR,
    5496                 :            :              "ioctl(SIOCGIFHWADDR) on %s device failed: %s",
    5497                 :            :              netdev_name, ovs_strerror(error));
    5498                 :          2 :         return error;
    5499                 :            :     }
    5500                 :       2815 :     hwaddr_family = ifr.ifr_hwaddr.sa_family;
    5501 [ +  - ][ -  + ]:       2815 :     if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
    5502         [ #  # ]:          0 :         VLOG_INFO("%s device has unknown hardware address family %d",
    5503                 :            :                   netdev_name, hwaddr_family);
    5504                 :          0 :         return EINVAL;
    5505                 :            :     }
    5506                 :       2815 :     memcpy(ea, ifr.ifr_hwaddr.sa_data, ETH_ADDR_LEN);
    5507                 :       2817 :     return 0;
    5508                 :            : }
    5509                 :            : 
    5510                 :            : static int
    5511                 :        109 : set_etheraddr(const char *netdev_name, const struct eth_addr mac)
    5512                 :            : {
    5513                 :            :     struct ifreq ifr;
    5514                 :            :     int error;
    5515                 :            : 
    5516                 :        109 :     memset(&ifr, 0, sizeof ifr);
    5517                 :        109 :     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
    5518                 :        109 :     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    5519                 :        109 :     memcpy(ifr.ifr_hwaddr.sa_data, &mac, ETH_ADDR_LEN);
    5520                 :        109 :     COVERAGE_INC(netdev_set_hwaddr);
    5521                 :        109 :     error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
    5522         [ -  + ]:        109 :     if (error) {
    5523         [ #  # ]:          0 :         VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s",
    5524                 :            :                  netdev_name, ovs_strerror(error));
    5525                 :            :     }
    5526                 :        109 :     return error;
    5527                 :            : }
    5528                 :            : 
    5529                 :            : static int
    5530                 :       1195 : netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd,
    5531                 :            :                         int cmd, const char *cmd_name)
    5532                 :            : {
    5533                 :            :     struct ifreq ifr;
    5534                 :            :     int error;
    5535                 :            : 
    5536                 :       1195 :     memset(&ifr, 0, sizeof ifr);
    5537                 :       1195 :     ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
    5538                 :       1195 :     ifr.ifr_data = (caddr_t) ecmd;
    5539                 :            : 
    5540                 :       1195 :     ecmd->cmd = cmd;
    5541                 :       1195 :     error = af_inet_ioctl(SIOCETHTOOL, &ifr);
    5542         [ -  + ]:       1195 :     if (error) {
    5543         [ #  # ]:          0 :         if (error != EOPNOTSUPP) {
    5544         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "ethtool command %s on network device %s "
    5545                 :            :                          "failed: %s", cmd_name, name, ovs_strerror(error));
    5546                 :            :         } else {
    5547                 :            :             /* The device doesn't support this operation.  That's pretty
    5548                 :            :              * common, so there's no point in logging anything. */
    5549                 :            :         }
    5550                 :            :     }
    5551                 :       1195 :     return error;
    5552                 :            : }
    5553                 :            : 
    5554                 :            : /* Returns an AF_PACKET raw socket or a negative errno value. */
    5555                 :            : static int
    5556                 :        930 : af_packet_sock(void)
    5557                 :            : {
    5558                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
    5559                 :            :     static int sock;
    5560                 :            : 
    5561         [ +  + ]:        930 :     if (ovsthread_once_start(&once)) {
    5562                 :         29 :         sock = socket(AF_PACKET, SOCK_RAW, 0);
    5563         [ +  - ]:         29 :         if (sock >= 0) {
    5564                 :         29 :             int error = set_nonblocking(sock);
    5565         [ -  + ]:         29 :             if (error) {
    5566                 :          0 :                 close(sock);
    5567                 :         29 :                 sock = -error;
    5568                 :            :             }
    5569                 :            :         } else {
    5570                 :          0 :             sock = -errno;
    5571         [ #  # ]:          0 :             VLOG_ERR("failed to create packet socket: %s",
    5572                 :            :                      ovs_strerror(errno));
    5573                 :            :         }
    5574                 :         29 :         ovsthread_once_done(&once);
    5575                 :            :     }
    5576                 :            : 
    5577                 :        930 :     return sock;
    5578                 :            : }

Generated by: LCOV version 1.12