Line data Source code
1 : /* SPDX-License-Identifier: BSD-2-Clause
2 : * Copyright(c) HCL TECHNOLOGIES LTD
3 : * Submitted on behalf of a third-party: Intel Corporation, a
4 : * Delaware corporation, having its principal place of business
5 : * at 2200 Mission College Boulevard,
6 : * Santa Clara, California 95052, USA
7 : */
8 :
9 : #include "vr_dpdk_n3k_mpls.h"
10 :
11 : #include <assert.h>
12 : #include <string.h>
13 : #include <sys/queue.h>
14 :
15 : #include <rte_log.h>
16 : #include <rte_malloc.h>
17 : #include <rte_spinlock.h>
18 :
19 : #include "vr_dpdk.h"
20 :
21 : enum { N3K_OFFLOAD_MPLS_LABEL_COUNT = 1 << 20 };
22 :
23 : #define EMPTY_LABEL UINT32_MAX
24 :
25 : struct vr_n3k_offload_mpls_entry {
26 : struct vr_n3k_offload_mpls value;
27 : STAILQ_ENTRY(vr_n3k_offload_mpls_entry) entries;
28 : };
29 :
30 8 : static bool entry_is_empty(const struct vr_n3k_offload_mpls_entry *entry) {
31 8 : return entry->value.label == EMPTY_LABEL;
32 : }
33 :
34 : STAILQ_HEAD(vr_n3k_nh_to_labels_list, vr_n3k_offload_mpls_entry);
35 :
36 : struct vr_n3k_nh_to_labels {
37 : struct vr_n3k_nh_to_labels_list list;
38 : size_t count;
39 : };
40 :
41 : static uint32_t nexthops_count;
42 :
43 : /* Invariant: !entry_is_empty(&label_to_nh[label]) iff.
44 : * nh_to_labels[label_to_nh[label].value.nexthop_id].list contains &label_to_nh[label] */
45 : static struct vr_n3k_offload_mpls_entry *label_to_nh;
46 : static struct vr_n3k_nh_to_labels *nh_to_labels;
47 :
48 : static rte_rwlock_t mpls_lock __rte_cache_aligned;
49 :
50 : int
51 12 : vr_dpdk_n3k_offload_mpls_init(uint32_t nh_count)
52 : {
53 : int idx;
54 :
55 12 : rte_rwlock_init(&mpls_lock);
56 :
57 12 : label_to_nh = rte_malloc("n3k_offload_mpls",
58 : N3K_OFFLOAD_MPLS_LABEL_COUNT * sizeof(*label_to_nh), 0);
59 12 : if (label_to_nh == NULL)
60 0 : return -ENOMEM;
61 :
62 : /* set label_to_nh[*].value.label = EMPTY_LABEL */
63 12 : memset(label_to_nh, 0xff, N3K_OFFLOAD_MPLS_LABEL_COUNT * sizeof(*label_to_nh));
64 :
65 12 : nh_to_labels = rte_zmalloc(
66 : "n3k_offload_mpls", nh_count * sizeof(*nh_to_labels), 0);
67 12 : if (nh_to_labels == NULL) {
68 0 : rte_free(label_to_nh);
69 0 : return -ENOMEM;
70 : }
71 :
72 1212 : for (idx = 0; idx < nh_count; ++idx) {
73 1200 : STAILQ_INIT(&nh_to_labels[idx].list);
74 : }
75 :
76 12 : nexthops_count = nh_count;
77 :
78 12 : return 0;
79 : }
80 :
81 : static void
82 4 : vr_dpdk_n3k_offload_mpls_insert(struct vr_n3k_offload_mpls mpls)
83 : {
84 4 : struct vr_n3k_offload_mpls_entry *entry = &label_to_nh[mpls.label];
85 4 : assert(entry_is_empty(entry));
86 :
87 4 : entry->value = mpls;
88 :
89 4 : struct vr_n3k_nh_to_labels *labels = &nh_to_labels[mpls.nexthop_id];
90 4 : STAILQ_INSERT_HEAD(&labels->list, entry, entries);
91 4 : labels->count++;
92 4 : }
93 :
94 : int
95 4 : vr_dpdk_n3k_offload_mpls_insert_copy_for_test(struct vr_n3k_offload_mpls mpls)
96 : {
97 4 : if (!entry_is_empty(&label_to_nh[mpls.label]))
98 0 : return -EEXIST;
99 :
100 4 : rte_rwlock_write_lock(&mpls_lock);
101 4 : vr_dpdk_n3k_offload_mpls_insert(mpls);
102 4 : rte_rwlock_write_unlock(&mpls_lock);
103 :
104 4 : return 0;
105 : }
106 :
107 : /* Removes mapping, if exists.
108 : * @returns
109 : * true if mapping existed and had been removed,
110 : * false is mapping did not exist */
111 : static bool
112 0 : vr_dpdk_n3k_offload_mpls_remove_mapping(int label)
113 : {
114 0 : struct vr_n3k_offload_mpls_entry *entry = &label_to_nh[label];
115 0 : if (entry_is_empty(entry)) {
116 0 : return false;
117 : }
118 :
119 0 : struct vr_n3k_nh_to_labels *labels = &nh_to_labels[entry->value.nexthop_id];
120 0 : STAILQ_REMOVE(&labels->list, entry, vr_n3k_offload_mpls_entry, entries);
121 0 : labels->count--;
122 :
123 0 : label_to_nh[label].value.label = EMPTY_LABEL;
124 :
125 0 : return true;
126 : }
127 :
128 : void
129 12 : vr_dpdk_n3k_offload_mpls_exit(void)
130 : {
131 12 : rte_free(nh_to_labels);
132 12 : nh_to_labels = NULL;
133 :
134 12 : rte_free(label_to_nh);
135 12 : label_to_nh = NULL;
136 12 : }
137 :
138 : extern int __attribute__((weak))
139 : vr_dpdk_n3k_offload_mpls_get_by_label(uint32_t label, struct vr_n3k_offload_mpls *);
140 :
141 : int
142 0 : vr_dpdk_n3k_offload_mpls_get_by_label(uint32_t label, struct vr_n3k_offload_mpls * out)
143 : {
144 0 : if (label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
145 0 : return -EINVAL;
146 :
147 0 : rte_rwlock_read_lock(&mpls_lock);
148 :
149 0 : if (label_to_nh[label].value.label == EMPTY_LABEL) {
150 0 : rte_rwlock_read_unlock(&mpls_lock);
151 0 : return -ENOENT;
152 : }
153 0 : *out = label_to_nh[label].value;
154 :
155 0 : rte_rwlock_read_unlock(&mpls_lock);
156 :
157 0 : return 0;
158 : }
159 :
160 : int
161 4 : vr_dpdk_n3k_offload_mpls_get_by_nh(uint32_t nh_id, struct vr_n3k_offload_mpls * out)
162 : {
163 4 : if (nh_id >= nexthops_count)
164 0 : return -EINVAL;
165 :
166 4 : rte_rwlock_read_lock(&mpls_lock);
167 4 : struct vr_n3k_nh_to_labels *labels = &nh_to_labels[nh_id];
168 4 : if (labels->count == 0) {
169 0 : rte_rwlock_read_unlock(&mpls_lock);
170 0 : return -ENOENT;
171 : }
172 :
173 4 : if (labels->count != 1) {
174 0 : rte_rwlock_read_unlock(&mpls_lock);
175 0 : RTE_LOG(WARNING, VROUTER,
176 : "%s(): Multiple MPLS labels found for nh=%d\n", __func__, nh_id);
177 0 : return -ENOTSUP;
178 : }
179 :
180 4 : *out = STAILQ_FIRST(&labels->list)->value;
181 4 : rte_rwlock_read_unlock(&mpls_lock);
182 :
183 4 : return 0;
184 : }
185 :
186 : int
187 0 : vr_dpdk_n3k_offload_mpls_add(struct vr_nexthop *nh, int label)
188 : {
189 0 : if(nh == NULL) {
190 0 : RTE_LOG(DEBUG, VROUTER, "%s() called; nh=NULL\n", __func__);
191 0 : return -EINVAL;
192 : }
193 :
194 0 : RTE_LOG(
195 : DEBUG, VROUTER,
196 : "%s() called; nh=%p; nh_id=%d; nh_type=%d; label=%d;\n",
197 : __func__, nh, nh->nh_id, nh->nh_type, label
198 : );
199 :
200 0 : if (nh->nh_id >= nexthops_count)
201 0 : return -EINVAL;
202 :
203 : /* TODO(n3k): Handle multiple routers */
204 0 : if (nh->nh_rid != 0)
205 0 : return -EINVAL;
206 :
207 0 : if (label < 0 || label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
208 0 : return -EINVAL;
209 :
210 0 : rte_rwlock_write_lock(&mpls_lock);
211 :
212 0 : uint32_t old_nh_id = label_to_nh[label].value.nexthop_id;
213 0 : bool mapping_removed = vr_dpdk_n3k_offload_mpls_remove_mapping(label);
214 :
215 0 : vr_dpdk_n3k_offload_mpls_insert((struct vr_n3k_offload_mpls) {
216 : .label = label,
217 0 : .nexthop_id = nh->nh_id,
218 : });
219 :
220 0 : rte_rwlock_write_unlock(&mpls_lock);
221 :
222 0 : if (mapping_removed) {
223 0 : RTE_LOG(
224 : WARNING, VROUTER,
225 : "%s(): nh=%p; nh_id=%u; label=%d; "
226 : "WARNING, label already offloaded; previous entry: nh_id=%u;\n",
227 : __func__, nh, nh->nh_id, label, old_nh_id
228 : );
229 : }
230 :
231 0 : return 0;
232 : }
233 :
234 : int
235 0 : vr_dpdk_n3k_offload_mpls_del(int label)
236 : {
237 0 : RTE_LOG(DEBUG, VROUTER, "%s() called; label=%d\n", __func__, label);
238 :
239 0 : if (label < 0 || label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
240 0 : return -EINVAL;
241 :
242 0 : rte_rwlock_write_lock(&mpls_lock);
243 0 : vr_dpdk_n3k_offload_mpls_remove_mapping(label);
244 0 : rte_rwlock_write_unlock(&mpls_lock);
245 :
246 0 : return 0;
247 : }
|