back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_tc.c (source / functions) Hit Total Coverage
Test: test_bgp_rmap_extcommunity_none.py::TestBGPExtCommunity Lines: 14 181 7.7 %
Date: 2023-02-24 18:37:31 Functions: 8 34 23.5 %

          Line data    Source code
       1             : /*
       2             :  * Zebra Traffic Control (TC) main handling.
       3             :  *
       4             :  * Copyright (C) 2022 Shichu Yang
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the Free
       8             :  * Software Foundation; either version 2 of the License, or (at your option)
       9             :  * any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      14             :  * more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include <jhash.h>
      24             : #include <hash.h>
      25             : #include <memory.h>
      26             : #include <hook.h>
      27             : 
      28             : #include "zebra/zebra_router.h"
      29             : #include "zebra/zebra_dplane.h"
      30             : #include "zebra/zebra_tc.h"
      31             : #include "zebra/debug.h"
      32             : 
      33           6 : DEFINE_MTYPE_STATIC(ZEBRA, TC_QDISC, "TC queue discipline");
      34           6 : DEFINE_MTYPE_STATIC(ZEBRA, TC_CLASS, "TC class");
      35           6 : DEFINE_MTYPE_STATIC(ZEBRA, TC_FILTER, "TC filter");
      36             : 
      37             : const struct message tc_qdisc_kinds[] = {
      38             :         {TC_QDISC_HTB, "htb"},
      39             :         {TC_QDISC_NOQUEUE, "noqueue"},
      40             :         {0},
      41             : };
      42             : 
      43             : const struct message tc_filter_kinds[] = {
      44             :         {TC_FILTER_BPF, "bpf"},
      45             :         {TC_FILTER_FLOW, "flow"},
      46             :         {TC_FILTER_FLOWER, "flower"},
      47             :         {TC_FILTER_U32, "u32"},
      48             :         {0},
      49             : };
      50             : 
      51             : const struct message *tc_class_kinds = tc_qdisc_kinds;
      52             : 
      53           4 : static uint32_t lookup_key(const struct message *mz, const char *msg,
      54             :                            uint32_t nf)
      55             : {
      56           4 :         static struct message nt = {0};
      57           4 :         uint32_t rz = nf ? nf : UINT32_MAX;
      58           4 :         const struct message *pnt;
      59             : 
      60           8 :         for (pnt = mz; memcmp(pnt, &nt, sizeof(struct message)); pnt++)
      61           8 :                 if (strcmp(pnt->str, msg) == 0) {
      62           4 :                         rz = pnt->key;
      63           4 :                         break;
      64             :                 }
      65           4 :         return rz;
      66             : }
      67             : 
      68           0 : const char *tc_qdisc_kind2str(uint32_t type)
      69             : {
      70           0 :         return lookup_msg(tc_qdisc_kinds, type, "Unrecognized QDISC Type");
      71             : }
      72             : 
      73           4 : enum tc_qdisc_kind tc_qdisc_str2kind(const char *type)
      74             : {
      75           4 :         return lookup_key(tc_qdisc_kinds, type, TC_QDISC_UNSPEC);
      76             : }
      77             : 
      78           0 : uint32_t zebra_tc_qdisc_hash_key(const void *arg)
      79             : {
      80           0 :         const struct zebra_tc_qdisc *qdisc;
      81           0 :         uint32_t key;
      82             : 
      83           0 :         qdisc = arg;
      84             : 
      85           0 :         key = jhash_1word(qdisc->qdisc.ifindex, 0);
      86             : 
      87           0 :         return key;
      88             : }
      89             : 
      90           0 : bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2)
      91             : {
      92           0 :         const struct zebra_tc_qdisc *q1, *q2;
      93             : 
      94           0 :         q1 = (const struct zebra_tc_qdisc *)arg1;
      95           0 :         q2 = (const struct zebra_tc_qdisc *)arg2;
      96             : 
      97           0 :         if (q1->qdisc.ifindex != q2->qdisc.ifindex)
      98           0 :                 return false;
      99             : 
     100             :         return true;
     101             : }
     102             : 
     103             : struct tc_qdisc_ifindex_lookup {
     104             :         struct zebra_tc_qdisc *qdisc;
     105             :         ifindex_t ifindex;
     106             : };
     107             : 
     108             : 
     109           0 : static int tc_qdisc_lookup_ifindex_walker(struct hash_bucket *b, void *data)
     110             : {
     111           0 :         struct tc_qdisc_ifindex_lookup *lookup = data;
     112           0 :         struct zebra_tc_qdisc *qdisc = b->data;
     113             : 
     114           0 :         if (lookup->ifindex == qdisc->qdisc.ifindex) {
     115           0 :                 lookup->qdisc = qdisc;
     116           0 :                 return HASHWALK_ABORT;
     117             :         }
     118             : 
     119             :         return HASHWALK_CONTINUE;
     120             : }
     121             : 
     122             : static struct zebra_tc_qdisc *
     123           0 : tc_qdisc_lookup_ifindex(struct zebra_tc_qdisc *qdisc)
     124             : {
     125           0 :         struct tc_qdisc_ifindex_lookup lookup;
     126             : 
     127           0 :         lookup.ifindex = qdisc->qdisc.ifindex;
     128           0 :         lookup.qdisc = NULL;
     129           0 :         hash_walk(zrouter.rules_hash, &tc_qdisc_lookup_ifindex_walker, &lookup);
     130             : 
     131           0 :         return lookup.qdisc;
     132             : }
     133             : 
     134           0 : static void *tc_qdisc_alloc_intern(void *arg)
     135             : {
     136           0 :         struct zebra_tc_qdisc *ztq;
     137           0 :         struct zebra_tc_qdisc *new;
     138             : 
     139           0 :         ztq = (struct zebra_tc_qdisc *)arg;
     140             : 
     141           0 :         new = XCALLOC(MTYPE_TC_QDISC, sizeof(*new));
     142             : 
     143           0 :         memcpy(new, ztq, sizeof(*ztq));
     144             : 
     145           0 :         return new;
     146             : }
     147             : 
     148           0 : static struct zebra_tc_qdisc *tc_qdisc_free(struct zebra_tc_qdisc *hash_data,
     149             :                                             bool free_data)
     150             : {
     151           0 :         hash_release(zrouter.qdisc_hash, hash_data);
     152             : 
     153           0 :         if (free_data) {
     154           0 :                 XFREE(MTYPE_TC_QDISC, hash_data);
     155           0 :                 return NULL;
     156             :         }
     157             : 
     158             :         return hash_data;
     159             : }
     160             : 
     161           0 : static struct zebra_tc_qdisc *tc_qdisc_release(struct zebra_tc_qdisc *qdisc,
     162             :                                                bool free_data)
     163             : {
     164           0 :         struct zebra_tc_qdisc *lookup;
     165             : 
     166           0 :         lookup = hash_lookup(zrouter.qdisc_hash, qdisc);
     167             : 
     168           0 :         if (!lookup)
     169             :                 return NULL;
     170             : 
     171           0 :         return tc_qdisc_free(lookup, free_data);
     172             : }
     173             : 
     174           0 : void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
     175             : {
     176           0 :         if (IS_ZEBRA_DEBUG_TC)
     177           0 :                 zlog_debug("%s: install tc qdisc ifindex %d kind %s", __func__,
     178             :                            qdisc->qdisc.ifindex,
     179             :                            tc_qdisc_kind2str(qdisc->qdisc.kind));
     180             : 
     181           0 :         struct zebra_tc_qdisc *found;
     182           0 :         struct zebra_tc_qdisc *old;
     183           0 :         struct zebra_tc_qdisc *new;
     184             : 
     185           0 :         found = tc_qdisc_lookup_ifindex(qdisc);
     186             : 
     187           0 :         if (found) {
     188           0 :                 if (!zebra_tc_qdisc_hash_equal(qdisc, found)) {
     189           0 :                         old = tc_qdisc_release(found, false);
     190           0 :                         (void)dplane_tc_qdisc_uninstall(old);
     191           0 :                         new = hash_get(zrouter.qdisc_hash, qdisc,
     192             :                                        tc_qdisc_alloc_intern);
     193           0 :                         (void)dplane_tc_qdisc_install(new);
     194           0 :                         XFREE(MTYPE_TC_QDISC, old);
     195             :                 }
     196             :         } else {
     197           0 :                 new = hash_get(zrouter.qdisc_hash, qdisc,
     198             :                                tc_qdisc_alloc_intern);
     199           0 :                 (void)dplane_tc_qdisc_install(new);
     200             :         }
     201           0 : }
     202             : 
     203           0 : void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
     204             : {
     205           0 :         if (IS_ZEBRA_DEBUG_TC)
     206           0 :                 zlog_debug("%s: uninstall tc qdisc ifindex %d kind %s",
     207             :                            __func__, qdisc->qdisc.ifindex,
     208             :                            tc_qdisc_kind2str(qdisc->qdisc.kind));
     209             : 
     210           0 :         (void)dplane_tc_qdisc_uninstall(qdisc);
     211             : 
     212           0 :         if (tc_qdisc_release(qdisc, true))
     213           0 :                 zlog_debug("%s: tc qdisc being deleted we know nothing about",
     214             :                            __func__);
     215           0 : }
     216             : 
     217           0 : uint32_t zebra_tc_class_hash_key(const void *arg)
     218             : {
     219           0 :         const struct zebra_tc_class *class;
     220           0 :         uint32_t key;
     221             : 
     222           0 :         class = arg;
     223             : 
     224           0 :         key = jhash_2words(class->class.ifindex, class->class.handle, 0);
     225             : 
     226           0 :         return key;
     227             : }
     228             : 
     229           0 : bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2)
     230             : {
     231           0 :         const struct zebra_tc_class *c1, *c2;
     232             : 
     233           0 :         c1 = (const struct zebra_tc_class *)arg1;
     234           0 :         c2 = (const struct zebra_tc_class *)arg2;
     235             : 
     236           0 :         if (c1->class.ifindex != c2->class.ifindex)
     237             :                 return false;
     238             : 
     239           0 :         if (c1->class.handle != c2->class.handle)
     240           0 :                 return false;
     241             : 
     242             :         return true;
     243             : }
     244             : 
     245           0 : static void *tc_class_alloc_intern(void *arg)
     246             : {
     247           0 :         struct zebra_tc_class *class;
     248           0 :         struct zebra_tc_class *new;
     249             : 
     250           0 :         class = (struct zebra_tc_class *)arg;
     251             : 
     252           0 :         new = XCALLOC(MTYPE_TC_CLASS, sizeof(*new));
     253             : 
     254           0 :         memcpy(new, class, sizeof(*class));
     255             : 
     256           0 :         return new;
     257             : }
     258             : 
     259           0 : static struct zebra_tc_class *tc_class_free(struct zebra_tc_class *hash_data,
     260             :                                             bool free_data)
     261             : {
     262           0 :         hash_release(zrouter.class_hash, hash_data);
     263             : 
     264           0 :         if (free_data) {
     265           0 :                 XFREE(MTYPE_TC_CLASS, hash_data);
     266           0 :                 return NULL;
     267             :         }
     268             : 
     269             :         return hash_data;
     270             : }
     271             : 
     272           0 : static struct zebra_tc_class *tc_class_release(struct zebra_tc_class *class,
     273             :                                                bool free_data)
     274             : {
     275           0 :         struct zebra_tc_class *lookup;
     276             : 
     277           0 :         lookup = hash_lookup(zrouter.class_hash, class);
     278             : 
     279           0 :         if (!lookup)
     280             :                 return NULL;
     281             : 
     282           0 :         return tc_class_free(lookup, free_data);
     283             : }
     284             : 
     285           0 : void zebra_tc_class_add(struct zebra_tc_class *class)
     286             : {
     287           0 :         if (IS_ZEBRA_DEBUG_TC)
     288           0 :                 zlog_debug(
     289             :                         "%s: add tc class ifindex %d handle %04x:%04x kind %s",
     290             :                         __func__, class->class.ifindex,
     291             :                         (class->class.handle & 0xffff0000u) >> 16,
     292             :                         class->class.handle & 0x0000ffffu,
     293             :                         tc_qdisc_kind2str(class->class.kind));
     294             : 
     295           0 :         struct zebra_tc_class *found;
     296           0 :         struct zebra_tc_class *new;
     297             : 
     298             :         /*
     299             :          * We find the class in the hash by (ifindex, handle) directly, and by
     300             :          * testing their deep equality to seek out whether it's an update.
     301             :          *
     302             :          * Currently deep equality is not checked since it will be okay to
     303             :          * update the totally same class again.
     304             :          */
     305           0 :         found = hash_lookup(zrouter.class_hash, class);
     306           0 :         new = hash_get(zrouter.class_hash, class, tc_class_alloc_intern);
     307             : 
     308           0 :         if (found)
     309           0 :                 (void)dplane_tc_class_update(new);
     310             :         else
     311           0 :                 (void)dplane_tc_class_add(new);
     312           0 : }
     313             : 
     314           0 : void zebra_tc_class_delete(struct zebra_tc_class *class)
     315             : {
     316           0 :         if (IS_ZEBRA_DEBUG_TC)
     317           0 :                 zlog_debug(
     318             :                         "%s: delete tc class ifindex %d handle %04x:%04x kind %s",
     319             :                         __func__, class->class.ifindex,
     320             :                         (class->class.handle & 0xffff0000u) >> 16,
     321             :                         class->class.handle & 0x0000ffffu,
     322             :                         tc_qdisc_kind2str(class->class.kind));
     323             : 
     324           0 :         (void)dplane_tc_class_delete(class);
     325             : 
     326           0 :         if (tc_class_release(class, true))
     327           0 :                 zlog_debug("%s: tc class being deleted we know nothing about",
     328             :                            __func__);
     329           0 : }
     330             : 
     331           0 : const char *tc_filter_kind2str(uint32_t type)
     332             : {
     333           0 :         return lookup_msg(tc_filter_kinds, type, "Unrecognized TFILTER Type");
     334             : }
     335             : 
     336           0 : enum tc_qdisc_kind tc_filter_str2kind(const char *type)
     337             : {
     338           0 :         return lookup_key(tc_filter_kinds, type, TC_FILTER_UNSPEC);
     339             : }
     340             : 
     341           0 : uint32_t zebra_tc_filter_hash_key(const void *arg)
     342             : {
     343           0 :         const struct zebra_tc_filter *filter;
     344           0 :         uint32_t key;
     345             : 
     346           0 :         filter = arg;
     347             : 
     348           0 :         key = jhash_2words(filter->filter.ifindex, filter->filter.handle, 0);
     349             : 
     350           0 :         return key;
     351             : }
     352             : 
     353           0 : bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2)
     354             : {
     355           0 :         const struct zebra_tc_filter *f1, *f2;
     356             : 
     357           0 :         f1 = (const struct zebra_tc_filter *)arg1;
     358           0 :         f2 = (const struct zebra_tc_filter *)arg2;
     359             : 
     360           0 :         if (f1->filter.ifindex != f2->filter.ifindex)
     361             :                 return false;
     362             : 
     363           0 :         if (f1->filter.handle != f2->filter.handle)
     364           0 :                 return false;
     365             : 
     366             :         return true;
     367             : }
     368             : 
     369           0 : static struct zebra_tc_filter *tc_filter_free(struct zebra_tc_filter *hash_data,
     370             :                                               bool free_data)
     371             : {
     372           0 :         hash_release(zrouter.filter_hash, hash_data);
     373             : 
     374           0 :         if (free_data) {
     375           0 :                 XFREE(MTYPE_TC_FILTER, hash_data);
     376           0 :                 return NULL;
     377             :         }
     378             : 
     379             :         return hash_data;
     380             : }
     381             : 
     382           0 : static struct zebra_tc_filter *tc_filter_release(struct zebra_tc_filter *filter,
     383             :                                                  bool free_data)
     384             : {
     385           0 :         struct zebra_tc_filter *lookup;
     386             : 
     387           0 :         lookup = hash_lookup(zrouter.filter_hash, filter);
     388             : 
     389           0 :         if (!lookup)
     390             :                 return NULL;
     391             : 
     392           0 :         return tc_filter_free(lookup, free_data);
     393             : }
     394             : 
     395           0 : static void *tc_filter_alloc_intern(void *arg)
     396             : {
     397           0 :         struct zebra_tc_filter *ztf;
     398           0 :         struct zebra_tc_filter *new;
     399             : 
     400           0 :         ztf = (struct zebra_tc_filter *)arg;
     401             : 
     402           0 :         new = XCALLOC(MTYPE_TC_FILTER, sizeof(*new));
     403             : 
     404           0 :         memcpy(new, ztf, sizeof(*ztf));
     405             : 
     406           0 :         return new;
     407             : }
     408             : 
     409           0 : void zebra_tc_filter_add(struct zebra_tc_filter *filter)
     410             : {
     411           0 :         if (IS_ZEBRA_DEBUG_TC)
     412           0 :                 zlog_debug(
     413             :                         "%s: add tc filter ifindex %d priority %u handle %08x kind %s",
     414             :                         __func__, filter->filter.ifindex,
     415             :                         filter->filter.priority, filter->filter.handle,
     416             :                         tc_filter_kind2str(filter->filter.kind));
     417             : 
     418           0 :         struct zebra_tc_filter *found;
     419           0 :         struct zebra_tc_filter *new;
     420             : 
     421           0 :         found = hash_lookup(zrouter.filter_hash, filter);
     422           0 :         new = hash_get(zrouter.filter_hash, filter, tc_filter_alloc_intern);
     423             : 
     424           0 :         if (found)
     425           0 :                 (void)dplane_tc_filter_update(new);
     426             :         else
     427           0 :                 (void)dplane_tc_filter_add(new);
     428           0 : }
     429             : 
     430           0 : void zebra_tc_filter_delete(struct zebra_tc_filter *filter)
     431             : {
     432           0 :         if (IS_ZEBRA_DEBUG_PBR)
     433           0 :                 zlog_debug(
     434             :                         "%s: delete tc filter ifindex %d priority %u handle %08x kind %s",
     435             :                         __func__, filter->filter.ifindex,
     436             :                         filter->filter.priority, filter->filter.handle,
     437             :                         tc_filter_kind2str(filter->filter.kind));
     438             : 
     439           0 :         (void)dplane_tc_filter_delete(filter);
     440             : 
     441           0 :         if (tc_filter_release(filter, true))
     442           0 :                 zlog_debug("%s: tc filter being deleted we know nothing about",
     443             :                            __func__);
     444           0 : }

Generated by: LCOV version v1.16-topotato