Coverage Report

Created: 2025-07-12 06:35

/src/openvswitch/lib/dpif-netdev-private-dfc.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
3
 * Copyright (c) 2019, 2020, 2021 Intel Corporation.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at:
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#ifndef DPIF_NETDEV_PRIVATE_DFC_H
19
#define DPIF_NETDEV_PRIVATE_DFC_H 1
20
21
#include "dpif.h"
22
#include "dpif-netdev-private-dpcls.h"
23
#include "dpif-netdev-private-flow.h"
24
25
#include <stdbool.h>
26
#include <stdint.h>
27
28
#ifdef  __cplusplus
29
extern "C" {
30
#endif
31
32
/* EMC cache and SMC cache compose the datapath flow cache (DFC)
33
 *
34
 * Exact match cache for frequently used flows
35
 *
36
 * The cache uses a 32-bit hash of the packet (which can be the RSS hash) to
37
 * search its entries for a miniflow that matches exactly the miniflow of the
38
 * packet. It stores the 'dpcls_rule' (rule) that matches the miniflow.
39
 *
40
 * A cache entry holds a reference to its 'dp_netdev_flow'.
41
 *
42
 * A miniflow with a given hash can be in one of EM_FLOW_HASH_SEGS different
43
 * entries. The 32-bit hash is split into EM_FLOW_HASH_SEGS values (each of
44
 * them is EM_FLOW_HASH_SHIFT bits wide and the remainder is thrown away). Each
45
 * value is the index of a cache entry where the miniflow could be.
46
 *
47
 *
48
 * Signature match cache (SMC)
49
 *
50
 * This cache stores a 16-bit signature for each flow without storing keys, and
51
 * stores the corresponding 16-bit flow_table index to the 'dp_netdev_flow'.
52
 * Each flow thus occupies 32bit which is much more memory efficient than EMC.
53
 * SMC uses a set-associative design that each bucket contains
54
 * SMC_ENTRY_PER_BUCKET number of entries.
55
 * Since 16-bit flow_table index is used, if there are more than 2^16
56
 * dp_netdev_flow, SMC will miss them that cannot be indexed by a 16-bit value.
57
 *
58
 *
59
 * Thread-safety
60
 * =============
61
 *
62
 * Each pmd_thread has its own private exact match cache and signature match
63
 * cache.
64
 * If dp_netdev_input is not called from a pmd thread, a mutex is used.
65
 */
66
67
0
#define EM_FLOW_HASH_SHIFT 13
68
0
#define EM_FLOW_HASH_ENTRIES (1u << EM_FLOW_HASH_SHIFT)
69
0
#define EM_FLOW_HASH_MASK (EM_FLOW_HASH_ENTRIES - 1)
70
0
#define EM_FLOW_HASH_SEGS 2
71
72
/* SMC uses a set-associative design. A bucket contains a set of entries that
73
 * a flow item can occupy. For now, it uses one hash function rather than two
74
 * as for the EMC design. */
75
0
#define SMC_ENTRY_PER_BUCKET 4
76
0
#define SMC_ENTRIES (1u << 20)
77
0
#define SMC_BUCKET_CNT (SMC_ENTRIES / SMC_ENTRY_PER_BUCKET)
78
0
#define SMC_MASK (SMC_BUCKET_CNT - 1)
79
80
/* Default EMC insert probability is 1 / DEFAULT_EM_FLOW_INSERT_INV_PROB */
81
0
#define DEFAULT_EM_FLOW_INSERT_INV_PROB 100
82
0
#define DEFAULT_EM_FLOW_INSERT_MIN (UINT32_MAX /                     \
83
0
                                    DEFAULT_EM_FLOW_INSERT_INV_PROB)
84
85
/* Forward declaration for SMC function prototype that requires access to
86
 * 'struct dp_netdev_pmd_thread'. */
87
struct dp_netdev_pmd_thread;
88
89
/* Forward declaration for EMC and SMC batch insert function prototypes that
90
 * require access to 'struct dpcls_rule'. */
91
struct dpcls_rule;
92
93
struct emc_entry {
94
    struct dp_netdev_flow *flow;
95
    struct netdev_flow_key key;   /* key.hash used for emc hash value. */
96
};
97
98
struct emc_cache {
99
    struct emc_entry entries[EM_FLOW_HASH_ENTRIES];
100
    int sweep_idx;                /* For emc_cache_slow_sweep(). */
101
};
102
103
struct smc_bucket {
104
    uint16_t sig[SMC_ENTRY_PER_BUCKET];
105
    uint16_t flow_idx[SMC_ENTRY_PER_BUCKET];
106
};
107
108
/* Signature match cache, differentiate from EMC cache */
109
struct smc_cache {
110
    struct smc_bucket buckets[SMC_BUCKET_CNT];
111
};
112
113
struct dfc_cache {
114
    struct emc_cache emc_cache;
115
    struct smc_cache smc_cache;
116
};
117
118
/* Iterate in the exact match cache through every entry that might contain a
119
 * miniflow with hash 'HASH'. */
