LCOV - code coverage report
Current view: top level - lib/node - ip6_rewrite.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 1 132 0.8 %
Date: 2025-05-01 17:49:45 Functions: 1 6 16.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 72 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(C) 2023 Marvell.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <eal_export.h>
       6                 :            : #include <rte_ethdev.h>
       7                 :            : #include <rte_ether.h>
       8                 :            : #include <rte_graph.h>
       9                 :            : #include <rte_graph_worker.h>
      10                 :            : #include <rte_ip.h>
      11                 :            : #include <rte_malloc.h>
      12                 :            : #include <rte_vect.h>
      13                 :            : 
      14                 :            : #include "rte_node_ip6_api.h"
      15                 :            : 
      16                 :            : #include "ip6_rewrite_priv.h"
      17                 :            : #include "node_private.h"
      18                 :            : 
      19                 :            : struct ip6_rewrite_node_ctx {
      20                 :            :         /* Dynamic offset to mbuf priv1 */
      21                 :            :         int mbuf_priv1_off;
      22                 :            :         /* Cached next index */
      23                 :            :         uint16_t next_index;
      24                 :            : };
      25                 :            : 
      26                 :            : static struct ip6_rewrite_node_main *ip6_rewrite_nm;
      27                 :            : 
      28                 :            : #define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
      29                 :            :         (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
      30                 :            : 
      31                 :            : #define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
      32                 :            :         (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
      33                 :            : 
      34                 :            : static uint16_t
      35                 :          0 : ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
      36                 :            :                          void **objs, uint16_t nb_objs)
      37                 :            : {
      38                 :            :         struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
      39                 :          0 :         struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
      40                 :          0 :         const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
      41                 :            :         uint16_t next0, next1, next2, next3, next_index;
      42                 :            :         uint16_t n_left_from, held = 0, last_spec = 0;
      43                 :            :         struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
      44                 :            :         void *d0, *d1, *d2, *d3;
      45                 :            :         void **to_next, **from;
      46                 :            :         rte_xmm_t priv01;
      47                 :            :         rte_xmm_t priv23;
      48                 :            :         int i;
      49                 :            : 
      50                 :            :         /* Speculative next as last next */
      51                 :          0 :         next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
      52                 :            :         rte_prefetch0(nh);
      53                 :            : 
      54                 :            :         pkts = (struct rte_mbuf **)objs;
      55                 :            :         from = objs;
      56                 :            :         n_left_from = nb_objs;
      57                 :            : 
      58   [ #  #  #  # ]:          0 :         for (i = 0; i < 4 && i < n_left_from; i++)
      59                 :          0 :                 rte_prefetch0(pkts[i]);
      60                 :            : 
      61                 :            :         /* Get stream for the speculated next node */
      62                 :          0 :         to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
      63                 :            :         /* Update Ethernet header of pkts */
      64         [ #  # ]:          0 :         while (n_left_from >= 4) {
      65         [ #  # ]:          0 :                 if (likely(n_left_from > 7)) {
      66                 :            :                         /* Prefetch only next-mbuf struct and priv area.
      67                 :            :                          * Data need not be prefetched as we only write.
      68                 :            :                          */
      69                 :          0 :                         rte_prefetch0(pkts[4]);
      70                 :          0 :                         rte_prefetch0(pkts[5]);
      71                 :          0 :                         rte_prefetch0(pkts[6]);
      72                 :          0 :                         rte_prefetch0(pkts[7]);
      73                 :            :                 }
      74                 :            : 
      75                 :          0 :                 mbuf0 = pkts[0];
      76                 :          0 :                 mbuf1 = pkts[1];
      77                 :          0 :                 mbuf2 = pkts[2];
      78                 :          0 :                 mbuf3 = pkts[3];
      79                 :            : 
      80                 :          0 :                 pkts += 4;
      81         [ #  # ]:          0 :                 n_left_from -= 4;
      82                 :          0 :                 priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
      83                 :          0 :                 priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
      84                 :          0 :                 priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
      85                 :          0 :                 priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
      86                 :            : 
      87                 :            :                 /* Update next_hop rewrite ethernet hdr on mbuf0 */
      88                 :          0 :                 d0 = rte_pktmbuf_mtod(mbuf0, void *);
      89                 :          0 :                 rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
      90         [ #  # ]:          0 :                            nh[priv01.u16[0]].rewrite_len);
      91                 :            : 
      92                 :          0 :                 next0 = nh[priv01.u16[0]].tx_node;
      93                 :            :                 ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
      94                 :            :                                               sizeof(struct rte_ether_hdr));
      95                 :          0 :                 ip0->hop_limits = priv01.u16[1] - 1;
      96                 :            : 
      97                 :            :                 /* Update next_hop rewrite ethernet hdr on mbuf1 */
      98                 :          0 :                 d1 = rte_pktmbuf_mtod(mbuf1, void *);
      99                 :          0 :                 rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
     100         [ #  # ]:          0 :                            nh[priv01.u16[4]].rewrite_len);
     101                 :            : 
     102                 :          0 :                 next1 = nh[priv01.u16[4]].tx_node;
     103                 :            :                 ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
     104                 :            :                                               sizeof(struct rte_ether_hdr));
     105                 :          0 :                 ip1->hop_limits = priv01.u16[5] - 1;
     106                 :            : 
     107                 :            :                 /* Update next_hop rewrite ethernet hdr on mbuf2 */
     108                 :          0 :                 d2 = rte_pktmbuf_mtod(mbuf2, void *);
     109                 :          0 :                 rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
     110         [ #  # ]:          0 :                            nh[priv23.u16[0]].rewrite_len);
     111                 :          0 :                 next2 = nh[priv23.u16[0]].tx_node;
     112                 :            :                 ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
     113                 :            :                                               sizeof(struct rte_ether_hdr));
     114                 :          0 :                 ip2->hop_limits = priv23.u16[1] - 1;
     115                 :            : 
     116                 :            :                 /* Update next_hop rewrite ethernet hdr on mbuf3 */
     117                 :          0 :                 d3 = rte_pktmbuf_mtod(mbuf3, void *);
     118                 :          0 :                 rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
     119         [ #  # ]:          0 :                            nh[priv23.u16[4]].rewrite_len);
     120                 :            : 
     121                 :          0 :                 next3 = nh[priv23.u16[4]].tx_node;
     122                 :            :                 ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
     123                 :            :                                               sizeof(struct rte_ether_hdr));
     124                 :          0 :                 ip3->hop_limits = priv23.u16[5] - 1;
     125                 :            : 
     126                 :            :                 /* Enqueue four packets to next node */
     127                 :          0 :                 rte_edge_t fix_spec =
     128                 :          0 :                         ((next_index == next0) && (next0 == next1) &&
     129   [ #  #  #  # ]:          0 :                          (next1 == next2) && (next2 == next3));
     130                 :            : 
     131         [ #  # ]:          0 :                 if (unlikely(fix_spec == 0)) {
     132                 :            :                         /* Copy things successfully speculated till now */
     133         [ #  # ]:          0 :                         rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
     134                 :          0 :                         from += last_spec;
     135                 :          0 :                         to_next += last_spec;
     136                 :          0 :                         held += last_spec;
     137                 :            :                         last_spec = 0;
     138                 :            : 
     139                 :            :                         /* next0 */
     140         [ #  # ]:          0 :                         if (next_index == next0) {
     141                 :          0 :                                 to_next[0] = from[0];
     142                 :          0 :                                 to_next++;
     143                 :          0 :                                 held++;
     144                 :            :                         } else {
     145                 :          0 :                                 rte_node_enqueue_x1(graph, node, next0,
     146                 :            :                                                     from[0]);
     147                 :            :                         }
     148                 :            : 
     149                 :            :                         /* next1 */
     150         [ #  # ]:          0 :                         if (next_index == next1) {
     151                 :          0 :                                 to_next[0] = from[1];
     152                 :          0 :                                 to_next++;
     153                 :          0 :                                 held++;
     154                 :            :                         } else {
     155                 :          0 :                                 rte_node_enqueue_x1(graph, node, next1,
     156                 :            :                                                     from[1]);
     157                 :            :                         }
     158                 :            : 
     159                 :            :                         /* next2 */
     160         [ #  # ]:          0 :                         if (next_index == next2) {
     161                 :          0 :                                 to_next[0] = from[2];
     162                 :          0 :                                 to_next++;
     163                 :          0 :                                 held++;
     164                 :            :                         } else {
     165                 :          0 :                                 rte_node_enqueue_x1(graph, node, next2,
     166                 :            :                                                     from[2]);
     167                 :            :                         }
     168                 :            : 
     169                 :            :                         /* next3 */
     170         [ #  # ]:          0 :                         if (next_index == next3) {
     171                 :          0 :                                 to_next[0] = from[3];
     172                 :          0 :                                 to_next++;
     173                 :          0 :                                 held++;
     174                 :            :                         } else {
     175                 :          0 :                                 rte_node_enqueue_x1(graph, node, next3,
     176                 :            :                                                     from[3]);
     177                 :            :                         }
     178                 :            : 
     179                 :          0 :                         from += 4;
     180                 :            : 
     181                 :            :                         /* Change speculation if last two are same */
     182         [ #  # ]:          0 :                         if ((next_index != next3) && (next2 == next3)) {
     183                 :            :                                 /* Put the current speculated node */
     184         [ #  # ]:          0 :                                 rte_node_next_stream_put(graph, node,
     185                 :            :                                                          next_index, held);
     186                 :            :                                 held = 0;
     187                 :            : 
     188                 :            :                                 /* Get next speculated stream */
     189                 :            :                                 next_index = next3;
     190                 :          0 :                                 to_next = rte_node_next_stream_get(
     191                 :            :                                         graph, node, next_index, nb_objs);
     192                 :            :                         }
     193                 :            :                 } else {
     194                 :          0 :                         last_spec += 4;
     195                 :            :                 }
     196                 :            :         }
     197                 :            : 
     198         [ #  # ]:          0 :         while (n_left_from > 0) {
     199                 :          0 :                 mbuf0 = pkts[0];
     200                 :            : 
     201                 :          0 :                 pkts += 1;
     202                 :          0 :                 n_left_from -= 1;
     203                 :            : 
     204         [ #  # ]:          0 :                 d0 = rte_pktmbuf_mtod(mbuf0, void *);
     205                 :          0 :                 rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
     206         [ #  # ]:          0 :                            nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
     207                 :            : 
     208                 :          0 :                 next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
     209                 :            :                 ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
     210                 :            :                                               sizeof(struct rte_ether_hdr));
     211                 :          0 :                 ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
     212                 :            : 
     213         [ #  # ]:          0 :                 if (unlikely(next_index ^ next0)) {
     214                 :            :                         /* Copy things successfully speculated till now */
     215         [ #  # ]:          0 :                         rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
     216                 :          0 :                         from += last_spec;
     217                 :          0 :                         to_next += last_spec;
     218                 :          0 :                         held += last_spec;
     219                 :            :                         last_spec = 0;
     220                 :            : 
     221                 :          0 :                         rte_node_enqueue_x1(graph, node, next0, from[0]);
     222                 :          0 :                         from += 1;
     223                 :            :                 } else {
     224                 :          0 :                         last_spec += 1;
     225                 :            :                 }
     226                 :            :         }
     227                 :            : 
     228                 :            :         /* !!! Home run !!! */
     229         [ #  # ]:          0 :         if (likely(last_spec == nb_objs)) {
     230                 :          0 :                 rte_node_next_stream_move(graph, node, next_index);
     231                 :          0 :                 return nb_objs;
     232                 :            :         }
     233                 :            : 
     234                 :          0 :         held += last_spec;
     235         [ #  # ]:          0 :         rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
     236         [ #  # ]:          0 :         rte_node_next_stream_put(graph, node, next_index, held);
     237                 :            :         /* Save the last next used */
     238                 :          0 :         IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
     239                 :            : 
     240                 :          0 :         return nb_objs;
     241                 :            : }
     242                 :            : 
     243                 :            : static int
     244                 :          0 : ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
     245                 :            : {
     246                 :            :         static bool init_once;
     247                 :            : 
     248                 :            :         RTE_SET_USED(graph);
     249                 :            :         RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
     250                 :            : 
     251         [ #  # ]:          0 :         if (!init_once) {
     252                 :          0 :                 node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
     253                 :            :                                 &node_mbuf_priv1_dynfield_desc);
     254         [ #  # ]:          0 :                 if (node_mbuf_priv1_dynfield_offset < 0)
     255                 :          0 :                         return -rte_errno;
     256                 :          0 :                 init_once = true;
     257                 :            :         }
     258                 :          0 :         IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
     259                 :            : 
     260                 :          0 :         node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
     261                 :            : 
     262                 :          0 :         return 0;
     263                 :            : }
     264                 :            : 
     265                 :            : int
     266                 :          0 : ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
     267                 :            : {
     268         [ #  # ]:          0 :         if (ip6_rewrite_nm == NULL) {
     269                 :          0 :                 ip6_rewrite_nm = rte_zmalloc(
     270                 :            :                         "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
     271                 :            :                         RTE_CACHE_LINE_SIZE);
     272         [ #  # ]:          0 :                 if (ip6_rewrite_nm == NULL)
     273                 :            :                         return -ENOMEM;
     274                 :            :         }
     275                 :          0 :         ip6_rewrite_nm->next_index[port_id] = next_index;
     276                 :            : 
     277                 :          0 :         return 0;
     278                 :            : }
     279                 :            : 
     280                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip6_rewrite_add, 23.07)
     281                 :            : int
     282                 :          0 : rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
     283                 :            :                          uint8_t rewrite_len, uint16_t dst_port)
     284                 :            : {
     285                 :            :         struct ip6_rewrite_nh_header *nh;
     286                 :            : 
     287         [ #  # ]:          0 :         if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
     288                 :            :                 return -EINVAL;
     289                 :            : 
     290         [ #  # ]:          0 :         if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
     291                 :            :                 return -EINVAL;
     292                 :            : 
     293         [ #  # ]:          0 :         if (ip6_rewrite_nm == NULL) {
     294                 :          0 :                 ip6_rewrite_nm = rte_zmalloc(
     295                 :            :                         "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
     296                 :            :                         RTE_CACHE_LINE_SIZE);
     297         [ #  # ]:          0 :                 if (ip6_rewrite_nm == NULL)
     298                 :            :                         return -ENOMEM;
     299                 :            :         }
     300                 :            : 
     301                 :            :         /* Check if dst port doesn't exist as edge */
     302         [ #  # ]:          0 :         if (!ip6_rewrite_nm->next_index[dst_port])
     303                 :            :                 return -EINVAL;
     304                 :            : 
     305                 :            :         /* Update next hop */
     306                 :          0 :         nh = &ip6_rewrite_nm->nh[next_hop];
     307                 :            : 
     308                 :          0 :         memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
     309                 :          0 :         nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
     310                 :          0 :         nh->rewrite_len = rewrite_len;
     311                 :          0 :         nh->enabled = true;
     312                 :            : 
     313                 :          0 :         return 0;
     314                 :            : }
     315                 :            : 
     316                 :            : static struct rte_node_register ip6_rewrite_node = {
     317                 :            :         .process = ip6_rewrite_node_process,
     318                 :            :         .name = "ip6_rewrite",
     319                 :            :         /* Default edge i.e '0' is pkt drop */
     320                 :            :         .nb_edges = 1,
     321                 :            :         .next_nodes = {
     322                 :            :                 [0] = "pkt_drop",
     323                 :            :         },
     324                 :            :         .init = ip6_rewrite_node_init,
     325                 :            : };
     326                 :            : 
     327                 :            : struct rte_node_register *
     328                 :          0 : ip6_rewrite_node_get(void)
     329                 :            : {
     330                 :          0 :         return &ip6_rewrite_node;
     331                 :            : }
     332                 :            : 
     333                 :        252 : RTE_NODE_REGISTER(ip6_rewrite_node);

Generated by: LCOV version 1.14