LCOV - code coverage report
Current view: top level - drivers/net/tap - tap_tcmsgs.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 69 0.0 %
Date: 2025-03-01 20:23:48 Functions: 0 9 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 36 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright 2017 6WIND S.A.
       3                 :            :  * Copyright 2017 Mellanox Technologies, Ltd
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <inttypes.h>
       7                 :            : #include <linux/netlink.h>
       8                 :            : #include <net/if.h>
       9                 :            : #include <string.h>
      10                 :            : 
      11                 :            : #include <rte_log.h>
      12                 :            : #include <tap_tcmsgs.h>
      13                 :            : #include "tap_log.h"
      14                 :            : 
      15                 :            : struct qdisc {
      16                 :            :         uint32_t handle;
      17                 :            :         uint32_t parent;
      18                 :            : };
      19                 :            : 
      20                 :            : struct list_args {
      21                 :            :         int nlsk_fd;
      22                 :            :         unsigned int ifindex;
      23                 :            :         void *custom_arg;
      24                 :            : };
      25                 :            : 
      26                 :            : struct qdisc_custom_arg {
      27                 :            :         uint32_t handle;
      28                 :            :         uint32_t parent;
      29                 :            :         uint8_t exists;
      30                 :            : };
      31                 :            : 
      32                 :            : /**
      33                 :            :  * Initialize a netlink message with a TC header.
      34                 :            :  *
      35                 :            :  * @param[in, out] msg
      36                 :            :  *   The netlink message to fill.
      37                 :            :  * @param[in] ifindex
      38                 :            :  *   The netdevice ifindex where the rule will be applied.
      39                 :            :  * @param[in] type
      40                 :            :  *   The type of TC message to create (RTM_NEWTFILTER, RTM_NEWQDISC, etc.).
      41                 :            :  * @param[in] flags
      42                 :            :  *   Overrides the default netlink flags for this msg with those specified.
      43                 :            :  */
      44                 :            : void
      45                 :          0 : tc_init_msg(struct tap_nlmsg *msg, unsigned int ifindex, uint16_t type, uint16_t flags)
      46                 :            : {
      47                 :            :         struct nlmsghdr *n = &msg->nh;
      48                 :            : 
      49                 :          0 :         n->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
      50                 :          0 :         n->nlmsg_type = type;
      51         [ #  # ]:          0 :         if (flags)
      52                 :          0 :                 n->nlmsg_flags = flags;
      53                 :            :         else
      54                 :          0 :                 n->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
      55                 :          0 :         msg->t.tcm_family = AF_UNSPEC;
      56                 :          0 :         msg->t.tcm_ifindex = ifindex;
      57                 :          0 : }
      58                 :            : 
      59                 :            : /**
      60                 :            :  * Delete a specific QDISC identified by its iface, and it's handle and parent.
      61                 :            :  *
      62                 :            :  * @param[in] nlsk_fd
      63                 :            :  *   The netlink socket file descriptor used for communication.
      64                 :            :  * @param[in] ifindex
      65                 :            :  *   The netdevice ifindex on whom the deletion will happen.
      66                 :            :  * @param[in] qinfo
      67                 :            :  *   Additional info to identify the QDISC (handle and parent).
      68                 :            :  *
      69                 :            :  * @return
      70                 :            :  *   0 on success, -1 otherwise with errno set.
      71                 :            :  */
      72                 :            : static int
      73                 :          0 : qdisc_del(int nlsk_fd, unsigned int ifindex, struct qdisc *qinfo)
      74                 :            : {
      75                 :            :         struct tap_nlmsg msg;
      76                 :            :         int fd = 0;
      77                 :            : 
      78                 :          0 :         tc_init_msg(&msg, ifindex, RTM_DELQDISC, 0);
      79                 :          0 :         msg.t.tcm_handle = qinfo->handle;
      80                 :          0 :         msg.t.tcm_parent = qinfo->parent;
      81                 :            :         /* if no netlink socket is provided, create one */
      82         [ #  # ]:          0 :         if (!nlsk_fd) {
      83                 :          0 :                 fd = tap_nl_init(0);
      84         [ #  # ]:          0 :                 if (fd < 0) {
      85                 :          0 :                         TAP_LOG(ERR,
      86                 :            :                                 "Could not delete QDISC: null netlink socket");
      87                 :          0 :                         return -1;
      88                 :            :                 }
      89                 :            :         } else {
      90                 :            :                 fd = nlsk_fd;
      91                 :            :         }
      92         [ #  # ]:          0 :         if (tap_nl_send(fd, &msg.nh) < 0)
      93                 :          0 :                 goto error;
      94         [ #  # ]:          0 :         if (tap_nl_recv_ack(fd) < 0)
      95                 :          0 :                 goto error;
      96         [ #  # ]:          0 :         if (!nlsk_fd)
      97                 :          0 :                 return tap_nl_final(fd);
      98                 :            :         return 0;
      99                 :          0 : error:
     100         [ #  # ]:          0 :         if (!nlsk_fd)
     101                 :          0 :                 tap_nl_final(fd);
     102                 :            :         return -1;
     103                 :            : }
     104                 :            : 
     105                 :            : /**
     106                 :            :  * Add the multiqueue QDISC with MULTIQ_MAJOR_HANDLE handle.
     107                 :            :  *
     108                 :            :  * @param[in] nlsk_fd
     109                 :            :  *   The netlink socket file descriptor used for communication.
     110                 :            :  * @param[in] ifindex
     111                 :            :  *   The netdevice ifindex where to add the multiqueue QDISC.
     112                 :            :  *
     113                 :            :  * @return
     114                 :            :  *   0 on success, -1 otherwise with errno set.
     115                 :            :  */
     116                 :            : int
     117                 :          0 : qdisc_add_multiq(int nlsk_fd, unsigned int ifindex)
     118                 :            : {
     119                 :          0 :         struct tc_multiq_qopt opt = {0};
     120                 :            :         struct tap_nlmsg msg;
     121                 :            : 
     122                 :          0 :         tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
     123                 :            :                     NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
     124                 :          0 :         msg.t.tcm_handle = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
     125                 :          0 :         msg.t.tcm_parent = TC_H_ROOT;
     126                 :          0 :         tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("multiq"), "multiq");
     127                 :          0 :         tap_nlattr_add(&msg.nh, TCA_OPTIONS, sizeof(opt), &opt);
     128         [ #  # ]:          0 :         if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
     129                 :            :                 return -1;
     130         [ #  # ]:          0 :         if (tap_nl_recv_ack(nlsk_fd) < 0)
     131                 :          0 :                 return -1;
     132                 :            :         return 0;
     133                 :            : }
     134                 :            : 
     135                 :            : /**
     136                 :            :  * Add the ingress QDISC with default ffff: handle.
     137                 :            :  *
     138                 :            :  * @param[in] nlsk_fd
     139                 :            :  *   The netlink socket file descriptor used for communication.
     140                 :            :  * @param[in] ifindex
     141                 :            :  *   The netdevice ifindex where the QDISC will be added.
     142                 :            :  *
     143                 :            :  * @return
     144                 :            :  *   0 on success, -1 otherwise with errno set.
     145                 :            :  */
     146                 :            : int
     147                 :          0 : qdisc_add_ingress(int nlsk_fd, unsigned int ifindex)
     148                 :            : {
     149                 :            :         struct tap_nlmsg msg;
     150                 :            : 
     151                 :          0 :         tc_init_msg(&msg, ifindex, RTM_NEWQDISC,
     152                 :            :                     NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
     153                 :          0 :         msg.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
     154                 :          0 :         msg.t.tcm_parent = TC_H_INGRESS;
     155                 :          0 :         tap_nlattr_add(&msg.nh, TCA_KIND, sizeof("ingress"), "ingress");
     156         [ #  # ]:          0 :         if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
     157                 :            :                 return -1;
     158         [ #  # ]:          0 :         if (tap_nl_recv_ack(nlsk_fd) < 0)
     159                 :          0 :                 return -1;
     160                 :            :         return 0;
     161                 :            : }
     162                 :            : 
     163                 :            : /**
     164                 :            :  * Callback function to delete a QDISC.
     165                 :            :  *
     166                 :            :  * @param[in] nh
     167                 :            :  *   The netlink message to parse, received from the kernel.
     168                 :            :  * @param[in] arg
     169                 :            :  *   Custom arguments for the callback.
     170                 :            :  *
     171                 :            :  * @return
     172                 :            :  *   0 on success, -1 otherwise with errno set.
     173                 :            :  */
     174                 :            : static int
     175                 :          0 : qdisc_del_cb(struct nlmsghdr *nh, void *arg)
     176                 :            : {
     177                 :            :         struct tcmsg *t = NLMSG_DATA(nh);
     178                 :            :         struct list_args *args = arg;
     179                 :            : 
     180                 :          0 :         struct qdisc qinfo = {
     181                 :          0 :                 .handle = t->tcm_handle,
     182                 :          0 :                 .parent = t->tcm_parent,
     183                 :            :         };
     184                 :            : 
     185                 :            :         /* filter out other ifaces' qdiscs */
     186         [ #  # ]:          0 :         if (args->ifindex != (unsigned int)t->tcm_ifindex)
     187                 :            :                 return 0;
     188                 :            :         /*
     189                 :            :          * Use another nlsk_fd (0) to avoid tampering with the current list
     190                 :            :          * iteration.
     191                 :            :          */
     192                 :          0 :         return qdisc_del(0, args->ifindex, &qinfo);
     193                 :            : }
     194                 :            : 
     195                 :            : /**
     196                 :            :  * Iterate over all QDISC, and call the callback() function for each.
     197                 :            :  *
     198                 :            :  * @param[in] nlsk_fd
     199                 :            :  *   The netlink socket file descriptor used for communication.
     200                 :            :  * @param[in] ifindex
     201                 :            :  *   The netdevice ifindex where to find QDISCs.
     202                 :            :  * @param[in] callback
     203                 :            :  *   The function to call for each QDISC.
     204                 :            :  * @param[in, out] arg
     205                 :            :  *   The arguments to provide the callback function with.
     206                 :            :  *
     207                 :            :  * @return
     208                 :            :  *   0 on success, -1 otherwise with errno set.
     209                 :            :  */
     210                 :            : static int
     211                 :          0 : qdisc_iterate(int nlsk_fd, unsigned int ifindex,
     212                 :            :               int (*callback)(struct nlmsghdr *, void *), void *arg)
     213                 :            : {
     214                 :            :         struct tap_nlmsg msg;
     215                 :          0 :         struct list_args args = {
     216                 :            :                 .nlsk_fd = nlsk_fd,
     217                 :            :                 .ifindex = ifindex,
     218                 :            :                 .custom_arg = arg,
     219                 :            :         };
     220                 :            : 
     221                 :          0 :         tc_init_msg(&msg, ifindex, RTM_GETQDISC, NLM_F_REQUEST | NLM_F_DUMP);
     222         [ #  # ]:          0 :         if (tap_nl_send(nlsk_fd, &msg.nh) < 0)
     223                 :            :                 return -1;
     224         [ #  # ]:          0 :         if (tap_nl_recv(nlsk_fd, callback, &args) < 0)
     225                 :          0 :                 return -1;
     226                 :            :         return 0;
     227                 :            : }
     228                 :            : 
     229                 :            : /**
     230                 :            :  * Delete all QDISCs for a given netdevice.
     231                 :            :  *
     232                 :            :  * @param[in] nlsk_fd
     233                 :            :  *   The netlink socket file descriptor used for communication.
     234                 :            :  * @param[in] ifindex
     235                 :            :  *   The netdevice ifindex where to find QDISCs.
     236                 :            :  *
     237                 :            :  * @return
     238                 :            :  *   0 on success, -1 otherwise with errno set.
     239                 :            :  */
     240                 :            : int
     241                 :          0 : qdisc_flush(int nlsk_fd, unsigned int ifindex)
     242                 :            : {
     243                 :          0 :         return qdisc_iterate(nlsk_fd, ifindex, qdisc_del_cb, NULL);
     244                 :            : }
     245                 :            : 
     246                 :            : /**
     247                 :            :  * Create the multiqueue QDISC, only if it does not exist already.
     248                 :            :  *
     249                 :            :  * @param[in] nlsk_fd
     250                 :            :  *   The netlink socket file descriptor used for communication.
     251                 :            :  * @param[in] ifindex
     252                 :            :  *   The netdevice ifindex where to add the multiqueue QDISC.
     253                 :            :  *
     254                 :            :  * @return
     255                 :            :  *   0 if the qdisc exists or if has been successfully added.
     256                 :            :  *   Return -1 otherwise.
     257                 :            :  */
     258                 :            : int
     259                 :          0 : qdisc_create_multiq(int nlsk_fd, unsigned int ifindex)
     260                 :            : {
     261                 :            :         int err = 0;
     262                 :            : 
     263                 :          0 :         err = qdisc_add_multiq(nlsk_fd, ifindex);
     264   [ #  #  #  # ]:          0 :         if (err < 0 && errno != -EEXIST) {
     265                 :          0 :                 TAP_LOG(ERR, "Could not add multiq qdisc (%d): %s",
     266                 :            :                         errno, strerror(errno));
     267                 :          0 :                 return -1;
     268                 :            :         }
     269                 :            :         return 0;
     270                 :            : }
     271                 :            : 
     272                 :            : /**
     273                 :            :  * Create the ingress QDISC, only if it does not exist already.
     274                 :            :  *
     275                 :            :  * @param[in] nlsk_fd
     276                 :            :  *   The netlink socket file descriptor used for communication.
     277                 :            :  * @param[in] ifindex
     278                 :            :  *   The netdevice ifindex where to add the ingress QDISC.
     279                 :            :  *
     280                 :            :  * @return
     281                 :            :  *   0 if the qdisc exists or if has been successfully added.
     282                 :            :  *   Return -1 otherwise.
     283                 :            :  */
     284                 :            : int
     285                 :          0 : qdisc_create_ingress(int nlsk_fd, unsigned int ifindex)
     286                 :            : {
     287                 :            :         int err = 0;
     288                 :            : 
     289                 :          0 :         err = qdisc_add_ingress(nlsk_fd, ifindex);
     290   [ #  #  #  # ]:          0 :         if (err < 0 && errno != -EEXIST) {
     291                 :          0 :                 TAP_LOG(ERR, "Could not add ingress qdisc (%d): %s",
     292                 :            :                         errno, strerror(errno));
     293                 :          0 :                 return -1;
     294                 :            :         }
     295                 :            :         return 0;
     296                 :            : }

Generated by: LCOV version 1.14