blob: 5401efe4700d25cf13a19d280140ff7a153dcfe8 [file] [log] [blame]
Yu Huang6b2f0be2017-10-18 16:11:49 -07001/*
2 **************************************************************************
Cemil Coskun26be6162019-06-28 15:44:48 -07003 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
Yu Huang6b2f0be2017-10-18 16:11:49 -07004 * 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"
Sachin Shashidhar0fc1a142018-08-08 14:15:27 -070019#include "nss_qrfs_log.h"
Yu Huang6b2f0be2017-10-18 16:11:49 -070020
21/*
22 * Notify data structure
23 */
24struct nss_qrfs_notify_data {
25 nss_qrfs_msg_callback_t qrfs_callback;
26 void *app_data;
27};
28
29static struct nss_qrfs_notify_data nss_qrfs_notify[NSS_CORE_MAX];
30
31/*
32 * nss_qrfs_verify_if_num()
33 * Verify if_num passed to us.
34 */
35static bool nss_qrfs_verify_if_num(uint32_t if_num)
36{
37 return if_num == NSS_QRFS_INTERFACE;
38}
39
40/*
41 * nss_qrfs_msg_handler()
42 * Handle NSS -> HLOS messages for QRFS
43 */
44static void nss_qrfs_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
45{
46 struct nss_qrfs_msg *nqm = (struct nss_qrfs_msg *)ncm;
47 nss_qrfs_msg_callback_t cb;
48
Sachin Shashidhar0fc1a142018-08-08 14:15:27 -070049 /*
50 * Trace messages.
51 */
52 nss_qrfs_log_rx_msg(nqm);
53
Yu Huang6b2f0be2017-10-18 16:11:49 -070054 if (!nss_qrfs_verify_if_num(ncm->interface)) {
55 nss_warning("%p: invalid interface %d for QRFS\n", nss_ctx, ncm->interface);
56 return;
57 }
58
59 /*
60 * Is this a valid request/response?
61 */
62 if (ncm->type >= NSS_QRFS_MSG_MAX) {
63 nss_warning("%p: invalid message %d for QRFS\n", nss_ctx, ncm->type);
64 return;
65 }
66
67 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_qrfs_msg)) {
68 nss_warning("%p: message length is greater than required: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
69 return;
70 }
71
72 /*
73 * Log failures
74 */
75 nss_core_log_msg_failures(nss_ctx, ncm);
76
Yu Huange189d8a2018-01-04 17:45:57 -080077 switch (ncm->type) {
78 case NSS_QRFS_MSG_STATS_SYNC:
79 /*
80 * Update QRFS statistics.
81 */
82 nss_qrfs_stats_sync(nss_ctx, &nqm->msg.stats_sync);
83 break;
84 }
85
Yu Huang6b2f0be2017-10-18 16:11:49 -070086 /*
87 * Update the callback and app_data for NOTIFY messages
88 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +053089 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Yu Huang6b2f0be2017-10-18 16:11:49 -070090 ncm->cb = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].qrfs_callback;
91 ncm->app_data = (nss_ptr_t)nss_qrfs_notify[nss_ctx->id].app_data;
92 }
93
94 /*
95 * Do we have a callback?
96 */
97 if (!ncm->cb) {
98 return;
99 }
100
101 /*
102 * callback
103 */
104 cb = (nss_qrfs_msg_callback_t)ncm->cb;
105 cb((void *)ncm->app_data, nqm);
106}
107
108/*
109 * nss_qrfs_get_ctx()
110 */
111static struct nss_ctx_instance *nss_qrfs_get_ctx(int core_id)
112{
113 return &nss_top_main.nss[core_id];
114}
115
116/*
117 * nss_qrfs_get_flow_keys()
118 * Get 5 tuple information from flow keys and set in flow rule message.
119 */
120#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 18, 21))
121static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
122 struct nss_qrfs_flow_rule_msg *nqfrm)
123{
124 struct flow_keys keys;
125 uint16_t protocol = skb->protocol;
126 bool res;
127 struct ipv6hdr *ip6hdr;
128
129 res = skb_flow_dissect(skb, &keys);
130 if (!res) {
131 nss_warning("%p: failed to get flow keys\n", nss_ctx);
132 return res;
133 }
134
135 nqfrm->protocol = keys.ip_proto;
136 nqfrm->src_port = keys.port16[0];
137 nqfrm->dst_port = keys.port16[1];
138
139 if (protocol == htons(ETH_P_IP)) {
140 nqfrm->ip_version = 4;
141 nqfrm->src_addr[0] = keys.src;
142 nqfrm->dst_addr[0] = keys.dst;
143 return true;
144 }
145
146 nqfrm->ip_version = 6;
147 ip6hdr = (struct ipv6hdr *)skb_network_header(skb);
148 if (!ip6hdr) {
149 nss_warning("%p: failed to get IPv6 address\n", nss_ctx);
150 return false;
151 }
152
153 memcpy(nqfrm->src_addr, &ip6hdr->saddr, sizeof(struct in6_addr));
154 memcpy(nqfrm->dst_addr, &ip6hdr->daddr, sizeof(struct in6_addr));
155
156 return true;
157}
158#else
159static bool nss_qrfs_get_flow_keys(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb,
160 struct nss_qrfs_flow_rule_msg *nqfrm)
161{
162 struct flow_keys keys;
163 bool res;
164
165 res = skb_flow_dissect_flow_keys(skb, &keys, 0);
166 if (!res) {
167 nss_warning("%p: failed to get flow keys\n", nss_ctx);
168 return res;
169 }
170
171 nqfrm->protocol = (uint16_t)keys.basic.ip_proto;
172 nqfrm->src_port = keys.ports.src;
173 nqfrm->dst_port = keys.ports.dst;
174
175 if (keys.basic.n_proto == htons(ETH_P_IP)) {
176 nqfrm->ip_version = 4;
177 nqfrm->src_addr[0] = keys.addrs.v4addrs.src;
178 nqfrm->dst_addr[0] = keys.addrs.v4addrs.dst;
179 return true;
180 }
181
182 nqfrm->ip_version = 6;
183 memcpy(nqfrm->src_addr, &keys.addrs.v6addrs.src, sizeof(struct in6_addr));
184 memcpy(nqfrm->dst_addr, &keys.addrs.v6addrs.dst, sizeof(struct in6_addr));
185
186 return true;
187}
188#endif
189
190/*
191 * nss_qrfs_flow_add_msg_callback()
192 * Callback function for receiving flow add response messages.
193 */
194static void nss_qrfs_flow_add_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
195{
196 struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
197 struct nss_qrfs_flow_rule_msg *nqfrm;
198
199 if (nqm->cm.type != NSS_QRFS_MSG_FLOW_ADD) {
200 nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
201 return;
202 }
203
204 nqfrm = &nqm->msg.flow_add;
205
206 if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
207 nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
208 return;
209 }
210
211 if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
212 nss_warning("%p: flow add configuration error: %d for NSS core %d\n",
213 nss_ctx, nqm->cm.error, nss_ctx->id);
214 }
215}
216
217/*
218 * nss_qrfs_flow_delete_msg_callback()
219 * Callback function for receiving flow delete response messages.
220 */
221static void nss_qrfs_flow_delete_msg_callback(void *app_data, struct nss_qrfs_msg *nqm)
222{
223 struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data;
224 struct nss_qrfs_flow_rule_msg *nqfrm;
225
226 if (nqm->cm.type != NSS_QRFS_MSG_FLOW_DELETE) {
227 nss_warning("%p: invalid flow response message %d\n", nss_ctx, nqm->cm.type);
228 return;
229 }
230
231 nqfrm = &nqm->msg.flow_delete;
232
233 if ((nqfrm->ip_version != 4) && (nqfrm->ip_version != 6)) {
234 nss_warning("%p: invalid IP version %d\n", nss_ctx, nqfrm->ip_version);
235 return;
236 }
237
238 if (nqm->cm.response != NSS_CMN_RESPONSE_ACK) {
239 nss_warning("%p: flow delete configuration error: %d for NSS core %d\n",
240 nss_ctx, nqm->cm.error, nss_ctx->id);
241 }
242}
243
244/*
245 * nss_qrfs_msg_init()
246 * Initialize the common header of QRFS message
247 */
248static 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)
249{
250 nss_cmn_msg_init(&nqm->cm, if_num, type, len, cb, app_data);
251}
252
253/*
254 * nss_qrfs_tx_msg()
255 * Transmit a QRFS message to NSS firmware
256 */
257static nss_tx_status_t nss_qrfs_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_qrfs_msg *msg)
258{
Yu Huang6b2f0be2017-10-18 16:11:49 -0700259 struct nss_cmn_msg *ncm = &msg->cm;
Yu Huang6b2f0be2017-10-18 16:11:49 -0700260
261 /*
Sachin Shashidhar0fc1a142018-08-08 14:15:27 -0700262 * Trace messages.
263 */
264 nss_qrfs_log_tx_msg(msg);
265
266 /*
Yu Huang6b2f0be2017-10-18 16:11:49 -0700267 * Sanity check the message
268 */
269 if (!nss_qrfs_verify_if_num(ncm->interface)) {
270 nss_warning("%p: interface is not QRFS interface: %d\n", nss_ctx, ncm->interface);
271 return NSS_TX_FAILURE;
272 }
273
274 if (ncm->type >= NSS_QRFS_MSG_MAX) {
275 nss_warning("%p: message type is out of range: %d\n", nss_ctx, ncm->type);
276 return NSS_TX_FAILURE;
277 }
278
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700279 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Yu Huang6b2f0be2017-10-18 16:11:49 -0700280}
281
282/*
283 * nss_qrfs_add_flow_rule()
284 * Set a QRFS flow rule add message and transmit the message to NSS core.
285 */
286static nss_tx_status_t nss_qrfs_add_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
287 struct sk_buff *skb, uint32_t cpu, bool need_cb)
288{
289 struct nss_qrfs_msg nqm;
290 struct nss_qrfs_flow_rule_msg *nqfrm;
291 nss_tx_status_t status;
292 nss_qrfs_msg_callback_t cb = NULL;
293 void *app_data = NULL;
294 bool res;
295
296 memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
297
298 if (need_cb) {
299 cb = nss_qrfs_flow_add_msg_callback;
300 app_data = (void *)nss_ctx;
301 }
302
303 /*
304 * Initialize common header of QRFS flow rule add message.
305 */
306 nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_ADD,
307 sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
308
309 /*
310 * Set flow rule of QRFS flow rule add message
311 */
312 nqfrm = &nqm.msg.flow_add;
313 res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
314 if (!res) {
315 return NSS_TX_FAILURE;
316 }
317
318 nqfrm->cpu = (uint16_t)cpu;
319 nqfrm->if_num = if_num;
320
321 /*
322 * Send QRFS flow rule add message to NSS core
323 */
324 status = nss_qrfs_tx_msg(nss_ctx, &nqm);
325 if (status == NSS_TX_SUCCESS) {
326 return status;
327 }
328
329 return NSS_TX_FAILURE;
330}
331
332/*
333 * nss_qrfs_delete_flow_rule()
334 * Set a QRFS delete flow rule message and transmit the message to all NSS core.
335 */
336static nss_tx_status_t nss_qrfs_delete_flow_rule(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
337 struct sk_buff *skb, uint32_t cpu, bool need_cb)
338{
339 struct nss_qrfs_msg nqm;
340 struct nss_qrfs_flow_rule_msg *nqfrm;
341 nss_tx_status_t status;
342 nss_qrfs_msg_callback_t cb = NULL;
343 void *app_data = NULL;
344 bool res;
345
346 memset(&nqm, 0, sizeof(struct nss_qrfs_msg));
347
348 if (need_cb) {
349 cb = nss_qrfs_flow_delete_msg_callback;
350 app_data = (void *)nss_ctx;
351 }
352
353 /*
354 * Initialize common header of QRFS flow rule delete message.
355 */
356 nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, NSS_QRFS_MSG_FLOW_DELETE,
357 sizeof(struct nss_qrfs_flow_rule_msg), cb, app_data);
358
359 /*
360 * Set flow rule of QRFS flow rule delete message
361 */
362 nqfrm = &nqm.msg.flow_delete;
363 res = nss_qrfs_get_flow_keys(nss_ctx, skb, nqfrm);
364 if (!res) {
365 return NSS_TX_FAILURE;
366 }
367
368 nqfrm->cpu = (uint16_t)cpu;
369 nqfrm->if_num = if_num;
370
371 /*
372 * Send QRFS flow rule delete message to NSS core
373 */
374 status = nss_qrfs_tx_msg(nss_ctx, &nqm);
375 if (status == NSS_TX_SUCCESS) {
376 return status;
377 }
378
379 return NSS_TX_FAILURE;
380}
381
382/*
383 * nss_qrfs_set_flow_rule()
384 * Set a QRFS flow rule message and transmit the message to all NSS cores.
385 */
Jackson Bockusbd1080c2018-07-30 16:33:41 -0700386nss_tx_status_t nss_qrfs_set_flow_rule(struct sk_buff *skb, uint32_t cpu, uint32_t action)
Yu Huang6b2f0be2017-10-18 16:11:49 -0700387{
388 struct nss_ctx_instance *nss_ctx;
389 nss_tx_status_t status;
390 int i;
391
392 for (i = 0; i < NSS_CORE_MAX; i++) {
393 nss_ctx = nss_qrfs_get_ctx(i);
394
395 /*
396 * Set QRFS flow rule message and transmit the message to NSS core.
Jackson Bockusbd1080c2018-07-30 16:33:41 -0700397 *
398 * TODO: Remove if_num parameter from add_flow_rule() and
399 * delete_flow_rule(), since it is unused in firmware.
Yu Huang6b2f0be2017-10-18 16:11:49 -0700400 */
401 if (action == NSS_QRFS_MSG_FLOW_ADD) {
Jackson Bockusbd1080c2018-07-30 16:33:41 -0700402 status = nss_qrfs_add_flow_rule(nss_ctx, 0, skb, cpu, true);
Yu Huang6b2f0be2017-10-18 16:11:49 -0700403 } else {
Jackson Bockusbd1080c2018-07-30 16:33:41 -0700404 status = nss_qrfs_delete_flow_rule(nss_ctx, 0, skb, cpu, true);
Yu Huang6b2f0be2017-10-18 16:11:49 -0700405 }
406
407 if (status != NSS_TX_SUCCESS) {
408 nss_warning("%p: failed to send flow rule to NSS core %d\n", nss_ctx, i);
409 return NSS_TX_FAILURE;
410 }
411 }
412
413 return NSS_TX_SUCCESS;
414}
415EXPORT_SYMBOL(nss_qrfs_set_flow_rule);
416
417/*
418 * nss_qrfs_register_handler()
419 */
420void nss_qrfs_register_handler(struct nss_ctx_instance *nss_ctx)
421{
422 nss_core_register_handler(nss_ctx, NSS_QRFS_INTERFACE, nss_qrfs_msg_handler, NULL);
Cemil Coskun26be6162019-06-28 15:44:48 -0700423
424 if (nss_ctx->id == NSS_CORE_0) {
425 nss_qrfs_stats_dentry_create();
426 }
Yu Huang6b2f0be2017-10-18 16:11:49 -0700427}
428EXPORT_SYMBOL(nss_qrfs_register_handler);
429
430/*
431 * nss_qrfs_notify_register()
432 * Register to receive QRFS notify messages.
433 */
434struct nss_ctx_instance *nss_qrfs_notify_register(int core, nss_qrfs_msg_callback_t cb, void *app_data)
435{
436 if (core >= NSS_CORE_MAX) {
437 nss_warning("Input core number %d is wrong\n", core);
438 return NULL;
439 }
440
441 nss_qrfs_notify[core].qrfs_callback = cb;
442 nss_qrfs_notify[core].app_data = app_data;
443
444 return (struct nss_ctx_instance *)&nss_top_main.nss[core];
445}
446
447/*
448 * nss_qrfs_notify_unregister()
449 * Unregister to receive QRFS notify messages.
450 */
451void nss_qrfs_notify_unregister(int core)
452{
453 if (core >= NSS_CORE_MAX) {
454 nss_warning("Input core number %d is wrong\n", core);
455 return;
456 }
457
458 nss_qrfs_notify[core].qrfs_callback = NULL;
459 nss_qrfs_notify[core].app_data = NULL;
460}
461
462/*
463 * nss_qrfs_init()
464 */
465void nss_qrfs_init(void)
466{
467 int core;
468
469 for (core = 0; core < NSS_CORE_MAX; core++) {
470 nss_qrfs_notify_register(core, NULL, NULL);
471 }
472}