blob: 121cd48aaed499329d7501f1c3a605c9217a3b33 [file] [log] [blame]
Yu Huang6b2f0be2017-10-18 16:11:49 -07001/*
2 **************************************************************************
3 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
17#include "nss_tx_rx_common.h"
Yu Huange189d8a2018-01-04 17:45:57 -080018#include "nss_qrfs_stats.h"
Yu Huang6b2f0be2017-10-18 16:11:49 -070019
20/*
21 * Notify data structure
22 */
23struct nss_qrfs_notify_data {
24 nss_qrfs_msg_callback_t qrfs_callback;
25 void *app_data;
26};
27
28static struct nss_qrfs_notify_data nss_qrfs_notify[NSS_CORE_MAX];
29
30/*
31 * nss_qrfs_verify_if_num()
32 * Verify if_num passed to us.
33 */
34static bool nss_qrfs_verify_if_num(uint32_t if_num)
35{
36 return if_num == NSS_QRFS_INTERFACE;
37}
38
39/*
40 * nss_qrfs_msg_handler()
41 * Handle NSS -> HLOS messages for QRFS
42 */
43static void nss_qrfs_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
44{
45 struct nss_qrfs_msg *nqm = (struct nss_qrfs_msg *)ncm;
46 nss_qrfs_msg_callback_t cb;
47
48 if (!nss_qrfs_verify_if_num(ncm->interface)) {
49 nss_warning("%p: invalid interface %d for QRFS\n", nss_ctx, ncm->interface);
50 return;
51 }
52
53 /*
54 * Is this a valid request/response?
55 */
56 if (ncm->type >= NSS_QRFS_MSG_MAX) {
57 nss_warning("%p: invalid message %d for QRFS\n", nss_ctx, ncm->type);
58 return;
59 }
60
61 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_qrfs_msg)) {
62 nss_warning("%p: message length is greater than required: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
63 return;
64 }
65
66 /*
67 * Log failures
68 */
69 nss_core_log_msg_failures(nss_ctx, ncm);
70
Yu Huange189d8a2018-01-04 17:45:57 -080071 switch (ncm->type) {
72 case NSS_QRFS_MSG_STATS_SYNC:
73 /*
74 * Update QRFS statistics.
75 */
76 nss_qrfs_stats_sync(nss_ctx, &nqm->msg.stats_sync);
77 break;
78 }
79
Yu Huang6b2f0be2017-10-18 16:11:49 -070080 /*
81 * Update the callback and app_data for NOTIFY messages
82 */
83 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
84 ncm->cb = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].qrfs_callback;
85 ncm->app_data = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].app_data;
86 }
87
88 /*
89 * Do we have a callback?
90 */
91 if (!ncm->cb) {
92 return;
93 }
94
95 /*
96 * callback
97 */
98 cb = (nss_qrfs_msg_callback_t)ncm->cb;
99 cb((void *)ncm->app_data, nqm);
100}
101
102/*
103 * nss_qrfs_get_ctx()
104 */
105static struct nss_ctx_instance *nss_qrfs_get_ctx(int core_id)
106{
107 return &nss_top_main.nss[core_id];
108}
109
110/*
111 * nss_qrfs_get_flow_keys()
112 * Get 5 tuple information from flow keys and set in flow rule message.
113 */
114#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 18, 21))
115static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
116 struct nss_qrfs_flow_rule_msg *nqfrm)
117{
118 struct flow_keys keys;
119 uint16_t protocol = skb->protocol;
120 bool res;
121 struct ipv6hdr *ip6hdr;
122
123 res = skb_flow_dissect(skb, &keys);
124 if (!res) {
125 nss_warning("%p: failed to get flow keys\n", nss_ctx);
126 return res;
127 }
128
129 nqfrm->protocol = keys.ip_proto;
130 nqfrm->src_port = keys.port16[0];
131 nqfrm->dst_port = keys.port16[1];
132
133 if (protocol == htons(ETH_P_IP)) {
134 nqfrm->ip_version = 4;
135 nqfrm->src_addr[0] = keys.src;
136 nqfrm->dst_addr[0] = keys.dst;
137 return true;
138 }
139
140 nqfrm->ip_version = 6;
141 ip6hdr = (struct ipv6hdr *)skb_network_header(skb);
142 if (!ip6hdr) {
143 nss_warning("%p: failed to get IPv6 address\n", nss_ctx);
144 return false;
145 }
146
147 memcpy(nqfrm->src_addr, &ip6hdr->saddr, sizeof(struct in6_addr));
148 memcpy(nqfrm->dst_addr, &ip6hdr->daddr, sizeof(struct in6_addr));
149
150 return true;
151}
152#else
153static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
154 struct nss_qrfs_flow_rule_msg *nqfrm)
155{
156 struct flow_keys keys;
157 bool res;
158
159 res = skb_flow_dissect_flow_keys(skb, &keys, 0);
160 if (!res) {
161 nss_warning("%p: failed to get flow keys\n", nss_ctx);
162 return res;
163 }
164
165 nqfrm->protocol = (uint16_t)keys.basic.ip_proto;
166 nqfrm->src_port = keys.ports.src;
167 nqfrm->dst_port = keys.ports.dst;
168
169 if (keys.basic.n_proto == htons(ETH_P_IP)) {
170 nqfrm->ip_version = 4;
171 nqfrm->src_addr[0] = keys.addrs.v4addrs.src;
172 nqfrm->dst_addr[0] = keys.addrs.v4addrs.dst;
173 return true;
174 }
175
176 nqfrm->ip_version = 6;
177 memcpy(nqfrm->src_addr, &keys.addrs.v6addrs.src, sizeof(struct in6_addr));
178 memcpy(nqfrm->dst_addr, &keys.addrs.v6addrs.dst, sizeof(struct in6_addr));
179
180 return true;
181}
182#endif
183
184/*
185 * nss_qrfs_flow_add_msg_callback()
186 * Callback function for receiving flow add response messages.
187 */
188static void nss_qrfs_flow_add_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
189{
190 struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
191 struct nss_qrfs_flow_rule_msg *nqfrm;
192
193 if (nqm->cm.type != NSS_QRFS_MSG_FLOW_ADD) {
194 nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
195 return;
196 }
197
198 nqfrm = &nqm->msg.flow_add;
199
200 if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
201 nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
202 return;
203 }
204
205 if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
206 nss_warning("%p: flow add configuration error: %d for NSS core %d\n",
207 nss_ctx, nqm->cm.error, nss_ctx->id);
208 }
209}
210
211/*
212 * nss_qrfs_flow_delete_msg_callback()
213 * Callback function for receiving flow delete response messages.
214 */
215static void nss_qrfs_flow_delete_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
216{
217 struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
218 struct nss_qrfs_flow_rule_msg *nqfrm;
219
220 if (nqm->cm.type != NSS_QRFS_MSG_FLOW_DELETE) {
221 nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
222 return;
223 }
224
225 nqfrm = &nqm->msg.flow_delete;
226
227 if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
228 nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
229 return;
230 }
231
232 if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
233 nss_warning("%p: flow delete configuration error: %d for NSS core %d\n",
234 nss_ctx, nqm->cm.error, nss_ctx->id);
235 }
236}
237
238/*
239 * nss_qrfs_msg_init()
240 * Initialize the common header of QRFS message
241 */
242static void nss_qrfs_msg_init(struct nss_qrfs_msg *nqm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
243{
244 nss_cmn_msg_init(&nqm->cm, if_num, type, len, cb, app_data);
245}
246
247/*
248 * nss_qrfs_tx_msg()
249 * Transmit a QRFS message to NSS firmware
250 */
251static nss_tx_status_t nss_qrfs_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_qrfs_msg *msg)
252{
253 struct nss_qrfs_msg *nqm;
254 struct nss_cmn_msg *ncm = &msg->cm;
255 struct sk_buff *nbuf;
256 int32_t status;
257
258 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
259 nss_warning("%p: message dropped as core not ready\n", nss_ctx);
260 return NSS_TX_FAILURE_NOT_READY;
261 }
262
263 /*
264 * Sanity check the message
265 */
266 if (!nss_qrfs_verify_if_num(ncm->interface)) {
267 nss_warning("%p: interface is not QRFS interface: %d\n", nss_ctx, ncm->interface);
268 return NSS_TX_FAILURE;
269 }
270
271 if (ncm->type >= NSS_QRFS_MSG_MAX) {
272 nss_warning("%p: message type is out of range: %d\n", nss_ctx, ncm->type);
273 return NSS_TX_FAILURE;
274 }
275
276 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_qrfs_msg)) {
277 nss_warning("%p: message length is invalid: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
278 return NSS_TX_FAILURE;
279 }
280
281 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
282 if (unlikely(!nbuf)) {
283 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
284 nss_warning("%p: message allocation failed\n", nss_ctx);
285 return NSS_TX_FAILURE;
286 }
287
288 /*
289 * Copy the message to our skb
290 */
291 nqm = (struct nss_qrfs_msg *)skb_put(nbuf, sizeof(struct nss_qrfs_msg));
292 memcpy(nqm, msg, sizeof(struct nss_qrfs_msg));
293
294 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
295 if (status != NSS_CORE_STATUS_SUCCESS) {
296 dev_kfree_skb_any(nbuf);
297 nss_warning("%p: unable to enqueue QRFS message\n", nss_ctx);
298 return NSS_TX_FAILURE;
299 }
300
301 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
302
303 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
304
305 return NSS_TX_SUCCESS;
306}
307
308/*
309 * nss_qrfs_add_flow_rule()
310 * Set a QRFS flow rule add message and transmit the message to NSS core.
311 */
312static nss_tx_status_t nss_qrfs_add_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
313 struct sk_buff *skb, uint32_t cpu, bool need_cb)
314{
315 struct nss_qrfs_msg nqm;
316 struct nss_qrfs_flow_rule_msg *nqfrm;
317 nss_tx_status_t status;
318 nss_qrfs_msg_callback_t cb = NULL;
319 void *app_data = NULL;
320 bool res;
321
322 memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
323
324 if (need_cb) {
325 cb = nss_qrfs_flow_add_msg_callback;
326 app_data = (void *)nss_ctx;
327 }
328
329 /*
330 * Initialize common header of QRFS flow rule add message.
331 */
332 nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_ADD,
333 sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
334
335 /*
336 * Set flow rule of QRFS flow rule add message
337 */
338 nqfrm = &nqm.msg.flow_add;
339 res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
340 if (!res) {
341 return NSS_TX_FAILURE;
342 }
343
344 nqfrm->cpu = (uint16_t)cpu;
345 nqfrm->if_num = if_num;
346
347 /*
348 * Send QRFS flow rule add message to NSS core
349 */
350 status = nss_qrfs_tx_msg(nss_ctx, &nqm);
351 if (status == NSS_TX_SUCCESS) {
352 return status;
353 }
354
355 return NSS_TX_FAILURE;
356}
357
358/*
359 * nss_qrfs_delete_flow_rule()
360 * Set a QRFS delete flow rule message and transmit the message to all NSS core.
361 */
362static nss_tx_status_t nss_qrfs_delete_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
363 struct sk_buff *skb, uint32_t cpu, bool need_cb)
364{
365 struct nss_qrfs_msg nqm;
366 struct nss_qrfs_flow_rule_msg *nqfrm;
367 nss_tx_status_t status;
368 nss_qrfs_msg_callback_t cb = NULL;
369 void *app_data = NULL;
370 bool res;
371
372 memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
373
374 if (need_cb) {
375 cb = nss_qrfs_flow_delete_msg_callback;
376 app_data = (void *)nss_ctx;
377 }
378
379 /*
380 * Initialize common header of QRFS flow rule delete message.
381 */
382 nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_DELETE,
383 sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
384
385 /*
386 * Set flow rule of QRFS flow rule delete message
387 */
388 nqfrm = &nqm.msg.flow_delete;
389 res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
390 if (!res) {
391 return NSS_TX_FAILURE;
392 }
393
394 nqfrm->cpu = (uint16_t)cpu;
395 nqfrm->if_num = if_num;
396
397 /*
398 * Send QRFS flow rule delete message to NSS core
399 */
400 status = nss_qrfs_tx_msg(nss_ctx, &nqm);
401 if (status == NSS_TX_SUCCESS) {
402 return status;
403 }
404
405 return NSS_TX_FAILURE;
406}
407
408/*
409 * nss_qrfs_set_flow_rule()
410 * Set a QRFS flow rule message and transmit the message to all NSS cores.
411 */
412nss_tx_status_t nss_qrfs_set_flow_rule(struct net_device *netdev, uint32_t if_num,
413 struct sk_buff *skb, uint32_t cpu, uint32_t action)
414{
415 struct nss_ctx_instance *nss_ctx;
416 nss_tx_status_t status;
417 int i;
418
419 for (i = 0; i < NSS_CORE_MAX; i++) {
420 nss_ctx = nss_qrfs_get_ctx(i);
421
422 /*
423 * Set QRFS flow rule message and transmit the message to NSS core.
424 */
425 if (action == NSS_QRFS_MSG_FLOW_ADD) {
426 status = nss_qrfs_add_flow_rule(nss_ctx, if_num, skb, cpu, true);
427 } else {
428 status = nss_qrfs_delete_flow_rule(nss_ctx, if_num, skb, cpu, true);
429 }
430
431 if (status != NSS_TX_SUCCESS) {
432 nss_warning("%p: failed to send flow rule to NSS core %d\n", nss_ctx, i);
433 return NSS_TX_FAILURE;
434 }
435 }
436
437 return NSS_TX_SUCCESS;
438}
439EXPORT_SYMBOL(nss_qrfs_set_flow_rule);
440
441/*
442 * nss_qrfs_register_handler()
443 */
444void nss_qrfs_register_handler(struct nss_ctx_instance *nss_ctx)
445{
446 nss_core_register_handler(nss_ctx, NSS_QRFS_INTERFACE, nss_qrfs_msg_handler, NULL);
Yu Huange189d8a2018-01-04 17:45:57 -0800447 nss_qrfs_stats_dentry_create();
Yu Huang6b2f0be2017-10-18 16:11:49 -0700448}
449EXPORT_SYMBOL(nss_qrfs_register_handler);
450
451/*
452 * nss_qrfs_notify_register()
453 * Register to receive QRFS notify messages.
454 */
455struct nss_ctx_instance *nss_qrfs_notify_register(int core, nss_qrfs_msg_callback_t cb, void *app_data)
456{
457 if (core >= NSS_CORE_MAX) {
458 nss_warning("Input core number %d is wrong\n", core);
459 return NULL;
460 }
461
462 nss_qrfs_notify[core].qrfs_callback = cb;
463 nss_qrfs_notify[core].app_data = app_data;
464
465 return (struct nss_ctx_instance *)&nss_top_main.nss[core];
466}
467
468/*
469 * nss_qrfs_notify_unregister()
470 * Unregister to receive QRFS notify messages.
471 */
472void nss_qrfs_notify_unregister(int core)
473{
474 if (core >= NSS_CORE_MAX) {
475 nss_warning("Input core number %d is wrong\n", core);
476 return;
477 }
478
479 nss_qrfs_notify[core].qrfs_callback = NULL;
480 nss_qrfs_notify[core].app_data = NULL;
481}
482
483/*
484 * nss_qrfs_init()
485 */
486void nss_qrfs_init(void)
487{
488 int core;
489
490 for (core = 0; core < NSS_CORE_MAX; core++) {
491 nss_qrfs_notify_register(core, NULL, NULL);
492 }
493}