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