LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_dpdk_host.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 338 733 46.1 %
Date: 2026-08-03 02:19:58 Functions: 45 68 66.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2014 Semihalf.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU General Public License as
       6             :  * published by the Free Software Foundation version 2.
       7             :  *
       8             :  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
       9             :  * kind, whether express or implied; without even the implied warranty
      10             :  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      11             :  * GNU General Public License for more details.
      12             :  *
      13             :  * vr_dpdk_host.c -- DPDK vrouter module
      14             :  *
      15             :  */
      16             : 
      17             : #include "vr_dpdk.h"
      18             : #include "vr_fragment.h"
      19             : #include "vr_hash.h"
      20             : #include "vr_proto.h"
      21             : #include "vr_sandesh.h"
      22             : #include "vr_dpdk_offloads.h"
      23             : #include "vr_cpuid.h"
      24             : 
      25             : #include <linux/if_ether.h>
      26             : #include <netinet/ip.h>
      27             : #include <netinet/tcp.h>
      28             : #include <sys/user.h>
      29             : #include <sys/resource.h>
      30             : 
      31             : #include <rte_cycles.h>
      32             : #include <rte_errno.h>
      33             : #include <rte_ethdev.h>
      34             : #include <rte_jhash.h>
      35             : #include <rte_malloc.h>
      36             : #include <rte_timer.h>
      37             : #include <rte_hash.h>
      38             : 
      39             : struct dpdk_work_cb_data {
      40             :     void (*dwc_fn)(void *);
      41             :     void *dwc_data;
      42             : };
      43             : 
      44             : /* Max number of CPUs. We adjust it later in vr_dpdk_host_init() */
      45             : unsigned int vr_num_cpus = VR_MAX_CPUS_DPDK;
      46             : 
      47             : /* Global init flag */
      48             : static bool vr_host_inited = false;
      49             : 
      50             : extern void vr_malloc_stats(unsigned int, unsigned int);
      51             : extern void vr_free_stats(unsigned int);
      52             : /* RCU callback */
      53             : extern void vr_flow_defer_cb(struct vrouter *router, void *arg);
      54             : extern void vr_htable_hentry_scheduled_delete(void *arg);
      55             : 
      56             : 
      57             : static void *
      58         703 : dpdk_page_alloc(unsigned int size)
      59             : {
      60         703 :     return rte_malloc(0, size, PAGE_SIZE);
      61             : }
      62             : 
      63             : static void
      64         577 : dpdk_page_free(void *address, unsigned int size)
      65             : {
      66         577 :     rte_free(address);
      67         577 : }
      68             : 
      69             : static int
      70          85 : dpdk_printf(const char *format, ...)
      71             : {
      72             :     va_list args;
      73             : 
      74          85 :     if (RTE_LOGTYPE_DPCORE & rte_logs.type) {
      75          85 :         char buf[VR_DPDK_STR_BUF_SZ] = "DPCORE: ";
      76             : 
      77          85 :         strncat(buf, format, sizeof(buf) - strlen(buf) - 1);
      78          85 :         buf[sizeof(buf) - 1] = '\0';
      79             : 
      80          85 :         va_start(args, format);
      81          85 :         rte_vlog(RTE_LOG_INFO, RTE_LOGTYPE_DPCORE, buf, args);
      82          85 :         va_end(args);
      83             :     }
      84             : 
      85          85 :     return 0;
      86             : }
      87             : 
      88             : static void *
      89        6463 : dpdk_malloc(unsigned int size, unsigned int object)
      90             : {
      91             :     struct vr_malloc_md *md;
      92             :     void *mem;
      93             : 
      94        6463 :     if (!size)
      95           0 :         return NULL;
      96             : 
      97        6463 :     if (vr_memory_alloc_checks) {
      98           0 :         size += sizeof(*md);
      99             :     }
     100             : 
     101        6463 :     mem = rte_malloc(NULL, size, 0);
     102        6463 :     if (likely(mem != NULL)) {
     103        6463 :         vr_malloc_stats(size, object);
     104             : 
     105        6463 :         if (vr_memory_alloc_checks) {
     106           0 :             vr_malloc_md_set(mem, object);
     107           0 :             mem = (uint8_t *)mem + sizeof(*md);
     108             :         }
     109             :     }
     110             : 
     111        6463 :     return mem;
     112             : }
     113             : 
     114             : static void *
     115      237666 : dpdk_zalloc(unsigned int size, unsigned int object)
     116             : {
     117             :     struct vr_malloc_md *md;
     118             :     void *mem;
     119             : 
     120      237666 :     if (!size)
     121           0 :         return NULL;
     122             : 
     123      237666 :     if (vr_memory_alloc_checks) {
     124           0 :         size += sizeof(*md);
     125             :     }
     126             : 
     127      237666 :     mem = rte_zmalloc(NULL, size, 0);
     128      237666 :     if (likely(mem != NULL)) {
     129      237666 :         vr_malloc_stats(size, object);
     130             : 
     131      237666 :         if (vr_memory_alloc_checks) {
     132           0 :             vr_malloc_md_set(mem, object);
     133           0 :             mem = (uint8_t *)mem + sizeof(*md);
     134             :         }
     135             :     }
     136             : 
     137      237666 :     return mem;
     138             : }
     139             : 
     140             : static void
     141      240821 : dpdk_free(void *mem, unsigned int object)
     142             : {
     143      240821 :     if (mem) {
     144      240821 :         if (vr_memory_alloc_checks) {
     145           0 :             vr_malloc_md_check(mem, object);
     146             :         }
     147             : 
     148      240821 :         vr_free_stats(object);
     149             : 
     150      240821 :         if (vr_memory_alloc_checks) {
     151           0 :             mem = (uint8_t *)mem - sizeof(struct vr_malloc_md);
     152             :         }
     153             : 
     154      240821 :         rte_free(mem);
     155             :     }
     156             : 
     157      240821 :     return;
     158             : }
     159             : 
     160             : static uint64_t
     161           0 : dpdk_vtop(void *address)
     162             : {
     163             :     /* TODO: not used */
     164           0 :     rte_panic("%s: not used in DPDK mode\n", __func__);
     165             : 
     166             :     return (uint64_t)0;
     167             : }
     168             : 
     169             : static struct vr_packet *
     170           0 : dpdk_palloc(unsigned int size)
     171             : {
     172             :     struct rte_mbuf *m;
     173             : 
     174             :     /* in DPDK we have fixed-sized mbufs only */
     175           0 :     RTE_VERIFY(size <= vr_packet_sz);
     176           0 :     m = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     177           0 :     if (!m)
     178           0 :         return (NULL);
     179             : 
     180           0 :     return vr_dpdk_packet_get(m, NULL);
     181             : }
     182             : 
     183             : static struct vr_packet *
     184           0 : dpdk_palloc_head(struct vr_packet *pkt, unsigned int size)
     185             : {
     186             :     /* TODO: not implemented */
     187           0 :     RTE_LOG(ERR, VROUTER, "%s: not implemented\n", __func__);
     188           0 :     return NULL;
     189             : }
     190             : 
     191             : static struct vr_packet *
     192           0 : dpdk_pexpand_head(struct vr_packet *pkt, unsigned int hspace)
     193             : {
     194             :     /* TODO: not implemented */
     195           0 :     return pkt;
     196             : }
     197             : 
     198             : static void
     199          39 : dpdk_pfree(struct vr_packet *pkt, unsigned short reason)
     200             : {
     201          39 :     if (pkt) {
     202             :         /* Handle Vrouter statistics */
     203          39 :         pkt_drop_stats(pkt->vp_if, reason, rte_lcore_id());
     204             : 
     205          39 :         rte_pktmbuf_free(vr_dpdk_pkt_to_mbuf(pkt));
     206             :     }
     207          39 : }
     208             : 
     209             : void
     210           0 : vr_dpdk_pfree(struct rte_mbuf *mbuf, struct vr_interface *vif, unsigned short reason)
     211             : {
     212           0 :     struct vr_packet *pkt = vr_dpdk_mbuf_to_pkt(mbuf);
     213           0 :     vr_dpdk_packet_get(mbuf, vif);
     214           0 :     dpdk_pfree(pkt, reason);
     215           0 : }
     216             : 
     217             : 
     218             : static void
     219          42 : dpdk_preset(struct vr_packet *pkt)
     220             : {
     221             :     struct rte_mbuf *m;
     222             : 
     223          42 :     if (!pkt)
     224           0 :         rte_panic("%s: NULL pkt", __func__);
     225             : 
     226          42 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     227             : 
     228             :     /* Reset packet data */
     229          42 :     pkt->vp_data = rte_pktmbuf_headroom(m);
     230          42 :     pkt->vp_tail = rte_pktmbuf_headroom(m) + rte_pktmbuf_data_len(m);
     231          42 :     pkt->vp_len = rte_pktmbuf_data_len(m);
     232             : 
     233          42 :     return;
     234             : }
     235             : 
     236             : /**
     237             :  * Copy packet mbuf data to another packet mbuf.
     238             : *
     239             :  * @param dst
     240             :  *   The destination packet mbuf.
     241             :  * @param src
     242             :  *   The source packet mbuf.
     243             :  */
     244             : 
     245             : static inline void
     246           6 : dpdk_pktmbuf_data_copy(struct rte_mbuf *dst, struct rte_mbuf *src)
     247             : {
     248           6 :     dst->data_off = src->data_off;
     249           6 :     dst->port = src->port;
     250           6 :     dst->ol_flags = src->ol_flags;
     251             : #ifdef IND_ATTACHED_MBUF
     252           6 :     dst->ol_flags &= (~IND_ATTACHED_MBUF);
     253             : #endif
     254           6 :     dst->packet_type = src->packet_type;
     255           6 :     dst->data_len = src->data_len;
     256           6 :     dst->pkt_len = src->pkt_len;
     257           6 :     dst->vlan_tci = src->vlan_tci;
     258           6 :     dst->hash = src->hash;
     259           6 :     dst->seqn = src->seqn;
     260           6 :     dst->userdata = src->userdata;
     261           6 :     dst->tx_offload = src->tx_offload;
     262             : 
     263             :     __rte_mbuf_sanity_check(dst, 1);
     264             :     __rte_mbuf_sanity_check(src, 0);
     265             : 
     266             :     /* copy data */
     267           6 :     rte_memcpy(rte_pktmbuf_mtod(dst, void *),
     268           6 :             rte_pktmbuf_mtod(src, void *), src->data_len);
     269           6 : }
     270             : 
     271             : /**
     272             :  * Creates a copy of the given packet mbuf.
     273             :  * TODO: remove once rte_pktmbuf_copy() is in DPDK
     274             :  *
     275             :  * Walks through all segments of the given packet mbuf, and for each of them:
     276             :  *  - Creates a new packet mbuf from the given pool.
     277             :  *  - Copies data to the newly created mbuf.
     278             :  * Then updates pkt_len and nb_segs of the "copy" packet mbuf to match values
     279             :  * from the original packet mbuf.
     280             :  *
     281             :  * @param md
     282             :  *   The packet mbuf to be copied.
     283             :  * @param mp
     284             :  *   The mempool from which the "copy" mbufs are allocated.
     285             :  * @return
     286             :  *   - The pointer to the new "copy" mbuf on success.
     287             :  *   - NULL if allocation fails.
     288             :  */
     289             : inline struct rte_mbuf *
     290           6 : vr_dpdk_pktmbuf_copy(struct rte_mbuf *md, struct rte_mempool *mp)
     291             : {
     292             :     struct rte_mbuf *mc, *mi, **prev;
     293             :     uint32_t pktlen;
     294             :     uint8_t nseg;
     295             : 
     296           6 :     if (unlikely ((mc = rte_pktmbuf_alloc(mp)) == NULL))
     297           0 :         return (NULL);
     298             : 
     299           6 :     mi = mc;
     300           6 :     prev = &mi->next;
     301           6 :     pktlen = md->pkt_len;
     302           6 :     nseg = 0;
     303             : 
     304             :     do {
     305           6 :         nseg++;
     306           6 :         dpdk_pktmbuf_data_copy(mi, md);
     307           6 :         *prev = mi;
     308           6 :         prev = &mi->next;
     309           6 :     } while ((md = md->next) != NULL &&
     310           0 :         (mi = rte_pktmbuf_alloc(mp)) != NULL);
     311             : 
     312           6 :     *prev = NULL;
     313           6 :     mc->nb_segs = nseg;
     314           6 :     mc->pkt_len = pktlen;
     315             : 
     316             :     /* Allocation of new indirect segment failed */
     317           6 :     if (unlikely (mi == NULL)) {
     318           0 :         rte_pktmbuf_free(mc);
     319           0 :         return (NULL);
     320             :     }
     321             : 
     322             :     __rte_mbuf_sanity_check(mc, 1);
     323           6 :     return (mc);
     324             : }
     325             : 
     326             : /**
     327             :  * Creates a copy of the given packet mbuf.
     328             :  *
     329             :  * Creates a new packet mbuf from the given pool.
     330             :  * Walks through all segments of the given packet mbuf, and appends them
     331             :  * in the new packet upto the size of the new packet and ignores the rest.
     332             :  * This needs to be done because KNI doesn't handle mbuf chains.
     333             :  *
     334             :  * @param md
     335             :  *   The packet mbuf to be copied.
     336             :  * @param mp
     337             :  *   The mempool from which the "copy" mbufs are allocated.
     338             :  * @return
     339             :  *   - The pointer to the new "copy" mbuf on success.
     340             :  *   - NULL if allocation fails.
     341             :  */
     342             : 
     343             : inline struct rte_mbuf *
     344           0 : vr_dpdk_pktmbuf_copy_mon(struct rte_mbuf *md, struct rte_mempool *mp)
     345             : {
     346             :     struct rte_mbuf *mc;
     347             :     char *append_ptr;
     348             :     uint32_t append_len;
     349             : 
     350           0 :     if (unlikely ((mc = rte_pktmbuf_alloc(mp)) == NULL))
     351           0 :         return (NULL);
     352             : 
     353           0 :     dpdk_pktmbuf_data_copy(mc, md);
     354           0 :     mc->pkt_len = md->data_len;
     355             : 
     356           0 :     while (md->next)
     357             :     {
     358           0 :         md = md->next;
     359           0 :         append_ptr = rte_pktmbuf_append(mc, md->data_len);
     360           0 :         append_len = (append_ptr)? md->data_len : rte_pktmbuf_tailroom(mc);
     361           0 :         if (append_ptr == NULL) {
     362           0 :             append_ptr = rte_pktmbuf_append(mc, rte_pktmbuf_tailroom(mc));
     363           0 :             rte_memcpy(append_ptr, rte_pktmbuf_mtod(md, void*), append_len);
     364           0 :             break;
     365             :         }
     366           0 :         rte_memcpy(append_ptr, rte_pktmbuf_mtod(md, void*), append_len);
     367             :     }
     368             : 
     369           0 :     mc->nb_segs = 1;
     370             : 
     371             :     __rte_mbuf_sanity_check(mc, 1);
     372           0 :     return (mc);
     373             : }
     374             : 
     375             : /* VRouter callback */
     376             : static struct vr_packet *
     377          16 : dpdk_pclone(struct vr_packet *pkt)
     378             : {
     379             :     struct rte_mbuf *m, *m_clone;
     380             :     struct vr_packet *pkt_clone;
     381             : 
     382          16 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     383             : 
     384          16 :     m_clone = rte_pktmbuf_clone(m, vr_dpdk.rss_mempool);
     385          16 :     if (!m_clone)
     386           0 :         return NULL;
     387             : 
     388             :     /* clone vr_packet data */
     389          16 :     pkt_clone = vr_dpdk_mbuf_to_pkt(m_clone);
     390          16 :     *pkt_clone = *pkt;
     391          16 :     pkt_clone->vp_cpu = vr_get_cpu();
     392             : 
     393          16 :     return pkt_clone;
     394             : }
     395             : 
     396             : /* Copy the specified number of bytes from the source mbuf to the
     397             :  * destination buffer.
     398             :  */
     399             : static int
     400           0 : dpdk_pktmbuf_copy_bits(const struct rte_mbuf *mbuf, int offset,
     401             :     void *to, int len)
     402             : {
     403             :     /* how many bytes to copy in loop */
     404           0 :     int copy = 0;
     405             :     /* loop pointer to a source data */
     406             :     void *from;
     407             : 
     408             :     /* check total packet length */
     409           0 :     if (unlikely(offset > (int)rte_pktmbuf_pkt_len(mbuf) - len))
     410           0 :         goto fault;
     411             : 
     412           0 :     do {
     413           0 :         if (offset < rte_pktmbuf_data_len(mbuf)) {
     414             :             /* copy a piece of data */
     415           0 :             from = (void *)(rte_pktmbuf_mtod_offset(mbuf, uintptr_t, offset));
     416           0 :             copy = rte_pktmbuf_data_len(mbuf) - offset;
     417           0 :             if (copy > len)
     418           0 :                 copy = len;
     419           0 :             rte_memcpy(to, from, copy);
     420           0 :             offset = 0;
     421             :         } else {
     422           0 :             offset -= rte_pktmbuf_data_len(mbuf);
     423             :         }
     424             :         /* get next mbuf */
     425           0 :         to += copy;
     426           0 :         len -= copy;
     427           0 :         mbuf = mbuf->next;
     428           0 :     } while (unlikely(len > 0 && NULL != mbuf));
     429             : 
     430           0 :     if (likely(0 == len))
     431           0 :         return 0;
     432             : 
     433           0 : fault:
     434           0 :     return -EFAULT;
     435             : }
     436             : 
     437             : /* VRouter callback */
     438             : static int
     439           0 : dpdk_pcopy(unsigned char *dst, struct vr_packet *p_src,
     440             :     unsigned int offset, unsigned int len)
     441             : {
     442             :     int ret;
     443             :     struct rte_mbuf *src;
     444             : 
     445           0 :     src = vr_dpdk_pkt_to_mbuf(p_src);
     446           0 :     ret = dpdk_pktmbuf_copy_bits(src, offset, dst, len);
     447           0 :     if (ret)
     448           0 :         return ret;
     449             : 
     450           0 :     return len;
     451             : }
     452             : 
     453             : static unsigned short
     454         771 : dpdk_pfrag_len(struct vr_packet *pkt)
     455             : {
     456             :     struct rte_mbuf *m;
     457             : 
     458         771 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     459             : 
     460         771 :     return rte_pktmbuf_pkt_len(m) - rte_pktmbuf_data_len(m);
     461             : }
     462             : 
     463             : static unsigned short
     464           3 : dpdk_phead_len(struct vr_packet *pkt)
     465             : {
     466             :     struct rte_mbuf *m;
     467             : 
     468           3 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     469             : 
     470           3 :     return rte_pktmbuf_data_len(m);
     471             : }
     472             : 
     473             : static void
     474           1 : dpdk_pset_data(struct vr_packet *pkt, unsigned short offset)
     475             : {
     476             :     struct rte_mbuf *m;
     477             : 
     478           1 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     479           1 :     m->buf_addr = pkt->vp_head;
     480           1 :     m->data_off = offset;
     481             : 
     482           1 :     return;
     483             : }
     484             : 
     485             : static unsigned int
     486     2107028 : dpdk_get_cpu(void)
     487             : {
     488     2107028 :     unsigned lcore_id = rte_lcore_id();
     489             : 
     490             :     /* For the RCU thread we get LCORE_ID_ANY, so memory stats and
     491             :      * other functions get crashed trying to index per-cpu data.
     492             :      */
     493     2106746 :     if (lcore_id < vr_num_cpus)
     494     2105142 :         return lcore_id;
     495             :     else
     496        1604 :         return 0;
     497             : }
     498             : 
     499             : /* DPDK timer callback */
     500             : static void
     501        6334 : dpdk_timer(struct rte_timer *tim, void *arg)
     502             : {
     503        6334 :     struct vr_timer *vtimer = (struct vr_timer*)arg;
     504             : 
     505        6334 :     vtimer->vt_timer(vtimer->vt_vr_arg);
     506        6334 : }
     507             : 
     508             : static int
     509          53 : dpdk_create_timer(struct vr_timer *vtimer)
     510             : {
     511             :     struct rte_timer *timer;
     512             :     uint64_t hz, ticks;
     513             : 
     514          53 :     timer = rte_zmalloc("vr_dpdk_timer", sizeof(struct rte_timer), 0);
     515             : 
     516          53 :     if (!timer) {
     517           0 :         RTE_LOG(ERR, VROUTER, "Error allocating RTE timer\n");
     518           0 :         return -1;
     519             :     }
     520             : 
     521             :     /* init timer */
     522          53 :     rte_timer_init(timer);
     523          53 :     vtimer->vt_os_arg = (void *)timer;
     524             : 
     525             :     /* reset timer */
     526          53 :     hz = rte_get_timer_hz();
     527          53 :     ticks = hz * vtimer->vt_msecs / 1000;
     528          53 :     if (rte_timer_reset(timer, ticks, PERIODICAL, VR_DPDK_TIMER_LCORE_ID,
     529             :         dpdk_timer, vtimer) == -1) {
     530           0 :         RTE_LOG(ERR, VROUTER, "Error resetting timer\n");
     531           0 :         rte_free(timer);
     532             : 
     533           0 :         return -1;
     534             :     }
     535             : 
     536          53 :     return 0;
     537             : }
     538             : 
     539             : static void
     540          53 : dpdk_delete_timer(struct vr_timer *vtimer)
     541             : {
     542          53 :     struct rte_timer *timer = (struct rte_timer*)vtimer->vt_os_arg;
     543             : 
     544          53 :     if (timer) {
     545          53 :         rte_timer_stop_sync(timer);
     546          53 :         rte_free(timer);
     547             :     } else {
     548           0 :         RTE_LOG(ERR, VROUTER, "No timer to delete\n");
     549             :     }
     550          53 : }
     551             : 
     552             : static void
     553          42 : dpdk_get_time(uint64_t *sec, uint64_t *usec)
     554             : {
     555             :     struct timespec ts;
     556             : 
     557          42 :     *sec = *usec = 0;
     558          42 :     if (-1 == clock_gettime(CLOCK_REALTIME, &ts))
     559           0 :         return;
     560             : 
     561          42 :     *sec = ts.tv_sec;
     562          42 :     *usec = ts.tv_nsec / 1000;
     563             : 
     564          42 :     return;
     565             : }
     566             : 
     567             : static void
     568        2412 : dpdk_get_mono_time(uint64_t *sec, uint64_t *nsec)
     569             : {
     570             :     struct timespec ts;
     571             : 
     572        2412 :     *sec = *nsec = 0;
     573        2412 :     if (-1 == clock_gettime(CLOCK_MONOTONIC, &ts))
     574           0 :         return;
     575             : 
     576        2412 :     *sec = ts.tv_sec;
     577        2412 :     *nsec = ts.tv_nsec;
     578             : 
     579        2412 :     return;
     580             : }
     581             : 
     582             : static void
     583           0 : dpdk_htable_work_cb(struct vrouter *router __attribute__((unused)), void *arg)
     584             : {
     585           0 :     struct dpdk_work_cb_data *defer = (struct dpdk_work_cb_data *)arg;
     586           0 :     defer->dwc_fn(defer->dwc_data);
     587             : 
     588           0 :     return;
     589             : }
     590             : 
     591             : /* Work callback called on NetLink lcore */
     592             : static int
     593         318 : dpdk_schedule_work(unsigned int cpu, void (*fn)(void *), void *arg)
     594             : {
     595             :     struct dpdk_work_cb_data *defer;
     596             : 
     597         318 :     if (!fn)
     598           0 :         return -1;
     599             : 
     600             :     /*
     601             :      * Fix ME:
     602             :      * Use RCU to defer the work only for hash tables. Rest all, invoke
     603             :      * function as is
     604             :      * This is a temporary fix to ensure that hash table deletion does
     605             :      * not happen parrallely in different CPU's
     606             :      */
     607             : 
     608         318 :     if (fn == vr_htable_hentry_scheduled_delete) {
     609           0 :         defer = vr_get_defer_data(sizeof(*defer));
     610           0 :         if (!defer)
     611           0 :             return -1;
     612             : 
     613           0 :         defer->dwc_fn = fn;
     614           0 :         defer->dwc_data = arg;
     615           0 :         vr_defer(NULL, dpdk_htable_work_cb, defer);
     616             : 
     617           0 :         return 0;
     618             :     }
     619             : 
     620         318 :     fn(arg);
     621             : 
     622         318 :     return 0;
     623             : }
     624             : 
     625             : static void
     626         394 : dpdk_delay_op(void)
     627             : {
     628         394 :     synchronize_rcu();
     629             : 
     630         394 :     return;
     631             : }
     632             : 
     633             : /* RCU callback called on RCU thread */
     634             : static void
     635         257 : dpdk_rcu_cb(struct rcu_head *rh)
     636             : {
     637             :     int i;
     638             :     struct vr_dpdk_rcu_cb_data *cb_data;
     639             :     struct vr_defer_data *defer;
     640             :     struct vr_flow_queue *vfq;
     641             :     struct vr_packet_node *pnode;
     642             : 
     643             : 
     644         257 :     cb_data = CONTAINER_OF(rcd_rcu, struct vr_dpdk_rcu_cb_data, rh);
     645             : 
     646             :     /* check if we need to pass the callback to packet lcore */
     647         257 :     if ((cb_data->rcd_user_cb == vr_flow_defer_cb) &&
     648             :             cb_data->rcd_user_data) {
     649           6 :         defer = (struct vr_defer_data *)cb_data->rcd_user_data;
     650           6 :         vfq = ((struct vr_flow_defer_data *)defer->vdd_data)->vfdd_flow_queue;
     651           6 :         if (vfq) {
     652           8 :             for (i = 0; i < VR_MAX_FLOW_QUEUE_ENTRIES; i++) {
     653           6 :                 pnode = &vfq->vfq_pnodes[i];
     654           6 :                 if (pnode->pl_packet) {
     655             :                     RTE_LOG_DP(DEBUG, VROUTER, "%s: lcore %u passing RCU callback "
     656             :                             "to lcore %u\n", __func__, rte_lcore_id(),
     657             :                             VR_DPDK_PACKET_LCORE_ID);
     658           0 :                     vr_dpdk_lcore_cmd_post(VR_DPDK_PACKET_LCORE_ID,
     659             :                             VR_DPDK_LCORE_RCU_CMD, (uintptr_t)rh);
     660           0 :                     return;
     661             :                 }
     662             :             }
     663             :             RTE_LOG_DP(DEBUG, VROUTER, "%s: lcore %u passing RCU callback to lcore %u\n",
     664             :                     __func__, rte_lcore_id(), VR_DPDK_PACKET_LCORE_ID);
     665             :         }
     666             :     }
     667             :     /* no need to send any packets, so just call the callback */
     668         257 :     cb_data->rcd_user_cb(cb_data->rcd_router, cb_data->rcd_user_data);
     669         257 :     vr_free(cb_data, VR_DEFER_OBJECT);
     670             : }
     671             : 
     672             : static void
     673         257 : dpdk_defer(struct vrouter *router, vr_defer_cb user_cb, void *data)
     674             : {
     675             :     struct vr_dpdk_rcu_cb_data *cb_data;
     676             : 
     677         257 :     cb_data = CONTAINER_OF(rcd_user_data, struct vr_dpdk_rcu_cb_data, data);
     678         257 :     cb_data->rcd_user_cb = user_cb;
     679         257 :     cb_data->rcd_router = router;
     680         257 :     call_rcu(&cb_data->rcd_rcu, dpdk_rcu_cb);
     681         257 : }
     682             : 
     683             : static void *
     684         257 : dpdk_get_defer_data(unsigned int len)
     685             : {
     686             :     struct vr_dpdk_rcu_cb_data *cb_data;
     687             : 
     688         257 :     if (!len)
     689           0 :         return NULL;
     690             : 
     691         257 :     cb_data = dpdk_malloc(sizeof(*cb_data) + len, VR_DEFER_OBJECT);
     692         257 :     if (!cb_data) {
     693           0 :         return NULL;
     694             :     }
     695             : 
     696         257 :     return cb_data->rcd_user_data;
     697             : }
     698             : 
     699             : static void
     700           0 : dpdk_put_defer_data(void *data)
     701             : {
     702             :     struct vr_dpdk_rcu_cb_data *cb_data;
     703             : 
     704           0 :     if (!data)
     705           0 :         return;
     706             : 
     707           0 :     cb_data = CONTAINER_OF(rcd_user_data, struct vr_dpdk_rcu_cb_data, data);
     708           0 :     dpdk_free(cb_data, VR_DEFER_OBJECT);
     709             : 
     710           0 :     return;
     711             : }
     712             : 
     713             : static void *
     714           0 : dpdk_network_header(struct vr_packet *pkt)
     715             : {
     716           0 :     if (pkt->vp_network_h < pkt->vp_end)
     717           0 :         return pkt->vp_head + pkt->vp_network_h;
     718             : 
     719             :     /* TODO: for buffer chain? */
     720           0 :     rte_panic("%s: buffer chain not supported\n", __func__);
     721             : 
     722             :     return NULL;
     723             : }
     724             : 
     725             : static void *
     726           0 : dpdk_inner_network_header(struct vr_packet *pkt)
     727             : {
     728             :     /* TODO: not used? */
     729           0 :     rte_panic("%s: not implemented\n", __func__);
     730             : 
     731             :     return NULL;
     732             : }
     733             : 
     734             : static void *
     735           0 : dpdk_data_at_offset(struct vr_packet *pkt, unsigned short off)
     736             : {
     737           0 :     if (off < pkt->vp_end)
     738           0 :         return pkt->vp_head + off;
     739             : 
     740             :     /* TODO: for buffer chain? */
     741           0 :     rte_panic("%s: buffer chain not supported\n", __func__);
     742             : 
     743             :     return NULL;
     744             : }
     745             : 
     746             : /*
     747             :  * dpdk_pheader_pointer
     748             :  * return pointer to data at pkt->vp_data offset if hdr_len bytes
     749             :  * in continuous memory, otherwise copy data to buf
     750             :  */
     751             : static void *
     752           9 : dpdk_pheader_pointer(struct vr_packet *pkt, unsigned short hdr_len, void *buf)
     753             : {
     754             :     struct rte_mbuf *m;
     755             :     int offset;
     756             : 
     757           9 :     m = vr_dpdk_pkt_to_mbuf(pkt);
     758             : 
     759             :     /*
     760             :      * vp_data is offset from start of buffer,
     761             :      * so first calculate offset from start of mbuf payload
     762             :      */
     763           9 :     offset = pkt->vp_data - rte_pktmbuf_headroom(m);
     764           9 :     if ((offset + hdr_len) < rte_pktmbuf_data_len(m))
     765           9 :         return (void *)((uintptr_t)m->buf_addr + pkt->vp_data);
     766             :     else {
     767           0 :         int len = rte_pktmbuf_data_len(m) - offset;
     768           0 :         void *tmp_buf = buf;
     769             : 
     770           0 :         rte_memcpy(tmp_buf, rte_pktmbuf_mtod_offset(m, char *, offset), len);
     771           0 :         hdr_len -= len;
     772           0 :         tmp_buf = (void *)((uintptr_t)tmp_buf + len);
     773             : 
     774             :         /* iterate thru buffers chain */
     775           0 :         while (hdr_len) {
     776           0 :             m = m->next;
     777           0 :             if (!m)
     778           0 :                 return (NULL);
     779           0 :             if (hdr_len > rte_pktmbuf_data_len(m))
     780           0 :                 len = rte_pktmbuf_data_len(m);
     781             :             else
     782           0 :                 len = hdr_len;
     783             : 
     784           0 :             rte_memcpy(tmp_buf, rte_pktmbuf_mtod(m, void *), len);
     785             : 
     786           0 :             tmp_buf = (void *)((uintptr_t)tmp_buf + len);
     787           0 :             hdr_len -= len;
     788             :         }
     789             : 
     790           0 :         return (buf);
     791             :     }
     792             : }
     793             : 
     794             : /* VRouter callback */
     795             : static int
     796           6 : dpdk_pcow(struct vr_packet **pktp, unsigned short head_room)
     797             : {
     798           6 :     struct vr_packet *pkt = *pktp;
     799           6 :     struct rte_mbuf *mbuf = vr_dpdk_pkt_to_mbuf(pkt);
     800             :     struct rte_mbuf *m_copy;
     801             :     struct vr_packet *p_copy;
     802             :     struct rte_mbuf *mbuf_new;
     803             : 
     804             :     /*
     805             :      * If this is an indirect mbuf, allocate a new mbuf and copy
     806             :      * its data. Then free the original mbuf.
     807             :      */
     808           6 :     if (RTE_MBUF_CLONED(mbuf)) {
     809           6 :         m_copy = vr_dpdk_pktmbuf_copy(mbuf, mbuf->pool);
     810           6 :         if (!m_copy) {
     811           0 :             return -ENOMEM;
     812             :         }
     813             : 
     814           6 :         p_copy = vr_dpdk_mbuf_to_pkt(m_copy);
     815           6 :         *p_copy = *pkt;
     816           6 :         p_copy->vp_head = m_copy->buf_addr;
     817             : 
     818           6 :         rte_pktmbuf_free(mbuf);
     819           6 :         mbuf = m_copy;
     820           6 :         *pktp = p_copy;
     821             :     }
     822             : 
     823           6 :     if (head_room > rte_pktmbuf_headroom(mbuf)) {
     824             : 
     825             :         /* When requested headroom is higher than configured pktmuf_headroom,
     826             :          * Create a new memory buffer and link to the old mbuf */
     827           0 :         mbuf_new = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     828           0 :         if (!mbuf_new) {
     829           0 :             return -ENOMEM;
     830             :         }
     831             : 
     832           0 :         pkt = vr_dpdk_packet_get(mbuf_new, pkt->vp_if);
     833           0 :         if(!pkt)
     834           0 :             return -ENOMEM;
     835             : 
     836           0 :         mbuf_new->next = mbuf;
     837           0 :         mbuf_new->nb_segs++;
     838           0 :         mbuf_new->ol_flags = mbuf->ol_flags;
     839           0 :         mbuf_new->data_off += head_room;
     840           0 :         mbuf_new->pkt_len +=  mbuf->data_len;
     841             : 
     842           0 :         pkt->vp_data = mbuf_new->data_off;
     843           0 :         *pktp = pkt;
     844             :     }
     845             : 
     846           6 :     return 0;
     847             : }
     848             : 
     849             : /*
     850             :  * dpdk_get_udp_src_port - return a source port for the outer UDP header.
     851             :  * The source port is based on a hash of the inner IP source/dest addresses,
     852             :  * vrf (and inner TCP/UDP ports in the future). The label from fmd
     853             :  * will be used in the future to detect whether it is a L2/L3 packet.
     854             :  * Returns 0 on error, valid source port otherwise.
     855             :  *
     856             :  * Based on linux/vrouter_mod.c:lh_get_udp_src_port
     857             :  * Copyright (c) 2013, 2014 Juniper Networks, Inc.
     858             :  */
     859             : static uint16_t
     860          38 : dpdk_get_udp_src_port(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
     861             :     unsigned short vrf)
     862             : {
     863          38 :     struct rte_mbuf *mbuf = vr_dpdk_pkt_to_mbuf(pkt);
     864             :     unsigned int pull_len;
     865             :     uint32_t ip_src, ip_dst, hashval, port_range;
     866             :     struct vr_ip *iph;
     867             :     uint16_t port;
     868          38 :     uint16_t sport = 0, dport = 0;
     869             :     struct vr_fragment *frag;
     870          38 :     struct vrouter *router = vrouter_get(0);
     871             :     uint32_t hash_key[5];
     872             :     uint16_t *l4_hdr;
     873             :     struct vr_flow_entry *fentry;
     874             : 
     875          38 :     if (likely(mbuf->ol_flags & PKT_RX_RSS_HASH)) {
     876          36 :         hashval = mbuf->hash.rss;
     877             :     } else {
     878           2 :         if (unlikely(hashrnd_inited == 0)) {
     879           0 :             vr_hashrnd = random();
     880           0 :             hashrnd_inited = 1;
     881             :         }
     882             : 
     883           2 :         if (pkt->vp_type == VP_TYPE_IP) {
     884             :             /* Ideally the below code is only for VP_TYPE_IP and not
     885             :              * for IP6. But having explicit check for IP only break IP6
     886             :              */
     887           0 :             pull_len = sizeof(struct iphdr);
     888           0 :             pull_len += pkt_get_network_header_off(pkt);
     889           0 :             pull_len -= rte_pktmbuf_headroom(mbuf);
     890             : 
     891             :             /* It's safe to assume the ip hdr is within this mbuf, so we skip
     892             :              * all the header checks.
     893             :              */
     894             : 
     895           0 :             iph = (struct vr_ip *)(mbuf->buf_addr + pkt_get_network_header_off(pkt));
     896           0 :             if (vr_ip_transport_header_valid(iph)) {
     897           0 :                 if ((iph->ip_proto == VR_IP_PROTO_TCP) ||
     898           0 :                             (iph->ip_proto == VR_IP_PROTO_UDP)) {
     899           0 :                     l4_hdr = (__u16 *) (((char *) iph) + (iph->ip_hl * 4));
     900           0 :                     sport = *l4_hdr;
     901           0 :                     dport = *(l4_hdr+1);
     902             :                 }
     903             :             } else {
     904             :                 /*
     905             :                  * If this fragment required flow lookup, get the source and
     906             :                  * dst port from the frag entry. Otherwise, use 0 as the source
     907             :                  * dst port (which could result in fragments getting a different
     908             :                  * outer UDP source port than non-fragments in the same flow).
     909             :                  */
     910           0 :                 frag = vr_fragment_get(router, vrf, iph, 0);
     911           0 :                 if (frag) {
     912           0 :                     sport = frag->f_sport;
     913           0 :                     dport = frag->f_dport;
     914             :                 }
     915             :             }
     916             : 
     917           0 :             if (fmd && fmd->fmd_flow_index >= 0) {
     918           0 :                 fentry = vr_flow_get_entry(router, fmd->fmd_flow_index);
     919           0 :                 if (fentry) {
     920           0 :                     vr_dpdk_mbuf_reset(pkt);
     921           0 :                     return fentry->fe_udp_src_port;
     922             :                 }
     923             :             }
     924             : 
     925           0 :             ip_src = iph->ip_saddr;
     926           0 :             ip_dst = iph->ip_daddr;
     927             : 
     928           0 :             hash_key[0] = ip_src;
     929           0 :             hash_key[1] = ip_dst;
     930           0 :             hash_key[2] = vrf;
     931           0 :             hash_key[3] = sport;
     932           0 :             hash_key[4] = dport;
     933             : 
     934           0 :             hashval = rte_jhash(hash_key, 20, vr_hashrnd);
     935           0 :             vr_dpdk_mbuf_reset(pkt);
     936             :         } else {
     937             : 
     938             :             /* We treat all non-ip packets as L2 here. For V6 we can extract
     939             :              * the required fieleds explicity and manipulate the src port
     940             :              */
     941             : 
     942           2 :             if (pkt_head_len(pkt) < ETH_HLEN)
     943           0 :                 goto error;
     944             : 
     945           2 :             hashval = vr_hash(pkt_data(pkt), ETH_HLEN, vr_hashrnd);
     946             :             /* Include the VRF to calculate the hash */
     947           2 :             hashval = vr_hash_2words(hashval, vrf, vr_hashrnd);
     948             :         }
     949             :     } /* !PKT_RX_RSS_HASH */
     950             : 
     951             : 
     952             :     /*
     953             :      * Convert the hash value to a value in the port range that we want
     954             :      * for dynamic UDP ports
     955             :      */
     956          38 :     port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
     957          38 :     port = (uint16_t) (((uint64_t) hashval * port_range) >> 32);
     958             : 
     959          38 :     if (unlikely(port > port_range)) {
     960             :         /*
     961             :          * Shouldn't happen...
     962             :          */
     963           0 :         port = 0;
     964             :     }
     965             : 
     966          38 :     return (port + VR_MUDP_PORT_RANGE_START);
     967             : 
     968           0 : error:
     969           0 :     vr_dpdk_mbuf_reset(pkt);
     970           0 :     return 0;
     971             : }
     972             : 
     973             : /**
     974             :  * dpdk_adjust_tcp_mss - helper adjusting TCP Maximum Segment Size, used in
     975             :  * dpdk_pkt_from_vm_tcp_mss_adj vRouter callback for packets from the VM and in
     976             :  * vr_ip_transport_parse to perform MSS adjust for packets sent to the VM.
     977             :  */
     978             : void
     979           0 : dpdk_adjust_tcp_mss(struct tcphdr *tcph, unsigned short overlay_len,
     980             :                     unsigned char iph_len)
     981             : {
     982           0 :     int opt_off = sizeof(struct tcphdr);
     983           0 :     u_int8_t *opt_ptr = (u_int8_t *) tcph;
     984             :     u_int16_t pkt_mss, max_mss, mtu;
     985             :     unsigned int csum;
     986             :     uint8_t port_id;
     987           0 :     struct vrouter *router = vrouter_get(0);
     988             : 
     989           0 :     if ((tcph == NULL) || !(tcph->syn) || (router == NULL))
     990           0 :         return;
     991             : 
     992           0 :     if (router->vr_eth_if[0] == NULL)
     993           0 :         return;
     994             : 
     995           0 :     while (opt_off < (tcph->doff * 4)) {
     996           0 :         switch (opt_ptr[opt_off]) {
     997           0 :         case TCPOPT_EOL:
     998           0 :             return;
     999             : 
    1000           0 :         case TCPOPT_NOP:
    1001           0 :             opt_off++;
    1002           0 :             continue;
    1003             : 
    1004           0 :         case TCPOPT_MAXSEG:
    1005           0 :             if ((opt_off + TCPOLEN_MAXSEG) > (tcph->doff*4))
    1006           0 :                 return;
    1007             : 
    1008           0 :             if (opt_ptr[opt_off+1] != TCPOLEN_MAXSEG)
    1009           0 :                 return;
    1010             : 
    1011           0 :             pkt_mss = (opt_ptr[opt_off+2] << 8) | opt_ptr[opt_off+3];
    1012           0 :             if (router->vr_eth_if[0] == NULL)
    1013           0 :                 return;
    1014             : 
    1015           0 :             port_id = (((struct vr_dpdk_ethdev *)(router->vr_eth_if[0]->vif_os))->
    1016             :                     ethdev_port_id);
    1017           0 :             rte_eth_dev_get_mtu(port_id, &mtu);
    1018             : 
    1019           0 :             max_mss = mtu - (overlay_len + iph_len + sizeof(struct tcphdr));
    1020             : 
    1021           0 :             if (pkt_mss > max_mss) {
    1022           0 :                 opt_ptr[opt_off+2] = (max_mss & 0xff00) >> 8;
    1023           0 :                 opt_ptr[opt_off+3] = max_mss & 0xff;
    1024             : 
    1025             :                 /* Recalculate checksum */
    1026           0 :                 csum = (unsigned short)(~rte_cpu_to_be_16(tcph->check));
    1027           0 :                 csum = csum + (unsigned short)~pkt_mss;
    1028           0 :                 csum = (csum & 0xffff) + (csum >> 16);
    1029           0 :                 csum += max_mss;
    1030           0 :                 csum = (csum & 0xffff) + (csum >> 16);
    1031           0 :                 tcph->check = rte_cpu_to_be_16(~((unsigned short)csum));
    1032             :             }
    1033           0 :             return;
    1034             : 
    1035           0 :         default:
    1036           0 :             if ((opt_off + 1) == (tcph->doff*4))
    1037           0 :                 return;
    1038             : 
    1039           0 :             if (opt_ptr[opt_off+1])
    1040           0 :                 opt_off += opt_ptr[opt_off+1];
    1041             :             else
    1042           0 :                 opt_off++;
    1043             : 
    1044           0 :             continue;
    1045             :         } /* switch */
    1046             :     } /* while */
    1047             : 
    1048           0 :     return;
    1049             : }
    1050             : 
    1051             : /*
    1052             :  * dpdk_pkt_from_vm_tcp_mss_adj - perform TCP MSS adjust, if required, for packets
    1053             :  * that are sent by a VM. Returns 0 on success, non-zero otherwise.
    1054             :  */
    1055             : static int
    1056         103 : dpdk_pkt_from_vm_tcp_mss_adj(struct vr_packet *pkt, unsigned short overlay_len)
    1057             : {
    1058         103 :     struct rte_mbuf *m = vr_dpdk_pkt_to_mbuf(pkt);
    1059         103 :     struct vr_ip *ip4h = NULL;
    1060         103 :     struct vr_ip6 *ip6h = NULL;
    1061             :     struct tcphdr *tcph;
    1062             :     int offset;
    1063         103 :     unsigned char iph_len = 0, iph_proto = 0;
    1064             : 
    1065             :     /* check if whole ip header is in the packet */
    1066         103 :     if (pkt->vp_type == VP_TYPE_IP) {
    1067          96 :         offset = sizeof(struct vr_ip);
    1068          96 :         if (pkt->vp_data + offset < pkt->vp_end)
    1069          96 :             ip4h = (struct vr_ip *) ((uintptr_t)m->buf_addr + pkt->vp_data);
    1070             :         else
    1071           0 :             rte_panic("%s: ip header not in first buffer\n", __func__);
    1072          96 :         iph_proto = ip4h->ip_proto;
    1073          96 :         iph_len = ip4h->ip_hl * 4;
    1074             : 
    1075             :         /*
    1076             :          * If this is a fragment and not the first one, it can be ignored
    1077             :          */
    1078          96 :         if (ip4h->ip_frag_off & rte_cpu_to_be_16(IP_OFFMASK))
    1079          36 :             goto out;
    1080           7 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
    1081           7 :         iph_len = offset = sizeof(struct vr_ip6);
    1082           7 :         if (pkt->vp_data + offset < pkt->vp_end)
    1083           7 :             ip6h = (struct vr_ip6 *) ((uintptr_t)m->buf_addr + pkt->vp_data);
    1084             :         else
    1085           0 :             rte_panic("%s: ip header not in first buffer\n", __func__);
    1086           7 :         iph_proto = ip6h->ip6_nxt;
    1087             :     }
    1088             : 
    1089          67 :     if (iph_proto != VR_IP_PROTO_TCP)
    1090          49 :         goto out;
    1091             : 
    1092             :     /*
    1093             :      * Now we know exact ip header length,
    1094             :      * check if whole tcp header is also in the packet
    1095             :      */
    1096          18 :     offset = iph_len + sizeof(struct tcphdr);
    1097             : 
    1098          18 :     if (pkt->vp_data + offset < pkt->vp_end)
    1099          18 :         tcph = (struct tcphdr *)pkt_data_at_offset(pkt, pkt->vp_data + iph_len);
    1100             :     else
    1101           0 :         rte_panic("%s: tcp header not in first buffer\n", __func__);
    1102             : 
    1103          18 :     if ((tcph->doff << 2) <= (sizeof(struct tcphdr))) {
    1104             :         /*Nothing to do if there are no TCP options */
    1105          18 :         goto out;
    1106             :     }
    1107             : 
    1108             : 
    1109           0 :     offset += (tcph->doff << 2) - sizeof(struct tcphdr);
    1110           0 :     if (pkt->vp_data + offset > pkt->vp_end)
    1111           0 :         rte_panic("%s: tcp header outside first buffer\n", __func__);
    1112             : 
    1113             : 
    1114           0 :     dpdk_adjust_tcp_mss(tcph, overlay_len, iph_len);
    1115             : 
    1116         103 : out:
    1117         103 :     return 0;
    1118             : }
    1119             : 
    1120             : static unsigned int
    1121          72 : dpdk_pgso_size(struct vr_packet *pkt)
    1122             : {
    1123          72 :     struct rte_mbuf *m = vr_dpdk_pkt_to_mbuf(pkt);
    1124             : 
    1125          72 :     return m->tso_segsz;
    1126             : }
    1127             : 
    1128             : static void
    1129           9 : dpdk_add_mpls(struct vrouter *router, unsigned mpls_label)
    1130             : {
    1131             :     int ret, i;
    1132             :     struct vr_interface *eth_vif;
    1133             : 
    1134       39204 :     for (i = 0; i < router->vr_max_interfaces; i++) {
    1135       39195 :         eth_vif = __vrouter_get_interface(router, i);
    1136       39195 :         if (eth_vif && (eth_vif->vif_type == VIF_TYPE_PHYSICAL)
    1137          10 :             && (eth_vif->vif_flags & VIF_FLAG_FILTERING_OFFLOAD)) {
    1138           0 :             RTE_LOG(INFO, VROUTER, "Enabling hardware acceleration on vif %u for MPLS %u\n",
    1139             :                 (unsigned)eth_vif->vif_idx, mpls_label);
    1140           0 :             if (!eth_vif->vif_ip) {
    1141           0 :                 RTE_LOG(ERR, VROUTER, "    error accelerating MPLS %u: no IP address set\n",
    1142             :                     mpls_label);
    1143           0 :                 continue;
    1144             :             }
    1145           0 :             ret = vr_dpdk_lcore_mpls_schedule(eth_vif,
    1146           0 :                                     ntohs(eth_vif->vif_ip), mpls_label);
    1147           0 :             if (ret != 0)
    1148           0 :                 RTE_LOG(INFO, VROUTER, "    error accelerating MPLS %u: %s (%d)\n",
    1149             :                     mpls_label, rte_strerror(-ret), -ret);
    1150             :         }
    1151             :     }
    1152             : 
    1153           9 : }
    1154             : 
    1155             : static void
    1156           9 : dpdk_del_mpls(struct vrouter *router, unsigned mpls_label)
    1157             : {
    1158             :     /* TODO: not implemented */
    1159           9 : }
    1160             : 
    1161             : static int
    1162           0 : dpdk_pkt_may_pull(struct vr_packet *pkt, unsigned int len)
    1163             : {
    1164           0 :     struct rte_mbuf *mbuf = vr_dpdk_pkt_to_mbuf(pkt);
    1165             : 
    1166           0 :     if (len > rte_pktmbuf_data_len(mbuf))
    1167           0 :         return -1;
    1168             : 
    1169           0 :     vr_dpdk_mbuf_reset(pkt);
    1170           0 :     return 0;
    1171             : }
    1172             : 
    1173             : static void
    1174           0 : dpdk_set_log_level(unsigned int log_level)
    1175             : {
    1176             :     unsigned int level;
    1177             : 
    1178           0 :     switch(log_level) {
    1179           0 :     case VR_LOG_EMERG:
    1180           0 :         level = RTE_LOG_EMERG;
    1181           0 :         break;
    1182             : 
    1183           0 :     case VR_LOG_ALERT:
    1184           0 :         level = RTE_LOG_ALERT;
    1185           0 :         break;
    1186             : 
    1187           0 :     case VR_LOG_CRIT:
    1188           0 :         level = RTE_LOG_CRIT;
    1189           0 :         break;
    1190             : 
    1191           0 :     case VR_LOG_ERR:
    1192           0 :         level = RTE_LOG_ERR;
    1193           0 :         break;
    1194             : 
    1195           0 :     case VR_LOG_WARNING:
    1196           0 :         level = RTE_LOG_WARNING;
    1197           0 :         break;
    1198             : 
    1199           0 :     case VR_LOG_NOTICE:
    1200           0 :         level = RTE_LOG_NOTICE;
    1201           0 :         break;
    1202             : 
    1203           0 :     case VR_LOG_INFO:
    1204           0 :         level = RTE_LOG_INFO;
    1205           0 :         break;
    1206             : 
    1207           0 :     case VR_LOG_DEBUG:
    1208           0 :         level = RTE_LOG_DEBUG;
    1209           0 :         break;
    1210             : 
    1211           0 :     default:
    1212           0 :         level = 0;
    1213           0 :         break;
    1214             :     }
    1215             : 
    1216           0 :     if (level > 0) {
    1217           0 :         rte_log_set_global_level(level);
    1218             :     } else
    1219           0 :         RTE_LOG(ERR, VROUTER, "Error: wrong log level (%u) specified\n",
    1220             :                 level);
    1221           0 : }
    1222             : 
    1223             : static unsigned int
    1224           0 : dpdk_get_log_level(void)
    1225             : {
    1226           0 :     unsigned int level = rte_log_get_global_level();
    1227             : 
    1228           0 :     switch(level) {
    1229           0 :     case RTE_LOG_EMERG:
    1230           0 :         return VR_LOG_EMERG;
    1231             : 
    1232           0 :     case RTE_LOG_ALERT:
    1233           0 :         return VR_LOG_ALERT;
    1234             : 
    1235           0 :     case RTE_LOG_CRIT:
    1236           0 :         return VR_LOG_CRIT;
    1237             : 
    1238           0 :     case RTE_LOG_ERR:
    1239           0 :         return VR_LOG_ERR;
    1240             : 
    1241           0 :     case RTE_LOG_WARNING:
    1242           0 :         return VR_LOG_WARNING;
    1243             : 
    1244           0 :     case RTE_LOG_NOTICE:
    1245           0 :         return VR_LOG_NOTICE;
    1246             : 
    1247           0 :     case RTE_LOG_INFO:
    1248           0 :         return VR_LOG_INFO;
    1249             : 
    1250           0 :     case RTE_LOG_DEBUG:
    1251           0 :         return VR_LOG_DEBUG;
    1252             :     }
    1253             : 
    1254             :     /* Should never reach here */
    1255           0 :     return 0;
    1256             : }
    1257             : 
    1258             : static void
    1259           0 : dpdk_set_log_type(unsigned int log_type, int enable)
    1260             : {
    1261             :     unsigned int type;
    1262             : 
    1263           0 :     switch (log_type) {
    1264           0 :     case VR_LOGTYPE_VROUTER:
    1265           0 :         type = RTE_LOGTYPE_VROUTER;
    1266           0 :         break;
    1267             : 
    1268           0 :     case VR_LOGTYPE_USOCK:
    1269           0 :         type = RTE_LOGTYPE_USOCK;
    1270           0 :         break;
    1271             : 
    1272           0 :     case VR_LOGTYPE_UVHOST:
    1273           0 :         type = RTE_LOGTYPE_UVHOST;
    1274           0 :         break;
    1275             : 
    1276           0 :     case VR_LOGTYPE_DPCORE:
    1277           0 :         type = RTE_LOGTYPE_DPCORE;
    1278           0 :         break;
    1279             : 
    1280           0 :     default:
    1281           0 :         type = 0;
    1282           0 :         break;
    1283             :     }
    1284             : 
    1285           0 :     if (type > 0) {
    1286           0 :         rte_log_set_level(type, enable);
    1287             :     } else
    1288           0 :         RTE_LOG(ERR, VROUTER, "Error: wrong log type (0x%x) specified\n",
    1289             :                 type);
    1290           0 : }
    1291             : 
    1292             : static unsigned int
    1293           0 : dpdk_log_type_to_vr_type(unsigned int type)
    1294             : {
    1295           0 :     switch (type) {
    1296           0 :     case RTE_LOGTYPE_VROUTER:
    1297           0 :         return VR_LOGTYPE_VROUTER;
    1298             : 
    1299           0 :     case RTE_LOGTYPE_USOCK:
    1300           0 :         return VR_LOGTYPE_USOCK;
    1301             : 
    1302           0 :     case RTE_LOGTYPE_UVHOST:
    1303           0 :         return VR_LOGTYPE_UVHOST;
    1304             : 
    1305           0 :     case RTE_LOGTYPE_DPCORE:
    1306           0 :         return VR_LOGTYPE_DPCORE;
    1307             :     }
    1308             : 
    1309             :     /* Should never reach here */
    1310           0 :     return 0;
    1311             : }
    1312             : 
    1313             : static unsigned int *
    1314           0 : dpdk_get_enabled_log_types(int *size)
    1315             : {
    1316           0 :     int num = rte_logs.dynamic_types_len;
    1317             : 
    1318             :     unsigned int *enabled_array =
    1319           0 :             vr_malloc(sizeof(int) * num, VR_LOG_TYPES_OBJECT);
    1320             :     int i;
    1321             : 
    1322           0 :     RTE_VERIFY(enabled_array != NULL);
    1323           0 :     *size = 0;
    1324           0 :     for (i = 0; i < num; i++) {
    1325           0 :         if (rte_log_get_level(i) > 0) {
    1326           0 :             enabled_array[i] = dpdk_log_type_to_vr_type(i);
    1327           0 :             (*size)++;
    1328             :         }
    1329             :     }
    1330             : 
    1331           0 :     return enabled_array;
    1332             : }
    1333             : 
    1334             : static void
    1335          53 : dpdk_soft_reset(struct vrouter *router)
    1336             : {
    1337             :     unsigned lcore_id;
    1338          53 :     rcu_barrier();
    1339             : 
    1340             :     /* Reset GRO hash tables */
    1341         424 :     RTE_LCORE_FOREACH(lcore_id) {
    1342         371 :         struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
    1343         371 :         if (lcore != NULL)
    1344          53 :             dpdk_gro_free_all_flows(lcore);
    1345             :     }
    1346          53 : }
    1347             : 
    1348             : static int
    1349          21 : dpdk_is_frag_limit_exceeded(void)
    1350             : {
    1351          21 :     struct vrouter *router = vrouter_get(0);
    1352             :     struct vr_malloc_stats *stats;
    1353          21 :     uint64_t sum = 0;
    1354             :     unsigned int cpu;
    1355             : 
    1356          21 :     if (router->vr_malloc_stats) {
    1357         273 :         for (cpu = 0; cpu < vr_num_cpus; cpu++) {
    1358         252 :             if (router->vr_malloc_stats[cpu]) {
    1359         252 :                 stats = &router->vr_malloc_stats[cpu][VR_FRAGMENT_QUEUE_ELEMENT_OBJECT];
    1360         252 :                 sum += stats->ms_alloc;
    1361         252 :                 sum -= stats->ms_free;
    1362             :             }
    1363             :         }
    1364          21 :         if (sum > VR_DPDK_MAX_FRAGMENT_ELEMENTS)
    1365           0 :             return 1;
    1366             :     }
    1367             : 
    1368          21 :     return 0;
    1369             : }
    1370             : 
    1371             : static void
    1372         332 : dpdk_register_nic(struct vr_interface* vif __attribute__((unused)),
    1373             :                   vr_interface_req* vifr __attribute__((unused)))
    1374             : {
    1375         332 : }
    1376             : 
    1377             : static void
    1378         109 : dpdk_flow_bucket_lock(struct vr_flow_entry *fe)
    1379             : {
    1380         109 :     while (!vr_sync_bool_compare_and_swap_8u(&fe->fe_bucket_lock, 0, 1)) {
    1381           0 :         vr_pause();
    1382             :     }
    1383         109 : }
    1384             : 
    1385             : static void
    1386         109 : dpdk_flow_bucket_unlock(struct vr_flow_entry *fe)
    1387             : {
    1388         109 :     vr_sync_bool_compare_and_swap_8u(&fe->fe_bucket_lock, 1, 0);
    1389         109 : }
    1390             : 
    1391             : struct host_os dpdk_host = {
    1392             :     .hos_printf                     =    dpdk_printf,
    1393             :     .hos_malloc                     =    dpdk_malloc,
    1394             :     .hos_zalloc                     =    dpdk_zalloc,
    1395             :     .hos_free                       =    dpdk_free,
    1396             :     .hos_vtop                       =    dpdk_vtop, /* not used */
    1397             :     .hos_page_alloc                 =    dpdk_page_alloc,
    1398             :     .hos_page_free                  =    dpdk_page_free,
    1399             : 
    1400             :     .hos_palloc                     =    dpdk_palloc,
    1401             :     .hos_palloc_head                =    dpdk_palloc_head, /* not implemented */
    1402             :     .hos_pexpand_head               =    dpdk_pexpand_head, /* not implemented */
    1403             :     .hos_pfree                      =    dpdk_pfree,
    1404             :     .hos_preset                     =    dpdk_preset,
    1405             :     .hos_pclone                     =    dpdk_pclone,
    1406             :     .hos_pcopy                      =    dpdk_pcopy,
    1407             :     .hos_pfrag_len                  =    dpdk_pfrag_len,
    1408             :     .hos_phead_len                  =    dpdk_phead_len,
    1409             :     .hos_pset_data                  =    dpdk_pset_data,
    1410             :     .hos_pgso_size                  =    dpdk_pgso_size,
    1411             :     .hos_get_cpu                    =    dpdk_get_cpu,
    1412             :     .hos_schedule_work              =    dpdk_schedule_work,
    1413             :     .hos_delay_op                   =    dpdk_delay_op, /* do nothing */
    1414             :     .hos_defer                      =    dpdk_defer,
    1415             :     .hos_get_defer_data             =    dpdk_get_defer_data,
    1416             :     .hos_put_defer_data             =    dpdk_put_defer_data,
    1417             :     .hos_get_time                   =    dpdk_get_time,
    1418             :     .hos_get_mono_time              =    dpdk_get_mono_time,
    1419             :     .hos_create_timer               =    dpdk_create_timer,
    1420             :     .hos_delete_timer               =    dpdk_delete_timer,
    1421             : 
    1422             :     .hos_network_header             =    dpdk_network_header, /* for chains? */
    1423             :     .hos_inner_network_header       =    dpdk_inner_network_header, /* not used? */
    1424             :     .hos_data_at_offset             =    dpdk_data_at_offset, /* for chains? */
    1425             :     .hos_pheader_pointer            =    dpdk_pheader_pointer,
    1426             :     .hos_pull_inner_headers         =    NULL,  /* not necessary */
    1427             :     .hos_pcow                       =    dpdk_pcow,
    1428             :     .hos_pull_inner_headers_fast    =    NULL,  /* not necessary */
    1429             : #if VR_DPDK_USE_MPLS_UDP_ECMP
    1430             :     .hos_get_udp_src_port           =    dpdk_get_udp_src_port,
    1431             : #endif
    1432             :     .hos_pkt_from_vm_tcp_mss_adj    =    dpdk_pkt_from_vm_tcp_mss_adj,
    1433             :     .hos_pkt_may_pull               =    dpdk_pkt_may_pull,
    1434             :     .hos_gro_process                =    dpdk_gro_process,
    1435             :     .hos_add_mpls                   =    dpdk_add_mpls,
    1436             :     .hos_del_mpls                   =    dpdk_del_mpls, /* not implemented */
    1437             :     .hos_enqueue_to_assembler       =    dpdk_fragment_assembler_enqueue,
    1438             :     .hos_fragment_sync_assemble     =    dpdk_fragment_sync_assemble,
    1439             :     .hos_set_log_level              =    dpdk_set_log_level,
    1440             :     .hos_set_log_type               =    dpdk_set_log_type,
    1441             :     .hos_get_log_level              =    dpdk_get_log_level,
    1442             :     .hos_get_enabled_log_types      =    dpdk_get_enabled_log_types,
    1443             :     .hos_soft_reset                 =    dpdk_soft_reset,
    1444             :     .hos_is_frag_limit_exceeded     =    dpdk_is_frag_limit_exceeded,
    1445             :     .hos_register_nic               =    dpdk_register_nic, /* not used with DPDK */
    1446             :     .hos_nl_broadcast_supported     =    false,
    1447             :     .hos_offload_flow_create        =    dpdk_offload_flow_create,
    1448             :     .hos_offload_flow_destroy       =    dpdk_offload_flow_destroy,
    1449             :     .hos_offload_prepare            =    dpdk_offload_prepare,
    1450             :     .hos_flow_bucket_lock           =    dpdk_flow_bucket_lock,
    1451             :     .hos_flow_bucket_unlock         =    dpdk_flow_bucket_unlock,
    1452             :     /* Below macro would be expanded for each callbacks registered in vr_info.h.
    1453             :      * this would map the actual dpdk callback function with
    1454             :      * vrouter_host(.hos_<fn. name>) */
    1455             :     FOREACH_VR_INFO_MAP()
    1456             : };
    1457             : 
    1458             : struct host_os *
    1459         106 : vrouter_get_host(void)
    1460             : {
    1461         106 :     return &dpdk_host;
    1462             : }
    1463             : 
    1464             : /* Remove xconnect callback */
    1465             : void
    1466          42 : vhost_remove_xconnect(void)
    1467             : {
    1468             :     int i;
    1469             :     struct vr_interface *vif;
    1470          42 :     struct vrouter *router = vrouter_get(0);
    1471             : 
    1472      182952 :     for (i = 0; i < router->vr_max_interfaces; i++) {
    1473      182910 :         vif = __vrouter_get_interface(router, i);
    1474      182910 :         if (vif && (vif_is_vhost(vif))) {
    1475          42 :             vif_remove_xconnect(vif);
    1476          42 :             if (vif->vif_bridge[0] != NULL)
    1477          42 :                 vif_remove_xconnect(vif->vif_bridge[0]);
    1478             :         }
    1479             :     }
    1480          42 : }
    1481             : 
    1482             : /* Implementation of the Linux kernel function */
    1483             : void
    1484          33 : get_random_bytes(void *buf, int nbytes)
    1485             : {
    1486             :     int i;
    1487             : 
    1488          33 :     if (nbytes == sizeof(uint32_t)) {
    1489          33 :         *(uint32_t *)buf = (uint32_t)rte_rand();
    1490           0 :     } else if (nbytes == sizeof(uint64_t)) {
    1491           0 :         *(uint64_t *)buf = rte_rand();
    1492             :     } else {
    1493           0 :         for (i = 0; i < nbytes; i++) {
    1494           0 :             *((uint8_t *)buf + i) = (uint8_t)rte_rand();
    1495             :         }
    1496             :     }
    1497          33 : }
    1498             : 
    1499             : uint32_t
    1500           0 : jhash(void *key, uint32_t length, uint32_t initval)
    1501             : {
    1502           0 :     return rte_jhash(key, length, initval);
    1503             : }
    1504             : 
    1505             : 
    1506             : 
    1507             : /**
    1508             :  * vr_dpdk_packet_get - convert DPDK mbuf to dp-core vr_packet
    1509             :  * Based on linux_get_packet()
    1510             :  *
    1511             :  * Return vr_packet pointer.
    1512             :  */
    1513             : struct vr_packet *
    1514         160 : vr_dpdk_packet_get(struct rte_mbuf *m, struct vr_interface *vif)
    1515             : {
    1516         160 :     struct vr_packet *pkt = vr_dpdk_mbuf_to_pkt(m);
    1517         160 :     pkt->vp_cpu = rte_lcore_id();
    1518         160 :     pkt->vp_head = m->buf_addr;
    1519             : 
    1520         160 :     pkt->vp_tail = rte_pktmbuf_headroom(m) + rte_pktmbuf_data_len(m);
    1521         160 :     pkt->vp_data = rte_pktmbuf_headroom(m);
    1522             :     /* vp_end is set in vr_dpdk_pktmbuf_init() */
    1523             : 
    1524         160 :     pkt->vp_len = rte_pktmbuf_data_len(m);
    1525         160 :     pkt->vp_if = vif;
    1526         160 :     pkt->vp_network_h = pkt->vp_inner_network_h = 0;
    1527         160 :     pkt->vp_nh = NULL;
    1528         160 :     pkt->vp_flags = 0;
    1529         160 :     if (likely(m->ol_flags & PKT_RX_IP_CKSUM_BAD))
    1530         160 :         pkt->vp_flags |= VP_FLAG_CSUM_PARTIAL;
    1531             : 
    1532         160 :     pkt->vp_ttl = 64;
    1533         160 :     pkt->vp_type = VP_TYPE_NULL;
    1534         160 :     pkt->vp_queue = VP_QUEUE_INVALID;
    1535         160 :     pkt->vp_priority = VP_PRIORITY_INVALID;
    1536         160 :     pkt->vp_rx_pass = 0;
    1537             : 
    1538         160 :     return pkt;
    1539             : }
    1540             : 
    1541             : /* Exit vRouter */
    1542             : void
    1543          53 : vr_dpdk_host_exit(void)
    1544             : {
    1545          53 :     vr_sandesh_exit();
    1546          53 :     vrouter_exit(false);
    1547             : 
    1548          53 :     return;
    1549             : }
    1550             : 
    1551             : /*
    1552             :  * vr_dpdk_set_fd_limit - set the max number of open files for the process. The
    1553             :  * user space vhost server requires one socket per interface. Allow a few more than
    1554             :  * that.
    1555             :  *
    1556             :  * Returns 0 on success, -1 otherwise.
    1557             :  */
    1558             : static int
    1559          53 : vr_dpdk_set_fd_limit(void)
    1560             : {
    1561             :     struct rlimit rl;
    1562             :     int ret, old_cur;
    1563             : 
    1564          53 :     ret = getrlimit(RLIMIT_NOFILE, &rl);
    1565          53 :     if (ret != 0) {
    1566           0 :         RTE_LOG(ERR, VROUTER,
    1567             :             "Could not get resource limits, error %d\n", errno);
    1568           0 :         return -1;
    1569             :     }
    1570             : 
    1571          53 :     old_cur = (int) rl.rlim_cur;
    1572          53 :     if (rl.rlim_max < (VR_MAX_INTERFACES + VR_DPDK_NUM_FDS)) {
    1573           0 :         rl.rlim_cur = rl.rlim_max;
    1574             :     } else {
    1575          53 :         rl.rlim_cur = VR_MAX_INTERFACES + VR_DPDK_NUM_FDS;
    1576             :     }
    1577             : 
    1578          53 :     ret = setrlimit(RLIMIT_NOFILE, &rl);
    1579          53 :     if (ret) {
    1580           0 :         RTE_LOG(ERR, VROUTER,
    1581             :             "Could not set fd limit to %d (max %d), error %d\n",
    1582             :                 (int) rl.rlim_cur, (int) rl.rlim_max, errno);
    1583           0 :         return -1;
    1584             :     }
    1585             : 
    1586          53 :     RTE_LOG(INFO, VROUTER,
    1587             :         "set fd limit to %d (prev %d, max %d)\n",
    1588             :         (int) rl.rlim_cur, old_cur, (int) rl.rlim_max);
    1589             : 
    1590          53 :     return 0;
    1591             : }
    1592             : 
    1593             : 
    1594             : /* Init vRouter */
    1595             : int
    1596          53 : vr_dpdk_host_init(void)
    1597             : {
    1598             :     int ret;
    1599             :     unsigned lcore_id;
    1600             : 
    1601          53 :     if (vr_host_inited)
    1602           0 :         return 0;
    1603             : 
    1604          53 :     vr_init_cpuid = vr_dpdk_init_cpuid;
    1605             : 
    1606             :     /*
    1607             :      * Set number of CPUs. Note it is not just number of lcores, so we
    1608             :      * cannot just use rte_lcore_count() here.
    1609             :      */
    1610          53 :     vr_num_cpus = 0;
    1611         424 :     RTE_LCORE_FOREACH(lcore_id) {
    1612         371 :         vr_num_cpus = RTE_MAX(vr_num_cpus, lcore_id);
    1613             :     }
    1614          53 :     vr_num_cpus++;
    1615             : 
    1616          53 :     if (!vrouter_host) {
    1617          53 :         vrouter_host = vrouter_get_host();
    1618             : 
    1619          53 :         if (vr_dpdk_flow_init()) {
    1620           0 :             return -1;
    1621             :         }
    1622             : 
    1623          53 :         if (vr_dpdk_bridge_init()) {
    1624           0 :             return -1;
    1625             :         }
    1626             :     }
    1627             : 
    1628             :     /*
    1629             :      * Allow at least one file descriptor per interface (as required by the
    1630             :      * user space vhost server.
    1631             :      */
    1632          53 :     ret = vr_dpdk_set_fd_limit();
    1633          53 :     if (ret) {
    1634           0 :         return ret;
    1635             :     }
    1636             : 
    1637          53 :     ret = vrouter_init();
    1638          53 :     if (ret)
    1639           0 :         return ret;
    1640             : 
    1641          53 :     ret = vr_sandesh_init();
    1642          53 :     if (ret)
    1643           0 :         goto init_fail;
    1644             : 
    1645          53 :     vr_host_inited = true;
    1646             : 
    1647          53 :     return 0;
    1648             : 
    1649           0 : init_fail:
    1650           0 :     vr_dpdk_host_exit();
    1651           0 :     return ret;
    1652             : }
    1653             : 
    1654             : /* Retry socket connection */
    1655             : int
    1656          53 : vr_dpdk_retry_connect(int sockfd, const struct sockaddr *addr,
    1657             :                         socklen_t alen)
    1658             : {
    1659             :     int nsec;
    1660             : 
    1661         101 :     for (nsec = 1; nsec < VR_DPDK_RETRY_CONNECT_SECS; nsec <<= 1) {
    1662         101 :         if (connect(sockfd, addr, alen) == 0)
    1663          53 :             return 0;
    1664             : 
    1665          48 :         if (nsec < VR_DPDK_RETRY_CONNECT_SECS/2) {
    1666          48 :             sleep(nsec);
    1667          48 :             RTE_LOG(INFO, VROUTER, "Retrying connection for socket %d...\n",
    1668             :                     sockfd);
    1669             :         }
    1670             :     }
    1671             : 
    1672           0 :     return -1;
    1673             : }
    1674             : 
    1675             : /* Returns a string hash */
    1676             : static inline uint32_t
    1677           0 : dpdk_strhash(const char *k, uint32_t initval)
    1678             : {
    1679             :     uint32_t a, b, c;
    1680             : 
    1681           0 :     a = b = RTE_JHASH_GOLDEN_RATIO;
    1682           0 :     c = initval;
    1683             : 
    1684             :     do {
    1685           0 :         if (*k) {
    1686           0 :             a += k[0];
    1687           0 :             k++;
    1688             :         }
    1689           0 :         if (*k) {
    1690           0 :             b += k[0];
    1691           0 :             k++;
    1692             :         }
    1693           0 :         if (*k) {
    1694           0 :             c += k[0];
    1695           0 :             k++;
    1696             :         }
    1697           0 :         __rte_jhash_mix(a, b, c);
    1698           0 :     } while (*k);
    1699             : 
    1700           0 :     return c;
    1701             : }
    1702             : 
    1703             : /* Generates unique log message */
    1704           0 : int vr_dpdk_ulog(uint32_t level, uint32_t logtype, uint32_t *last_hash,
    1705             :                     const char *format, ...)
    1706             : {
    1707             :     va_list ap;
    1708           0 :     int ret = 0;
    1709             :     uint32_t hash;
    1710             :     char buf[VR_DPDK_STR_BUF_SZ];
    1711             : 
    1712             :     /* fallback to rte_log */
    1713           0 :     if (last_hash == NULL) {
    1714           0 :         va_start(ap, format);
    1715           0 :         ret = rte_log(level, logtype, "%s", buf);
    1716           0 :         va_end(ap);
    1717             :     } else {
    1718             :         /* calculate message hash */
    1719           0 :         va_start(ap, format);
    1720           0 :         vsnprintf(buf, sizeof(buf) - 1, format, ap);
    1721           0 :         va_end(ap);
    1722           0 :         buf[sizeof(buf) - 1] = '\0';
    1723           0 :         hash = dpdk_strhash(buf, level + logtype);
    1724             : 
    1725           0 :         if (hash != *last_hash) {
    1726           0 :             *last_hash = hash;
    1727           0 :             ret = rte_log(level, logtype, "%s", buf);
    1728             :         }
    1729             :     }
    1730             : 
    1731           0 :     return ret;
    1732             : }

Generated by: LCOV version 1.14