120
#define EMC_FOR_EACH_POS_WITH_HASH(EMC, CURRENT_ENTRY, HASH)                 \
121
0
    for (uint32_t i__ = 0, srch_hash__ = (HASH);                             \
122
0
         (CURRENT_ENTRY) = &(EMC)->entries[srch_hash__ & EM_FLOW_HASH_MASK], \
123
0
         i__ < EM_FLOW_HASH_SEGS;                                            \
124
0
         i__++, srch_hash__ >>= EM_FLOW_HASH_SHIFT)
125
126
void dfc_cache_init(struct dfc_cache *flow_cache);
127
128
void dfc_cache_uninit(struct dfc_cache *flow_cache);
129
130
/* Check and clear dead flow references slowly (one entry at each
131
 * invocation).  */
132
void emc_cache_slow_sweep(struct emc_cache *flow_cache);
133
134
static inline bool
135
emc_entry_alive(struct emc_entry *ce)
136
0
{
137
0
    return ce->flow && !ce->flow->dead;
138
0
}
Unexecuted instantiation: dpif-netdev.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-private-dfc.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-private-dpif.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-private-extract.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-extract-study.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-lookup.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-lookup-autovalidator.c:emc_entry_alive
Unexecuted instantiation: dpif-netdev-lookup-generic.c:emc_entry_alive
139
140
/* Used to compare 'netdev_flow_key' in the exact match cache to a miniflow.
141
 * The maps are compared bitwise, so both 'key->mf' and 'mf' must have been
142
 * generated by miniflow_extract. */
143
static inline bool
144
emc_flow_key_equal_mf(const struct netdev_flow_key *key,
145
                         const struct miniflow *mf)
146
0
{
147
0
    return !memcmp(&key->mf, mf, key->len);
148
0
}
Unexecuted instantiation: dpif-netdev.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-private-dfc.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-private-dpif.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-private-extract.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-extract-study.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-lookup.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-lookup-autovalidator.c:emc_flow_key_equal_mf
Unexecuted instantiation: dpif-netdev-lookup-generic.c:emc_flow_key_equal_mf
149
150
static inline struct dp_netdev_flow *
151
emc_lookup(struct emc_cache *cache, const struct netdev_flow_key *key)
152
0
{
153
0
    struct emc_entry *current_entry;
154
155
0
    EMC_FOR_EACH_POS_WITH_HASH (cache, current_entry, key->hash) {
156
0
        if (current_entry->key.hash == key->hash
157
0
            && emc_entry_alive(current_entry)
158
0
            && emc_flow_key_equal_mf(&current_entry->key, &key->mf)) {
159
160
            /* We found the entry with the 'key->mf' miniflow */
161
0
            return current_entry->flow;
162
0
        }
163
0
    }
164
165
0
    return NULL;
166
0
}
Unexecuted instantiation: dpif-netdev.c:emc_lookup
Unexecuted instantiation: dpif-netdev-private-dfc.c:emc_lookup
Unexecuted instantiation: dpif-netdev-private-dpif.c:emc_lookup
Unexecuted instantiation: dpif-netdev-private-extract.c:emc_lookup
Unexecuted instantiation: dpif-netdev-extract-study.c:emc_lookup
Unexecuted instantiation: dpif-netdev-lookup.c:emc_lookup
Unexecuted instantiation: dpif-netdev-lookup-autovalidator.c:emc_lookup
Unexecuted instantiation: dpif-netdev-lookup-generic.c:emc_lookup
167
168
/* Insert a batch of keys/flows into the EMC and SMC caches. */
169
void
170
emc_probabilistic_insert_batch(struct dp_netdev_pmd_thread *pmd,
171
                               const struct netdev_flow_key *keys,
172
                               struct dpcls_rule **rules,
173
                               uint32_t emc_insert_mask);
174
175
void
176
smc_insert_batch(struct dp_netdev_pmd_thread *pmd,
177
                               const struct netdev_flow_key *keys,
178
                               struct dpcls_rule **rules,
179
                               uint32_t smc_insert_mask);
180
181
struct dp_netdev_flow *
182
smc_lookup_single(struct dp_netdev_pmd_thread *pmd,
183
                  struct dp_packet *packet,
184
                  struct netdev_flow_key *key);
185
186
#ifdef  __cplusplus
187
}
188
#endif
189
190
#endif /* dpif-netdev-private-dfc.h */