Line data Source code
1 : /*
2 : * vr_qos.c -- QOS implementation for vRouter datapath
3 : *
4 : * Copyright (c) 2015, Juniper Networks Inc.
5 : * All rights reserved
6 : */
7 : #include <vr_os.h>
8 : #include <vr_types.h>
9 : #include <vr_packet.h>
10 :
11 : #include "vr_message.h"
12 : #include "vr_sandesh.h"
13 : #include "vr_interface.h"
14 : #include "vr_datapath.h"
15 : #include "vr_qos.h"
16 : #include "vr_offloads_dp.h"
17 :
18 : unsigned int vr_qos_map_entries = VR_DEF_QOS_MAP_ENTRIES;
19 : unsigned int vr_fc_map_entries = VR_DEF_FC_MAP_ENTRIES;
20 : unsigned int vr_qos_map_entry_size = VR_QOS_MAP_ENTRY_SIZE;
21 :
22 : static void
23 0 : vr_qos_message_error(int error)
24 : {
25 0 : vr_send_response(error);
26 0 : return;
27 : }
28 :
29 : unsigned int
30 0 : vr_qos_map_req_get_size(void *object)
31 : {
32 : unsigned int size;
33 0 : vr_qos_map_req *req = (vr_qos_map_req *)object;
34 :
35 0 : size = 4 * sizeof(*req);
36 0 : size += 4 * req->qmr_dscp_size;
37 0 : size += 4 * req->qmr_dscp_fc_id_size;
38 0 : size += 4 * req->qmr_mpls_qos_size;
39 0 : size += 4 * req->qmr_mpls_qos_fc_id_size;
40 0 : size += 4 * req->qmr_dotonep_size;
41 0 : size += 4 * req->qmr_dotonep_fc_id_size;
42 :
43 0 : return size;
44 : }
45 :
46 : static int
47 0 : vr_qos_map_request_validate(vr_qos_map_req *req)
48 : {
49 0 : if (req->qmr_id >= vr_qos_map_entries)
50 0 : return -EINVAL;
51 :
52 0 : if (req->qmr_dscp_size != req->qmr_dscp_fc_id_size)
53 0 : return -EINVAL;
54 :
55 0 : if (req->qmr_mpls_qos_size != req->qmr_mpls_qos_fc_id_size)
56 0 : return -EINVAL;
57 :
58 0 : if (req->qmr_dotonep_size != req->qmr_dotonep_fc_id_size)
59 0 : return -EINVAL;
60 :
61 0 : return 0;
62 : }
63 :
64 : static struct vr_forwarding_class *
65 79 : vr_qos_map_get_fc(struct vrouter *router, unsigned int id)
66 : {
67 79 : if (id >= vr_qos_map_entries)
68 0 : return NULL;
69 :
70 79 : return router->vr_qos_map[id];
71 : }
72 :
73 : static int
74 0 : vr_qos_map_set_fc(struct vrouter *router, unsigned int id,
75 : struct vr_forwarding_class *fc_p)
76 : {
77 0 : if (id >= vr_qos_map_entries)
78 0 : return -EINVAL;
79 :
80 0 : router->vr_qos_map[id] = fc_p;
81 0 : return 0;
82 : }
83 :
84 : static void
85 0 : vr_qos_map_req_destroy(vr_qos_map_req *req)
86 : {
87 0 : if (!req)
88 0 : return;
89 :
90 0 : if (req->qmr_dscp && req->qmr_dscp_size) {
91 0 : vr_free(req->qmr_dscp, VR_QOS_MAP_OBJECT);
92 0 : req->qmr_dscp = NULL;
93 0 : req->qmr_dscp_size = 0;
94 0 : if (req->qmr_dscp_fc_id) {
95 0 : vr_free(req->qmr_dscp_fc_id, VR_QOS_MAP_OBJECT);
96 0 : req->qmr_dscp_fc_id_size = 0;
97 : }
98 : }
99 :
100 0 : if (req->qmr_mpls_qos && req->qmr_mpls_qos_size) {
101 0 : vr_free(req->qmr_mpls_qos, VR_QOS_MAP_OBJECT);
102 0 : req->qmr_mpls_qos = NULL;
103 0 : req->qmr_mpls_qos_size = 0;
104 0 : if (req->qmr_mpls_qos_fc_id) {
105 0 : vr_free(req->qmr_mpls_qos_fc_id, VR_QOS_MAP_OBJECT);
106 0 : req->qmr_mpls_qos_fc_id = NULL;
107 0 : req->qmr_mpls_qos_fc_id_size = 0;
108 : }
109 : }
110 :
111 0 : if (req->qmr_dotonep && req->qmr_dotonep_size) {
112 0 : vr_free(req->qmr_dotonep, VR_QOS_MAP_OBJECT);
113 0 : req->qmr_dotonep = NULL;
114 0 : req->qmr_dotonep_size = 0;
115 0 : if (req->qmr_dotonep_fc_id) {
116 0 : vr_free(req->qmr_dotonep_fc_id, VR_QOS_MAP_OBJECT);
117 0 : req->qmr_dotonep_fc_id = NULL;
118 0 : req->qmr_dotonep_fc_id_size = 0;
119 : }
120 : }
121 :
122 0 : vr_free(req, VR_QOS_MAP_OBJECT);
123 0 : return;
124 : }
125 :
126 : static vr_qos_map_req *
127 0 : vr_qos_map_req_get(void)
128 : {
129 : vr_qos_map_req *req;
130 :
131 0 : req = vr_zalloc(sizeof(vr_qos_map_req), VR_QOS_MAP_OBJECT);
132 0 : if (!req)
133 0 : return NULL;
134 :
135 0 : req->qmr_dscp =
136 0 : vr_zalloc(sizeof(uint8_t) * VR_DSCP_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
137 0 : if (!req->qmr_dscp) {
138 0 : goto alloc_failure;
139 : }
140 0 : req->qmr_dscp_size = VR_DSCP_QOS_ENTRIES;
141 :
142 0 : req->qmr_dscp_fc_id =
143 0 : vr_zalloc(sizeof(uint8_t) * VR_DSCP_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
144 0 : if (!req->qmr_dscp_fc_id) {
145 0 : goto alloc_failure;
146 : }
147 0 : req->qmr_dscp_fc_id_size = VR_DSCP_QOS_ENTRIES;
148 :
149 0 : req->qmr_mpls_qos =
150 0 : vr_zalloc(sizeof(uint8_t) * VR_MPLS_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
151 0 : if (!req->qmr_mpls_qos) {
152 0 : goto alloc_failure;
153 : }
154 0 : req->qmr_mpls_qos_size = VR_MPLS_QOS_ENTRIES;
155 :
156 0 : req->qmr_mpls_qos_fc_id =
157 0 : vr_zalloc(sizeof(uint8_t) * VR_MPLS_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
158 0 : if (!req->qmr_mpls_qos_fc_id) {
159 0 : goto alloc_failure;
160 : }
161 0 : req->qmr_mpls_qos_fc_id_size = VR_MPLS_QOS_ENTRIES;
162 :
163 0 : req->qmr_dotonep =
164 0 : vr_zalloc(sizeof(uint8_t) * VR_DOTONEP_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
165 0 : if (!req->qmr_dotonep) {
166 0 : goto alloc_failure;
167 : }
168 0 : req->qmr_dotonep_size = VR_DOTONEP_QOS_ENTRIES;
169 :
170 0 : req->qmr_dotonep_fc_id =
171 0 : vr_zalloc(sizeof(uint8_t) * VR_DOTONEP_QOS_ENTRIES, VR_QOS_MAP_OBJECT);
172 0 : if (!req->qmr_dotonep_fc_id) {
173 0 : goto alloc_failure;
174 : }
175 0 : req->qmr_dotonep_fc_id_size = VR_DOTONEP_QOS_ENTRIES;
176 :
177 0 : return req;
178 :
179 0 : alloc_failure:
180 0 : vr_qos_map_req_destroy(req);
181 0 : return NULL;
182 : }
183 :
184 : static void
185 0 : vr_qos_map_make_req(unsigned int qmrid, vr_qos_map_req *resp,
186 : struct vr_forwarding_class *fc_p)
187 : {
188 : unsigned int i;
189 :
190 0 : resp->qmr_id = qmrid;
191 :
192 0 : for (i = 0; i < VR_DSCP_QOS_ENTRIES; i++) {
193 0 : if (!fc_p[i].vfc_valid)
194 0 : continue;
195 :
196 0 : resp->qmr_dscp[i] = fc_p[i].vfc_dscp;
197 0 : resp->qmr_dscp_fc_id[i] = fc_p[i].vfc_id;
198 : }
199 :
200 0 : for (i = 0; i < VR_MPLS_QOS_ENTRIES; i++) {
201 0 : if (!fc_p[i].vfc_valid)
202 0 : continue;
203 :
204 0 : resp->qmr_mpls_qos[i] = fc_p[VR_DSCP_QOS_ENTRIES + i].vfc_mpls_qos;
205 0 : resp->qmr_mpls_qos_fc_id[i] = fc_p[VR_DSCP_QOS_ENTRIES + i].vfc_id;
206 : }
207 :
208 0 : for (i = 0; i < VR_DOTONEP_QOS_ENTRIES; i++) {
209 0 : if (!fc_p[i].vfc_valid)
210 0 : continue;
211 :
212 0 : resp->qmr_dotonep[i] =
213 0 : fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES + i].vfc_dotonep_qos;
214 0 : resp->qmr_dotonep_fc_id[i] =
215 0 : fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES + i].vfc_id;
216 : }
217 :
218 0 : return;
219 : }
220 :
221 : static void
222 0 : vr_qos_map_free_fc_cb(struct vrouter *router, void *data)
223 : {
224 0 : struct vr_defer_data *defer = (struct vr_defer_data *)data;
225 :
226 0 : if (!defer)
227 0 : return;
228 :
229 0 : vr_free(defer->vdd_data, VR_QOS_MAP_OBJECT);
230 0 : return;
231 : }
232 :
233 : static int
234 0 : vr_qos_map_free_fc_defer(struct vrouter *router,
235 : struct vr_forwarding_class *fc_p)
236 : {
237 : struct vr_defer_data *defer;
238 :
239 0 : defer = vr_get_defer_data(sizeof(*defer));
240 0 : if (!defer)
241 0 : return -ENOMEM;
242 :
243 0 : defer->vdd_data = fc_p;
244 0 : vr_defer(router, vr_qos_map_free_fc_cb, (void *)defer);
245 :
246 0 : return 0;
247 : }
248 :
249 : static void
250 0 : vr_qos_map_delete(vr_qos_map_req *req)
251 : {
252 0 : int ret = 0;
253 :
254 : struct vr_forwarding_class *fc_p;
255 0 : struct vrouter *router = vrouter_get(req->qmr_rid);
256 :
257 0 : if (req->qmr_id >= vr_qos_map_entries) {
258 0 : ret = -EINVAL;
259 0 : goto generate_response;
260 : }
261 :
262 0 : fc_p = vr_qos_map_get_fc(router, req->qmr_id);
263 0 : if (!fc_p) {
264 0 : ret = 0;
265 0 : goto generate_response;
266 : }
267 :
268 0 : vr_qos_map_set_fc(router, req->qmr_id, NULL);
269 0 : if (vr_qos_map_free_fc_defer(router, fc_p)) {
270 0 : vr_delay_op();
271 0 : vr_free(fc_p, VR_QOS_MAP_OBJECT);
272 : }
273 :
274 0 : (void)vr_offload_qos_map_del(req);
275 :
276 0 : generate_response:
277 0 : vr_send_response(ret);
278 0 : return;
279 : }
280 :
281 : static void
282 0 : vr_qos_map_dump(vr_qos_map_req *req)
283 : {
284 0 : int ret = 0;
285 : unsigned int i;
286 :
287 : vr_qos_map_req *resp;
288 : struct vr_forwarding_class *fc_p;
289 0 : struct vrouter *router = vrouter_get(req->qmr_rid);
290 0 : struct vr_message_dumper *dumper = NULL;
291 :
292 0 : if (req->qmr_marker + 1 >= vr_qos_map_entries)
293 0 : goto generate_response;
294 :
295 0 : dumper = vr_message_dump_init(req);
296 0 : if (!dumper) {
297 0 : ret = -ENOMEM;
298 0 : goto generate_response;
299 : }
300 :
301 0 : for (i = (req->qmr_marker + 1); i < vr_qos_map_entries; i++) {
302 0 : fc_p = vr_qos_map_get_fc(router, i);
303 0 : if (!fc_p)
304 0 : continue;
305 :
306 0 : resp = vr_qos_map_req_get();
307 0 : if (!resp) {
308 0 : ret = -ENOMEM;
309 0 : goto generate_response;
310 : }
311 :
312 0 : vr_qos_map_make_req(i, resp, fc_p);
313 :
314 0 : (void)vr_offload_qos_map_get(resp);
315 :
316 0 : ret = vr_message_dump_object(dumper, VR_QOS_MAP_OBJECT_ID, resp);
317 0 : vr_qos_map_req_destroy(resp);
318 0 : if (ret <= 0)
319 0 : break;
320 : }
321 :
322 0 : generate_response:
323 0 : vr_message_dump_exit(dumper, ret);
324 0 : return;
325 : }
326 :
327 : static void
328 0 : vr_qos_map_get(vr_qos_map_req *req)
329 : {
330 0 : int ret = 0;
331 :
332 : vr_qos_map_req *resp;
333 0 : struct vrouter *router = vrouter_get(req->qmr_rid);
334 0 : struct vr_forwarding_class *fc_p = NULL;
335 :
336 0 : if (req->qmr_id >= vr_qos_map_entries) {
337 0 : ret = -EINVAL;
338 0 : goto get_error;
339 : }
340 :
341 0 : fc_p = vr_qos_map_get_fc(router, req->qmr_id);
342 0 : if (!fc_p) {
343 0 : ret = -ENOENT;
344 0 : goto get_error;
345 : }
346 :
347 0 : resp = vr_qos_map_req_get();
348 0 : if (!resp) {
349 0 : ret = -ENOMEM;
350 0 : goto get_error;
351 : }
352 :
353 0 : vr_qos_map_make_req(req->qmr_id, resp, fc_p);
354 :
355 : /* Debug comparison to check if matching entry is programmed on NIC */
356 0 : (void)vr_offload_qos_map_get(resp);
357 :
358 0 : vr_message_response(VR_QOS_MAP_OBJECT_ID, resp, ret, false);
359 0 : if (resp) {
360 0 : vr_qos_map_req_destroy(resp);
361 : }
362 :
363 0 : return;
364 :
365 0 : get_error:
366 0 : vr_send_response(ret);
367 0 : return;
368 : }
369 :
370 : static void
371 0 : vr_qos_map_add(vr_qos_map_req *req)
372 : {
373 0 : int ret = 0;
374 0 : bool need_set = false;
375 : unsigned int size, i;
376 :
377 0 : struct vrouter *router = vrouter_get(req->qmr_rid);
378 : struct vr_forwarding_class *fc_p, *fc_e;
379 :
380 0 : ret = vr_qos_map_request_validate(req);
381 0 : if (ret) {
382 0 : goto generate_response;
383 : }
384 :
385 0 : fc_p = vr_qos_map_get_fc(router, req->qmr_id);
386 0 : if (!fc_p) {
387 0 : size = vr_qos_map_entry_size * sizeof(struct vr_forwarding_class);
388 0 : fc_p = vr_zalloc(size, VR_QOS_MAP_OBJECT);
389 0 : if (!fc_p) {
390 0 : ret = -ENOMEM;
391 0 : goto generate_response;
392 : }
393 0 : need_set = true;
394 : }
395 :
396 0 : for (i = 0; i < req->qmr_dscp_size; i++) {
397 0 : if (req->qmr_dscp[i] >= VR_DSCP_QOS_ENTRIES)
398 0 : continue;
399 :
400 0 : fc_e = &fc_p[req->qmr_dscp[i]];
401 0 : fc_e->vfc_dscp = req->qmr_dscp[i];
402 0 : fc_e->vfc_id = req->qmr_dscp_fc_id[i];
403 0 : fc_e->vfc_valid = 1;
404 : }
405 :
406 0 : for (i = 0; i < req->qmr_mpls_qos_size; i++) {
407 0 : if (req->qmr_mpls_qos[i] >= VR_MPLS_QOS_ENTRIES)
408 0 : continue;
409 :
410 0 : fc_e = &fc_p[VR_DSCP_QOS_ENTRIES + req->qmr_mpls_qos[i]];
411 0 : fc_e->vfc_mpls_qos = req->qmr_mpls_qos[i];
412 0 : fc_e->vfc_id = req->qmr_mpls_qos_fc_id[i];
413 0 : fc_e->vfc_valid = 1;
414 : }
415 :
416 0 : for (i = 0; i < req->qmr_dotonep_size; i++) {
417 0 : if (req->qmr_dotonep[i] >= VR_DOTONEP_QOS_ENTRIES)
418 0 : continue;
419 :
420 0 : fc_e = &fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES +
421 0 : req->qmr_dotonep[i]];
422 0 : fc_e->vfc_dotonep_qos = req->qmr_dotonep[i];
423 0 : fc_e->vfc_id = req->qmr_dotonep_fc_id[i];
424 0 : fc_e->vfc_valid = 1;
425 : }
426 :
427 0 : ret = vr_offload_qos_map_add(req);
428 0 : if (ret) {
429 0 : vr_printf("offload QoS map not supported - not configuring\n");
430 0 : vr_free(fc_p, VR_QOS_MAP_OBJECT);
431 0 : goto generate_response;
432 : }
433 :
434 0 : if (need_set) {
435 0 : vr_qos_map_set_fc(router, req->qmr_id, fc_p);
436 : }
437 :
438 0 : generate_response:
439 0 : vr_send_response(ret);
440 0 : return;
441 : }
442 :
443 : void
444 0 : vr_qos_map_req_process(void *s_req)
445 : {
446 0 : vr_qos_map_req *req = (vr_qos_map_req *)s_req;
447 :
448 0 : switch (req->h_op) {
449 0 : case SANDESH_OP_ADD:
450 0 : vr_qos_map_add(req);
451 0 : break;
452 :
453 0 : case SANDESH_OP_GET:
454 0 : vr_qos_map_get(req);
455 0 : break;
456 :
457 0 : case SANDESH_OP_DUMP:
458 0 : vr_qos_map_dump(req);
459 0 : break;
460 :
461 0 : case SANDESH_OP_DEL:
462 0 : vr_qos_map_delete(req);
463 0 : break;
464 :
465 0 : default:
466 0 : vr_qos_message_error(-EINVAL);
467 0 : break;
468 : }
469 :
470 0 : return;
471 : }
472 :
473 : static struct vr_forwarding_class *
474 0 : vr_fc_map_get_fc(struct vrouter *router, unsigned int i)
475 : {
476 0 : if (i >= vr_fc_map_entries)
477 0 : return NULL;
478 :
479 0 : return &router->vr_fc_table[i];
480 : }
481 :
482 : static void
483 0 : vr_fc_map_req_destroy(vr_fc_map_req *req)
484 : {
485 0 : if (!req)
486 0 : return;
487 :
488 0 : if (req->fmr_id) {
489 0 : vr_free(req->fmr_id, VR_FC_OBJECT);
490 0 : req->fmr_id_size = 0;
491 : }
492 :
493 0 : if (req->fmr_dscp) {
494 0 : vr_free(req->fmr_dscp, VR_FC_OBJECT);
495 0 : req->fmr_dscp_size = 0;
496 : }
497 :
498 0 : if (req->fmr_mpls_qos) {
499 0 : vr_free(req->fmr_mpls_qos, VR_FC_OBJECT);
500 0 : req->fmr_mpls_qos_size = 0;
501 : }
502 :
503 0 : if (req->fmr_dotonep) {
504 0 : vr_free(req->fmr_dotonep, VR_FC_OBJECT);
505 0 : req->fmr_dotonep_size = 0;
506 : }
507 :
508 0 : if (req->fmr_queue_id) {
509 0 : vr_free(req->fmr_queue_id, VR_FC_OBJECT);
510 0 : req->fmr_queue_id_size = 0;
511 : }
512 :
513 0 : vr_free(req, VR_FC_OBJECT);
514 0 : return;
515 : }
516 :
517 : static vr_fc_map_req *
518 0 : vr_fc_map_req_get(unsigned int entries)
519 : {
520 : vr_fc_map_req *req;
521 :
522 0 : req = vr_zalloc(sizeof(*req), VR_FC_OBJECT);
523 0 : if (!req)
524 0 : return NULL;
525 :
526 0 : req->fmr_id = vr_zalloc(entries, VR_FC_OBJECT);
527 0 : if (!req->fmr_id) {
528 0 : goto error;
529 : }
530 0 : req->fmr_id_size = entries;
531 :
532 0 : req->fmr_dscp = vr_zalloc(entries, VR_FC_OBJECT);
533 0 : if (!req->fmr_dscp) {
534 0 : goto error;
535 : }
536 0 : req->fmr_dscp_size = entries;
537 :
538 0 : req->fmr_mpls_qos = vr_zalloc(entries, VR_FC_OBJECT);
539 0 : if (!req->fmr_mpls_qos) {
540 0 : goto error;
541 : }
542 0 : req->fmr_mpls_qos_size = entries;
543 :
544 0 : req->fmr_dotonep = vr_zalloc(entries, VR_FC_OBJECT);
545 0 : if (!req->fmr_dotonep) {
546 0 : goto error;
547 : }
548 0 : req->fmr_dotonep_size = entries;
549 :
550 0 : req->fmr_queue_id = vr_zalloc(entries, VR_FC_OBJECT);
551 0 : if (!req->fmr_queue_id) {
552 0 : goto error;
553 : }
554 0 : req->fmr_queue_id_size = entries;
555 :
556 0 : return req;
557 :
558 0 : error:
559 0 : vr_fc_map_req_destroy(req);
560 0 : return NULL;
561 : }
562 :
563 : static void
564 0 : vr_fc_map_delete(vr_fc_map_req *req)
565 : {
566 0 : int ret = 0;
567 :
568 0 : struct vrouter *router = vrouter_get(req->fmr_rid);
569 : struct vr_forwarding_class *fc_p;
570 :
571 0 : if (!req->fmr_id) {
572 0 : ret = -EINVAL;
573 0 : goto generate_response;
574 : }
575 :
576 0 : if (req->fmr_id[0] >= vr_fc_map_entries) {
577 0 : ret = -EINVAL;
578 0 : goto generate_response;
579 : }
580 :
581 0 : fc_p = vr_fc_map_get_fc(router, req->fmr_id[0]);
582 0 : if (!fc_p) {
583 0 : ret = -EINVAL;
584 0 : goto generate_response;
585 : }
586 :
587 0 : memset(fc_p, 0, sizeof(*fc_p));
588 0 : (void)vr_offload_fc_map_del(req);
589 0 : vr_send_response(0);
590 :
591 0 : return;
592 :
593 0 : generate_response:
594 0 : vr_send_response(ret);
595 0 : return;
596 : }
597 :
598 : static void
599 0 : vr_fc_map_dump(vr_fc_map_req *req)
600 : {
601 0 : int ret = 0;
602 : unsigned int i;
603 :
604 : vr_fc_map_req *resp;
605 : struct vr_forwarding_class *fc_p;
606 0 : struct vrouter *router = vrouter_get(req->fmr_rid);
607 0 : struct vr_message_dumper *dumper = NULL;
608 :
609 0 : if (req->fmr_marker + 1 >= vr_fc_map_entries)
610 0 : goto generate_response;
611 :
612 0 : dumper = vr_message_dump_init(req);
613 0 : if (!dumper) {
614 0 : ret = -ENOMEM;
615 0 : goto generate_response;
616 : }
617 :
618 0 : for (i = (req->fmr_marker + 1); i < vr_fc_map_entries; i++) {
619 0 : fc_p = vr_fc_map_get_fc(router, i);
620 0 : if (!fc_p || !fc_p->vfc_valid)
621 0 : continue;
622 :
623 0 : resp = vr_fc_map_req_get(1);
624 0 : if (!resp) {
625 0 : ret = -ENOMEM;
626 0 : goto generate_response;
627 : }
628 :
629 0 : resp->fmr_id[0] = i;
630 0 : resp->fmr_dscp[0] = fc_p->vfc_dscp;
631 0 : resp->fmr_mpls_qos[0] = fc_p->vfc_mpls_qos;
632 0 : resp->fmr_dotonep[0] = fc_p->vfc_dotonep_qos;
633 0 : resp->fmr_queue_id[0] = fc_p->vfc_queue_id;
634 :
635 0 : (void)vr_offload_fc_map_get(resp);
636 :
637 0 : ret = vr_message_dump_object(dumper, VR_FC_MAP_OBJECT_ID, resp);
638 0 : vr_fc_map_req_destroy(resp);
639 0 : if (ret <= 0)
640 0 : break;
641 : }
642 :
643 0 : generate_response:
644 0 : vr_message_dump_exit(dumper, ret);
645 0 : return;
646 : }
647 :
648 : static void
649 0 : vr_fc_map_get(vr_fc_map_req *req)
650 : {
651 0 : int ret = 0;
652 :
653 0 : vr_fc_map_req *resp = NULL;
654 0 : struct vrouter *router = vrouter_get(req->fmr_rid);
655 : struct vr_forwarding_class *fc_p;
656 :
657 0 : if (!req->fmr_id) {
658 0 : ret = -EINVAL;
659 0 : goto generate_response;
660 : }
661 :
662 0 : if (req->fmr_id[0] >= vr_fc_map_entries) {
663 0 : ret = -EINVAL;
664 0 : goto generate_response;
665 : }
666 :
667 0 : fc_p = vr_fc_map_get_fc(router, req->fmr_id[0]);
668 0 : if (!fc_p || !fc_p->vfc_valid) {
669 0 : ret = -ENOENT;
670 0 : goto generate_response;
671 : }
672 :
673 0 : resp = vr_fc_map_req_get(1);
674 0 : if (!resp) {
675 0 : ret = -ENOMEM;
676 0 : goto generate_response;
677 : }
678 :
679 0 : resp->fmr_id[0] = req->fmr_id[0];
680 0 : resp->fmr_dscp[0] = fc_p->vfc_dscp;
681 0 : resp->fmr_mpls_qos[0] = fc_p->vfc_mpls_qos;
682 0 : resp->fmr_dotonep[0] = fc_p->vfc_dotonep_qos;
683 0 : resp->fmr_queue_id[0] = fc_p->vfc_queue_id;
684 :
685 : /* Debug comparison to check if matching entry is programmed on NIC */
686 0 : (void)vr_offload_fc_map_get(resp);
687 :
688 0 : generate_response:
689 0 : vr_message_response(VR_FC_MAP_OBJECT_ID, ret < 0 ? NULL : resp, ret, false);
690 0 : if (resp)
691 0 : vr_fc_map_req_destroy(resp);
692 :
693 0 : return;
694 : }
695 :
696 : static void
697 0 : vr_fc_map_add(vr_fc_map_req *req)
698 : {
699 0 : int ret = 0;
700 : unsigned int i;
701 :
702 0 : struct vrouter *router = vrouter_get(req->fmr_rid);
703 : struct vr_forwarding_class *fc_p;
704 :
705 0 : if (!req->fmr_id || !req->fmr_id_size ||
706 0 : !req->fmr_dscp || !req->fmr_dscp_size ||
707 0 : !req->fmr_mpls_qos || !req->fmr_mpls_qos_size ||
708 0 : !req->fmr_dotonep || !req->fmr_dotonep_size ||
709 0 : !req->fmr_queue_id || !req->fmr_queue_id_size) {
710 0 : ret = -EINVAL;
711 0 : goto generate_response;
712 : }
713 :
714 0 : for (i = 0; i < req->fmr_id_size; i++) {
715 0 : fc_p = vr_fc_map_get_fc(router, req->fmr_id[i]);
716 0 : if (!fc_p) {
717 0 : ret = -EINVAL;
718 0 : goto generate_response;
719 : }
720 :
721 0 : fc_p->vfc_id = req->fmr_id[i];
722 0 : fc_p->vfc_dscp = req->fmr_dscp[i];
723 0 : fc_p->vfc_mpls_qos = req->fmr_mpls_qos[i];
724 0 : fc_p->vfc_dotonep_qos = req->fmr_dotonep[i];
725 0 : fc_p->vfc_queue_id = req->fmr_queue_id[i];
726 0 : fc_p->vfc_valid = 1;
727 : }
728 :
729 0 : ret = vr_offload_fc_map_add(req);
730 0 : if (ret) {
731 0 : vr_printf("offload FC map not supported - not configuring\n");
732 0 : for (i = 0; i < req->fmr_id_size; i++) {
733 0 : fc_p = vr_fc_map_get_fc(router, req->fmr_id[i]);
734 0 : if (fc_p)
735 0 : memset(fc_p, 0, sizeof(*fc_p));
736 : }
737 : }
738 :
739 0 : generate_response:
740 0 : vr_send_response(ret);
741 0 : return;
742 : }
743 :
744 : void
745 0 : vr_fc_map_req_process(void *s_req)
746 : {
747 0 : vr_fc_map_req *req = (vr_fc_map_req *)s_req;
748 :
749 0 : switch (req->h_op) {
750 0 : case SANDESH_OP_ADD:
751 0 : vr_fc_map_add(req);
752 0 : break;
753 :
754 0 : case SANDESH_OP_GET:
755 0 : vr_fc_map_get(req);
756 0 : break;
757 :
758 0 : case SANDESH_OP_DUMP:
759 0 : vr_fc_map_dump(req);
760 0 : break;
761 :
762 0 : case SANDESH_OP_DEL:
763 0 : vr_fc_map_delete(req);
764 0 : break;
765 :
766 0 : default:
767 0 : vr_qos_message_error(-EINVAL);
768 0 : break;
769 : }
770 :
771 0 : return;
772 : }
773 :
774 : struct vr_forwarding_class_qos *
775 79 : vr_qos_get_forwarding_class(struct vrouter *router, struct vr_packet *pkt,
776 : struct vr_forwarding_md *fmd)
777 : {
778 : int8_t tos;
779 79 : int16_t qos_id = -1;
780 : unsigned int fc_id;
781 :
782 : struct vr_interface *vif;
783 : struct vr_forwarding_class *fc_p;
784 :
785 79 : vif = pkt->vp_if;
786 :
787 79 : if (fmd->fmd_flow_index >= 0) {
788 21 : qos_id = vr_flow_get_qos(router, pkt, fmd);
789 : }
790 :
791 79 : if (qos_id < 0) {
792 79 : qos_id = vif->vif_qos_map_index;
793 : }
794 :
795 79 : if (qos_id >= 0) {
796 79 : fc_p = vr_qos_map_get_fc(router, qos_id);
797 79 : if (!fc_p)
798 79 : return NULL;
799 :
800 0 : if (pkt->vp_type == VP_TYPE_IP || pkt->vp_type == VP_TYPE_IP6) {
801 0 : tos = fmd->fmd_dscp;
802 : } else {
803 0 : tos = fmd->fmd_dotonep;
804 0 : if (tos >= 0)
805 0 : tos += VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES;
806 : }
807 :
808 0 : if (tos >= 0) {
809 0 : fc_id = fc_p[tos].vfc_id;
810 0 : fc_p = vr_fc_map_get_fc(router, fc_id);
811 0 : if (!fc_p->vfc_valid)
812 0 : return NULL;
813 :
814 0 : return &fc_p->vfc_qos;
815 : }
816 : }
817 :
818 0 : return NULL;
819 : }
820 :
821 : void
822 53 : vr_qos_exit(struct vrouter *router, bool soft_reset)
823 : {
824 : unsigned int i;
825 : unsigned long size;
826 :
827 53 : if (soft_reset) {
828 0 : size = vr_qos_map_entries * sizeof(struct vr_forwarding_class *);
829 0 : if (router->vr_qos_map) {
830 0 : memset(router->vr_qos_map, 0, size);
831 : }
832 0 : size = vr_fc_map_entries * sizeof(struct vr_forwarding_class);
833 0 : if (router->vr_fc_table) {
834 0 : memset(router->vr_fc_table, 0, size);
835 : }
836 : } else {
837 53 : if (router->vr_qos_map) {
838 217141 : for (i = 0; i < vr_qos_map_entries; i++) {
839 217088 : if (router->vr_qos_map[i]) {
840 0 : vr_free(router->vr_qos_map[i], VR_QOS_MAP_OBJECT);
841 0 : router->vr_qos_map[i] = NULL;
842 : }
843 : }
844 53 : vr_free(router->vr_qos_map, VR_QOS_MAP_OBJECT);
845 53 : router->vr_qos_map = NULL;
846 : }
847 :
848 53 : if (router->vr_fc_table) {
849 53 : vr_free(router->vr_fc_table, VR_FC_OBJECT);
850 53 : router->vr_fc_table = NULL;
851 : }
852 : }
853 :
854 53 : return;
855 : }
856 :
857 : int
858 53 : vr_qos_init(struct vrouter *router)
859 : {
860 : unsigned long size;
861 :
862 53 : if (!router->vr_qos_map) {
863 53 : size = vr_qos_map_entries * sizeof(struct vr_forwarding_class *);
864 53 : router->vr_qos_map = vr_zalloc(size, VR_QOS_MAP_OBJECT);
865 53 : if (!router->vr_qos_map) {
866 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size);
867 : }
868 : }
869 :
870 53 : if (!router->vr_fc_table) {
871 53 : size = vr_fc_map_entries * sizeof(struct vr_forwarding_class);
872 53 : router->vr_fc_table = vr_zalloc(size, VR_FC_OBJECT);
873 53 : if (!router->vr_fc_table) {
874 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size);
875 : }
876 : }
877 :
878 53 : return 0;
879 : }
|