1/*
2 **************************************************************************
3 * Copyright (c) 2013-2015, 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/*
18 * nss_ipv4.c
19 *	NSS IPv4 APIs
20 */
21#include <linux/sysctl.h>
22#include "nss_tx_rx_common.h"
23
24int nss_ipv4_conn_cfg __read_mostly = NSS_DEFAULT_NUM_CONN;
25static struct  nss_conn_cfg_pvt i4cfgp;
26
27/*
28
29 * nss_ipv4_max_conn_count()
30 *     Return the maximum number of IPv4 connections that the NSS acceleration engine supports.
31 */
32int nss_ipv4_max_conn_count(void)
33{
34    return nss_core_max_ipv4_conn_get();
35}
36EXPORT_SYMBOL(nss_ipv4_max_conn_count);
37
38/*
39 * nss_ipv4_driver_conn_sync_update()
40 *	Update driver specific information from the messsage.
41 */
42static void nss_ipv4_driver_conn_sync_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync *nirs)
43{
44	struct nss_top_instance *nss_top = nss_ctx->nss_top;
45
46	/*
47	 * Update statistics maintained by NSS driver
48	 */
49	spin_lock_bh(&nss_top->stats_lock);
50	nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_RX_PKTS] += nirs->flow_rx_packet_count + nirs->return_rx_packet_count;
51	nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_RX_BYTES] += nirs->flow_rx_byte_count + nirs->return_rx_byte_count;
52	nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_TX_PKTS] += nirs->flow_tx_packet_count + nirs->return_tx_packet_count;
53	nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_TX_BYTES] += nirs->flow_tx_byte_count + nirs->return_tx_byte_count;
54	spin_unlock_bh(&nss_top->stats_lock);
55}
56
57/*
58 * nss_ipv4_driver_conn_sync_many_update()
59 *	Update driver specific information from the conn_sync_many messsage.
60 */
61static void nss_ipv4_driver_conn_sync_many_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync_many_msg *nicsm)
62{
63	int i;
64
65	/*
66	 * Sanity check for the stats count
67	 */
68	if (nicsm->count * sizeof(struct nss_ipv4_conn_sync) >= nicsm->size) {
69		nss_warning("%p: stats sync count %u exceeds the size of this msg %u", nss_ctx, nicsm->count, nicsm->size);
70		return;
71	}
72
73	for (i = 0; i < nicsm->count; i++) {
74		nss_ipv4_driver_conn_sync_update(nss_ctx, &nicsm->conn_sync[i]);
75	}
76}
77
78/*
79 * nss_ipv4_driver_node_sync_update)
80 *	Update driver specific information from the messsage.
81 */
82static void nss_ipv4_driver_node_sync_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_node_sync *nins)
83{
84	struct nss_top_instance *nss_top = nss_ctx->nss_top;
85	uint32_t i;
86
87	/*
88	 * Update statistics maintained by NSS driver
89	 */
90	spin_lock_bh(&nss_top->stats_lock);
91	nss_top->stats_node[NSS_IPV4_RX_INTERFACE][NSS_STATS_NODE_RX_PKTS] += nins->node_stats.rx_packets;
92	nss_top->stats_node[NSS_IPV4_RX_INTERFACE][NSS_STATS_NODE_RX_BYTES] += nins->node_stats.rx_bytes;
93	nss_top->stats_node[NSS_IPV4_RX_INTERFACE][NSS_STATS_NODE_RX_DROPPED] += nins->node_stats.rx_dropped;
94	nss_top->stats_node[NSS_IPV4_RX_INTERFACE][NSS_STATS_NODE_TX_PKTS] += nins->node_stats.tx_packets;
95	nss_top->stats_node[NSS_IPV4_RX_INTERFACE][NSS_STATS_NODE_TX_BYTES] += nins->node_stats.tx_bytes;
96
97	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_CREATE_REQUESTS] += nins->ipv4_connection_create_requests;
98	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_CREATE_COLLISIONS] += nins->ipv4_connection_create_collisions;
99	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_CREATE_INVALID_INTERFACE] += nins->ipv4_connection_create_invalid_interface;
100	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_DESTROY_REQUESTS] += nins->ipv4_connection_destroy_requests;
101	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_DESTROY_MISSES] += nins->ipv4_connection_destroy_misses;
102	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_HASH_HITS] += nins->ipv4_connection_hash_hits;
103	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_HASH_REORDERS] += nins->ipv4_connection_hash_reorders;
104	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_FLUSHES] += nins->ipv4_connection_flushes;
105	nss_top->stats_ipv4[NSS_STATS_IPV4_CONNECTION_EVICTIONS] += nins->ipv4_connection_evictions;
106	nss_top->stats_ipv4[NSS_STATS_IPV4_FRAGMENTATIONS] += nins->ipv4_fragmentations;
107	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_CREATE_REQUESTS] += nins->ipv4_mc_connection_create_requests;
108	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_UPDATE_REQUESTS] += nins->ipv4_mc_connection_update_requests;
109	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_CREATE_INVALID_INTERFACE] += nins->ipv4_mc_connection_create_invalid_interface;
110	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_DESTROY_REQUESTS] += nins->ipv4_mc_connection_destroy_requests;
111	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_DESTROY_MISSES] += nins->ipv4_mc_connection_destroy_misses;
112	nss_top->stats_ipv4[NSS_STATS_IPV4_MC_CONNECTION_FLUSHES] += nins->ipv4_mc_connection_flushes;
113
114	for (i = 0; i < NSS_EXCEPTION_EVENT_IPV4_MAX; i++) {
115		 nss_top->stats_if_exception_ipv4[i] += nins->exception_events[i];
116	}
117	spin_unlock_bh(&nss_top->stats_lock);
118}
119
120/*
121 * nss_ipv4_rx_msg_handler()
122 *	Handle NSS -> HLOS messages for IPv4 bridge/route
123 */
124static void nss_ipv4_rx_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
125{
126	struct nss_ipv4_msg *nim = (struct nss_ipv4_msg *)ncm;
127	nss_ipv4_msg_callback_t cb;
128
129	BUG_ON(ncm->interface != NSS_IPV4_RX_INTERFACE);
130
131	/*
132	 * Sanity check the message type
133	 */
134	if (ncm->type >= NSS_IPV4_MAX_MSG_TYPES) {
135		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
136		return;
137	}
138
139	if (ncm->len > sizeof(struct nss_ipv4_msg)) {
140		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
141		return;
142	}
143
144	/*
145	 * Log failures
146	 */
147	nss_core_log_msg_failures(nss_ctx, ncm);
148
149	switch (nim->cm.type) {
150	case NSS_IPV4_RX_NODE_STATS_SYNC_MSG:
151		/*
152		* Update driver statistics on node sync.
153		*/
154		nss_ipv4_driver_node_sync_update(nss_ctx, &nim->msg.node_stats);
155		break;
156
157	case NSS_IPV4_RX_CONN_STATS_SYNC_MSG:
158		/*
159		 * Update driver statistics on connection sync.
160		 */
161		nss_ipv4_driver_conn_sync_update(nss_ctx, &nim->msg.conn_stats);
162		break;
163
164	case NSS_IPV4_TX_CONN_STATS_SYNC_MANY_MSG:
165		/*
166		 * Update driver statistics on connection sync many.
167		 */
168		nss_ipv4_driver_conn_sync_many_update(nss_ctx, &nim->msg.conn_stats_many);
169		break;
170	}
171
172	/*
173	 * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
174	 * to the same callback/app_data.
175	 */
176	if (nim->cm.response == NSS_CMM_RESPONSE_NOTIFY) {
177		ncm->cb = (uint32_t)nss_ctx->nss_top->ipv4_callback;
178		ncm->app_data = (uint32_t)nss_ctx->nss_top->ipv4_ctx;
179	}
180
181	/*
182	 * Do we have a callback?
183	 */
184	if (!ncm->cb) {
185		return;
186	}
187
188	/*
189	 * Callback
190	 */
191	cb = (nss_ipv4_msg_callback_t)ncm->cb;
192	cb((void *)ncm->app_data, nim);
193}
194
195/*
196 * nss_ipv4_tx_with_size()
197 *	Transmit an ipv4 message to the FW with a specified size.
198 */
199nss_tx_status_t nss_ipv4_tx_with_size(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim, uint32_t size)
200{
201	struct nss_ipv4_msg *nim2;
202	struct nss_cmn_msg *ncm = &nim->cm;
203	struct sk_buff *nbuf;
204	int32_t status;
205
206	NSS_VERIFY_CTX_MAGIC(nss_ctx);
207	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
208		nss_warning("%p: ipv4 msg dropped as core not ready", nss_ctx);
209		return NSS_TX_FAILURE_NOT_READY;
210	}
211
212	/*
213	 * Sanity check the message
214	 */
215	if (ncm->interface != NSS_IPV4_RX_INTERFACE) {
216		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
217		return NSS_TX_FAILURE;
218	}
219
220	if (ncm->type >= NSS_IPV4_MAX_MSG_TYPES) {
221		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
222		return NSS_TX_FAILURE;
223	}
224
225	if (ncm->len > sizeof(struct nss_ipv4_msg)) {
226		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
227		return NSS_TX_FAILURE;
228	}
229
230	if(size > PAGE_SIZE) {
231		nss_warning("%p: tx request size too large: %u", nss_ctx, size);
232		return NSS_TX_FAILURE;
233	}
234
235	nbuf = dev_alloc_skb(size);
236	if (unlikely(!nbuf)) {
237		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
238		nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
239		return NSS_TX_FAILURE;
240	}
241
242	/*
243	 * Copy the message to our skb.
244	 */
245	nim2 = (struct nss_ipv4_msg *)skb_put(nbuf, sizeof(struct nss_ipv4_msg));
246	memcpy(nim2, nim, sizeof(struct nss_ipv4_msg));
247
248	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
249	if (status != NSS_CORE_STATUS_SUCCESS) {
250		dev_kfree_skb_any(nbuf);
251		nss_warning("%p: unable to enqueue IPv4 msg\n", nss_ctx);
252		return NSS_TX_FAILURE;
253	}
254
255	nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
256								NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
257
258	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
259	return NSS_TX_SUCCESS;
260}
261
262/*
263 * nss_ipv4_tx()
264 *	Transmit an ipv4 message to the FW.
265 */
266nss_tx_status_t nss_ipv4_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim)
267{
268	return nss_ipv4_tx_with_size(nss_ctx, nim, NSS_NBUF_PAYLOAD_SIZE);
269}
270
271/*
272 **********************************
273 Register/Unregister/Miscellaneous APIs
274 **********************************
275 */
276
277/*
278 * nss_ipv4_notify_register()
279 *	Register to received IPv4 events.
280 *
281 * NOTE: Do we want to pass an nss_ctx here so that we can register for ipv4 on any core?
282 */
283struct nss_ctx_instance *nss_ipv4_notify_register(nss_ipv4_msg_callback_t cb, void *app_data)
284{
285	/*
286	 * TODO: We need to have a new array in support of the new API
287	 * TODO: If we use a per-context array, we would move the array into nss_ctx based.
288	 */
289	nss_top_main.ipv4_callback = cb;
290	nss_top_main.ipv4_ctx = app_data;
291	return &nss_top_main.nss[nss_top_main.ipv4_handler_id];
292}
293
294/*
295 * nss_ipv4_notify_unregister()
296 *	Unregister to received IPv4 events.
297 *
298 * NOTE: Do we want to pass an nss_ctx here so that we can register for ipv4 on any core?
299 */
300void nss_ipv4_notify_unregister(void)
301{
302	nss_top_main.ipv4_callback = NULL;
303}
304
305/*
306 * nss_ipv4_get_mgr()
307 *
308 * TODO: This only suppports a single ipv4, do we ever want to support more?
309 */
310struct nss_ctx_instance *nss_ipv4_get_mgr(void)
311{
312	return (void *)&nss_top_main.nss[nss_top_main.ipv4_handler_id];
313}
314
315/*
316 * nss_ipv4_register_handler()
317 *	Register our handler to receive messages for this interface
318 */
319void nss_ipv4_register_handler(void)
320{
321	if (nss_core_register_handler(NSS_IPV4_RX_INTERFACE, nss_ipv4_rx_msg_handler, NULL) != NSS_CORE_STATUS_SUCCESS) {
322		nss_warning("IPv4 handler failed to register");
323	}
324}
325
326/*
327 * nss_ipv4_conn_cfg_process()
328 *	Process request to configure number of ipv4 connections
329 */
330static int nss_ipv4_conn_cfg_process(struct nss_ctx_instance *nss_ctx, int conn,
331				     void (*cfg_cb)(void *app_data, struct nss_ipv4_msg *nim))
332{
333	struct nss_ipv4_msg nim;
334	struct nss_ipv4_rule_conn_cfg_msg *nirccm;
335	nss_tx_status_t nss_tx_status;
336	uint32_t sum_of_conn;
337
338	/*
339	 * The input should be multiple of 1024.
340	 * Input for ipv4 and ipv6 sum together should not exceed 8k
341	 * Min. value should be at least 256 connections. This is the
342	 * minimum connections we will support for each of them.
343	 */
344	sum_of_conn = conn + nss_ipv6_conn_cfg;
345	if ((conn & NSS_NUM_CONN_QUANTA_MASK) ||
346		(sum_of_conn > NSS_MAX_TOTAL_NUM_CONN_IPV4_IPV6) ||
347		(conn < NSS_MIN_NUM_CONN)) {
348		nss_warning("%p: input supported connections (%d) does not adhere\
349				specifications\n1) not multiple of 1024,\n2) is less than \
350				min val: %d, OR\n 	IPv4/6 total exceeds %d\n",
351				nss_ctx,
352				conn,
353				NSS_MIN_NUM_CONN,
354				NSS_MAX_TOTAL_NUM_CONN_IPV4_IPV6);
355		return -EINVAL;
356	}
357
358	nss_info("%p: IPv4 supported connections: %d\n", nss_ctx, conn);
359
360	memset(&nim, 0, sizeof(struct nss_ipv4_msg));
361	nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CONN_CFG_RULE_MSG,
362		sizeof(struct nss_ipv4_rule_conn_cfg_msg), cfg_cb, NULL);
363
364	nirccm = &nim.msg.rule_conn_cfg;
365	nirccm->num_conn = htonl(conn);
366	nss_tx_status = nss_ipv4_tx(nss_ctx, &nim);
367
368	if (nss_tx_status != NSS_TX_SUCCESS) {
369		nss_warning("%p: nss_tx error setting IPv4 Connections: %d\n",
370							nss_ctx,
371							conn);
372		return -EIO;
373	}
374
375	return 0;
376}
377
378/*
379 * nss_ipv4_conn_cfg_callback()
380 *	call back function for the ipv4 connection configuration handler
381 */
382static void nss_ipv4_conn_cfg_callback(void *app_data, struct nss_ipv4_msg *nim)
383{
384
385	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
386		nss_warning("IPv4 connection configuration failed with error: %d\n", nim->cm.error);
387		/*
388		 * Error, hence we are not updating the nss_ipv4_conn_cfg
389		 * Restore the current_value to its previous state
390		 */
391		i4cfgp.response = NSS_FAILURE;
392		complete(&i4cfgp.complete);
393		return;
394	}
395
396	/*
397	 * Sucess at NSS FW, hence updating nss_ipv4_conn_cfg, with the valid value
398	 * saved at the sysctl handler.
399	 */
400	nss_info("IPv4 connection configuration success: %d\n", nim->cm.error);
401	i4cfgp.response = NSS_SUCCESS;
402	complete(&i4cfgp.complete);
403}
404
405/*
406 * nss_ipv4_conn_cfg_handler()
407 *	Sets the number of connections for IPv4
408 */
409static int nss_ipv4_conn_cfg_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
410{
411	struct nss_top_instance *nss_top = &nss_top_main;
412	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
413	int ret = NSS_FAILURE;
414
415	/*
416	 * Acquiring semaphore
417	 */
418	down(&i4cfgp.sem);
419
420	/*
421	 * Take snap shot of current value
422	 */
423	i4cfgp.current_value = nss_ipv4_conn_cfg;
424
425	/*
426	 * Write the variable with user input
427	 */
428	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
429	if (ret || (!write)) {
430		up(&i4cfgp.sem);
431		return ret;
432	}
433
434	/*
435	 * Process request to change number of IPv4 connections
436	 */
437	ret = nss_ipv4_conn_cfg_process(nss_ctx, nss_ipv4_conn_cfg, nss_ipv4_conn_cfg_callback);
438	if (ret != 0) {
439		goto failure;
440	}
441
442	/*
443	 * Blocking call, wait till we get ACK for this msg.
444	 */
445	ret = wait_for_completion_timeout(&i4cfgp.complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
446	if (ret == 0) {
447		nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
448		goto failure;
449	}
450
451	/*
452	 * ACK/NACK received from NSS FW
453	 * If ACK: Callback function will update nss_ipv4_conn_cfg with
454	 * i4cfgp.num_conn_valid, which holds the user input
455	 */
456	if (NSS_FAILURE == i4cfgp.response) {
457		goto failure;
458	}
459
460	up(&i4cfgp.sem);
461	return 0;
462
463failure:
464	/*
465	 * Restore the current_value to its previous state
466	 */
467	nss_ipv4_conn_cfg = i4cfgp.current_value;
468	up(&i4cfgp.sem);
469	return -EINVAL;
470}
471
472/*
473 * nss_ipv4_update_conn_count_cb()
474 *	call back function for the ipv4 connection count update handler
475 */
476static void nss_ipv4_update_conn_count_cb(void *app_data, struct nss_ipv4_msg *nim)
477{
478	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
479		nss_warning("IPv4 connection count update failed with error: %d\n", nim->cm.error);
480		return;
481	}
482
483	nss_warning("IPv4 connection count update success: %d\n", nim->cm.error);
484}
485
486/*
487 * nss_ipv4_update_conn_count()
488 *	Sets the maximum number of connections for IPv4
489 */
490int nss_ipv4_update_conn_count(int ipv4_num_conn)
491{
492	struct nss_top_instance *nss_top = &nss_top_main;
493	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
494	int saved_nss_ipv4_conn_cfg = nss_ipv4_conn_cfg;
495	int ret = 0;
496
497	nss_ipv4_conn_cfg = ipv4_num_conn;
498
499	/*
500	 * Process request to change number of IPv4 connections
501	 */
502	ret = nss_ipv4_conn_cfg_process(nss_ctx, nss_ipv4_conn_cfg,
503					nss_ipv4_update_conn_count_cb);
504	if (ret != 0) {
505		nss_ipv4_conn_cfg = saved_nss_ipv4_conn_cfg;
506		return ret;
507	}
508
509	return 0;
510}
511
512static ctl_table nss_ipv4_table[] = {
513	{
514		.procname		= "ipv4_conn",
515		.data			= &nss_ipv4_conn_cfg,
516		.maxlen			= sizeof(int),
517		.mode			= 0644,
518		.proc_handler   	= &nss_ipv4_conn_cfg_handler,
519	},
520	{ }
521};
522
523static ctl_table nss_ipv4_dir[] = {
524	{
525		.procname		= "ipv4cfg",
526		.mode			= 0555,
527		.child			= nss_ipv4_table,
528	},
529	{ }
530};
531
532
533static ctl_table nss_ipv4_root_dir[] = {
534	{
535		.procname		= "nss",
536		.mode			= 0555,
537		.child			= nss_ipv4_dir,
538	},
539	{ }
540};
541
542static ctl_table nss_ipv4_root[] = {
543	{
544		.procname		= "dev",
545		.mode			= 0555,
546		.child			= nss_ipv4_root_dir,
547	},
548	{ }
549};
550
551static struct ctl_table_header *nss_ipv4_header;
552
553/*
554 * nss_ipv4_register_sysctl()
555 *	Register sysctl specific to ipv4
556 */
557void nss_ipv4_register_sysctl(void)
558{
559	/*
560	 * Register sysctl table.
561	 */
562	nss_ipv4_header = register_sysctl_table(nss_ipv4_root);
563	sema_init(&i4cfgp.sem, 1);
564	init_completion(&i4cfgp.complete);
565	i4cfgp.current_value = nss_ipv4_conn_cfg;
566}
567
568/*
569 * nss_ipv4_unregister_sysctl()
570 *	Unregister sysctl specific to ipv4
571 */
572void nss_ipv4_unregister_sysctl(void)
573{
574	/*
575	 * Unregister sysctl table.
576	 */
577	if (nss_ipv4_header) {
578		unregister_sysctl_table(nss_ipv4_header);
579	}
580}
581
582/*
583 * nss_ipv4_msg_init()
584 *	Initialize IPv4 message.
585 */
586void nss_ipv4_msg_init(struct nss_ipv4_msg *nim, uint16_t if_num, uint32_t type, uint32_t len,
587			nss_ipv4_msg_callback_t cb, void *app_data)
588{
589	nss_cmn_msg_init(&nim->cm, if_num, type, len, (void *)cb, app_data);
590}
591
592EXPORT_SYMBOL(nss_ipv4_tx);
593EXPORT_SYMBOL(nss_ipv4_tx_with_size);
594EXPORT_SYMBOL(nss_ipv4_notify_register);
595EXPORT_SYMBOL(nss_ipv4_notify_unregister);
596EXPORT_SYMBOL(nss_ipv4_get_mgr);
597EXPORT_SYMBOL(nss_ipv4_register_sysctl);
598EXPORT_SYMBOL(nss_ipv4_unregister_sysctl);
599EXPORT_SYMBOL(nss_ipv4_msg_init);
600EXPORT_SYMBOL(nss_ipv4_update_conn_count);
601